美文网首页
VC 中如何使用 BCB 编译的库文件

VC 中如何使用 BCB 编译的库文件

作者: 让笑意折了枝 | 来源:发表于2016-08-04 22:36 被阅读333次

    在 Visual C++ 或者 Visual Studio 中, 是无法直接使用 BCB 工程编译产生的库文件的. 究其原因, 是由于微软 Visual C++ lib 文件格式与 BCB 工程的 lib 文件格式不同所导致. Lib 文件中存放的是动态链接库的接口信息, 而不会含有任何函数的内部实现细节. 因此, 我们可以直接通过 Dll 文件来反向生成特定格式的 lib 文件, 以便在 VC 和 BCB 中交叉使用各个编译的动态链接库.

    以 MTK 平台的多路下载工具 SP_MDT 为例, 演示在 VC++ 中直接使用 BCB 编译的 lib 库的问题及解决方案. 我们以 Eboot 为例, 源代码目录下关于 Eboot 的文件有以下几个:
    Eboot 头文件定义, 路径: SP_MDT_SRC\Eboot
    Eboot lib 库文件, 路径: SP_MDT_SRC\Lib
    Eboot 动态链接库文件, 路径: SP_MDT_SRC\output

    我们新建一个 VC++ MFC 工程, 将上述文件全部拷贝到 MFC 工程目录下, 同时在对话框中实现如下代码段:

    #include "interface.h"
    ANDROID_DL_HANDLE_T handle;
    Android_DL_Create(&handle);
    

    此时, 编译工程会报出如下错误:

    error LNK2019: 无法解析的外部符号 _Android_DL_Create@4
    该符号在函数 "public: void __thiscall CLibDemoDlg::OnBnClickedOk(void)" 中被引用
    

    原因在于我们仅仅包含了相应函数的头文件, 而并没有导入任何的函数实现(如 cpp 源文件或者 lib 库文件). 接下来, 我们尝试直接在 VC++ 中使用 BCB 编译生成的 lib 库文件, 加入以下代码:

    #pragma comment(lib, "eboot.lib")
    

    编译时报出如下错误:

    eboot.lib : warning LNK4003: 无效的库格式; 已忽略库
    

    显然, VC++ 并不能正确的识别 BCB 所生成的 lib 库文件. 那么如何解决这个问题呢? 一般来说有两种方法:

    1. 动态加载 dll 动态链接库
      最直接的方法是, 既然有头文件, 那么就可以知道各个函数的定义, 而 dll 动态链接库则会将这些公开的函数导出. 因此, 可以直接调用 LoadLibrary 载入动态链接库, 并查找到相应的函数地址, 完成调用. 这种方法简单粗暴, 其好处是写出的源代码无论是在 BCB 还是在 VC++ 平台都能够通用. 但其缺点也很明显, 需要改写头文件, 定义各种各样的函数指针, 如果使用到的导出函数很多, 则工作量较大.
    2. 使用 VC++ 编译工具生成 lib 文件
      那么既然原有的工程提供了头文件, 为了最大程度的减少工作量, 可以通过 BCB 生成的 dll 反向输出 VC++ 的 lib 文件, 实现静态加载 dll 动态链接库. 方法如下:
      (1) 使用 dumpbin 生成 .def 文件
      dumpbin 位于 [VS_DIR]\VC\bin 目录中, 执行如下命令产生 .def 文件:
    dumpbin eboot.dll /EXPROTS /OUT:eboot.def
    

    此时, eboot.def 文件内容为:

    Dump of file E:\eboot.dll
    File Type: DLL
      Section contains the following exports for eboot.dll
        00000000 characteristics
        4E3F5BF7 time date stamp Mon Aug 08 11:45:59 2011
            0.00 version
               1 ordinal base
             101 number of functions
              44 number of names
     
        ordinal hint RVA      name
             49    0 000021F0 Android_ADV_Connect
             41    1 00001000 Android_ADV_Create
             42    2 00001150 Android_ADV_Destory
             47    3 00001B00 Android_ADV_FreeBuffer
             46    4 000015D0 Android_ADV_LoadBuffer
             51    5 00002A00 Android_ADV_Reboot
             48    6 00001B30 Android_ADV_SendBuffer
             50    7 00002640 Android_ADV_SendImage
             43    8 000011D0 Android_ADV_SetBootArg
             44    9 00001340 Android_ADV_SetDownloadArg
             45    A 000015A0 Android_ADV_SetRemoteArg
             13    B 00002FD0 Android_Boot_As_Download
             18    C 00003150 Android_DA_Download
             31    D 00003420 Android_DL_Create
             32    E 000034E0 Android_DL_Destroy
             33    F 00003550 Android_DL_Rom_Load
             34   10 00003B20 Android_DL_Rom_UnloadAll
             14   11 00003080 Android_Flash_Download
             35   12 00003B60 Android_Remote_Download
             71   13 00003C30 Android_Secured_Download
             15   14 00003330 Android_Set_Lock
             19   15 00003240 Android_Write_Trace
              9   16 000140B0 CloseActiveSync
            101   17 00010940 Eboot_DebugChangePath
              4   18 00010910 Eboot_DebugClear
              3   19 00010900 Eboot_DebugOff
              5   1A 000108F0 Eboot_DebugOn
              6   1B 00010920 Eboot_GetDLLInfo
             12   1C 000108C0 Eboot_Log
             64   1D 000154E0 GetAllDeviceNumber
             63   1E 000155F0 GetAllPresentDevicePath
             62   1F 000158B0 GetDeviceNumber
             65   20 00016400 GetPortsDriverVersion
             61   21 000159D0 GetPresentDevicePath
             10   22 000140E0 RestartActiveSync
             16   23 0000F2D0 SP_BootAsAdvmeta
             21   24 0000F680 SP_BootAsAdvmetaByUSB
              7   25 0000FA60 SP_BootAsFactoryNormalMode
             20   26 0000FDD0 SP_BootAsFactoryNormalModeByUSB
              2   27 0000EB70 SP_BootAsMeta
             17   28 0000EF00 SP_BootAsMetaByUSB
             11   29 00011260 SP_Flash_Direct_Download
              1   2A 000111C0 SP_Flash_Download
              8   2B 00013EF0 SP_MPDownload
      Summary
          106000 .data
            4000 .rdata
            3000 .reloc
            1000 .rsrc
           18000 .text
    

    (2) 为 .def 文件添加 lib 说明
    在 .def 文件开头处加入如下描述:

    LIBRARY "eboot"
    

    (3) 整理 .def 中的 EXPORT 信息
    删除除 EXPORTS 段以外的其他无用信息, 同时根据头文件将 EXPORTS 段的 ordinal 和 name 字段进行整理:

    • 如果是 stdcall 调用, 则整理为 name@param_size @ordinal 的形式; 注意, name 和 param size 之间不能有空格.
    • 如果是 cdecl 调用, 则整理为 name@ordinal 的形式;

    例如, Android_DL_Create 的定义为:

    extern int __stdcall Android_DL_Create(ANDROID_DL_HANDLE_T *p_dl_handle);
    

    可以看到该函数是一个 stdcall 调用, 其参数为 1 个指针, 占用 4 个字节, 因此整理为如下形式:

    EXPORTS ...... Android_DL_Create@4 @31
    

    (4) 根据 .def 生成 .lib 文件
    在 .def 文件整理完毕之后, 使用 lib.exe 生成 .lib 文件, 执行如下命令:

    lib /def:eboot.def /machine:i386 /out:eboot.lib
    

    即可生成 eboot.exp 和 eboot.lib 文件. 将 eboot.lib 文件拷贝到 MFC 工程目录下替换原有的 lib 文件,
    并重新编译, 通过. 将 eboot.dll 拷贝到与 exe 相同路径下, 运行正常.

    相关文章

      网友评论

          本文标题:VC 中如何使用 BCB 编译的库文件

          本文链接:https://www.haomeiwen.com/subject/xshhsttx.html