Board index » Visual Studio » [VC6] Passing Visual Basic 6 arrays via SAFEARRAY

[VC6] Passing Visual Basic 6 arrays via SAFEARRAY

Visual Studio378
Hi,



I'd like a VB6 app to pass an array of floats to an MFC dialog-based OLE

Automation server (developed in VC6).



I'd like to use SAFEARRAY to have more robust code and type-checking, but

I see no support by ClassWizard...



The only thing I managed to do has been to use VARIANT *.

Then, in the C++ method, I "cast" the VARIANT to SAFEARRAY, and use its

pointer to elements.



On the VB6 side, instead, I cast the array to variant.



<CODE lang="VB6">

Dim arrValues(10) as Single

Dim varValues as Variant



' process arrValues

...



' Pass it so C++ server, after casting to Variant

varValues = arrValues()

myObject.MyMethod varValues



</CODE>



I hope there's a better way to do this thing...specifying SAFEARRAY * as

input parameter for my C++ server method.



T.I.A. for any help/suggestion.

Dan


-
 

Re:[VC6] Passing Visual Basic 6 arrays via SAFEARRAY

Hi Danguard,



The limiting factor are the OLE marshalling routines. Although you

can coerce your automation server into compiling with what you are

looking for, COM/DCOM/OLE will not understand it.



For example:



// doc.cpp

long CSafeArrayDoc::TestSingle(SAFEARRAY **pFloat) { return 0;}



// doc.h

afx_msg long TestSingle(SAFEARRAY **pFloat);



// In the ODL file

[id(1)] long TestSingle(SAFEARRAY(float) *pFloat);



You can compile this, then run it once so that it will register

itself. Then looking at this thing in the VB6 object browser after

setting a project reference to the .TLB file you see the tantalizing

desired prototype:



Function TestSingle(pFloat() As Single) As Long

Member of SafeArray.Document



But this will throw a runtime error at the point where you call the

method as the OLE code pukes on it. Also, the parsers for the ODL

file will refuse to let you add more methods via the wizard in the C++

program because it too knows that the variable type cannot be

marshalled.



The correct solution is as you guessed, but you can still get type

safety. The code to properly type-check your variant is as follows:





// doc.h

afx_msg long TestSingle(const VARIANT FAR& pFloat);



// In the ODL file

[id(1)] long TestSingle(VARIANT pFloat);



// doc.cpp

long CSafeArrayDoc::TestSingle(const VARIANT FAR& pFloat)

{

long rc = 0;



if (pFloat.vt != (VT_BYREF|VT_VARIANT)) {

// Not the type we want

rc = -3;



} else {



// Dereference the pointer to VARIANT

VARIANT * pvar = pFloat.pvarVal;



if (pvar->vt != (VT_ARRAY|VT_R4)) {

// We only take an array of Single/float

rc = -9;

} else {



// Get the pointer to the array

SAFEARRAY * psa = pvar->parray;

if (psa) {



// Verify array dimensions

UINT dimensions = ::SafeArrayGetDim(psa);



if (dimensions == 1) {

long lBound;

long uBound;

HRESULT hresult1;

HRESULT hresult2;



// Verify that the SafeArray is the proper shape.

hresult1 = SafeArrayGetLBound(psa, 1, &lBound);

hresult2 = SafeArrayGetUBound(psa, 1, &uBound);



if (FAILED(hresult1) || FAILED(hresult2)) {

// Need upper and lower bounds

rc = -7;



} else {

// Compute the number of elements in the array

long count = uBound - lBound + 1;

float * pData = (float*)malloc(count * sizeof(float));

int p;

float * floatArray;



// Lock down the array

SafeArrayAccessData(psa, (void**)&floatArray);



// Copy the array

for (p = 0; p < count; p++) {

pData[p] = floatArray[p];

}



// Unlock the array again

SafeArrayUnaccessData(psa);



// Now you can go crazy with your type safe input



Simple, right? :)



Hope that helps,



- Kurt



On Tue, 07 Jun 2005 22:27:06 GMT, "Danguard"

<danguard_robot@see.signat.com>wrote:



Quote
Hi,



I'd like a VB6 app to pass an array of floats to an MFC dialog-based OLE

Automation server (developed in VC6).



I'd like to use SAFEARRAY to have more robust code and type-checking, but

I see no support by ClassWizard...



The only thing I managed to do has been to use VARIANT *.

Then, in the C++ method, I "cast" the VARIANT to SAFEARRAY, and use its

pointer to elements.



On the VB6 side, instead, I cast the array to variant.



<CODE lang="VB6">

Dim arrValues(10) as Single

Dim varValues as Variant



' process arrValues

...



' Pass it so C++ server, after casting to Variant

varValues = arrValues()

myObject.MyMethod varValues



</CODE>



I hope there's a better way to do this thing...specifying SAFEARRAY * as

input parameter for my C++ server method.



T.I.A. for any help/suggestion.

Dan



-

Re:[VC6] Passing Visual Basic 6 arrays via SAFEARRAY

Il Wed, 08 Jun 2005 12:26:46 -0500, Kurt Grittner ha scritto:



Quote
[CUT... Very useful and interesting code]

// Now you can go crazy with your type safe input



Simple, right? :)



Hope that helps,



Thank you very much, Kurt.



Ciao

Dan



-