VC 制作ActiveX 控件(OCX)
http://ileson.iteye.com/blog/1002910
1、vc6下建立一下activeX工程
详见http://hi.baidu.com/mailrabbit/blog/item/0624a608bde798346b60fbb6.html
2、在页面中调用
2.1:注册ocx到系统(也可以这样)
Cmd代码 收藏代码
regsvr32 E:\ocx\test.ocx
2.2找到classid
有几种方法:
①、VC--》菜单栏中的“工具”--》OEL/COM Object viewer--》Object Classes--》All Objects --》找到对应的OCX名称,找到例如 如下值:clsid={96E5CC6E-18BD-43DA-B564-2EAB9F282C76}=XNPOS Control
②、在注册表里找,其实上面的工具,也是从注册表里提取的。。。
cmd->regedit-> ctrl+f 输入你的ocx名称
③、其实在工程文件里,有个odl文件。。最后一行的clsid 就是。。。
2.3页面
Html代码 收藏代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>无标题文档</title>
<script type="text/javascript" language="javascript">
/**
*测试OCX
*/
function testOCX(){
alert("进入");
var ocx=document.getElementById("pos");
alert(ocx);
var t=ocx.test(1,2);
alert(t);
}
</script>
</head>
<body>
<!--clsid : 如果控件成功注册到本机后,这个值在本机注册表中可以找到,js获取控件对象就是通过这个来找的。-->
<OBJECT name="xn_pos" ID="pos" WIDTH="0" HEIGHT="0" CLASSID="CLSID:96E5CC6E-18BD-43DA-B564-2EAB9F282C76" codebase="xnpos.ocx"></OBJECT>
<input type="button" value="测试OCX" onclick="testOCX();" />
</body>
</html>
3、过程中遇到的一些问题
3.1、xxx.odl 中支持boolean; .cpp和.h中不支持boolean只能用BOOL;
xxx.odl 中不支持int 支持long .参数写成int时 ctrl+w就不管用了,报
“Parsing error: "int" is not a valid OLE parameter type。”
3.2、接口函数都写在 xxxCtl.cpp中
3.3、VC设置编译时活动的工程
3.3.1>menu---Project---Settings(具体的项目,无参考价值,请读者忽略!)
3.3.2>menu---Build---Set Active Configuration
3.4、用regsvr32 注册不到系统里报“找不到指定模块”错误。
分析:有可能控件有依赖的其它DLL文件没有在系统System32下。
解决办法:用工具depends查看一下ocx 控件的依赖关系,其中有黄色标记的dll 就是该控件所需要的。将其放到system32下就可以了。(这个方法百试不爽,同样可以解决浏览器有些可以加载有些加载不上去的问题)
今天发现:LoadLibrary("xxx.dll"); 返回NULL 也是这个问题。。。
3.5、解决ActiveX 工程无法用vc 调试的问题(更正:是有办法的;各种调试)
方法一:笨办法 AfxMessageBox();(在适当的时候用,这个太费劲了,特别是大项目时)
方法二:曲线救国 ;
·在一个工作空间中分别建ActiveX工程 和Dialog工程,用dialog 工程来管理ActiveX工程。具体办法 就是用dialog 工程来加载ActiveX工程下你自己写的程序文件,然后编译调试就OK
·在这期间遇到dialog中无法编译源程序,提示找不到头文件。解决方法如下: 1、Project -->Settings-->如下图:
点击查看原始大小图片
3.6、很多时候,在本机编写ocx时,本机上的浏览器加载不到这个控件,今天终于发现如何解决了。
其实不是找不到,是因为浏览器通过clsid 已经找到本机有自己制作的控件了,所以它就默认不再加载控件到浏览器控件的目录了。如果这时候,你把vc工程清理一下,再通过浏览器访问你的页面时,就会加载你的控件。害我迷糊了好长时间,甚至要测试我还要换一台机器。希望新手可以解惑!!!!
3.7、页面刷新,重复加载ocx对象几次后,会将浏览器卡死。。。(还未找到解决办法,哪位有解决思路,QQ:278952725)
经过大量的实验,发现比较接近的可能是:
3.7.1、资源占用未及时释放。(如调用了第三方的dll,这个dll用调用了i/o 操作,何时释放不受控制,so 出现崩溃)如操作外设,i/o资源没有及时释放(我遇到的一个例子是:我写了两个控件(功能是一样的,调用同样的硬件资源)分别加载到两个页面中,当点A页面后,再点B页面就会造成浏览器崩溃,甚至关闭!)。程序中一定要注意释放i/o资源,及其它耗时的操作!
3.7.2、程序问题。多线程造成的死锁。
3.8、因为现在有好多机器装的是64位的操作系统(win7,win8),这时候老的32位动态库,放到system32 下就不能被调用了。。
解决办法:windows下有个 sysWOW 目录。。。把32位的dll 放到这里在。。。{我发现打成cab压缩包后,在浏览器端 自动解压时,也会自动解压到 sysWOW64中!所以还是打包方便}
DEPENDS.rar (134 KB)
========
VC++开发Activex控件以及签名发布
http://arlon.iteye.com/blog/845775
前言
本人不懂C++,当前由于要做一个打印控件,使用Activex插件技术,所以在网络上搜索了相关技术文档,今天有空,遂将自己的当前学到的一些关于Activex技术整理之,进而和朋友们分享之。
一、 开发环境
开发工具:Visual Studio 2008
开发语言:Visual C++
测试工具:IE 7+
二、 创建MFC ActiveX项目
1、 打开VS2008新建MFC项目。这里我们取名为“PrintUtil”。
2、 输入项目名称为“PrintUtil”和项目位置。点击“确定”按钮,打开向导对话框。
3、 选择“控件设置”选项卡,具体设置可参考上图。其它选项卡为默认设置。最后点击“完成”按钮保存设置。
三、 添加控件方法
VC2005会为我们自动创建好MFC ActiveX程序框架,我们只要给该ActiveX控件添加方法即可。现在我们给控件添加一个“AddFun”方法,这个方法是将两个数相加并返回结果。
1、 点击“视图”,打开“类视图”窗口。
2、 展开“PrintUtilLib”项,选中“_DPrintUtil”项。点击鼠标右键,选择“添加”下的“添加方法”。
3、 打开添加方法向导窗口。因为我们是添加一个加法方法,所以我们设置的返回类型为LONG型,方法名设为AddFun,添加两个LONG类型参数Add1,Add2。
4、 其它为默认设置,点击“完成”按钮完成添加方法。接下来我们打开“解决方案资源管理器”打开“PrintUtilCtrl.cpp”文件。
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实现文件中包括两个文件:
在PrintUtil.h文件中实现以下方法:
// PrintUtil.cpp : CPrintUtilApp 和DLL 注册的实现。
#include "stdafx.h"
#include "PrintUtil.h"
#include <objsafe.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CPrintUtilApp theApp;
const GUID CDECL BASED_CODE _tlid =
{ 0x3C8F86CA, 0x6470, 0x4B7C, { 0xB2, 0x76, 0x3B, 0xEB, 0xF, 0xB0, 0x1B, 0x4E } };
const WORD _wVerMajor = 1;
const WORD _wVerMinor = 0;
// CPrintUtilApp::InitInstance - DLL 初始化
BOOL CPrintUtilApp::InitInstance()
{
BOOL bInit = COleControlModule::InitInstance();
if (bInit)
{
// TODO: 在此添加您自己的模块初始化代码。
}
return bInit;
}
// CPrintUtilApp::ExitInstance - DLL 终止
int CPrintUtilApp::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;
}
// DllRegisterServer - 将项添加到系统注册表
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;
}
现在控件就可以在自注册时就注册为安全控件了。
2、设置项目属性 将配置类型设置成静态库(.lib)
3、最后生成项目,ocx控件就产生了。
五、 ActiveX发布步骤
在这里简单说明下,打包activeX需要制作证书,具体用到makecert 、cert2spc 、signtool 这三个VS提供的工具,工具在VS文件夹里面,以下制作过程需要在工具所在的文件夹下完成!
1、单击"开始"-->"运行(R)"-->输入"cmd"-->回车-->进入到操作的控件所在的目录(需要将上面所说的工具,和ocx控件放到一个文件夹下);
2、创建PVK文件(私人密匙文件),在命令行中输入" makecert -sk PrintUtil PrintUtil.pvk -n CN=XXXXXXX公司",然后回车;
sk-表示主题的密钥容器位置,ss-主题的证书存储名称, n-证书颁发对象,r-证书存储位置;
3、创建CER文件(公司证书),在命令行中输入" makecert -sk PrintUtil.pvk PrintUtil.cer ",然后回车,如图所示,若出现"Successed"提示,则会在C:\ PrintUtil目录下生成PrintUtil.cer文件;
sk-表示主题的密钥容器位置,is-颁发者的证书存储名称, n-证书颁发对象,ic-颁发者的证书存储位置,-$-授权范围(用于代码签名);
4、创建SPC测试软件出版商证明书,在命令行中输入" cert2spc PrintUtil.cer PrintUtil.spc ",然后回车;
5、创建INF文件,用记录本编辑以下信息:
Inf代码 收藏代码
[version]
signature="$CHINA$"
AdvancedINF=1.0
[Add.Code]
PrintUtil.ocx=PrintUtil.ocx
[PrintUtil.ocx]
file=thiscab
clsid={ 1BABEDC3-3936-4850-B79B-2417E28A5655 }
FileVersion=1,0,0,0
RegisterServer=yes
DestDir=11
6、创建CAB文件,在命令行中输入" cabarc -s 6144 n PrintUtil.cab PrintUtil.ocx PrintUtil.inf ",-s 选项表示在压缩文件中保留用于代码签名的空间,n命令指定希望创建 CAB 文件,然后回车;
7、使用Code Signing Wizard签署一个CAB文件,首先双击运行工具集里面的signcode.exe(或在命令行里直接输入“signcode”后回车),系统会弹出如图所示的数字签名向导;
8、单击"下一步(N)"按钮,选择要进行数字签名的且已做成CAB包的文件PrintUtil.cab文件;
9、选择好CAB包后单击"下一步(N)"按钮,在选择想要的签名类型里选择"自定义(C)"并单击"下一步(N)"按钮;
10、点击“从文件选择”签名证书 ( 公钥文件 ),如: PrintUtil.cer :
11、在图20中单击“下一步(N)”按钮来到下图,然后在图里选择“CSP中的私钥(K)”。
12、在上图中单击“下一步(N)”按钮,然后在下图中的散列算法中选择“shal”,并单击“下一步(N)”按钮。
13、在“证书路径中的证书”中选择“证书路径中的所有证书,包括根证书(C)”,在“其它证书(可选)”中选择“包括在以下PKCS #7 证书(.p7b)文件中的证书(P):”,并单击“浏览(R)…”按钮选择PrintUtil.spc文件,选择完后单击“下一步(N)”按钮:
14、接下来在弹出的“数据描述”窗口中输入公司的名称和网址并单击“下一步(N)”按:
15、现大部份工作都已完成,在接下来的一步当中是可选的操作,其作用只是为CAB加入时间戳,此步骤完全可以不做。
VeriSign: http://timestamp.verisign.com/scripts/timstamp.dll
Comodo: http://timestamp.comodoca.com/authenticode
GeoTrust/TrustCenter: http://www.trustcenter.de/codesigning/timestamp
16、完成
六、 运行
编写jsp页面,test.jsp
Html代码 收藏代码
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<object id="printUtil"
classid="clsid:1BABEDC3-3936-4850-B79B-2417E28A5655"
codebase="<%=basePath%>/PrintUtil.cab#version=1,0,0,0"></object>
<script type="text/javascript">
function add(arg1,args) {
try {
var v = printUtil.AddFun(arg1,args);
alert(v);
} catch (e) {
alert(e.message)
}
}
add(1,2);
</script>
</head>
<body>
</body>
</html>
运行结果:
本文所用到的工具见附件:
makeCAB.rar (188.6 KB)
========
VC6编写ActiveX控件全过程
http://www.cnblogs.com/rushoooooo/archive/2011/06/22/2087547.html
/*vc编写Activex控件全过程*/
最近在自己的项目中使用了ActiveX控件。在这里就不介绍ActiveX控件的相关知识给大家扫盲了,我们直接进入编程。
1、新建控件工程
在新建项目时,选择新建ActiveX控件,如下图所示:
VC++下的ActiveX控件编程相关
其他的基本可以选择默认属性,然后我们就可以进入自己新建的工程了,如右下图所示。方框中标出的是新建控件之后自带的三个类。我做的控件只是使用了C***Ctrl这个类,主要是设置一些与外界进行数据通信的接口的属性的,我自定义的几个属性都是在这里完成编程的。
2、为控件添加对话框
VC++下的ActiveX控件编程相关
这个控件的思想其实不是我的原创,只是项目的变化而产生的,而之前我是基于传统的上位机软件来编写这个程序的,所以就选择了向控件中加载对话框的方法。首先是设置对话框的ID,这里假设对话框的ID为IDD_XY_DLG,然后我们可以在C***Ctrl中的OnCreate() 函数中添加对话框的加载程序,具体的程序如下:
int C***Ctrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (COleControl::OnCreate(lpCreateStruct) == -1)
return -1;
dlg.Create(IDD_XY_DLG,this);
dlg.ShowWindow(SW_SHOW);
return 0;
}
对话框添加完之后,对对话框的操作与基于对话框的操作时完全一致的。所以这里没有什么好讲的。我自己的对话框的编写也基本移植的之前自己编写的上位机的程序。
3、为控件添加属性
制作控件的一个重要原因就是要提高程序的通用性,而通用性的提高必须是控件能够与第三方程序进行数据交换,这里的数据交换就是通过控件的属性来完成的。现在我们来讲一下添加属性的步骤。View->ClassWizard->Automation后进入添加界面,如下图所示:
VC++下的ActiveX控件编程相关
注意上图中红色直线标注的部分,我们是在C***Ctrl类下来进行属性的添加,做为示范,我们用两种方法分别添加两个属性。
(1)在上图中点击Add Property按钮添加新的属性名称,如下图所示。
VC++下的ActiveX控件编程相关
我们添加一个名字为xy0的float型属性,这里需要注意的是最上面的External name上填写的是控件属性的外部名称,就是第三方用户在使用你的控件时看到的属性名称,而系统会自动为你生成一个Variable name名称来关联你添加的属性的外部名称。我们在控件内部编程时只需要调用内部变量就可以了。现在我们来使用Member variable属性创建属性,这种方式不需要自己编写关联,而是系统自己为你添加。一路点击OK就可以完成属性的添加,我们可以看到在C***Ctrl类上新增了与新添加的属性相对应的程序,这个程序相当于属性值发生改变的回调函数,具体的程序如下:
void C***Ctrl::OnXy0Changed()
{
// 添加属性值发生改变后需要控件进行的相应的操作
SetModifiedFlag();
}
(2)使用Get/Set methods属性创建属性。
使用这种方法添加的属性,我们需要自己编写获取控件属性函数和改变控件属性程序。在我做的项目中,使用这种方法比较的多,我们以新建一个float型的C5属性做为例子,添加属性后,我们可以看到系统新增了两个函数——GetSC5() 和SetC5() ,对应着获取属性的值和设置属性的值,具体的程序如下:
float C***Ctrl::GetSC5()
{
// 获取C5属性相应的操作
return f0.0; //返回属性值
}
void C***Ctrl::SetC5(float newValue)
{
// 设置C5属性相应的操作
SetModifiedFlag();
}
========
VC++编写ActiveX控件
http://blog.csdn.net/waxgourd0/article/details/6637017
前言:ocx是ocx控件的扩展名,OCX 是对象类别扩充组件。如果你用过Visual Basic或者Delphi一类的可视化编程工具,那么对控件这个概念一定不会陌生,就是那些工具条上的小按钮,如EditBox,Grid,ImageBox,Timer等等。每个控件都有自己的事件、方法和属性。使用了控件的编程非常容易。首先,在程序的设计阶段可以设置一些属性,如大小,位置,标题(caption)等等;在程序运行阶段,可以更改这些属性,还可以针对不同的事件,调用不同的方法来实现对该控件的控制。控件就好像一块块的积木,程序要做的事只是将这些积木搭起来。控件的最大好处是可以重复使用,甚至可以在不同的编程语言之间使用,例如你可以在VB中嵌入用VC开发的控件。
那么下面开始详细介绍如何生成你想要的“*.ocx”文件:
1、从最简单的开始入手
1.1 如何建立Ocx工程
新建项目->MFC ActiveX WinZard
在这里解决方案的名字我取名为SIP_OCX_DEMO,点击“确定”,在出现的窗口中直接点击“完成”。VC++会自动生成一些文件,这些文件就构成了ActiveX的基本模板,文件的主要结构如下:
注意上面红框标注的文件是非常重要的部分,直接编译会在Debug目录下生成一个名为“SIP_OCX_DEMO.ocx”的控件注册文件,然后利用“regsvr32”命令就可以实现本机对此控件的注册,就可以使用本语言或者跨语言编写程序时引用此控件来实现相应的功能(当然现在没有任何功能)。
1.2 如何调试
VC++6.0自带有一个调试控件的工具“ActiveX控件测试容器”,通过三种方式可以打开:
1.点击“调试”按钮,然后浏览"C:\Program Files\Microsoft Visual Studio\Common\Tools\TSTCON32.EXE“;
2. 系统的“开始“-》“程序”-》“Microsoft Visual C++ 6.0”-》“Microsoft Visual C++ 6.0 Tools”-》“Active Control Test Container”;
3. VC++开发环境中的“工具”-》“ActiveX Control Test Container”。
但是如果编译环境是VS2005呢?VC6.0时代的第一种调试方法还是可行的,点击调试按钮,如下所示:
在上面的可执行文件名称的下拉框中有ActiveX Control Test Container的选项,选择点确定即可。当然还有别的手段,后面会提到。用上面的方法调试出下面窗口:
右击空白区域,插入控件,然后会弹出下面的对话框:
选中指定控件,点击确定,控件就被加载到此工具中,然后可以通过这个工具来看此控件的相关事件响应等等。
2、自定义方法和事件
1.点击“视图”,打开“类视图”窗口;其中App类负责启动初始化与结束时清理工作;Ctrl类是我们主要使用的;PropPage是属性类。
注意红框所示内容(以-lib结尾的文件)即为供第三方使用的借口和事件通知的接口的所在位置。
2.展开“ActiveXDemoLib”项,选中“_DActiveXDemo”项。点击鼠标右键,选择“添加”下的“添加方法”。
3.打开添加方法向导窗口。因为是添加一个无形参无返回值的测试方法,所以设置的返回类型为void,方法名设为test。
4.其它为默认设置,点击“完成”按钮完成添加方法。接下来我们打开“解决方案资源管理器”打开“SIP_OCX_DEMOCtrl.cpp”文件。
5. 打开代码视图,我们会发现VC2005已经为我们添加了一个“test”方法;
同时在.idl文件中会发现:
这里就是供第三方集成的接口列表。
3、自定义功能实现
首先为了实现这个功能,我需要一个主对话框,当IE加载这个ActiveX时会把这个对话框图显示出来。在资源视图中选择Dialog右键点击添加资源:
然后会出现如下窗口:
选择新建,在生成的属性窗口中将ID改为IDD_MAINDIALOG,同时把下面的几种属性设置一下:
Border :None
Style :Child
Visible :True
为了以后扩展的要求,加入了一个新的类“CMainDialog”类。操作:右键点一个这个对话框,然后选择“添加类“:
为了能够在Ctrl类中使用这个对话框,在SIP_OCX_DEMOCtrl.h增加一个成员变量“m_MainDialog”。
由于这个变量和对话框资源与关联,在创建控件时需要把这个对话框也创建出来。这个操作要用消息来驱动。单击SIP_OCX_DEMOCtrl,在其属性窗口中的消息窗口中有一个消息叫WM_CREATE,可以让VS2005创建一个函数OnCreate()。
在这个函数体中,添加如下代码,来创建这个对话框。
m_MainDialog.Create(IDD_MAINDIALOG, this);
这里自定义的功能是SIP的一个简单呼叫,这里不作详细说明。
4.控件的使用方法
ocx控件的安装方式有很多种,这里介绍最简单的一种。
1、进入命令行;
2、进入Ocx生成目录;
3、regsvr32.exe .ocx文件;
4、创建html文件调用本地Ocx;
由于是本地注册,打开注册表,开始 菜单 -》 运行 -》regedit -》用控件的名称SIP_OCX_DEMO查找,可以找到
可以发现其classid 的值为BFE10FBC-C682-4423-8C6E-7A38219FA064,和SIP_OCX_DEMO.ocx 文件同一路径下编辑一个 test.html文件,内容如下:
[html] view plain copy print?
<OBJECT id="SIP_OCX_DEMO" name="SIP_OCX_DEMO.ocx"
classid="clsid:BFE10FBC-C682-4423-8C6E-7A38219FA064"
width="100%" height="250">
5、保存后用IE 浏览器打开选择允许使用ActiveX 控件即可看到控件的面板;
在这里本文告一段落,关于更深入的事件和属性,以及ocx控件的安全发布的内容会另起两个章节详细说明。
以下是关于ocx安全发布的博文,欢迎指正:
ocx控件MSI打包升级方案
OCX控件CAB打包手册及升级方法
ActiveX控件实现安全的初始化和脚本
ActiveX控件属性:自定义属性的使用
========
VC++编写ActiveX控件
http://www.cnblogs.com/beer/archive/2010/08/21/1805462.html
前言:
暑假在做一个项目的时候,本来是用C#.NET来写的一个港口进出闸的流程控制程序,里面涉及一个响应用PLC的采集信息的问题(PLC用串口和工控机相连接),然后思考如何用C#写串口通讯程序,结果师兄在一旁直接用VC++写了一个“*.ocx控件”,并在自己的电脑上进行了测试,完工后就把生成的“*.ocx”控件注册文件复制到了我们的电脑上。我们就在C#.NET程序里面将此控件拖入到主窗口中,然后就能直接利用此控件的事件来捕捉PLC的命令了,感觉好神奇。然后,我对C++的态度有了极大的转变,以前只知道C++写窗口程序是多么麻烦啊(远不如C#.NET来得快和直接),而它的所谓“比较底层,和底层操作系统的关系比C#这些高级语言要密切很多”的好处一直都没有体会到,现在才知道,正是因为C++比较底层,比较基础,所以它可以开发出很多和语言无关的公用程序块,如dll动态链接库和COM组件,原则上,只要你的Windows的系统,用VC++开发出来的这些公用程序块就能被任何语言调用(如果不用MFC框架,而用ATL框架来编写,甚至还可以脱离Windwos系统,不仅仅实现跨语言,甚至跨平台调用,这个笔者就没有仔细研究了)。
本人大学本科所学本来是电子技术的工业自动化,结果中途做的几次项目都是“纯软件”,这次暑假的经历,终于让我在“硬件”和“软件”之前找到一个连接交汇点了。
image
以前做电子产品只是为了实现功能,现在发现这远远不够,按照目前的时代潮流,一个系统除了要功能完备化,还要信息化 ,信息化就涉及到数据采集、存储、分析和显示。当然如果你不是做系统的,那么你也不必去用全局的眼光去看待这个问题,但你做了电子产品后,却不能让它的功能仅仅局限于在现场完成一些自动控制,而应该开发出和设备相关的上层API,供广大的非电子专业的上层程序员进行二次开发,在PC上层平台上对数据信息进行更好的组织和处理。而提供的API最好是具有较好的移植性,以适应不同企业的不同语言的程序员。而COM组件技术很好地解决了这个问题。
说到跨语言的模块化程序设计,在本文之前发表的一篇《VC++的DLL应用(含Demo演示)》中讲了dll的创建方法,用户可以将一些公用函数放在dll源文件中,然后编译生成一个dll文件,供程序动态加载连接并调用里面的函数,这个也可以跨语言地进行调用。但dll有自己的局限性,就是没有事件,而这个时候ActiveX控件就隆重登场了,同样能够跨语言使用,ActiveX可以提供方法,属性甚至是事件(当然对比dll也有缺点,它不是单独的文件,无法动态加载和卸载)。
因为笔者现在只是学习这个技术并作为一个技术积累,而没有对这个技术进行原理上的深入研究,所以很多术语可能完全是错误的,希望高手看到后,不吝踢教和指正,也能防止本文误认“子弟”了。本文中,作者是把ActiveX,COM,OCX当作相同的概念来对待的,可能不妥,请见识,如果想细究其具体的区别,请参考文章:
《Activex、OLE、COM、OCX、DLL之间有什么区别?》
http://fykyx521.javaeye.com/blog/446275
其实不管你是否了解它们之前的区别,都无所谓,因为本文只是讲解如何从零开始学习并应用这门技术来解决实际问题,大家只需要知道实现步骤就OK了。
好,多的话不说了,下面开始介绍ActiveX这门技术的实现方式。
正文:
ActiveX这门技术是通过生成“*.ocx”文件来实现的。先来了解下OCX文件,在百度百科上面对OCX是这样解释的:
“.ocx是ocx控件的扩展名,OCX 是对象类别扩充组件。如果你用过Visual Basic或者Delphi一类的可视化编程工具,那么对控件这个概念一定不会陌生,就是那些工具条上的小按钮,如EditBox,Grid,ImageBox,Timer等等。每个控件都有自己的事件、方法和属性。使用了控件的编程非常容易。首先,在程序的设计阶段可以设置一些属性,如大小,位置,标题(caption)等等;在程序运行阶段,可以更改这些属性,还可以针对不同的事件,调用不同的方法来实现对该控件的控制。控件就好像一块块的积木,程序要做的事只是将这些积木搭起来。控件的最大好处是可以重复使用,甚至可以在不同的编程语言之间使用,例如你可以在VB中嵌入用VC开发的控件。”
里面最后一句话比较重要,就是用VC开发的OCX控件,你可以在其它语言里面都能调用,这样很好的实现了功能化组件的良好循环使用,而且还可以实现跨语言地调用(例如,你完全可以用C#调用C++开发的OCX控件)。
下面开始介绍,如何用VC++一步步生成你想要的“*.ocx”文件。
1. 建立最简单的ocx文件并进行调试
1.1 建立最简单的ocx文件
VC->新建项目->MFC ActiveX WinZard
clip_image004
一路点击“确定”,直到点击“完成”。最后VC++会自动生成一些文件,这些文件就构成了ActiveX的基本模板,文件的主要结构如下:
clip_image006
直接编译一下,然后在Debug目录下面就会生成一个名为“ocxDemo.ocx”的控件注册文件,然后利用“regsvr32”命令就可以实现本机对此控件的注册,然后就可以使用本语言或者跨语言编写程序时引用此控件来实现相应的功能(后面将会讲到)。
1.2 ocx调试方法:
VC++自带有一个调试控件的工具“ActiveX控件测试容器”,通过三种方式可以打开:
1.点击“调试”按钮,会出现如下对话框:
clip_image008
然后浏览"C:\Program Files\Microsoft Visual Studio\Common\Tools\TSTCON32.EXE“
2. 系统的“开始“-》“程序”-》“Microsoft Visual C++ 6.0”-》“Microsoft Visual C++ 6.0 Tools”-》“Active Control Test Container”
3. VC++开发环境中的“工具”-》“ActiveX Control Test Container”
通过上面的任意一种方法,都可以调出下面的程序:
clip_image010
右击空白区域,插入控件,然后会弹出下面的对话框:
clip_image012
选中指定控件,然后点击确定,控件就被加载到此工具中了,然后可以通过这个工具来看此控件的相关事件响应等等。
clip_image014
2.自VC++生成的模板基础上自定义功能
所有的自定义功能基本上都来自于“MFC ClassWizard”类向导对话框。
(“快捷键Ctrl+W”或者“查看”->“建立类向导…”)
clip_image016
在“Automation”选项卡中为控件添加方法和属性。
在“ActiveX Events”选项卡中为控件添加事件。
2.1 添加控件属性
切换到“Automation”选项卡中,点击右边的“Add Property…”会弹出对话框:
clip_image018
External name:外部名称。指此控件被使用时,外部程序看到的属性名称,仅在外部引用时被使用。
Type:属性类型。除了基本的整形等数据类型外,还有很多复杂的高级数据类型。
Variable name:变量名称。此属性在控件源文件中的变量名称,在编写控件源码时使用。
Notification function:提醒函数。当此属性被改变时,会触发此提醒函数。
Implementation:实现方式。指属性的三种类型:固有型,成员变量型,Get/Set方法型。固有型是指系统赋予的固有属性,如背景色,标题;成员变量型是用户自定义的属性;Get/Set方法型,可能是指只能通过Get/Set方法才能获取和改变的变量吧(这个没研究)。
2.2 添加控件方法
在“Automation”选项卡中,点击右边的“Add Method…”会弹出对话框:
clip_image020
External name:方法外部名称。
Internal name:方法内部名称。
Return type:返回值类型。除了基本的整形等数据类型外,还有很多复杂的高级数据类型。
Implementation:实现方式。两种:固有方法,自定义方法。
Parameter list:参数列表。参数名称和参数类型:参数类型包含很多高级数据类型。
2.3 添加控件事件
切换到“ActiveX Events”选项卡中,点击右边的“Add Event…”会弹出对话框:
clip_image022
External name:事件外部名称。
Internal name:事件内部名称。比外部名称多了个前缀“Fire”。
Implementation:实现方式。两种:固有事件,自定义事件。固有事件一般是鼠标移动,双击等等事件,这些事件都由系统消息触发;自定义事件则是完全由用户定义的一个函数,但这个函数需要用户在源文件中调用(在内部调用,对于控件的使用方来说,就相当于在调用的地方此事件被触发,而内部传入的参数,则是此事件产生的消息附带信息)。
Parameter list:参数列表。参数名称和参数类型:参数类型包含很多高级数据类型。
总述:通过“类向导”工具,为控件添加属性、方法和事件后,VC++会自动在相应的文件里面生成代码,比如内部方法属性和外部方法属性之间的映射,消息的建立,消息的声明,等等。如果用户要对引进行深入研究,还需要对程序的结构比较熟悉,知道各部分代码的作用,知道哪些地方的代码是系统自动生成的,哪些代码需要用户手动加入的。Visual C++开发环境虽然有很多优点,但有个缺点也很明显,就是代码结构比较乱,感觉没有VS2005和后面的Visual Studio系列要好。但是由于VC6.0作为一个比较经典的开发环境,而且网上的有关C++的程序设计基本上都是基于VC6.0的,所以,有必要对其进行学习,便于自己读懂网上的代码并进行消化吸收。
2.4 生成ocx文件并调试
直接编译用户加入了自定义代码的项目,然后在项目的Debug目录下面会生成一个ocx文件,这个就是此控件的注册文件了。
控件的调试工具仍然是“ActiveX Control Test Container”。
假设我们在控件中加入了一个事件:固有事件——“MouseMove”鼠标移动事件;用户自定义事件——ocxClick事件(此事件是通过“WM_MOUSEMOVE”消息来触发的,返回的是鼠标当前位置的x坐标)。
运行“ActiveX Control Test Container”并插入当前控件,当鼠标在上面移动的时候,可以看到MouseMove产生了事件了。
clip_image024
同时可以通过“Control”-》“Invoke Method”来对控件的方法进行测试,测试的方法就是你输入参数,它返回计算结果(下面以自定义的方法funHello为例)。
clip_image026
3.控件的使用方法
3.1 注册控件
ocx控件的安装方式有很多种,这里介绍最简单的一种。
步骤:
1.将需要安装的OCX控件文件复制到某个目录,例如C盘根目录下。
2.进入开始,点击运行。
3.在出现的框中键入regsvr32 C:/xxxx.ocx 。(XXXX为控件名, C:/为目录)
4.点击确认后等待出现提醒注册成功即可。
3.2 ActiveX控件的调用
ActiveX作为一种通用的COM组件,可以被不同语言调用的。
3.2.1 通过VC++调用
利用VC6.0建立一个MFC的基本对话框应用程序
clip_image028
在完成程序向导后。执行下面的步骤:
1. 执行“工程”-》“添加到工程”--》“Components and Controls…”。
2. 在弹出的文件浏览对话框中,找到Registered ActiveX Controls文件目录下的你刚才注册的控件,比如“OcxDemo Control”,然后点击“Insert”按钮即可将此控件添加到控件工具条集合中。
3. 将控件工具条上新增加的OCX控件拖入到应用程序主窗口中。
完成上面的步骤后,就可以像使用普通控件一样在VC中使用此控件了(右击此控件,可以查看此控件的“事件”和“属性”,就是你在编写控件源码时的那些“外部名称External name”)。
3.2.2 通过C#调用
其实这个才是重点,因为跨语言调用ActiveX技术最被笔者看好的地方。
用Visual Studio 2005新建一个C#.NET的Windows窗口程序,然后在工具箱面板上,右击“选择项”,选择COM组件,找到你注册的ActiveX控件:
clip_image030
确定后,那个OcxDemo Control控件就加载到工具箱里面了。可以直接拖动这个控件到C#.NET应用程序的主窗口上去了,然后就像使用普通控件那样使用此控件了。
比如,本文中的ActiveX控件的自定义事件中,是通过鼠标移动来触发,那么在应用程序中,只要鼠标移动到控件上,那么就会触发此自定义事件,并获取当前鼠标位置的橫坐标。
4. 最后一些Tip
1) 在自定义控件时,可在控件源码的OnDraw()函数中设置控件的外观(也就是控件被拖入到应用程序中时呈现的样子,一般默认是一个白色的方框内切椭圆的样式)。
2) 用C#来使用ActiveX的事件时,事件所产生的数据都包含在Event变量中,只需要用个点运算符就可以取出来了。
5.展望
控件函数的返回值类型那么多,那么复杂,如果要用得好,还需要对那些OLE数据类型进行好好学习。
========