C# calling a function from unmanaged c++ dll - c#

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.

Related

System.AccessViolationException when calling function from unmanaged DLL using DLLImport

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

Using a C struct in C#

I am trying to port a windows-only USB driver to Linux by switching from hid.dll and other windows-only-stuff to the cross-platform hidapi.
hidapi.h contains the following definitions:
struct hid_device_info {
char *path;
unsigned short vendor_id;
unsigned short product_id;
wchar_t *serial_number;
unsigned short release_number;
wchar_t *manufacturer_string;
wchar_t *product_string;
unsigned short usage_page;
unsigned short usage;
int interface_number;
struct hid_device_info *next;
};
and
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);
Please see the link above for the code with comments.
The driver is written in C#, so I would like to connect to the hidapi library and use these directly. I have managed to get access to hid_enumerate by doing this:
[DllImport ("/usr/local/lib/libhidapi-hidraw.so.0")]
internal static extern IntPtr hid_enumerate (ushort vendor_id, ushort product_id);
Calling hid_enumerate later then gives me a pointer. However, I am unsure how to proceed from here. I would like to turn this into a LinkedList of hid_device_info objects, or some other structure in C#.
I am quite new to C#, but have a lot of programming experience.
Could you please point me in the right direction?
Here's what I ended up doing. I made a struct in C# like this:
[StructLayout(LayoutKind.Sequential)]
private struct hid_device_info {
[MarshalAs(UnmanagedType.LPStr)]
public String path;
public ushort vendor_id;
public ushort product_id;
[MarshalAs(UnmanagedType.LPWStr)]
public String serial_number;
public ushort release_number;
[MarshalAs(UnmanagedType.LPWStr)]
public String manufacturer_string;
[MarshalAs(UnmanagedType.LPWStr)]
public String product_string;
public ushort usage_page;
public ushort usage;
public int interface_number;
public IntPtr next;
};
and when calling hid_enumerate, I did this to turn the pointer into an instance of the struct:
List<hid_device_info> list = new List<HidDeviceManager.hid_device_info> ();
IntPtr pDev = hid_enumerate (0, 0);
while (pDev != IntPtr.Zero) {
hid_device_info dev = new hid_device_info();
dev = (hid_device_info)Marshal.PtrToStructure (pDev, typeof(hid_device_info));
list.Add (dev);
pDev = dev.next;
}
It works well.

PInvoke for complex method calls C#

I am using a 3. party SDK, which is made up from .dll, .lib and .h files.
I am using the .dll's to PInvoke against. And the .h files to see the function names and parameters. (So I am not using the .lib files).
The SDK is rather complex, so making the PInvoke wrappers have proven to be a challenge. All the functions/structs/enums is defined in the .h files.
The function I am trying to wrap is called InitBaseComponent, and I can call it, but it returns a "Error In Argument" enum back. So my guess is it is marshalling that creates this problem.
So the question is: I am doing this right?
Function: InitBaseComponent(...)
//C Function: InitBaseComponent(...)
ERROR InitBaseComponent(
Method_Interface* methodInterface, //[in]
void* methodInst, //[in]
ErrorCallBackFunction errorCallbackFunc, //[in]
void* ErrorCallbackInst, //[in]
Component* BaseComponent //[in, out]
);
//C# Function: InitBaseComponent(...)
[DllImport("externalSDK.dll", EntryPoint = "InitBaseComponent", CallingConvention = CallingConvention.Cdecl)]
public static extern ERROR InitBaseComponent(
Method_Interface methodInterface,
IntPtr methodInst,
ErrorCallBackFunction errorCallbackFunc,
IntPtr ErrorCallbackInst,
out Component BaseComponent
);
Enum: ERROR
//C Enum: ERROR
typedef enum ERROR_E {
OK = 0, //Everything is ok
E_ARG = 1, //Error in the Arguments
E_DATA = 2 //Data error
//And more...
} ERROR;
//C# Enum: ERROR
public enum ERROR
{
OK = 0, //Everything is ok
E_ARG = 1, //Error in the Arguments
E_DATA = 2 //Data error
//And more...
}
Struct: Method_Interface
//C struct: Method_Interface
typedef struct Method_Interface_S
{
void* (*Method1)(void* Inst, size_t size);
void* (*Method2)(void* Inst, size_t nelements, size_t bytes);
void* (*Method3)(void* Inst, void *pointer, size_t size);
void (*Method4)(void* Inst, void* pointer);
}Method_Interface;
//C# class: Method_Interface
[StructLayout(LayoutKind.Sequential)]
public class Method_Interface
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void Method1_delegate(IntPtr Inst, uint size);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void Method2_delegate(IntPtr Inst, uint nelements, uint bytes);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void Method3_delegate(IntPtr Inst, IntPtr pointer, uint size);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void Method4_delegate(IntPtr Inst, IntPtr pointer);
public Method1_delegate Method1;
public Method2_delegate Method2;
public Method3_delegate Method3;
public Method4_delegate Method4;
}
Delegate: ErrorCallBackFunction
//C ErrorCallBackFunction
typedef void (*ErrorCallBackFunction)(void* errorCallBackInst, ERROR errorCode, const char* szMessage, const char* szDetail);
//C# delegate: ErrorCallBackFunction
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ErrorCallBackFunction(IntPtr errorCallBackInst, ERROR errorCode, string szMessage, string szDetail);
Struct: Component
//C struct: Component
typedef struct Component_S
{
void* ObjPointer;
unsigned long number;
} Component;
//C# class: Component
[StructLayout(LayoutKind.Sequential)]
public class Component
{
public IntPtr ObjPointer;
public ulong number;
}
Anyone knows what I am doing wrong?
You have declared Component in the C# as a class. That means that it is already a reference. But then you passed it as an out parameter which adds an extra layer of indirection, one too many. So, you need to remove the out, just as you did for methodInterface.
[DllImport(...)]
public static extern ERROR InitBaseComponent(
Method_Interface methodInterface,
IntPtr methodInst,
ErrorCallBackFunction errorCallbackFunc,
IntPtr ErrorCallbackInst,
Component BaseComponent
);
Obviously you need to instantiate the Component object in your C# before you call InitBaseComponent.
Some other observations:
size_t is pointer sized, so your translation as uint will fail on 64 bit platforms.
C# long is 64 bits, but C++ long is 32 bits, on Windows. So your translation of the C++ Component struct is wrong. The number field must be declared with type uint.

Calling C function with struct in C# - what am I doing wrong?

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);

How to transmit c++ strucure from dll to c# program?

I have DLL, written in C++. There is structure in this DLL.
typedef struct TransmitData
{
wchar_t szPath[MAX_PATH];
DWORD dwResult;
} *lpTransmitData;
And I have one function to fill this struct
extern "C" __declspec(dllexport) int GetData(struct TransmitData &data)
{
//I HAVE ONE THE SAME STRUCT IN THIS DLL
memcpy(&data, &transmitData, sizeof(struct TransmitData));
return ret_value;
}
In C# program I use functions with simple data types well, but for structure it doesn't work. There is code on C#:
public struct TransmitData
{
[MarshalAs(UnmanagedType.LPWStr, SizeConst = 260)] //260 = MAX_PATH
public string szPath;
public uint dwResult;
}
//...
[DllImport("MyDLL")]
public static extern int GetData(ref TransmitData data);
What am I doing wrong?
Thanks!
I suggest you to replace
[DllImport("MyDLL")]
with
[DllImport("MyDLL", CallingConvention = CallingConvention.Cdecl)]
and
extert "C"
with
extern "C"
Moreover, as Joe suggested, add
[StructLayout(LayoutKind.Sequential)]
before the declaration of the struct in C# code

Categories