简体   繁体   中英

Linker unresolved external symbols - can't find functions in dll

I am working in Visual Studio C++.

I made an class with a non-static function and packaged it as a dll. Here is the code to generate my dll:

// head file
#ifndef FUNCTIONS_H_
#define FUNCTIONS_H_

#include <string>
#include <memory>

#ifdef MATHFUNCSDLL_EXPORTS
#define MATHFUNCSDLL_API __declspec(dllexport) 
#else
#define MATHFUNCSDLL_API __declspec(dllimport) 
#endif

MATHFUNCSDLL_API class Functions
{
public:
    MATHFUNCSDLL_API void func(int, std::string);
};


extern "C" MATHFUNCSDLL_API Functions * __cdecl create_class();

#endif


// cpp file
#include "stdafx.h"
#include "Functions.h"
#include <iostream>

void Functions::func(int id, std::string name)
{
    std::cout << "Your ID: " << id << ". Your name: " << name << std::endl;
}

Functions * create_class()
{
    std::cout << __FUNCTION__ << std::endl;
    return new Functions();
}

Now I have a C++ project that loads this dll dynamically. Here is the code:

#include <iostream>
#include <Windows.h>
#include "../../testDmcDLL/testDmcDLL/Functions.h"
typedef Functions *(__stdcall *f_funci)();
int main(int argc, char ** argv)
{
    HINSTANCE hGetProcIDDLL = LoadLibrary("C:\\Documents\\Visual Studio 2013\\Projects\\testDmcDLL\\Debug\\testDmcDLL.dll");
    f_funci func_create_class = (f_funci)GetProcAddress(hGetProcIDDLL, "create_class");
    Functions * pf = func_create_class();
    ////LNK error////pf->func(1, "toto");
    system("pause");
    return 0;
}

I can make sure that hGetProcIDDLL and func_create_class have been initialized successfully (I've tested them with if , but here I removed the if ).

When I run this project, I can see that create_class is shown on the console because there is std::cout << __FUNCTION__ << std::endl; in that function. So everything looks fine.

However, when I compile it with the code pf->func(1, "toto") uncommented, I get a linker (LNK2019) error:

Error 1 error LNK2019: unresolved external symbol "__declspec(dllimport) public: void __thiscall Functions::func(int,class std::basic_string,class std::allocator >)" (__imp_?func@Functions@@QAEXHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function _main c:\\documents\\visual studio 2013\\Projects\\testLoadDmcDLL\\testLoadDmcDLL\\main.obj testLoadDmcDLL

The class definition is not quite right with the exports, it should be of the form;

class MATHFUNCSDLL_API Functions // MATHFUNCSDLL_API moved
{
public:
    void func(int, std::string); // MATHFUNCSDLL_API removed
};

Once a class is exported, all its members are exported.

You don't mention how MATHFUNCSDLL_EXPORTS is defined during compilation (from the command line or possibly in the stdafx.h), but make sure it is defined when building the dll, but not when building the exe. Be sure to link against the .lib produced with the .dll.


Notes on the LoadLibrary and GetProcAddress usage; if you require the dll to be loaded dynamically, you need to get the C++ class member function bound to the exported function. I've not seen a successful implementation of this or if it is even reasonable possible. If the use of the LoadLibrary and GetProcAddress is required, consider using an abstract class and create the object in a factory of some sort.

You don't detail the motivation for the dynamic loading of the dll, but consideration could also be given the delay loading the dll.

If the motivation is to delay the loading of the dll, but the same dll is always used, then the delay-load linking may help. If the motivation is to load an unknown dll (by name/location) based on some runtime parameter (or configuration), then the virtual base class and a single C-style function as a factory for the object is probably the preferred solution.

There is a good code project article on this describing various solutions for this. In particular using the abstract base class is very portable.

If you don't rely on the import library but call GetProcAddress , you need to do that for every function you're importing. You never called GetProcAddress for __imp_?func@Functions@@QAEXHV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z (which is how your Functions::func is mangled in the DLL).

Also, be aware that you get a function pointer from GetProcAddress . While that points to the code implementing pf->func , function pointers aren't called with member function call syntax.

The root problem is that GetProcAddress really is designed for C, not C++.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM