norains的专栏

只专注于WINCE开发

用户操作
[即时聊天] [发私信] [加为好友]
norainsID:norains
142931次访问,排名598,好友0人,关注者53人。
代码其实是一种乐趣
norains的文章
原创 189 篇
翻译 0 篇
转载 10 篇
评论 274 篇
norains的公告
联系方式请看置顶文章
最近评论
dfdf:讨厌MFC!我觉得MFC就是太乱了!看似无用的代码不要不行,MD微软啥都给我们做完了,原理性的东西我们却永远没法搞懂了!
ironox:有个地方 我觉得很别扭,不知道怎么办好

比如说 CReg reg(HKEY_CURRENT_USER,TEXT("ControlPanel\Volume"));
ControlPanel\Volume 有可能不存在呀,这个该怎么处理哦?对象虽然创建了,出错了也没提示
szterry:呵呵,果然工作狂技术狂,同感,一样的感觉……不过我才刚毕业一年……搞IT就是玩……
jinlking:这个botton的实现只是在主窗口画了一块区域,对于事件的处理还要放在主窗口的窗口处理函数之中,在对应的消息处理上调用CheckTap来判断是否是此“按钮”,问一下,这种方法与把按钮封装在子窗口中有什么区别,二者使用那个更好?
KUODY:博主真是好人
文章分类
收藏
    相册
    动漫
    文章图片
    程序交流
    xumercury的BLOG
    狗友们的博客
    清蒸石斑鱼
    美女如刀锋
    茁茁的BLOG
    魅力老姐的窝
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 说说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导出函数的地址也不一定相同.

    发表于 @ 2008年01月30日 22:14:00|评论(loading...)|编辑

    新一篇: 燕殇 | 旧一篇: 又一年

    评论

    #electroniXtar 发表于2008-02-13 16:24:39  IP: 202.115.203.*
    博主这篇文章解释了我很多疑虑啊,感谢!

    有一个问题,如果我有一个.lib static library,可以被VB、MASM调用那种,我想把它转换成dll以便被Dephi和C#调用,看博主的文章猜想应该可以实现:
    1. 自动导出dep格式
    2. 手动link .lib为 dll
    由于我是C/C++白痴,希望博主能够指导一下如何手动导出dep、手动link。谢谢!

    我想把网上的ufmod.lib 转换成ufmod.dll
    我的邮箱是electronixtar@gmail.com
    2008-02-14 10:26:01作者回复
    确切地说,lib文件过程大概如此: .cpp->.obj->.lib, 而dll则是.cpp->.obj->.dll, 所以你无法link .lib为dll。不过,似乎你倒是可以新建一个dll工程,然后在该工程中将lib link进dll中。
    #bobo 发表于2008-02-14 13:42:28  IP: 222.66.38.*
    重新建个dll的工程吧,

    记得类前加宏:
    #ifdef DLL_EXPORT
    #define DLLImportExportMacro __declspec(dllexport)
    #else
    #define DLLImportExportMacro __declspec(dllimport)
    #endif
    #electroniXtar 发表于2008-02-15 21:58:50  IP: 202.115.203.*
    感谢!

    我在Visual Studio 2008里新建一个dll工程,然后该怎么做啊?貌似没找到哪里可以把lib link进dll

    胡乱编译了一下,发现依赖msvcr90.dll啊?是不是只有VC6才不依赖这个dll?

    多谢指导!
    2008-02-16 21:15:30作者回复
    在代码中采用#pragma comment (lib,"..\StcLib\StcLib.lib")这样的语句在link阶段就会查找相应的lib。但估计这样对于解决你的问题似乎并无太多帮助,link在dll,还是需要在dll中自己自定义导出函数,这还不如直接在主代码中使用更方便。
    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © norains