0

I need to dynamically load a dll in C++.

I have followed this tutorial http://msdn.microsoft.com/en-us/library/ms235636.aspx to create the dll and everything worked fine.

Then I followed this one http://msdn.microsoft.com/en-us/library/64tkc9y5.aspx and I've adapted the console application as follow:

typedef DOUBLE(CALLBACK* DllFunc)(DOUBLE, DOUBLE);

int _tmain(int argc, _TCHAR* argv[])
{
    HINSTANCE hDLL;               // Handle to DLL
    DllFunc dllFunc1;
    DOUBLE p1 = 1.0, p2 = 2.0, r;
    hDLL = LoadLibrary(L"MathFuncsDLL");
    if (hDLL != NULL)
    {
        cout <<  "DLL loaded: " << hDLL << endl;
        dllFunc1 = (DllFunc)GetProcAddress(hDLL, "MyMathFuncs@MathFuncs@Multiply");
        if (!dllFunc1)
        {
            // handle the error
            FreeLibrary(hDLL);
            cout << "Function not found!" << endl;
            return -1;
        }
        else
        {
            // call the function
            r = dllFunc1(p1, p2);
            cout << "The result is: " << r << endl;
        }               
    }
    else {
        cout << "Dll not found" << endl;
        return -1;
    }
    cout << "Press any key to exit." << endl;
    int i;
    cin >> i;
    return 0;
}

The DLL is loaded correctly and it is not null. The problem is the GetProcAddress() function which always return 0.

I've tried with every combination of Namespace, ClassName, Method name. I've tried to use the scope operator (::) instead of the @ in the function name.

I've tried to define the entire namespace as extern "C" but nothing changes. Every time i run or debug the console application, it cannot find the 'Multiply' function.

I think I'm missing something... Where am I wrong?


EDIT

Dependency Walker exposed me the following Export Table:

DLL Export table

Now I wonder what the last part of the function name means... Why does the __declspec(dllexports) add those symbols?

  • Please dump your dll's symbols, and add that. – Deduplicator Oct 14 '14 at 16:37
  • 1
    Hard to guess where you got that name from, looks like you just guessed at it. It ought to be "?Multiply@MyMathFuncs@MathFuncs@@SANNN@Z" for the MSVC++ compiler. Use Dumpbin.exe /exports on the DLL to see the names. You avoid having to do awful things like this by linking the .lib file that the DLL project generated. – Hans Passant Oct 14 '14 at 16:49
  • Nothing more, actually... For sake of curiosity, I was asking why the compiler add those symbols.. Khouri Giordano's answer, below, explain that! ;) – Riccardo Cipolleschi Oct 15 '14 at 09:52
  • http://en.wikipedia.org/wiki/Name_mangling – David Heffernan Oct 15 '14 at 09:54

2 Answers2

3

Welcome to C++ name mangling. All of the cruft that the compiler adds to your function names is to ensure that each function with a unique signature has a unique name. Microsoft does name mangling one way and GCC/Clang does it another. It isn't standardized, but compilers on a particular OS all do name mangling the same way so they can all get along.

The only way to ensure your name remains predictable by humans is to declare the exported DLL function as extern "C". However, this limits you to exporting C functions.

In libraries I've worked on, there is one exported C function to initialize the library and get back an interface pointer. In this case, "interface" means an abstract virtual base class with no data and only virtual functions.

This is the proper way to declare an interface class:

struct my_interface
{
    virtual int my_function1( int param1, int param2 ) = 0;
    virtual int my_function2( const char *param ) = 0;

#if CHOOSE_DESTRUCTION_TYPE

protected:
    // Protected non-virtual destructor prevents the use of delete on the interface pointer.
    // Must be defined because it will be used as objects of derived types are destructed.
    ~my_interface() {};

#else

    // Public virtual destructor allows the use of delete on the interface pointer.
    virtual ~my_interface() = 0;

#endif

private:
    // Private copy assignment prevents "*ptr1 = *ptr2".
    // This odd syntax CAN be supported, but you probably shouldn't.
    // Only needs to be declared because nobody can call it.
    my_interface & operator=( const my_interface & );

    // Ditto for move assignment.
    my_interface & operator=( my_interface && );
};
Khouri Giordano
  • 1,426
  • 15
  • 17
2

Use a tool like dumpbin or Dependency Viewer to inspect the exported function names. This will allow you to diagnose which of the likely failure modes applies to your case:

  1. The function is not exported, or
  2. The function is exported, but the name is decorated, or
  3. The function is exported with the name that you expected, but you just typed it incorrectly.
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490