Reputation: 1960
I have Visual Basic for Applications code that uses WinHttp
and works flawlessly with 32-bit Office 2010 running on 32-bit Windows XP. The same code fails to run properly on 64-bit Office 2013 on 64-bit Windows 8, even though it compiles fine.
The problem is that WinHttpCrackUrl()
returns an error 87 "The parameter is incorrect" on Windows 8.
I have double-checked and triple-checked that all pointers are declared as LongPtr in the code where appropriate. What am I doing wrong?
Here is the code that runs fine on 32-bit Excel/Windows, but fails to run on 64-bit 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.stackoverflow.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
Upvotes: 5
Views: 1161
Reputation: 21
Since this thread came up in my searches several times, despite being ancient-- OP's problem was using Len instead of LenB.
The padding didn't need to be manually added. VBA follows normal packing rules and will insert that padding automatically. The original code was fine besides needing .dwStructSize = LenB(URLComp) instead of Len(URLComp). You almost always should use LenB, which includes padding bytes, while Len includes only what you see in the editor, for UDT sizes.
Don't go crazy with padding and conditional compilation when you don't have to.
PS- Both posts are incorrect in that nPort should be an Integer (typedef WORD INTERNET_PORT;). Making it a Long doesn't break the call because there's padding bytes there when it's Integer, but it will give the port as zero always, even if you set it.
Upvotes: 0
Reputation: 612854
The struct
is aligned in the C++ code, but VBA structs are packed. In 32 bit, for your struct, it does not matter since all members have alignment 4. But in 64 bit the pointers need 8 byte alignment and the struct has some extra padding. Put it in like this:
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
I guess you'll want some conditional compilation to switch better 32 and 64 bit versions but I must confess to having no idea how to do that with VBA.
Upvotes: 5