zoukankan      html  css  js  c++  java
  • activeX 开发

    转自 (http://www.cnblogs.com/chinadhf/archive/2010/09/03/1817336.html),并且在开发过程中遇到的问题进行了补充说明,让新手少走弯路

    本文描述了使用ATL开发一个ActiveX控件的完整过程。

    一、创建项目

    单击起始页中的“New Project…”,选择“ATL”分类下的“ATL Project”项目,项目名称为“Calculator”。在随后出现的项目向导中,使用默认配置即可。

    image

    二、添加控件

    在解决方案管理器中的项目上右击,依次选择“Add”、“Class”,在添加类对话框中选择ATL分类下的ATL Control类型。单击“Add”按钮,将会出现添加ATL Control向导。

    image 

    image

    在向导的第二步中,将接口类型选择为“Dual”,为控件支持事件做为准备,在Support选项中,选中“Connection points”复选框。

    随后出现选择控件要实现的接口的界面,除VS默认添加的实现外,再添加IObjectSafety接口,实现该接口可以避免控件在IE中使用时IE弹出运行的脚本不安全的提示。

    image

    三、为控件添加并实现方法

    在Class View窗口中右击ICalc接口,依次选择“Add”、“Add Method…”,此处假定我们实现一个加法运算,将方法命名为“Add”,然后添加参数:

    image

    需要注意的是对返回值的处理。应将参数类型选定为DOUBLE*,并选中“retval”复选框。

    向导结束后,VS自动在Calc.cpp中添加了该方法的空实现,略加修改后的方法代码为:

    STDMETHODIMP CCalc::Add(DOUBLE a, DOUBLE b, DOUBLE* result)
    {
    	*result = a + b;
    
    	return S_OK;
    }

    测试该方法:

    由于只是调用该控件进行加法运算,并不需要该控件的界面展示,因此在测试控件之前,可以将VS自动生成的OnDraw方法中的其他代码删除,直接返回 S_OK 即可。

    对VS自动生成的用于测试的htm略做修改来测试添加的方法。修改后的完整htm代码如下:

    <HTML><HEAD><TITLE>ATL 8.0 test page for object Calc</TITLE></HEAD><BODY><OBJECTID="Calc"CLASSID="CLSID:59443E6F-7B99-4F75-A7AF-6FEE5B8208CD"></OBJECT><inputtype="button"value="Add"onclick="add();"/><scripttype="text/javascript">
        function add() {
            var calc = document.getElementById('Calc');
            var result = calc.Add(2, 3);
            alert(result);
        }
    </script></BODY></HTML>

    点击“Add”按钮后的运行效果:

    image

    四、为控件添加事件

    假定控件进行的是一个非常复杂的运算,为了在调用运算时不阻塞调用者线程,可以使用异步方式完成运算。控件在完成运算时需要通知调用者,这时便需要事件。

    首先按照步骤三中的方法,添加一个异步调用加法运算的方法AddAsync,然后为控件添加运算完成的事件AddCompleted。

    在Class View窗口中右击_ICalcEvents接口,依次选择“Add”、“Add Method…”,根据添加方法向导添加AddCompleted方法,如下图所示:

    -----------------------------------------------------------------------
    在2013中添加事件时,可能会出错,请在源文件->.ldl 中添加
    dispinterface _IwebAXFingerEvents
    
    	{
    
    		properties:
    
    		methods:
    
    			[id(1)] void xxxx(char xxx);
    //事件
    
    
    	};
    然后点右键编译该文件

    image

    然后在Class View窗口中右击CCalc类,依次选择“Add”、“Add Connection Point…”,在弹出的实现连接点窗口中实现_ICalcEvents接口。

    image

    完成向导后,VS会自动为我们生成基本框架,包括引发事件的方法Fire_AddCompleted。我们只需在AddAsync方法中添加运算并在运算结束时调用Fire_AddCompleted的代码:

    STDMETHODIMP CCalc::AddAsync(DOUBLE a, DOUBLE b)
    {
    	double result;
    	result = a + b;
    	Fire_AddCompleted(&result);
    
    	return S_OK;
    }

    在网页中添加异步计算的代码进行测试(添加的javascript代码如下),应该能够得到我们想要的效果。

    <script type="text/javascript">
        function addAsync() {
            var calc = document.getElementById('Calc');
            calc.attachEvent("AddCompleted", OnAddCompleted);
            calc.AddAsync(3, 4);
        }
    
        function OnAddCompleted(result) {
            alert(result);
        }
    </script>

    五、ActiveX控件的事件与多线程

    细心的读者一定会发现步骤四中所谓的“异步”是假的:虽然在运算结束后使用事件对调用者进行通知,但由于运算是在主线程上进行的,所以调用过程仍是同步的。步骤四其实只是展示了一下事件的简单用法,如果真正实现异步,则需要在控件中使用多线程。

    在ActiveX控件中使用多线程时需要注意的是:引发事件(即调用Fire_XXXX)必须在窗口线程中进行,否则会导致事件不能被ActiveX控件的容器处理。如果事件发生时执行代码的线程不是窗口线程。那么应该使用PostMessage或SendMessage来通知窗口线程,并在消息处理函数中执行Fire_XXXX。为了使用控件的消息机制,还应该在CCalc的构造函数中将m_bWindowOnly字段设置为TRUE。

    以下是改为多线程后的部分示例代码:

    STDMETHODIMP CCalc::AddAsync(DOUBLE a, DOUBLE b)
    {
    	m_a = a;
    	m_b = b;
    
    	_beginthreadex(NULL, NULL, AddMethod, this, NULL, NULL);
    
    	return S_OK;
    }
    
    unsigned __stdcall CCalc::AddMethod(LPVOID arg)
    {
    	CCalc* pThis = (CCalc*)arg;
    	pThis->m_result = pThis->m_a + pThis->m_b;
    
    	pThis->SendMessage(WM_ADDCOMPLETED);return 0;
    }
    
    LRESULT CCalc::OnAddCompleted(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
    {
    	Fire_AddCompleted(&m_result);
    
    	return 0;
    }

    至此,一个简单的ActiveX控件就开发完成了。关于ActiveX控件的打包部署等问题,可以参考以下内容:

    1、Web发布cab文件打包的ActiveX控件总结

    2、ActiveX控件打包成Cab置于网页中自动下载安装

    3、VS2005下MFC开发的ActiveX控件的部分总结

    本文示例所使用的开发环境为Visual Studio 2010。

    附:使用VC6开发时的注意事项

    在今天看来,VC6显得有些古老,但由于目前能见到的大多数版本的Windows操作系统已经内置了运行VC6开发的应用程序所需要的库,因此从方便发布的角度看,使用VC6来开发ActiveX控件不失为一个好的选择。

    使用VC6开发ActiveX控件与上文所述步骤大同小异,但是需要注意微软给开发者留下的两道试题--使用VC6向导生成的代码中包含两处错误:

    第一处错误位于连接点映射,DIID__IXXXXEvents中的第一个字符‘D’需手动添加。

    示例代码:

    BEGIN_CONNECTION_POINT_MAP(CCalc)
    	CONNECTION_POINT_ENTRY(DIID__ICalcEvents)	// 修改 IID_XXXX 为 DIID_XXXX
    END_CONNECTION_POINT_MAP()

    该错误会造成生成失败,比较容易发现。

    第二处错误位于Fire_XXXX方法内,不会造成生成失败但会造成运行结果莫名其妙,因此该错误更隐蔽一些。

    示例代码:

    if (pConnection)
    {
      CComVariant avarParams[1];
      avarParams[0].byref = result;    //此处自动生成的代码有错误,应去掉原代码中的取址运算
      avarParams[0].vt = VT_R8|VT_BYREF;
      CComVariant varResult;
    
      //...
    }
    
    
    ----------------------------------------------------------------------
    pThis->SendMessage(WM_ADDCOMPLETED);
    WM_ADDCOMPLETED是用户自定义的消息
    static const UINT WM_ADDCOMPLETED = WM_APP + 101;//定义WM_ADDCOMPLETED消息
    MESSAGE_HANDLER(WM_ADDCOMPLETED, OnAddCompleted)//绑定事件,在发送消息是触发
    ------------------------------------------------------------------------------
    char 转bstr
                            char temp1[1024];
    
    			hex2visiblec(_finerstr, temp1, 497);
    
    			char temp2[30];
    
    			hex2visiblec(_deviceid, temp2, 10);
    
    			BSTR xxx= _com_util::ConvertStringToBSTR(temp1);
    
    			BSTR xxx1 = _com_util::ConvertStringToBSTR(temp2);

    注意应该调用dll,应该放在windwos/system32/

  • 相关阅读:
    Codeforces Round #251 (Div. 2) A
    topcoder SRM 623 DIV2 CatAndRat
    topcoder SRM 623 DIV2 CatchTheBeatEasy
    topcoder SRM 622 DIV2 FibonacciDiv2
    topcoder SRM 622 DIV2 BoxesDiv2
    Leetcode Linked List Cycle II
    leetcode Linked List Cycle
    Leetcode Search Insert Position
    关于vim插件
    Codeforces Round #248 (Div. 2) B. Kuriyama Mirai's Stones
  • 原文地址:https://www.cnblogs.com/weiwin/p/4493813.html
Copyright © 2011-2022 走看看