|
re
用DLL实现包
利用DLL实现包和我们平常利用DLL来扩展命令只有稍微的差别:1,必须引出一个和DLL的名字关联的初始化函数;2,在该初始化函数中调用TCL库函数Tcl_PkgProvide。
下面我们利用一个win32 的non-MFC DLL来实现一个名为add的package,其中也实现了add扩展命令,为了和上面的add包区别,我们把这里的实现作为版本2.0。
启动VC6,点击菜单File/New,在弹出的对话框中选择projects属性页,在这个属性页中选择Win32 Dynamic-Link Library,然后在右边的“Project name”栏输入工程名Add,在"Location"栏选择你的工程想保存的目录,然后点击“OK”按钮,在接下来的对话框中,会有三个选项,为了方便,可以选择选项“A DLL that exports some symbols”,最后点击"finish"按钮,工程自动生成。
打开工程中的文件add.h,add.cpp,我们会发现,MFC已经自动给我们添加了一个变量,一个类和一个函数的引出示例。在add.h和add.cpp中把这些变量、类和函数的声明和实现删除。然后加上我们自己的代码。
add.h如下:
#ifdef ADD_EXPORTS
#define ADD_API __declspec(dllexport)
#else
#define ADD_API __declspec(dllimport)
#endif
#include "tcl.h"
extern "C" ADD_API int Add_Init(Tcl_Interp *interp);
add.cpp中的代码如下:
#include "stdafx.h"
#include "Add.h"
int AddCmd(ClientData clientData, Tcl_Interp *interp,int argc, char *argv[]);
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
ADD_API int Add_Init(Tcl_Interp *interp)
{
Tcl_CreateCommand(interp, "add", AddCmd,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
Tcl_PkgProvide(interp, "Add", "2.0");
return TCL_OK;
}
int AddCmd(ClientData clientData, Tcl_Interp *interp,
int argc, char *argv[])
{
int n1,n2;
if (argc != 3) {
interp->result = "Usage error: add int1 int2";
return TCL_ERROR;
}
if(TCL_OK != Tcl_GetInt(interp, argv[1], &n1))
{
sprintf(interp->result,"Expect int but get %s",argv[1]);
return TCL_ERROR;
}
if(TCL_OK != Tcl_GetInt(interp, argv[2], &n2))
{
sprintf(interp->result,"Expect int but get %s",argv[2]);
return TCL_ERROR;
}
sprintf(interp->result, "%d", n1+n2);
return TCL_OK;
}
自己设置好包含tcl头文件的目录,并把tcl的库文件加入工程中,编译就可以得到Add.dll动态链接库了。
TCL要求实现包的DLL必须导出一个初始化函数,在这个函数中注册包中扩展的所有TCL命令,比如上述例子中的导出函数是Add_Init。TCL为了能方便的使用自动加载功能,对DLL的名字、包的名字、导出函数的名字有严格规定。DLL的名字必须和包的名字一样,导出函数的名字必须是DLL的名字+下划线+Init。例如上述例子中,DLL的名字是Add.dll,那么包的名字就必须是Add,导出函数的名字就必须是Add_Init,当然可以不区分大小写。注意导出函数声明时必须加上extern "C",以避免编译器对它进行名字修饰,不然,加载Add.dll时TCL会报告找不到Add_Init函数。 |
|