VB控件事件LPSAFEARRAY*参数的问题

fudiaoab1 2007-10-18 04:04:10
用VB简单写了个控件代码如下:
Private sMsg(0 To 1) As String
Public Event LBMouseDown(MsgArray() As String)

Private Sub UserControl_Initialize()
sMsg(0) = "1234"
sMsg(1) = "5678"
End Sub

Private Sub UserControl_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
RaiseEvent LBMouseDown(sMsg)
Cls
Print sMsg(0)
Print sMsg(1)
End Sub
---------------------------------
注:Public Event LBMouseDown(MsgArray() As String)是一个自定义的事件,
会在用户单击控件时触发,MsgArray()参数是一个字符串数组参数。目的很简单,
就是在用户的单击控件的事件里面获得sMsg字符串数组的值后并重新赋值(随便一个字符串的值)
然后Print出来

在C++Builder里面安装上控件后,在控件的LBMouseDown事件里面的MsgArray()数组会自动转化
为LPSAFEARRAY *类型的参数:
void __fastcall TForm1::TestLBMouseDown(TObject *Sender, LPSAFEARRAY *sMsg)
{

}
问题出在这里,我怎么从sMsg读出里面的字符串数组“1234”和“5678"? 我在事件处理函数里面
这样调用时
int i = sMsg[0]->cDims;
BCB里提示这样类似错误:
Access violation at address 00401BD4 in Module 'Test.exe'. Read of address 00006008
我想调用SafeArrayAccessData()来访问sMsg的时候会提示同样的错,请问这里面的sMsg在这里
不能做输出参数的吗?代码应当怎么写好?我本身对COM/ActiveX方面不熟,高手们指点指点,谢谢啦



...全文
273 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
勉励前行 2007-10-22
  • 打赏
  • 举报
回复
LPSAFEARRAY __fastcall GetMsg(void);
void __fastcall SetMsg(LPSAFEARRAY* MsgArray);
如果有這樣的接口,就可以對其讀寫了。

寫:
構造一個 SAFEARRAY 然後傳遞SetMsg , 方法參考 i_love_pc 所寫或者自行構造一個safearray也可以
讀:
LPSAFEARRAY array = GetMsg();

BSTR *pdata ;//數組地址
long L , H ;
SafeArrayAccessData(array,(void HUGEP **) &pdata);
SafeArrayGetLBound(array,1, &L);
SafeArrayGetUBound(array,1, &H);
int count = H - L ; //數組大小
對於一維數組可用:
BSTR *pdata = (BSTR*)array->pvData ; //數組地址
int count = array->rgsabound->cElements ;//數組大小

直接讀寫是不行的,因為要遵守在哪申請內存就要在哪釋放。復制導致速度比較慢。
fudiaoab1 2007-10-20
  • 打赏
  • 举报
回复
to:PPower
我觉得你说的原因并没有回答我的问题,首先,VB的DLL和OCX都是基于COM的,内部传递数组参数时就是用SAFEARRAY,
这么说吧,在VB里写两个函数(针对上面我提出的VB的例子)来实现我说的目的,
Public Function GetMsg() as String()
...
End Function

Public Function SetMsg(MsgArray() as String)
...
End Function
在BCB6里安装控件后,相应的函数变成:

LPSAFEARRAY __fastcall GetMsg(void);
void __fastcall SetMsg(LPSAFEARRAY* MsgArray);
这两个函数是可以分别对字符串数组进行读和写的,
然而我现在想问的:字符串数组作为参数在事件里传递时为什么不能读写呢?
勉励前行 2007-10-20
  • 打赏
  • 举报
回复
LPSAFEARRAY *sMsg 相當於一個 SAFEARRAY *&a;
你要傳遞的是一個字符串數組 ,問題在於 VB 中的字符串 在 其他語言中 沒有對應的數據結構,所以不能對其進行讀或寫。真要做一般也只做讀操作,很難做寫操作,除非在C++中實現一個與 VB字符串數組內存布局相同的類。

就好象用 BCB 傳遞一個 AnsiString 去給 VC 或 VB 處理一樣。或者用BCB傳遞一個vector 給delphi 處理一樣的困難。

fudiaoab1 2007-10-19
  • 打赏
  • 举报
回复
没有人看看的吗?走过路过不要错过呀
我的目的很简单:
VB控件的事件里,传递一个字符串数组过来,在BCB的事件处理代码里面能获取并修改这个字符串。
没有人碰到过这样类似的问题吗
fudiaoab1 2007-10-19
  • 打赏
  • 举报
回复
TO: truelove7283159(大头娃娃)
不行的呢,这样的代码我也试过,虽然不出错,但是字符串根本回传不回VB控件里面去
laowang2 2007-10-19
  • 打赏
  • 举报
回复
up
fudiaoab1 2007-10-19
  • 打赏
  • 举报
回复
To:i_love_pc 先谢啦 上面的代码不是我要问的啦

我要实现的是:
在VB控件里有一个字符串数组,要求客户端可以读取和修改,我想让客户端在控件的单击事件里
面能够对字符串数组进行读取和修改(返回)。

我现在的问题是:
用BCB在VB控件的单击事件里面处理代码,传递的SafeArray ** 的指针无效。当然,变
通的办法是在VB控件里面写个Get和Set的方法分别对符串数组进行读取和赋值,这样做是没有
问题的。而我想问的是,为什么在VB控件事件里面传递SafeArray做参数的时候,BCB无法获取
和修改,主要是本人对Active/COM/Atl方面不熟,故有此疑惑,是不是SafeArray不能作事件
的参数的还是有其他地方写的不对?
i_love_pc 2007-10-19
  • 打赏
  • 举报
回复
[转]

最近要用自动化组件传递字符串数组,查阅MSDN相关资料,还是觉得不够详尽。费了好大力气才调通,(也可能是水平不够,见笑)。特写下一简单实例,希望会对其他人有所帮助。



为自动化传递数组要选择VARIANT类型,在组件中创建分配内存,由COM机制来释放内存。所以COM客户在用完组件要调用SET OBJ=NULL来清内存。自动化传递的字符串是BSTR型,选用_bstr_t包装类会简单的多。



程序解释:创建数组,数组赋值,将数组传入返回值。

希望和大家交流,也请将错误指出。联系MAIL:okokex@sina.com.cn

本程序在VC6,VB6中测试通过。以下是代码:



STDMETHOD(GetArray)(/*[out]*/VARIANT* pArray);

STDMETHODIMP CRegWorker::GetArray(VARIANT *pArray)

{

AFX_MANAGE_STATE(AfxGetStaticModuleState())//选择MFC支持自动添加



int i;

_bstr_t Temp;//#include <comdef.h>,为操作BSTR简单

PCHAR ArrayBack[] = {//返回的数组,最简单的形式

"string1",

"string2",

"string3",

"string4",

"string5"

};



SAFEARRAY* psa;//定义数组描述符

SAFEARRAYBOUND bound[1] = { 5,1 }; //一维数组

psa = SafeArrayCreate ( VT_BSTR, 1, bound );//创建数组

_ASSERTE ( psa != NULL );



for( i=1;i<6;i++){

Temp = _bstr_t(ArrayBack[i-1]);

SafeArrayPutElement(psa,(long*)&i,Temp.copy());//数组赋值,必须是BSTR型

}



pArray->vt = VT_ARRAY | VT_BSTR;//VARIANT类型定义,BSTR型数组

pArray->parray = psa; //数组传入返回值



return S_OK;

}





truelove7283159 2007-10-18
  • 打赏
  • 举报
回复
LPSAFEARRAY* pAudioDeviceList = NULL;

SAFEARRAYBOUND sabound[1];
sabound[0].lLbound = 0 ;
sabound[0].cElements = lcount;
*pAudioDeviceList = SafeArrayCreate(VT_BSTR,1,sabound);

CComBSTR first = "5678"

SafeArrayPutElement(*pAudioDeviceList, &j, first);

VB 里面这样修改哈,
fudiaoab1 2007-10-18
  • 打赏
  • 举报
回复
TO: truelove7283159(大头娃娃)
不行,你的代码调用的那些函数我也调用过,都提示访问违法的错误
是不是VB里面的的写法有问题?
truelove7283159 2007-10-18
  • 打赏
  • 举报
回复
伪代码,没有调试过哦。
1 在vb那里可能要创建数组 什么的,都不会用vb了。
2 c里。

if(msg != null)
{
UINT uDim = SafeArrayGetDim(nAudioDeviceList);
long Low(-1),High(-1);
hr=SafeArrayGetLBound(nAudioDeviceList,uDim,&Low);
hr=SafeArrayGetUBound(nAudioDeviceList,uDim,&High);

long pos=0;
CComBSTR first="" ;
hr = SafeArrayGetElement(*pAudioDeviceList, &pos, &first);
if (SUCCEEDED(hr))
{
m_selectedAudioName = first;
}

}

703

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder ActiveX/COM/DCOM
社区管理员
  • ActiveX/COM/DCOM社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧