2

I am trying to invoke a driver dll for a force sensor thats been written for c/cpp. The working Cpp code looks like this:

I the header file that was delivered with the dll, the struct is defined like this

typedef struct
{
  DWORD usb_hid_idx;
  int open;
  char vid_pid[256];
  char dev_info[256];
  char sn_info[256];
  int hw_info;
  unsigned char hw_var;
  int fw_vers;
} t_DeviceInfo;

And the function I need to call is defined like this:

extern "C" DLL_API int Search(t_DeviceInfo *p_dev_info);

In the main code I just create an array of the former defined t_DeviceInfostruct and a pointer to the first element and call the function Searchwith this pointer:

t_DeviceInfo deviceInfo[16];
t_DeviceInfo* deviceInfoPtr = &deviceInfo[0];
int ret = search(deviceInfoPtr);

At least there, everything works fine. With C# it currently looks like this:

unsafe public struct t_DeviceInfo
{
    long usb_hid_idx;
    int open;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    char[] vid_pid;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    char[] dev_info;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    char[] sn_info;
    int hw_info;
    char hw_var;
    int fw_vers;
}

unsafe public class ASTAS
{
    [DllImport("ASTAS_DLL.dll")]
    public extern static int Search(t_DeviceInfo* devInfPtr);
}

And in the main:

t_DeviceInfo[] devInfo = new t_DeviceInfo[16];

But thats about it. How do I marshal the array of structs to a fixed memory location and pass the corresponding pointer to Search()?

6
  • You should add [StructLayout(LayoutKind.Sequential)] to your structure. Commented Jul 30, 2014 at 11:42
  • @LucasTrzesniewski Since that is the default for struct, how would that change anything? Commented Jul 30, 2014 at 11:45
  • @DavidHeffernan The default is LayoutKind.Auto (docs), and my comment didn't mean to solve the question by itself. Commented Jul 30, 2014 at 11:47
  • @Lucas on a struct, when you omit the StructLayout attribute, you get sequential layout. For a class you get auto. Commented Jul 30, 2014 at 11:53
  • @David Hmm... you may be right, but I can't find any doc on MSDN for this behavior so I wouldn't rely on it. And IMHO the attribute is a nice indicator that says "this struct is used in interop, don't mess with it". Commented Jul 30, 2014 at 12:02

2 Answers 2

3

There's no need for unsafe here. You may as well remove that. And your struct declaration is incorrect. Some of the types are wrong. An C++ DWORD is a unsigned 32 bit value. A C# long is a signed 64 bit value. A C++ unsigned char is an unsigned 8 bit value. A C# char is a 16 bit character. Typically unsigned char maps to byte.

The struct should be:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct t_DeviceInfo
{
    uint usb_hid_idx;
    int open;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    string vid_pid;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    string dev_info;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    string sn_info;
    int hw_info;
    byte hw_var;
    int fw_vers;
}

The function declaration should then be:

[DllImport("ASTAS_DLL.dll")]
public extern static int Search([In] t_DeviceInfo[] devInfPtr);

This assumes that the calling convention is stdcall. It looks to me as though it is actually cdecl. In which case you need:

[DllImport("ASTAS_DLL.dll", CallingConvention=CallingConvention.Cdecl)]
public extern static int Search([In] t_DeviceInfo[] devInf);

I've used [In] marshalling. You may need to modify that depending on the semantics, which I cannot discern from the information provided.

Sign up to request clarification or add additional context in comments.

8 Comments

Hi and thansk for the suggestion :)
I tried the cdecl calling convention and Search gives back an error and doesn't attempt to write to the struct array. 'Thiscall' seems to work, but I get an access violation. StdCall also seems to work, but I get a stack imbalance error.
What is DLL_API? Evidence suggests that cdecl is the correct choice. It won't be thiscall because this is not an instance method. So, it would seem that cdecl is the choice, and you need to work out how to call the function properly. If you want to see anything returned in the array, then you need [In, Out] or [Out]. Remember that you've told us nothing about how to call the function and which way the data flows. Only you know that.
Hi, my testing suggests, that cdecl is ok as calling convetion for a bunch of other functions in this dll so it should also be ok for Search(). But on the other hand, every other function also is called correctly with StdCall. And I dont know, what DLL_API is doing - I kind of hoped you would ^^
Is there any way to look at a stack content during runtime or at a breakpoint? Maybe by looking at the actual output from Search() to the buffer I can figure out if the buffer is initialized correctly.
|
0

Use the fixed statement in an unsafe context.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.