随着互联网的飞速发展,现在的人们都习惯了打开浏览器进行工作,基于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可运行。
|