0

I have a function in C++ and exported in DLL. the function is

LONG LOGIN(LPDEVINFO info);

the struct of LPDEVINFO is:

struct{  
       BYTE sSerialNumber[20];
} *LPDEVINFO;

to pass LPDEVINFO parameter, I have defined a class in managed code:

class DEVINFO{
     Byte[] sSerialNumber = new Byte[20];
}

and then P/Invoke like this:

[DllImport ('MyDll.dll')]
public static extern Int32 LOGIN(DEVINFO info);

and then call it in C#:

DEVINFO info = new DEVINFO();
Int id = LOGIN(info)

When I run this code, I got following error:

An unhandled exception of type 'System.AccessViolationException' occurred in WindowsFormsApplication1.exe

Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

I think the problem is caused by the array sSerialNumber. But I do not know how to define it in a right way.

Thanks in advance!

5
  • If LONG is defined as a 64-bit integer type in C++, you'll have to either map export the function as extern Int64 LOGIN(DEVINFO info); or extern long LOGIN(DEVINFO info);. As for your DEVINFO class, I would make it a struct and apply the attribute [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] to the byte array. see this answer Commented Dec 23, 2011 at 17:48
  • @Jim LONG is 32 bit integer in C and C++ on Windows. Commented Dec 23, 2011 at 17:58
  • Ah, I've seen it redefined. I don't know why it would be, though. Commented Dec 23, 2011 at 20:01
  • @Jim It's a very common trap, LONG is the same as LONG and is 32 bits in C on Windows. In C# long is 64 bits. Commented Dec 23, 2011 at 20:03
  • Thanks @JimSchubert, [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] works for me. Commented Dec 24, 2011 at 1:41

3 Answers 3

3

I would use UmanagedType.ByValArray here:

class DEVINFO {
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=20)]
    public byte[] sSerialNumber;
}

Otherwise it all looks fine to me. In particular it is perfectly fine to do this with a class rather than a struct.

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

1 Comment

I'm puzzled by the downvote on this answer and the downvote on Bradley's answer. I can't see anything wrong with either of them. If there is something wrong I'd like to correct it.
3

Use the fixed keyword to declare a struct that contains a fixed-size buffer:

public unsafe struct DevInfo
{
    public fixed byte sSerialNumber[20];
}

For more information, see Fixed Size Buffers.

Also, to pass the struct by pointer (corresponding to LPDEVINFO on the native side), declare the function as follows:

[DllImport ('MyDll.dll')]
public static extern Int32 LOGIN(ref DevInfo info);

and call it:

DevInfo info = new DevInfo();
int id = LOGIN(ref info)

2 Comments

with keyword "fixed", I get the error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
@englefly You'll probably need to put unsafe in the struct declaration (amended my answer) and (maybe) in the code that uses it. You'll also need to enable unsafe code in the C# Project Properties.
0

The function is expecting a pointer to a structure, not the actual structure.

Use the Marshal.StructureToPtr() function to convert your structure to an IntPtr.

Example in C#:

[DllImport("MyDll.dll")]
public static extern Int32 LOGIN(IntPtr info);

...

DEVINFO info = new DEVINFO();
IntPtr infoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(info));
Marshal.StructureToPtr(info, infoPtr, false);
LOGIN(infoPtr);

If this is an OUT parameter, that is you need to read from it after the function is called since it is modified by the callee, then you use the Marshal.PtrToStructure to read it back into a managed structure like follows:

DEVINFO info = (DEVINFO)Marshal.PtrToStructure(infoPtr, typeof(DEVINFO));

4 Comments

Using class rather than struct, as per the code in the question means that a pointer will be passed. That's not the problem.
Bradley's answer is better. I'm just used to using StructureToPtr for weird interop scenarios, like pointers to arrays of pointers to structs, where the simple ref functionality did not suffice.
Using class is just fine. I do it all the time.
And the point is this fact makes the entire content of your answer invalid.

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.