2010-11-28 66 views
1

我一直在试图创建一个DLL并将DLL链接到我的程序,但每次我尝试我的程序都找不到该函数。该DLL加载正常,但功能无法找到。动态链接C++ DLL ...我做错了什么?

计划:

#include <iostream> 
#include <windows.h> 
using namespace std; 

typedef void (*HelloPtr)(); 

int main() { 
    HelloPtr hello; 
    HINSTANCE hDll = LoadLibrary("dll.dll"); 
    if(hDll) 
    { 
     hello = (HelloPtr)GetProcAddress(hDll, "hello"); 
     if(hello) { 
      hello(); 
     } else { 
      // Error code here 
     } 
    } 
    return 0; 
} 

dllmain.cpp

#include "dll.h" 
#include <windows.h> 

DLLIMPORT void hello() 
{ 
    MessageBox(NULL, "Hey", "", MB_OK);   
} 

DllClass::DllClass() 
{ 

} 

DllClass::~DllClass() 
{ 

} 


BOOL APIENTRY DllMain (HINSTANCE hInst  /* Library instance handle. */ , 
         DWORD reason  /* Reason this function is being called. */ , 
         LPVOID reserved  /* Not used. */) 
{ 
    switch (reason) 
    { 
     case DLL_PROCESS_ATTACH: 
     break; 

     case DLL_PROCESS_DETACH: 
     break; 

     case DLL_THREAD_ATTACH: 
     break; 

     case DLL_THREAD_DETACH: 
     break; 
    } 

    /* Returns TRUE on success, FALSE on failure */ 
    return TRUE; 
} 

dll.h

#ifndef _DLL_H_ 
#define _DLL_H_ 

#if BUILDING_DLL 
# define DLLIMPORT __declspec (dllexport) void hello(void) 
#else /* Not BUILDING_DLL */ 
# define DLLIMPORT __declspec (dllexport) void hello(void) 
#endif /* Not BUILDING_DLL */ 

class DLLIMPORT DllClass 
{ 
    public: 
    DllClass(); 
    virtual ~DllClass(void); 

    // Says hello world 
    DLLImport void hello(void); 

    private: 

}; 


#endif /* _DLL_H_ */ 

我想知道我做错了什么,所以我可以将其记录下来并学习。

感谢

+1

我不认为可以编译:`class DLLIMPORT DllClass`会展开成`class __declspec(dllexport)void hello(void)DllClass`。 – 2010-11-28 11:11:58

+0

当你不在类中放置`void hello(void)`,并在其周围添加`extern“C”{}`块时会发生什么? – stakx 2010-11-28 11:12:53

回答

1

你需要把你的DLL的代码在extern "C"块的所有功能,否则编译器的所有功能都mangle the names

看看这个问题作进一步的信息: C++ DLL Export: Decorated/Mangled names

+0

为了方便您自己查看,请在DLL上使用[Dependency Walker](http://www.dependencywalker.com/)。它会告诉你所有的出口。 – kichik 2010-11-28 11:18:12

0

在DLL把你想要导出到

#ifdef __cplusplus 
    extern "C" { 
    #endif 

    DLLIMPORT void hello() 
    { 
    MessageBox(NULL, "Hey", "", MB_OK);   
    } 

    #ifdef __cplusplus 
    } 
    #endif 
0

函数名are mangled出口时,出于显而易见的原因。如果你正在使用函数重载呢?如果在两个不同的类中有一个名为hello()的函数呢?例如,Qt的QString& remove(const QRegExp& rx)导出为[email protected]@@[email protected]@@@Z。解决这个问题的最简单的方法是使用extern "C"和cdecl或stdcall导出函数,以便它们不被破坏(或以更标准/可预测的方式破坏)。

0

您有:

#if BUILDING_DLL 
# define DLLIMPORT __declspec (dllexport) void hello(void) 
#else /* Not BUILDING_DLL */ 
# define DLLIMPORT __declspec (dllexport) void hello(void) 
#endif /* Not BUILDING_DLL */ 

然后,你必须:

DLLIMPORT void hello() 

的组合会变成这样,这没有任何意义:

__declspec (dllexport) void hello(void) void hello() 

更改您的DllImport宏代之以:

#if BUILDING_DLL 
# define DLLIMPORT __declspec(dllexport) 
#else /* Not BUILDING_DLL */ 
# define DLLIMPORT __declspec(dllimport) 
#endif /* Not BUILDING_DLL */ 

编辑:你也有dllexport两种情况;下层应该是dllimport。

您还在hello方法中使用了DLLImport而不是DLLIMPORT。

你也不能(或至少不应该)在DLL中导出非静态类成员。如果你想导出C++类,我会推荐:

  1. 导出DLL函数,它会在你的类对象上创建,销毁和调用方法。创建函数会返回类似HANDLE,void *或类似的不透明指针。其他方法会将其作为参数,将其转换为实际的内容,然后调用该方法。

  2. 使用COM。

您还应该遵循Sanja Melnichuk的建议,以避免导出的函数名称被修饰。

下面是一个例子Dll.h:

#ifndef _DLL_H_ 
#define _DLL_H_ 

#if BUILDING_DLL 
# define DLLIMPORT __declspec(dllexport) 
#else /* Not BUILDING_DLL */ 
# define DLLIMPORT __declspec(dllimport) 
#endif /* Not BUILDING_DLL */ 


extern "C" 
{ 
    DLLIMPORT void hello(void); 
} 

注意DllClass走了。 (你在dllmain.cpp中的hello函数没有变化,因为它从未指定它是DllClass的一部分。)

不要忘记在DLL项目中定义BUILDING_DLL,并确保不在项目中定义它它试图加载DLL。