Good morning, I'm tring to implement a pos device. The native api is a C++ lib, that I have to use in my C# project. I already imported almost all the functions required (working fine), but there is one of them that I cannot do it anyway.
This is the function into the C++ lib:
__declspec(dllexport) void setHost(char* id, Host* host, char* trx, char* flag);
This is the struct declared into the C++ lib:
typedef struct {
int hostConnectionType;
char ipAddress[15 + 1];
int tcpPort;
int hostTransportProtocol;
char gtId[5 + 1];
char gprsAPN[64 + 1];
char gprsUserName[15 + 1];
char gprsPassword[8 + 1];
int tlsCertificateId;
char personalizationId[10 + 1];
int gtIndex;
} Host;
And this is the usage sample in C++ demo project:
Host test_host;
test_host.hostConnectionType = 3;
test_host.hostTransportProtocol = 2;
test_host.gtIndex = 9;
strcpy(test_host.ipAddress, "199.188.177.166");
test_host.tcpPort = 54321;
strcpy(test_host.gtId, "12345");
test_host.tlsCertificateId = 21985;
strcpy(test_host.personalizationId, "001");
MobilePosAdapter_dll("00000123", &test_host, "0000000001", "1000");
What I done in my C# project is declaring the Host struct:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Host
{
public int hostConnectionType;
public int hostTransportProtocol;
public int tcpPort;
public int tlsCertificateId;
public int gtIndex;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string ipAddress;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public string gtId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
public string gprsAPN;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string gprsUserName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
public string gprsPassword;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public string personalizationId;
}
Then, declaring the function, attributes and sign:
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private delegate void cdecl__setHost([MarshalAs(UnmanagedType.LPStr)] string id, Host Host, [MarshalAs(UnmanagedType.LPStr)] string trx, [MarshalAs(UnmanagedType.LPStr)] string flags);
private static cdecl__setHost _setHost = (cdecl__setHost)Marshal.GetDelegateForFunctionPointer(NativeMethods.GetProcAddress(DllPtr, "setHost"), typeof(cdecl__setHost));
Finally test it:
Host host = new Host()
{
gtId = 12345,
gtIndex = 0,
hostConnectionType = 3,
hostTransportProtocol = 2,
ipAddress = "199.188.177.166",
personalizationId = "001",
tcpPort = 54321,
tlsCertificateId = 21985
};
_setHost("00000123", host, "0000000001", "1000");
I got a System.AccessViolationException.
What I wrong?
This is the only function in the entire API it has a struct as parameter. The others functions has struct as value return, and they works all fine.
Just a quick guess
On the unmanaged side, the parameter type is
Host*
and in C++ you're passing&test_host
.However, on the C# side, you have a struct (a thing that is by default pass by-a-copy, so by-val) and you're passing just
host
to a function with declared params of:Note that you have not added any MarshalAs to the
host
parameter, so I suppose it will be passed by-copy, and some damage will occur, as the receiving function expects to get a pointer (few bytes) not the whole structure (few times more).First thing I'd try is adding ANY hint that you want to pass it as a pointer, for example:
and call it like
Also, be sure to double-check what Ackdari said in comments - if the field order differs between what C# provides and what native code expected, that may also result in the same exception..