`

VC6 COM控件增加事件支持

阅读更多

 

前一阵子写一个控件,感觉接口有些地方使用返回值控制不大方便使用,所以打算给控件增加上几个事件,结果在网上搜了很久,也看不到合适的方法,网上说的一些东西,在我的VC环境中看的时候,根本就没有办法那么操作(包括VC6和VC2010)。于是找了一个示例程序,反反复复试验了好多次,终于自己的控件能够通过事件回调了,现在把我的试验方法记录下来。(网上说的更多是在建立控件工程时增加事件,如果对于一个建立工程时没有时间支持的控件,根本没有提到的)。

 

我的试验中提到的内容,不知道是否都是必要的,我也没有在这方面再去尝试。

 

(1)修改控件类的继承列表,如果需要有事件支持,需要继承以下的类:

 

IDispatchImpl

IProvideClassInfo2Impl

IConnectionPointContainerImpl

 

 

继承这些类,有可能还需要在 BEGIN_COM_MAP 和END_COM_MAP加入相应的宏。

加入连接点支持,需要使用 BEGIN_CONNECTION_POINT_MAP、CONNECTION_POINT_ENTRY和END_CONNECTION_POINT_MAP加入连接点的宏

 

 

 

 

 

(2)IDL中声明事件支持,在Library一节中,CoClass上面,如下方式说明:

 

    importlib("stdole32.tlb");
    importlib("stdole2.tlb");
    [
        uuid(95F04622-2670-4206-AB52-03CDE8CA8074),
        helpstring("_IMyCtrlEvents Interface")
    ]

    dispinterface _IMyCtrlEvents
    {
        properties:
        methods:
        [id(1), helpstring("method OnOK")] HRESULT OnOK();
        [id(2), helpstring("method OnError")] HRESULT OnError(LONG err,BSTR msg);
    };

 

 

 

(3)实现代理类,在其中实现触发事件的代码,例如:

 


template <class T>
class CProxy_IMyCtrlEvents : public IConnectionPointImpl<T, &DIID__IMyCtrlEvents, CComDynamicUnkArray>
{
    //Warning this class may be recreated by the wizard.
public:
    HRESULT __stdcall Fire_OnOK()
    {
        CComVariant varResult;
        T* pT = static_cast<T*>(this);
        int nConnectionIndex;
        int nConnections = m_vec.GetSize();
       
        for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
        {
            pT->Lock();
            CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
            pT->Unlock();
            IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
            if (pDispatch != NULL)
            {
                VariantClear(&varResult);
                DISPPARAMS disp = { NULL, NULL, 0, 0 };
                pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
            }
        }
        return varResult.scode;
   
    }


    HRESULT __stdcall Fire_OnError(LONG err,BSTR msg)
    {
        CComVariant varResult;
        T* pT = static_cast<T*>(this);
        int nConnectionIndex;
        int nConnections = m_vec.GetSize();
       
        for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
        {
            pT->Lock();
            CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
            pT->Unlock();
            IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
            if (pDispatch != NULL)
            {
                VariantClear(&varResult);
                //DISPPARAMS disp = { NULL, NULL, 0, 0 };
                DISPPARAMS dispparams;
               memset(&dispparams, 0, sizeof(dispparams));
               dispparams.cArgs=2;   // 设置参数个数
               dispparams.rgvarg=new VARIANTARG[1]; // 初始化参数数组
               dispparams.rgvarg[0].vt=VT_UI4; // 第一个参数的类型
               dispparams.rgvarg[0].uintVal=(UINT)err;
               dispparams.rgvarg[1].vt=VT_BSTR; // 第一个参数的类型
               dispparams.rgvarg[1].bstrVal=(BSTR)msg;              

                pDispatch->Invoke(0x2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, &varResult, NULL, NULL);
            }
        }
        return varResult.scode;
   
    }
};

 

 

 

我们可以看到,触发事件的FireEvent实现中,特殊之处在于,要把参数进行赋值,再调用定义的事件,0x1、0x2就是定义的事件。

 

 

实现之后,还需要在控件类定义处加入代理类,如(1)中需继承的其他类。

 

(4)有了这些之后,就可以在需要的地方触发事件,例如,在出现某种错误或情况时触发onError事件

 

(5)请注意,不要在控件所起的线程中触发事件,如果需要的话,请在线程中需要触发事件的地方给控件窗口(仅限控件有窗口的情况)发送自定义的消息,由控件窗口接收到消息后触发事件。要使用线程消息,需要在控件类定义时,在BEGIN_MSG_MAP和END_MSG_MAP中定义消息处理函数。

 

 

 

(6)一个题外话,控件类还应该继承 IObjectSafetyImpl,并在COM_MAP中声明宏,这样在浏览器中使用时,就不会弹出“在此页上的ActiveX控件和本页上的其它部分交互可能不安全”这样的提示。当然,要更好的解决安全问题,还需要考虑对控件数字签名等等方式。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1
0
分享到:
评论
4 楼 windshome 2013-12-04  
有十年不搞COM这东西了
3 楼 leaow567 2013-12-04  
同感同感啊
2 楼 windshome 2013-12-04  
其实多年前做COM类的开发时遇到过很多问题,很多也通过探索解决了,不过现在好像大部分都忘记了,而且忘得干干净净。所以从此遇到问题,解决之后就记录下来。
1 楼 leaow567 2013-12-03  
com成体系的资料太少了

相关推荐

    VC树控件多选

    这个“VC树控件多选”实现就是针对这种情况,提供了一个扩展的树控件类,支持节点的多选操作。 这个实现可能包括以下关键知识点: 1. **多选模式**:默认的TreeView控件不支持多选,需要通过自定义控件或扩展已有...

    vc写的多功能表格控件增加数据源

    "vc写的多功能表格控件增加数据源"这个主题聚焦于一个特定的表格控件,它是由VC++(Visual C++)编写的,并且具有增强的功能,特别是支持绑定到数据源,能够展示数据库中的内容。这一特性使得开发人员能更方便地创建...

    图片显示控件(VC6可用)

    本资源提供了一个从`CWnd`派生的图片显示控件,它专为在Visual C++ 6(VC6)环境中使用而设计,并且利用了GDI+库来实现图像的显示功能。GDI+是Microsoft Windows API的一个扩展,它提供了更高级的图形绘制功能,包括...

    VC开发实时曲线控件

    "VC开发实时曲线控件"是指利用Microsoft的MFC(Microsoft Foundation Classes)库或者ATL(Active Template Library)库来设计一个能够实时更新并显示动态数据变化的图形控件。这种控件类似于LabVIEW中的Graph控件,...

    VC各种自定义扩展控件

    扩展可能涉及增加输入验证、自动完成功能、多行文本编辑、右键菜单支持等。通过继承CEdit类并覆盖其成员函数,可以定制编辑框的行为,例如实现自定义的文本格式化、颜色高亮或者输入限制。 Progress控件通常用于...

    VC TAB 控件派生类

    6. **自定义事件**:增加了更多的回调函数,允许开发者根据需要添加自己的逻辑,比如在切换标签时触发特定的事件。 7. **多语言支持**:可能集成了多语言支持,方便国际化应用的开发。 8. **性能优化**:可能对...

    VC通用控件使用实例及详解

    6. **控件的国际化和本地化**:如何使控件支持多语言环境,包括字符串资源的管理。 7. **控件的扩展**:利用MFC的派生机制,你可以创建自己的控件类,增加新的功能或优化已有功能。 在"VC通用控件使用实例"部分,...

    vc6.0改变控件颜色、形状

    在Windows编程领域,Visual C++ 6.0...总结来说,VC6.0中改变控件颜色和形状主要依赖于MFC库、代码绘制以及可能的第三方库支持。熟练掌握这些技术,能够帮助你创建出独特且吸引人的用户界面,提高应用程序的用户体验。

    VC树形控件制作的鄱阳湖看图程序

    总的来说,“VC树形控件制作的鄱阳湖看图程序”涵盖了Windows桌面应用开发的基础知识,包括UI设计、事件处理、资源管理、文件操作等多个方面,是一个学习和实践VC++编程的好案例。通过深入研究这个程序,开发者可以...

    VC6增加皮肤

    在VC6中,我们需要引入第三方库来支持皮肤功能,因为原生的MFC(Microsoft Foundation Classes)框架并不直接支持皮肤化。 常见的皮肤库有如AlloySkin、eXtreme Skin Engine、Snowy Night等,这些库提供API接口,...

    VC控件相关的一些代码

    6. **SuperGrid** 和 **QuickList**: 这些是第三方库提供的高级网格控件,提供了更多的自定义选项和功能,如单元格合并、颜色定制、行/列拖动等,能够更好地满足复杂界面的需求。 7. **ReportCtrl**: 报表控件通常...

    制作VC表格控件

    ### 制作VC表格控件 在开发基于数据库的应用程序时,经常需要...例如,可以通过增加滚动条支持更大的数据集,或者添加排序功能提高用户体验等。希望本文能够帮助你在VC开发过程中更加得心应手地处理表格数据展示问题。

    VC 鼠标悬停控件,漂亮的泡泡提示

    6. **响应机制**:除了消息处理外,还可以通过重载OnMouseMove成员函数来检测鼠标的位置,当鼠标在控件范围内时显示提示,否则隐藏。 7. **布局与定位**:为了使泡泡提示在屏幕上的位置合理,可能需要计算提示框相...

    web Office vc写的 控件 源码

    6. **定制与扩展**:由于提供了源码,开发者可以根据实际需求对控件进行修改和扩展,例如增加新的功能,优化性能,或者调整用户界面以适应特定应用场景。 7. **嵌入与集成**:控件的使用方式是“拉一拉”即可,这...

    VC 在窗体上动态添加文本框、标签及按钮控件.rar

    一个支持事件响应 保存 读取的VC 动态控件应用示例,可以在窗体上动态添加文本框、标签及按钮控件,可以循环的添加下去,每点击一次添加按钮,就会动态添加一个控件对象,如演示截图所示的运行窗口,动态控件可被...

    VC 自定义时间轴控件

    以上是关于"VC 自定义时间轴控件"的一些核心知识点,实际开发中可能还会涉及到更多的细节和技术,例如性能优化、多线程更新、国际化支持等。通过对这些技术的掌握和应用,可以创建出功能强大且用户友好的时间轴控件...

    VC 增强版TreeList树形列表控件.rar_Treelist控件_VC树形控件_treeListCtl_treelist_

    在这个“VC增强版TreeList树形列表控件”中,开发者可能已经对其进行了优化,增加了更多的功能和更好的性能,使其更适合复杂的项目需求。 在描述中提到的“好用的treelistctl”,这表明这个控件在易用性和功能上都...

    vc中为列表控件listctrl增加列行的内容

    本文将详细讲解如何在VC中为列表控件ListCtrl增加列和行的内容。 首先,我们需要了解CListCtrl的基本用法。在创建CListCtrl对象后,通常需要设置其风格,例如LVS_REPORT,这使得列表控件以报告视图显示,支持多列和...

    VC上用的曲线控件(多个)

    随着跨平台开发的需求增加,选择支持Windows、Linux甚至移动端的曲线控件会提高应用的可移植性。 总之,"VC上用的曲线控件(多个)"集合提供了多样化的曲线绘制解决方案,涵盖了从基本的2D图表到复杂的工业级图表...

Global site tag (gtag.js) - Google Analytics