► |  | The Racket Foreign Interface

1 | Overview
2 | Loading Foreign Libraries
3 | C Types
4 | Pointer Functions
5 | Derived Utilities
6 | Miscellaneous Support
7 | Unexported Primitive Functions
| Bibliography
| Index

► | 5 | Derived Utilities

5.1 | Safe Homogenous Vectors
5.2 | Safe C Vectors
5.3 | Tagged C Pointer Types
5.4 | Defining Bindings
5.5 | Allocation and Finalization
5.6 | Custodian Shutdown Registration
5.7 | Atomic Execution
5.8 | Speculatively Atomic Execution
5.9 | Objective-C FFI
5.10 | Cocoa Foundation
5.11 | COM (Common Object Model)
5.12 | File Security-Guard Checks
5.13 | Windows API Helpers

▼ | 5.11 | COM (Common Object Model)

5.11.1 | COM Automation
5.11.2 | COM Classes and Interfaces
5.11.3 | Active X Controls

► | 5.11.2 | COM Classes and Interfaces

5.11.2.1 | Describing COM Interfaces
5.11.2.2 | Obtaining COM Interface References
5.11.2.3 | COM FFI Helpers
5.11.2.4 | COM Interface Example

On this page:

5.11.2.1`` Describing COM Interfaces
define-com-interface
5.11.2.2`` Obtaining COM Interface References
Query Interface
Add Ref
Release
make-com-object
5.11.2.3`` COM FFI Helpers
_ wfun
_ mfun
_ hfun
_ hmfun
_ GUID
_ GUID-pointer
_ HRESULT
_ LCID
LOCALE_ SYSTEM_ DEFAULT
Sys Free String
Sys Alloc String Len
IID_ NULL
IID_ IUnknown
_ IUnknown
_ IUnknown-pointer
_ IUnknown_ vt
windows-error
5.11.2.4`` COM Interface Example

top ← prev up next →

##### 5.11.2`` COM Classes and Interfaces

( require ffi/unsafe/com )

The ffi/unsafe/com library exports all of ffi/com, and it also supports direct, FFI-based calls to COM object methods.

##### 5.11.2.1`` Describing COM Interfaces

> > syntax

> > ( define-com-interface (_id _super-id)
> > ([method-id ctype-expr maybe-alloc-spec] ...))

> maybe-alloc-spec

> =

> |  | | |  | #:release-with-function function-id
> |  | | |  | #:release-with-method method-id
> |  | | |  | #:releases

Defines _id as an interface that extends _super-id, where _super-id is often _IUnknown, and that includes methods named by method-id. The _id and _super-id identifiers must start with an underscore. A _super-id _vt must also be defined for deriving a virtual-method table type.

The order of the method-ids must match the specification of the COM interface, not including methods inherited from _super-id. Each method type produced by ctype-expr that is not _fpointer must be a function type whose first argument is the “self” pointer, usually constructed with _mfun or _hmfun.

The define-com-interface form binds _id, id ?, _id -pointer, _id _ vt (for the virtual-method table), _id _ vt-pointer, and method-id for each method whose ctype-expr is not _fpointer. (In other words, use _fpointer as a placeholder for methods of the interface that you do not need to call.) An instance of the interface will have type _id -pointer. Each defined method-id is bound to a function-like macro that expects a _id -pointer as its first argument and the method arguments as the remaining arguments.

A maybe-alloc-spec describes allocation and finalization information for a method along the lines of ffi/unsafe/alloc. If the maybe-alloc-spec is #:release-with-function function-id, then function-id is used to deallocate the result produced by the method, unless the result is explictly deallocated before it becomes unreachable; for exmaple, #:release-with-function Release is suitable for a method that returns a COM interface reference that must be eventually released. The #:release-with-method method-id form is similar, except that the deallocator is a method on the same object as the allocating method (i.e., one of the other method-ids or an inherited method). A #:releases annotation indicates that a method is a deallocator (so that a value should not be automatically deallocated if it is explicitly deallocated using the method).

See COM Interface Example for an example using define-com-interface.

##### 5.11.2.2`` Obtaining COM Interface References

> > procedure

> > ( QueryInterface |  | iunknown |  |  |  |
> > |  | iid |  |  |  |
> > |  | intf-pointer-type) |  | → |  | ( or/c cpointer? #f)

> iunknown : com-iunknown?
> iid : iid?
> intf-pointer-type : ctype?

Attempts to extract a COM interface pointer for the given COM object. If the object does not support the requested interface, the result is #f, otherwise it is cast to the type intf-pointer-type.

Specific IIDs and intf-pointer-types go together. For example, IID_IUnknown goes with _IUnknown-pointer.

For a non-#f result, Release function is the automatic deallocator for the resulting pointer. The pointer is register with a deallocator after the cast to intf-pointer-type, which is why QueryInterface accepts the intf-pointer-type argument (since a cast generates a fresh reference).

> > procedure

> > ( AddRef iunknown) → exact-positive-integer?

> iunknown : com-iunknown?

> > procedure

> > ( Release iunknown) → exact-nonnegative-integer?

> iunknown : com-iunknown?

Increments or decrements the reference count on iunknown, returning the new reference count and releasing the interface reference if the count goes to zero.

> > procedure

> > ( make-com-object |  | iunknown |  |  |  |
> > |  | clsid |  |  |  |
> > | [ | #:manage? manage?]) |  | → |  | com-object?

> iunknown : com-iunknown?
> clsid : ( or/c clsid? #f)
> manage? : any/c = #t

Converts a COM object into a object that can be used with the COM automation functions, such as com-invoke.

If manage? is true, the resulting object is registered with the current custodian and a finalizer to call com-release when the custodian is shut down or when the object becomes inaccessible.

##### 5.11.2.3`` COM FFI Helpers

> > syntax

> > ( _wfun fun-option ... maybe-args type-spec ... -> type-spec
> > maybe-wrapper)

Like _fun, but adds #:abi winapi.

> > syntax

> > ( _mfun fun-option ... maybe-args type-spec ... -> type-spec
> > maybe-wrapper)

Like _wfun, but adds a _pointer type (for the “self” argument of a method) as the first argument type-spec.

> > syntax

> > ( _hfun fun-option ... type-spec ... -> id output-expr)

Like _wfun, but for a function that returns an _HRESULT. If the result is not zero, then an error is raised using windows-error and using id as the name of the failed function. Otherwise, output-expr (as in a maybe-racket for _fun) determines the result.

> > syntax

> > ( _hmfun fun-option ... type-spec ... -> id output-expr)

Like _hfun, but lke _mfun in that _pointer is added for the first argument.

> > value

> > _GUID : ctype?

> > value

> > _GUID-pointer : ctype?

> > value

> > _HRESULT : ctype?

> > value

> > _LCID : ctype?

Some C types that commonly appear in COM interface specifications.

> > value

> > LOCALE_SYSTEM_DEFAULT : exact-integer?

The usual value for a _LCID argument.

> > procedure

> > ( SysFreeString str) → void?

> str : _pointer

> > procedure

> > ( SysAllocStringLen content len) → cpointer?

> content : _pointer
> len : integer?

COM interfaces often require or return srings that must be allocated or freed as system strings.

When receiving a string value, cast it to _string/utf-16 to extract a copy of the string, and then free the original pointer with SysFreeString.

> > value

> > IID_NULL : iid?

> > value

> > IID_IUnknown : iid?

Commonly used IIDs.

> > value

> > _IUnknown : ctype?

> > value

> > _IUnknown-pointer : ctype?

> > value

> > _IUnknown_vt : ctype?

Types for the IUnknown COM interface.

> > procedure

> > ( windows-error msg hresult) → any

> msg : string?
> hresult : exact-integer?

Raises an exception. The msg strign provides the base error message, but hresult and its human-readable interpretation (if available) are added to the message.

##### 5.11.2.4`` COM Interface Example

Here’s an example using the Standard Component Categories Manager to enumerate installed COM classes that are in the different system-defined categories. The example illustrates instantiating a COM class by CLSID, describing COM interfaces with define-com-interface, and using allocation specifications to ensure that resources are reclaimed even if an error is encountered or the program is interrupted.

> #lang racket/base
> ( require ffi/unsafe
> ffi/unsafe/com)
> ( provide show-all-classes)
> ; The function that uses COM interfaces defined further below:
> ( define (show-all-classes)
> ( define ccm
> ( com-create-instance CLSID_StdComponentCategoriesMgr))
> ( define icat ( QueryInterface ( com-object-get-iunknown ccm)
> IID_ICatInformation
> _ICatInformation-pointer))
> ( define eci (EnumCategories icat LOCALE_SYSTEM_DEFAULT ))
> ( for ([catinfo ( in-producer ( lambda () (Next/ci eci)) #f)])
> ( printf "~a:\n"
> ( cast ( array-ptr (CATEGORYINFO-szDescription catinfo))
> _pointer
> _string/utf-16 ))
> ( define eg
> (EnumClassesOfCategories icat (CATEGORYINFO-catid catinfo)))
> ( for ([guid ( in-producer ( lambda () (Next/g eg)) #f)])
> ( printf " ~a\n" ( or ( clsid->progid guid)
> ( guid->string guid))))
> ( Release eg))
> ( Release eci)
> ( Release icat))
> ; The class to instantiate:
> ( define CLSID_StdComponentCategoriesMgr
> ( string->clsid "{0002E005-0000-0000-C000-000000000046}"))
> ; Some types and variants to match the specification:
> ( define _ULONG _ulong )
> ( define _CATID _GUID )
> ( define _REFCATID _GUID-pointer )
> ( define-cstruct _CATEGORYINFO ([catid _CATID]
> [lcid _LCID ]
> [szDescription ( _array _short 128)]))
> ; —— IEnumGUID ——-
> ( define IID_IEnumGUID
> ( string->iid "{0002E000-0000-0000-C000-000000000046}"))
> ( define-com-interface (_IEnumGUID _IUnknown )
> ([Next/g ( _mfun (_ULONG = 1) ; simplifed to just one
> (guid : ( _ptr o _GUID ))
> (got : ( _ptr o _ULONG))
> -> (r : _HRESULT )
> -> ( cond
> [( zero? r) guid]
> [( = r 1) #f]
> [ else ( windows-error "Next/g failed" r)]))]
> [Skip _fpointer ]
> [Reset _fpointer ]
> [Clone _fpointer ]))
> ; —— IEnumCATEGORYINFO ——-
> ( define IID_IEnumCATEGORYINFO
> ( string->iid "{0002E011-0000-0000-C000-000000000046}"))
> ( define-com-interface (_IEnumCATEGORYINFO _IUnknown )
> ([Next/ci ( _mfun (_ULONG = 1) ; simplifed to just one
> (catinfo : ( _ptr o _CATEGORYINFO))
> (got : ( _ptr o _ULONG))
> -> (r : _HRESULT )
> -> ( cond
> [( zero? r) catinfo]
> [( = r 1) #f]
> [ else ( windows-error "Next/ci failed" r)]))]
> [Skip _fpointer ]
> [Reset _fpointer ]
> [Clone _fpointer ]))
> ; —— ICatInformation ——-
> ( define IID_ICatInformation
> ( string->iid "{0002E013-0000-0000-C000-000000000046}"))
> ( define-com-interface (_ICatInformation _IUnknown )
> ([EnumCategories ( _hmfun _LCID
> (p : ( _ptr o _IEnumCATEGORYINFO-pointer))
> -> EnumCategories p)]
> [GetCategoryDesc ( _hmfun _REFCATID _LCID
> (p : ( _ptr o _pointer ))
> -> GetCategoryDesc
> ( begin0
> ( cast p _pointer _string/utf-16 )
> ( SysFreeString p)))]
> [EnumClassesOfCategories ( _hmfun (_ULONG = 1) ; simplifed
> _REFCATID
> (_ULONG = 0) ; simplifed
> ( _pointer = #f)
> (p : ( _ptr o
> _IEnumGUID-pointer))
> -> EnumClassesOfCategories p)
> #:release-with-function Release ]
> [IsClassOfCategories _fpointer ]
> [EnumImplCategoriesOfClass _fpointer ]
> [EnumReqCategoriesOfClass _fpointer ]))

top ← prev up next →