随着互联网的飞速发展,现在的人们都习惯了打开浏览器进行工作,基于WEB的程序蜂拥而至,几乎变得无所不能。由于WEB脚本语言的限制,对于本地计算机的访问受到很大的限制。开发WEB的程序员都会因为WEB的打印而烦恼,对于WEB开发者来讲,更大的挑战还在后面。电子商务需要身份认证,需要访问本地计算机上操作人员的U-KEY, 还有诸如此类的读卡器、扫描仪等外围输入设备。
这所有的一切困难都可以用基于ACTIVEX技术的OCX组件来解决。OCX的编写并不难,下面就讲解基于VC6环境下OCX的制作。
一、创建工程:
对于使用过VC的人,可以很容易地创建一个开发ActiveX控件的工程,没有使用过VC的人,按
照下面的操作步骤,也可以很快创建一个同样的工程出来。
第一步:“File”—>“New”—>“(Projects)MFC ActiveX ControlWizard”,在“Project Name”中输入合适的工程名(以readcard为例),在“Location”中选择工程文件存放路径,然后,“OK”进入下一步;
第二步:选择你想在这个工程中生成的ActiveX控件的个数(至少一个),其余选项决定是否生成一些辅助文件,通常按照默认设置即可,“Next”进入下一步;
第三步:编辑你的工程中各个类和文件的名称,配置一些辅助选项,可以全部选择默认设置,“Finish”进入下一步;
第四步:展示向导为你的工程生成的各种配置信息,“Cancel”重新设置不满意的选项,“OK”结束工程的创建。
二、添加属性和方法:
1、操作菜单:“View”—>“ClassWizard“
"查看"”—>“建立类向导...“(中文菜单)
2、在"MFC ClassWizard"对话框中选取"Automation"页,注意"Class Name"项是"CReadCardCtrl",
点击右边的"Add Property..."添加控件的属性,点击右边的"Add Method..."添加控件的方法.
添加属性
添加方法
三、给控件添加安全接口
1、打开ReadCard.cpp文件
2、添加头文件及定义
#include "COMCAT.H"
#include "Objsafe.h"
const GUID CDECL CLSID_SafeItem = { 0xc5788f5, 0xa711, 0x412a, { 0x99, 0xe4, 0xef, 0x18, 0x70, 0x1, 0xef, 0xc5 } };
3、复制以下代码段到ReadCard.cpp中。
//创建组件种类
HRESULT CreateComponentCategory(CATID catid,WCHAR *catDescription)
{
ICatRegister* pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (FAILED(hr))
return hr;
// Make sure the HKCR/Component Categories/{..catid...}
// key is registered.
CATEGORYINFO catinfo;
catinfo.catid = catid;
catinfo.lcid = 0x0409 ; // english
// Make sure the provided description is not too long.
// Only copy the first 127 characters if it is.
int len = wcslen(catDescription);
if (len>127)
len = 127;
wcsncpy(catinfo.szDescription, catDescription, len);
// Make sure the description is null terminated.
catinfo.szDescription[len] = '/0';
hr = pcr->RegisterCategories(1, &catinfo);
pcr->Release();
return hr;
}
//注册组件种类
HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
{
// Register your component categories information.
ICatRegister* pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (SUCCEEDED(hr))
{
// Register this category as being "implemented" by the class.
CATID rgcatid[1] ;
rgcatid[0] = catid;
hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);
}
if (pcr != NULL)
pcr->Release();
return hr;
}
//卸载组件种类
HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
{
ICatRegister* pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (SUCCEEDED(hr))
{
// Unregister this category as being "implemented" by the class.
CATID rgcatid[1] ;
rgcatid[0] = catid;
hr = pcr->UnRegisterClassImplCategories(clsid, 1, rgcatid);
}
if (pcr != NULL)
pcr->Release();
return hr;
}
4、修改控件注册入口函数及注销函数:
/////////////////////////////////////////////////////////////////////////////
// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void)
{
AFX_MANAGE_STATE(_afxModuleAddrThis);
if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
return ResultFromScode(SELFREG_E_TYPELIB);
if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
return ResultFromScode(SELFREG_E_CLASS);
// 标记控件初始化安全.
// 创建初始化安全组件种类
HRESULT hr;
hr = CreateComponentCategory(CATID_SafeForInitializing, L"Controls safely initializable from persistent data!");
if (FAILED(hr))
return hr;
// 注册初始化安全
hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);
if (FAILED(hr))
return hr;
// 标记控件脚本安全
// 创建脚本安全组件种类
hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls safely scriptable!");
if (FAILED(hr))
return hr;
// 注册脚本安全组件种类
hr = RegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);
if (FAILED(hr))
return hr;
return NOERROR;
}
/////////////////////////////////////////////////////////////////////////////
// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer(void)
{
AFX_MANAGE_STATE(_afxModuleAddrThis);
if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))
return ResultFromScode(SELFREG_E_TYPELIB);
if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE))
return ResultFromScode(SELFREG_E_CLASS);
HRESULT hr;
// 删除控件初始化安全入口.
hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);
if (FAILED(hr))
return hr;
// 删除控件脚本安全入口
hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);
if (FAILED(hr))
return hr;
return NOERROR;
}
四、取得当前OCX所在路径
由于读取配置文件或进行文件交互,需用到组件的运行路径,我试过不少方法,都取值不正确,经过不少测试,
用下面的方法最好:
char szPath[100]={0};
char szLogPath[100]={0};
char szIniPath[100]={0};
short PORT=1,CARDTYPE=1;
BOOL CReadCardApp::InitInstance()
{
BOOL bInit = COleControlModule::InitInstance();
if (bInit)
{
int il=strlen(this->m_pszHelpFilePath);
memcpy(szPath,this->m_pszHelpFilePath,il);
while( (il>0) && (0 != memcmp(szPath+il,"//",1)) )
{
szPath[il]=0;
il-=1;
}
il+=1;
memcpy(szLogPath,szPath,il);
memcpy(szIniPath,szPath,il);
memcpy(szLogPath+il,"jdl_ocx.log",11);
memcpy(szIniPath+il,"readcard.ini",12);
PORT=::GetPrivateProfileInt("COMM","PORT",1,szIniPath);
CARDTYPE=::GetPrivateProfileInt("CARDTYPE","TYPE",1,szIniPath);
}
return bInit;
}
五、在OCX方法中调用DLL中的库函数
一般设备都提供了动态链接库,下面讲一下如何在OCX方法中调用DLL中的库函数:
typedef int (WINAPI *InitCommDef)(int);
InitCommDef InitComFunc = NULL;
short CReadCardCtrl::initocx() {
char szDllPath[100]={0};
int len = strlen(szPath);
memcpy(szDllPath,szPath,len);
memcpy(szDllPath+len,"termb.dll",9);
HINSTANCE hInst = LoadLibrary(szDllPath);
if(!hInst) return -2;
InitComFunc = (InitCommDef)GetProcAddress(hInst, "InitComm"]);
if (!InitComFunc) return -3;
return 0;
};
六、实现控件的方法
short CReadCardCtrl::InitComm()
{
return InitComFunc(PORT);
};
对所有的方法进行实现后,点击菜单"build"(组建)—>"build all"(全部组建)进行编译.
至此readcard.ocx生成并可以使用了。
七、写个WEB页进行测试
把以下内容保存到一个html文件中,用浏览器打开即可测试。其中clsid:EC373183-761E-431C-8BD9-629027B5CCE5
可根据你的readcard.odl文件[ uuid(EC373183-761E-431C-8BD9-629027B5CCE5), helpstring("ReadCard Control"), 修改。
<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0">
<TITLE></TITLE>
<script language="JavaScript">
function button1_click()
{
wrong = card.init_dll();
if(wrong == 0)
{
alert("调用成功");
}
}
</script>
</HEAD>
<BODY>
<P>
<INPUT id=button1 type=button value=Button name=button1 onClick="button1_click()">
<OBJECT id=card classid=clsid:EC373183-761E-431C-8BD9-629027B5CCE5>
<PARAM NAME="_Version" VALUE="65536">
<PARAM NAME="_ExtentX" VALUE="2646">
<PARAM NAME="_ExtentY" VALUE="1323">
<PARAM NAME="_StockProps" VALUE="0"></OBJECT>
</P>
</BODY>
</HTML>
八、IE无法加载控件的解决办法
1、IE菜单 工具—>internet选项...
2、 选择安全页中的受信任站点。在弹出框中去掉最下面检查框中的对勾,添加WEB服务器
的IP地址:http://10.10.10.1
3、设置安全项中activeX可运行。
转自:http://zhaowenbinmail.blog.163.com/blog/static/3908086200933053127226/