Click here to Skip to main content
16,018,805 members
Articles / Programming Languages / C#
Article

Calling methods from Dll compiled in 'C' from C#

Rate me:
Please Sign up or sign in to vote.
2.84/5 (17 votes)
1 May 20044 min read 162K   31   8
Describes how to interface 'C' code with C# through Dlls compiled in 'C'

There a few examples out there on how to call Win32 methods from user.dll in C# for example but I didn’t find any articles that dealt explicitly with creating a DLL in straight ‘C’ then importing the methods in the ‘C’ dll from C#.

<o:p> 

This begs the obvious question: why would you want to write a Dll in ‘C’ in the first place?

<o:p> 

Well, in my case (I’ll try to keep the story short) I have a fifteen year old ISA card that supports eight electronic relays. These relays can switch electronic appliances on or off from computer control through the IO bus. This is where the fun begins because you cannot simply use the ANSI ‘C’ method outportb() to send a value out directly to an IO port while running various flavors of XP like you could do in the past with old versions of Windows where all processes shared the same memory heap (thus causing all of those fun access violations).

<o:p> 

I found a ready made device driver written in ‘C’ that allows a process access to IO ports in XP but in order to make a call outportb() from C#,  still required that I write an ‘adaptor’ .Dll in ‘C’.

<o:p> 

I knew how to use the [DllImport()] attribute when importing native Win32 methods from user.dll etc. but I found that that very technique did not work with the Dll that I had written myself in ‘C’.

<o:p> 

The first problem was that the C# compiler kept throwing an error that said “Unable to find an entry point named OpenIO in DLL PortIO.dll. After looking carefully at the method signature in OpenIO – I could find nothing wrong but then I remembered that there was something you had to do with a .DEF file or something. I scoured with Google searches where I found bits and pieces but no articles that addressed my problem explicitly.

<o:p> 

In summary here are the lessons learned (some re-learned):

<o:p> 

-         When using the .Net compiler (or the VC6 compiler as well) with a ‘C’ project where the source file extension is *.cpp – you must either turn name mangling off by enclosing your public (__declspec(dllexport) = public in ‘C’) methods in a block defined as ‘extern “C”’ or use a .DEF file. I chose to use ‘extern “C”’. Name mangling is how C++ compilers distinguish overloaded methods with the same name. Note that you cannot overload any methods enclosed in ‘extern “C”. I believe with VC6 you can turn off mangling by simply changing the source extension to *.c but I have not tried this with VS.Net.<o:p>

-         You can import mangled or any other public method by using the EntryPoint parameter for DllImport which will take either an ordinal index or the method name. I use both method name and ordinal position in the sample code to illustrate this point.<o:p>

-         Dumpbin.exe which comes with VS.Net is indispensable when troubleshooting Dlls written in ‘C’. An example of how to use this and sample output is in the comments of the source code.<o:p>

-         If you do not include the modifier __declspec(dllexport) in your ‘C’ Dll function definition (prototype in header [.h] file) and declaration (function body in *.c or *.cpp file) the method will not be exported as ‘public’ and the entry point will not show up in the binary dump of the Dll.

<o:p> 

<o:p>Here's an example of a properly defined native Dll method written in 'C':

<o:p> 

<o:p>

extern "C" <o:p>

{<o:p>

//Note: must use __declspec(dllexport) to make (export) methods as 'public'<o:p>

      __declspec(dllexport) void DoSomethingInC(unsigned short int ExampleParam, unsigned char AnotherExampleParam)<o:p>

      {<o:p>

            printf("You called method DoSomethingInC(), You passed in %d and %c\n\r", ExampleParam, AnotherExampleParam);<o:p>

      }<o:p>

}//End 'extern "C"' to prevent name mangling<o:p>

 

 Here's what the import declaration in C# looks like:

[DllImport("C_DLL_with_Csharp.dll", EntryPoint="DoSomethingInC")]

public static extern void DoSomethingInC(ushort ExampleParam, char AnotherExampleParam);

Here's what the Dll dump looks like:

File Type: DLL

Section contains the following exports for C_DLL_with_Csharp.dll

00000000 characteristics

409557E6 time date stamp Sun May 02 13:19:50 2004

0.00 version

1 ordinal base

2 number of functions

2 number of names

ordinal hint RVA name

1 0 00011596 ?DoSomethingInMangledC@@YAXPAD@Z

2 1 0001110E DoSomethingInC

Summary

4000 .data

1000 .idata

5000 .rdata

2000 .reloc

1F000 .text

10000 .textbss

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior) Experior Technologies
United States United States
www.thorskettle.com

Comments and Discussions

 
QuestionHow To Call a 'C' Function with " unsigned char *log " as a parameter in the function Pin
Muneer Safi16-Dec-08 21:07
Muneer Safi16-Dec-08 21:07 
This Is My C Function

int BII_Read_Transaction_Log (int option, int updateFlag, int maxEntries,
unsigned char *log)


it will return 1 and will fill ( *log ) = pointer to a buffer to hold the Transaction Log data

I call it in C# as :

[DllImportAttribute("BII_V1100.dll")]
				public static extern int BII_Read_Transaction_Log(int option, int updateFlag, int maxEntries,ref byte log);

byte[] buffer = new byte[2069];
int Result = BII_Read_Transaction_Log(1, 0, -1,ref buffer[0]);


i have the buffer array filled with bytes
but when trying to convert the byte value to string
the generated string is

"X\a\f\adX\a\f 0\nBfX\a\f,0\nGdX\a\f\r\f10\nKfX\a\f\r\n50\nIiX\a\f\v+#0\nSgX\a\f\t\r80\nJfX\a\f\b$0\n8gX\a\f\"0\nHeX\a\f &0\nCiX\a\f'0\nXfX\a\f0\n5dX\a\f0\nBeX\a\f\n90\nFgX\a\f\r8,0\nKfX\a\f\r8!0\n7fX\a\f\r80\nzfX\a\f\r80\n,zfX\a\f\r80\n,zfX\a\f\r80\n$zgX\a\f\r\n0\nJgX\a\f\r\n0\n1zeX\a\f\r\f0\nGfX\a\f\r#0\n2gX\a\f\n$0\nSdX\a\f\t0"

is there is something that i missed
AnswerRe: How To Call a 'C' Function with " unsigned char *log " as a parameter in the function Pin
rserven14-Jun-10 6:02
rserven14-Jun-10 6:02 
Generalanother reason for using C dll Pin
dumparun28-Jan-07 23:37
dumparun28-Jan-07 23:37 
Questionhow to call dumpbins [modified] Pin
Xp3ll3d29-Aug-06 21:09
Xp3ll3d29-Aug-06 21:09 
AnswerRe: how to call dumpbins Pin
Sriharsha Vardhan3-Dec-06 8:45
Sriharsha Vardhan3-Dec-06 8:45 
QuestionCallingConvention? Pin
Ceus2-Sep-04 4:55
Ceus2-Sep-04 4:55 
AnswerRe: CallingConvention? Pin
Yossi_pRJ19-Jan-05 4:20
Yossi_pRJ19-Jan-05 4:20 
Generalchar* names[] Pin
kobybr23-Aug-04 10:22
kobybr23-Aug-04 10:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.