This module adds Windows COM support for Winim. It allows Nim to interact with COM objects like a scripting language. For example:
comScript: var dict = CreateObject("Scripting.Dictionary") dict.add("a", "the") dict.add("b", item:="quick") dict.add(item:="fox", key:="c") dict.item(key:="c") = "dog" for key in dict: echo key, " => ", dict.item(key)
This module introduces two new types for dealing with COM objects: "com" and "variant". In summary, CreateObject() and GetObject() return a "com" value, and any input/output of a COM method should be a "variant" value.
Most Nim data types and Winim string types can be converted to/from "variant" values. The conversion is usually automatic. However, explicit conversion is also supported.
proc toVariant[T](x: T): variant proc fromVariant[T](x: variant): T # Supported type: # char|string|cstring|mstring|wstring|BSTR # bool|enum|SomeInteger|SomeReal # com|variant|VARIANT|ptr IUnknown|ptr IDispatch|pointer # SYSTEMTIME|FILETIME # 1D~3D array|seq|COMBinary
The COMBinary type can help deal with binary data. For example:
var input = "binary\0string\0test\0" var v = toVariant(COMBinary input) var output = string fromVariant[COMBinary](v) assert input == output
Types
com = ref object when hasTraceTable:
- IDispatch wrapper.
COMArray1D = seq[variant]
- One-dimensional Automation array.
COMArray2D = seq[seq[variant]]
- Two-dimensional Automation array.
COMArray3D = seq[seq[seq[variant]]]
- Three-dimensional Automation array.
COMBinary = distinct string
- Binary bytes transported as VT_ARRAY|VT_UI1.
COMError = object of CatchableError hresult*: HRESULT
- Base error for COM.
comEventHandler = proc (self: com; name: string; params: varargs[variant]): variant
COMException = object of COMError
- COM dispatch exception.
variant = ref object when hasTraceTable:
- VARIANT wrapper.
VariantConversionError = object of ValueError
- Raised when a VARIANT conversion fails.
Procs
proc adoptVariant(x: var VARIANT): variant {....raises: [COMError], tags: [], forbids: [].}
- Takes ownership of a raw VARIANT and resets x to VT_EMPTY.
proc COM_FullRelease() {....raises: [], tags: [], forbids: [].}
-
Releases all COM wrappers tracked on the current thread.
Normally the memory manager releases wrappers. Some COM servers, such as Excel.Application, can keep a process alive when cycles or outstanding references survive GC_fullCollect; this procedure provides deterministic cleanup for that case.
The hidden per-thread COM initialization remains active until the thread exits, avoiding delayed-destructor use-after-uninitialize hazards. Use -d:notrace to disable wrapper tracking.
proc connect(self: com; handler: comEventHandler; riid: REFIID = nil): DWORD {. discardable, ...raises: [COMError, Exception], tags: [RootEffect], forbids: [].}
-
Connects a COM event handler and returns its connection cookie. The handler is a user-defined proc to receive the COM event. comEventHandler is defined as:
type comEventHandler = proc(self: com, name: string, params: varargs[variant]): variant
proc CreateObject(progId: string): com {....raises: [COMError, Exception], tags: [RootEffect], forbids: [].}
- Creates a COM object in the current thread's automatically initialized apartment. Raises COMError for invalid class identifiers or activation failures.
proc disconnect(self: com; cookie: DWORD; riid: REFIID = nil): bool {. discardable, ...raises: [COMError, Exception], tags: [RootEffect], forbids: [].}
- Disconnects an event cookie.
proc fromVariant[T](x: variant): T
proc getCurrentCOMError(): ref COMError {.inline, ...raises: [], tags: [], forbids: [].}
- Returns the current exception cast to COMError.
proc newCom(file, progId: string): com {.inline, ...raises: [COMError, Exception], tags: [RootEffect], forbids: [].}
- Alias for GetObject(file, progId).
proc newVariant(x: VARIANT): variant {....raises: [COMError, VariantConversionError], tags: [], forbids: [].}
- Copies a raw VARIANT.
proc rawTypeDesc(x: variant): string {....raises: [], tags: [], forbids: [].}
- Returns a readable raw VARTYPE description.
proc toVariant(x: COMBinary): variant {....raises: [VariantConversionError], tags: [], forbids: [].}
proc toVariant(x: ptr IDispatch): variant {....raises: [Exception], tags: [RootEffect], forbids: [].}
proc toVariant(x: ptr IUnknown): variant {....raises: [Exception], tags: [RootEffect], forbids: [].}
Converters
converter variantConverterToBool(x: variant): bool {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToChar(x: variant): char {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToCom(x: variant): com {. ...raises: [VariantConversionError, COMError, Exception], tags: [RootEffect], forbids: [].}
converter variantConverterToCOMArray1D(x: variant): COMArray1D {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToCOMArray2D(x: variant): COMArray2D {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToCOMArray3D(x: variant): COMArray3D {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToCOMBinary(x: variant): COMBinary {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToCString(x: variant): cstring {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToFILETIME(x: variant): FILETIME {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToFloat32(x: variant): float32 {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToFloat64(x: variant): float64 {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToIDispatch(x: variant): ptr IDispatch {. ...raises: [VariantConversionError, COMError, Exception], tags: [RootEffect], forbids: [].}
converter variantConverterToInt(x: variant): int {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToInt8(x: variant): int8 {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToInt16(x: variant): int16 {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToInt32(x: variant): int32 {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToInt64(x: variant): int64 {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToIUnknown(x: variant): ptr IUnknown {. ...raises: [VariantConversionError, COMError, Exception], tags: [RootEffect], forbids: [].}
converter variantConverterToMString(x: variant): mstring {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToPointer(x: variant): pointer {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToString(x: variant): string {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToSYSTEMTIME(x: variant): SYSTEMTIME {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToUInt(x: variant): uint {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToUInt8(x: variant): uint8 {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToUInt16(x: variant): uint16 {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToUInt32(x: variant): uint32 {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToUInt64(x: variant): uint64 {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
converter variantConverterToVARIANT(x: variant): VARIANT {. ...raises: [VariantConversionError], tags: [], forbids: [].}
converter variantConverterToWString(x: variant): wstring {. ...raises: [VariantConversionError, COMError], tags: [], forbids: [].}
Macros
macro comScript(x: untyped): untyped
-
Nim's dot operators .= only allow "a.b = c". With this macro, "a.b(c, d) = e" is allowed. Some assignments require this macro to work. Moreover, this macro also translates named arguments to table constructor syntax which functions related to methods and properties can accept (here we use := as assignment to avoid syntax conflict). For example:
comScript: dict.item("c") = "dog" dict.add(item:="fox", key:="c") excel.activeSheet.cells(1, 1) = "text" excel.activeSheet.range(cell1:="A1") = "text"