以下内容转自:http://blog.csdn.net/yysdsyl/article/details/2626033
前言:为了介绍C#写界面,C++写算法的快捷开发方式,C#与C++的交互,首先介绍c++,C#内部的DLL,COM调用。
一, 静态的Lib:静态的lib经过编译后只有.h和.lib文件,没有dll,因为实现部分也包含在lib中,这就是与动态dll的区别。还有在写静态lib的时候不需要在使用导出关键字_declspec(dllexport)。一般有2中方法调用静态lib,如下实例:
静态lib:CPPLib->test.h
class CTest
{
public :
CTest(void);
public :
~CTest(void);
public :
int Add( int x, int y);
int Square( int x);
};
// 函数的实现必须写在.cpp文件中,否则编译有错,说重复定义
int Max( int x, int y);
静态lib的实现文件: CPPLib->test.cpp
#include " Test.h "
CTest::CTest(void)
{
}
CTest::~CTest(void)
{
}
int CTest::Add( int x, int y)
{
return x + y;
}
int CTest::Square( int x)
{
return x * x;
}
int Max( int x, int y)
{
return x;
}
client调用CPPLibClient->CPPibClient.cpp
// #include " test.h "
// #include < windows.h >
// #include < string >
// #include < assert.h >
// #include " ../CppLib/test.h "
// #pragma comment(lib, " ../debug/CppLib.lib " )
// #pragma 使用法
// #include " test.h "
// 修改编译选项调用静态库
// 需要修改:include的path,lib的path,和加入lib的名字,如下:
// C ++-> General -> additional include directories
// Linker -> General -> additional library directories
// linker -> input -> additional dependencies
// 不能动态加载静态的lib库
// HMODULE m_handle = LoadLibrary(L " ../debug/CppLib.Lib " );
// GetProcAddress(m_handle, " Max " );
// FreeLibrary(m_handle);
int _tmain( int argc, _TCHAR * argv[])
{
CTest test;
int a = test.Add( 10 , 20 );
printf( " the result is :%d/n " ,a);
a = Max( 10 , 20 );
printf( " the result is :%d/n " ,a);
return 0 ;
}
调用方法:可以看出对于静态的只可以使用修改编译选项和pragma comment()来调用,不能使用loadlibrary()来调用。
二 ,动态DLL:在动态dll中,可以导出变量,函数和整个类。编译后有.h,.lib和dll文件,真正的实现包含在dll中,所以在client调用动态dll的时候,必须要使用dll,最后和client的放在同意目录下。要导出必须使用导出关键字_declspec(dllexport)。有时还使用extern “C”,为了使导出能够与C兼容,一般我们都加extern “c”。
一般调用有3中方法,实例如下:
实例1:演示了导出变量和函数,和前2中调用方法,修改编译选项和pragma comment().
动态dll:CPPdll->test.h
extern " C " _declspec(dllexport) int nCppDll;
extern " C " _declspec(dllexport) int fnCppDll(void);
extern " C " _declspec(dllexport) int Max( int a, int b);
extern " C " _declspec(dllexport) int Min( int a, int b);
动态dll的实现:CPPDLL->test.cpp
#include " Test.h "
// This is an example of an exported variable
int nCppDll = 100 ;
// This is an example of an exported function .
int fnCppDll(void)
{
return 42 ;
}
int Max( int a, int b)
{
if (a >= b)return a;
else
return b;
}
int Min( int a, int b)
{
if (a >= b)return b;
else
return a;
}
client的调用:cppclient->cppclient.cpp
#pragma comment(lib, " ../debug/CppDll.lib " )
extern " C " int Max( int a, int b); // _declspec(dllimport)
extern " C " int Min( int a, int b); // _declspec(dllimport)
extern " C " _declspec(dllimport) int nCppDll;
extern " C " int fnCppDll(void);
// #include " test.h "
// 修改编译选项调用静态库
// 需要修改:include的path,lib的path,和加入lib的名字,如下:
// C ++-> General -> additional include directories
// Linker -> General -> additional library directories
// linker -> input -> additional dependencies
int _tmain( int argc, _TCHAR * argv[])
{
int a;
a = Min( 8 , 10 );
printf( " 比较的结果为 %d/n " ,a);
a = Max( 8 , 10 );
printf( " 比较的结果为%d/n " ,a);
printf( " 导出的变量:%d/n " ,nCppDll);
a = fnCppDll();
printf( " fnCppDll的结果:%d/n " ,a);
return 0 ;
}
上面演示了对一般变量和函数的导出的调用方法中的其中的2中,修改编译选项和pragma comment(),当使用pragma comment()的使用,应当注意:
使用#pragma隐式加载动态库
对于变量,必须申明且不能include头文件。extern "C" _declspec(dllimport) int nCppDll;
对于函数,或include头文件,或是申明。extern "C" int fnCppDll(void);
对于类,最好使用函数封装导出指针供使用。
参考:http://www.cppblog.com/mzty/archive/2006/07/24/10419.html
实例2:演示类的导出和使用动态加载来调用。
动态dll的类导出:CPPDll2->test.h
// #include " boost/shared_ptr.hpp "
class Test
{
public :
virtual ~Test() {}
virtual void DoIt() = 0 ;
};
// extern " C " _declspec(dllexport) std::auto_ptr < Test > CreateTest();
// extern " C " _declspec(dllexport) boost::shared_ptr < Test > CreateTest();
extern " C " _declspec(dllexport) Test * CreateTestPtr();
extern " C " _declspec(dllexport) void DeleteTestPtr(Test * );
动态dll的类导出的实现:CPPDll2->test.cpp
#include " stdafx.h "
#include " Test.h "
#include < stdio.h >
// #include < memory >
// #include " boost/shared_ptr.hpp "
class CTest : public Test
{
public :
virtual void DoIt()
{ printf( " Should do something/n " ); }
};
// std::auto_ptr < Test > CreateTest()
// {
// return std::auto_ptr < Test > ( new CTest);
// }
// boost::shared_ptr < Test > CreateTest()
// {
// return boost::shared_ptr < Test > ( new CTest);
// }
Test * CreateTestPtr()
{
return new CTest();
}
void DeleteTestPtr(Test * t)
{
if (t ! = NULL )
{
delete t;
t = NULL ;
}
}
对loadlibrary的分装,可以作为tools:
#pragma once
#include < windows.h >
#include < string >
#include < assert.h >
class Library
{
public :
explicit Library( const wchar_t * name)
{
m_handle = LoadLibrary(name);
assert(m_handle);
if (!m_handle)
throw std::runtime_error(std:: string ( " Could not find library file: " ));
}
~Library()
{
FreeLibrary(m_handle);
}
void * GetProc( const char * name)
{
void * proc = ::GetProcAddress(m_handle, name);
assert(proc);
return proc;
}
private :
HMODULE m_handle;
};
client的调用:
#include " stdafx.h "
#include " library.h "
#include " ../CppDll2/test.h "
int _tmain( int argc, _TCHAR * argv[])
{
typedef Test * ( * CREATE)();
typedef void ( * DEL)(Test * );
Library lib(L " CppDll2.dll " );
// std::auto_ptr < Test > test = ((std::auto_ptr < Test > ) lib.GetProc( " CreateTest " ));
Test * test = (((CREATE)(lib.GetProc( " CreateTestPtr " )))());
test -> DoIt();
((DEL)(lib.GetProc( " DeleteTestPtr " )))(test);
return 0 ;
}
上面的是对类的动态调用,注意需要include头文件哦!
//通过API动态加载动态库
//对于类的导出,最好使用函数封装,导出类的指针。
//动态加载dll, 如果导出的函数只使用 extern,而没有使用extern "C" 则GetProcAdress会找不到函数的指针,要想找到可以使用真正要找的函数原型哦,可能是函数名后加@@。。。,也可以使用编号来找到需要的函数地址。
//但是如果导出函数使用extern "C"的话,导出函数的返回值不能是auto_ptr<>或shared_ptr<>哦,但是我们仍然可以使用智能指针哦,采用的方法是不使用return返回,使用函数的参数返回哦。//使用智能指针导出的更好的实现,请参考 http://www.cppblog.com/eXile
//参考: http://www.cppblog.com/eXile/archive/2007/04/19/22262.html
//更多dll类型:http://www.vckbase.com/document/viewdoc/?id=1116
//调用约定:http://blog.chinaunix.net/u/21790/showart_265932.html
三 资源DLL
在C++中,我们可以建立纯资源的动态dll,比如说我们建立了一个动态的资源dll,里面增加一个string: id为IDS_APPLICATION,值为:aaa,
则我们可以在client动态调用如下:
#include < windows.h >
#include " ../ResDll/resource.h "
int _tmain( int argc, _TCHAR * argv[])
{
HMODULE hModule = LoadLibrary(L " ../debug/ResDll.dll " );
if ( NULL ! = hModule)
{
TCHAR szName[ 200 ];
::LoadString(hModule,IDS_APPLICATION,szName, 200 );
FreeLibrary(hModule);
}
return 0 ;
}
资源还可以是其他的比如是icon,bitmap。。。。等,有对应的load。()函数去调用。
四,总结
熟悉dll调用的3中方法,其中对静态的调用只有2中方法,一般对类的导出调用要使用函数封装哦!:~
以下内容转自:http://blog.csdn.net/yysdsyl/article/details/2626109
c++动态加载dll中的类(用于实现依据字符串类名创建对象)
参考资料:
http://blog.csdn.net/yysdsyl/archive/2008/07/08/2626033.aspx
用来生成dll的文件:
- Test.h
- class Test
- {
- public:
- Test(void);
- public:
- virtual ~Test(void);
- public:
- virtual void DoSth()=0;
- };
Test.h
class Test
{
public:
Test(void);
public:
virtual ~Test(void);
public:
virtual void DoSth()=0;
};
--------------------------------------------
- ///TTest.h
- /TTest继承自Test
- class TTest :
- public Test
- {
- public:
- TTest(void);
- public:
- ~TTest(void);
- public:
- virtual void DoSth(){std::cout<<"TTest:do sth/n";};
- };
///TTest.h
/TTest继承自Test
class TTest :
public Test
{
public:
TTest(void);
public:
~TTest(void);
public:
virtual void DoSth(){std::cout<<"TTest:do sth/n";};
};
- ///关键
- extern "C" __declspec(dllexport) Test* CreateTTestPtr();
- extern "C" __declspec(dllexport) void DeleteTTestPtr(Test* t);
///关键
extern "C" __declspec(dllexport) Test* CreateTTestPtr();
extern "C" __declspec(dllexport) void DeleteTTestPtr(Test* t);
--------------------------------------------------
- TTest.cpp
- #include "TTest.h"
- TTest::TTest(void)
- {
- }
- TTest::~TTest(void)
- {
- std::cout<<"destruct TTest/n";
- }
- Test* CreateTTestPtr()
- {
- return new TTest();
- }
- void DeleteTTestPtr(Test* t)
- {
- if(t!=NULL)
- delete t;
- }
TTest.cpp
#include "TTest.h"
TTest::TTest(void)
{
}
TTest::~TTest(void)
{
std::cout<<"destruct TTest/n";
}
Test* CreateTTestPtr()
{
return new TTest();
}
void DeleteTTestPtr(Test* t)
{
if(t!=NULL)
delete t;
}
- 测试程序:
测试程序:
- <pre class="csharp" name="code">#include "Test.h"
- #include <Windows.h>
- typedef Test* (CREATEFN)();
- typedef void (DELETEFN)(Test* );
- int _tmain(int argc, _TCHAR* argv[])
- {
- HINSTANCE hd=::LoadLibrary("AnotherDll.dll");
- CREATEFN* pfn;
- DELETEFN* xfn;
- pfn=(CREATEFN *)::GetProcAddress(hd,"CreateTTestPtr");
- xfn=(DELETEFN *)::GetProcAddress(hd,"DeleteTTestPtr");
- Test* t=(*pfn)();
- t->DoSth();
- (*xfn)(t);
- getchar();
- return 0;
- }
- </pre>
- <pre class="csharp" name="code"> </pre>
- <pre class="csharp" name="code"> </pre>
- <pre class="csharp" name="code"> </pre>
- <pre class="csharp" name="code">-------------------------------------------------------------------</pre>
- <pre class="csharp" name="code"> </pre>
- <pre class="csharp" name="code">向dll中添加新的继承于Test基类时,实现自身的同时实现下面的两函数</pre>
- <pre class="csharp" name="code">
- extern "C" __declspec(dllexport) Test* CreateXXXPtr();
- extern "C" __declspec(dllexport) void DeleteXXXPtr(Test* t);</pre>
- <pre class="csharp" name="code"> </pre>
- <pre class="csharp" name="code">(其中XXX表示新添加的类的类名,当然命名可以随意,只要你能在应用程序中找到这两导出函数,不过统一的命名规则</pre>
- <pre class="csharp" name="code">对根据类名创建对象是有好处的)</pre>