24

I have written a DLL in dev C++. The DLL's name is "DllMain.dll" and it contains two functions: HelloWorld and ShowMe. The header file looks like this:

DLLIMPORT  void HelloWorld();
DLLIMPORT void ShowMe();

And the source file looks like this:

DLLIMPORT void HelloWorld ()
{
  MessageBox (0, "Hello World from DLL!\n", "Hi",MB_ICONINFORMATION);
}

DLLIMPORT void ShowMe()
{
 MessageBox (0, "How are u?", "Hi", MB_ICONINFORMATION);
}

I compile the code into a DLL and call the two functions from C#. The C# code looks like this:

[DllImport("DllMain.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void HelloWorld();

[DllImport("DllMain.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void ShowMe();

When I call the function "HelloWorld" it runs well and pops up a messageBox, but when I call the function ShowMe an EntryPointNotFoundException occurs. How do I avoid this exception? Do I need to add extern "C" in the header file?

atoMerz
  • 7,534
  • 16
  • 61
  • 101
user1333098
  • 243
  • 1
  • 2
  • 6

3 Answers3

17

The following code in VS 2012 worked fine:

#include <Windows.h>
extern "C"
{
    __declspec(dllexport) void HelloWorld ()
    {
        MessageBox (0, L"Hello World from DLL!\n", L"Hi",MB_ICONINFORMATION);
    }
    __declspec(dllexport) void ShowMe()
    {
        MessageBox (0, L"How are u?", L"Hi", MB_ICONINFORMATION);
    }
}

NOTE: If I remove the extern "C" I get exception.

atoMerz
  • 7,534
  • 16
  • 61
  • 101
  • ok,I have change the code and the problem is solved.thanks very much. – user1333098 May 03 '13 at 06:54
  • 18
    It doesn't answer how to call C++ (i.e. mangled code) functions from C#. – Hi-Angel Oct 01 '14 at 15:15
  • 1
    @Hi-Angel I don't know what a mangled code is and how to call it from C#. If you'd like to complete my answer please post a comment or you could post your own answer. – atoMerz Oct 01 '14 at 19:43
  • @atoMerz I'd like to know the answer :D Well, from what I found yesterday — for I was looking for it — the only way is to find the mangled names in a *dll*, and write these instead of an usual ones. But of course it wouldn't be portable as a name mangling isn't standardized, and so GCC's one not compatible with Visual Studio one, and both incompatible with ICC, and etc.Probably if you want to use both the compilers, you have to try at first a function name of one compiler, catch an exception for the case was no such a function, and try a function name of a next compiler, something like this. – Hi-Angel Oct 02 '14 at 03:00
  • @atoMerz btw, that's funny to me that you were the one, who solved the question by the directive `extern "C"{}`, which just removes a name mangling from an object file, but you still don't know what the name mangling is :D In C++ compiler can't name a function to be in an object just like «HelloWorld», because here's could be two function of the same name that receives different argument types. «Name mangling» is the thing to solve this: it appends some symbols to the name of the function based on it's own algorithm. And this algorithms (and the resulting names) differ in a compilers. – Hi-Angel Oct 02 '14 at 03:15
  • @Hi-Angel AFAIK C++ DLLs are not portable, when I started learning about dll/so I learnt that c++ dll/so is not portable across compilers. So I was directed to use `extern "C"{}` to convert signature to C code which is less likely to encounter portability problems. Until yesterday I had no idea why this was the case, but thanks to your comment and a little bit of research I think I know now. – atoMerz Oct 02 '14 at 08:01
  • @Hi-Angel To address your question if it isn't clear from above: There's no cross-platform way of getting around name mangling and `extern "C"` should be used for exported functions (which omits mangling). – atoMerz Oct 02 '14 at 08:04
  • @atoMerz alas, the `extern "C" {}` very often couldn't be used. And that's my case: I have many classes that have many functions of the same name and different arguments. If I would wanted to remove a name mangling, I need to rewrite ¹/₁₅ of my code. – Hi-Angel Oct 02 '14 at 09:43
  • I'm decided to clarify: for the time of writing, the code wasn't supposed to be used in any kind of a shared library. And so `extern "C"{}` and alike problems wasn't considered. – Hi-Angel Oct 03 '14 at 04:57
6
using System;
using System.Runtime.InteropServices;

namespace MyNameSpace
{
    public class MyClass
    {
        [DllImport("DllMain.dll", EntryPoint = "HelloWorld")]
        public static extern void HelloWorld();

        [DllImport("DllMain.dll", EntryPoint = "ShowMe")]
        public static extern void ShowMe();
    }
}
mjb
  • 7,649
  • 8
  • 44
  • 60
  • 1
    ok,I have change the code and the problem is solved.thanks very much. – user1333098 May 03 '13 at 06:55
  • 2
    It won't work as the "HelloWorld" in the dynamic library is mangled. – Hi-Angel Oct 01 '14 at 15:40
  • @mjb Do you actually need the "EntryPoint " or is it implicit? I have seen code that do not use it. Is that a bad thing? – progLearner Jan 10 '20 at 15:40
  • 1
    @progLearner, "You can use the DllImportAttribute.EntryPoint field to specify a DLL function by name or ordinal. If the name of the function in your method definition is the same as the entry point in the DLL, you do not have to explicitly identify the function with the EntryPoint field." https://learn.microsoft.com/en-us/dotnet/framework/interop/specifying-an-entry-point#renaming-a-function-in-c-and-c – paretech Dec 14 '21 at 17:42
3

things that helped:

  • The: extern "C" { function declarations here in h file } will disable C++ name encoding. so c# will find the function

  • Use __stdcall for the C declaration or CallingConvention.Cdecl in the C# declaration

  • maybe use BSTR/_bstr_t as string type and use other vb types. http://support.microsoft.com/kb/177218/EN-US

  • download "PInvoke Interop Assistant" https://clrinterop.codeplex.com/releases/view/14120 paste function declaration from .h file in the 3rd tab = c# declaration. replace with dll filename.

Shimon Doodkin
  • 4,310
  • 34
  • 37