VC创建OCX

    技术2025-12-12  1

     随着互联网的飞速发展,现在的人们都习惯了打开浏览器进行工作,基于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://blog.csdn.net/jiadelin/archive/2008/09/12/2917225.aspx

    最新回复(0)