本文讲讲用VS2008制作易语言支持库(动态库和静态库)的具体方法和步骤。
这是我学习制作支持库时的学习笔记,贴出来分享下,也方便我以后查询。
时间仓促水平有限,不到之处还请各位高手们批评指正,以便完善。
本文欢迎转载,但请注明作者和出处。谢谢!
易语言支持库制作顺序是先制作动态库(dll) 再制作静态库(lib)。

I. 动态库的制作

1. 打开VS2008, 新建项目MFC DLL, 名称mylib, 完成

2. 项目属性,配置里选择所有配置 (设置debug和release模式的配置项)
项目属性 -> 常规 -> 字符集 设置为多字节字符集
项目属性 -> C++选项卡 -> 附加包含目录 填入sdk的Elib目录,如我的Elib目录是 D:\E51\sdk\cpp\ELib

3. 编写代码
1. 打开mylib.cpp文件
2. 文件头处加入

复制代码
  1. #include <lib2.h>
  2. #include <lang.h>
  3. #include <fnshare.h>
  4. #include <fnshare.cpp>

3.文件结尾处加入自己的代码

1) 定义LIB_INFO
这段代码是定义模块信息的,只在动态模块中使用,所以加入宏__E_STATIC_LIB来定义。
也就是说,如果是静态库那么这段代码就不会被编译。
静态库编译的时候只需在项目设置的C++ -> 预处理器 中加入 __E_STATIC_LIB 即可。

复制代码
  1. #ifndef __E_STATIC_LIB
  2. static LIB_INFO LibInfo =
  3. {
  4. /* { 库格式号, GUID串号, 主版本号, 次版本号, 构建版本号, 系统主版本号, 系统次版本号, 核心库主版本号, 核心库次版本号,
  5. 支持库名, 支持库语言, 支持库描述, 支持库状态,
  6. 作者姓名, 邮政编码, 通信地址, 电话号码, 传真号码, 电子邮箱, 主页地址, 其它信息,
  7. 类型数量, 类型指针, 类别数量, 命令类别, 命令总数, 命令指针, 命令入口,
  8. 附加功能, 功能描述, 消息指针, 超级模板, 模板描述,
  9. 常量数量, 常量指针, 外部文件} */
  10. LIB_FORMAT_VER, _T(LIB_GUID_STR),
  11. LIB_MajorVersion, LIB_MinorVersion, LIB_BuildNumber,
  12. LIB_SysMajorVer, LIB_SysMinorVer, LIB_KrnlLibMajorVer, LIB_KrnlLibMinorVer,
  13. _T(LIB_NAME_STR), __GBK_LANG_VER, _WT(LIB_DESCRIPTION_STR), _LIB_OS(__OS_WIN),
  14. _WT(LIB_Author), _WT(LIB_ZipCode), _WT(LIB_Address), _WT(LIB_Phone), _WT(LIB_Fax), _WT(LIB_Email), _WT(LIB_HomePage), _WT(LIB_Other),
  15. sizeof(DataTypes)/sizeof(DataTypes[0]), DataTypes, LIB_TYPE_COUNT, _WT(LIB_TYPE_STR), sizeof(Commands)/sizeof(Commands[0]), Commands, ExecuteCommand,
  16. NULL, NULL, mylib_ProcessNotifyLib, NULL, NULL,
  17. sizeof(Consts)/sizeof(Consts[0]), Consts, NULL
  18. };
  19. PLIB_INFO WINAPI GetNewInf()
  20. {
  21. return (&LibInfo);
  22. };
  23. #endif

注意: GetNewInf 是易语言动态库 (dll) 唯一必须导出的函数。所以需要在.def文件(mylib.def)里加入以下

复制代码
  1. EXPORTS
  2. ; 此处可以是显式导出
  3. GetNewInf

接下来我们看看LIB_INFO 是如何定义的。具体含义可以参阅开发文档。这里根据库的不同,需要修改的地方有
1- LIB_ 这样的变量是我们另外定义的,可以定义在mylib.h中如下:

复制代码
  1. #ifndef __E_STATIC_LIB
  2. #define LIB_GUID_STR "0000000000000000000000000000" /*GUID串: {00000000-0000-0000-0000-00000000}, 必须使用guidgen.exe生成*/
  3. #define LIB_MajorVersion 1 /*库主版本号*/
  4. #define LIB_MinorVersion 1 /*库次版本号*/
  5. #define LIB_BuildNumber 20110318 /*构建版本号*/
  6. #define LIB_SysMajorVer 3 /*系统主版本号*/
  7. #define LIB_SysMinorVer 0 /*系统次版本号*/
  8. #define LIB_KrnlLibMajorVer 3 /*核心库主版本号*/
  9. #define LIB_KrnlLibMinorVer 0 /*核心库次版本号*/
  10. #define LIB_NAME_STR "支持库名称" /*支持库名*/
  11. #define LIB_DESCRIPTION_STR "支持库功能描述" /*功能描述*/
  12. #define LIB_Author "作者名称" /*作者名称*/
  13. #define LIB_ZipCode "邮政编码" /*邮政编码*/
  14. #define LIB_Address "通信地址" /*通信地址*/
  15. #define LIB_Phone "电话号码" /*电话号码*/
  16. #define LIB_Fax "传真号码" /*传真号码*/
  17. #define LIB_Email "电子邮箱" /*电子邮箱*/
  18. #define LIB_HomePage "主页地址" /*主页地址*/
  19. #define LIB_Other "其它信息" /*其它信息*/
  20. #define LIB_TYPE_COUNT 1 /*命令分类数量*/
  21. #define LIB_TYPE_STR "0000基本命令\0""\0" /*命令分类*/
  22. #endif

2- DataTypes 是库中定义的数据类型表,类型的数量可以自动由sizeof(DataTypes)/sizeof(DataTypes[0]) 计算。
Commands 函数命令信息表,ExecuteCommand 命令指针表,Consts 常量表 都是一样的。这些都是库中希望定义的成员。
如果不需要就在数量上写0,变量处替换成NULL即可。

3- mylib_ProcessNotifyLib 是库中需要定义的消息指针。必须定义在宏的外面以便静态和动态库都能调用

复制代码
  1. EXTERN_C INT WINAPI mylib_ProcessNotifyLib(INT nMsg, DWORD dwParam1, DWORD dwParam2)
  2. {
  3. #ifndef __E_STATIC_LIB
  4. if(nMsg == NL_GET_CMD_FUNC_NAMES) // 返回所有命令实现函数的的函数名称数组(char*[]), 支持静态编译的动态库必须处理
  5. return (INT)CommandNames;
  6. else if(nMsg == NL_GET_NOTIFY_LIB_FUNC_NAME) // 返回处理系统通知的函数名称(PFN_NOTIFY_LIB函数名称), 支持静态编译的动态库必须处理
  7. return (INT)"mylib_ProcessNotifyLib";
  8. else if(nMsg == NL_GET_DEPENDENT_LIBS) return (INT)NULL;
  9. // 返回静态库所依赖的其它静态库文件名列表(格式为\0分隔的文本,结尾两个\0), 支持静态编译的动态库必须处理
  10. // kernel32.lib user32.lib gdi32.lib 等常用的系统库不需要放在此列表中
  11. // 返回NULL或NR_ERR表示不指定依赖文件
  12. #endif
  13. return ProcessNotifyLib(nMsg, dwParam1, dwParam2);
  14. };

本函数的作用是接收来自易语言IDE或者运行时环境的通知。并且在编译的时候起到在静态库和动态库之间通讯的目的。

接下来我们就可以定义库中需要使用的 函数,类型,常量 了。
这些都定义在 mylib_ProcessNotifyLib 函数的前面,且都定义在宏中,如下:
#ifndef __E_STATIC_LIB
...
#endif
因为这些只需包含在动态模块里,不需要静态中定义。 函数的具体实现过程需要定义在宏的外面,具体方式会在下文中讲到。

2) 定义常量 Consts

复制代码
  1. #ifndef __E_STATIC_LIB
  2. LIB_CONST_INFO Consts[] =
  3. {
  4. /* { 中文名称, 英文名称, 常量布局, 常量等级(LVL_), 参数类型(CT_), 文本内容, 数值内容 } */
  5. { _WT("常量_ZERO"), _WT("ZERO"), NULL, LVL_SIMPLE, CT_NUM, NULL, 0 },//数值常量
  6. { _WT("常量_TEST"), _WT("TEST"), NULL, LVL_HIGH, CT_TEXT, "TEST", NULL }//文本常量
  7. };
  8. #endif

常量等级有: LVL_SIMPLE          1        // 初级
                      LVL_SECONDARY       2        // 中级
                      LVL_HIGH            3        // 高级

参数类型有: CT_NUM             1    // sample: 3.1415926
                      CT_BOOL            2    // sample: 1
                      CT_TEXT            3    // sample: "abc"

文本内容是CT_TEXT用,数值内容是CT_NUM和CT_BOOL用。

3) 定义数据类型 DataTypes

用作提供支持库自定义数据类型,包含窗口单元。一个简单的例子:

复制代码
  1. #ifndef __E_STATIC_LIB
  2. INT DatatypeCommandIndexs[] =
  3. {
  4. 2
  5. };
  6. static LIB_DATA_TYPE_INFO DataTypes[] =
  7. {
  8. /* { 中文名称, 英文名称, 数据描述, 索引数量, 命令索引, 对象状态, 图标索引, 事件数量, 事件指针, 属性数量, 属性指针, 界面指针, 元素数量, 元素指针 } */
  9. { _WT("数据类型命令"), _WT("DatatypeCommand"), _WT("测试数据类型命令。"), sizeof(DatatypeCommandIndexs)/sizeof(DatatypeCommandIndexs[0]), DatatypeCommandIndexs, NULL, 0, 0, NULL, 0, NULL, NULL, 0, NULL }
  10. };
  11. #endif

关于LIB_DATA_TYPE_INFO的解释 以及 窗口型数据的定义 都可参见开发文档中 "m_pDataType成员说明"和"数据类型说明"。

4) 定义函数,ExecuteCommand,Commands

函数书写规范是

复制代码
  1. EXTERN_C void mylib_函数名(PMDATA_INF pRetData, INT iArgCount, PMDATA_INF pArgInf)
  2. {
  3. ...
  4. };

函数的实现都需要定义在宏的外面以便静态和动态库都能使用,但ExecuteCommand,Commands则只需定义在宏的里面供动态库使用。
pRetData 输出数据指针。当对应CMD_INFO中m_dtRetType为_SDT_NULL(即定义无返回值)时,pRetData无效;
iArgCount 函数参数个数
pArgInf 函数参数指针

复制代码
  1. #ifndef __E_STATIC_LIB
  2. PFN_EXECUTE_CMD ExecuteCommand[] =
  3. {
  4. mylib_函数名 // 所有需要库中调用的函数都列在这里,用逗号隔开
  5. };
  6. static const char* const CommandNames[] =
  7. {
  8. "mylib_函数名" // 所有需要库中调用的函数名都写在这里,用逗号隔开
  9. };
  10. ARG_INFO CommandArgs[] =
  11. {
  12. /* { 参数名称, 参数描述, 图像索引, 图像数量, 参数类型(参见SDT_), 默认数值, 参数类别(参见AS_) } */
  13. { _WT("参数1"), _WT("本命令的参数1"), 0, 0, SDT_INT, NULL, NULL } //函数参数数组定义写在这里,每个{}为一个参数的表述,用逗号隔开
  14. };
  15. static CMD_INFO Commands[]=
  16. {
  17. /* { 中文名称, 英文名称, 对象描述, 所属类别(-1是数据类型的方法), 命令状态(CT_), 返回类型(SDT_), 此值保留, 对象等级(LVL_), 图像索引, 图像数量, 参数个数, 参数信息 } */
  18. { _WT("函数名"), _WT("英文函数名"), _WT("函数功能描述"), 1, NULL, SDT_BOOL, 0, LVL_SIMPLE, 0, 0, 1, CommandArgs },//基本命令
  19. };
  20. #endif

注:
a. 函数名前的前缀 mylib_ 是以后静态库中使用的。要求必须是动态库项目名称mylib的全小写形式 mylib_。
b. 只需对库中需要调出的函数加前缀处理,其他函数不需要这样书写。
c. 如果程序内部需要调用这个函数,只需使用函数名即可,无须前缀。
d. 参数类型如果是 AS_RECEIVE_VAR或AS_RECEIVE_VAR_ARRAY或AS_RECEIVE_VAR_OR_ARRAY 则参数必须是变量。
// AS_DEFAULT_VALUE_IS_EMPTY  参数可空且默认值为空
// AS_HAS_DEFAULT_VALUE 参数有默认值 且不可空
// AS_RECEIVE_VAR 参数必须是非数组变量
// AS_RECEIVE_VAR_OR_ARRAY 参数是数组或非数组变量
// AS_RECEIVE_ARRAY_DATA 参数是数组数据
// AS_RECEIVE_ALL_TYPE_DATA 参数是数组或非数组数据
以上参数除了前两个互斥,其他都可以相加使用,以便具有多个性质。
例如 AS_DEFAULT_VALUE_IS_EMPTY + AS_RECEIVE_VAR 表示参数可空,并且只能是变量。
e. 所属类别是在库中函数归类的子目录,这些子目录的名字在 LIB_INFO的LIB_TYPE_STR 字串定义。-1是数据类型,1第一类,2第二类...

sdk中关于数据类型的定义如下: 
    #define        _SDT_NULL        0           // 空白数据类型
    #define        _SDT_ALL         MAKELONG (MAKEWORD (0, 0), 0x8000)  // 通用型

/*  仅用于支持库命令定义其参数或返回值的数据类型,当用于定义库命令参数时,
        _SDT_ALL可以匹配所有数据类型(数组类型必须符合要求)。*/
    #define        SDT_BYTE         MAKELONG (MAKEWORD (1, 1), 0x8000)  // 字节
    #define        SDT_SHORT        MAKELONG (MAKEWORD (1, 2), 0x8000)  // 短整数
    #define        SDT_INT          MAKELONG (MAKEWORD (1, 3), 0x8000)  // 整数
    #define        SDT_INT64        MAKELONG (MAKEWORD (1, 4), 0x8000)  // 长整数
    #define        SDT_FLOAT        MAKELONG (MAKEWORD (1, 5), 0x8000)  // 小数
    #define        SDT_DOUBLE       MAKELONG (MAKEWORD (1, 6), 0x8000)  // 双精度小数
    #define        SDT_BOOL         MAKELONG (MAKEWORD (2, 0), 0x8000)  // 逻辑
    #define        SDT_DATE_TIME    MAKELONG (MAKEWORD (3, 0), 0x8000)  // 日期时间
    #define        SDT_TEXT         MAKELONG (MAKEWORD (4, 0), 0x8000)  // 文本
    #define        SDT_BIN          MAKELONG (MAKEWORD (5, 0), 0x8000)  // 字节集
    #define        SDT_SUB_PTR      MAKELONG (MAKEWORD (6, 0), 0x8000)  // 记录用户易语言子程序的代码地址

这些数据类型在函数定义参数时调用。

动态库制作完成后,编译会生成mylib.dll文件。把.dll改成.fne 拷贝到易语言的lib文件目录下即可使用。或者也可以修改项目属性,把编译输出文件后缀从.dll修改成.fne,并输出在易语言的lib目录中。 这样编译完后即可直接在易语言里调用。

II. 静态库的制作

如果你已经按照上面的方法书写代码并制作好了动态库,接着就可以方便的再此基础上制作静态库了。方法有两种
第一种是生成一个静态库项目编译
第二种是在原来的动态库项目上修改成静态库项目

方法一)生成静态库项目
具体步骤如下:
1. 在项目解决方案上鼠标右键 -> 添加 -〉新建项目 名称输入 mylib_static (就是动态库项目名称加后缀_static)。
VS的向导里设置程序类型 为"静态库"。去掉预编译头的钩。点击完成。

2. 选择动态库项目文件列表中的所有文件,ctrl+C 复制 在新的mylib_static项目 中ctrl+V拷贝过来。

3. 配置mylib_static 项目属性, 以release模式为例,打开release配置。修改配置如下:
+ 常规 -> 字符集 设置为多字节字符集
+ 常规 -> 全程序优化 设成 无全程序优化 (这里很重要否则会影响 resym.exe 的工作)
+ C++选项卡 -> 附加包含目录 填入D:\E51\sdk\cpp\ELib
+ C++ -> 预处理器 -> 预处理定义 添加宏 __E_STATIC_LIB
+ 生成事件 -> 生成后事件 -> 命令行 填入 D:\E51\sdk\tools\resym.exe all infile=$(TargetPath) outfile=$(TargetPath)
resym.exe 是用来修改lib库连接符号的,以解决连接时符号冲突的问题。程序位置设成你自己sdk所在位置。

设置后选择release编译即可。 编译完后会生成静态库mylib_static.lib文件。

方法二)修改动态库配置为静态库配置
具体步骤如下:
打开动态库项目mylib的项目管理,点击配置管理器,mylib的配置处下拉菜单选择 "新建", 添入名称 release_static, "从此处复制设置"选择release
创建release_static后开始修改配置如下:
+ 常规 -> 配置类型 设置为 静态库(.lib)
+ 常规 -> 全程序优化 设成 无全程序优化
+ C++ -> 预处理器 -> 预处理定义 删除宏 _USRDLL 添加宏 __E_STATIC_LIB
+ C++ -> 预编译头 -> 选择不使用预编译头
+ 管理员 -> 常规 -> 输出文件 改为 $(OutDir)\$(ProjectName)_static.lib
+ 生成事件 -> 生成后事件 -> 命令行 填入你 D:\E51\sdk\tools\resym.exe all infile=$(TargetPath) outfile=$(TargetPath)

设置修改完成后,选择release_static项目编译

静态库的使用需要动态库支持。我们需要把动态库的fne放在易语言的lib目录下 和 静态库的lib放在static_lib目录下。这样才能静态编译。编译出来的结果将可以脱离任何非系统支持库独立运行。

关于运行时库的配置:

个人比较喜欢把release模式设置成"在静态库中使用 MFC"并且使用"多线程(/MT)"。
VS向导生成的MFC项目(exe,dll,lib)一般都默认设置为 "在共享 DLL 中使用 MFC" 并使用 "多线程 DLL (/MD)"
这样编译出来的COFF文件尺寸小,但程序运行时必须依赖MFC的dll库。
把设置修改成"在静态库中使用 MFC"并且使用"多线程(/MT)" 就可以脱离MFC的dll库运行。这样即使在没有安装Visual C++ Runtime library的机器上也能正常运行。这种模式也就是VC++的"静态编译"。编译后的文件尺寸会稍大些。技术上和易语言的静态编译是一样的。

具体设置方法
+ 常规 -> MFC的使用 选择 "在静态库中使用 MFC",如果库中没有用到MFC的类函数和类资源 那么也可以选择"使用标准 Windows 库"
+ C++ -> 代码生成 -> 运行时库 选择 "多线程(/MT)"

很多VC软件开发者就是因为这里没有设置好,结果程序在其他机器上一运行就跳出缺少运行时库的错误提示。所以本人建议最好养成习惯,使用静态编译模式配置项目。

下面给出一个简单的支持库的例子:

我们希望库里面有一个函数,且不需要自定义数据类型和常量。
函数中文名称是 "两数相加",英文名称是"myadd", 希望调用格式是。
〈小数型〉 两数相加 (小数型 参数1,小数型 参数2)

该函数在库中所属函数分类是"基本运算"

源代码如下:

+ mylib.cpp文件内容

复制代码
  1. #include "stdafx.h"
  2. #include "mylib.h"
  3. #include <lib2.h>
  4. #include <lang.h>
  5. #include <fnshare.h>
  6. #include <fnshare.cpp>
  7. //
  8. // 模块内容
  9. //
  10. //定义函数
  11. EXTERN_C void mylib_myadd(PMDATA_INF pRetData, INT iArgCount, PMDATA_INF pArgInf)
  12. {
  13. pRetData->m_float = pArgInf[0].m_float + pArgInf[1].m_float;
  14. };
  15. /
  16. #ifndef __E_STATIC_LIB
  17. PFN_EXECUTE_CMD ExecuteCommand[] =
  18. {
  19. mylib_myadd // 所有需要库中调用的函数都列在这里,用逗号隔开
  20. };
  21. static const char* const CommandNames[] =
  22. {
  23. "mylib_myadd" // 所有需要库中调用的函数名都写在这里,用逗号隔开
  24. };
  25. ARG_INFO CommandArgs[] =
  26. {
  27. /* { 参数名称, 参数描述, 图像索引, 图像数量, 参数类型(参见SDT_), 默认数值, 参数类别(参见AS_) } */
  28. { _WT("参数1"), _WT("加数1,小数型"), 0, 0, SDT_FLOAT, NULL, NULL }, //函数参数数组定义写在这里,每个{}为一个参数的表述,用逗号隔开
  29. { _WT("参数2"), _WT("加数2,小数型"), 0, 0, SDT_FLOAT, NULL, NULL } //函数参数数组定义写在这里,每个{}为一个参数的表述,用逗号隔开
  30. };
  31. static CMD_INFO Commands[]=
  32. {
  33. /* { 中文名称, 英文名称, 对象描述, 所属类别(-1是数据类型的方法), 命令状态(CT_), 返回类型(SDT_), 此值保留, 对象等级(LVL_), 图像索引, 图像数量, 参数个数, 参数信息 } */
  34. { _WT("两数相加"), _WT("myadd"), _WT("两个小数相加求和,返回小数"), 1, NULL, SDT_FLOAT, 0, LVL_SIMPLE, 0, 0, 2, CommandArgs },//基本命令
  35. };
  36. #endif
  37. //
  38. EXTERN_C INT WINAPI mylib_ProcessNotifyLib(INT nMsg, DWORD dwParam1, DWORD dwParam2)
  39. {
  40. #ifndef __E_STATIC_LIB
  41. if(nMsg == NL_GET_CMD_FUNC_NAMES)
  42. return (INT)CommandNames;
  43. else if(nMsg == NL_GET_NOTIFY_LIB_FUNC_NAME)
  44. return (INT)"mylib_ProcessNotifyLib";
  45. else if(nMsg == NL_GET_DEPENDENT_LIBS)
  46. return (INT)NULL;
  47. #endif
  48. return ProcessNotifyLib(nMsg, dwParam1, dwParam2);
  49. };
  50. #ifndef __E_STATIC_LIB
  51. static LIB_INFO LibInfo =
  52. {
  53. /* { 库格式号, GUID串号, 主版本号, 次版本号, 构建版本号, 系统主版本号, 系统次版本号, 核心库主版本号, 核心库次版本号,
  54. 支持库名, 支持库语言, 支持库描述, 支持库状态,
  55. 作者姓名, 邮政编码, 通信地址, 电话号码, 传真号码, 电子邮箱, 主页地址, 其它信息,
  56. 类型数量, 类型指针, 类别数量, 命令类别, 命令总数, 命令指针, 命令入口,
  57. 附加功能, 功能描述, 消息指针, 超级模板, 模板描述,
  58. 常量数量, 常量指针, 外部文件} */
  59. LIB_FORMAT_VER, _T(LIB_GUID_STR),
  60. LIB_MajorVersion, LIB_MinorVersion, LIB_BuildNumber,
  61. LIB_SysMajorVer, LIB_SysMinorVer, LIB_KrnlLibMajorVer, LIB_KrnlLibMinorVer,
  62. _T(LIB_NAME_STR), __GBK_LANG_VER, _WT(LIB_DESCRIPTION_STR), _LIB_OS(__OS_WIN),
  63. _WT(LIB_Author), _WT(LIB_ZipCode), _WT(LIB_Address), _WT(LIB_Phone), _WT(LIB_Fax), _WT(LIB_Email), _WT(LIB_HomePage), _WT(LIB_Other),
  64. 0, NULL, LIB_TYPE_COUNT, _WT(LIB_TYPE_STR), sizeof(Commands)/sizeof(Commands[0]), Commands, ExecuteCommand,
  65. NULL, NULL, mylib_ProcessNotifyLib, NULL, NULL,
  66. 0, NULL, NULL
  67. };
  68. PLIB_INFO WINAPI GetNewInf()
  69. {
  70. return (&LibInfo);
  71. };
  72. #endif

+ mylib.h的文件里加入

复制代码
  1. #ifndef __E_STATIC_LIB
  2. #define LIB_GUID_STR "9D13FF9D0E1240aaBE1B78E6B32B855F" /*GUID串: {9D13FF9D-0E12-40aa-BE1B-78E6B32B855F}, 必须使用guidgen.exe生成*/
  3. #define LIB_MajorVersion 1 /*库主版本号*/
  4. #define LIB_MinorVersion 1 /*库次版本号*/
  5. #define LIB_BuildNumber 20110410 /*构建版本号*/
  6. #define LIB_SysMajorVer 3 /*系统主版本号*/
  7. #define LIB_SysMinorVer 0 /*系统次版本号*/
  8. #define LIB_KrnlLibMajorVer 3 /*核心库主版本号*/
  9. #define LIB_KrnlLibMinorVer 0 /*核心库次版本号*/
  10. #define LIB_NAME_STR "我的易库" /*支持库名*/
  11. #define LIB_DESCRIPTION_STR "测试易库制作" /*功能描述*/
  12. #define LIB_Author "kaien" /*作者名称*/
  13. #define LIB_ZipCode "" /*邮政编码*/
  14. #define LIB_Address "" /*通信地址*/
  15. #define LIB_Phone "" /*电话号码*/
  16. #define LIB_Fax "" /*传真号码*/
  17. #define LIB_Email "[email]kaienfr@gmail.com[/email]" /*电子邮箱*/
  18. #define LIB_HomePage "" /*主页地址*/
  19. #define LIB_Other "祝大家使用愉快" /*其它信息*/
  20. #define LIB_TYPE_COUNT 1 /*命令分类数量*/
  21. #define LIB_TYPE_STR "0000基本运算\0""\0" /*命令分类*/
  22. #endif

常见问题:

Q: 编译静态库没问题,但是易语言调用静态编译时出现
error LNK2001: unresolved external symbol ___security_cookie
error LNK2001: unresolved external symbol @__security_check_cookie@4

A: 关掉“缓冲区安全检测”重新编译静态库。 具体方法:
静态库编译项目设置里,C++ -> 代码生成 -> 缓冲区安全检测 设置为 否 重新编译静态库即可。

Q: 如果你的静态库在静态编译的时候需要其他静态库的支持 怎么办?

A: 例如: 你的静态库A.lib里使用了其他静态库B.lib和C.lib的函数。
那么你需要修改A源码里的函数mylib_ProcessNotifyLib的
  else if(nMsg == NL_GET_DEPENDENT_LIBS)
   return (INT)"B.lib\0""C.lib\0""\0";
  // 返回静态库所依赖的其它静态库文件名列表(格式为\0分隔的文本,结尾两个\0)

相应的编译动态库时,需要把 B.lib;C.lib 加入到项目属性的
连接器 -> 输入 -> 附加依赖项 里。也就是使用静态库编译dll和exe的方法。

Q: 如何调试你的动态库?

A: VC上调试你的动态库和调试dll是一样的。具体步骤是:
1. debug模式编译出动态库fne/fnr文件,放到lib目录下
2. 易语言写个测试程序,里面调用这个动态库某个需要调试的函数
3. 动态编译这个测试程序,加入是test.exe
4. VC中在需要调试的调试函数开头处设断点,然后F5运行调试
5. 选择test.exe文件,执行。一旦测试程序运行到这个函数,就会断下来,我们就可以调试了。
只要动态库运行正常了,静态库因为用的是同一套代码,所以也没问题。

Q: 待续...

易语言支持库制作学习笔记相关推荐

  1. java支持库 易语言_易语言支持库|易语言支持库更新集合包下载233个 - 欧普软件下载...

    易语言支持库更新集合包是目前比较齐全的集合包,包含233个,有EXCEL2000支持库2.0.Java支持库2.0.PowerPoint2000支持库2.0.DirectX2D支持库2.0.位图操作支 ...

  2. c开发 易语言支持库,易写易库-用易语言开发易语言支持库.pdf

    易写易库-用易语言开发易语言支持库 易写易库(EXEK)用户手册 版本:0.2 作者:liigo,/liigo 时间:2008.10 概述 EXEK EXEK "易写易库(EEXXEEKK) ...

  3. 易语言支持库编写 第2卷

    现在我们打开易语言安装目录下,有一个SDK目录,打开它找到子目录 cpp工程 里面有一个htmlview的例子,首先我们用我们第1卷的代码和 工程对比一下, 我们可以发现,vc自己生成的cpp中,我们 ...

  4. 升级易语言支持库保证向下兼容性的几点总结

    点击阅读原文 易语言支持库升级之后,要保证向下兼容性,主要是做到以下几点: 一:保证原有的易语言源程序(.e)能正常打开(兼容点1).正常编译(兼容点2).编译结果正确(兼容点3): 二:保证原有的易 ...

  5. “易写易库(EXEK)”项目启动,用易语言开发易语言支持库

    "易写易库"(EXEK,E Xie E Ku)项目已经启动,用易语言开发易语言支持库.我(liigo)准备用一个月左右的业余时间,完成本项目的一期工程. 用易语言开发易语言支持库, ...

  6. java支持库 易语言_易语言支持库简单安装加载添加

    1,首先,准备好欲安装的易语言支持库文件(fne.fnr或lib为后缀名等文件) 2,接下来,有必要对易语言支持库的文件做重要讲解.要安装支持库之前,先要弄明白易语言安装目录下的两个文件夹:lib和s ...

  7. 易语言支持库配置闪退丨支持库配置崩溃_易语言打开支持库配置就闪退怎么办?

    易语言支持库配置闪退打不开怎么办? 易语言支持库配置闪退解决方法丨支持库配置崩溃_易语言打开支持 易语言支持库配置闪退丨支持库配置崩溃_易语言打开支持库配置就闪退怎么办? 很多人都遇到过 打开易语言支 ...

  8. 易语言支持库系统学习笔记-----核心支持库

    学了易语言有一段时间了,虽然能写一般的程序,但是总是好像好了点什么,看教程的时候总能学到一些大大小小的以前没注意的小知识,所以想把易语言重新系统的自学一遍!这个是主要目的!这次以学习支持库为主 知识穿 ...

  9. c语言写易语言支持库6,易语言编写支持库

    ========== 1.易支持库机制 ========== !!!易支持库的库信息.命令信息等等均使用某个结构储存 !!!易源码中的自定义数据类型.类模块.组件即为支持库中的库定义数据类型 !!!易 ...

最新文章

  1. 2022-2028年中国塑料合成革的制造行业市场全景评估及发展趋势研究报告
  2. Mybatis 基础 定义别名,属性配置
  3. 可穿戴计算之父:成都能成为可穿戴技术未来中心
  4. 上交大计算机导师俞凯,WLA青科聊高考①|偶像剧“男主”、上海交大教授俞凯的学霸人生...
  5. 第二阶段冲刺 站立会议03
  6. SAP Leonardo机器学习训练之前的初始化操作
  7. linux服务器配置ssl证书
  8. CVPR 2020 中的群组活动识别
  9. 确保VDI顺利部署 试点项目是关键
  10. 电控 应用层开发 学习_阿里巴巴如何改善开发人员在 K8s 上的体验?
  11. VS2010平台下OpenCV编译和安装
  12. Mixtile Garage产品简介
  13. matlab 计算图像的基本参数
  14. 合并出错:svn Working copy and merge source not ready for reintegration
  15. 2018年数学建模竞赛-高温作业专用服装设计
  16. 睡眠分期matlab代码,非接触式睡眠分期方法与流程
  17. 吊打面试官系列之:移动APP测试开发面试题汇总,对标P7职位~ ~熬夜整理,建议收藏!!!
  18. centos7设置DNS
  19. 安超云生态 | 安超云与杉岩数据完成产品互兼容认证 携手打造协同生态
  20. [软考]系统架构设计师 备考经验分享(二) - 知识点学习+综合知识篇

热门文章

  1. 系统流程图与数据流图的联系与区别
  2. 【三维装箱】基于遗传和模拟退火的三维装箱问题matlab源码
  3. MCSE2012 视频(央邦)简单笔记
  4. xp无法搜索计算机名,雨林木风xp系统无法搜索到工作组计算机怎么办
  5. 全能巨声麦克风音响一体,周末宅家欢乐多
  6. 不要学计算机,学IT的我已经后悔了
  7. 【OWA】04集成SharePoint:SharePoint集成OWA详细步骤(SharePoint与OWA集成)
  8. 上海交通大学c语言程序设计考试,2016年华东交通大学软件学院C语言程序设计考研复试题库...
  9. 多张图片转换成PDF的必备办公技能
  10. stm32f103c8t6c语言教程,STM32f103C8T6入门学习记录.doc