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
-