-Create a public class
- Create public static methods in this class using
http://community.silabs.com/mgrfq63796/attachments/mgrfq63796/5%40tkb/331/1/Creating%20a%20C%23%20Module%20From%20a%20DLL%20Header%20File.pdf
DLLImport for each exported function
Example:
C (.h) File:
__declspec(dllexport) int Add(int a, int b);
C# (.cs) File:
public class MathDll
{
[DllImport("Math.dll")]
public static extern int Add(int a, int b);
}
- Create public const class members for each #define constant
Example:
C(.h) File:
#define PI 3.14159
#define START_OF_FRAME 0x55
C# (.cs) File:
public class SomeDll
{
public const double PI = 3.14159;
public const byte START_OF_FRAME = 0x55;
}
- Use the appropriate data types:
Type C C#
1 byte unsigned bool, unsigned char, BYTE byte
1 byte signed char sbyte
2 bytes unsigned unsigned short, WORD ushort
2 bytes signed short short
4 bytes unsigned unsigned int, unsigned long, UINT, DWORD uint
4 bytes signed int, long, BOOL int
4 bytes floating point float float
8 bytes floating point double double
4/8 byte pointer void* IntPtr
See http://msdn.microsoft.com/en-us/library/4xwz0t37(VS.80).aspx for more information on
data types.
- Special cases:
1. Parameters passed as a pointer should use the ref keyword.
Example:
C (.h) File:
__declspec(dllexport) void Halve(BYTE* value);
C# (.cs) File:
public class MathDll
{
[DllImport("Math.dll")]
public static extern void Half(ref byte value);
}
2. Parameters passed as an output C string (char* or LPSTR) should use the StringBuilder
class.
Example:
C (.h) File:
__declspec(dllexport) void GetName(char* name, int size);
C# (.cs) File:
using System.Text;
public class SomeDll
{
[DllImport("Some.dll")]
public static extern void GetName(StringBuilder name, int size);
}
Calling Example:
StringBuilder name = new StringBuilder(100);
SomeDll.GetName(name, 100);
3. Parameters passed as an input C string (const char* or LPCSTR) should use the string
class.
Example:
C (.h) File:
__declspec(dllexport) void SetName(const char* name);
C# (.cs) File:
public class SomeDll
{
[DllImport("Some.dll")]
public static extern void SetName(string name);
}
Calling Example:
string name = “John Smith”;
SomeDll.SetName(name);
4. Parameters passed as an array should use C# arrays.
Example:
C (.h) File:
__declspec(dllexport) void GetBuffer(BYTE* buffer, int size, int* bytesReturned);
C# (.cs) File:
public class SomeDll
{
[DllImport("Some.dll")]
public static extern void GetBuffer(byte[] buffer, int size, ref int
bytesReturned);
}
Note: Arrays in C# are considered objects. As such, arrays are already passed by
reference, therefore you should not add the ref keyword before the array.
5. Parameters passed as a void pointer (void*) should use the IntPtr type.
Example:
C (.h) File:
__declspec(dllexport) void SetObject(void* object);
__declspec(dllexport) void GetObject(void** object);
C# (.cs) File:
public class SomeDll
{
[DllImport("Some.dll")]
public static extern void SetObject(IntPtr object);
[DllImport("Some.dll")]
public static extern void GetObject(ref IntPtr object);
}
Note: Passing pointers can be problematic when dealing with 32-bit/64-bit systems.
IntPtr is platform dependent, meaning that it is a four byte pointer on 32-bit systems
and an eight byte pointer on a 64-bit system. A .NET application running in 64-bit mode
will not be able to load a 32-bit DLL. You must either build a separate 64-bit DLL or
modify your .NET project to only run in 32-bit mode.
6. Structures must always be passed by reference in the C DLL.
Example:
C (.h) File:
typedef struct PERSON
{
BYTE id;
WORD month;
char name[10];
} PERSON, *PPERSON;
__declspec(dllexport) void GetPerson(PPERSON person);
__declspec(dllexport) void SetPerson(PPERSON person);
C# (.cs) File:
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public class PERSON
{
public byte id;
public ushort month;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public byte [] name;
}
public class SomeDLL
{
[DllImport(“SomeDLL.dll”)]
public static extern void GetPerson(
[In,Out, MarshalAs(UnmanagedType.LPStruct)]
PERSON person);
[DllImport(“SomeDLL.dll”)]
public static extern void SetPerson(
[In, MarshalAs(UnmanagedType.LPStruct)]
PERSON person);
}
Calling Example:
PERSON person = new PERSON();
SomeDLL.GetPerson(person);
person.id = 2;
SomeDLL.SetPerson(person);
Note: The “In” attribute forces marshaling data from the caller to the callee. The “Out”
attribute forces marshaling data from the callee back to the caller. The default attribute
is “In”. If “Out” is specified, then “In” does not implicitly apply.
7. Parameters passed as an array of structs should use C# arrays of Structs passed by
value with the In/Out attributes specified as needed.
Examples:
C (.h) File:
typedef struct PERSON
{
BYTE id;
WORD month;
char name[10];
} PERSON, *PPERSON;
__declspec(dllexport) void GetPeople(PERSON people[], DWORD* numPeople);
__declspec(dllexport) void SetPeople(PERSON people[], DWORD numPeople);
C# (.cs) File:
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct PERSON
{
public byte id;
public ushort month;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public byte[] name;
}
public class SomeDLL
{
[DllImport("StructTest.dll")]
public static extern void GetPeople([In, Out]PERSON[] people, ref uint
numPeople);
[DllImport("StructTest.dll")]
public static extern void SetPeople(PERSON[] people, uint numPeople);
}
Calling Example:
PERSON[] people = new PERSON[2];
uint numPeople = (uint)people.Length;
people[0].id = 1;
people[0].month = 11;
people[0].name = new byte[10];
people[0].name[0] = 0x31;
people[1].id = 2;
people[1].month = 12;
people[1].name = new byte[10];
people[1].name[0] = 0x32;
SomeDLL.SetPeople(people, numPeople);
numPeople = (uint)people.Length;
SomeDLL.GetPeople(people, ref numPeople);
8. Callbacks must be defined as C# delegates.
Examples:
C (.h) File:
typedef void (CALLBACK *ProgressCallback)(int percent);
__declspec(dllexport) void RegisterProgress(ProgressCallback progress);
C# (.cs) File:
public class SomeDLL
{
public delegate void ProgressCallback(int percent);
[DllImport("Some.dll")]
public static extern void RegisterProgress(ProgressCallback progress);
}
Calling Example:
void Progress(int percent)
{
// do something with the progress percent
}
void CallingExample()
{
SomeDLL.RegisterProgress(new SomeDLL.ProgressCallback(Progress));
}
9. Win32 BOOL (4-byte int) data types can be automatically marshaled as a C# bool data
type (1-byte).
Examples:
C (.h) File:
__declspec(dllexport) void SetEnable(BOOL enable);
__declspec(dllexport) void GetEnable(BOOL* enable);
C# (.cs) File:
public class SomeDLL
{
[DllImport("Some.dll")]
public static extern void SetEnable(bool enable);
[DllImport("Some.dll")]
public static extern void GetEnable(ref bool enable);
}
Calling Example:
bool success;
bool enable = true;
SomeDLL.SetEnable(enable);
SomeDLL.GetEnable(ref enable);
if (enable)
{
success = true;
}