2016-10-10 71 views
4

我试图调用WinHttpGetIEProxyConfigForCurrentUser函数来获取自动检测到的IE代理设置。它接受根据documentation的inout结构参数。我使用下面的代码:golang:winapi调用结构参数

func GetProxySettings() { 
    winhttp, _ := syscall.LoadLibrary("winhttp.dll") 
    getIEProxy, _ := syscall.GetProcAddress(winhttp, "WinHttpGetIEProxyConfigForCurrentUser") 

    settings := new(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG) 
    var nargs uintptr = 1 

    ret, _, callErr := syscall.Syscall(uintptr(getIEProxy), nargs, uintptr(unsafe.Pointer(&settings)), 0, 0) 
    fmt.Println(ret, callErr) 
    if settings != nil { 
     fmt.Println(settings.fAutoDetect) 
     fmt.Println(settings.lpszAutoConfigUrl) 
     fmt.Println(settings.lpszProxy) 
     fmt.Println(settings.lpszProxyBypass) 
    } 
} 

type WINHTTP_CURRENT_USER_IE_PROXY_CONFIG struct { 
    fAutoDetect  bool 
    lpszAutoConfigUrl string 
    lpszProxy   string 
    lpszProxyBypass string 
} 

它看起来像调用成功,settings不是零,但只要我访问它,我得到的恐慌。下面是输出:

1 The operation completed successfully. 
panic: runtime error: invalid memory address or nil pointer dereference 
[signal 0xc0000005 code=0x0 addr=0x1 pc=0x4d2bb4] 
+1

Go字符串与C字符串不同,在这种情况下,文档看起来像字段应该是宽字符(?),所以这些应该可能是'* uint16'而不是字符串。你还传递一个指向系统调用的指针,它只需要一个指针。摆脱参数中额外的'&'。 – JimB

+0

感谢您的提示。如何将'* uint16'转换为去串?我发现'UTF16PtrFromString'做了相反的转换,但没有任何东西可以转换回来。 – rosencreuz

回答

4

您需要将指针传递给您已经使用new函数创建的已分配结构。从系统调用中删除额外的&; uintptr(unsafe.Pointer(settings))

您还需要具有与系统调用预期的C结构具有相同布局的结构。结构定义是这样的:

typedef struct { 
    BOOL fAutoDetect; 
    LPWSTR lpszAutoConfigUrl; 
    LPWSTR lpszProxy; 
    LPWSTR lpszProxyBypass; 
} WINHTTP_CURRENT_USER_IE_PROXY_CONFIG; 

这应该转化为

type WINHTTP_CURRENT_USER_IE_PROXY_CONFIG struct { 
    fAutoDetect  bool 
    lpszAutoConfigUrl *uint16 
    lpszProxy   *uint16 
    lpszProxyBypass *uint16 
} 

每个那些LPWSTR领域将是一个空结束,16位/字符的字符串。为了将它们转换为Go字符串,首先需要将*uint16转换为[]uint16切片,然后将该切片解码为utf8字符串。

// Convert a *uint16 C string to a Go String 
func GoWString(s *uint16) string { 
    if s == nil { 
     return "" 
    } 

    p := (*[1<<30 - 1]uint16)(unsafe.Pointer(s)) 

    // find the string length 
    sz := 0 
    for p[sz] != 0 { 
     sz++ 
    } 

    return string(utf16.Decode(p[:sz:sz])) 
} 
1

你把这里的地址的地址:

// The type of settings is *WINHTTP_CURRENT_USER_IE_PROXY_CONFIG 
settings := new(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG) 

// ... 

// The type of &settings is **WINHTTP_CURRENT_USER_IE_PROXY_CONFIG 
ret, _, callErr := syscall.Syscall(uintptr(getIEProxy), nargs, uintptr(unsafe.Pointer(&settings)), 0, 0) 

取出&Syscall调用一个它应该工作。

+0

你说得对。但是'lpszProxy'的类型仍然存在问题。 'string'似乎并不正确。我试过'* uint16',但我找不到将其转换为字符串的方法。 – rosencreuz