Помогите, нужно передать массив UDT из VB-клиента в ATL-EXE-сервер, нихрена неработает (использовал SAFEARRAY** , VARIANT* ), а в DLL-cервер все передается.
В idl-файле описал свою UDT-структуру. Скомпилировал и зарегестрировал Proxy/Stub.
В VB
dim s(10) as MyUdt
MyAtlExe.SendData s() 'В этом месте отладчик отладчик выдает MessageBox с ошибкой
429 и говорит что не может создать объект.
Здравствуйте VladD2, Вы писали:
VD>1. Proxy/Stub не нужне и даже вреден.
VD>2. Не "MyAtlExe.SendData s()", а "MyAtlExe.SendData s"
VD>3. Массив лучше обявлять динамически:
VD>VD>dim s() as MyUdt
VD>ReDim s(0 to 10)
VD>
VD>4. В статье http://www.rsdn.ru/article/?com/COMvs.xmlАвтор(ы): Чистяков В.Ю.
Эта статья входит в цикл "COM vs. CORBA" и знакомит читателя с основами COM, начиная с интерфейса IUnknown
и заканчивая маршалингом, DCOM и COM+.
дан пример того как это делается.
VD>5. Покажи свое описание (idl) и реализащие метода SendData (ну, и самого интерфейса).
Спасибо, что откликнулись на мой вопрос.
1. Я читал вашу статью, очень полезная. Я хочу пометить что у меня EXE-сервер, может в этом какая-то особенность.
2. Вот мой idl (вроде также как у вас в стотье)
typedef
[
uuid(C21871A0-33EB-11D4-A13A-BE2573A1120F), version(1.0),
helpstring("A UDT variable for VB projects")
]
struct UDTVariable {
BSTR Name;
long Value;
} UDTVariable;
[
object,
uuid(BAFDFAB1-71F9-11D5-A9D2-00A024F25C30),
dual,//oleautomation,//
helpstring("ICoolMsgHandler Interface"),
pointer_default(unique)
]
interface ICoolMsgHandler : IDispatch//IUnknown//
{
.....
[id(3), helpstring("method SendConditionArrays")] HRESULT SendConditionArrays(VARIANT *StateArray, VARIANT *KeyArray, [out, retval] VARIANT_BOOL* bResult);
[id(4), helpstring("method SendData")] HRESULT SendData([in] SAFEARRAY(UDTVariable)* StateArr);
[id(5), helpstring("method M")] HRESULT M([in] long len, [in, size_is(len)] UDTVariable* ssa);
};
-при вызове 4-ой функции из VB возникает ошибка Run-time error 429, ActiveX component cannot create object, при отладке в VC проекте ставил точку останова на самое начало функции но туда управление не дошло, сообщение об ошибке возникало раньше;
-с 5-ой функцией все в порядке (работает если зарегестрировать Proxy/Stub );
-так как 4-ая функция не работает то я попробовал передавать отдельно массив long и BSTR, используя
VARIANT (функция — SendConditionArrays ) здесь все нормально;
3. С++ описания
STDMETHOD(M)(/*[in]*/ long len, /*[in, size_is(len)]*/ UDTVariable* ssa);
STDMETHOD(SendData)(/*[in]*/ SAFEARRAY** StateArr);
STDMETHOD(SendConditionArrays)(VARIANT *StateArray, VARIANT *KeyArray, VARIANT_BOOL* bResult);
......
STDMETHODIMP CCoolMsgHandler::SendConditionArrays(VARIANT *StateArray, VARIANT *KeyArray, VARIANT_BOOL *bResult)
{
long i;
SAFEARRAY FAR* psa = NULL;
SAFEARRAY FAR* pka = NULL;
BSTR HUGEP *pKey;
DWORD HUGEP *pState;
HRESULT hr;
//DWORD dwTimeStart;
LONG cElements, lLBound, lUBound;
// Type check VARIANT parameter. It should contain a BSTR array
// passed by reference. The array must be passed by reference it is
// an in-out-parameter.
if (V_VT(KeyArray) != (VT_ARRAY | VT_BSTR))
return E_INVALIDARG;
if (V_VT(StateArray) != (VT_ARRAY | VT_I4))
return E_INVALIDARG;
psa = V_ARRAY(StateArray);
pka = V_ARRAY(KeyArray);
// Check dimensions of the array.
if (SafeArrayGetDim(psa) != 1)
return E_INVALIDARG;
if (SafeArrayGetDim(pka) != 1)
return E_INVALIDARG;
//dwTimeStart = GetTickCount();
// Get array bounds.
hr = SafeArrayGetLBound(psa, 1, &lLBound);
if (FAILED(hr))
goto error;
hr = SafeArrayGetUBound(psa, 1, &lUBound);
if (FAILED(hr))
goto error;
// Get a pointer to the elements of the array.
hr = SafeArrayAccessData(psa, (void HUGEP* FAR*)&pState);
if (FAILED(hr))
goto error;
hr = SafeArrayAccessData(pka, (void HUGEP* FAR*)&pKey);
if (FAILED(hr))
goto error;
cElements = lUBound-lLBound+1;
........
hr = SafeArrayUnaccessData(pka);
if (FAILED(hr))
goto error;
hr = SafeArrayUnaccessData(psa);
if (FAILED(hr))
goto error;
return S_OK;
error:
return 0;
}
STDMETHODIMP CCoolMsgHandler::SendData(SAFEARRAY **StateArr)
{
.....
return S_OK;
}
STDMETHODIMP CCoolMsgHandler::M(long len, UDTVariable *ssa)
{
.....
return S_OK;
}
4. Вот VB вызовы
////////////////////////////////////////////////////////////////////
Private Sub Command2_Click()
Dim s() As UDTVariable
n = GetTickCount()
i = MsgHndlrInQElCol.Count
If i > 0 Then
ReDim s(i — 1) As UDTVariable
While i > 0
s(i — 1).lState = i
s(i — 1).sKey = "str" + Format(i)
i = i — 1
Wend
MyAtlExe.m MsgHndlrInQElCol.Count, s(0) // работает если зарегестрировать Proxy/Stub
Set MsgHndlrInQElCol = Nothing
End If
m = GetTickCount() — n
Text2.Text = Format(m)
End Sub
////////////////////////////////////////////////////////////////////
Private Sub Command3_Click()
Dim s() As UDTVariable
n = GetTickCount()
i = MsgHndlrInQElCol.Count
If i > 0 Then
ReDim s(i — 1) As UDTVariable
While i > 0
s(i — 1).lState = i
s(i — 1).sKey = "str" + Format(i)
i = i — 1
Wend
Set MsgHndlrInQElCol = Nothing
MyAtlExe.SendData s //возникает ошибка Run-time error 429, ActiveX component cannot create object;
End If
m = GetTickCount() — n
Text3.Text = Format(m)
End Sub
////////////////////////////////////////////////////////////////////
Private Sub Command6_Click()
Dim k As Variant
Dim s As Variant
n = GetTickCount()
i = MsgHndlrInQElCol.Count
If i > 0 Then
ReDim k(i — 1) As String
ReDim s(i — 1) As Long
While i > 0
s(i — 1) = i
k(i — 1) = "str" + Format(i)
MsgHndlrInQElCol.Remove i
i = i — 1
Wend
MyAtlExe.SendConditionArrays s, k //здесь все нормально
End If
m = GetTickCount() — n
Text4.Text = Format(m)
End Sub