Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
819 views
in Technique[技术] by (71.8m points)

vb.net - How do I figure out the correct argument structure for an unmanaged dll?

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:windowssystem32wininet.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
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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:

DWORD
A 32-bit unsigned integer. The range is 0 through 4294967295 decimal.

This type is declared in IntSafe.h as follows:

typedef unsigned long 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 or UInteger). In C/C++ a long is the same thing as an int, which is why it's mapped to an integer and not the Long/ULong.

Here's a summary of the most common types:

(Big thanks to David Heffernan for helping me correct some of the string declarations!)

+------------------+------------------------------------------------------+
|   Windows Type   |                   .NET equivalent                    |
+------------------+------------------------------------------------------+
| BOOL             | <MarshalAs(UnmanagedType.Bool)> Boolean  (vb.net)    |
| BOOL             | [MarshalAs(UnmanagedType.Bool)] bool     (c#)        |
| BYTE             | Byte   / Byte     (vb.net) / byte  (c#)              |
| CHAR             | Char   / Char     (vb.net) / char  (c#)              |
| DWORD            | UInt32 / UInteger (vb.net) / uint  (c#)              |
| DWORDLONG        | UInt64 / ULong    (vb.net) / ulong (c#)              |
| DWORD_PTR        | UIntPtr                                              |
| FLOAT            | Single / Single   (vb.net) / float (c#)              |
|                  |                                                      |
| HANDLE           | IntPtr                                               |
| HBITMAP          | IntPtr                                               |
| HCURSOR          | IntPtr                                               |
| HDESK            | IntPtr                                               |
| HDC              | IntPtr                                               |
| HICON            | IntPtr                                               |
| HINSTANCE        | IntPtr                                               |
| HRESULT          | Int32 / Integer (vb.net) / int (c#)                  |
| HWND             | IntPtr                                               |
|                  |                                                      |
| INT              | Int32 / Integer (vb.net) / int (c#)                  |
| INT_PTR          | IntPtr                                               |
| INT8             | SByte                                                |
| INT16            | Int16 / Short   (vb.net) / short (c#)                |
| INT32            | Int32 / Integer (vb.net) / int   (c#)                |
| INT64            | Int64 / Long    (vb.net) / long  (c#)                |
| LONG             | Int32 / Integer (vb.net) / int   (c#)                |
| LONGLONG         | Int64 / Long    (vb.net) / long  (c#)                |
| LONG_PTR         | IntPtr                                               |
| LPARAM           | IntPtr                                               |
|                  |                                                      |
| LPCSTR           | String (Specify CharSet.Ansi in DllImport)           |
| LPCTSTR          | String                                               |
| LPCWSTR          | String (Specify CharSet.Unicode in DllImport)        |
| LPDWORD          | (= DWORD,  declared as ByRef (vb.net) / ref (c#))    |
| LPHANDLE         | (= HANDLE, declared as ByRef (vb.net) / ref (c#))    |
| LPINT            | IntPtr                                               |
| LPLONG           | IntPtr                                               |
|                  |                                                      |
| LPSTR            | StringBuilder (Specify CharSet.Ansi in DllImport)    |
| LPTSTR           | StringBuilder                                        |
| LPVOID           | IntPtr                                               |
| LPWORD           | (= WORD, declared as ByRef (vb.net) / ref (c#))      |
| LPWSTR           | StringBuilder (Specify CharSet.Unicode in DllImport) |
|                  |                                                      |
| QWORD            | UInt64 / ULong (vb.net) / ulong (c#)                 |
| SHORT            | Int16  / Short (vb.net) / short (c#)                 |
| SIZE_T           | UIntPtr                                              |
| UCHAR            | Byte   / Byte    (vb.net) / byte (c#)                 |
| UINT             | UInt32 / UInteger (vb.net) / uint  (c#)                 |
| UINT_PTR         | IntPtr                                               |
| UINT8            | Byte   / Byte     (vb.net) / byte   (c#)             |
| UINT16           | UInt16 / UShort   (vb.net) / ushort (c#)             |
| UINT32           | UInt32 / UInteger (vb.net) / uint    (c#)             |
| UINT64           | UInt64 / ULong    (vb.net) / ulong   (c#)             |
| ULONG            | UInt32 / UInteger (vb.net) / uint    (c#)             |
| ULONGLONG        | UInt64 / ULong    (vb.net) / ulong   (c#)             |
| ULONG_PTR        | UIntPtr                                              |
| USHORT           | UInt16 / UShort   (vb.net) / ushort (c#)             |
| WORD             | UInt16 / UShort   (vb.net) / ushort (c#)             |
+------------------+------------------------------------------------------+

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...