为了账号安全,请及时绑定邮箱和手机立即绑定

COM 中的 UTF-16 字符串

COM 中的 UTF-16 字符串

Go
至尊宝的传说 2022-05-18 10:38:38
请有人解释一下我尝试调用 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-olefunc 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 ....}
查看完整描述

1 回答

?
函数式编程

TA贡献1807条经验 获得超9个赞

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 *uint16


func 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))


查看完整回答
反对 回复 2022-05-18
  • 1 回答
  • 0 关注
  • 94 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信