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  }