C# PInvoke签名与非托管目标签名不匹配
我正在尝试为modbusm.dll(win-tech.com/html/mbusocx.htm)创建一个包装器C#文件,为此我使用了dumpbin输出 文件modbusm.dll的转储C# PInvoke签名与非托管目标签名不匹配,c#,wrapper,dumpbin,modbus-tcp,C#,Wrapper,Dumpbin,Modbus Tcp,我正在尝试为modbusm.dll(win-tech.com/html/mbusocx.htm)创建一个包装器C#文件,为此我使用了dumpbin输出 文件modbusm.dll的转储 00000000 characteristics 41128817 time date stamp Fri Aug 06 00:48:47 2004 0.00 version 1 ordinal base 27 number of functions 27 numbe
00000000 characteristics
41128817 time date stamp Fri Aug 06 00:48:47 2004
0.00 version
1 ordinal base
27 number of functions
27 number of names
ordinal hint RVA name
1 0 000085BA _AbortTheCall@4
2 1 00003441 _CloseConnection@4
3 2 000033A7 _ConnectASCII@12
4 3 000033E1 _ConnectDanielsASCII@12
5 4 000033C4 _ConnectDanielsRTU@12
6 5 0000338A _ConnectRTU@12
7 6 00001019 _ConnectTCP2@12
8 7 00001000 _ConnectTCP@8
9 8 0000829A _DialCall@8
10 9 00003376 _EnableConnectionCallback@4
11 A 00003342 _EnableModbusCallback@8
12 B 00008123 _GetCallState@8
13 C 00007FD2 _GetLineDeviceName@12
14 D 00003320 _GetPollDelay@0
15 E 00003339 _Get_Modbus_DLL_Revision@0
16 F 000033FE _HookRspNotification@16
17 10 000032ED _InitializeWinSock@0
18 11 0000277C _MBAPWndProc@16
19 12 0000393F _MODBUSResponse@16
20 13 00007EAA _NumberOfLineDevices@0
21 14 00003521 _PollMODBUS@8
22 15 000039F2 _ReadDebugData@16
23 16 00003BA4 _ReadTransparentResponse@16
24 17 0000332A _SetPollDelay@4
25 18 00003313 _UnInitializeWinSock@0
26 19 00003712 _WriteMODBUS@12
27 1A 00003AB3 _WriteTransparentString@12
文件类型:DLL
节包含modbusm.dll的以下导出
00000000 characteristics
41128817 time date stamp Fri Aug 06 00:48:47 2004
0.00 version
1 ordinal base
27 number of functions
27 number of names
ordinal hint RVA name
1 0 000085BA _AbortTheCall@4
2 1 00003441 _CloseConnection@4
3 2 000033A7 _ConnectASCII@12
4 3 000033E1 _ConnectDanielsASCII@12
5 4 000033C4 _ConnectDanielsRTU@12
6 5 0000338A _ConnectRTU@12
7 6 00001019 _ConnectTCP2@12
8 7 00001000 _ConnectTCP@8
9 8 0000829A _DialCall@8
10 9 00003376 _EnableConnectionCallback@4
11 A 00003342 _EnableModbusCallback@8
12 B 00008123 _GetCallState@8
13 C 00007FD2 _GetLineDeviceName@12
14 D 00003320 _GetPollDelay@0
15 E 00003339 _Get_Modbus_DLL_Revision@0
16 F 000033FE _HookRspNotification@16
17 10 000032ED _InitializeWinSock@0
18 11 0000277C _MBAPWndProc@16
19 12 0000393F _MODBUSResponse@16
20 13 00007EAA _NumberOfLineDevices@0
21 14 00003521 _PollMODBUS@8
22 15 000039F2 _ReadDebugData@16
23 16 00003BA4 _ReadTransparentResponse@16
24 17 0000332A _SetPollDelay@4
25 18 00003313 _UnInitializeWinSock@0
26 19 00003712 _WriteMODBUS@12
27 1A 00003AB3 _WriteTransparentString@12
总结
5000 .data
2000 .rdata
2000 .reloc
1000 .rsrc
C000 .text
我的C#包装是
class MbMasterV7
{
[DllImport("modbusm.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "_ConnectTCP2@12")]
public static extern int ConnectModbusTCP(short Port);
public static string TCPDevice { set; get; }
}
当我运行代码时
MbMasterV7.TCPDevice = "127.0.0.1"; // from demo version of .ocx file converted using tlbimp.exe
MbMasterV7.ConnectModbusTCP(502);
在VisualStudio中,我遇到了一个例外
对PInvoke函数的调用
“特斯塔普!TestApp.MbMasterV7::ConnectModbusTCP'已使
堆栈这可能是因为托管PInvoke签名没有
匹配非托管目标签名。检查通话是否正常
PInvoke签名的约定和参数与目标匹配
非托管签名
我尝试了所有的调用约定,但都出现了相同的错误。
可用于modbus协议的.Net库对于我正在使用的新plc类型来说不够好
FILE HEADER VALUES
14C machine (x86)
5 number of sections
41128817 time date stamp Fri Aug 06 00:48:47 2004
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
210E characteristics
Executable
Line numbers stripped
Symbols stripped
32 bit word machine
DLL
OPTIONAL HEADER VALUES
10B magic # (PE32)
6.00 linker version
C000 size of code
A000 size of initialized data
0 size of uninitialized data
94E4 entry point (100094E4)
1000 base of code
D000 base of data
10000000 image base (10000000 to 10016FFF)
1000 section alignment
1000 file alignment
4.00 operating system version
0.00 image version
4.00 subsystem version
0 Win32 version
17000 size of image
1000 size of headers
0 checksum
2 subsystem (Windows GUI)
0 DLL characteristics
100000 size of stack reserve
1000 size of stack commit
100000 size of heap reserve
1000 size of heap commit
0 loader flags
10 number of directories
DF90 [ 357] RVA [size] of Export Directory
D7C8 [ 50] RVA [size] of Import Directory
14000 [ 3E8] RVA [size] of Resource Directory
0 [ 0] RVA [size] of Exception Directory
0 [ 0] RVA [size] of Certificates Directory
15000 [ BC0] RVA [size] of Base Relocation Directory
0 [ 0] RVA [size] of Debug Directory
0 [ 0] RVA [size] of Architecture Directory
0 [ 0] RVA [size] of Global Pointer Directory
0 [ 0] RVA [size] of Thread Storage Directory
0 [ 0] RVA [size] of Load Configuration Directory
0 [ 0] RVA [size] of Bound Import Directory
D000 [ 198] RVA [size] of Import Address Table Directory
0 [ 0] RVA [size] of Delay Import Directory
0 [ 0] RVA [size] of COM Descriptor Directory
0 [ 0] RVA [size] of Reserved Directory
第一件事第一,
_ConnectTCP2@12
表示将12个字节作为参数传递给函数,这意味着short
(2个字节长)显然不兼容。您需要传递12个字节作为参数,大概是3DWORD
s
为了冒险起见,让我们实际分解二进制文件,看看那里发生了什么。
所以:ConnectTCP@8
正在接收2DWORD
s作为参数,并调用ConnectTCP2
,其中0x1F6
作为第二个参数(实际上是一个短参数)。此外,调用约定是
这些信息足以让我们了解如何调用函数:
[DllImport("modbusm.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "_ConnectTCP2@12")]
public static extern int ConnectModbusTCP(int a, short Port, int b);
会有用,但会扔
"Unhandled Exception: System.AccessViolationException:
Attempted to read or write protected memory.
This is often an indication that other memory is corrupt."
这是因为第二个整数(我称之为b
)实际上是指向结构的指针(其值我只能根据代码猜测)。因此,让我们重建结构。根据规范,该结构的访问次数为五次,如下所示:
因此,通过创建以下结构:
struct MbMasterStruct
{
int a;
int b;
int c;
short d;
int e;
}
并将功能重新定义为:
unsafe class MbMasterV7
{
[DllImport("modbusm.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "_ConnectTCP2@12")]
public static extern int ConnectModbusTCP(int a, short Port, MbMasterStruct * b);
}
并称之为:
static void Main(string[] args)
{
var structure = new MbMasterStruct();
unsafe
{
MbMasterV7.ConnectModbusTCP(1, 2, &structure);
}
}
它实际上是有效的,而且不会抛出。在我的计算机上,它返回51(当结构和参数都为零时)
现在,您需要了解每个参数,并了解如何正确调用函数。您如何知道参数+返回类型是什么,我有一个相同dll(演示)的ActiveX(ocx)文件,我已将其转换为.net程序集,从该程序集,他们提供.doc文件解释代码。问题中的导出不是ocx(应该有方法
DllRegisterServer
等)。因此,我猜您运行了一些转换器,从OCX类型信息生成了一个标准DLL,但是在导入该DLL时,您有错误的方法签名。您可以发布转换后的文档/标题吗?为什么你不能直接使用OCX,我遵循url中给出的方法。我找不到任何关于编写C#wrapper的好文章。问题中的导出不是来自ocx,而是来自win-tech.com/html/mbusocx.htm的包中的dll。我猜dll方法使用ocx中相同的签名,因为这些方法的名称相似。OCX演示仅能运行30分钟。您能评论一下哪些工具用于反汇编,哪些文件用作输入吗?我使用IDA(交互式反汇编程序)和modbusm.dll作为输入,@jobinev