ActiveX控件的MFC设计之旅 联系客服

发布时间 : 星期四 文章ActiveX控件的MFC设计之旅更新完毕开始阅读0008256ca98271fe910ef902

sa.PtrOfIndex(lindex, (void**)&prect); m_cells[i-llb1][j-llb2].m_rect = prect; } }

sa.Unlock();

InvalidateControl(); SetModifiedFlag(); }

其实只要将Texts属性的代码拷贝过来,稍微修改一下就可以了,这里的 GUID_Lib和GUID_Rect定义在LiteGridCtrl.cpp中,如下: const GUID GUID_Lib =

{ 0x191618F9, 0xEBF9, 0x4538, { 0x9E, 0x10, 0xD9, 0xC5, 0x62, 0x7E, 0xAE, 0xA9 } }; const GUID GUID_Rect =

{ 0x6BF5EE0C, 0x373A, 0x4893, { 0x89, 0xEB, 0x2C, 0x02, 0x08, 0xD3, 0xD4, 0xEB } };

3.在VB的Form_Load中添加如下代码 Private Sub Form_Load()

Dim str(0 To 9, 0 To 9) As String Dim stro() As String Dim i As Integer Dim j As Integer For i = 0 To 9 For j = 0 To 9

str(i, j) = i & \ Next Next

LiteGrid1.Texts = str stro = LiteGrid1.Texts Dim v() As Rect Dim x As Integer Dim y As Integer x = 0 y = 0

v = LiteGrid1.Rects

For i = LBound(v) To UBound(v) y = 0

For j = LBound(v, 2) To UBound(v, 2) v(i, j).Left = x v(i, j).Top = y

v(i, j).Right = x + 40 v(i, j).bottom = y + 16 y = y + 20 Next x = x + 50

Next

LiteGrid1.Rects = v End Sub

前面的一段是上一步中的内容,也给列了出来,运行一下会发现框框没有并在一起了,分开了些,证明Rect属性的Get和Set都是调用成功了。 所以,其实还是蛮简单的

本来是想要用SafeArrayAllocDescriptor和SafeArrayAllocData来模拟 SafeArrayCreateEx的,而且事实上好象也不会出错的,SAFEARRAY的各个成员的值两种方法得到的都一样,如下: SAFEARRAY* psa = NULL;

SafeArrayAllocDescriptor(2, &psa); psa->rgsabound[0].lLbound = 0; psa->rgsabound[0].cElements = 10; psa->rgsabound[1].lLbound = 0; psa->rgsabound[1].cElements = 10; psa->cbElements = sizeof(RECT); psa->fFeatures = FADF_RECORD;

HRESULT hresult = SafeArrayAllocData(psa); if(FAILED(hresult)){

SafeArrayDestroyDescriptor(psa); return vaResult; }

可是,意外的是竟然GetRects和SetRects全都没有正确执行 然后在后面加上

SafeArraySetRecordInfo(psa, pRecInfo);

就OK了。

所以看起来似乎这个 IRecordInfo是隐藏在SAFEARRAY结构中的,具体放哪里,就不去管它了,研究这个好象也没什么意义的,如果哪位朋友碰巧熟悉这个,烦情告知一下,感谢。 差点忘了,因为这里还是用COleSafeArray来解析的,所以没用到SafeArrayGetVartype,这个函数好象也是msdn 中没有的,可以用它来判断是否是你所需要的VARTYPE,应该是比较有用的。 VARTYPE vt;

SafeArrayGetVarType(psa, &vt);

这里psa为SAFEARRAY*。

这一步很需要一些COM基础,因为没有这个基础的话,可能会有为什么要做这个,有必要吗,之类的疑问的。这回我们要看看双接口,为MFC设计的控件添加双接口(双接口是什么就不解释了)。

这里参考了msdn中的例子acdual,并且应用了例子里面的一些宏,这个例子可以直接搜索 msdn找到,还有TN065: Dual-Interface Support for OLE Automation Servers参考。 老是用一个例子,也有些腻了,咱新来一例子,TDual控件 好,开始:

1.新建MFC控件工程,这里添加了一个属性 Hello(在控件上显示Hello属性对应的字符串),一个方法SayHello,弹出一消息框,显示方法参数中的字符串。

2.改造接口, 添加第二个接口

[ uuid(C3180013-EB23-4e8f-924C-38F5A201D3D8), helpstring(\ oleautomation, dual ]

interface ITDual : IDispatch {

[propput, id(1)] HRESULT Hello([in] BSTR newText); [propget, id(1)] HRESULT Hello([out, retval] BSTR* ret); [id(2)] HRESULT SayHello(BSTR strHello); }

双接口的接口描述中必须有oleautomation和dual属性,而且接口必须派生自 IDispatch。 这里的接口定义很象ATL中的IDL定义,如果用ATL设计过控件的话,应该不陌生的,具体的规则就不罗嗦了,如果不清楚的话,请自行查找资料了,大家可以和MFC中原来的接口定义对照一下: properties:

// NOTE - ClassWizard will maintain property information here. // Use extreme caution when editing this section. //{{AFX_ODL_PROP(CTDualCtrl) [id(1)] BSTR Hello; //}}AFX_ODL_PROP methods:

// NOTE - ClassWizard will maintain method information here. // Use extreme caution when editing this section. //{{AFX_ODL_METHOD(CTDualCtrl) [id(2)] void SayHello(BSTR strHello); //}}AFX_ODL_METHOD

定义好了新的接口后,需要在coclass描述中添加新接口的一个引用,如下: [ uuid(A1E75855-8561-4416-BE49-97B4D9A228E2), helpstring(\ coclass TDual {

// [default] dispinterface _DTDual;

// [default, source] dispinterface _DTDualEvents; [default] interface ITDual;

[default, source] dispinterface _DTDualEvents; dispinterface _DTDual; };

这里将缺省的接口设置为了ITDual而不是原来的dispinterface _DTDual。

3.改造好了接口后,就要实现这个新的接口了。MFC使用嵌套类来实现一个接口,得到嵌套类的方法是使用 BEGIN_INTERFACE_PART/END_INTERFACE_PART宏对,接着具体实现嵌套类的相应接口函数(包括IUnknown和 IDispatch的接口函数)就可以了。

这里用了acdul例子中定义的BEGIN_DUAL_INTERFACE_PART和 END_DUAL_INTERFACE_PART宏对和DELEGATE_DUAL_INTERFACE宏来简化实现IUnknown和 IDispatch中的接口函数。这些宏的定义将在最后列出。

在TDualCtl.h中,#include \添加新接口PART,如下: // Event maps

//{{AFX_EVENT(CTDualCtrl) //}}AFX_EVENT

DECLARE_EVENT_MAP()

//此处为添加部分 public:

///////////////////////////////////////////////////////////////////////////// // Double Interface Part

DECLARE_INTERFACE_MAP()

BEGIN_DUAL_INTERFACE_PART(TDual, ITDual)

STDMETHOD(put_Hello)(THIS_ BSTR newText); STDMETHOD(get_Hello)(THIS_ BSTR FAR* ret); STDMETHOD(SayHello)(THIS_ BSTR strHello); END_DUAL_INTERFACE_PART(TDual)

在TDualCtl.cpp中

///////////////////////////////////////////////////////////////////////////// // Control type information

static const DWORD BASED_CODE _dwTDualOleMisc = OLEMISC_ACTIVATEWHENVISIBLE | OLEMISC_SETCLIENTSITEFIRST | OLEMISC_INSIDEOUT |

OLEMISC_CANTLINKINSIDE | OLEMISC_RECOMPOSEONRESIZE;

IMPLEMENT_OLECTLTYPE(CTDualCtrl, IDS_TDUAL, _dwTDualOleMisc)

//添加AddRef,QueryInterface等通用函数的实现 DELEGATE_DUAL_INTERFACE(CTDualCtrl, TDual) ......

//这两个函数是原来Dispatch接口分发时要用到的Hello属性和SayHello方法函数 void CTDualCtrl::OnHelloChanged() {

// TODO: Add notification handler code InvalidateControl(); SetModifiedFlag(); }

void CTDualCtrl::SayHello(LPCTSTR strHello) {

// TODO: Add your dispatch handler code here AfxMessageBox(strHello);