如何使 WinHttpCrackUrl 在 64 位下工作

Posted

技术标签:

【中文标题】如何使 WinHttpCrackUrl 在 64 位下工作【英文标题】:How to make WinHttpCrackUrl work in 64-bit 【发布时间】:2013-06-13 22:46:13 【问题描述】:

我有 Visual Basic for Applications 代码,它使用 WinHttp 并且与在 32 位 Windows XP 上运行的 32 位 Office 2010 完美配合。相同的代码无法在 64 位 Windows 8 上的 64 位 Office 2013 上正常运行,即使它编译得很好。

问题是WinHttpCrackUrl() 在 Windows 8 上返回错误 87“参数不正确”。

我已经仔细检查和三重检查了所有指针在适当的代码中都声明为 LongPtr。我做错了什么?

这是在 32 位 Excel/Windows 上运行良好,但在 64 位 Excel/Windows 上运行失败的代码:

Private Type URL_COMPONENTS
    dwStructSize      As Long
    lpszScheme        As LongPtr
    dwSchemeLength    As Long
    nScheme           As Long
    lpszHostName      As LongPtr
    dwHostNameLength  As Long
    nPort             As Long
    lpszUserName      As LongPtr
    dwUserNameLength  As Long
    lpszPassword      As LongPtr
    dwPasswordLength  As Long
    lpszUrlPath       As LongPtr
    dwUrlPathLength   As Long
    lpszExtraInfo     As LongPtr
    dwExtraInfoLength As Long
End Type

Private Declare PtrSafe Function WinHttpCrackUrl Lib "WinHTTP" ( _
    ByVal pwszUrl As LongPtr, _
    ByVal dwUrlLength As Long, _
    ByVal dwFlags As Long, _
    ByRef lpUrlComponents As URL_COMPONENTS) As Long

Sub Test()
    Dim result as Long
    Dim URLComp As URL_COMPONENTS
    Dim mURL as String
    mURL = "http://www.***.com" & vbNullChar

    With URLComp
        .dwStructSize = Len(URLComp)
        .dwHostNameLength = -1
        .dwSchemeLength = -1
        .dwUrlPathLength = -1
    End With

    result = WinHttpCrackUrl(StrPtr(mURL), 0, 0, URLComp)

    ' Prints 1 on 32-bit Excel/Windows (indicating success)
    ' Prints 0 on 64-bit Excel/Windows (indicating failure)
    Debug.Print result

    ' Prints 87 on 64-bit Excel/Windows ("The parameter is incorrect.")
    Debug.Print err.LastDllError
End Sub

【问题讨论】:

+1 写得非常好。获得可以粘贴并立即运行的代码是一种乐趣。如果所有 SO 问题都写得这么好。 @DavidHeffernan 谢谢,非常感谢! 【参考方案1】:

struct 在 C++ 代码中是对齐的,但 VBA 结构是打包的。在 32 位中,对于您的结构,这并不重要,因为所有成员都有对齐 4。但在 64 位中,指针需要 8 字节对齐,并且结构有一些额外的填充。像这样放进去:

Private Type URL_COMPONENTS
    dwStructSize      As Long
    padding1          As Long
    lpszScheme        As LongPtr
    dwSchemeLength    As Long
    nScheme           As Long
    lpszHostName      As LongPtr
    dwHostNameLength  As Long
    nPort             As Long
    lpszUserName      As LongPtr
    dwUserNameLength  As Long
    padding2          As Long
    lpszPassword      As LongPtr
    dwPasswordLength  As Long
    padding3          As Long
    lpszUrlPath       As LongPtr
    dwUrlPathLength   As Long
    padding4          As Long
    lpszExtraInfo     As LongPtr
    dwExtraInfoLength As Long
    padding5          As Long
End Type

我猜你会想要一些条件编译来切换更好的 32 位和 64 位版本,但我必须承认不知道如何使用 VBA 来做到这一点。

【讨论】:

非常感谢!实际上,我之前(在使用低级 SAFEARRAY 结构时)偶然发现了这种对齐要求,但没有认识到它是什么并且未能概括。 条件编译开关是#If Win64 Then ... #End If,应该放在每个paddings周围。

以上是关于如何使 WinHttpCrackUrl 在 64 位下工作的主要内容,如果未能解决你的问题,请参考以下文章

如何使代码兼容 32 位和 64 位

如何使 Android 的 aapt 和 adb 在没有 ia32-libs 的 64 位 Ubuntu 上工作(适用于版本 12、13 和 14)

如何使base64解码函数以本地语言解码字符串?

如何防止 MS Access 连接模式和表名,从而使它们超过 64 个字符的限制?

如何使 rpm 自动安装依赖项

如何使 TensorFlow Hub 模型为 TensorFlow Serving REST 请求做好准备(使用 base64 编码图像)?