前言:为了介绍C#写界面,C++写算法的快捷开发方式,C#与C++的交互,首先介绍c++,C#内部的DLL,COM调用。
一, 静态的Lib:静态的lib经过编译后只有.h和.lib文件,没有dll,因为实现部分也包含在lib中,这就是与动态dll的区别。还有在写静态lib的时候不需要在使用导出关键字_declspec(dllexport)。一般有2中方法调用静态lib,如下实例:
静态lib:CPPLib->test.h
#pragma once
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
"
StdAfx.h
"
#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
"
stdafx.h
"
//
#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
#pragma once
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
"
StdAfx.h
"
#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
#include
"
stdafx.h
"
#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
#pragma once
//
#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
//
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:
//
library.h
#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
"
stdafx.h
"
#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中方法,一般对类的导出调用要使用函数封装哦!:~