这一步本来要往上走的,因为感觉上面还有很多风景,可是一次意外,发现我的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,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*。
原文链接:https://www.f2er.com/vb/260931.html开始之前,先推荐一文章
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,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*。