2013-05-21 3 views
6

Я пришел из фона C#/Java, поэтому я пытаюсь понять, как создать dll C++, который ведет себя подобно C# dll.Как экспортировать класс C++ в качестве dll?

Я экспериментировал с __declspec(dllexport) и __declspec(dllimport), но мне удалось запустить его только для статических методов. Я уверен, что это связано с моим ограниченным пониманием.

Как я могу экспортировать классы в C++ (целиком, включая частные члены), и иметь возможность создавать их в конце ссылки так же, как и с C#? Некоторые указатели на онлайн-ресурсы/учебник также будут делать это.

Я начал использовать шаблон dll MFC, и, честно говоря, я понятия не имею, что такое 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 failed\n")); 
      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 failed\n")); 
     nRetCode = 1; 
    } 

    return nRetCode; 
} 

Я хотел бы иметь возможность раскомментируйте следующие строки в приведенном выше коде:

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

Пожалуйста, покажите свой код ... –

+0

@ bash.d Обновлен с кодом. – Alwyn

ответ

4

От MSDN

Чтобы экспортировать все члены общественных данных и функций-членов в классе, ключевое слово должно появиться слева от названия класса следующим образом:

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

Также , подумайте, что есть больше способов сделать это, например .DEF -files. Не спешите читать объяснения на сайте MSDN.

+0

Могу ли я затем «new» использовать класс 'CExampleExport' в ссылочном коде? через эту статью говорится, что он будет экспортировать только «публичные» члены. Означает ли это, что экземпляр класса будет иметь доступ к частному члену, только они не будут доступны или они не будут импортированы вообще, период? – Alwyn

+2

@Alwyn Он экспортирует всех членов класса, включая внутренний код, генерируемый компилятором, и данные, такие как vtable, неявно сгенерированные функции-члены, RTTI и т. Д. –

+1

Речь идет о области видимости. Вы создаете точки входа в DLL, которые можно использовать Это просто означает, что вы не можете публиковать публичных членов таким образом. –

3

Для экспорта всех членов класс, вы можете включить declspec в его декларацию, как показано ниже.

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

Это тоже правильный ответ :(Если бы я мог отметить, что вы оба получили правильный ответ, я бы это сделал. Но я дал +1. – Alwyn

5

С помощью __declspec (dllexport) и __declspec (dllimport) вы просто создаете вид api, который может использоваться для экспорта методов или членов из вашей DLL. Экспортируя эти методы, вы можете получить к нему доступ из другого dlll. Что вы можете сделать, так это создать файл заголовка, в котором вы укажете свой экспортный макрос.

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

и когда вы объявите свой метод, если вы хотите экспортировать, нужно просто поставить макрос перед вашим объявлением метода, например:

MYPROJECT_EXPORTS void myMethod(); 

А также вы должны добавить комментарий (в MS Visual Studio -> Свойства проекта -> C/C++ -> Препроцессор -> Определения предшественника.

3

Вы должны прочитать this very interesting article on CodeProject по этому вопросу.

Обратите внимание, что если вы строите DLL с C++ классов на границах (включая классы MFC, или классов STL), клиент DLL должен использовать же VC++ компилятор версии и же ЭЛТ вкус (например, многопоточный DLL-отладочный CRT, многопоточный DLL-релиз CRT и другие «более тонкие» настройки, например те же настройки _HAS_ITERATOR_DEBUGGING) для создания EXE, которые будут использовать DLL.

Вместо этого, если вы экспортируете интерфейс чистый C из DLL (но вы можете использовать C++ внутри в DLL, так же, как Win32 API), или если вы строите COM библиотеки DLL, ваши DLL клиенты могут использовать другую версию компилятора VC++ (и даже другие CRT) для использования вашей DLL.

Кроме того, обратите внимание также на то, что вышеназванная статья определяет как "C++ Mature Approach" (то есть с использованием абстрактного интерфейса).

Смежные вопросы