com.go 11 KB

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