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