ActiveX控件的MFC设计之旅-第6步

    技术2022-05-11  131

    这一步本来要往上走的,因为感觉上面还有很多风景,可是一次意外,发现我的msdn竟然无法找到网上流行的SafeArrayCreateEx这个函数,大感意外,因此就决定继续横爬了,来看看怎么用SAFEARRAY包装自定义结构了。 开始之前,先推荐一文章 VB真是想不到系列之四:VB指针葵花宝典之SafeArray网址就不提供了,网上搜搜就找到了,绝对不是做广告的,只是觉得挺有意思的,从VB的眼光来看SAFEARRAY。 很显然COleSafeArray并没有封装SafeArrayCreateEx函数,所以这回咱直接用API了。 1.为CLiteGridCtrl添加上Rects属性,VARIANT类型,还是用Get/Set methods吧,这个属性功能就不用多说了,为我们所有的CCell设置和返回m_rect成员。 2.实现Rects属性 VARIANT CLiteGridCtrl::GetRects() {     VARIANT vaResult;     VariantInit(&vaResult);     // TODO: Add your property handler here     IRecordInfo* pRecInfo = NULL;     GetRecordInfoFromGuids(GUID_Lib, 1, 0, LOCALE_USER_DEFAULT, GUID_Rect, &pRecInfo);     SAFEARRAYBOUND sab[2];     sab[0].cElements = 10;     sab[0].lLbound = 0;     sab[1].cElements = 10;     sab[1].lLbound = 0;     SAFEARRAY* psa = SafeArrayCreateEx(VT_RECORD, 2, sab, pRecInfo);     long lindex[2] = {0};     RECT* prect = NULL;     SafeArrayLock(psa);     for(int i=0; i<10; i++){         lindex[0] = i;         for(int j=0; j<10; j++){             lindex[1] = j;             SafeArrayPtrOfIndex(psa, lindex, (void**)&prect);             *prect = m_cells[i][j].m_rect;         }     }     SafeArrayUnlock(psa);     vaResult.vt = VT_ARRAY | VT_RECORD;     vaResult.pRecInfo = pRecInfo;     vaResult.parray = psa;     return vaResult; } void CLiteGridCtrl::SetRects(const VARIANT FAR& newValue) {     // TODO: Add your property handler here     COleSafeArray sa(newValue);     ASSERT(sa.GetDim() == 2);     long llb1 = 0;     long lub1 = 0;     long llb2 = 0;     long lub2 = 0;     long l1 = 0;     long l2 = 0;     sa.GetLBound(1, &llb1);     sa.GetUBound(1, &lub1);     l1 = lub1-llb1+1;     ASSERT(l1 == 10);     sa.GetLBound(2, &llb2);     sa.GetUBound(2, &lub2);     l2 = lub2-llb2+1;     ASSERT(l2 == 10);     long lindex[2] = {0};     RECT* prect = NULL;     sa.Lock();     for(int i=llb1; i<=lub1; i++){         lindex[0] = i;         for(int j=llb2; j<=lub2; j++){             lindex[1] = j;             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 & " : " & j     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*。

    最新回复(0)