Trouble using COM Server that need VARIANT* from VB.NET

HiTongue Tied
I have an ATL COM Server that need to return a lot of data. To accomplish this task the COM Server use an argument of type VARIANT*.
With VB6 we haven't problems, the server works properly. Using the same componente with VB.NET we are not able to pass an Array or an Object by reference. The COM Server method fails because the data is always VT_EMPTY or is notVT_BYREF.
This is dependent from MIDL definition.

// MIDL --

[id(6), helpstring("method ResponseArray")] HRESULT ResponseArray([out] LONG* Slave, [out] LONG* Function, [out] LONG* Count, [in,out] VARIANT* TelegramData, [in] LONG WaitTime);

Server get VT_EMPTY

// MIDL --

[id(6), helpstring("method ResponseArray")] HRESULT ResponseArray([out] LONG* Slave, [out] LONG* Function, [out] LONG* Count, [out] VARIANT* TelegramData, [in] LONG WaitTime);

Server get VT_ARRAY | VT_UI1 but SAFEARRAY pointer is invalid!

In order to describe the test conditions i have also included some parts of source to describe the environment.

// Server -

STDMETHODIMP CModBusConnection::ResponseArray(LONG* Slave, LONG* Function, LONG* Count, VARIANT* TelegramData, LONG WaitTime){

if( m_pModBus == NULL )
return E_ACCESSDENIED;

if( !m_pModBus->Connected() )
r
eturn E_ABORT;

if( TelegramData == NULL ){
ATLASSERT( TelegramData != NULL );
return E_INVALIDARG;
}

if( TelegramData->vt != (VT_BYREF | VT_ARRAY | VT_UI1)) {
ATLASSERT( TelegramData->vt == (VT_BYREF | VT_ARRAY | VT_UI1) ) ;
return E_INVALIDARG;
}

long Dims = SafeArrayGetDim(*TelegramData->pparray);

if( Dims !=1 )
return E_INVALIDARG;

long LowerBounds,UpperBounds;

if( FAILED(SafeArrayGetLBound(*TelegramData->pparray,1,&LowerBounds)) )
return E_FAIL;

if( FAILED(SafeArrayGetUBound(*TelegramData->pparray,1,&UpperBounds)) )
return
E_FAIL;

if( LowerBounds <0 || UpperBounds <1024 )
return E_INVALIDARG;

....
// Client -

VB.NET CODE
PrivateSub btnReadRegisters_Click(ByVal senderAs System.Object,ByVal eAs System.EventArgs)Handles btnReadRegisters.Click

Dim RxSlaveAsLong
Dim RxFunctionAsLong
Dim RxByteCountAsLong
Dim ErrorCodeAsLong
Dim DataBuf(1024)AsByte

modbus.ResponseArray(RxSlave, RxFunction, RxByteCount, DataBuf,1000)

Any help would be appreciated.
Thanks

[5592 byte] By [r.guerzoni] at [2007-12-16]
# 1
Hi,
You need to marshal your array parameter correctly by marking it with the correct MarshalAs attribute.

See this topic for the details:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconDefaultMarshalingForArrays.asp

cmccoll_MS at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...
# 2
Thank you. Your post was very usefull for a beginner like me!
Big Smile have a nice day.
Roberto
r.guerzoni at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...
# 3
I have followed your advices but the result wasn't changed.
The problem was how .NET pass arrays, it use SAFEARRAY while VB use VARIANT.
In order to use SAFEARRAYS the MIDL should be changed in this way (for ATL)

[id(5), helpstring("method ResponseArray")] HRESULT ResponseArray([out] LONG* Slave, [out] LONG* Function, [out] LONG* Count, [in,out, satype("BYTE")] SAFEARRAY* TelegramData, [in] LONG WaitTime);

This declaration prevents the use of the COM server with VB.

Have a nice day

Roberto

r.guerzoni at 2007-9-9 > top of Msdn Tech,Visual Basic,Visual Basic General...