job*_*elv 2 c# wrapper dumpbin modbus-tcp
我正在尝试为modbusm.dll创建一个包装器C#文件(win-tech.com/html/mbusocx.htm),我正在使用dumpbin输出.
转储文件modbusm.dll
文件类型:DLL
该部分包含modbusm.dll的以下导出
Run Code Online (Sandbox Code Playgroud)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
摘要
Run Code Online (Sandbox Code Playgroud)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; }
}
Run Code Online (Sandbox Code Playgroud)
当我运行代码时
MbMasterV7.TCPDevice = "127.0.0.1"; // from demo version of .ocx file converted using tlbimp.exe
MbMasterV7.ConnectModbusTCP(502);
Run Code Online (Sandbox Code Playgroud)
在视觉工作室,我得到例外
对PInvoke函数'TestApp!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
Run Code Online (Sandbox Code Playgroud)
首先,_ConnectTCP2@12
意味着将12个字节作为参数传递给函数,这意味着short
(长度为2个字节)显然是不兼容的.您需要传递12个字节作为参数,大概为3 DWORD
秒.
让我们,为了冒险,实际上拆解二进制文件,看看那里发生了什么.
所以:ConnectTCP@8
接收2 DWORD
s作为参数,ConnectTCP2
并0x1F6
作为第二个参数调用(实际上是一个短).此外,调用约定是stdcall.
这足以让我们弄清楚如何调用该函数:
[DllImport("modbusm.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "_ConnectTCP2@12")]
public static extern int ConnectModbusTCP(int a, short Port, int b);
Run Code Online (Sandbox Code Playgroud)
会工作,但会抛出
"Unhandled Exception: System.AccessViolationException:
Attempted to read or write protected memory.
This is often an indication that other memory is corrupt."
Run Code Online (Sandbox Code Playgroud)
这是因为第二个整数(我调用的b
)实际上是一个指向结构的指针(它的值只能根据代码猜测).所以让我们重建结构.根据代码,结构访问五次如下:
Offset Type
0x00 -> INT32
0x04 -> INT32
0x08 -> INT32
0x0C -> INT16
0x10 -> INT32
Run Code Online (Sandbox Code Playgroud)
因此,通过创建以下结构:
struct MbMasterStruct
{
int a;
int b;
int c;
short d;
int e;
}
Run Code Online (Sandbox Code Playgroud)
并重新定义功能:
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);
}
Run Code Online (Sandbox Code Playgroud)
并将其称为以下:
static void Main(string[] args)
{
var structure = new MbMasterStruct();
unsafe
{
MbMasterV7.ConnectModbusTCP(1, 2, &structure);
}
}
Run Code Online (Sandbox Code Playgroud)
它实际上是有效的,它不会抛出.在我的计算机上,它返回51(当结构和参数都为零时).
现在由您来理解每个参数,并了解如何正确调用该函数.