Repository navigation
SysWin Com Procedures
Home › All Categories › sys/win › sys/win/com › COM procedures
Creates COM objects and handles GUIDs, reference counts, event connections and variants.
These are the free functions of sys/win/com: no class to create first. They work with raw
interface pointers, so the COM rules apply to them directly:
-
Initialise COM first. Call
CoInitialize( NULL )once on the thread before creating or using objects, andCoUninitialize()at the end, after the last object is released. - Every pointer you are given carries a reference. NewCom, GetCom, AnyCom and SafeAddRef hand you one; give each back with SafeRelease when you are done.
-
Memory from COM is freed with
CoTaskMemFree, notdeallocate: the string of WstrAlloc is one.
A GUID is the 128-bit identifier COM names every class (CLSID) and interface (IID) with. Its text form is 38 characters: 32 hexadecimal digits in braces, grouped 8-4-4-4-12 with hyphens.
#import "sys/win"
#import "sys/win/com"
using win, comGUIDs in both directions, an object created two ways and released, and a VARIANT as text:
#import "sys/win"
#import "sys/win/com"
using win, com
function main() as long
CoInitialize( NULL )
' GUIDs: a CLSID to text and back, and a fresh one
dim clsDic as CLSID = ( &hEE09B103, &h97E0, &h11CF, { &h97, &h8F, &h00, &hA0, &h24, &h63, &hE0, &h6F } )
dim text as string = GuidText( clsDic )
dim back as GUID = GetGuid( text )
print "Scripting.Dictionary is "; text; ", read back equal: "; iif( IsEqualGUID( @back, @clsDic ), "yes", "no" )
print "a new GUID: "; GuidText( GetGuid() )
' create an object by ProgID and by CLSID, then release both
dim pUnk as any ptr = NewCom( "Scripting.Dictionary" )
dim pDisp as IDispatch ptr = NewCom( clsDic, IID_IDispatch )
print "by ProgID: "; iif( pUnk, "created", "failed" ); ", by CLSID: "; iif( pDisp, "created", "failed" )
SafeRelease( pUnk )
SafeRelease( pDisp )
print "after SafeRelease: "; iif( pUnk = NULL andalso pDisp = NULL, "both NULL", "not NULL" )
' a plain VARIANT as text
dim v as VARIANT
v.vt = VT_R8 : v.dblVal = 0.125
print "VARIANT: "; VarToStr( @v ); ", a number:"; IsVariantTypeNumber( v.vt )
CoUninitialize()
return 0
end function
end main()It prints the dictionary's CLSID in braces, read back equal: yes, a different new GUID on each
run, then:
by ProgID: created, by CLSID: created
after SafeRelease: both NULL
VARIANT: 0.125, a number:true
| Function | Does |
|---|---|
| NewCom | Creates an object from a ProgID, a CLSID, or a DLL file. |
| GetCom | Attaches to a running instance of an Automation server. |
| AnyCom | Attaches to a running instance, or creates an in-process one. |
| SafeAddRef | Adds a reference to an interface pointer. |
| SafeRelease | Releases an interface pointer and sets it to NULL. |
| Advise | Connects an event sink to an object's connection point. |
| Unadvise | Disconnects an event sink. |
| GetOleErrorInfo | Returns the description of the last Automation error. |
| GetGuid | Converts GUID text to a GUID, or makes a new one. |
| GuidText | Returns the text form of a GUID. |
| IsBstr | Guesses whether a pointer is a BSTR. |
| WstrAlloc | Copies a string into memory allocated with CoTaskMemAlloc. |
| OleCreateFontDisp | Creates a standard OLE font and returns its IFontDisp. |
| OleCreateFont | Creates a standard OLE font and returns its IFont. |
| VarToStr | Returns the contents of a VARIANT as text. |
| GetVarType | Returns the type code of a VARIANT. |
| IsVariantTypeFloat | Tells whether a type code is VT_R4 or VT_R8. |
| IsVariantTypeSignedInteger | Tells whether a type code is a signed integer. |
| IsVariantTypeUnsignedInteger | Tells whether a type code is an unsigned integer. |
| IsVariantTypeInteger | Tells whether a type code is any integer. |
| IsVariantTypeNumber | Tells whether a type code is an integer or floating-point number. |
| Type | Is |
|---|---|
| ComUnknown, LPCOMUNKNOWN |
IUnknown as an abstract tiko type, and a pointer to it. |
| ComDispatch, LPCOMDISPATCH |
IDispatch as an abstract tiko type, and a pointer to it. |
function NewCom overload( byref wszProgID as const wstring, byref wszLicKey as wstring = "" ) as any ptr
function NewCom overload( byref wszClsID as const wstring, byref wszIID as const wstring ) as any ptr
function NewCom overload( byref classID as const CLSID ) as any ptr
function NewCom overload( byref classID as const CLSID, byref riid as const IID ) as any ptr
function NewCom overload( byref wszLibName as const wstring, byref rclsid as const CLSID, byref riid as const IID, byref wszLicKey as wstring = "" ) as any ptr
function NewCom overload( byref wszLibName as const wstring, byref wszClsid as const wstring, byref wszIid as const wstring, byref wszLicKey as wstring = "" ) as any ptrCreates a new, uninitialised object and returns an interface pointer to it, carrying one reference.
-
By name (
wszProgID): a ProgID such as"Scripting.Dictionary", or a CLSID in braces. The result is the object'sIUnknown. With a licence key, the class object is asked forIClassFactory2and the instance is created with that key. -
By CLSID, optionally with an IID: the result is
IUnknown, or the interfaceriid. -
From a DLL file (
wszLibName, the full path): the DLL is loaded if it is not already, and the object is created through its exportedDllGetClassObject, without the class being registered. With a licence key the class object is requested asIClassFactoryand itsIClassFactory2::CreateInstanceLicis called. This suits plain in-process servers; it does not suit system components (XML, ADO, DirectX …), parts of applications such as Office, add-ins and snap-ins, or visual ActiveX controls, which need their container. Do not free the DLL while any of its objects is alive;CoUninitializeunloads it at the end.
The forms by name and by CLSID create in-process servers only (DLLs): an application server
such as Excel.Application is not started; use GetCom to attach to one that is
running.
Two overloads take two strings, so a call with two string literals is ambiguous. To pass a
licence key, put it in a wstring variable. The CLSID-and-IID text form converts the IID with
CLSIDFromProgID, which does not accept an interface ID, so it returns NULL; convert both
with GetGuid and use the CLSID-and-IID form instead.
| Parameter | Meaning |
|---|---|
wszProgID |
A ProgID, or a CLSID as text. |
wszLicKey |
A licence key for a licensed control; empty for none. |
classID, rclsid, wszClsid
|
The class to create. |
riid, wszIid
|
The interface wanted. |
wszLibName |
The DLL that implements the class. |
Returns the interface pointer, or NULL when the class is unknown or creation fails.
Example
dim clsDic as CLSID = ( &hEE09B103, &h97E0, &h11CF, { &h97, &h8F, &h00, &hA0, &h24, &h63, &hE0, &h6F } )
dim pUnk as any ptr = NewCom( "Scripting.Dictionary" )
dim pDisp as IDispatch ptr = NewCom( clsDic, IID_IDispatch )
dim pFile as IDispatch ptr = NewCom( "C:\Windows\System32\scrrun.dll", clsDic, IID_IDispatch )
print ( pUnk <> NULL ); ( pDisp <> NULL ); ( pFile <> NULL ) ' prints -1-1-1
SafeRelease( pUnk ) : SafeRelease( pDisp ) : SafeRelease( pFile )Microsoft Learn: CoCreateInstance
function GetCom overload( byref wszProgID as const wstring ) as IDispatch ptr
function GetCom overload( byref classID as const CLSID ) as IDispatch ptrReturns the IDispatch of a running instance of an Automation server, found in the Running
Object Table. Applications register there only after starting up; Office applications do so the
first time they lose the focus, so a call made while one has just started can fail.
Returns the pointer, carrying a reference, or NULL when no instance is registered.
Example
dim pExcel as IDispatch ptr = GetCom( "Excel.Application" )
if pExcel = NULL then print "Excel is not running"
SafeRelease( pExcel )Microsoft Learn: GetActiveObject
function AnyCom overload( byref wszProgID as const wstring ) as IDispatch ptr
function AnyCom overload( byref classID as const CLSID ) as IDispatch ptrReturns the IDispatch of a running instance, as GetCom does, and otherwise creates a
new instance as NewCom does. Creation is in-process only, so for an application server
such as Excel.Application it returns NULL unless the application is already running.
Returns the pointer, carrying a reference, or NULL.
Example
dim pDic as IDispatch ptr = AnyCom( "Scripting.Dictionary" )
print ( pDic <> NULL ) ' prints -1
SafeRelease( pDic )function SafeAddRef( byval pv as any ptr ) as ULONGAdds a reference to the interface pv, which must be a COM interface pointer or NULL. Call it
when you keep a second copy of a pointer that must outlive the first; release each copy.
Returns the new reference count, meant only for testing, or 0 for NULL.
Example
dim pDic as IDispatch ptr = AnyCom( "Scripting.Dictionary" )
dim pSecond as IDispatch ptr = pDic
SafeAddRef( pSecond )
SafeRelease( pDic ) : SafeRelease( pSecond )Microsoft Learn: IUnknown::AddRef
function SafeRelease( byref pv as any ptr ) as ULONGReleases the interface pv and sets the variable to NULL, so a second call does nothing. When
the last reference goes, the object frees itself.
Returns the remaining reference count, meant only for testing, or 0 for NULL.
Example
dim pDic as IDispatch ptr = AnyCom( "Scripting.Dictionary" )
SafeRelease( pDic )
print ( pDic = NULL ) ' prints -1Microsoft Learn: IUnknown::Release
function Advise overload( byval pUnk as any ptr, byval pEvtObj as any ptr, byval riid as IID ptr, byval pdwCookie as DWORD ptr ) as HRESULT
function Advise overload( byval pUnk as any ptr, byval pEvtObj as any ptr, byref riid as const IID, byval pdwCookie as DWORD ptr ) as HRESULT
function Advise overload( byval pUnk as any ptr, byval pEvtObj as any ptr, byref riid as IID, byval pdwCookie as DWORD ptr ) as HRESULTConnects your event sink pEvtObj to the object pUnk, so that the object calls the sink when
the events of the outgoing interface riid occur. The object's IConnectionPointContainer is
asked for the connection point of riid, and the sink is registered with it. Keep the cookie for
Unadvise.
| Parameter | Meaning |
|---|---|
pUnk |
The object whose events you want. |
pEvtObj |
Your sink: an object implementing the events interface. |
riid |
The events interface (the connection point's IID). |
pdwCookie |
Receives the cookie that identifies the connection. |
Returns S_OK; E_INVALIDARG when an argument is NULL; E_NOINTERFACE or
CONNECT_E_NOCONNECTION when the object has no such connection point; or the error from
registering the sink.
Example
dim as any ptr pSource, pSink ' your object and your sink
dim cookie as DWORD
if Advise( pSource, pSink, IID_IDispatch, @cookie ) <> S_OK then print "not connected"Microsoft Learn: IConnectionPoint::Advise
function Unadvise overload( byval pUnk as any ptr, byval riid as IID ptr, byval dwCookie as DWORD ) as HRESULT
function Unadvise overload( byval pUnk as any ptr, byref riid as const IID, byval dwCookie as DWORD ) as HRESULT
function Unadvise overload( byval pUnk as any ptr, byref riid as IID, byval dwCookie as DWORD ) as HRESULTEnds the connection that Advise made, identified by its cookie. Call it before releasing the sink.
Returns S_OK; E_INVALIDARG when pUnk or riid is NULL or the cookie is 0; or the
error from the connection point.
Example
dim pSource as any ptr
dim cookie as DWORD ' from Advise
if cookie then Unadvise( pSource, IID_IDispatch, cookie )Microsoft Learn: IConnectionPoint::Unadvise
function GetOleErrorInfo() as ustringReturns the description of the most recent Automation error on the thread, and clears it. Call
it right after the failing method call. Only objects that support rich error information
(IErrorInfo) leave one.
Returns the description, or an empty string when there is none.
Example
dim info as ustring = GetOleErrorInfo()
if len( info ) = 0 then print "no error information"Microsoft Learn: GetErrorInfo
function GetGuid( byval pwszGuidText as wstring ptr = NULL ) as GUIDConverts the text form of a GUID, braces included, to a GUID; case does not matter. Without an
argument it generates a new, unique GUID.
Returns the GUID. GetLastError() is 0 afterwards on success and the failing HRESULT
otherwise (CO_E_CLASSSTRING, &h800401F3, for text that is not a GUID); a failed conversion
returns all zeros.
Example
dim g as GUID = GetGuid( GuidText( IID_IDispatch ) )
print IsEqualGUID( @g, @IID_IDispatch ) ' prints -1
dim bad as GUID = GetGuid( "not a guid" )
print "&h"; hex( GetLastError() ) ' prints &h800401F3Microsoft Learn: CLSIDFromString, UuidCreate
function GuidText overload( byval classID as CLSID ptr ) as string
function GuidText overload( byval classID as CLSID ) as string
function GuidText overload( byval riid as REFIID ) as stringReturns the 38-character text form of a GUID, in braces and upper case.
Returns the text. GetLastError() is the result of the conversion.
Example
dim text as string = GuidText( IID_IDispatch )
print len( text ); " "; left( text, 10 ) ' prints 38 {00020400-Microsoft Learn: StringFromCLSID
function IsBstr( byval pv as any ptr ) as booleanGuesses whether pv points at a BSTR. A BSTR is stored with its length in bytes in the four
bytes before the text; the function reads those bytes and compares them with the length of the
null-terminated text. It is a heuristic: a BSTR that contains a null character is reported as
not one, any other string whose preceding bytes happen to match is reported as one, and reading
before a pointer that is not a string can fault.
Returns true when the two lengths agree; false for NULL and otherwise.
Example
dim b as BSTR = SysAllocString( "abc" )
print IsBstr( b ); " "; IsBstr( NULL ) ' prints true false
SysFreeString( b )function WstrAlloc( byref wszStr as wstring ) as wstring ptrCopies a string into memory allocated with CoTaskMemAlloc, for a method that takes ownership of
the string it is given and frees it itself. Free the copy with CoTaskMemFree if it is not
handed over.
Returns the copy, or NULL when memory runs out.
Example
dim pw as wstring ptr = WstrAlloc( "copy me" )
print len( *pw ) ' prints 7
CoTaskMemFree( pw )Microsoft Learn: SHStrDupW
function OleCreateFontDisp( byref wszFontName as wstring, byval cySize as LONGLONG, byval fWeight as short = FW_NORMAL, byval fItalic as WINBOOL = FALSE, byval fUnderline as WINBOOL = FALSE, byval fStrikethrough as WINBOOL = FALSE, byval fCharset as short = DEFAULT_CHARSET ) as IFontDisp ptrCreates a standard OLE font object, the kind ActiveX controls take for their Font property,
and returns its IFontDisp interface. Release it when you are done.
| Parameter | Meaning |
|---|---|
wszFontName |
The typeface, such as "Segoe UI". |
cySize |
The size in whole points. |
fWeight |
FW_NORMAL (400), FW_BOLD (700) …; above 550 also makes the font bold. |
fItalic, fUnderline, fStrikethrough
|
Nonzero for that style. |
fCharset |
The character set, such as DEFAULT_CHARSET or SYMBOL_CHARSET; give the one the typeface uses. |
Returns the font, or NULL on failure.
Example
dim pFont as IFontDisp ptr = OleCreateFontDisp( "Segoe UI", 9 )
SafeRelease( pFont )Microsoft Learn: OleCreateFontIndirect
function OleCreateFont( byref wszFontName as wstring, byval cySize as LONGLONG, byval fWeight as short = FW_NORMAL, byval fItalic as WINBOOL = FALSE, byval fUnderline as WINBOOL = FALSE, byval fStrikethrough as WINBOOL = FALSE, byval fCharset as short = DEFAULT_CHARSET ) as IFont ptrCreates a standard OLE font object as OleCreateFontDisp does and returns it
as an IFont pointer, through which the font's size, weight and other properties can be read
and changed, and its HFONT obtained. The font reports its size rounded to what the screen can
show: a 10-point Courier New reads back as 9.75 points. Release it when you are done.
Returns the font, or NULL on failure.
Example
dim pFont as IFont ptr = OleCreateFont( "Courier New", 10, FW_BOLD )
dim bold as WINBOOL
if pFont then pFont->lpVtbl->get_Bold( pFont, @bold )
print bold ' prints 1
SafeRelease( pFont )Microsoft Learn: IFont
function VarToStr overload( byval pvarIn as VARIANT ptr, byval bClear as boolean = false ) as ustringReturns the contents of a VARIANT as text, and with bClear = true clears the variant
afterwards (VariantClear). This is what DVARIANT.ToStr uses.
- Numbers are written without grouping, in the invariant format (
.as decimal point). A single has up to 7 significant digits, a double up to 18 (0.1stays0.1). -
VT_BOOLis-1or0;VT_ERRORis its code in decimal. -
VT_CYhas four decimals (-1.5000,0.0000), except a whole amount other than zero, which has none (5).VT_DECIMALkeeps its own digits. - A date is
2026/10/31:12:30:00.000.VT_EMPTYandVT_NULLgive an empty string. - A
VT_BYREFnumber or string is read through its pointer. - An array gives its elements joined with
"; ":10; 20; 30. A byte array gives the byte values (65; 66; 67); use DVARIANT.ToBuffer for the bytes. Arrays ofsingle,doubleandVARIANTelements whose lower bound is not 0 are read from the wrong position: the first element is skipped and memory past the end is read in its place. Arrays from Automation servers usually start at 0. - A
VT_CYorVT_DECIMALvariant is not cleared even withbClear = true; it holds nothing to free.
| Parameter | Meaning |
|---|---|
pvarIn |
The variant to read. |
bClear |
true clears the variant after a successful conversion. |
Returns the text; an empty string for NULL or a value that cannot be converted, in which
case the variant is not cleared.
Example
dim v as VARIANT
v.vt = VT_CY : v.cyVal.int64 = -15000
print VarToStr( @v ) ' prints -1.5000
v.vt = VT_BSTR : v.bstrVal = SysAllocString( "bye" )
print VarToStr( @v, true ); " "; v.vt ' prints bye 0Microsoft Learn: VariantToStringAlloc
function GetVarType( byval pvar as VARIANT ptr ) as VARTYPEReturns the type code (vt) of a VARIANT. pvar must not be NULL.
Example
dim v as VARIANT
v.vt = VT_UI2
print GetVarType( @v ) ' prints 18Microsoft Learn: VARENUM
function IsVariantTypeFloat( byval vt as VARTYPE ) as booleanTells whether vt is VT_R4 or VT_R8. Flags such as VT_ARRAY or VT_BYREF make it false.
Example
print IsVariantTypeFloat( VT_R8 ); " "; IsVariantTypeFloat( VT_CY ) ' prints true falsefunction IsVariantTypeSignedInteger( byval vt as VARTYPE ) as booleanTells whether vt is VT_I1, VT_I2, VT_I4 or VT_I8. VT_INT is not included.
Example
print IsVariantTypeSignedInteger( VT_I2 ) ' prints truefunction IsVariantTypeUnsignedInteger( byval vt as VARTYPE ) as booleanTells whether vt is VT_UI1, VT_UI2, VT_UI4 or VT_UI8. VT_UINT is not included.
Example
print IsVariantTypeUnsignedInteger( VT_UI2 ) ' prints truefunction IsVariantTypeInteger( byval vt as VARTYPE ) as booleanTells whether vt is one of the signed or unsigned integer types above. VT_INT and VT_UINT
are not included.
Example
print IsVariantTypeInteger( VT_UI2 ); " "; IsVariantTypeInteger( VT_INT ) ' prints true falsefunction IsVariantTypeNumber( byval vt as VARTYPE ) as booleanTells whether vt is an integer type (IsVariantTypeInteger) or a
floating-point type. VT_CY and VT_DECIMAL are not included.
Example
print IsVariantTypeNumber( VT_R4 ); " "; IsVariantTypeNumber( VT_BSTR ) ' prints true falsetype ComUnknown as ComUnknown_
type ComUnknown_ extends object
declare abstract function QueryInterface( byval riid as REFIID, byval ppvObject as LPVOID ptr ) as HRESULT
declare abstract function AddRef() as ULONG
declare abstract function Release() as ULONG
end type
type LPCOMUNKNOWN as ComUnknown ptrIUnknown declared as an abstract tiko type. Its virtual-method table has the layout of a COM
interface, so a pointer to a COM object can be held as a ComUnknown ptr and its methods called
as methods, p->Release(), instead of through lpVtbl. Interfaces declared by extending it,
as the Direct2D ones are, inherit the three methods.
Example
dim pUnk as LPCOMUNKNOWN = NewCom( "Scripting.Dictionary" )
dim pDisp as any ptr
if pUnk then pUnk->QueryInterface( @IID_IDispatch, @pDisp ) : pUnk->Release()
SafeRelease( pDisp )Microsoft Learn: IUnknown
type ComDispatch as ComDispatch_
type ComDispatch_ extends ComUnknown
declare abstract function GetTypeInfoCount( byval pctinfo as UINT ptr ) as HRESULT
declare abstract function GetTypeInfo( byval iTInfo as UINT, byval lcid as LCID, byval ppTInfo as ITypeInfo ptr ptr ) as HRESULT
declare abstract function GetIDsOfNames( byval riid as const IID const ptr, byval rgszNames as LPOLESTR ptr, byval cNames as UINT, byval lcid as LCID, byval rgDispId as DISPID ptr ) as HRESULT
declare abstract function Invoke( byval dispIdMember as DISPID, byval riid as const IID const ptr, byval lcid as LCID, byval wFlags as WORD, byval pDispParams as DISPPARAMS ptr, byval pVarResult as VARIANT ptr, byval pExcepInfo as EXCEPINFO ptr, byval puArgErr as UINT ptr ) as HRESULT
end type
type LPCOMDISPATCH as ComDispatch ptrIDispatch declared the same way, extending ComUnknown: the four
Automation methods after the three of IUnknown. For calling methods by name,
CDispInvoke does the GetIDsOfNames and Invoke work.
Example
dim clsDic as CLSID = ( &hEE09B103, &h97E0, &h11CF, { &h97, &h8F, &h00, &hA0, &h24, &h63, &hE0, &h6F } )
dim pDisp as LPCOMDISPATCH = NewCom( clsDic, IID_IDispatch )
dim count as UINT
if pDisp then pDisp->GetTypeInfoCount( @count ) : pDisp->Release()
print count ' prints 1Microsoft Learn: IDispatch
- sys/win/com
- DVARIANT, the variant class built on VarToStr
- CDispInvoke for calling Automation objects by name
- BSTRING for COM strings
tiko-lang · Home · Feature Index · Keyword Index · License
FreeBASIC manual pages reproduced under the GNU FDL 1.3.
- Generics
- Interfaces
- For Each
- Iterators
- Tuples
- Array Results
- Defer
- Lambdas
- Block Strings
- String Slices
- Embed
- Typed Variadics
- C Header Import
- Foreign Library Linking
- UString
- Fixed-Width Types
- Nullptr
- String Library
- Format
- Array
- Map
- Set
- LinkedList
- OrderedMap
- OrderedSet
- Sorting
- Optional
- Result
- Smart Pointers
- Date and Time (Chrono)
- Filesystem
- File Streams
- Config (INI and TOML)
- Codec
- Hash
- UUID
- OS
- Process
- Net
- HTTP and TLS
- Math Library
- Finance
- Logging
- Terminal TUI Library
- PsControls
- tkControls
- sys/win
- Goroutines and Channels
- LLVM Backend
- tiko build
- TIKO_COMPILER
- Variable Declarations
- Standard Data Types
- User Defined Types
- Procedures
- Operators
- Control Flow Statements
- Converting Data Types
- Array Functions
- String Functions
- Mathematical Functions
- Bit Manipulation
- Date and Time Functions
- File I/O Functions
- Console Functions
- User Input (Runtime Library)
- User Input Functions (Graphics Library)
- Screen Functions
- 2D Drawing Functions
- Graphics Library Reference
- Graphics Keyword List
- Memory Functions
- Threading Support Functions
- Error Handling Functions
- Operating System Functions
- Preprocessor
- Intrinsic Defines
- Miscellaneous Keywords
- Modularizing