mapping COM and SML#

IDispatch and Variant.

OLE/SML# interoperates with COM objects through IDispatch interface.

Methods exposed by COM objects are accessed via IDispatch::Invoke.

IDispatch::Invoke takes and returns OLE Variant. Variant is a tagged union of various data types.

data type mapping.

Data types which can be stored in Variant are enumerated in VARENUM. Data types indicated by VARENUM are mapped to SML# datatype as follows.

VARENUM SML# data type
VT_EMPTY unsupported
VT_NULL unsupported
VT_R4 Real32.real
VT_R8 Real64.real
VT_CY unsupported
VT_DATE unsupported
VT_BSTR OLE.string
VT_ERROR unsupported
VT_BOOL bool
VT_UI1 Word8.word
VT_UI2 Word32.word
VT_UI4 Word32.word
VT_UINT Word32.word
VT_VOID unit
VT_HRESULT unsupported
VT_PTR(vt) OLE.variant
VT_SAFEARRAY(vt) [SML# type of vt] OLE.safearray
VT_CARRAY unsupported
VT_USERDEFINED(other type) unsupported
VT_LPSTR unsupported
VT_LPWSTR unsupported
VT_RECORD unsupported
VT_INT_PTR unsupported
VT_UINT_PTR unsupported
VT_FILETIME unsupported
VT_BLOB unsupported
VT_STREAM unsupported
VT_STORAGE unsupported
VT_STORED_OBJECT unsupported
VT_BLOB_OBJECT unsupported
VT_CF unsupported
VT_CLSID unsupported
VT_BSTR_BLOB unsupported
VT_VECTOR unsupported
VT_ARRAY unsupported
VT_BYREF(vt) OLE.variant

SAFEARRAY mapping.

COM SAFEARRAY can describe multi-dimension arrays. OLE/SML# maps a SAFEARRAY to OLE.safearray. For example, a three-dimensional SAFEARRAY

VT_INT a[10][20][30]

is mapped to OLE.safearray.

a : OLE.safearray

An element of a SAFEARRAY


is accessed as

OLE.SafeArray.sub (a, [1, 2, 3])

In addition to using OLE.SafeArray, you can access an safearray directly. OLE.safearray is a pair of an array of and a list of int.

(array, [10, 20, 30]) : array * int list

The elements of an array are stored in column major order. The first dimension changes first, and the last dimension changes last.

For example, an element of the above SAFEARRAY a


is stored at the index of 3 * (10 * 20) + 2 * 10 + 1 = 621. It can be accessed from SML# as

Array.sub(array, 621)

method mapping.

A COM method which takes n arguments is mapped to a SML# function which takes a tuple of n elements.

If a method is a void function returning nothing, it is mapped to a SML# fuction which returns a unit.

COM method SML# function
t0 method() method : unit -> [t0]
t0 method(t1) method : [t1] -> [t0]
t0 method(t1, ..., tn) method : [t1] * ... * [tn] -> [t0]

In this table,


indicates the SML# datatype mapped from Variant type t.

parameter mapping.

optional parameter.

An optional parameter of type t is mapped to

[t] option

[out] attribute.

If a parameter is annotated with [out] attribute, the type of the parameter is mapped to OLE.variant ref.

null reference parameter.

Use OLE.NullUnknown and OLE.NullDispatch to pass a null reference in VT_UNKNOWN and VT_DISPATCH parameter.

Use EMPTY to pass a null pointer to other types in VT_VARIANT parameter.

property accessor

In addition to usual methods, COM objects expose three types of methods. These are accessor methods for properties of COM objects.

The getter of a property p of type t is mapped to a SML# function

getp : unit -> [t]

The setter of a property p of type t is mapped to a SML# function

setp : [t] -> unit

The reference setter of a property p of type t is mapped to a SML# function

setRefp : [t] -> unit


OLE structure and OLE2SML ignore methods which satisfy any of following.

  • any of its parameters has [ret] attribute.
  • any of its parameters is variant type which is not included in OLE.variant.

exception mapping.

If a COM object throws an exception in an invocation of its method from OLE/SML#, an SML# exception

OLE.OLEError(OLE.ComApplicationError detail)

is raised to the caller in SML#.

If COM framework API function returns an error, an SML# exception

OLE.OLEError(ComSystemError message)

is raised to SML# world.