Articles

Navigation ( archives ›› 2006 ›› July ›› 11 ›› CSharp PInvoke Interop Experiences )

CSharp PInvoke Interop Experiences

Posted on July 11, 2006, 2:25 am EST

Information

Wow, when people say interops in C# is very cruelsome then you better believe that. PInvoking managed code could be very messy, even if the developer is one experienced person.

Last week I was attempting to convert unmanaged C++ code to managed C# code within the .NET 2.0 compiler. It was a big library that control the haptics device which was made in the C/C++ language. I am going to share the difficulties that I had during my interoping PInvoking experience :)

Problems Encountered

  1. Older C++ Code not recognizable by function name while DLLImport
  2. Improper Parameter Types
  3. Misuse of CALLBACKS / Macros

The steps to PInvoke

First of all you must Convert all the constants, methods, macros, and events. Thats how you do a proper PInvoke. I explained some steps below.

The Solutions

Older code sometimes causes bad standards in the construction of the dll. It took me couple of days to find out that the compilation of the older code to a dynamic link library ruins todays dll standards. For that being, all DLLImports would not recognize the name, they need an entrypoint with respect to its ordinal entry point within the dll itself. The reason why I used the ordinal is simply because the naming convention of old compiled dll's are different than the todays convention.

CODE:
[DllImport("hd", EntryPoint = "#22")]
public static extern void hdScheduleSynchronous( HDSchedulerCallback pCallback, IntPtr pUserData, UInt16 nPriority );

Notice the ordinal entry point for the function hdScheduleSynchronous is 22, thats the location of the function in the dll table. That solved the issue for my first problem.

PInvoke must be done correctly else many exceptions will be taken in place. The most common error that many users do is not supplying the correct types within the parameter and return type. C# types differ tremendously. There is a difference between a unsigned double and a unsigned int. For example all unsigned doubles in c/C++ is considered as uint within C#. That was the tricky undocumented one. When you supply a double within C# it is a longer value then C type. Thus StackException would occur. If the return type is a char, it could be considered as a char or as a bool. All other return types are equivalent to its corresponding types.

All callbacks which have a void * must be converted to a type IntPtr. All callbacks must be declared as a normal delegate. But when you are making a control, the events for that delegate must be declared within that control. Not within that interop class. Remember macros are not DLL Calls, they are simply functions. Which look like this:

CODE:
public static bool HD_DEVICE_ERROR(HDDefines.HDErrorInfo x) { 
    return x.errorCode != HDDefines.HD_SUCCESS; 
}

Remember within an interop, you must reserve the type definitions of the constants, the methods, the structures and the evetns.

The below code represents how you would preserve the c/c++ constants.

CODE:
// Cartesian space values
public const uint HD_CURRENT_POSITION = 0x2050;
public const uint HD_CURRENT_VELOCITY = 0x2051;
public const uint HD_CURRENT_TRANSFORM = 0x2052;
public const uint HD_CURRENT_ANGULAR_VELOCITY = 0x2053;
public const uint HD_CURRENT_JACOBIAN = 0x2054;

When you declare a structure for the PInvoke, you must lay the datamembers in correct order or another exception would occur. A proper way to do so, aligning them in correct order and assigning the type of sequential. A sample struct looks like this:

CODE:
[StructLayout(LayoutKind.Sequential)]
public struct HDErrorInfo
{
    public uint errorCode;
    public int internalErrorCode;
    public uint hHD;
}

Conclusion

Thats all for now, it is easy to do normal PInvoke using DLLImports, but I hope if anyone is trying it wont get in the same mess I got into. Thanks to Microsoft developers that helped me throughout the process. The tricky problem was why the DLL wont get recognized :)

About this Article:

Comments (0) - Add yours, or View the replies

Categoy (CSharp)

Views (1571)

Digg it: Digg this article