Skip to main content
GameDev.net gamedev.net
🔒 Locked

Calling c++ dll from c#

Started by csisy Jun 17, 2011 at 4:54 PM 11 replies 12.1k views
Original Post
csisy
csisy
Hi,

I want to use my c++ engine in c#. I've heard about the PInvoke, I've seen some tutorial, but it doesn't work, and I don't know where I am wrong.
c++ code:

int __declspec(dllexport) Add(int a, int b)
{
return (a+b);
}

This code has been complied to dll

using System;
using System.Runtime.InteropServices;

class main
{
[DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
static extern int LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);

[DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
static extern IntPtr GetProcAddress(int hModule, [MarshalAs(UnmanagedType.LPStr)] string lpProcName);

[DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
static extern bool FreeLibrary(int hModule);

delegate int Add(int a, int b);

public static void Main()
{
int hDll = LoadLibrary("DLLExporter.dll");
IntPtr funcPtr = GetProcAddress(hDll, "Add");

Add addFunc = (Add)Marshal.GetDelegateForFunctionPointer(funcPtr, typeof(Add));

int c = addFunc(5, 4);
Console.WriteLine(c);

FreeLibrary(hDll);
}
}

the hDll isn't null, but the funcPtr is 0. Where am I wrong?

I hope, you could help me,
Thanks
sorry for my bad english
ApochPiQ
ApochPiQ
Have a look at this article, particularly the Calling Convention section. Your code is probably using cdecl calling convention, whereas by default PInvoke expects the WINAPI (aka stdcall) calling convention. Try changing your DLL import spec to the correct calling convention, or just change your C++ code to add __stdcall to the function definition, and you should be good.
csisy
csisy

Have a look at this article, particularly the Calling Convention section. Your code is probably using cdecl calling convention, whereas by default PInvoke expects the WINAPI (aka stdcall) calling convention. Try changing your DLL import spec to the correct calling convention, or just change your C++ code to add __stdcall to the function definition, and you should be good.


Thanks for the fast reply


Now my code is (this is a cpp file)

int __declspec(dllexport) __stdcall Add(int a, int b)
{
return (a+b);
}

But it doesn't work

I've tried a "base" function:
delegate void MessageBox(IntPtr hWnd, string text, string caption, uint type);


int hDll = LoadLibrary("user32.dll");
IntPtr funcPtr = GetProcAddress(hDll, "MessageBoxA");

MessageBox msgFunc = (MessageBox)Marshal.GetDelegateForFunctionPointer(funcPtr, typeof(MessageBox));

msgFunc(IntPtr.Zero, "Hello world!", "title", 0);

and it works! So I think my c++ code is wrong.

Do I have only set the compiler's configuration type to dll, or should I have to set more parameters?
sorry for my bad english
csisy
csisy
Any idea?

Otherwise I'd like to use the c# to make an editor (with winforms). Is there any easy way in c++ to make an editor form?
I've seen that I can make winform controls from code, and control with winapi, but it's not the ideal solution.

So I need a winforms editor in c++, which can handle unmanaged c++ code, or I need to use my unmanaged c++ dll in c# to make winforms easy.
sorry for my bad english
bubu LV
bubu LV
If funcPtr is 0, then are you sure you are exporting function by name "Add"? If you are compiling your source code with C++ not C, then function will have name mangling, something like __Z3Addii. Either declare function as extern "C" or compile your source file as C file.

To verify what by what name are you exporting your function, try dumpbin.exe program (it comes with VC++ installation):
dumpbin /exports DLLExporter.dll
Or open your dll file in some other dll inspector.

As for calling convention, you can also indicate that for delegate - no need to change C/C++ source:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int Add(int a, int b);
csisy
csisy
I don't know where I'm wrong, but .... I'm unlucky (or simple stupid )

c++ project:
main.cpp
int __declspec(dllexport) Add(int a, int b)
{
return (a+b);
}

project settings:
[attachment=3413:dllexp01.JPG]


c# project:
main.cs
[DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
static extern int LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);

[DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
static extern IntPtr GetProcAddress(int hModule, [MarshalAs(UnmanagedType.LPStr)] string lpProcName);

[DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
static extern bool FreeLibrary(int hModule);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int Add(int a, int b);


public static void Main()
{
int hDll = LoadLibrary("DLLExporter.dll");
IntPtr funcPtr = GetProcAddress(hDll, "Add");

if (funcPtr == IntPtr.Zero)
{
Console.WriteLine("function pointer is zero");
goto _end;
}

Add addFunc = (Add)Marshal.GetDelegateForFunctionPointer(funcPtr, typeof(Add));

int c = addFunc(5, 4);
Console.WriteLine(c);

_end:
FreeLibrary(hDll);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}

and it isn't working
sorry for my bad english
bubu LV
bubu LV
Verify export table for your dll file. Does "Add" is really present there?
Does LoadLibrary returns valid handle? It doesn't return 0? If so, then C# exe simply can not find your dll file.

Also - there is one more possible problem if you are running 64-bit Windows. If so, and you are compiling 32-bit dll file, but running your C# code in AnyCPU configuration (it means that by default your C# exe will run as 64-bit process), then you won't be able to load 32-bit dll. Verify that your C# exe runs as 32-bit process.
csisy
csisy

Verify export table for your dll file. Does "Add" is really present there?
Does LoadLibrary returns valid handle? It doesn't return 0? If so, then C# exe simply can not find your dll file.

Also - there is one more possible problem if you are running 64-bit Windows. If so, and you are compiling 32-bit dll file, but running your C# code in AnyCPU configuration (it means that by default your C# exe will run as 64-bit process), then you won't be able to load 32-bit dll. Verify that your C# exe runs as 32-bit process.



I don't know how I can verify the "export table". I'm not an expert in these things, I'm just writing the code

hDll isn't 0, so maybe the dll doesn't contain the Add method (?) - as you said
I'm using 32-bit Windows, but I set the compiler to x86. Nothing changed

If you use visual studio, can you make me an example code (which works) and send it to me?
(If you can, I'll send you lots of kiss )
sorry for my bad english
Erik Rufelt
Erik Rufelt
Did you try using extern C?
Something like this:
extern "C" int __stdcall Add(int a, int b)

Also, even with extern C, stdcall names usually get the parameter size added to the name, so you would have something like "_Add@8" as your actual function name in the DLL. You can get rid of that for example by using something like this in your CPP file to add a linker command:
#pragma comment (linker, "/EXPORT:Add=_Add@8,@1")

If you want to check your DLL for what symbols it exports, Google for DLL export viewer or similar, as there are a few free ones I think that will easily show you all the functions in a DLL.

See Exporting from a DLL for some information on different ways to export functions.
bubu LV
bubu LV
I don't know how I can verify the "export table". I'm not an expert in these things, I'm just writing the code

You can run dumpbin command from above in Visual Studio C++ command line.
Or you can use tools like this: http://www.nirsoft.net/utils/dll_export_viewer.html
csisy
csisy
Eh...
[attachment=3415:dllexported.JPG]

But it isn't working... :S

edit:
yea, it's working... I don't know what I've done, but it works

If I'd like to use some class in c# (from dll), what should I do? Write "extern "C"" everywhere? I can't set the compiler to compile as C code (I've tried, it isn't work, because of class)

Thanks for the help
sorry for my bad english
bubu LV
bubu LV
You can't use C++ classes in C# in easy way. You should wrap your API with simple C functions that dispatches calls to appropriate C++ methods:
class MyClass
{
public:
MyClass(int a, float b) { ... }
bool DoSomething(int x) { ... }
};

extern "C"
{
void* __declspec(dllexport) MyClass_New(int a, float b)
{
return new MyClass(a, b);
}

void __declspec(dllexport) MyClass_Delete(void* obj)
{
delete (MyClass*)obj;
}

bool __declspec(dllexport) MyClass_DoSomething(void* obj, int x)
{
return ((MyClass*)obj)->DoSomething(x);
}
}

And then wrap those exported MyClass_xyz functions in your managed code with nice C# class.

Or you can write C++/CLI to create managed library (dll file) that wraps your native C++ class - this is much easier that write those tiny C functions, and then import them into C#. With C++/CLI all the wrapper code will be in one place.

Or you can create COM object from your class, and then marshaling will be done automatically in .NET.
Or you can do some nasty hacks like this: http://blogs.msdn.com/b/vcblog/archive/2008/12/08/inheriting-from-a-native-c-class-in-c.aspx
csisy
csisy
@[color="#1c2837"]MartinsM: Your solution is good for me Lots of kiss

[color="#1c2837"]I post the full code, if someone are interested in it.
[size=2][edited]

Of course, I'll write an class, which will manage this, but it's a pilot version [color="#1c2837"]

[color="#1c2837"]So thanks everyone for the help

[color="#1c2837"]EDIT:
[color="#1c2837"]I had some trouble with code blocks, so I uploaded the files
[color="#1c2837"][attachment=3416:cpp_in_csharp.zip]
sorry for my bad english

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.