编写浏览器使用的OCX全过程(转)

随着互联网的飞速发展,现在的人们都习惯了打开浏览器进行工作,基于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..."添加控件的方法.


                 添加属性

 编写浏览器使用的OCX全过程(转)_第1张图片

    添加方法

  


 

 

三、给控件添加安全接口

 

     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/

你可能感兴趣的:(入门,ocx,VC,控件)