VC++ Tips: 如何从 DLL 导出 *.DEF

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/XinYaping/article/details/52866764

背景

在 C++ 编程中,我们引用动态链接库(DLL)有两个办法:

  1. 已有 .h 和 .lib,将 .h 和 .lib 文件引入工程进行编译,将 .dll 文件拷贝到运行目录。
  2. 在程序中动态加载 .dll 文件,通过函数的指针使用 .dll 文件中定义的函数。

显然上述方法中,方法 1 比较容易。

但是,有时候我们拿到的只有 .h 和 .dll 文件,并没有 .lib 文件。怎么办呢?

假如我们方便找到 .dll 的源代码,而且该源代码的 dependency 比较好解决,这种情况下我们不妨自己编译出 .lib 文件。但是如果我们没有这么幸运呢?那么我们可以通过我下面描述的这个方法来解决。

请看我下面要讲的这个方法。

解决方案

首先说明一下我的软件环境:

  • Windows 7 64位版本
  • Visual Studio 2015 Community

在本文中,我已有 xlsxio_read.dll,我希望得到 xlsxio_read.lib。

如果你的环境和我的不一致,受影响的无非是 VC++ 的 bin 和 Common7\IDE 目录不一样。我认为你应该能够在我下面的步骤中使用你自己的路径。

生成 .DEF 文件

已知我的 \VC\bin 目录如下:

C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin

已知我的 Common7\IDE 目录如下:

C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE

所以,在控制台(俗称“命令行”)中执行:

path = C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin;%PATH%
path = C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE;%PATH%

这样好方便我们使用 dumpbin 和 lib 这两个工具。

然后,执行:

dumpbin /exports xlsxio_read.dll > xlsxio_read.def

这样,我们就得到了一个文件:xlsxio_read.def。但是,它的格式并不是正确的。

我们打开这个文件看一下:

Microsoft (R) COFF/PE Dumper Version 14.00.24213.1
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file xlsxio_read.dll

File Type: DLL

  Section contains the following exports for xlsxio_read.dll

    00000000 characteristics
    57CC218A time date stamp Sun Sep  4 21:28:42 2016
        0.00 version
           1 ordinal base
          66 number of functions
          66 number of names

    ordinal hint RVA      name

          1    0 00002283 xlsxioread_close
          2    1 00001580 xlsxioread_get_version
          3    2 000015B3 xlsxioread_get_version_string
          4    3 00002605 xlsxioread_list_sheets
          5    4 00002226 xlsxioread_open
          6    5 000036C8 xlsxioread_process
          7    6 00003BEA xlsxioread_sheet_close
          8    7 00003CD5 xlsxioread_sheet_next_cell
          9    8 00003F92 xlsxioread_sheet_next_cell_datetime
         10    9 00003F4E xlsxioread_sheet_next_cell_float
         11    A 00003EE9 xlsxioread_sheet_next_cell_int
         12    B 00003EAE xlsxioread_sheet_next_cell_string
         13    C 00003C44 xlsxioread_sheet_next_row
         14    D 00003B55 xlsxioread_sheet_open
         15    E 00003A92 xlsxioread_sheetlist_close
         16    F 00003AEC xlsxioread_sheetlist_next
         17   10 00003984 xlsxioread_sheetlist_open
         18   11 00008DE0 zip_archive_set_tempdir
         19   12 00004270 zip_close
         20   13 00006C70 zip_discard
         21   14 00006DE0 zip_error_code_system
         22   15 00006DF0 zip_error_code_zip
         23   16 00006E00 zip_error_fini
         24   17 00006E20 zip_error_init
         25   18 00006E40 zip_error_init_with_code
         26   19 00006F50 zip_error_set
         27   1A 00006E90 zip_error_system_type
         28   1B 00006FA0 zip_error_to_data
         29   1C 00007A70 zip_fclose
         30   1D 00007B80 zip_fopen
         31   1E 00007BE0 zip_fopen_index_encrypted
         32   1F 00007CD0 zip_fread
         33   20 00007EA0 zip_get_name
         34   21 00007DC0 zip_get_num_entries
         35   22 00008990 zip_name_locate
         36   23 0000A410 zip_open
         37   24 0000A0A0 zip_open_from_source
         38   25 0000A4B0 zip_source_begin_write
         39   26 0000F000 zip_source_buffer
         40   27 0000EE80 zip_source_buffer_create
         41   28 0000A690 zip_source_close
         42   29 0000A740 zip_source_commit_write
         43   2A 0000B7D0 zip_source_error
         44   2B 0000D8B0 zip_source_file
         45   2C 0000D750 zip_source_file_create
         46   2D 0000B7E0 zip_source_free = __zip_source_zip_new
         47   2E 0000B9C0 zip_source_function
         48   2F 0000B930 zip_source_function_create
         49   30 0000B8A0 zip_source_keep
         50   31 0000BFF0 zip_source_make_command_bitmap
         51   32 0000BAD0 zip_source_open
         52   33 0000BBD0 zip_source_read
         53   34 0000BCF0 zip_source_rollback_write
         54   35 0000BD50 zip_source_seek
         55   36 0000BDF0 zip_source_seek_compute_offset = _zip_stat_index
         56   37 0000BEA0 zip_source_seek_write
         57   38 0000BF30 zip_source_stat
         58   39 0000C040 zip_source_tell = __zip_string_crc32
         59   3A 0000C0C0 zip_source_tell_write
         60   3B 00010A00 zip_source_win32handle
         61   3C 00010960 zip_source_win32handle_create = _deflate_slow
         62   3D 0000DB50 zip_source_win32w
         63   3E 0000DAB0 zip_source_win32w_create
         64   3F 0000C770 zip_source_write
         65   40 0000CDF0 zip_stat_index
         66   41 0000CF50 zip_stat_init

  Summary

        1000 .CRT
        1000 .bss
        1000 .data
        2000 .debug_abbrev
        1000 .debug_aranges
        1000 .debug_frame
       19000 .debug_info
        6000 .debug_line
       17000 .debug_loc
        3000 .debug_ranges
        1000 .debug_str
        1000 .edata
        A000 .eh_frame
        1000 .idata
        E000 .rdata
        4000 .reloc
       37000 .text
        1000 .tls

现在我们要修改这个文件,使它的格式正确。其实我们参考一个已知的 .DEF 文件就好了。
在此我参考一下 sqlite.def (这是著名的 SQLite 库的DEF文件):

sqlite.def

EXPORTS
sqlite_open
sqlite_close
sqlite_exec
sqlite_last_insert_rowid
sqlite_error_string
sqlite_interrupt
sqlite_complete
sqlite_busy_handler
sqlite_busy_timeout
sqlite_get_table
sqlite_free_table
sqlite_mprintf
sqlite_vmprintf
sqlite_exec_printf
sqlite_exec_vprintf
sqlite_get_table_printf
sqlite_get_table_vprintf
sqlite_freemem
sqlite_libversion
sqlite_libencoding
sqlite_changes
sqlite_create_function
sqlite_create_aggregate
sqlite_function_type
sqlite_user_data
sqlite_aggregate_context
sqlite_aggregate_count
sqlite_set_result_string
sqlite_set_result_int
sqlite_set_result_double
sqlite_set_result_error
sqliteMalloc
sqliteFree
sqliteRealloc
sqlite_set_authorizer
sqlite_trace
sqlite_compile
sqlite_step
sqlite_finalize

我们看一下 xlsxio_read.h 好知道都有哪些函数是我们需要导出的。不需要导出的函数就可以不必出现在 .def 文件中:

xlsxio_read.h

/*****************************************************************************
Copyright (C)  2016  Brecht Sanders  All Rights Reserved

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*****************************************************************************/

/**
 * @file xlsxio_read.h
 * @brief XLSX I/O header file for reading .xlsx files.
 * @author Brecht Sanders
 * @date 2016
 * @copyright MIT
 *
 * Include this header file to use XLSX I/O for reading .xlsx files and
 * link with -lxlsxio_read.
 * This header provides both advanced methods using callback functions and
 * simple methods for iterating through data.
 */

#ifndef INCLUDED_XLSXIO_READ_H
#define INCLUDED_XLSXIO_READ_H

#include <stdlib.h>
#include <stdlib.h>
#if defined(_MSC_VER) && _MSC_VER < 1600
typedef signed __int64 int64_t;
#else
#include <stdint.h>
#endif
#include <time.h>

/*! \cond PRIVATE */
#ifndef DLL_EXPORT_XLSXIO
#ifdef _WIN32
#if defined(BUILD_XLSXIO_DLL)
#define DLL_EXPORT_XLSXIO __declspec(dllexport)
#elif !defined(STATIC) && !defined(BUILD_XLSXIO_STATIC) && !defined(BUILD_XLSXIO)
#define DLL_EXPORT_XLSXIO __declspec(dllimport)
#else
#define DLL_EXPORT_XLSXIO
#endif
#else
#define DLL_EXPORT_XLSXIO
#endif
#endif
/*! \endcond */

#ifdef __cplusplus
extern "C" {
#endif

/*! \brief get xlsxio_write version string
 * \param  pmajor        pointer to integer that will receive major version number
 * \param  pminor        pointer to integer that will receive minor version number
 * \param  pmicro        pointer to integer that will receive micro version number
 * \sa     xlsxiowrite_get_version_string()
 */
DLL_EXPORT_XLSXIO void xlsxioread_get_version (int* pmajor, int* pminor, int* pmicro);

/*! \brief get xlsxio_write version string
 * \return version string
 * \sa     xlsxiowrite_get_version()
 */
DLL_EXPORT_XLSXIO const char* xlsxioread_get_version_string ();

/*! \brief read handle for .xlsx object */
typedef struct xlsxio_read_struct* xlsxioreader;

/*! \brief open .xlsx file
 * \param  filename      path of .xlsx file to open
 * \return read handle for .xlsx object or NULL on error
 * \sa     xlsxioread_close()
 */
DLL_EXPORT_XLSXIO xlsxioreader xlsxioread_open (const char* filename);

/*! \brief close .xlsx file
 * \param  handle        read handle for .xlsx object
 * \sa     xlsxioread_open()
 */
DLL_EXPORT_XLSXIO void xlsxioread_close (xlsxioreader handle);



/*! \brief type of pointer to callback function for listing worksheets
 * \param  name          name of worksheet
 * \param  callbackdata  callback data passed to xlsxioread_list_sheets
 * \return zero to continue, non-zero to abort
 * \sa     xlsxioread_list_sheets()
 */
typedef int (*xlsxioread_list_sheets_callback_fn)(const char* name, void* callbackdata);

/*! \brief list worksheets in .xlsx file
 * \param  handle        read handle for .xlsx object
 * \param  callback      callback function called for each worksheet
 * \param  callbackdata  custom data as passed to quickmail_add_body_custom/quickmail_add_attachment_custom
 * \sa     xlsxioread_list_sheets_callback_fn
 */
DLL_EXPORT_XLSXIO void xlsxioread_list_sheets (xlsxioreader handle, xlsxioread_list_sheets_callback_fn callback, void* callbackdata);



/*! \brief possible values for the flags parameter of xlsxioread_process()
 * \sa     xlsxioread_process()
 * \name   XLSXIOREAD_SKIP_*
 * \{
 */
/*! \brief don't skip any rows or cells \hideinitializer */
#define XLSXIOREAD_SKIP_NONE            0
/*! \brief skip empty rows (note: cells may appear empty while they actually contain data) \hideinitializer */
#define XLSXIOREAD_SKIP_EMPTY_ROWS      0x01
/*! \brief skip empty cells \hideinitializer */
#define XLSXIOREAD_SKIP_EMPTY_CELLS     0x02
/*! \brief skip empty rows and cells \hideinitializer */
#define XLSXIOREAD_SKIP_ALL_EMPTY       (XLSXIOREAD_SKIP_EMPTY_ROWS | XLSXIOREAD_SKIP_EMPTY_CELLS)
/*! \brief skip extra cells to the right of the rightmost header cell \hideinitializer */
#define XLSXIOREAD_SKIP_EXTRA_CELLS     0x04
/*! @} */

/*! \brief type of pointer to callback function for processing a worksheet cell value
 * \param  row           row number (first row is 1)
 * \param  col           column number (first column is 1)
 * \param  value         value of cell (note: formulas are not calculated)
 * \param  callbackdata  callback data passed to xlsxioread_process
 * \return zero to continue, non-zero to abort
 * \sa     xlsxioread_process()
 * \sa     xlsxioread_process_row_callback_fn
 */
typedef int (*xlsxioread_process_cell_callback_fn)(size_t row, size_t col, const char* value, void* callbackdata);

/*! \brief type of pointer to callback function for processing the end of a worksheet row
 * \param  row           row number (first row is 1)
 * \param  maxcol        maximum column number on this row (first column is 1)
 * \param  callbackdata  callback data passed to xlsxioread_process
 * \return zero to continue, non-zero to abort
 * \sa     xlsxioread_process()
 * \sa     xlsxioread_process_cell_callback_fn
 */
typedef int (*xlsxioread_process_row_callback_fn)(size_t row, size_t maxcol, void* callbackdata);

/*! \brief process all rows and columns of a worksheet in an .xlsx file
 * \param  handle        read handle for .xlsx object
 * \param  sheetname     worksheet name (NULL for first sheet)
 * \param  flags         XLSXIOREAD_SKIP_ flag(s) to determine how data is processed
 * \param  cell_callback callback function called for each cell
 * \param  row_callback  callback function called after each row
 * \param  callbackdata  callback data passed to xlsxioread_process
 * \return zero on success, non-zero on error
 * \sa     xlsxioread_process_row_callback_fn
 * \sa     xlsxioread_process_cell_callback_fn
 */
DLL_EXPORT_XLSXIO int xlsxioread_process (xlsxioreader handle, const char* sheetname, unsigned int flags, xlsxioread_process_cell_callback_fn cell_callback, xlsxioread_process_row_callback_fn row_callback, void* callbackdata);



/*! \brief read handle for list of worksheet names */
typedef struct xlsxio_read_sheetlist_struct* xlsxioreadersheetlist;

/*! \brief open list of worksheet names
 * \param  handle           read handle for .xlsx object
 * \sa     xlsxioread_sheetlist_close()
 * \sa     xlsxioread_open()
 */
DLL_EXPORT_XLSXIO xlsxioreadersheetlist xlsxioread_sheetlist_open (xlsxioreader handle);

/*! \brief close worksheet
 * \param  sheetlisthandle  read handle for worksheet object
 * \sa     xlsxioread_sheetlist_open()
 */
DLL_EXPORT_XLSXIO void xlsxioread_sheetlist_close (xlsxioreadersheetlist sheetlisthandle);

/*! \brief get next cell from worksheet
 * \param  sheetlisthandle  read handle for worksheet object
 * \return name of worksheet or NULL if no more worksheets are available
 * \sa     xlsxioread_sheetlist_open()
 */
DLL_EXPORT_XLSXIO const char* xlsxioread_sheetlist_next (xlsxioreadersheetlist sheetlisthandle);



/*! \brief read handle for worksheet object */
typedef struct xlsxio_read_sheet_struct* xlsxioreadersheet;

/*! \brief open worksheet
 * \param  handle        read handle for .xlsx object
 * \param  sheetname     worksheet name (NULL for first sheet)
 * \param  flags         XLSXIOREAD_SKIP_ flag(s) to determine how data is processed
 * \return read handle for worksheet object or NULL in case of error
 * \sa     xlsxioread_sheet_close()
 * \sa     xlsxioread_open()
 */
DLL_EXPORT_XLSXIO xlsxioreadersheet xlsxioread_sheet_open (xlsxioreader handle, const char* sheetname, unsigned int flags);

/*! \brief close worksheet
 * \param  handle        read handle for worksheet object
 * \sa     xlsxioread_sheet_open()
 */
DLL_EXPORT_XLSXIO void xlsxioread_sheet_close (xlsxioreadersheet sheethandle);

/*! \brief get next row from worksheet (to be called before each row)
 * \param  handle        read handle for worksheet object
 * \return non-zero if a new row is available
 * \sa     xlsxioread_sheet_open()
 */
DLL_EXPORT_XLSXIO int xlsxioread_sheet_next_row (xlsxioreadersheet sheethandle);

/*! \brief get next cell from worksheet
 * \param  handle        read handle for worksheet object
 * \return value (caller must free the result) or NULL if no more cells are available in the current row
 * \sa     xlsxioread_sheet_open()
 */
DLL_EXPORT_XLSXIO char* xlsxioread_sheet_next_cell (xlsxioreadersheet sheethandle);

/*! \brief get next cell from worksheet as a string
 * \param  handle        read handle for worksheet object
 * \param  pvalue        pointer where string will be stored if data is available (caller must free the result)
 * \return non-zero if a new cell was available in the current row
 * \sa     xlsxioread_sheet_open()
 * \sa     xlsxioread_sheet_next_cell()
 */
DLL_EXPORT_XLSXIO int xlsxioread_sheet_next_cell_string (xlsxioreadersheet sheethandle, char** pvalue);

/*! \brief get next cell from worksheet as an integer
 * \param  handle        read handle for worksheet object
 * \param  pvalue        pointer where integer will be stored if data is available
 * \return non-zero if a new cell was available in the current row
 * \sa     xlsxioread_sheet_open()
 * \sa     xlsxioread_sheet_next_cell()
 */
DLL_EXPORT_XLSXIO int xlsxioread_sheet_next_cell_int (xlsxioreadersheet sheethandle, int64_t* pvalue);

/*! \brief get next cell from worksheet as a floating point value
 * \param  handle        read handle for worksheet object
 * \param  pvalue        pointer where floating point value will be stored if data is available
 * \return non-zero if a new cell was available in the current row
 * \sa     xlsxioread_sheet_open()
 * \sa     xlsxioread_sheet_next_cell()
 */
DLL_EXPORT_XLSXIO int xlsxioread_sheet_next_cell_float (xlsxioreadersheet sheethandle, double* pvalue);

/*! \brief get next cell from worksheet as date and time data
 * \param  handle        read handle for worksheet object
 * \param  pvalue        pointer where date and time data will be stored if data is available
 * \return non-zero if a new cell was available in the current row
 * \sa     xlsxioread_sheet_open()
 * \sa     xlsxioread_sheet_next_cell()
 */
DLL_EXPORT_XLSXIO int xlsxioread_sheet_next_cell_datetime (xlsxioreadersheet sheethandle, time_t* pvalue);

#ifdef __cplusplus
}
#endif

#endif

所以,我们最终把 xlsxio_read.def 改成了以下这个样子:

xlsxio_read.def

EXPORTS

    xlsxioread_close
    xlsxioread_get_version
    xlsxioread_get_version_string
    xlsxioread_list_sheets
    xlsxioread_open
    xlsxioread_process
    xlsxioread_sheet_close
    xlsxioread_sheet_next_cell
    xlsxioread_sheet_next_cell_datetime
    xlsxioread_sheet_next_cell_float
    xlsxioread_sheet_next_cell_int
    xlsxioread_sheet_next_cell_string
    xlsxioread_sheet_next_row
    xlsxioread_sheet_open
    xlsxioread_sheetlist_close
    xlsxioread_sheetlist_next
    xlsxioread_sheetlist_open

生成 .LIB 和 .EXP 文件

执行下面的命令:

LIB /DEF:xlsxio_read.def /machine:IX86

这样就得到了 x86 版本的 .LIB 文件(和 .exp 文件)。如果想得到 x64 版本的,改变上述命令的 /machine 参数即可。

猜你喜欢

转载自blog.csdn.net/XinYaping/article/details/52866764