`
lbyzx123
  • 浏览: 468782 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

我的第一个OCX制作打包

    博客分类:
  • c++
 
阅读更多

    本文在《VC2005从开发MFC ActiveX ocx控件到发布到.net网站的全部过程》基础改造而来,也参考了《如何制作CAB包》,做一个简单ocx示例。

 

最近在弄ocx控件发布到网站上使用,就是用户在使用过程中,自动下载安装ocx控件。
ActiveX控件用于Web的过程是将控件嵌入主页中,用户通过浏览器访问该主页时,将主页中的控件下载,
并在用户机器上注册,以后就可在用户的浏览器上运行。控件下载一次后就驻留在用户本地机器上,下次
再访问相同的主页时,可不再下载该控件,而是直接运行用户本地的控件。这里控件容器就是浏览器,用
户不需要通过浏览器调用控件的属性或方法。因此,开发面向Web的ActiveX控件比开发桌面的控件还要简
单些,所复杂的是如何将该控件很好地嵌入主页,使用户能正常浏览。

 一.        创建MFC ActiveX项目

 

 

1.       打开VS2005新建MFC项目。这里我们取名为“ActiveXDemo”。

2.       输入项目名称为“ActiveXDemo”和项目位置。点击“确定”按钮,打开向导对话框。

3.       选择“控件设置”选项卡,具体设置可参考上图。其它选项卡为默认设置。最后点击“完成”按钮保存设置。

二.        添加控件方法

 

VC2005会为我们自动创建好MFC ActiveX程序框架,我们只要给该ActiveX控件添加方法即可。现在我们给控件添加一个“AddFun”方法,这个方法是将两个数相加并返回结果。

 

1.       点击“视图”,打开“类视图”窗口。

2.       展开“ActiveXDemoLib”项,选中“_DActiveXDemo”项。点击鼠标右键,选择“添加”下的“添加方法”。

3.       打开添加方法向导窗口。因为我们是添加一个加法方法,所以我们设置的返回类型为LONG型,方法名设为AddFun,添加两个LONG类型参数Add1Add2

5.       打开代码视图,我们会发现VC2005已经为我们添加了一个“AddFun”方法,我们在方法内添加“return Add1 + Add2;”语句。

三、MFC Activex 安全问题

 1、在默认环境下,编译的MFC Activex控件,只能在本地代码中运行,即在http://localhost/xxx/xxx.htm中执行,而在http://127.0.0.1/xxx/xxx.htm中提示无相关属性,需要设置其初始化和脚本运行的安全性。

 ActiveX在远程IE页面上执行,需要实现安全接口。

  在ATL写的ActiveX中,用IObjectSafety。

 

  http://support.microsoft.com/kb/168371/en-us

 

  在MFC写的ActiveX中,直接修改注册表。

 

  http://support.microsoft.com/kb/161873/en-us

 

 

  mfc实现的ocx,要在app实现文件中包括两个文件:并重写DllRegisterServer和DllUnregisterServer方法。重写后的代码如下:ActiveXDemo.cpp

 

#include "stdafx.h"
#include "ActivexDemo.h"
#include <comcat.h>    
#include <objsafe.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif


CActiveXDemoApp theApp;

const GUID CDECL BASED_CODE _tlid =
{0x3332A68D,0xAB57,0x4577,{0x82,0x16,0xCC,0x09,0xE0,0x0F,0x41,0x90}};//此处是ActiveXDemo.idl中uuid的16进制数组
//{ 0x344B8576, 0xAB2C, 0x4D38, { 0xAE, 0x7, 0x73, 0x74, 0x22, 0x89, 0x72, 0xEA } };
const WORD _wVerMajor = 1;
const WORD _wVerMinor = 0;



// CActiveXDemoApp::InitInstance - DLL 初始化

BOOL CActiveXDemoApp::InitInstance()
{
	BOOL bInit = COleControlModule::InitInstance();

	if (bInit)
	{
		// TODO: 在此添加您自己的模块初始化代码。
	}

	return bInit;
}



// CActiveXDemoApp::ExitInstance - DLL 终止

int CActiveXDemoApp::ExitInstance()
{
	// TODO: 在此添加您自己的模块终止代码。

	return COleControlModule::ExitInstance();
}

// 创建组件种类    
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;    
}    
STDAPI DllRegisterServer(void) 
{    
	HRESULT hr;    
	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(BASED_CODE _tlid , CATID_SafeForInitializing);    
	if (FAILED(hr)) return hr;    
	// 标记控件脚本安全    
	// 创建脚本安全组件种类    
	hr = CreateComponentCategory(CATID_SafeForScripting, L"Controls safely scriptable!");    
	if (FAILED(hr)) return hr;    
	// 注册脚本安全组件种类    
	hr = RegisterCLSIDInCategory(BASED_CODE _tlid , CATID_SafeForScripting);    
	if (FAILED(hr)) return hr;    
	return NOERROR;    
}    
// DllUnregisterServer - Removes entries from the system registry    
STDAPI DllUnregisterServer(void) 
{    
	HRESULT hr;    
	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(BASED_CODE _tlid , CATID_SafeForInitializing);    
	if (FAILED(hr)) return hr;    
	// 删除控件脚本安全入口    
	hr=UnRegisterCLSIDInCategory(BASED_CODE _tlid , CATID_SafeForScripting);    
	if (FAILED(hr)) return hr;    
	return NOERROR;    
}

 

 

此处如果复制网上代码不做改动进行build,也能生成ocx,但是vs工具生成ocx后自动注册ocx,将有以下错误提示:

 

Project : error PRJ0050: Failed to register output.  Please try enabling Per-user Redirection or register the component from a command prompt with elevated permissions.

 

最终导致ocx无法注册成功。

出现以上错误的原因是:

1、win7环境uac设置的原因,要以管理员身份运行cmd。

2、ocx本身依赖的dll缺少。

3、我自己的原因:ActiveXDemo.cpp有一个GUID的实例_tlid,它的值必须为idl文件中uuid的16进制数组形式,否则无法在注册表中注册。

 

现在控件就可以在自注册时就注册为安全控件了。

3、       最后build项目,ocx控件就产生了。

 

ActiveX打包

用到的工具:

打包工具iexpress.exe打包文件:

test.html

extadd.inf

ActiveXDemo.ocx

制作步骤

步骤1 准备inf文件

 

[version]   
signature="$CHICAGO$"
AdvancedINF=2.0

[DefaultInstall]
CopyFiles=install.files
RegisterOCXs=RegisterFiles

[RInstallApplicationFiles]
CopyFiles=install.files
RegisterOCXs=RegisterFiles

[DestinationDirs]
install.files = 24,Program Files\extadd
  
[SourceDisksNames]
1=%DiskName%,extadd.cab,1

[install.files]
ActiveXDemo.ocx=ActiveXDemo.ocx
test.html=test.html

[test.html]
file-win32-x86=thiscab
RegisterServer=no

[ActiveXDemo.ocx]
file-win32-x86=thiscab
RegisterServer=yes
clsid={99FFE4AD-6E24-490A-A849-BEFDB9808F11}
DestDir=24,Program Files\extadd

[RegisterFiles]
%24%\Program Files\extadd\ActiveXDemo.ocx


 

 

注释:

  (1) "thiscab" 是一个关键字,意指包含该INFCAB文件。也可以从网上下载所需要的DLL文件,只要指定一个HTTP 网址即可

  (2)关键字"file-win32-x86" 指定平台是 x86

 

  (3)文件版本号可见属性。

 

  (4) "DestDir"指的是装载目录或者文件的地址: 11 指定为系统目录 WINDOWS/ /SYSTEM32;

 

  (5) "clsid" 指的是要安装控件的CLSID

 

步骤2 制作CAB

0)       运行iexpress.exe

1)      选择“Create new Self Extraction Directive file”,点击下一步。

2)      选择“Create compressed files only(ActiveX Installs)”,点击下一步。

3)      点击Add,选择所有文件包括inf,点击下一步。

4)      点击Browse,输入.CAB文件的存放地址(包含所取文件名),并且要选中Store files using Long File Name inside Package”。点击下一步。

5)      选择“Dont save”,一直点击下一步,直到完成。

遇到的问题

以上制作的ActiveXDemo.ocx,能够在开发环境下注册,并在html页面上调用成功,但是到另外一台没有安装

VS2005的机器进行注册,会注册失败。因为此系统缺少VS2005的运行库,而ActiveXDemo.ocx依赖运行库,所以无法完成注册。VS2005运行库的文件列表如下:

MFC80U.DLL
mfcm80u.dll
msvcm80.dll
msvcp80.dll
msvcr80.dll
Microsoft.VC80.ATL.manifest
Microsoft.VC80.CRT.manifest
Microsoft.VC80.MFC.manifest
需要把这些文件和
ActiveXDemo.ocx放在同一目录下,才能找到。

 

有了这些文件,在没有VS2005的机器上也可以注册成功ActiveXDemo.ocx并进行调用。

 

赠送一个知识点:可以通过Depends.exe(VC6有带)分析ocx的依赖性和提供的属性、事件、方法等。

 

Depends.exe可以分析dll依赖的文件,出现黄色问号的为缺少的文件。

 

编译ocx的release版时可能出现权限不足的问题,是因为缺少VS2005的运行库。可以在编译之前在“属性”中设置不注册ocx,以输出release版本。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 大小: 28.9 KB
  • 大小: 27 KB
  • 大小: 12.8 KB
  • 大小: 22.6 KB
  • 大小: 24.6 KB
  • 大小: 20.9 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics