Lib和Dll,前者是运用于link使其,后者则于runtime起作用.按理说不该会有歧义,但偏偏微软定义DLL的调用时,又将lib给牵扯上,以致于不少初学者会发出这样的疑问:为何我link了lib,运行时还需要Dll? 本文试图以微薄之力,以基础来解释这疑问.
1.Dll Export Dll,动态链接库,从字面就知道是程序运行时才需要用上的玩意. //////////////////////////////////////////// // DllSmp.cpp : Defines the entry point for the DLL application. //////////////////////////////////////////// BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { return TRUE; } //////////////////////////////////////////// //Function.h //////////////////////////////////////////// extern "C" __declspec(dllexport) void Test(); //////////////////////////////////////////// //Function.cpp //////////////////////////////////////////// #include "Function.h" void Test() { printf("Dll Test"); } 我们只需要留意Function.h文件中函数Test的声明语句即可:extern "C" __declspec(dllexport) void Test(); C++在编译时,会对函数名进行处理,也就是说Test函数也许会变成Test@1等形式.为了避免这个情况,我们需要采用extern "C"关键字,用来告诉编译器,这个函数采用C语言的编译方式,一方面在Dll中Test会以原名出现,另一方面也让C程序能够调用C++编写的Dll库.而__declspec(dllexport)则是告诉编译器,我们这个函数要作为对外接口. 2)采用def文件 另外一种方法则是我们建立一个.def为后缀的文件,然后在内定义对外接口即可. 如果采用该方式,则之前的例子则会改建为: //////////////////////////////////////////// // DllSmp.cpp : Defines the entry point for the DLL application. //////////////////////////////////////////// BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { return TRUE; } //////////////////////////////////////////// //Function.h //////////////////////////////////////////// void Test(); //////////////////////////////////////////// //Function.cpp //////////////////////////////////////////// #include "Function.h" void Test() { printf("Dll Test"); } /////////////////////////////////////////// // DllSmp.def ////////////////////////////////////////// EXPORTS Test
如果我们知道Dll导出函数的形参,那么我们可以显式调用该函数. 那么我们调用之前例子生成Dll的Test函数,则代码可以这么写: int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { typedef void (WINAPI *DLL_TEST)(void); DLL_TEST TEST; //DllSmp.dll为我们所要调用的Dll路径. HINSTANCE hInstDll = LoadLibrary(TEXT("DllSmp.dll")); if(hInstDll != NULL) { //获取Dll函数地址 TEST = (DLL_TEST) GetProcAddress(hInstDll,TEXT("Test")); } TEST(); //释放资源 FreeLibrary(hInstDll); return 0; }
Lib有两种,一种是static lib,另一种纯粹是dll的导出函数列表(在这里我姑且称其为dynamic lib). //////////////////////////////////////////// //Function.h //////////////////////////////////////////// void Test(); //////////////////////////////////////////// //Function.cpp //////////////////////////////////////////// #include "Function.h" void Test() { printf("Static Test"); }
4.Lib 的使用 要在代码中使用lib,则必须具备两个条件,一为lib的h声明文件,二是相应的lib. 因为lib是在link阶段才发挥作用,所以只要在IDE环境中设置相应的lib路径即可.但这样会带来一个无法避免的问题,就是路径必须是固定的,假如将工程移动到别的机器进行编译,还需要对IDE重新进行设置.为避免在频繁迁移中造成lib链接失效问题,我强烈建议当确知使用何种lib时,尽可能在代码中显示包含. //lib的声明头文件 #include "../StcLib/function.h" //导入lib文件 #pragma comment (lib,"../StcLib/StcLib.lib") int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { // 调用test函数. Test(); return 0; }
在这里顺便提一下如何判断函数或宏没有声明的可能出错原因.如果调用comple可以不能顺利通过,则是没有包含相应的.h文件;如果comple顺利,但link时出错,那则是相应的lib没有导入. 如之前所述,dll文件还可以通过lib进行调用.而采用该方式,代码会显得更为精炼. //Dll导出函数的声明头文件 #include "../DllSmp/function.h" //导入dll 的lib文件,该文件包含的dll导出函数信息 #pragma comment (lib,"../DllSmp/DllSmp.lib") int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { Test(); return 0; }
|
|
来自: learnandup > 《其他》