I was loading in some old VB functions from VBA, and mostly got everything updated to VB.NET, but there are function declarations for functions in "wininet.dll" which don't seem to match up correctly.
The Error I'm getting is:
Exception Thrown: Managed Debugging Assistant, 'PInvokeStackImbalance':...
The long and short of it is that the length of the declared arguments needs to be explicit and it isn't matching up to the real functions in the dll.
I looked this up and I can get by just removing the checks, but it will have a "stack imbalance" and eventually eat up all the stack over time as these calls are made. Also, these are called "unmanaged" dlls, and some declarations have been put up on a PInvoke function wiki at http://pinvoke.net. This wiki does have some of the function calls I'm using, but not all of them. A few of them I had to guess at some things, and that didn't work out.
Most of the changes from what I copied from the older code were changing from long
to int32
or integer
, and a few changes to IntPtr
, which was never used in the old code. I assume this gets all the integer sizes correct (i.e. 16/32/64 bits), which is probably where most of the problems were. One case though, was a change from long
to string()
, which seems a bit odd and didn't compile okay.
So, how do I actually look up the function lengths in the dll and match the API?
I looked up a few things, but when I try to add a reference to c:\windows\system32\wininet.dll to my VB.NET project in Visual Studio, it says I can't add it. This appears to stop me from being able to use the Object or Assembly browser in Visual Studio. It doesn't appear to be a COM object. Any help here?
For reference, here's the old code that is failing:
Private Declare Function InternetOpen Lib "wininet.dll" Alias "InternetOpenA" ( _
ByVal Agent As String, ByVal AccessType As Long, ByVal ProxyName As String, _
ByVal ProxyBypass As String, ByVal Flags As Long) As Long
Private Declare Function InternetConnect Lib "wininet.dll" Alias "InternetConnectA" ( _
ByVal hInternetSession As Long, ByVal ServerName As String, ByVal ServerPort As Integer, ByVal UserName As String, _
ByVal Password As String, ByVal Service As Long, ByVal Flags As Long, ByVal Context As Long) As Long
Private Declare Function InternetCloseHandle Lib "wininet.dll" ( _
ByVal hInet As Long) As Boolean
Private Declare Function InternetReadFile Lib "wininet.dll" ( _
ByVal hConnect As Long, ByVal Buffer As String, ByVal NumberOfBytesToRead As Long, _
NumberOfBytesRead As Long) As Boolean
Private Declare Function HttpOpenRequest Lib "wininet.dll" Alias "HttpOpenRequestA" ( _
ByVal hHttpSession As Long, ByVal Verb As String, ByVal ObjectName As String, ByVal Version As String, _
ByVal Referer As String, ByVal AcceptTypes As Long, ByVal Flags As Long, Context As Long) As Long
Private Declare Function HttpSendRequest Lib "wininet.dll" Alias "HttpSendRequestA" ( _
ByVal hHttpRequest As Long, ByVal Headers As String, ByVal HeadersLength As Long, _
ByVal sOptional As String, ByVal OptionalLength As Long) As Boolean
As already noted by Hans Passant you should use the managed alternatives instead.
However to answer your actual question: You basically just need to check the MSDN documentation article Windows Data Types, and based on a type's declaration determine the respective .NET type.
For instance, a
DWORD
:In this case we can either go by the range (0 - 4294967295) or the definition (
unsigned long
) in order to determine that this should be an unsigned 32-bit integer (UInt32
orUInteger
). In C/C++ along
is the same thing as anint
, which is why it's mapped to an integer and not theLong/ULong
.Here's a summary of the most common types:
(Big thanks to David Heffernan for helping me correct some of the string declarations!)