I've spent several days looking for info about precisely how to do DLLs and have found bits and pieces here and there but noplace that ties it all together. I'm thinking this could grow into a 'how-to' for DLLs which might be useful for others as well. I'd like to have code in there that people could actually use.

At the moment, I'm primarily interested in C# calling into C, but it'd be good to have one place that describes any-to-any types. Also, having a static link example would be good too. I'm using codelite.org v4684 for compiling.

In fact, it might be worth discussing this off-line so that the discussion (and my mistakes) don't add too much noise to the forum, and then I can just post the result when it's done.

So here are my examples:

DLL "C" code:

extern "C"
{  __declspec(dllexport) int addit( int a, int b ); }
int addit (int a, int b) { return a+b;}

Main "C" code (which doesn't compile so I obviously have the syntax wrong):

#include <stdio.h>
extern __declspec(dllimport)int addit( int a, int b );
int main(int argc, char **argv)
{
  int x=2;  int y=3;
  int answer = addit(x,y);
  printf("hello world, answer is %d\n", answer);
  return 0;
}

I would like to have examples for C++/C, C#/C, C/C as well as dynamically linked (.dll) and statically linked at build time, as well as VB if somebody would like to provide that, I'd be willing to create an html 'how-to'.

Oh, and also how to have string-type args and return value.
TIA!

Recommended Answers

All 8 Replies

Since I posted, I was able to get this example more or less working:
http://www.codeproject.com/KB/cs/usecdlllibincs.aspx
I removed the args and made the value void from what I wanted to do, and it works, although the 'printf' in the DLL example doesn't print anything to the console.

When I try to change the routine to have args and a return value (in the first posting of this thread), in Visual Studio C# 2010 express, I get:

PInvokeStackImbalance was detected
Message: A call to PInvoke function 'ConsoleApplication1!ConsoleApplication1.Program::addit' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

Oops, what I had in the first posting for the dll compiled, but it wasn't exactly the example, so this is what I changed it to (because I can't edit the first posting anymore):

#include <stdio.h>
extern "C"
{  __declspec(dllexport) int addit( int a, int b )
{ return a + b; }
}

It occurred to me that 'int' in C is 16 bits, and 'int' in C# is 32 bits, so I changed the type to 'long' in the C code so both the C and C# would be exchanging 32-bits and tried again, but I get the same error.

I just tried making the routine have a return value and no args and it works.

Then I tried adding in one argument and it fails, so it looks like the problem is with the arguments, not the return value.

Could it be an incompatibility between gcc and the MS Express C# compiler? Here's the gcc compile command string:
gcc -c "C:/apk/adev/visual/testdlls/testsub.cpp" -g -o ./Debug/testsub.o "-I." "-I."
gcc -shared -fPIC -o ./Debug/testsub.dll ./Debug/testsub.o "-L."

Any suggestions? It's amazing to me how often DLLs are used, but there's very little info out there that I've found to get them working.

Thanks for the tip! However, I tried his example and I get the same error. I'm thinking there's some incompatibility between gcc and the Visual Studio C# 2010 Express. It wouldn't be the first time M$ was caught doing things incompatible with the rest of the world. I've written the author to see if he has any suggestions.

What do people use for compiling C#? I'd really like to use Visual Studio because it
has the WPF stuff built it.

I just tried making the routine have a return value and no args and it works.
Then I tried adding in one argument and it fails, so it looks like the problem is with the arguments, not the return value.

This suggests mismatched calling conventions (C# is assuming Stdcall, whereas your export is Cdecl).

The following import probably works in your case:

[System.Runtime.InteropServices.DllImport("testsub.dll",
  CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]
  private static extern int addit(int a, int b);

You're a genius! Yes, it works! A few more questions...

1) Is it possible to get printf to the console to work in the DLL?

2) How would I statically link the DLL into the C# build? Would that solve the printf problem if I can't dynamically link and get printf to work?

3) Will there be any issues with strings in either direction? In other words, can I access the DLL address space from a string pointer passed to C# and visa-versa? Would I have to cast the string in C# to something to get it to print?

Forget 1 and 2. Looks like printf works already, and you can't statically link C#/C.

And 3 is more complicated. I found an example elsewhere of the syntax for MarshalAs for a string argument (to convert between 8-bit and 16-bit characters) but what is the syntax for returning a string and using MarshalAs for doing the same but reverse conversion:

private static extern char* dodll(int a, int b,
[MarshalAs(UnmanagedType.LPArray)] byte[] strA,
[MarshalAs(UnmanagedType.LPArray)] byte[] strB);

I haven't gotten this to compile yet, I'm trying to figure out what I need to change "char*" to for doing the MarshalAs on the output of the routine.

TIA!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.