github.com/hspan/go-ole@v0.0.0/com.go (about) 1 // +build windows 2 3 package ole 4 5 import ( 6 "syscall" 7 "unicode/utf16" 8 "unsafe" 9 ) 10 11 var ( 12 procCoInitialize, _ = modole32.FindProc("CoInitialize") 13 procCoInitializeEx, _ = modole32.FindProc("CoInitializeEx") 14 procCoUninitialize, _ = modole32.FindProc("CoUninitialize") 15 procCoCreateInstance, _ = modole32.FindProc("CoCreateInstance") 16 procCoTaskMemFree, _ = modole32.FindProc("CoTaskMemFree") 17 procCLSIDFromProgID, _ = modole32.FindProc("CLSIDFromProgID") 18 procCLSIDFromString, _ = modole32.FindProc("CLSIDFromString") 19 procStringFromCLSID, _ = modole32.FindProc("StringFromCLSID") 20 procStringFromIID, _ = modole32.FindProc("StringFromIID") 21 procIIDFromString, _ = modole32.FindProc("IIDFromString") 22 procCoGetObject, _ = modole32.FindProc("CoGetObject") 23 procGetUserDefaultLCID, _ = modkernel32.FindProc("GetUserDefaultLCID") 24 procCopyMemory, _ = modkernel32.FindProc("RtlMoveMemory") 25 procVariantInit, _ = modoleaut32.FindProc("VariantInit") 26 procVariantClear, _ = modoleaut32.FindProc("VariantClear") 27 procVariantTimeToSystemTime, _ = modoleaut32.FindProc("VariantTimeToSystemTime") 28 procSysAllocString, _ = modoleaut32.FindProc("SysAllocString") 29 procSysAllocStringLen, _ = modoleaut32.FindProc("SysAllocStringLen") 30 procSysFreeString, _ = modoleaut32.FindProc("SysFreeString") 31 procSysStringLen, _ = modoleaut32.FindProc("SysStringLen") 32 procCreateDispTypeInfo, _ = modoleaut32.FindProc("CreateDispTypeInfo") 33 procCreateStdDispatch, _ = modoleaut32.FindProc("CreateStdDispatch") 34 procGetActiveObject, _ = modoleaut32.FindProc("GetActiveObject") 35 36 procGetMessageW, _ = moduser32.FindProc("GetMessageW") 37 procDispatchMessageW, _ = moduser32.FindProc("DispatchMessageW") 38 ) 39 40 // coInitialize initializes COM library on current thread. 41 // 42 // MSDN documentation suggests that this function should not be called. Call 43 // CoInitializeEx() instead. The reason has to do with threading and this 44 // function is only for single-threaded apartments. 45 // 46 // That said, most users of the library have gotten away with just this 47 // function. If you are experiencing threading issues, then use 48 // CoInitializeEx(). 49 func coInitialize() (err error) { 50 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms678543(v=vs.85).aspx 51 // Suggests that no value should be passed to CoInitialized. 52 // Could just be Call() since the parameter is optional. <-- Needs testing to be sure. 53 hr, _, _ := procCoInitialize.Call(uintptr(0)) 54 if hr != 0 { 55 err = NewError(hr) 56 } 57 return 58 } 59 60 // coInitializeEx initializes COM library with concurrency model. 61 func coInitializeEx(coinit uint32) (err error) { 62 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms695279(v=vs.85).aspx 63 // Suggests that the first parameter is not only optional but should always be NULL. 64 hr, _, _ := procCoInitializeEx.Call(uintptr(0), uintptr(coinit)) 65 if hr != 0 { 66 err = NewError(hr) 67 } 68 return 69 } 70 71 // CoInitialize initializes COM library on current thread. 72 // 73 // MSDN documentation suggests that this function should not be called. Call 74 // CoInitializeEx() instead. The reason has to do with threading and this 75 // function is only for single-threaded apartments. 76 // 77 // That said, most users of the library have gotten away with just this 78 // function. If you are experiencing threading issues, then use 79 // CoInitializeEx(). 80 func CoInitialize(p uintptr) (err error) { 81 // p is ignored and won't be used. 82 // Avoid any variable not used errors. 83 p = uintptr(0) 84 return coInitialize() 85 } 86 87 // CoInitializeEx initializes COM library with concurrency model. 88 func CoInitializeEx(p uintptr, coinit uint32) (err error) { 89 // Avoid any variable not used errors. 90 p = uintptr(0) 91 return coInitializeEx(coinit) 92 } 93 94 // CoUninitialize uninitializes COM Library. 95 func CoUninitialize() { 96 procCoUninitialize.Call() 97 } 98 99 // CoTaskMemFree frees memory pointer. 100 func CoTaskMemFree(memptr uintptr) { 101 procCoTaskMemFree.Call(memptr) 102 } 103 104 // CLSIDFromProgID retrieves Class Identifier with the given Program Identifier. 105 // 106 // The Programmatic Identifier must be registered, because it will be looked up 107 // in the Windows Registry. The registry entry has the following keys: CLSID, 108 // Insertable, Protocol and Shell 109 // (https://msdn.microsoft.com/en-us/library/dd542719(v=vs.85).aspx). 110 // 111 // programID identifies the class id with less precision and is not guaranteed 112 // to be unique. These are usually found in the registry under 113 // HKEY_LOCAL_MACHINE\SOFTWARE\Classes, usually with the format of 114 // "Program.Component.Version" with version being optional. 115 // 116 // CLSIDFromProgID in Windows API. 117 func CLSIDFromProgID(progId string) (clsid *GUID, err error) { 118 var guid GUID 119 lpszProgID := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(progId))) 120 hr, _, _ := procCLSIDFromProgID.Call(lpszProgID, uintptr(unsafe.Pointer(&guid))) 121 if hr != 0 { 122 err = NewError(hr) 123 } 124 clsid = &guid 125 return 126 } 127 128 // CLSIDFromString retrieves Class ID from string representation. 129 // 130 // This is technically the string version of the GUID and will convert the 131 // string to object. 132 // 133 // CLSIDFromString in Windows API. 134 func CLSIDFromString(str string) (clsid *GUID, err error) { 135 var guid GUID 136 lpsz := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(str))) 137 hr, _, _ := procCLSIDFromString.Call(lpsz, uintptr(unsafe.Pointer(&guid))) 138 if hr != 0 { 139 err = NewError(hr) 140 } 141 clsid = &guid 142 return 143 } 144 145 // StringFromCLSID returns GUID formated string from GUID object. 146 func StringFromCLSID(clsid *GUID) (str string, err error) { 147 var p *uint16 148 hr, _, _ := procStringFromCLSID.Call(uintptr(unsafe.Pointer(clsid)), uintptr(unsafe.Pointer(&p))) 149 if hr != 0 { 150 err = NewError(hr) 151 } 152 str = LpOleStrToString(p) 153 return 154 } 155 156 // IIDFromString returns GUID from program ID. 157 func IIDFromString(progId string) (clsid *GUID, err error) { 158 var guid GUID 159 lpsz := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(progId))) 160 hr, _, _ := procIIDFromString.Call(lpsz, uintptr(unsafe.Pointer(&guid))) 161 if hr != 0 { 162 err = NewError(hr) 163 } 164 clsid = &guid 165 return 166 } 167 168 // StringFromIID returns GUID formatted string from GUID object. 169 func StringFromIID(iid *GUID) (str string, err error) { 170 var p *uint16 171 hr, _, _ := procStringFromIID.Call(uintptr(unsafe.Pointer(iid)), uintptr(unsafe.Pointer(&p))) 172 if hr != 0 { 173 err = NewError(hr) 174 } 175 str = LpOleStrToString(p) 176 return 177 } 178 179 // CreateInstance of single uninitialized object with GUID. 180 func CreateInstance(clsid *GUID, iid *GUID) (unk *IUnknown, err error) { 181 if iid == nil { 182 iid = IID_IUnknown 183 } 184 hr, _, _ := procCoCreateInstance.Call( 185 uintptr(unsafe.Pointer(clsid)), 186 0, 187 CLSCTX_SERVER, 188 uintptr(unsafe.Pointer(iid)), 189 uintptr(unsafe.Pointer(&unk))) 190 if hr != 0 { 191 err = NewError(hr) 192 } 193 return 194 } 195 196 // GetActiveObject retrieves pointer to active object. 197 func GetActiveObject(clsid *GUID, iid *GUID) (unk *IUnknown, err error) { 198 if iid == nil { 199 iid = IID_IUnknown 200 } 201 hr, _, _ := procGetActiveObject.Call( 202 uintptr(unsafe.Pointer(clsid)), 203 uintptr(unsafe.Pointer(iid)), 204 uintptr(unsafe.Pointer(&unk))) 205 if hr != 0 { 206 err = NewError(hr) 207 } 208 return 209 } 210 211 type BindOpts struct { 212 CbStruct uint32 213 GrfFlags uint32 214 GrfMode uint32 215 TickCountDeadline uint32 216 } 217 218 // GetObject retrieves pointer to active object. 219 func GetObject(programID string, bindOpts *BindOpts, iid *GUID) (unk *IUnknown, err error) { 220 if bindOpts != nil { 221 bindOpts.CbStruct = uint32(unsafe.Sizeof(BindOpts{})) 222 } 223 if iid == nil { 224 iid = IID_IUnknown 225 } 226 hr, _, _ := procCoGetObject.Call( 227 uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(programID))), 228 uintptr(unsafe.Pointer(bindOpts)), 229 uintptr(unsafe.Pointer(iid)), 230 uintptr(unsafe.Pointer(&unk))) 231 if hr != 0 { 232 err = NewError(hr) 233 } 234 return 235 } 236 237 // VariantInit initializes variant. 238 func VariantInit(v *VARIANT) (err error) { 239 hr, _, _ := procVariantInit.Call(uintptr(unsafe.Pointer(v))) 240 if hr != 0 { 241 err = NewError(hr) 242 } 243 return 244 } 245 246 // VariantClear clears value in Variant settings to VT_EMPTY. 247 func VariantClear(v *VARIANT) (err error) { 248 hr, _, _ := procVariantClear.Call(uintptr(unsafe.Pointer(v))) 249 if hr != 0 { 250 err = NewError(hr) 251 } 252 return 253 } 254 255 // SysAllocString allocates memory for string and copies string into memory. 256 func SysAllocString(v string) (ss *int16) { 257 pss, _, _ := procSysAllocString.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(v)))) 258 ss = (*int16)(unsafe.Pointer(pss)) 259 return 260 } 261 262 // SysAllocStringLen copies up to length of given string returning pointer. 263 func SysAllocStringLen(v string) (ss *int16) { 264 utf16 := utf16.Encode([]rune(v + "\x00")) 265 ptr := &utf16[0] 266 267 pss, _, _ := procSysAllocStringLen.Call(uintptr(unsafe.Pointer(ptr)), uintptr(len(utf16)-1)) 268 ss = (*int16)(unsafe.Pointer(pss)) 269 return 270 } 271 272 // SysFreeString frees string system memory. This must be called with SysAllocString. 273 func SysFreeString(v *int16) (err error) { 274 hr, _, _ := procSysFreeString.Call(uintptr(unsafe.Pointer(v))) 275 if hr != 0 { 276 err = NewError(hr) 277 } 278 return 279 } 280 281 // SysStringLen is the length of the system allocated string. 282 func SysStringLen(v *int16) uint32 { 283 l, _, _ := procSysStringLen.Call(uintptr(unsafe.Pointer(v))) 284 return uint32(l) 285 } 286 287 // CreateStdDispatch provides default IDispatch implementation for IUnknown. 288 // 289 // This handles default IDispatch implementation for objects. It haves a few 290 // limitations with only supporting one language. It will also only return 291 // default exception codes. 292 func CreateStdDispatch(unk *IUnknown, v uintptr, ptinfo *IUnknown) (disp *IDispatch, err error) { 293 hr, _, _ := procCreateStdDispatch.Call( 294 uintptr(unsafe.Pointer(unk)), 295 v, 296 uintptr(unsafe.Pointer(ptinfo)), 297 uintptr(unsafe.Pointer(&disp))) 298 if hr != 0 { 299 err = NewError(hr) 300 } 301 return 302 } 303 304 // CreateDispTypeInfo provides default ITypeInfo implementation for IDispatch. 305 // 306 // This will not handle the full implementation of the interface. 307 func CreateDispTypeInfo(idata *INTERFACEDATA) (pptinfo *IUnknown, err error) { 308 hr, _, _ := procCreateDispTypeInfo.Call( 309 uintptr(unsafe.Pointer(idata)), 310 uintptr(GetUserDefaultLCID()), 311 uintptr(unsafe.Pointer(&pptinfo))) 312 if hr != 0 { 313 err = NewError(hr) 314 } 315 return 316 } 317 318 // copyMemory moves location of a block of memory. 319 func copyMemory(dest unsafe.Pointer, src unsafe.Pointer, length uint32) { 320 procCopyMemory.Call(uintptr(dest), uintptr(src), uintptr(length)) 321 } 322 323 // GetUserDefaultLCID retrieves current user default locale. 324 func GetUserDefaultLCID() (lcid uint32) { 325 ret, _, _ := procGetUserDefaultLCID.Call() 326 lcid = uint32(ret) 327 return 328 } 329 330 // GetMessage in message queue from runtime. 331 // 332 // This function appears to block. PeekMessage does not block. 333 func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, err error) { 334 r0, _, err := procGetMessageW.Call(uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(MsgFilterMin), uintptr(MsgFilterMax)) 335 ret = int32(r0) 336 return 337 } 338 339 // DispatchMessage to window procedure. 340 func DispatchMessage(msg *Msg) (ret int32) { 341 r0, _, _ := procDispatchMessageW.Call(uintptr(unsafe.Pointer(msg))) 342 ret = int32(r0) 343 return 344 }