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后红色字体部分。


发布评论