2024年6月14日发(作者:)

将DLL封装成OCX

说明文档

1、 封装工具

使用Visual C++ 6.0对dll文件进行封装。

2、 封装方法

可使用静态调用dll和动态调用dll两种方法调用dll,然后封装各接口函数。

静态调用的前提条件是:厂家提供dll和相关的库文件(.lib)以及头文件(.h)。

动态调用的前提条件是:厂家只提供dll文件

3、 封装过程

3.1 动态调用dll封装(以封装浩宁达读写卡dll为例)

3.1.1创建项目

1、打开Visual C++ 6.0,单击file→new单击Project选项卡,选择

,弹出如下对话框:

2、输入项目名,单击,出现如下对话框。

单击完成创建一个控件。

3.1.2 创建接口函数

单击菜单栏上的“查看”,选择

弹出如下对话框:

菜单,选择Automation选项卡,

单击Add Method按钮,弹出如下对话框:

在第一个文本框里面输入想要加入的方法名,第三个下拉选框里面选择方法的返回类

型。在下面的Parameter list列表框里可以加入该方法要带的参数和参数类型,如果参数要

回调,则要选择带指针的类型;单击Edit Code按钮可以开始编写方法。

注:参数类型的选择不多,对于dll中提供的函数参数要挑选适当的类型,然后在接口

函数中将其转换为dll函数的参数类型。

3.1.3 编辑接口函数

主要编辑“项目名”中的内容。下面以封装浩宁达提供的卡表操作动态库文件

中的读卡函数Read_card为例说明如何封装dll文件。

dll中Read_Card函数:

__stdcall long

Read_Card(HANDLE AHandle, long Port, struct rcStruct *rcS,

char *User_ID,

char *Comm_ID,

char *CycleDisplay,

char *MRData);

ocx中封装的函数

a、定义Read_Card函数

typedef long (CALLBACK* RCard)(long, long, struct

rcStruct*FAR,char*FAR,char*FAR,char*FAR,char*FAR);

b、定义自定义的结构体

//读卡结构体(参数)

#pragma pack( push, 1 )

struct rcStruct{

//以下标识数据项不管插没插表都必须返回

long Work_ID; //厂商代码(最大2位十进制数字)

long Prog_ID; //表型代码(最大2位十进制数字)

long Card_ID; //卡型代码(最大2位十进制数字)

long Office_ID; //各供电局的地区代码

//如果没有插表,返回以下参数数据

long Far_ID; //远抄表号。

long Meter_Const; //表常数

long WarnDL1; //一级报警电量(金额)

long WarnDL2; //二级报警电量(金额)

long Max_HoardDL; //最大囤积电量(金额)

long Max_OverDL; //最大透支电量(金额)

double Max_Load; //最大负荷(千瓦)

long PTCT; //倍率

long CBDay; //自动抄表日

long XLDTSJ; //需量递推时间

long Loadwarndelay; //超负荷报警延时

double Price_J; //尖单价

double Price_F; //峰单价

double Price_P; //平单价

double Price_G; //谷单价

double SaleDL; //购电量(金额)

long Sale_Num; //购电次数(购电次数从1起)

//如果插表,返回以下抄表数据

double OverZeroDL_M; //过零电量

double RemainDL_M; //剩余电量

long Sale_Num_M; //表内购电次数(购电次数从1起)。

double Power_Z_M; //总用电量

double Power_J_M; //尖用电量

double Power_F_M; //峰用电量

double Power_P_M; //平用电量

double Power_G_M; //谷用电量

long Read_Year_M; //抄表日期的年

long Read_Mon_M; //抄表日期的月

long Read_Day_M; //抄表日期的日

long Read_Hour_M; //抄表日期的时

long Read_Minute_M; //抄表日期的分

long Read_Second_M; //抄表日期的秒

BOOL CBFlag;//插表标识,true:插表(有电卡),false:没有插表(无电卡)

BOOL TZ_State; //电表允许是否允许跳闸

BOOL CX_State; //表内信息是否允许常显

BOOL SQ_State; //是否允许赊欠

};

#pragma pack( pop )

c、编辑接口函数,调用dll中的函数

//读卡函数

BSTR CHndocxCtrl::ReadCard(long AHandle, long Port)

{

CString strResult;

// TODO: Add your dispatch handler code here

//读取ini配置文件

short port_ini =

GetPrivateProfileInt("hndocx","port",0,"C:");

struct rcStruct FAR* rcs= new rcStruct;

struct rcStruct rcS;

char link = '/';

long result = (long)999; //初始化返回值result

//必须定义好分配的内存大小,否则会导致不可预测的错误

char FAR*UserID = new char[13];

char FAR*CommID = new char[13];

char FAR*cycleDisplay = new char[2049];

char FAR*mRData = new char[24577];

BSTR User_ID_i;

BSTR Comm_ID_i;

BSTR CycleDisplay_i;

BSTR MRData_i;

CString Card_ID;

CString SaleDL;

CString Sale_Num;

CString OverZeroDL_M;

CString RemainDL_M;

CString Sale_Num_M;

CString Power_Z_M;

CString Power_J_M;

CString Power_F_M;

CString Power_P_M;

CString Power_G_M;

CString CBFlag;

HINSTANCE hinst;

RCard ReadCardfun;

hinst = LoadLibraryW(L""); //调用dll文件

if(hinst != NULL) //调用dll文件成功(dll文件存在)

{

ReadCardfun=(RCard)GetProcAddress(hinst,"Read_Card");

if (!ReadCardfun) //初始化dll中函数不成功

{

// handle the error

FreeLibrary(hinst); //释放dll文件

result = (long)1000;

("%d",result);

//打开读卡器串口,读卡器蜂鸣

int icdev = Init();

//初始化dll中的函

beep(icdev,20);

IcExit(icdev);

return ysString();

}

else //初始化dll中函数成功

{

result

ReadCardfun(AHandle,port_ini,rcs,UserID,CommID,cycleDisplay,mRData);

dll中函数并获取返回值

if(result == 0)

{

//转char*为BSTR

User_ID_i = _com_util::ConvertStringToBSTR(UserID);

Comm_ID_i = _com_util::ConvertStringToBSTR(CommID);

=

//调用

CycleDisplay_i = _com_util::ConvertStringToBSTR(cycleDisplay);

MRData_i = _com_util::ConvertStringToBSTR(mRData);

FreeLibrary(hinst); //释放dll

//释放指针

delete UserID;

UserID = NULL;

delete CommID;

CommID = NULL;

delete cycleDisplay;

cycleDisplay = NULL;

delete mRData;

mRData = NULL;

rcS = *rcs;

delete rcs;

rcs = NULL;

FreeLibrary(hinst); //释放dll

//转数值型为CString

//long

Card_("%d",_ID);

//double

("%f",);

//long

Sale_("%d",_Num);

//double

OverZeroDL_("%f",roDL_M);

//double

RemainDL_("%f",DL_M);

//long

Sale_Num_("%d",_Num_M);

//double

Power_Z_("%f",_Z_M);

//double

Power_J_("%f",_J_M);

//double

Power_F_("%f",_F_M);

//double

Power_P_("%f",_P_M);

//double

Power_G_("%f",_G_M);

//int

if()

CBFlag = "true";

else

CBFlag = "false";

//组装返回字符串,用/分割

("%d",result);

strResult += (CString)link;

strResult += Card_ID;

strResult += (CString)link;

strResult += SaleDL;

strResult += (CString)link;

strResult += Sale_Num;

strResult += (CString)link;

strResult += OverZeroDL_M;

strResult += (CString)link;

strResult += RemainDL_M;

strResult += (CString)link;

strResult += Sale_Num_M;

strResult += (CString)link;

strResult += Power_Z_M;

strResult += (CString)link;

strResult += Power_J_M;

strResult += (CString)link;

strResult += Power_F_M;

strResult += (CString)link;

strResult += Power_P_M;

strResult += (CString)link;

strResult += Power_G_M;

strResult += (CString)link;

strResult += CBFlag;

strResult += (CString)link;

strResult += User_ID_i;

strResult += (CString)link;

strResult += Comm_ID_i;

strResult += (CString)link;

strResult += CycleDisplay_i;

strResult += (CString)link;

strResult += MRData_i;

//打开读卡器串口,读卡器蜂鸣

int icdev = Init();

beep(icdev,20);

IcExit(icdev);

return ysString();

}

FreeLibrary(hinst); //释放dll

("%d",result);

//打开读卡器串口,读卡器蜂鸣

int icdev = Init();

beep(icdev,20);

IcExit(icdev);

return ysString();

}

}

else

{

("%d",result);

//打开读卡器串口,读卡器蜂鸣

int icdev = Init();

beep(icdev,20);

IcExit(icdev);

return ysString();

}

}

注:(1)Javascript不支持指针,故要将所有回调函数组装成串返回来。

(2)统一规定所有接口函数调用dll文件不成功时返回1000,调用dll文件里的函数

不成功时返回999。

3.2 静态调用dll封装(以封装读银行卡dll为例)

3.2.1创建项目

1、打开Visual C++ 6.0,单击file→new单击Project选项卡,选择

,弹出如下对话框:

2、输入项目名,单击,出现如下对话框。

单击完成创建一个控件。

3.2.2 静态调用dll

将厂家提供的库文件(.lib)和(.h)文件拷贝到项目内,点击菜单上的【Project】—

—【Settings】,点击打开【link】页,在【Object/library modules】里面增加库文件的

全名:

右键点击项目,选择【Add Files to Project…】选中厂家dll的头文件:ICT3K5.h

3.2.3 创建接口函数

单击菜单栏上的“查看”,选择

弹出如下对话框:

菜单,选择Automation选项卡,

单击Add Method按钮,弹出如下对话框:

在第一个文本框里面输入想要加入的方法名,第三个下拉选框里面选择方法的返回类

型。在下面的Parameter list列表框里可以加入该方法要带的参数和参数类型,如果参数要

回调,则要选择带指针的类型;单击Edit Code按钮可以开始编写方法。

注:参数类型的选择不多,对于dll中提供的函数参数要挑选适当的类型,然后在接口

函数中将其转换为dll函数的参数类型。

3.1.3 编辑接口函数

主要编辑“项目名”中的内容。下面以打开串口函数OpenPort为例说明如

何封装dll文件。

long CCardReaderCtrl::IOpenPort()

{

// TODO: Add your dispatch handler code here

//读取ini配置文件

short port =

GetPrivateProfileInt("CardReader","port",6,"C:");

long baud =

GetPrivateProfileInt("CardReader","baud",9600,"C:WINDOWSsystem32pssts.i

ni");

//初始化串口

int iret = OpenPort(port,baud);

if(iret != 0)

return iret;

//复位设备

iret = IResetDev(0);

if(iret != 0)

{

ClosePort();

return iret;

}

//允许插卡

iret = EnableInsertCard();

if(iret != 0)

{

ClosePort();

return iret;

}

return iret;

}

4、 OCX的使用

编译完成后在工程项目的文件夹下找“项目名.odl”文件,该activex控件的uuid为

红色部分的字符串:

// Class information for CHndocxCtrl

[ uuid(ADF45DA5-87F7-49EF-B3D0-ACA0290679FF),

helpstring("Hndocx Control"), control ]

coclass Hndocx

{

[default] dispinterface _DHndocx;

[default, source] dispinterface _DHndocxEvents;

};

引用ocx时CLID为上面uuid后红色字体部分。