com.go 12 KB

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