VS2010下ocx开发:(3)在Web页面中调用已实现的ocx控件

    打开在博文:http://blog.csdn.net/henter/article/details/79399986 中创建的 MultiplyDemo 项目,在“解决方案资源管理器”窗口中双击 MultiplyDemo.idl 文件,在该文件中找到“CMultiplyDemoCtrl 的类信息”这一段内容,将其中的uuid后面括号中的内容保存下来,后面将会用到。如下图:



    写一个名为index.html的文件,内容如下:

<!DOCTYPE html>
<html>
<body>
<OBJECT id="MultiplyDemo" classid="clsid:526453C4-2FC0-4196-99BC-3B0D223BE780" width="0" height="0">
</OBJECT>
<h1>调用乘法控件演示页面</h1>
<p>请输入数字</p>
<p>x = <input id="num1" type="text"></p>
<p>y = <input id="num2" type="text"></p>
<p id="productText">结果将显示在这里......</p>
<script>
function computProduct()
{
  var num01=document.getElementById("num1").value;
  if (num01=="" || isNaN(num01))
  {
    alert("输入错误!不是整数")
	return;
  }
  
  var num02=document.getElementById("num2").value;
  if (num02=="" || isNaN(num02))
  {
    alert("输入错误!不是整数")
	return;
  }
  
  var multiplyOcx=document.getElementById("MultiplyDemo")
  if (multiplyOcx)
  {
    var productResult = multiplyOcx.Multiply(num01, num02);
	document.getElementById("productText").innerHTML = num01.toString() + "*" + num02.toString() + "= " + productResult.toString();
  }
  else
  {
    alert("控件不存在!");
  }
}

function showOcxAboutBox()
{
  var multiplyOcx=document.getElementById("MultiplyDemo")
  if (multiplyOcx)
  {
    multiplyOcx.AboutBox();
  }
  else
  {
    alert("控件不存在!");
  }
}

</script>

<button type="button" onclick="computProduct()">计算乘积</button>
<p></p>
<button type="button" onclick="showOcxAboutBox()">显示控件自带的对话框</button>
</body>
</html>

    注意 html 文件中的 classid="clsid:526453C4-2FC0-4196-99BC-3B0D223BE780" ,这里用到了前面保存的 uuid 值。


    将 index.html 和 MultiplyDemo.ocx 文件放到同一个目录下,使用IE打开保存在本机磁盘上的 index.html 文件,显示如下:



    点击下方的“允许阻止的内容”,将弹出如下对话框:



    点击“是”按钮后,页面显示如下:



    在输入框中分别输入两个整数值,点击“计算乘积”按钮,页面显示类似下图:



    如果点击“显示控件自带的对话框”按钮,页面显示如下:



    如果html文件调用ocx文件失败,可以从以下方面查找原因:

1)ocx控件是否已被注册过?

2)系统中是否包括一些必要的库文件,比如VS 2010相关的动态库。为了减轻对库文件的依赖,在编译ocx控件时,可以按下图设置:


    这样编译出来的ocx文件的体积虽然会增大一些,但是可以减轻对库文件的依赖。

    上面介绍了在本地磁盘上的html文件中调用已实现的ocx控件,接下来将index.html文件放到Web服务器上。为了简单,这里使用一个轻量级的Web服务器软件 Abyss Web Server X1,其官网地址是 http://aprelium.com/abyssws/ 。安装该软件后,将index.html 和 MultiplyDemo.ocx 这两个文件拷贝到 \Abyss Web Server\htdocs 目录下,启动 IE 浏览器,将 http://localhost 添加到受信任的站点,如下图所示:



  在“开始”菜单中点击 Abyss Web Server X1 软件图标,启动该 Web 服务器,如下图:



   打开 IE 浏览器,输入网址:http://localhost/index.html ,显示如下:



    在输入框中随意分别输入两个整数值,点击“计算乘积”按钮及点击“显示控件自带的对话框”按钮,页面显示如下:



    如果不将 http://localhost 添加到 IE 的受信任站点,使用 IE 浏览器时,在“Internet选项”->“高级”中如果勾选了“禁用脚本调试(Internet Explorer)”,那么点击网页上的按钮时,将无任何反应。如果取消了对“禁用脚本调试(Internet Explorer)”的勾选,如下图:



    点击网页上的按钮时,会出现如下错误提示:



    导致这个错误的原因是在编程实现ocx控件时,没有相关的安全接口,因此IE阻止了对该控件的调用。对于实现安全接口的方法,可以参考以下链接:
https://support.microsoft.com/en-us/help/161873/how-to-mark-mfc-activex-controls-as-safe-for-scripting-and-initializat
http://www.cnblogs.com/qguohog/archive/2013/01/22/2871805.html

    这里介绍一下实现过程。首先以管理员身份启动VS 2010,打开项目 MultiplyDemo,在“解决方案资源管理器”窗口中,在“头文件”下添加一个名为Cathelp.h的文件,内容如下:

#include "comcat.h"

// Helper function to create a component category and associated
// description
HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription);

// Helper function to register a CLSID as belonging to a component
// category
HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid);

// HRESULT UnRegisterCLSIDInCategory - Remove entries from the registry 
HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid);

    在“源文件”下添加一个名为Cathelp.cpp的文件,内容如下:

#include "stdafx.h"
#include "comcat.h"
#include "strsafe.h"
#include "objsafe.h"


// HRESULT CreateComponentCategory - Used to register ActiveX control as safe 
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
    size_t len;
    // Make sure the provided description is not too long.
    // Only copy the first 127 characters if it is.
    // The second parameter of StringCchLength is the maximum
    // number of characters that may be read into catDescription.
    // There must be room for a NULL-terminator. The third parameter
    // contains the number of characters excluding the NULL-terminator.
    hr = StringCchLength(catDescription, STRSAFE_MAX_CCH, &len);
    if (SUCCEEDED(hr))
        {
        if (len>127)
          {
            len = 127;
          }
        }   
    else
        {
          // TODO: Write an error handler;
        }
    // The second parameter of StringCchCopy is 128 because you need 
    // room for a NULL-terminator.
    hr = StringCchCopy(catinfo.szDescription, len + 1, catDescription);
    // Make sure the description is null terminated.
    catinfo.szDescription[len + 1] = '\0';
 
    hr = pcr->RegisterCategories(1, &catinfo);
    pcr->Release();
 
    return hr;
}
 
// HRESULT RegisterCLSIDInCategory -
//      Register your component categories information 
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 - Remove entries from the registry 
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;
}

    在“解决方案资源管理器”子窗口中,双击“源文件”下面的 MultiplyDemoCtrl.cpp,打开该文件后,找到下面的内容:



    将以下内容记录下来:
// 初始化类工厂和 guid

IMPLEMENT_OLECREATE_EX(CMultiplyDemoCtrl, "MULTIPLYDEMO.MultiplyDemoCtrl.1",
0x526453c4, 0x2fc0, 0x4196, 0x99, 0xbc, 0x3b, 0xd, 0x22, 0x3b, 0xe7, 0x80)

    在“解决方案资源管理器”子窗口中,双击“源文件”下面的 MultiplyDemo.cpp,打开该文件,编写下面一段代码:
const CATID CLSID_SafeItem = {0x526453c4, 0x2fc0, 0x4196,{0x99, 0xbc, 0x3b, 0xd, 0x22, 0x3b, 0xe7, 0x80}};

    注意:花括号中的数值来源于刚才复制的内容,并加以修改,即前三个值不变,后面8个值再放入到一个花括号中。将这一段代码粘贴到 MultiplyDemoCtrl.cpp 文件中 CMultiplyDemoApp theApp; 这一行后面,如下图:



    在 MultiplyDemo.cpp 文件起始处,加入下面两行代码:

#include "Cathelp.h"

#include "objsafe.h"

如下图:



    在 MultiplyDemo.cpp 文件中,找到 DllRegisterServer( ) 和 DllUnregisterServer( )两个函数,删除它们。粘贴下面的代码:

// DllRegisterServer - Adds entries to the system registry

STDAPI DllRegisterServer(void)
{
    HRESULT hr;    // HResult used by Safety Functions
 
    AFX_MANAGE_STATE(_afxModuleAddrThis);
 
    if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
      return ResultFromScode(SELFREG_E_TYPELIB);
 
    if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
      return ResultFromScode(SELFREG_E_CLASS);
 
    // Mark the control as safe for initializing.
                                             
    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;
 
    // Mark the control as safe for scripting.
 
    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);  

    // 删除控件初始化安全入口.   
    HRESULT hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForInitializing);  

    if (FAILED(hr))  
        return hr;  

    // 删除控件脚本安全入口   
    hr=UnRegisterCLSIDInCategory(CLSID_SafeItem, CATID_SafeForScripting);  

    if (FAILED(hr))  
        return hr;  

    if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))  
        return ResultFromScode(SELFREG_E_TYPELIB);  

    if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE))  
        return ResultFromScode(SELFREG_E_CLASS);  

    return NOERROR;
}

    在“解决方案资源管理器”子窗口中,右键单击“资源文件”下面的 MultiplyDemo.rc,在弹出菜单中选择“查看代码”,如下图所示:



    找到“BLOCK "StringFileInfo"”这一行,从这一行开始向下看,
1)将BLOCK的值设为:"040904e4"
2)将OLESelfRegister的值设为:"\0"

3)"Translation"后面改为:0x0409, 1252。修改如下图所示:



    重新生成 MultiplyDemo.ocx 等文件。将该文件拷贝到 Abyss Web Server X1 服务器软件的  \Abyss Web Server\htdocs 目录下,覆盖原有的同名文件。重启一下 Abyss Web Server X1 服务器软件,启动 IE 浏览器,输入网址:http://localhost/index.html (注意:当前未将 http://localhost 加入 IE 的受信任站点),在页面上的输入框中分别随意输入两个整数,点击“计算乘积”按钮及点击“显示控件自带的对话框”按钮,页面显示如下:



 此时点击网页上的按钮,能够执行对应的功能。 建议如果有条件的话,最好对 MultiplyDemo.ocx 文件进行数字签名。

猜你喜欢

转载自blog.csdn.net/henter/article/details/79424020