??xml version="1.0" encoding="utf-8" standalone="yes"?> 1Q关于__declspec(dllimport)和__declspec(dllexport) 在一个DLL的编写过E中Q如果要使一个变量、一个函数或一个类能够被外部程序调用,在函数声明上加上__declspec(dllimport)关键字?/p>
例: 引出一个变量: 引出一个函敎ͼ 引出一个类Q?br />class __declspec(dllexport) CClassEx 在外部程序引用DLLӞ如果采用隐式调用的方法(关于隐式调用E后讨论Q,需要包含DLL文g相关的头文gQ这个头文g用__declspec(dllimport)关键字指ZDLL导出的内容(实际上就是把原来的__declspec(dllexport)全部替换为__declspec(dllimport)Q?/p>
例: 引入一个变量: 引入一个函敎ͼ 引入一个类Q?br />class __declspec(dllimport) CClassEx Z提高E序可读性,可以定义如下宏: 实际上一般定义如下宏Q?br /> MYDLL_EXPORTS
MYDLL_API
__declspec
(
dllexport
)
MYDLL_API
__declspec
(
dllimport
)
q样Q在源程序的实现文g中先定义
MYDLL_EXPORTS
Q再包含q个头文Ӟ在外E序内,可以直接包含q个头文件。这U方法可以实C个文件多U用途?/span>
2
Q隐式调用和昑ּ调用
隐式调用是最常用的一U调用方法。它需要原
DLL
文g、原头文件和库文件组成。在E序内要包含q个头文Ӟq加入库文g一同编译。在E序启动时会把所有隐式调用的
DLL
文g加蝲到内存?/span>
如果惛_使用的时候才?/span>
DLL
文g加入到内存的话,可以使用昑ּ调用。显式调用只需要原
DLL
文g卛_Q但是用时必须对知道这?/span>
DLL
有哪些导出的W号。可以在
VS
的命令行方式下输入?/span>
depends
”命令来查看
DLL
信息?/span>
CZQ?/font>
隐式调用Q?/font>
CallDll(
void
)
{
wchar_t
wszBuf[ 32 ];
wsprintf( wszBuf, TEXT(
"%d"
), fnDllTest( 9 ) );
//fnDllTest
DLL文g导出的方?span lang="EN-US">
wprintf( wszBuf );
}
昑ּ调用Q?/font>
CallDll(
void
)
{
typedef
int
(*ADDPROC)(
int
i );
ADDPROC Fn;
HINSTANCE hInst = LoadLibrary( L
"DllTest.dll"
);
if
( NULL == hInst )
{
wprintf( L
"Failed on load DLL."
);
return
;
}
Fn = ( ADDPROC )GetProcAddress( hInst,
"fnDllTest"
);
//
_stdcall, 那么q里我们也应该?span lang="EN-US">(_stdcall ADDPROC)
if
( !Fn )
wprintf( L
"Failed on get Process Address."
);
else
{
int
i;
i = Fn( 9 );
wchar_t
wszBuf[ 32 ];
wsprintf( wszBuf, L
"%d"
, i );
wprintf( wszBuf );
}
FreeLibrary(hInst);
//
DLL
/*
* ADDRPROC Add = (ADDPROC)GetProcAddress(hInst, "add");
W而个参数也可以用序?span lang="EN-US">:
代替函数?span lang="EN-US">.
*/
}
3
Q注意事?/span>
如果使用
C++
~程Q那么在E序~译的时候会为变量名{符号重命ؓ诸如?/span>
?fnDllTest@QAEAAV
0
?/font>
?span lang="EN-US">c?span lang="EN-US">?span lang="EN-US">形式Q?span lang="EN-US">?span lang="EN-US">?span lang="EN-US">?span lang="EN-US">调用?span lang="EN-US">?span lang="EN-US">?span lang="EN-US">?span lang="EN-US">?span lang="EN-US">。针?span lang="EN-US">q?span lang="EN-US">?span lang="EN-US">问题Q?span lang="EN-US">?span lang="EN-US">?span lang="EN-US">可以?span lang="EN-US">?span lang="EN-US">导出?span lang="EN-US">W号?span lang="EN-US">?span lang="EN-US">?/span>
extern “C?/font>
”修饰符Q就可以保持原有名称。但是导出的cd仍然是重命名后的名称Q要再研I研I?/span>
如果你用MFC生成MFC DLL那么只要做如下定义就可以了class AFX_EXT_CLASS yourClass?/span>
在函数声明或定义中函数返回类型前加上关键字inlinexminQ)指定为内联?/strong> inline int min(int first, int secend) {/****/}; inline函数对编译器而言必须是可见的Q以便它能够在调用点内展开该函数。与非inline函数不同的是Qinline函数必须在调用该函数的每个文本文件中定义。当Ӟ对于同一E序的不同文Ӟ如果inline函数出现的话Q其定义必须相同。对于由两个文gcompute.C和draw.C构成的程序来_E序员不能定义这Lmin()函数Q它在compute.C中指一件事情,而在draw.C中指另外一件事情。如果两个定义不相同Q程序将会有未定义的行ؓQ?/p>
Z证不会发生这L事情Q徏议把inline函数的定义放到头文g中。在每个调用该inline函数的文件中包含该头文g。这U方法保证对每个inline函数只有一个定义,且程序员无需复制代码Qƈ且不可能在程序的生命期中引v无意的不匚w的事情?/p>
Q二Q内联函数的~程风格(摘自高质量C++/C ~程指南)
关键字inline 必须与函数定义体攑֜一h能函数成ؓ内联Q仅inline 攑֜函数声明前面不vM作用?/p>
如下风格的函数Foo 不能成ؓ内联函数Qinline void Foo(int x, int y); // inline 仅与函数声明攑֜一起void Foo(int x, int y){}而如下风格的函数Foo 则成为内联函敎ͼvoid Foo(int x, int y);inline void Foo(int x, int y) // inline 与函数定义体攑֜一起{}所以说Qinline 是一U“用于实现的关键字”,而不是一U“用于声明的关键字”。一般地Q用户可以阅d数的声明Q但是看不到函数的定义。尽在大多数教U书中内联函数的声明、定义体前面都加了inline 关键字,但我认ؓinline 不应该出现在函数的声明中。这个细节虽然不会媄响函数的功能Q但是体C高质量C++/C E序设计风格的一个基本原则:声明与定义不可Z谈,用户没有必要、也不应该知道函数是否需要内联?/p>
定义在类声明之中的成员函数将自动地成为内联函?/strong>Q例如class A{public:void Foo(int x, int y) { } // 自动地成为内联函数}成员函数的定义体放在类声明之中虽然能带来书写上的方便,但不是一U良好的~程风格Q上例应该改成:// 头文件class A{public:void Foo(int x, int y)Q}// 定义文ginline void A::Foo(int x, int y){} 慎用内联内联能提高函数的执行效率Qؓ什么不把所有的函数都定义成内联函数Q如果所有的函数都是内联函数Q还用得着“内联”这个关键字吗?内联是以代码膨胀Q复ӞZP仅仅省去了函数调用的开销Q从而提高函数的执行效率。如果执行函C内代码的旉Q相比于函数调用的开销较大Q那么效率的收获会很。另一斚wQ每一处内联函数的调用都要复制代码Q将使程序的M码量增大Q消耗更多的内存I间。以下情况不宜用内联:Q?Q如果函C内的代码比较长,使用内联导致内存消耗代仯高。(2Q如果函C内出现@环,那么执行函数体内代码的时间要比函数调用的开销大。类的构造函数和析构函数Ҏ(gu)让h误解成用内联更有效。要当心构造函数和析构函数可能会隐藏一些行为,如“偷偷地”执行了基类或成员对象的构造函数和析构函数。所以不要随便地构造函数和析构函数的定义体攑֜cd明中。一个好的编译器会Ҏ(gu)函数的定义体Q自动地取消不值得的内联(q进一步说明了inline 不应该出现在函数的声明中Q?br />
__declspec(dllexport) int iEx;
__declspec(dllexport) int fnEx( int i );
{……};
__declspec(dllimport) int iEx;
__declspec(dllimport) int fnEx( int i );
{……};
#define DllImport __declspec(dllimport)
#define DllExport __declspec(dllexport)
以便使用?/p>
]]>
Q一Qinline函数Q摘自C++ Primer的第三版Q?/p>
注意?
内联函数既能够去除函数调用所带来的效率负担又能够保留一般函数的优点。然而,内联函数q不是万能药Q?
在一些情况下Q它甚至能够降低E序的性能。因此在使用的时候应该慎重?
1Q我们先来看看内联函数给我们带来的好处:从一个用L角度来看Q内联函数看h和普通函CP
它可以有参数和返回|也可以有自己的作用域Q然而它却不会引入一般函数调用所带来的负担。另外,
它可以比宏更安全更容易调试?
当然有一点应该意识到Qinline specifier仅仅是对~译器的Q编译器有权利忽略这个徏议。那么编译器?
如何军_函数内联与否呢?一般情况下关键性因素包括函C的大,是否有局部对象被声明Q函数的复杂性等{?
2Q那么如果一个函数被声明为inline但是却没有被内联会发生什么呢Q理ZQ当~译器拒l内联一?
函数的时候,那个函数会像普通函C栯对待Q但是还会出C些其他的问题。例如下面这D代码:
// filename Time.h
#include<ctime>
#include<iostream>
using namespace std;
class Time
{
public:
inline void Show() { for (int i = 0; i<10; i++) cout<<time(0)<<endl;}
};
因ؓ成员函数Time::Show()包括一个局部变量和一个for循环Q所以编译器一般拒linlineQƈ且把它当作一个普通的成员函数。但是这个包含类声明的头文g会被单独?includeq各个独立的~译单元中:
// filename f1.cpp
#include "Time.hj"
void f1()
{
Time t1;
t1.Show();
}
// filename f2.cpp
#include "Time.h"
void f2()
{
Time t2;
t2.Show();
}
l果~译器ؓq个E序生成了两个相同成员函数的拯Q?
void f1();
void f2();
int main()
{
f1();
f2();
return 0;
}
当程序被链接的时候,linker会面对两个相同的Time::Show()拯Q于是函数重
定义的连接错误发生。但是老一些的C++实现对付q种情况的办法是通过把一?
un-inlined函数当作static来处理。因此每一份函数拷贝仅仅在自己的编译单元中
可见Q这样链接错误就解决了,但是在程序中却会留下多䆾函数拯。在q种情况
下,E序的性能不但没有提升Q反而增加了~译和链接时间以及最l可执行体的大小?
但是q运的是Q新的C++标准中关于un-inlined函数的说法已l改变。一个符合标?
C++实现应该只生成一份函数拷贝。然而,要想所有的~译器都支持q一点可能还
需要很长时间?
另外关于内联函数q有两个更o人头疼的问题。第一个问题是该如何进行维护?
一个函数开始的时候可能以内联的Ş式出玎ͼ但是随着pȝ的扩展,函数体可能要
求添加额外的功能Q结果内联函数就变得不太可能Q因此需要把inline specifier
去除以及把函C攑ֈ一个单独的源文件中。另一个问题是当内联函数被应用在代
码库的时候生。当内联函数改变的时候,用户必须重新~译他们的代码以反映q?
U改变。然而对于一个非内联函数Q用户仅仅需要重新链接就可以了?
q里惌说的是,内联函数q不是一个增强性能的灵丹妙药。只有当函数非常短小
的时候它才能得到我们惌的效果,但是如果函数q不是很短而且在很多地斚w?
调用的话Q那么将会得可执行体的体积增大。最令h烦恼的还是当~译器拒l内?
的时候。在老的实现中,l果很不h意,虽然在新的实C有很大的改善Q但?
仍然q是不那么完善的。一些编译器能够_的聪明来指出哪些函数可以内联哪些
不能Q但是,大多数编译器׃那么聪明了,因此q就需要我们的l验来判断?
如果内联函数不能增强行能Q就避免使用它!
*/
/*
用指针代替数l?
在许多种情况下,可以用指针运代替数l烦引,q样做常常能产生又快又短?
代码。与数组索引相比Q指针一般能使代码速度更快Q占用空间更。用多l数
l时差异更明显。下面的代码作用是相同的Q但是效率不一栗?
char* pBuffer = new char[100];
nTestNumber = 0;
for(dwIndex = 0;dwIndex < 100;dwIndex ++)
{
nTestNumber = pBuffer[dwIndex];
}
char* pTemp = pBuffer;
for(dwIndex = 0;dwIndex < 100;dwIndex ++)
{
nTestNumber = *(pTemp ++);
}
指针Ҏ(gu)的优Ҏ(gu)QpBuffer的地址每次装入地址pTemp后,在每ơ@环中只需对pTemp增量操作?
在数l烦引方法中Q每ơ@环中都必进行基于dwIndex值求数组下标的复杂运?
*/
]]>
l构与类很相|都表C可以包含数据成员和函数成员的数据结构。与cM同的是,l构是值类型ƈ且不需要堆分配。结构类型的变量直接包含l构的数据,而类cd的变量包含对数据的引用(该变量称为对象)?struct cd适合表示如点、矩形和颜色q样的轻量对象。尽可能将一个点表示为类Q但l构在某些方案中更有效。在一些情况下Q结构的成本较低。例如,如果声明一个含?1000 个点对象的数l,则将为引用每个对象分配附加的内存。结构可以声明构造函敎ͼ但它们必d参数。声明结构的默认Q无参数Q构造函数是错误的。L提供默认构造函C结构成员初始化为它们的默认倹{在l构中初始化实例字段是错误的。在cM,必须初始化实例对? 使用 new q算W创建结构对象时Q将创徏该结构对象,q且调用适当的构造函数。与cM同的是,l构的实例化可以不?new q算W。如果不使用 newQ那么在初始化所有字D之前,字段保持未赋值状态且对象不可用。对于结构,不像c那样存在ѝ一个结构不能从另一个结构或cȝ承,而且不能作ؓ一个类的基。但是,l构从基c?Object l承?br />
l构可实现接口,其方式同cd全一栗?br />
一个是值类型(l构Q,一个是引用cdQ类Q,l构在传递的时候如果没有指定refQ则传递的是内存中的一分副本,而class则是传递对他的引用?br />
cd堆中Q结构在栈中Q类传递的是类在堆中的地址Q而结构是在栈中另复制了一个传递,你改变传递过来的l构不会影响原结构。而类是引用,q一块内存,会改变堆中类的内?
]]>
HANDLE hFind;
WIN32_FIND_DATA wfd;
if ( !SetCurrentDirectory(strPath) )
return;
hFind = FindFirstFile(_ucT("*.*"), &wfd);
if ( hFind == INVALID_HANDLE_VALUE )
return;
while(FindNextFile(hFind, &wfd))
{
if ( (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !(wfd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) )
{
if ( wfd.cFileName[0] != '.' )
{
UCString temp = (UCString)strPath + wfd.cFileName;
if ( HasSubFolder(ucLPCTSTR(temp)) )
{
}
}
}
}
SetCurrentDirectory(_ucT(".."));