如何为非托管dll找出正确的参数结构? [英] How do I figure out the correct argument structure for an unmanaged dll?

查看:88
本文介绍了如何为非托管dll找出正确的参数结构?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从VBA加载一些旧的VB函数,并且大部分内容都已更新到VB.NET,但是"wininet.dll"中的函数声明似乎与之不正确.

我遇到的错误是:

引发的异常:托管调试助手,"PInvokeStackImbalance":...

长或短的地方是声明的参数的长度必须是明确的,并且与dll中的实际函数不匹配.

我检查了一下,只要删除支票就可以得到,但是这会产生堆栈不平衡",并最终随着调用的进行而逐渐耗尽所有堆栈.而且,这些被称为非托管" dll,并且一些声明已放置在PInvoke函数Wiki的 http://pinvoke.net上.该Wiki确实有一些我正在使用的函数调用,但不是全部.其中一些我不得不猜测一些事情,但没有解决.

与我从旧代码中复制的内容相比,大多数更改是从long更改为int32integer,并且对IntPtr进行了一些更改,这在旧代码中从未使用过.我假设这可以使所有整数大小正确(即16/32/64位),这可能是大多数问题所在的地方.但是,有一种情况是将long更改为string(),这似乎有些奇怪,并且编译不正确.

那么,我实际上如何查找dll中的函数长度并匹配API?

我查了几件事,但是当我尝试在Visual Studio的VB.NET项目中添加对c:\ windows \ system32 \ wininet.dll的引用时,它说我无法添加它.这似乎使我无法使用Visual Studio中的对象"或程序集"浏览器.它似乎不是COM对象.这里有帮助吗?

作为参考,这是失败的旧代码:

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

解决方案

已经 David Heffernan 帮助我纠正了一些字符串声明!)

 +------------------+------------------------------------------------------+
|   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#)             |
+------------------+------------------------------------------------------+
 

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:

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#)             |
+------------------+------------------------------------------------------+

这篇关于如何为非托管dll找出正确的参数结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆