步步学ACTIVEX网页控件开发

2023-11-19

 本文将首先介绍如何使用Visual Studio开发一个简单的ActiveX控件,然后介绍ActiveX控件开发相关的基础知识,比如方法,属性和事件等,最后介绍如何利用这些知识,实现ActiveX控件和网页页面之间的 通信


MyActiveX控件的效果图

  简介

  ActiveX是由Microsoft在90年代中期提出的一项技术。利用ActiveX技术,开发者可以创建像Java小程序applet一样的小型应用程序。这些应用程序可以被下载然后在Microsoft的浏览器中运行。这篇文章是为那些想学习如何开发他们的第一个ActiveX控件的Visual C++开发者准备的。

  当我自己尝试学习这些技术的时候,我发现很多针对ActiveX技术的资料都已经不再适用了,都已经过时了,或者丢失了很多关键性的信息,这些都使得我在为我的项目创建一个ActiveX控件的时候,变得困难重重。这篇文章将帮助你实现ActiveX网页控件开发的快速入门。本文将首先介绍如何使用Visual Studio开发一个简单的ActiveX控件,然后介绍ActiveX控件开发相关的基础知识,比如方法,属性和事件等,最后介绍如何利用这些知识,实现ActiveX控件和网页页面之间的通信。

  另外,你也将学习到如何在默认的Internet Explorer安全设置下取消掉控件加载过程中的警告或者错误提示,使你的控件成为一个“安全”的ActiveX控件。

  在本文中,我们将创建一个实际的ActiveX控件。在控件加载的过程中,它将显示一个动态的进度条,告诉用户控件正在加载并处理信息。同时,这个控件也将展示如何在ActiveX控件和Web页面之间传递信息。本文将引导你一步步地利用Microsoft Visual Studio 2005完成ActiveX控件的开发工作。

  创建ActiveX控件

  要创建一个ActiveX控件,首先启动Visual Studio 2005,执行下面这些步骤:

  1.选择“文件”菜单,然后选择“新建”->“项目”。 
  2.在“新建项目”对话框中,如下图1所示,选择“Visual C++”分类.

3.将新项目命名 为“MyActiveX”,然后选择项目的保存目录,最后点击“确定”按钮,关闭“新项目”对话框,进入“MFC ActiveX控件”向导。 


图1 新项目对话框

  4.在“MFC ActiveX控件”向导中,如下图2所示,选择左侧的“控件设置”,进入控件参数设置页面。
  5.在“Create control based on”下拉列表中选择“STATIC”。这表示我们使用的是一个静态控件,因为我们仅仅是显示输出而不接收输入。
  6.在下面的“Additional features”的所有选项中,我们确认选中“Activates when visible”和“Flicker-free activation”这两个选项,同时确认“Has an About box dialog”选项没有被选中。  


图2 MFC ActiveX 控件向导对话框

  7.点击“Finish”按钮关闭整个“MFC ActiveX控件向导”对话框,然后向导就会为我们创建整个项目的源代码。默认情况下,向导创建的项目是使用共享MFC DLL的,这里我们需要改变这一设置。因为如果目标机器上没有安装MFC DLL,那么ActiveX控件就不会运行。我们常常看到一些网页上的ActiveX控件被显示为红色的叉叉,很多都是这个原因造成的。
  为了解决这个问题,我们使用静态的MFC DLL。从Visual Studio的菜单中选择“项目”->“属性”,然后切换到“配置属性”->“普通”,在配置页面中的“Use of MFC ”下拉列表中,将“use MFC in a shared DLL”切换成“Use MFC in a Static Library”就可以了。

  8.向导创建了如下三个类:
  CMyActiveXApp – 这是从COleControlModule派生的ActiveX控件应用程序类。通过这个类,我们可以得到一个OLE控件对象,这个对象包含了对控件进行初始化(InitInstance)和对控件进行清理(ExitInstance)的成员函数。
  CMyActiveXCtrl – 这个类是从COleControl派生的。我们将在这个类中实现控件的主要功能。
  CMyActiveXPropPage – 这个类从COlePropertyPage派生的。它被用来管理控件的属性对话框。MFC ActiveX控件向导已经为我们创建了一个默认的属性对话框,我们只需要在其基础上进行修改就可以了。

  添加对动态GIF动画的支持

  为了实现使用ActiveX控件显示动态的进度条GIF动画,我们将使用Oleg Bykov在CodeProject的一篇文章中创建的类CPictureEx。具体的文章地址,请查阅本文最后的参考资料。

  首先,我们需要将源代码文件pictureex.cpp和pictureex.h添加到我们的项目中。选择Visual Studio 2005 IDE中的“解决方案浏览器”,在源代码窗口中点击“Header Files or Source Files”,然后点击右键,在弹出的上下文菜单中选择“Add”->“Existing Item”,在文件选择对话框中,选中我们需要的源代码文件添加到项目中。

  默认情况下,Visual Studio 2005本身是不支持GIF资源的。如果你尝试着添加一个GIF资源,它将弹出一个错误窗口报告说这个文件不是一个合法的GIF文件。为了添加一个动态的GIF动画资源,我们需要做一些额外的工作。请按照下面的步骤添加GIF资源:

  1.复制GIF文件ProcessingProgressBar.gif到你的项目目录,然后将其扩展名修改为“gaf”。在资源视图中,右键单击MyActiveX.rc,然后选择“Add Resource”。在弹出的添加资源对话框中,点击“Import”按钮,然后选择ProcessingProgressBar.gaf。

  在“自定义资源类型”对话框中,填入“GIF”作为资源类型。这样我们就可以将GIF图像文件导入到项目中作为资源了。你可以在资源视图的“GIF”目录下中找到我们刚刚导入的GIF图像文件。选中这个GIF图像资源,然后将它的ID由默认的IDR_GIF1修改为IDR_PROGRESSBAR。

  2.在上一步中,我们使用“gaf”作为文件扩展名绕过了Visual Studio对GIF资源文件的检查。现在,我们需要做一些事情将这个“错误”修正过来,使得GIF图像文件能够正常工作。首先,在Visual Studio 2005中保存MyActiveX.rc。然后打开项目目录,用记事本直接打开资源文件MyActiveX.rc,然后找到IDR_PROGRESSBAR的定义行。这里我们需要将文件名修改为“ProcessingProgressBar.gif”。同样的,将项目目录下的GIF资源文件的文件名修改为“ProcessingProgressBar.gif”。

接着,保存记事本中的MyActiveX.rc。这时,Visual Studio将报告说MyActiveX.rc被外部程序修改,点击“Yes”重载这个资源文件。最后,选中“解决方案浏览器”中的“ProcessingProgressBar.gaf”,在它的属性对话框中,将“Relative Path”修改为“ProcessingProgressBar.gif”
添加对话框显示进度条

  现在,我们将添加一个对话框用以显示进度条:
  1.在资源视图中,右键点击对话框节点,在上下文菜单中选择“Insert Dialog”创建一个新的默认对话框。
  2.删除对话框模板上我们不需要的“OK”和“Cancel”按钮,然后将对话框的尺寸调整为230 x 40。
  3.然后,我们对对话框的属性做一些必要的修改,使它更适合于用来显示进度条:Border – None, Style – Child, System Menu – False, Visible – True。
  4.将对话框的ID修改为IDD_MAINDIALOG。
  5.在对话框上添加一个图像控件(Picture Control)。将图像控件的尺寸调整为200 x 20,然后将其ID修改为IDC_PROGRESSBAR。同时,将其颜色属性修改为白色(White)。
  6.最后,我们需要为对话框资源创建一个新的类。在对话框资源上右键单击,在弹出的菜单中选择“Add Class”,在接着出现的“MFC类向导”对话框中,我们将新的类命名为CMainDialog,基类设置为CDialog,点击“Finish”完成类的创建。


图3 创建新的对话框类CMainDialog

  现在,我们来为这个新创建的对话框类添加成员变量。成员变量m_MainDialog对应于类CMainDialog,而m_ProgressBar对应于我们刚刚添加的进度条显示控件。
  1.为类CMyActiveXCtrl添加成员变量m_MainDialog。选择类视图,在类CMyActiveXCtrl的节点上点击右键,在上下文菜单中选择“Add”->“ Add Variable”,然后输入CMainDialog作为变量类型,输入m_MainDialog作为变量名。
  2.跟上面的步骤一样,我们为类CMainDialog添加成员变量m_ProgressBar。输入CPictureEx作为变量类型,m_ProgressBar作为变量名。同时,选中“Control variable”复选框,使其成为一个控件变量。在“Control ID”下拉列表中,确认控件的ID为“IDC_PROGRESSBAR”。具体设置如下图4所示:


图4 添加成员变量m_ProgressBar

  添加代码实现进度条的显示

  现在,我们将添加代码实现主对话框和进度条控件的显示。

  1.在类视图中,选中类CMyActiveXCtrl。然后在其属性页中选中消息(Messages)图标,在消息列表中,选择“WM_CREATE”消息,然后选择“<Add> OnCreate”为WM_CREATE消息创建一个消息响应函数OnCreate。这样,向导就会为我们在类CMyActiveXCtrl中创建一个消息响应函数OnCreate。
  2.编辑MyActiveXCtrl.cpp文件,将下列代码添加到我们刚刚创建的OnCreate函数中。这段代码将负责创建主对话框:
m_MainDialog.Create(IDD_MAINDIALOG, this);
然后,将下列代码添加到绘制函数OnDraw中,以实现对主对话框大小尺寸和背景的修改:
m_MainDialog.MoveWindow(rcBounds, TRUE);
CBrush brBackGnd(TranslateColor(AmbientBackColor()));
pdc->FillRect(rcBounds, &brBackGnd);
  3.同样的,我们为主对话框类CMainDialog添加创建消息WM_CREATE的消息响应函数OnCreate。
  4.编辑MainDialog.cpp文件,将下列代码添加到函数OnCreate中,以实现进度条GIF图像的加载和绘制:
if(m_ProgressBar.Load(MAKEINTRESOURCE(IDR_PROGRESSBAR),_T("GIF")))
    m_ProgressBar.Draw();

  最后,确认我们的配置文件是Release版本,构建生成MyActiveX整个解决方案。这样,我们就完成了整个ActiveX控件的创建。

为ActiveX控件创建网页

  光完成了ActiveX控件还不行,因为ActiveX控件无法单独运行,所以我们还需要为ActiveX控件创建相应的测试页面。如果想为我们的ActiveX控件创建一个默认的测试页面,最佳的工具就是Microsoft ActiveX Control Pad。这是一个免费的工具,我们可以从微软的网站上下载得到。

  我们需要下载ActiveX Control Pad并将它安装在我们的开发机器上。同时为了简化测试工作,我们还需要在同一台机器上安装微软的IIS服务器作为Web服务器

  当我们第一次运行ActiveX Control Pad的时候,它将创建一个默认的HTML页面。接下来,我们需要将ActiveX控件插入到这个页面中。在<BODY>标签内的某个位置右键单击,选择“Insert ActiveX Control”,在弹出的“Insert ActiveX Control”对话框中,选中我们刚刚创建的ActiveX控件MyActiveX,然后点击“OK”关闭对话框,将ActiveX控件插入到页面中。

 


图5 插入ActiveX控件

  ActiveX Control Pad提供了两个对话框,供我们对ActiveX控件的各个属性进行修改编辑。属性对话框用于修改ActiveX控件的各项属性。而“编辑ActiveX控件(Edit ActiveX Control)”对话框用于手动地对ActiveX控件进行修改。当然,我们也可以不使用对话框,直接编辑HTML代码达到相同的效果。在代码中找到OBJECT ID标签,如下图6所示,修改它的尺寸参数为“WIDTH=350”和“HEIGHT=50”。完成代码的修改后,将这个文件保存为myactivex.htm,放置到IIS服务器的网站根目录wwwroot下。

 


图6 在ActiveX Control Pad中编辑页面

  现在,我们就可以使用IE打开http://localhost/myactivex.htm对ActiveX控件进行测试了。在ActiveX控件加载的过程中,如果你得到一些警告消息,点击“OK”略过就可以了。正常情况下,你将看到页面中显示的一个进度条GIF动画。如果你没有看到动画,或者是仅仅在ActiveX控件的位置显示一个红色的叉叉,这可能是你的浏览器的安全设置,阻止了ActiveX控件的加载和运行。要解决这个问题,请修改你的浏览器的安全设置,使其所有关于ActiveX的选项都在“允许(enabled)”状态。


图7 浏览器中的MyActiveX控件

  接下来,我们将让我们的控件成为一个“签名的”或者是“安全的”控件,以此来解决在ActiveX控件加载过程中所产生的那些警告信息。
构建一个“签名的”ActiveX控件。要想创建一个“签名的”ActiveX控件,你必须从一些认证机构,例如Thawte,Verisign和GeoTrust,获得代码签名证书(Code Signing Certificate)。通过这项服务,他们将对你进行认证同时为你提供用于对ActiveX控件进行签名的证书文件。这些用于应用程序签名的证书文件包括mycert.spc和mykey.pvk.两个文件。

  为了对ActiveX应用程序进行签名,我们需要将这个程序的所有组件打包成CAB文件。这个CAB文件将被从网站上下载到目标机器上,然后ActiveX控件会通过下载的CAB文件被安装到目标机器上。要启用这项功能,我们必须在ActiveX控件的版本信息VERSIONINFO结构体中定义OLESelfRegister变量。在VS 2003及其之前的Visual Studio之中,这一变量是被自动添加的。但是在Visual Studio 2005中,默认情况下VERSIONINFO结构体中并不包含这一变量,我们需要按照下面的示例手动添加OLESelfRegister这一变量:

 

<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> VS_VERSION_INFO VERSIONINFO
FILEVERSION
1 , 0 , 0 , 1
PRODUCTVERSION
1 , 0 , 0 , 1
FILEFLAGSMASK
0x3fL
#ifdef _DEBUG
FILEFLAGS
0x1L
#else
FILEFLAGS
0x0L
#endif
FILEOS
0x4L
FILETYPE
0x2L
FILESUBTYPE
0x0L
BEGIN
    BLOCK
" StringFileInfo "
    BEGIN
        BLOCK
" 040904e4 "
        BEGIN
            VALUE
" CompanyName " , " TODO: <Company name> "
            VALUE
" FileDescription " , " TODO: <File description> "
            VALUE
" FileVersion " , " 1.0.0.1 "
            VALUE
" InternalName " , " MyActiveX.ocx "
            VALUE
" LegalCopyright " ,
                  
" TODO: (c) <Company name>. All rights reserved. "
            VALUE
" OLESelfRegister " , " \0 "
            VALUE
" OriginalFilename " , " MyActiveX.ocx "
            VALUE
" ProductName " , " TODO: <Product name> "
            VALUE
" ProductVersion " , " 1.0.0.1 "
        END
    END
    BLOCK
" VarFileInfo "
    BEGIN
        VALUE
" Translation " , 0x409 , 1252
    END
END

 

  在签名ActiveX控件之前,ActiveX控件应该被打包成CAB文件。这个CAB文件同样还包含一个INF文件,它将用于安装你的ActiveX控件。要创建CAB文件,你需要Microsoft Cabinet Software Development Kit中的cabarc.exe。下面的INF文件演示了如何将我们的MyActiveX控件打包到CAB文件中。对于其中的CLSID,你需要将其修改为跟之前我们使用ActiveX Control Pad创建的HTML页面中OBJECT ID相同的值。

 

<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> [Add.Code]
myactivex.ocx
= myactivex.ocx
myactivex.inf
= myactivex.inf
[myactivex.ocx]
file
= thiscab
clsid
= { 36299202 - 09EF - 4ABF - ADB9 - 47C599DBE778}
RegisterServer
= yes
FileVersion
= 1 , 0 , 0 , 0
[myactivex.inf]
file
= thiscab

 

  我们可以通过下面的DOS命令创建CAB文件。这里需要注意的是:OCX文件和INF文件必须跟你所执行的cabarc.exe在同一个目录,否则CAB文件在被下载后将无法正确的解压缩。这也是一个导致ActiveX控件被显示为红色叉叉的重要原因。
cabarc -s 6144 N myactivex.cab myactivex.ocx myactivex.inf

  要对我们刚刚创建的CAB文件进行签名,我们需要Microsoft MSDN为我们提供的工具signcode.exe 。(请查阅本文末尾与“Signing and Checking with Authenticode”相关的参考资料) 。通过这个工具,我们就可以用我们从认证机构获得的代码签名证书对CAB文件进行签名了。下面是一个使用signcode对myactivex.cab进行签名的例子:

 

<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> signcode -n "myactivex" -i
http://www.myactivex.com -spc mycert.spc -v mykey.pvk -t http://timestamp.verisign.com/scripts/timstamp.dll myactivex.cab

 

  在上面的例子中,http://www.myactivex.com应该被替换成你的ActiveX控件的说明页面,通过这个页面,你可以为用户提供更多的关于这个控件的信息。

  要使用签名过后的CAB文件,首先我们需要将myactivex.cab复制到web服务器的一个合适的目录下,然后我们修改Web页面中的OBJECT ID标签,添加一个参数CODEBASE指向CAB文件。具体代码如下图8所示。这样,当你再使用IE打开这个页面时,CAB文件会被下载,然后ActiveX控件会被正确的安装到你的机器上。在安装的过程中,再也不会弹出提示未签名ActiveX控件的警告信息了。


图8 添加CODEBASE参数

创建安全的ActiveX控件

  要想创建一个能够在IE中成功加载而没有“不安全”的警告或者错误提示信息的ActiveX控件,我们必须实现安全的初始化和脚本。关于安全初始化的更加详细的信息,请参考本文结尾的参考资料“Safe Initialization and Scripting for ActiveX Controls”。基本上,所有要做的工作都是在DllRegisterServer 和DllUnregisterServer这两个函数中完成的。下面,我们就来一步步地将我们的ActiveX控件变成一个“安全的”控件。

  1.编辑MyActiveX.cpp并添加如下的代码。其中,CLSID_SafeItem的值应该跟MyActiveXCtrl.cpp中的IMPLEMENT_OLECREATE_EX一致,这就等同于你的ActiveX控件。同样,它也应该跟你的HTML页面中的OBJECT ID标签中的CLSID一致。

 

<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> #include " comcat.h "
#include
" strsafe.h "
#include
" objsafe.h "

// CLSID_SafeItem – 安全的ActiveX控件所必须的内容
// ID的值跟xxxCtrl.cpp文件中的IMPLEMENT_OLECREATE_EX一致

const CATID CLSID_SafeItem =
{
0x36299202 , 0x9ef , 0x4abf ,{ 0xad , 0xb9 , 0x47 , 0xc5 , 0x99 , 0xdb , 0xe7 , 0x78 }};

// HRESULT CreateComponentCategory – 用于注册安全的ActiveX控件

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;

    
// 确认HKCR\Component Categories\{..catid...}键值被注册

    CATEGORYINFO catinfo;
    catinfo.catid
= catid;
    catinfo.lcid
= 0x0409 ; // english

    size_t len;
    
// 确认描述不是太长。
// 只复制开始的127个字符。
// StringCchLength的第二个参数表示被读入catDescription的最大字符数。
    
// 第三个参数表示字符串的长度

    hr
= StringCchLength(catDescription, STRSAFE_MAX_CCH, & len);
    
if (SUCCEEDED(hr))
        {
        
if (len > 127 )
          {
            len
= 127 ;
          }
        }  
    
else
        {
          
// TODO: Write an error handler;

        }

    hr
= StringCchCopy(catinfo.szDescription, len + 1 , catDescription);
    
// 添加字符串结束符.
    catinfo.szDescription[len + 1 ] = ' \0 ' ;

    hr
= pcr -> RegisterCategories( 1 , & catinfo);
    pcr
-> Release();

    
return hr;
}

// HRESULT RegisterCLSIDInCategory -

//       注册组件分类信息


HRESULT RegisterCLSIDInCategory(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))
    {
       CATID rgcatid[
1 ] ;
       rgcatid[
0 ] = catid;
       hr
= pcr -> RegisterClassImplCategories(clsid, 1 , rgcatid);
    }

    
if (pcr != NULL)
        pcr
-> Release();
            
    
return hr;
}

// HRESULT UnRegisterCLSIDInCategory

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))
    {
       CATID rgcatid[
1 ] ;
       rgcatid[
0 ] = catid;
       hr
= pcr -> UnRegisterClassImplCategories(clsid, 1 , rgcatid);
    }

    
if (pcr != NULL)
        pcr
-> Release();

    
return hr;
}

 

  2.修改 DllRegisterServer函数: 

 

<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> 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);
    
// 为初始化标记控件为安全控件                                      
    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;
}

 

  3.修改 DllUnregisterServer函数: 

 

<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> STDAPI DllUnregisterServer( void )
{
    HRESULT hr;    
// HResult used by Safety Functions
    AFX_MANAGE_STATE(_afxModuleAddrThis);
    
if ( ! AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))
      
return ResultFromScode(SELFREG_E_TYPELIB);
    
if ( ! COleObjectFactoryEx::UpdateRegistryAll(FALSE))
      
return ResultFromScode(SELFREG_E_CLASS);
    hr
= UnRegisterCLSIDInCategory(CLSID_SafeItem,                      CATID_SafeForInitializing);
    
if (FAILED(hr))
      
return hr;
    hr
= UnRegisterCLSIDInCategory(CLSID_SafeItem,
                        CATID_SafeForScripting);
    
if (FAILED(hr))
      
return hr;
    
return NOERROR;

ActiveX控件的属性,方法和事件

  ActiveX控件和Web页面之间的通信是通过ActiveX控件的属性,方法和事件来完成的。为了演示这些内容,我们需要创建一个带有输入框的页面。当页面上的“提交”按钮被点击后,输入的文本将通过一个输入参数自定义属性传递给ActiveX控件。然后,控件的一个函数将被调用,复制这些文本到一个输出参数自定义属性。接着,将触发一个事件,将这些文本显示到页面上。我们将通过下面这些步骤来实现这一ActiveX控件和Web页面之间的通信过程:

  1.首先,我们将为ActiveX控件创建自定义属性,用于发送和接收文本。在类视图中,展开MyActiveXLib,然后选择_DMyActiveX。右键单击_DMyActiveX,在上下文菜单中选择“Add”->“Add Property”。在”添加属性向导”对话框中,选择BSTR作为属性类型,然后输入“InputParameter”作为属性的名称。至于对话框中的其它内容,向导将自动为我们生成。最后,点击“Finish”按钮关闭对话框,向导将为我们创建相应的代码。同样地,添加另外一个BSTR类型的属性OutputParameter。

 


图9 添加属性向导

  2.接下来,我们将创建一个方法,使Web页面能够通知控件将文本从输入参数传递到输出参数。在类视图中,展开MyActiveXLib,然后选择_DMyActiveX。右键单击_DMyActiveX,在上下文菜单中选择“Add”->“ Add Method”。在“添加方法向导”对话框中,选择void作为方法的返回类型,输入“LoadParameter”作为方法名,向导会自动地填入“LoadParameter”作为外部名字。点击“Finish”按钮关闭对话框,向导将为我们创建相应的方法代码。  

 


图10添加方法向导

  3.现在,我们将创建一个事件,让ActiveX控件通知Web页面已经完成了文本从输入参数到输出参数的传送。Web页面中的代码将对这个事件做出响应,将输出参数中的文本显示出来以证明传送确实发生了。在类视图中,右键点击CMyActiveXCtrl,然后选择“Add”->“Add Event”。在“添加事件向导”对话框中,输入“ParameterLoaded”作为事件名称,然后将外部名称修改为“FireParameterLoaded”。点击“Finish”按钮关闭对话框,向导将为我们创建相应的代码。

 


图11 添加事件向导

  通过上面这些步骤,向导已经为我们创建了代码的大致框架。我们只需要添加几行代码,完成文本的复制然后通过事件通知Web页面就可以了。编辑文件MyActiveXCtrl.cpp,在函数LoadParameter中添加如下的代码:

 

<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> // 将文本从输入参数复制到输出参数
m_OutputParameter = m_InputParameter;
// 触发一个事件通知Web页面
FireParameterLoaded();
  为了测试ActiveX控件和Web页面之间的通信,使用ActiveX Control Pad创建如下的HTML代码:
< HTML >
< HEAD >
< TITLE > MyActiveX - Methods, Properties, and Events </ TITLE >
< SCRIPT LANGUAGE ="JavaScript" >

function PassParameter()
{
    
if (StringInput.value != " " )
    {
        MyActiveX1.InputParameter
= StringInput.value;
        MyActiveX1.LoadParameter();
    }
}
</ SCRIPT >
</ HEAD >
< BODY >
< center >
MyActiveX - Methods, Properties, and Events Example
< p ></ p >
< OBJECT ID ="MyActiveX1" WIDTH =350 HEIGHT =50
CLASSID ="CLSID:36299202-09EF-4ABF-ADB9-47C599DBE778" >
    
< PARAM NAME ="_Version" VALUE ="65536" >
    
< PARAM NAME ="_ExtentX" VALUE ="2646" >
    
< PARAM NAME ="_ExtentY" VALUE ="1323" >
    
< PARAM NAME ="_StockProps" VALUE ="0" >
</ OBJECT >
< p ></ p >
Input Parameter:
< INPUT TYPE ="text" NAME ="StringInput" VALUE =" " >
< p ></ p >
< INPUT TYPE ="button" NAME ="Submit"
       VALUE
="Submit" ONCLICK =PassParameter() >

< SCRIPT FOR =MyActiveX1 EVENT =ParameterLoaded() >
<!-- {
   window.document.write(
" The parameter you entered is:<br> " + MyActiveX1.OutputParameter + "    " )
-->
</ SCRIPT >
</ center >
</ BODY >

 

  将上面的页面保存到Web服务器上,然后在IE中打开这个页面。你将看到一个用于输入文本的编辑框和“提交”按钮。在编辑框中输入文本,然后点击“提交”按钮,你将得到一个新的页面,其中显示了你刚刚输入的文本内容。下面,我们来解释一下整个Web页面的工作过程。

  当你点击“提交”按钮之后,JavaScript函数PassParameter将被调用。这个函数将文本从编辑框StringInput复制到ActiveX控件的InputParameter属性。然后,它将调用控件的函数LoadParameter,将文本从InputParameter复制到OutputParameter,接着调用FireParameterLoaded产生一个ActiveX控件事件。下面的HTML代码将负责对这个事件进行处理,通过ActiveX控件的OutputParameter属性访问文本内容,将输入的文本显示到新窗口中。如此,就完成了ActiveX控件和Web页面之间的通信。

 

<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> < SCRIPT FOR =MyActiveX1 EVENT =ParameterLoaded()>
<!-- {
  window.document.write("The parameter you entered is:<br
> " +                         MyActiveX1.OutputParameter + "  ")
-->

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

步步学ACTIVEX网页控件开发 的相关文章

  • MySQL外键允许NULL吗?

    我正在拼凑一个图像网站 基本模式非常简单 MySQL 但我在尝试表示与图像关联的可能的管理标志 不适当 受版权保护 等 时遇到了一些麻烦 我目前的想法如下 tblImages imageID INT UNSIGNED NOT NULL AU
  • EditText 视图返回 null

    我有两个活动 一个 主页 片段活动和一个普通的 选项 活动 在我的主页片段活动中 我尝试使用从选项活动检索的数据来更新 EditText 视图 不幸的是 由于某种原因 片段活动无法检测到我的视图以进行更新 我不太清楚为什么 这是我的功能 u
  • 如果字符串中间出现空字符怎么办?

    我知道字符串的结尾由空字符表示 但我无法理解以下代码的输出 include
  • 默认情况下启用或禁用菜单项。为什么?

    我有一些遗留代码 由于某种原因 菜单项在启动时被启用或禁用 我的问题是 如何 有没有办法在不调用 EnableMenuItem 函数的情况下执行此操作 MFC 有没有办法做与资源设置所说相反的事情 我也不明白为什么当最后一个子窗口关闭时 当
  • 如何检查 params[:some][:field] 是否为零?

    我尝试了代码 这让很多人受益匪浅 如何测试rails中是否存在参数 https stackoverflow com questions 5629402 how to test if parameters exist in rails 但它不
  • 如何在现有 Windows 应用程序中获得 ATL 支持

    我正在 Visual Studio 2012 中使用 Qt 5 3 1 构建一个应用程序 我还想使用一个硬件库 这需要我向项目添加一个简单的 ATL 对象 这可以通过使用 Visual Studio 向导来完成 该向导抱怨我的项目既不是 M
  • Haskell 中的 undefined 和 Java 中的 null 有什么区别?

    两者的类型都是所有类型的交集 无人居住 两者都可以在代码中传递而不会失败 直到尝试评估它们为止 我能看到的唯一区别是 在 Java 中 有一个漏洞允许null仅针对一个操作进行评估 即引用相等比较 而在 Haskell 中undefined
  • 如何发光最小。最大和关闭按钮?

    我按照以下指南使用 DWM API 创建自定义 Aero 框架 My work void CMainFrame OnActivate UINT nState CWnd pWndOther BOOL bMinimized CFrameWnd
  • 空值并不唯一

    我在 postgres 上有这样的行 name address college john rome john rome max tokyo 我创建一个这样的表 create test name varchar 10 address varc
  • 如何创建文件名中包含空字节的文件?

    对于安全测试 我需要传递一个内容和文件名中包含空字符的文件 对于body内容来说 很容易使用printf printf Hello 00 Null gt containsnull txt xxd contains null 0000000
  • 如何消除SQL中的NULL字段

    我正在为 SQL Server 2008 R2 开发 TSQL 查询 我正在尝试开发此查询来识别一条记录 客户 由于其中一些值为 NULL 因此我目前正在对大多数表执行 LEFT JOINS 但 LEFT JOIN 的问题是 现在我为某些客
  • 无法检查 int 是否为 null

    我正在尝试使用字典 每当我想检查字典中是否存在某个元素时 我都会这样做 int value results get aKeyThatMayOrMayNotBePresent if value null 但编译器说我无法比较int to a
  • 如何将命名管道字符串从非托管代码空间发送到托管代码空间?

    我似乎遇到了命名管道 101 问题 我有一个非常简单的设置来连接从 C 非托管应用程序传输到 C 托管应用程序的单工命名管道 管道已连接 但我无法通过管道发送 消息 除非我关闭似乎刷新缓冲区并传递消息的句柄 就好像消息被屏蔽了一样 我尝试颠
  • 禁用/启用 MFC 功能包的功能区按钮

    我正在使用 MFC 功能包 并且功能区栏上有一些按钮 即 CMFCRibbonButton 的实例 问题是我想在某些条件下启用和禁用其中一些 但在运行时 我怎样才能做到这一点 因为没有具体的方法 我听说解决方案是在运行时附加 分离事件处理程
  • 如何在 SQL 中替换 PIVOT 中的 Null 值

    我有以下代码 我试图用零替换使用枢轴时出现的 Null 我执行了以下操作 但它说 ISNULL 附近的语法不正确 我不确定我做错了什么 有什么建议请 select from tempfinaltable pivot ISNULL sum T
  • 如何将基数词转换为序数词

    有没有一种简单的方法可以将数字 1 2 3 转换为 1st 2nd 3rd 并且以这种方式我可以为该函数提供一种语言并具有它会返回我目标语言的正确形式吗 标准 C stl 或 boost 都可以 MFC 或 ATL win32 api 或我
  • 如何检查 GAS 中是否存在文件(通过 id)

    我知道有关如何检查文件是否存在的问答by name using hasnext 不过我需要检查一下按文件 ID 最好没有高级 Drive API 披露 我写了一个基于错误处理的解决方案 function ifFileExists id tr
  • C 中的 NULL 是否需要/定义为零?

    在我的 GCC 测试程序中 NULL 似乎为零 但维基百科说NULL只需要指向不可寻址的内存 有编译器做吗NULL非零 我很好奇是否if ptr NULL 是比更好的练习if ptr NULL is guaranteed to be zer
  • 确定非空列表条目是否“连续”的 Pythonic 方法

    我正在寻找一种方法来轻松确定列表中所有非 None 项目是否出现在单个连续切片中 我将使用整数作为非 None 项目的示例 例如 列表 None None 1 2 3 None None 满足我对连续整数条目的要求 相比之下 1 2 Non
  • 如何在无 null 设计中实现 List、Set 和 Map?

    当您在大多数情况下可以返回 null 空对象以避免 null 时 这很好 但是像 Collection 这样的对象呢 在爪哇 Map回报null if key in get key 地图上没有找到 我能想到的最好的避免方法null在这种情况

随机推荐

  • VS 2008配置Winpcap环境

    写在前面的话 这篇博客主要是写给小白看的 因为自己也是一个小白 之前从没有接触过网络嗅探器这些东西 如果说基础的话就是学习过计算机网络 对于计算机网络有一点点了解 再就是对于编程语言基础语法还算熟悉吧 这学期选修了网络攻击与防范这门课程 老
  • 视觉SLAM14讲笔记-第7讲-视觉里程计1

    图像特征点 特征点由关键点和描述子两部分组成 我们说的特征点具有旋转不变性 都是指的是特征点的描述子具有旋转不变性 而描述子指的是一个点周围的特征 一般由一个向量组成 描述一个点附近的特征 比如45度方向是亮的 135度方向是暗的等 比较著
  • 【WIN】【C++】查询文件信息(公司、版本、版权、描述、厂商等)

    使用C 提供的一个查询文件信息的接口 实现接口为 QueryValue fileInfo h class FileInfoUtils public static bool GetFileDescription const std wstri
  • mysql 免安装重装_mysql 卸载 重装 免安装版

    今天下午一下午都在安装mysql 首先说 卸载 1 如果控制面板里有mysql sever 先卸载 2 把安装的文件都删掉 3 regedit exe注册表中的三个地方的MySQl文件夹删掉 在cmd中输入regedit就找到注册表了 4
  • linux下C语言中的flock函数用法

    http blog csdn net lin fs article details 7804494 表头文件 include
  • 感知机(perceptron)代码实现

    书面内容参考 统计学习方法 李航 感知机 perceptron 是二分类的线性模型 旨在求出将训练数据进行线性划分的分离超平面 感知机模型 假设输入空间 特征空间 是x Rn 输出空间是输入x x表示实例的特征向量 对应于输入空间 特征空间
  • cp: cannot stat '/usr/local/bin/node': Too many levels of symbolic links

    升级nodejs 出现这个问题 ln failed to create symbolic link node File exists cp cannot stat usr local bin node Too many levels of
  • 低代码和专业开发云 开发平台 3.4.7 全新版本框架源码 旗舰版

    低代码开发云 高效全栈开发 跨端App开发 自由发布 灵活部署 提供开发 测试 部署 运维的一体化支持 真正低代码 高效率的DevOps开发运维一体化平台 低代码PaaS平台 企业云架构的关键层 真正提升企业应用的架构 开发 运维和治理 低
  • 初识Node.js-安装

    简介 node js其实就是js的运行环境 对于js的运行环境来说 1 前端一般指浏览器 比如谷歌浏览器提供了V8 js解析器 2 服务器段指的是Node js 1 区分LTS版本和Current版本的不同 https nodejs org
  • 报错EL1007E: Property or field ‘xxxxx’ cannot be found on null原因竟是这

    报错EL1007E Property or field xxxxx cannot be found on null 是什么原因 有时我们发现Springboot项目前端的 thymleaf 会报这样的错 EL1007E Property o
  • 设计模式 -- 工厂模式(Factory Pattern)

    简单工厂模式 Simple Factory Pattern 根据传入的参数决定实例化哪个对象 优点 不直接在客户端创建具体产品的实例 降低了耦合性 缺点 违反了开闭原则 对扩展开放 对修改关闭 不容易形成高内聚松耦合结构 每当我们增加一种产
  • 10个程序员可以接私活的平台和一些建议!

    来源 http mrw so 5isQLi 什么样的私活不能接 1 没有第三方担保的个人对个人的尽量不要接 双方都没保障 出了问题很大的可能撕破脸皮不了了之 2 一上来就直接说给我开发一个什么软件 不说具体需求 没有需求文档的都不靠谱 这样
  • zotero如何用markdown记笔记

    1 去下载 Releases adam p markdown here GitHub 拖拽到 2 ctrl alt M对笔记进行渲染
  • 【华为OD机试真题2023B卷 JAVA&JS】字符串加密

    华为OD2023 B卷 机试题库全覆盖 刷题指南点这里 字符串加密 时间限制 2秒 内存限制 65536K 语言限制 不限 题目描述 给你一串未加密的字符串str 通过对字符串的每一个字母进行改变来实现加密 加密方式是在每一个字母str i
  • Altium Designer覆铜后变为绿色是怎么回事?

    最近在做一个小板子 但是覆完铜后也把网络设置为GND 但是板子变绿色了 之前没有碰到过 也查过想过资料说是规则设置有问题 找了半天也没有发现规则相关问题 最后终于找到了解决方法 我把步骤写在下面 出现的问题如图所示 不知道你们有没有碰到这样
  • wx.config的时候总是报错63002是什么原因,配置时总是 invalid signature

    真的是真的是 我都弄的崩溃了差点 卡了三天的问题 各种留言各种找人还是不行 为了不再让各位体验那种感觉 zkhh666我的wx 首先说 我用的hbuilderx的uni做的 使用了推荐的插件jweixin module ps 我的问题是ur
  • PostgreSQL 关于Jsonb字段的处理详解(长期更)

    大家好 在开发的过程中由于业务复杂多变 普通的字符串格式满足不了业务开发需求 可能会用到jsonb字段去处理格外逻辑的业务 话不多说 1 一般jsonb存储的逻辑是 一个字段里面存储多条数据 以id为存储对象举例 该jsonb字段中存储的多
  • 参考文献格式GB/T 7714-2015的主要内容

    格式 主要责任者 题名 其他题名信息 文献类型标志 其他责任者 版本项 出版地 出版者 出版年 引文页码 引用日期 获取和访问路径 示例 1 余敏 出版集体研究 M 北京 中国书籍出版社 2001 179 193 2 昂温 G 昂温 P S
  • 八种点云聚类方法(一)— DBSCAN

    本文为博主原创文章 未经博主允许不得转载 本文为专栏 python三维点云从基础到深度学习 系列文章 地址为 https blog csdn net suiyingy article details 124017716 传统机器学习聚类的方
  • 步步学ACTIVEX网页控件开发

    本文将首先介绍如何使用Visual Studio开发一个简单的ActiveX控件 然后介绍ActiveX控件开发相关的基础知识 比如方法 属性和事件等 最后介绍如何利用这些知识 实现ActiveX控件和网页页面之间的 通信 MyActive