I have this panini scanner api (written in c++ i suppose) which i want to call from c# application.
PS: I dont have the implementation of this DLL, only the header and the dll file.
the function declaration from VApiInterface.h file is
typedef DWORD ERR_CODE;
typedef ERR_CODE VAPI_RET_TYPE;
typedef struct _DeviceListStruct
{
DWORD DeviceType;
char DeviceSerialNumber[MVX_SN_SIZE];
DWORD DeviceID;
DWORD InternalDeviceID;
BOOL Connected;
}DEVICELISTSTRUCT,* PDEVICELISTSTRUCT;
// Tag for VISION API function declaration
#define VISION_API_DECL __declspec(dllexport)
// VISION API function tag
#define VISION_API WINAPI
VISION_API_DECL VAPI_RET_TYPE VISION_API VApiGetDeviceList(PDEVICELISTSTRUCT pDevList, DWORD Length, DWORD *DetectedDevices);
and i'm trying to call this function from c# like this
public class VisionAPI
{
[StructLayout(LayoutKind.Sequential)]
public struct _DeviceListStruct
{
public uint DeviceType;
[MarshalAs(UnmanagedType.LPStr, SizeConst = 11)]
public string DeviceSerialNumber;
public uint DeviceID;
public uint InternalDeviceID;
public bool Connected;
}
[DllImport("VisionAPI.dll", EntryPoint = "VApiGetDeviceList")]
public static extern uint VApiGetDeviceList(ref _DeviceListStruct d,uint len,ref uint devices);
}
////////////
//the call
VisionAPI._DeviceListStruct d = new VisionAPI._DeviceListStruct() ;
VisionAPI.VApiGetDeviceList(ref d, 0, 0);
and I m getting this error
Unable to find an entry point named 'VApiGetDeviceList' in DLL 'VisionAPI.dll'.
as a java backend developer I'm really out of my element here and I have absolutely no Idea what I'm doing wrong.
plz help.
I'm trying to call a function from a C++ DLL using DLLImport (P/Invoke) and I keep getting a System.AccessViolationException error when I call it. Note that I other functions to work.
Declaration of the DLLImport function:
[DllImport("DocProc.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern uint getDPpupTrkBaseConfigPath(DPHandle hdl, StringBuilder str, uint strsize);
Usage:
StringBuilder sb = new StringBuilder(256);
getDPpupTrkBaseConfigPath(handle, sb, (uint)sb.Capacity);
DPHandle: (note that it works in other functions)
public struct DPHandle
{
public uint Size;
public IntPtr UserHandle;
[MarshalAs(UnmanagedType.LPStr)] public string DeviceName;
public uint DeviceTypeId;
public uint DeviceState;
public uint OpenFlags;
public IntPtr Reserved1;
};
C++:
BPS_PROPL getDPpupTrkBaseConfigPath(DPHandle hdl, char *str, unsigned long strsize);
(Note BPS_PROPL = unsigned long)
DPHandle:
struct DocProcHandle {
unsigned long Size;//sizeof(DocProcHandle)
void* UserHandle;
const char* DeviceName;
unsigned long DeviceTypeId;
unsigned long DeviceState;
unsigned long OpenFlags;
void* Reserved1;
};
typedef struct DocProcHandle *DPHandle;
Again, when I try to call the function that exception shows up. I tried looking at other answers but can't figure out what's wrong?
In the C++ code, you have:
typedef struct DocProcHandle *DPHandle;
This means that DPHandle is a pointer to the struct. But in your C# code you pass the the struct by value.
The simplest way to achieve that is to change the declaration of the first argument of your pinvoke code from
DPHandle hdl
to
[In] ref DPHandle hdl
In C, MAPINAMEID is defined as:
typedef struct _MAPINAMEID
{
LPGUID lpguid;
ULONG ulKind;
union {
LONG lID;
LPWSTR lpwstrName;
} Kind;
} MAPINAMEID, FAR * LPMAPINAMEID;
In C#, my definition is:
[StructLayout(LayoutKind.Explicit)]
private struct MAPINAMEID
{
[FieldOffset(0)]
public IntPtr lpguid;
[FieldOffset(8)]
public uint ulKind;
[FieldOffset(16)]
public int lID;
[FieldOffset(16)]
public IntPtr lpwstrName;
};
Obviously, it works in 64-bit mode only, with 32-bit I need different offset values. Unfortunately, FieldOffset attribute does not allow using computable values (like IntPtr.Size). Is there a platform-independent way to specify offset (or somehow else tell the compiler that I want lID and lpwstrName to share the same offset?
You can declare it like that:
[StructLayout(LayoutKind.Sequential)]
private struct MAPINAMEID
{
public IntPtr lpguid;
public uint ulKind;
public IntPtr lpwstrName; // or lID
};
And use IntPtr 32-bit conversion to switch between lpwstrName and lId when needed (LONG and ULONG are 32-bit).
I thought this one was fairly straight forward but still trying to understand all of this and having some issues.
I don't know much about the C function b/c i've been given limited information.
Here is the function call in C:
int GetCard(CardInfo card);
Here is the request structure:
typedef struct _tCardInfo
{
char CardNumber[80];
char isExist;
} TCardInfo, *pTCardInfo;
I want to pass the card number to see if it exists.
So in C# I did the following:
public struct CardInfo
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string cardNumber;
public byte isExist;
}
[DllImport("card.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
public static extern int GetCardInfo(ref CardInfo cardInfo);
Then in the c# method:
CardInfo cardInfo = new CardInfo();
cardInfo.cardNumber = "1234567890";
int success = GetCardInfo (ref cardInfo);
The good thing about the DLL that I'm calling is it generates a log file.
When I execute the call, the log tells me that I'm hitting the DLL but it is not passing the card number which then sets a message saying the card number was not passed.
Any help is greatly appreciated.
Thanks!
The problem is that you're requesting TChar marshaling, but the DLL requires 8-byte characters. Change the C struct to wchar_t.
Also, use Visual Studio to set a breakpoint in your DLL, and actually inspect the data when it comes in! Visual Studio can debug across .NET/native boundaries, which is super cool!
Try to add attribute StructLayout for struct
[StructLayout(LayoutKind.Sequential)]
public struct CardInfo
{
...
Try to create the .Net struct like this:
[StructLayout(LayoutKind.Sequential)]
public struct CardInfo
{
[MarshalAs(UnmanagedType.AnsiBStr, SizeConst = 80)]
public string cardNumber;
[MarshalAs(UnmanagedType.I1)]
public sbyte isExist;
}
And for the function declaration: try not to use the CallingConvention and CharSet in the DLL import, and use the [In, Out] attributes before the parameter. Like this:
[DllImport("card.dll")]
public static extern int GetCardInfo([In, Out] CardInfo cardInfo);
I am referencing a DLL in my C# project as follows:
[DllImport("FeeCalculation.dll", CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi)]
public static extern void FeeCalculation(string cin, string cout, string flimit,
string frate, string fwindow, string fincrement, string fbird,
string fparameter, string fvalidation, string fcoupon);
The FeeCalculation function is exported as follows in the DLL:
extern "C" __declspec(dllexport) void __stdcall FeeCalculation(char *cin,
char *cout, char *flimit, char *frate,
char *fwindow, char *fincrement, char *fbird,
char *fparameter, char *fvalidation, char *fcoupon);
The DLL function returns a reference to it's internal structures in the form of char * so if you were to reference this DLL in C++, you would do the following to do the calculation and get the returned structures:
FeeCalculation(buff, (char *)&fans, (char *)fl, (char *)ft, (char *)fw, (char *)fi, (char *)fe, (char *)&fm, (char *)val, (char *)cpn);
Now, how do I retrieve those values that are returned by reference using C#? Meaning, how do I do the same thing in C# to get the returned structures to get my returned calculation? I know I need to create an unsafe method, but I am unclear on how to deal with the memory addresses in C# like you would in C++.
Edit: Below states to use IntPtr but how do you place into identical structure so the fields of the structure can be referenced?
Edit: Here is the returned structure that I am interested in (cout):
struct feeAnswer {
unsigned int fee;
unsigned int tax1;
unsigned int tax2;
unsigned int tax3;
unsigned int tax4;
unsigned int surcharge1;
unsigned int surcharge2;
unsigned int validationFee;
unsigned int couponFee1;
unsigned int couponFee2;
unsigned int couponFee3;
unsigned int couponFee4;
unsigned short int dstay; //Day Stay
unsigned short int mstay; //Minute Stay
};
Here is the (cin) that I would pass along with other structures (they are zero byte at the moment, I want to get this to work first then I will implement the rest):
struct feeRequest {
unsigned char day;
unsigned char month;
unsigned int year; //2000 ~ 2099
unsigned char hour;
unsigned char minute;
unsigned char rate;
unsigned char validation;
unsigned char coupon1;
unsigned char coupon2;
unsigned char coupon3;
unsigned char coupon4;
};
The char* parameters in this case are not strings but pointers to chunks of raw bytes representing the data. You should marshal your parameters as instances of the IntPtr type, in conjunction with Marshal.AllocHGlobal to create a chunk of memory and then Marshal.PtrToStructure to convert that block of memory into a usable .NET type.
As an example:
[StructLayout(LayoutKind.Sequential)]
struct MyUnmanagedType
{
public int Foo;
public char C;
}
IntPtr memory = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MyUnmanagedType)));
try
{
FeeCalculation(memory);
MyUnmanagedType result = (MyUnmanagedType)Marshal.PtrToStructure(
memory, typeof(MyUnmanagedType));
}
finally
{
Marshal.FreeHGlobal(memory);
}
Edit: now that we have structures to work with, a better solution is possible. Just declare structs in C# that match your C++ structs, and use them in the extern declaration
[StructLayout(LayoutKind.Sequential)]
public struct feeAnswer {
public uint fee;
public uint tax1;
public uint tax2;
public uint tax3;
public uint tax4;
public uint surcharge1;
public uint surcharge2;
public uint validationFee;
public uint couponFee1;
public uint couponFee2;
public uint couponFee3;
public uint couponFee4;
public ushort dstay; //Day Stay
public ushort mstay; //Minute Stay
};
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct feeRequest {
public byte day;
public byte month;
public uint year; //2000 ~ 2099
public byte hour;
public byte minute;
public byte rate;
public byte validation;
public byte coupon1;
public byte coupon2;
public byte coupon3;
public byte coupon4;
};
[DllImport ("FeeCalculation.dll", CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi)]
public static extern void FeeCalculation (
feeRequest cin,
out feeAnswer cout,
...
....
original answer (before we had structs) below
It appears to me that these are not references to internal strings, but rather pointers to string buffers that will be filled in by the call. If you were returning string pointers, then these would be declared char** rather than char*.
So I think these are just standard out parameters. There's just a lot of them. So your C# interop would look like this
[DllImport("FeeCalculation.dll", CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi)]
public static extern void FeeCalculation(string cin,
[MarshalAs(UnmanagedType.LPStr, SizeConst=100)]
out string cout,
[MarshalAs(UnmanagedType.LPStr, SizeConst=100)]
out string flimit,
or this if your "strings" aren't really strings
[DllImport("FeeCalculation.dll", CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Ansi)]
public static extern void FeeCalculation(string cin,
[MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
out byte[] cout,
[MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
out byte[] flimit,
....
To answer your Edit, you need to create a struct, and then use the StructLayoutAttribute on the fields in order to make the byte order and padding the same as the original dll did.