Skip to content

std.com

COM/WinRT types as data (GUID, HRESULT, IUnknown, vtables); no OS calls out-pointers carry one ref, release exactly once; lent pointers aren’t yours

pub Guid :: struct {
data1: u32,
data2: u16,
data3: u16,
data4: [8]u8,
}

–– GUID –– 16 bytes, align 4; IIDs and CLSIDs are GUIDs

pub eq :: fn(self: *const Self, other: *const Guid) -> bool
pub is_null :: fn(self: *const Self) -> bool

all zero (GUID_NULL)

pub format :: fn(self: *const Self, out: []u8) -> usize ! GuidError

upper-case “{8-4-4-4-12}” into out, returns 38; .buffer_too_small if shorter

pub GUID_TEXT_LEN :: 38

text form length, with braces

pub GuidError :: errors {
invalid_format,
buffer_too_small,
}
  • invalid_format: not 8-4-4-4-12 hex, braces optional
  • buffer_too_small: the output buffer is shorter than GUID_TEXT_LEN
pub parse_guid :: fn(text: []const u8) -> Guid ! GuidError

strict 8-4-4-4-12 hex, either case, braces optional; no spaces or extra text

pub IID_IUnknown : Guid : .{ 0x00000000, 0x0000, 0x0000, .{ 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } } :: …
pub IID_IInspectable : Guid : .{ 0xAF86E2E0, 0xB12D, 0x4C6A, .{ 0x9C, 0x5A, 0xD7, 0xAA, 0x65, 0x10, 0x1E, 0x90 } } :: …
pub IID_IAgileObject : Guid : .{ 0x94EA2B94, 0xE9CC, 0x49E0, .{ 0xC0, 0xFF, 0xEE, 0x64, 0xCA, 0x8F, 0x5B, 0x90 } } :: …
pub IID_IActivationFactory : Guid : .{ 0x00000035, 0x0000, 0x0000, .{ 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } } :: …
pub Hresult :: i32

–– HRESULT –– bit 31 failure, bits 16-26 facility, bits 0-15 code; values from winerror.h

pub S_OK :: 0
pub S_FALSE :: 1
pub E_NOTIMPL :: -2147467263
pub E_NOINTERFACE :: -2147467262
pub E_POINTER :: -2147467261
pub E_ABORT :: -2147467260
pub E_FAIL :: -2147467259
pub E_UNEXPECTED :: -2147418113
pub E_OUTOFMEMORY :: -2147024882
pub E_INVALIDARG :: -2147024809
pub E_ACCESSDENIED :: -2147024891
pub E_HANDLE :: -2147024890
pub E_PENDING :: -2147483638
pub E_BOUNDS :: -2147483637
pub E_CHANGED_STATE :: -2147483636
pub E_ILLEGAL_METHOD_CALL :: -2147483634
pub RPC_E_CHANGED_MODE :: -2147417850
pub REGDB_E_CLASSNOTREG :: -2147221164
pub CO_E_NOTINITIALIZED :: -2147221008
pub CLASS_E_NOAGGREGATION :: -2147221232
pub CLASS_E_CLASSNOTAVAILABLE :: -2147221231
pub FACILITY_NULL :: 0
pub FACILITY_RPC :: 1
pub FACILITY_STORAGE :: 3
pub FACILITY_ITF :: 4
pub FACILITY_WIN32 :: 7
pub FACILITY_WINDOWS :: 8
pub succeeded :: fn(hr: i32) -> bool
pub failed :: fn(hr: i32) -> bool
pub facility :: fn(hr: i32) -> u32
pub code :: fn(hr: i32) -> u32
pub from_win32 :: fn(err: u32) -> i32

HRESULT_FROM_WIN32; 0 stays 0, negative passes through

pub ComError :: errors {
not_implemented,
no_interface,
invalid_pointer,
aborted,
failed,
unexpected,
out_of_memory,
invalid_arg,
access_denied,
bad_handle,
bounds,
changed_state,
illegal_call,
changed_mode,
class_not_registered,
not_initialized,
other,
}

common failures by name; the rest are .other

  • not_implemented: E_NOTIMPL
  • no_interface: E_NOINTERFACE
  • invalid_pointer: E_POINTER
  • aborted: E_ABORT
  • failed: E_FAIL
  • unexpected: E_UNEXPECTED
  • out_of_memory: E_OUTOFMEMORY
  • invalid_arg: E_INVALIDARG
  • access_denied: E_ACCESSDENIED
  • bad_handle: E_HANDLE
  • bounds: E_BOUNDS
  • changed_state: E_CHANGED_STATE
  • illegal_call: E_ILLEGAL_METHOD_CALL
  • changed_mode: RPC_E_CHANGED_MODE: already initialised the other way
  • class_not_registered: REGDB_E_CLASSNOTREG
  • not_initialized: CO_E_NOTINITIALIZED
  • other: any other failure
pub check :: fn(hr: i32) -> void ! ComError

ok on any success (S_FALSE too); .other loses the code, keep hr if you need it

pub IUnknownVtbl :: struct {
query_interface: extern fn(*IUnknown, *const Guid, **void) -> i32,
add_ref: extern fn(*IUnknown) -> u32,
release: extern fn(*IUnknown) -> u32,
}
pub IUnknown :: struct {
vtbl: *IUnknownVtbl,
}
pub query_interface :: fn(self: *Self, iid: *const Guid, out: **void) -> i32

on success *out has its own ref to release; null on E_NOINTERFACE

pub add_ref :: fn(self: *Self) -> u32

returns the count; diagnostics only, don’t branch on it

pub release :: fn(self: *Self) -> u32

last ref destroys the object, pointer is dead after; count is diagnostics only

pub IInspectableVtbl :: struct {
query_interface: extern fn(*IInspectable, *const Guid, **void) -> i32,
add_ref: extern fn(*IInspectable) -> u32,
release: extern fn(*IInspectable) -> u32,
get_iids: extern fn(*IInspectable, *u32, **Guid) -> i32,
get_runtime_class_name: extern fn(*IInspectable, *usize) -> i32,
get_trust_level: extern fn(*IInspectable, *i32) -> i32,
}

base of every WinRT interface; read/release its HSTRING with std.winrt

  • get_iids: ULONG*, IID**: free the array with CoTaskMemFree
  • get_runtime_class_name: HSTRING*: an owned string
  • get_trust_level: TrustLevel*
pub IInspectable :: struct {
vtbl: *IInspectableVtbl,
}
pub add_ref :: fn(self: *Self) -> u32
pub release :: fn(self: *Self) -> u32
pub query_interface :: fn(self: *Self, iid: *const Guid, out: **void) -> i32
pub as_unknown :: fn(self: *Self) -> *IUnknown

same object; first three vtable entries match

pub IActivationFactoryVtbl :: struct {
query_interface: extern fn(*IActivationFactory, *const Guid, **void) -> i32,
add_ref: extern fn(*IActivationFactory) -> u32,
release: extern fn(*IActivationFactory) -> u32,
get_iids: extern fn(*IActivationFactory, *u32, **Guid) -> i32,
get_runtime_class_name: extern fn(*IActivationFactory, *usize) -> i32,
get_trust_level: extern fn(*IActivationFactory, *i32) -> i32,
activate_instance: extern fn(*IActivationFactory, **IInspectable) -> i32,
}

WinRT class factory, default construction

pub IActivationFactory :: struct {
vtbl: *IActivationFactoryVtbl,
}
pub add_ref :: fn(self: *Self) -> u32
pub release :: fn(self: *Self) -> u32
pub activate_instance :: fn(self: *Self, out: **IInspectable) -> i32

default ctor; *out gets an owned IInspectable

pub BASE_TRUST :: 0

TrustLevel (inspectable.h)

pub PARTIAL_TRUST :: 1
pub FULL_TRUST :: 2
pub RefCount :: struct {
n: u32,
}

–– RefCount –– atomic, thread-safe; start at 1, free your object when release() returns 0

pub add :: fn(self: *Self) -> u32

returns the new count

pub release :: fn(self: *Self) -> u32

returns the new count; release at zero is a caller bug, traps in checked builds

pub get :: fn(self: *Self) -> u32

snapshot

pub new_refcount :: fn() -> RefCount

starts at 1, the creator’s ref