说说static lib ,dynamic lib,dll

//========================================================================
//TITLE:
//    说说Lib和Dll
//AUTHOR:
//    norains
//DATE:
//    Wednesday  30-January-2008
//Environment:
//    VS2005 + SDK-WINCE5.0-MIPSII(Include web browser component)    
//========================================================================
    Lib和Dll,前者是运用于link使其,后者则于runtime起作用.按理说不该会有歧义,但偏偏微软定义DLL的调用时,又将lib给牵扯上,以致于不少初学者会发出这样的疑问:为何我link了lib,运行时还需要Dll? 本文试图以微薄之力,以基础来解释这疑问.
   

1.Dll Export

    Dll,动态链接库,从字面就知道是程序运行时才需要用上的玩意.
    
    Dll和Exe其实架构上非常相似,相同之处是两者都是二进制文件;不同的是,Exe以WinMain为函数入口点(console程序为Main),而Dll则是DllMain.除了该点,本质上Exe和Dll再无更多区别.
    
    创建一个Dll不比一个Exe的复杂,以Evc为例,只要在Project标签栏中选择WCE Dynamic-Link Library即可.唯一还需要操心的则是我们必须定义Dll的函数导出接口.
    
    定义导出接口有两种方式:
    
    1)采用__declspec
    
    以某个Dll导出一个名为Test函数作为例子: 

////////////////////////////////////////// //    
//  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



2.Dll调用方式之一

    如果我们知道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 ;
}



3.Lib Type

    Lib有两种,一种是static lib,另一种纯粹是dll的导出函数列表(在这里我姑且称其为dynamic lib).
    
    他们的异同大致如下:
    
    1)两者都是二进制文件.
    
    2)两者都是在link期使用
    
    3)static lib在link之后可以直接运行使用,dynamic lib还需要相应的dll配合.
    
    4)static lib需要建立工程进行编译,dynamic lib是编译Dll自动生成的附加产物
    
    因为dynamic lib是自动生成的,我们先不管它,接下来看看如何建立一个static lib.
    
    static lib没有函数入口点,也就是说,并没有类似于WinMain或DllMain的函数,简单的说,只是函数的一个集合而已.想要建立static lib也非常简单,以EVC为例,只要建立工程时选择WCE Static Library即可.
    
    将之前的例子改装为static lib,则代码只需如此更改:

////////////////////////////////////////// //
// Function.h
////////////////////////////////////////// //
void  Test();

////////////////////////////////////////// //
// Function.cpp
////////////////////////////////////////// //
#include  " Function.h "
void  Test()
{
    printf(
" Static Test " );
}



    没有DllMain,也没有WinMain,甚至连标识导出的关键字__declspec也不需要,就是这么简单.
    
   

4.Lib 的使用

    要在代码中使用lib,则必须具备两个条件,一为lib的h声明文件,二是相应的lib. 因为lib是在link阶段才发挥作用,所以只要在IDE环境中设置相应的lib路径即可.但这样会带来一个无法避免的问题,就是路径必须是固定的,假如将工程移动到别的机器进行编译,还需要对IDE重新进行设置.为避免在频繁迁移中造成lib链接失效问题,我强烈建议当确知使用何种lib时,尽可能在代码中显示包含.
    
    无论是static lib还是dynamic 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 ;
}


   
    代码中的StcLib.lib如果是static,则编译完毕后直接运行即可;如果为dynamic,则还需要拷贝相应的dll到相关目录(在wince中,可拷贝到当前运行目录或windows文件夹).

    在这里顺便提一下如何判断函数或宏没有声明的可能出错原因.如果调用comple可以不能顺利通过,则是没有包含相应的.h文件;如果comple顺利,但link时出错,那则是相应的lib没有导入.
   
    
    
4.Dll调用方式之二

    如之前所述,dll文件还可以通过lib进行调用.而采用该方式,代码会显得更为精炼.
    
    以lib形式来改写文中的第2点dll调用代码:


// 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 ;
}



    DLL两种调用方式各有利弊.在代码编写阶段,动态获取Dll导出函数地址比较麻烦,既要读取又要释放,还要判断是否获取导出函数地址;而采用lib方式,则只需要包含头文件以及相关的lib即可非常方便使用. 在部署阶段,动态获取Dll导出函数方式中,只要dll的函数形参没有改变,exe不用重新编译而只是更新相应的dll即可;而lib方式,因为lib静态列出了Dll函数地址,Exe程序又是根据该地址调用Dll函数,在Dll更新之后,导出函数的地址不一定和之前的相同,所以exe文件还需要根据更新的Dll所产生的lib重新进行编译.
    
    还有一点需要注意的是,即使是相同的代码,如果编译器不同,那么Dll导出函数的地址也不一定相同.



转自:http://dev.10086.cn/cmdn/wiki/index.php?doc-view-3016.html

你可能感兴趣的:(dll,exe,library,编译器,WinCE,winapi)