ComObject

Creates a COM object on Windows, connects to a D-Bus service on Linux, or addresses a scriptable application on macOS.

ComObj := ComObject(CLSID , IID)

ComObject itself is a class derived from ComValue, but is used only to create or identify COM objects.

See Interprocess automation with ComObject for the Linux and macOS addressing models.

Parameters

CLSID

Type: String

CLSID or human-readable Prog ID of the COM object to create.

On Linux, the D-Bus target to connect to, written [session:|system:]service.name[:/object/path]. The service is activated if it is not already running.

On macOS, the application to address: a bundle identifier such as "com.apple.Finder", an application name such as "Finder", the path of an application bundle, or "pid:1234". The application is launched in the background if it is not already running; a pid: target which is not running throws.

IID

Type: String

If omitted, it defaults to "{00020400-0000-0000-C000-000000000046}" (IID_IDispatch). Otherwise, specify the identifier of the interface to return. In most cases this is omitted.

On Linux, the name of the D-Bus interface to bind to, such as "org.freedesktop.DBus". If omitted, members are resolved across all of the object's interfaces. Supply it when a member name is ambiguous.

On macOS, the name of the scripting suite to bind to, such as "Standard Suite". If omitted, members are resolved across every suite the application publishes. Supply it when a member name is ambiguous.

Return Value

Type: Object

This function returns a COM wrapper object of type dependent on the IID parameter.

IIDClassVariant TypeDescription
IID_IDispatch ComObject VT_DISPATCH (9) Allows the script to call properties and methods of the object using normal object syntax.
Any other IID ComValue VT_UNKNOWN (13) Provides only a Ptr property, which allows the object to be passed to DllCall or ComCall.

Error Handling

An exception is thrown on failure, such as if a parameter is invalid or the object does not support the interface specified by IID.

On Linux, an error is thrown if the object has no usable interfaces at the requested path, if the object does not implement the requested interface, or if a member name is ambiguous. An ambiguous method raises a MethodError, and an ambiguous property raises a PropertyError; the error lists the interfaces to choose from. An error reported by the service is thrown with the D-Bus error name it sent. A call which receives no reply within 25 seconds throws a timeout error.

On macOS, an error is thrown if no such application can be found, if it publishes no scripting terminology, if it has no suite of the requested name, or if a member name is defined by more than one suite. An error reported by the application is thrown with the message and number it sent. Refused Automation permission throws an OSError naming the setting to grant, and a command which receives no reply within 25 seconds throws a timeout error.

Remarks

Windows

Implicit string conversion calls the COM object's ToString member. COM dispatch errors, including a missing ToString member, propagate.

Linux

Methods and properties are resolved through D-Bus introspection. Unless an interface is selected explicitly, the object's own interfaces take precedence over the standard org.freedesktop.DBus.* interfaces. If several interfaces at the same level define a name, select one with IID or ComObjQuery. A read-only property throws when assigned.

A D-Bus method may return several values. A single return value is returned directly; two or more are returned as an Array in declared order. A method which returns nothing yields an empty string.

Indexing the object with an object path returns a child object, so nm["Devices/0"] and nm["/org/freedesktop/NetworkManager/Devices/0"] are equivalent. Child objects cannot be assigned.

Waiting for a reply does not block timers, hotkeys or the GUI.

Introspection data is read when the wrapper is created. Create another wrapper to see interfaces changed by the service.

macOS

Commands, properties and elements are resolved through the application's scripting definition and used with ordinary object syntax. A property whose definition marks it read-only throws when assigned.

An object is a query which the application resolves each time it is used. Indexing a collection narrows it: app.Windows[1] by position, counting from one and reading a negative index from the end, or app.Windows["Untitled"] by name. ById(value) selects by unique identifier, Count returns the number of elements, and a for-loop iterates the elements present when the loop starts.

A command takes its direct parameter as the first unnamed argument and every other value by name. When the command is sent to an object, that object is the direct parameter, so passing another unnamed argument is an error.

Values convert both ways: text, numbers and booleans directly, a record to a Map, a list to an Array, a file reference to its POSIX path, a date to YYYYMMDDHH24MISS, and an object specifier back to another ComObject. An enumerator is reported by name, and a name is accepted wherever the definition declares an enumerated type. Use ComValue where a value must carry a type the definition does not pin down.

Apple Events calls are ordered per target application. A slow target does not block calls to other targets. Pending calls are skipped after their callers time out; an event already sent may still take effect. Native dispatch is unverified on macOS.

Controlling another application requires Automation permission, granted per application.

Waiting for a reply does not block timers, hotkeys or the GUI.

ComValue, ComObjGet, ComObjActive, ComObjConnect, ComObjArray, ComObjQuery, ComCall, CreateObject (Microsoft Docs)

Examples

For a long list of v1.1 examples, see this archived forum thread.

Windows only. Launches an instance of Internet Explorer, makes it visible and navigates to a website.

ie := ComObject("InternetExplorer.Application")
ie.Visible := true  ; This is known to work incorrectly on IE7.
ie.Navigate("https://www.autohotkey.com/")

Windows only. Retrieves the path of the desktop's current wallpaper.

AD_GETWP_BMP := 0
AD_GETWP_LAST_APPLIED := 0x00000002
CLSID_ActiveDesktop := "{75048700-EF1F-11D0-9888-006097DEACF9}"
IID_IActiveDesktop := "{F490EB00-1240-11D1-9888-006097DEACF9}"
cchWallpaper := 260
GetWallpaper := 4

AD := ComObject(CLSID_ActiveDesktop, IID_IActiveDesktop)
wszWallpaper := Buffer(cchWallpaper * 2)
ComCall(GetWallpaper, AD, "ptr", wszWallpaper, "uint", cchWallpaper, "uint", AD_GETWP_LAST_APPLIED)
Wallpaper := StrGet(wszWallpaper, "UTF-16")
MsgBox "Wallpaper: " Wallpaper

Linux only. Asks the message bus itself which services are currently on the session bus. The bus daemon is always present, so this runs on any Linux system with a session bus.

bus := ComObject("org.freedesktop.DBus")
for name in bus.ListNames()
    if !InStr(name, ":")  ; skip unique connection names
        MsgBox name

Linux only. Discovers what an object offers. Introspect returns an XML description of the object's interfaces, methods, properties, signals and child objects.

bus := ComObject("org.freedesktop.DBus")
xml := bus.Introspect()

; The interfaces this object implements.
out := "Interfaces:`n"
pos := 1
while pos := RegExMatch(xml, '<interface name="([^"]+)"', &m, pos)
{
    out .= "  " m[1] "`n"
    pos += m.Len
}

; The members of one interface. Each <method>, <property> and <signal>
; belongs to the <interface> it is nested in, so narrow to that element first.
seg := SubStr(xml, InStr(xml, '<interface name="org.freedesktop.DBus"'))
seg := SubStr(seg, 1, InStr(seg, "</interface>"))

out .= "`nMethods of org.freedesktop.DBus:`n"
pos := 1
while pos := RegExMatch(seg, '<method name="([^"]+)"', &m, pos)
{
    out .= "  " m[1] "`n"
    pos += m.Len
}

out .= "`nProperties:`n"
pos := 1
while pos := RegExMatch(seg, '<property name="([^"]+)" type="([^"]+)" access="([^"]+)"', &m, pos)
{
    out .= "  " m[1] " (" m[2] ", " m[3] ")`n"
    pos += m.Len
}

MsgBox out

Linux only. Reads property values. A single property is read as an ordinary property of the object. GetAll, on the standard org.freedesktop.DBus.Properties interface, returns every property of one interface at once as a Map.

bus := ComObject("org.freedesktop.DBus")

; One property, by name.
MsgBox "Interfaces: " bus.Interfaces.Length

; Every property of one interface. ComObjQuery selects the interface which
; declares GetAll, so its own members do not collide with the object's.
props := ComObjQuery(bus, "org.freedesktop.DBus.Properties")
for name, value in props.GetAll("org.freedesktop.DBus")
    MsgBox name " = " (value is Array ? "[" value.Length " items]" : value)

; Where this object lives.
MsgBox ComObjType(bus, "Name") " at " ComObjType(bus, "Path")

Linux only. Walks to child objects, starting at the service's root object, /. Each <node> in the introspection XML names a child of the introspected object.

root := ComObject("org.freedesktop.DBus:/")   ; the service's root object
xml := root.Introspect()

pos := 1
while pos := RegExMatch(xml, '<node name="([^"]+)"', &m, pos)
{
    child := root[m[1]]           ; a child name is relative to its parent
    MsgBox m[1] " -> " ComObjType(child, "Path")
    pos += m.Len
}

Linux only. Passes a dictionary whose values are typed explicitly, which is required wherever introspection cannot supply the type. This example names a hypothetical service; adapt it to one present on your system.

obj := ComObject("system:com.example.Service")
options := Map(
    "label", "report",                 ; a plain string needs no annotation
    "count", ComValue("u", 4),         ; unsigned 32-bit
    "path", ComValue("o", "/com/example/Target"))  ; object path, not a string
obj.Submit(options)

macOS only. Reads properties and walks a collection. System Events is installed on every Mac, so this needs no other application; the first run prompts for permission to control it.

events := ComObject("com.apple.systemevents")
for p in events.ApplicationProcesses
    MsgBox p.Name

macOS only. Narrows a collection and sends a command with a named parameter.

finder := ComObject("com.apple.Finder")
MsgBox finder.Windows.Count
if finder.Windows.Count
{
    w := finder.Windows[1]
    MsgBox w.Name          ; a property of that window
    w.Close(Saving: "no")  ; the window is the command's direct parameter
}