如何将c++类导出为dll

How to export C++ class as a dll?

本文关键字:dll c++      更新时间:2023-10-16

我来自c#/Java背景,所以我想弄清楚如何创建一个行为类似于c# dll的c++ dll。

我已经用__declspec(dllexport)__declspec(dllimport)做了实验,但我只设法让它在静态方法上工作。我相信这是由于我的理解有限。

我如何在c++中导出类(包括私有成员)并能够在引用端实例化它们,就像我在c#中一样?一些指向在线资源/教程的指针也可以。

我开始使用MFC dll模板,老实说,我不知道他们的90%是什么,为什么我从CWinApp继承。我试图用CCppPracticeLibraryApp标记类,但它不再编译。

// CppPracticeLibrary.h : main header file for the CppPracticeLibrary DLL
//

#pragma once
#ifndef __AFXWIN_H__
    #error "include 'stdafx.h' before including this file for PCH"
#endif
#include "resource.h"       // main symbols
#ifdef CCppPracticeLibraryApp_EXPORTS
#define CCppPracticeLibraryApp_API __declspec(dllexport) 
#else
#define CCppPracticeLibraryApp_API __declspec(dllimport) 
#endif
// CCppPracticeLibraryApp
// See CppPracticeLibrary.cpp for the implementation of this class
//
class CCppPracticeLibraryApp : public CWinApp
{
public:
    CCppPracticeLibraryApp();
    static CCppPracticeLibraryApp_API void SayHelloWorld();
// Overrides
public:
    virtual BOOL InitInstance();
    DECLARE_MESSAGE_MAP()
};

定义文件

//CppPracticeLibrary.cpp:定义DLL的初始化例程。

#include "stdafx.h"
#include "CppPracticeLibrary.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#define CCppPracticeLibraryApp_EXPORTS

BEGIN_MESSAGE_MAP(CCppPracticeLibraryApp, CWinApp)
END_MESSAGE_MAP()

// CCppPracticeLibraryApp construction
CCppPracticeLibraryApp::CCppPracticeLibraryApp()
{
    // TODO: add construction code here,
    // Place all significant initialization in InitInstance
}
void CCppPracticeLibraryApp::SayHelloWorld()
{
    printf( "Hello world");
}

// The one and only CCppPracticeLibraryApp object
CCppPracticeLibraryApp theApp;

// CCppPracticeLibraryApp initialization
BOOL CCppPracticeLibraryApp::InitInstance()
{
    CWinApp::InitInstance();
    return TRUE;
}

客户端/引用方法

// TestConsoleApplication.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "TestConsoleApplication.h"
#include "CppPracticeLibrary.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// The one and only application object
CWinApp theApp;
using namespace std;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int nRetCode = 0;
    HMODULE hModule = ::GetModuleHandle(NULL);
    if (hModule != NULL)
    {
        // initialize MFC and print and error on failure
        if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
        {
            // TODO: change error code to suit your needs
            _tprintf(_T("Fatal Error: MFC initialization failedn"));
            nRetCode = 1;
        }
        else
        {
            // TODO: code your application's behavior here.
            /*CCppPracticeLibraryApp* testCallingLibrary =  new CCppPracticeLibraryApp();
            testCallingLibrary->SayHelloWorld();*/
            CCppPracticeLibraryApp::SayHelloWorld();
        }
    }
    else
    {
        // TODO: change error code to suit your needs
        _tprintf(_T("Fatal Error: GetModuleHandle failedn"));
        nRetCode = 1;
    }
    return nRetCode;
}

我希望能够取消上述代码中以下几行的注释:

        /*CCppPracticeLibraryApp* testCallingLibrary =  new CCppPracticeLibraryApp();
        testCallingLibrary->SayHelloWorld();*/

From MSDN

要导出类中的所有公共数据成员和成员函数,关键字必须出现在类名的左侧,如下所示:

class __declspec(dllexport) CExampleExport : public CObject
{ ... class definition ... };

另外,考虑有更多的方法可以做到这一点,比如.DEF -files。请慢慢阅读msdn网站上的解释。

使用__declspec(dllexport)和__declspec(dllimport),您只需创建一种api,可用于从dll导出方法或成员。通过导出这些方法,您可以从另一个dll访问它。您可以做的是创建一个头文件,在其中定义导出宏。

    ifdef MYPROJECT_EXPORTS
      define MYPROJECT_EXPORTS__declspec( dllexport )
   else 
       define MYPROJECT_EXPORTS__declspec( dllimport )
   endif 

,当你声明你的方法时,如果你想导出它,你只需要把你的宏放在方法声明之前,像这样:

MYPROJECT_EXPORTS void myMethod();

并且您还必须将您的符号添加到预处理器定义(在MS Visual Studio ->项目属性-> C/c++ ->预处理器->预处理器定义)

为了导出一个类的所有成员,你可以在它的声明中包括declspec,如下所示。

class __declspec(dllexport) ExportedClass
{
    //....
};

您必须阅读关于这个主题的CodeProject的这篇非常有趣的文章。

请注意,如果您在边界(包括MFC类或STL类)构建带有 c++类的DLL,您的DLL客户端必须使用相同的vc++编译器版本相同的CRT风格(例如多线程DLL调试CRT,多线程DLL释放CRT和其他"更微妙"的设置,例如相同的_HAS_ITERATOR_DEBUGGING设置)来构建将使用DLL的exe。

相反,如果你从DLL中导出一个纯C接口(但你可以在 DLL中使用c++ ,就像Win32 api一样),或者如果你构建COM DLL,你的DLL客户端可以使用不同版本的vc++编译器(甚至不同的crt)来使用你的DLL。

此外,还要注意前面提到的文章所定义的"c++成熟方法"(即使用抽象接口)。