Array of variants problem 
Author Message
 Array of variants problem

I am using array of variants as one of arguments to COM object method. In
IDL, method is defined as follows:

[id(1)] void RunSP([in] BSTR* strSPName, [in] BSTR* strConnectString, [in]
VARIANT vntParArray);

Array should be stored in variant variable, since SAFEARRAY is not the basic
IDL type.

I managed to call this method from VC client but when I use VB or VBS I get
the error message. In VB I define vntParArray as follows:

Dim vntParArray as variant
vntParArray = Array(Array("ai_id",adInteger,adParamInput,4,0),
Array("as_text",adVarChar,adParamInput,50,"test"))

Set objDB = New DBHelper    'DBHelper is my COM object
objDB.RunSP "sp_test","..connstring definition", vntParArray

When I run this program, I get the error message: "Run-time error 13 type
mismatch." in line where RunSP is called.

Does somebody have a clue what could be the problem?

I am building this object in VC/MFC (not using ATL)

Thanks,
Tvrtko



Sun, 06 Jun 2004 22:40:28 GMT  
 Array of variants problem
First, always use pointer to variant in IDL, even for [in] parameter:

void RunSP([in] VARIANT *pvarArray);

It is impossible to pack a VARIANT by value into DISPPARAMS - hence type
mismatch. BTW, you don't need extra level of indirection for [in] BSTR
parameters - just use

[id(1)] void RunSP([in] BSTR strSPName, [in] BSTR strConnectString,
    [in] VARIANT *pvntParArray);

Second, SAFEARRAY is an IDL type:

void RunSP([in] SAFEARRAY(VARIANT) *parray);

This declaration becomes SAFEARRAY **parray in C++ - note extra level of
indirection. For some reason VB does not properly handle

void RunSP([in] SAFEARRAY(VARIANT) array);

which becomes SAFEARRAY *array in C++.
--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken


Quote:
> I am using array of variants as one of arguments to COM object method.
In
> IDL, method is defined as follows:

> [id(1)] void RunSP([in] BSTR* strSPName, [in] BSTR* strConnectString,
[in]
> VARIANT vntParArray);

> Array should be stored in variant variable, since SAFEARRAY is not the
basic
> IDL type.

> I managed to call this method from VC client but when I use VB or VBS
I get
> the error message. In VB I define vntParArray as follows:

> Dim vntParArray as variant
> vntParArray = Array(Array("ai_id",adInteger,adParamInput,4,0),
> Array("as_text",adVarChar,adParamInput,50,"test"))

> Set objDB = New DBHelper    'DBHelper is my COM object
> objDB.RunSP "sp_test","..connstring definition", vntParArray

> When I run this program, I get the error message: "Run-time error 13
type
> mismatch." in line where RunSP is called.

> Does somebody have a clue what could be the problem?

> I am building this object in VC/MFC (not using ATL)

> Thanks,
> Tvrtko



Sun, 06 Jun 2004 23:03:26 GMT  
 Array of variants problem
Quote:
> First, always use pointer to variant in IDL, even for [in] parameter:

> void RunSP([in] VARIANT *pvarArray);

> It is impossible to pack a VARIANT by value into DISPPARAMS - hence type
> mismatch.

How come the methods defined in ADO library use VARIANT types for [in]
parameters, and not VARIANT*?
And unfortunately, my methods still don't work in VB. Type mismatch again,
even after I changed  VARIANT to VARIANT*.

Quote:
> Second, SAFEARRAY is an IDL type:

> void RunSP([in] SAFEARRAY(VARIANT) *parray);

Yes, but you should import objidl.idl file in object IDL file. Am I wrong?
And when I did that, I got the error message mentioning SAFEARRAY (I can't
recall the exact text, something about SAFEARRAY not being standard type).

Anyway, thanks for the prompt answer.

Tvrtko



Mon, 07 Jun 2004 00:05:43 GMT  
 Array of variants problem
I'm taking back my statement that [in] VARIANT cannot be used. It works,
but differently in early-bound and late-bound cases. In early-bound case
it contains whatever type was passed by the client. In late-bound case
it holds VT_VARIANT | VT_BYREF, and this referred-to variant holds the
actual value passed by the client. Your implementation has to deal with
both situations.

I have prepared a test project.

IDL definition is like this:
********************************************************

import "oaidl.idl";
import "ocidl.idl";
 [
  object,
  uuid(03A3BD8C-956E-4363-B140-94D87E38EC78),
  dual,
  helpstring("ITestObj Interface"),
  pointer_default(unique)
 ]
 interface ITestObj : IDispatch
 {
  [id(1), helpstring("method Test1")] HRESULT Test1([in] VARIANT var);
  [id(2), helpstring("method Test2")] HRESULT Test2([in] VARIANT *pVar);
  [id(3), helpstring("method Test3")] HRESULT Test3([in]
SAFEARRAY(VARIANT) *ppArr);
 };

Implementation is as follows:
********************************************************

STDMETHODIMP CTestObj::Test1(VARIANT var)
{
 SAFEARRAY *psa = 0;

 // Early-bound case
 if (V_ISARRAY(&var))
  psa = V_ARRAY(&var);
 // Late-bound case
 else if (V_VT(&var) == (VT_VARIANT | VT_BYREF) &&
V_ISARRAY(V_VARIANTREF(&var)))
  psa = V_ARRAY(V_VARIANTREF(&var));
 // Unexpected
 else
  ;

 TraceArray(psa);

 return S_OK;

Quote:
}

STDMETHODIMP CTestObj::Test2(VARIANT *pvar)
{
 SAFEARRAY *psa = 0;

 // Comes like this in all cases
 if (V_ISARRAY(pvar))
  psa = V_ARRAY(pvar);
 // Unexpected
 else
  ;

 TraceArray(psa);

 return S_OK;

Quote:
}

STDMETHODIMP CTestObj::Test3(SAFEARRAY **ppArr)
{
 SAFEARRAY *psa = 0;
 if (ppArr)
  psa = *ppArr;

 TraceArray(psa);

 return S_OK;

Quote:
}

void CTestObj::TraceArray(SAFEARRAY *psa)
{
 if (psa)
 {
  long lLB, lUB;
  SafeArrayGetLBound(psa, 1, &lLB);
  SafeArrayGetUBound(psa, 1, &lUB);
  ATLTRACE(_T("Got array of size %ld\n"), lUB - lLB + 1);
 }
 else
  ATLTRACE(_T("NULL array pointer"));

Quote:
}

Note how the version that accepts [in] VARIANT has to check two
different cases to extract safearray.

To test it, I've made a simple VB project with 6 buttons on a form,
doing a call to each of the three methods using early binding and late
binding. Like this:
********************************************************

Private Sub EB1_Click()

Dim vntParArray As Variant
vntParArray = Array(Array("ai_id", adInteger, adParamInput, 4, 0),
Array("as_text", adVarChar, adParamInput, 50, "test"))

Dim obj As New TestObj
obj.Test1 vntParArray

End Sub

Private Sub EB2_Click()

Dim vntParArray As Variant
vntParArray = Array(Array("ai_id", adInteger, adParamInput, 4, 0),
Array("as_text", adVarChar, adParamInput, 50, "test"))

Dim obj As New TestObj
obj.Test2 vntParArray

End Sub

Private Sub EB3_Click()

Dim vntParArray() As Variant
vntParArray = Array(Array("ai_id", adInteger, adParamInput, 4, 0),
Array("as_text", adVarChar, adParamInput, 50, "test"))

Dim obj As New TestObj
obj.Test3 vntParArray

End Sub

Private Sub LB1_Click()

Dim vntParArray As Variant
vntParArray = Array(Array("ai_id", adInteger, adParamInput, 4, 0),
Array("as_text", adVarChar, adParamInput, 50, "test"))

Dim obj As Object
Set obj = CreateObject("Test.TestObj")
obj.Test1 vntParArray

End Sub

Private Sub LB2_Click()

Dim vntParArray As Variant
vntParArray = Array(Array("ai_id", adInteger, adParamInput, 4, 0),
Array("as_text", adVarChar, adParamInput, 50, "test"))

Dim obj As Object
Set obj = CreateObject("Test.TestObj")
obj.Test2 vntParArray

End Sub

Private Sub LB3_Click()

Dim vntParArray() As Variant
vntParArray = Array(Array("ai_id", adInteger, adParamInput, 4, 0),
Array("as_text", adVarChar, adParamInput, 50, "test"))

Dim obj As Object
Set obj = CreateObject("Test.TestObj")
obj.Test3 vntParArray

End Sub

Note that for Test1 and Test2, vntParArray is Dimmed as Variant, but for
Test3 it is Dimmed as Variant(). This provides for better type safety -
the method does expect an array, not an arbitrary variant.
--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken


Quote:
> > First, always use pointer to variant in IDL, even for [in]
parameter:

> > void RunSP([in] VARIANT *pvarArray);

> > It is impossible to pack a VARIANT by value into DISPPARAMS - hence
type
> > mismatch.
> How come the methods defined in ADO library use VARIANT types for [in]
> parameters, and not VARIANT*?
> And unfortunately, my methods still don't work in VB. Type mismatch
again,
> even after I changed  VARIANT to VARIANT*.

> > Second, SAFEARRAY is an IDL type:

> > void RunSP([in] SAFEARRAY(VARIANT) *parray);
> Yes, but you should import objidl.idl file in object IDL file. Am I
wrong?
> And when I did that, I got the error message mentioning SAFEARRAY (I
can't
> recall the exact text, something about SAFEARRAY not being standard
type).

> Anyway, thanks for the prompt answer.

> Tvrtko



Mon, 07 Jun 2004 01:03:21 GMT  
 Array of variants problem
Quote:

> I have prepared a test project.

Seems to me I caused you a lot of work. But I am very grateful.

Quote:
>  else if (V_VT(&var) == (VT_VARIANT | VT_BYREF) &&
> V_ISARRAY(V_VARIANTREF(&var)))
>   psa = V_ARRAY(V_VARIANTREF(&var));

> Note how the version that accepts [in] VARIANT has to check two
> different cases to extract safearray.

I was definitely missing this part (early/late binding differences). I went
for VARIANT parameter and incorporated full early/late b. checking and IT
WORKED!
You also enlightened me in using V*** and VT_** macros defined in oleauto.h.
Thanks very much!

Quote:
> To test it, I've made a simple VB project with 6 buttons on a form,
> doing a call to each of the three methods using early binding and late
> binding. Like this:

Again, I'm amazed at the effort you made in answering my question.

Quote:
> With best wishes,
>     Igor Tandetnik

You too. If I don't pop up with some extra questions in next few days (which
is highly unlikely), I wish you all the best for coming holidays.

Tvrtko



Mon, 07 Jun 2004 17:36:25 GMT  
 
 [ 5 post ] 

 Relevant Pages 

1. How do i get size VARIANT array of VARIANTs

2. How do I convert a VARIANT array to a CString array

3. STL string to VARIANT Array (Safe Array)

4. How to pass VARIANT ARRAY to AccessibleChildren

5. - Array of Variant -

6. Sending an Array of Strings as a Variant

7. -Array of Variant -

8. Passing An Array of String or Variant

9. ActiveX - Passing variant array from VBScript & C#

10. Can't Return Array of VARIANTs in release version

11. atl object with variant array [out] parameter do not work for vbscript

12. How to handle an array of Variants?

 

 
Powered by phpBB® Forum Software