COM 中的 UTF-16 字符串

请有人解释一下我尝试调用 COM 函数的 Go 指针魔法


func (p *IServer) Authorize(user, pass string) error {

  UserName := ole.SysAllocString(login.UserName)

  defer ole.SysFreeString(UserName)

  UserPsw := ole.SysAllocString(login.UserPsw)

  defer ole.SysFreeString(UserPsw)  


  // HRESULT IServer::Authorize([in] BSTR UserName, [in] BSTR UserPsw, [out] VARIANT* SID, [out, retval] long* Result)

  hr, _, _ := Call(p.VTable().Authorize,

    uintptr(unsafe.Pointer(p)),

    uintptr(unsafe.Pointer(UserName)),

    uintptr(unsafe.Pointer(UserPsw)),

    uintptr(unsafe.Pointer(sid)),

    uintptr(unsafe.Pointer(&res)))


   ...

}

此代码运行良好,但是当我将转换替换为


UserName := syscall.StringToUTF16Ptr(login.UserName)

UserPsw := syscall.StringToUTF16Ptr(login.UserPsw)

它会导致访问违规!来自 go-ole


func SysAllocString(v string) (ss *int16) {

  pss, _, _ := procSysAllocString.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(v))))

  ss = (*int16)(unsafe.Pointer(pss))

  return

}

我究竟做错了什么?


更新:在 C/C++ 中 wchar* 指针在 386/amd64 中都可以正常工作


void Authorize(IServer* p wchar* user, wchar* pass) {

   p.Authorize(user, pass ....

}


至尊宝的传说
浏览 178回答 1
1回答

函数式编程

SysAllocString 返回 BSTR 类型,com 类型对象。 typedef struct { #ifdef _WIN64     DWORD pad; #endif     DWORD size;     union {         char ptr[1];         WCHAR str[1];         DWORD dwptr[1];     } u; // take it as a starting point of the string  } bstr_t;换句话说,它是相同的 utf16 编码字符串,但前缀是其大小(Unicode 字符的长度乘以 wchar_t 的大小(2-4 字节))。出于优化的原因,它也有填充。由于它的浮动大小,最好使用 ole 包而不是重新发明轮子。如果你想自己实现它,并且 wchar_t 的大小为 int16(2 字节),那么你必须执行以下操作:(半伪代码,我没测试过)type BSTR *uint16func SysAllocString(str string) (result BSTR) {    // DWORD == int32 == rune    const padf = "\x00" // only for 64 bit system    const sizef = "\x00"    // int32 == 4 byte     // int16 == 2 byte    const wordSize = unsafe.Sizeof(int16(0))    utf16 := utf16.Encode([]rune(padf + sizef + str))    /* pad is on index 0 and 1 */    size :=  &utf16[2 /* 0 for 32 bit system */]    // set "size" field as unicode charachers length multypled by size of wchar_t    *(*rune)(unsafe.Pointer(size)) = rune((len(utf16)-2) * int(wordSize))    result = BSTR(&utf16[0])    return}// ...bstr := SysAllocString(login.UserName)uintptr(unsafe.Pointer(bstr))
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go