Accessing Safearray of Safearrays in C++ 
Author Message
 Accessing Safearray of Safearrays in C++

 I am new to variants and safearrays in C++ and I am attempting to
write a C++ method that accepts a variant from a VB client which
contains a safearray of safearrays of variant.
I get compiler errors whenever I use the [] operater on either parray.

What is the proper way to do such a thing in C++?

Get this error on all code that uses [].
error C2039: 'parray' : is not a member of 'tagSAFEARRAY'

Below are snippets of client and an attempt at server code.

Server code:
// Internal helper method in C++ to unpackage safearry elements into
parameter objects
// Called internally from RunSPReturnInteger() which is called by
client.
void CDBWrapper::AddParameters(_CommandPtr& a_command, _variant_t&
array_of_params)
{
        long array_lbound, array_ubound = 0;
        long param_lbound, param_ubound = 0;
        SAFEARRAY *pSa;
        _variant_t param_array;

        if(array_of_params.vt == (VT_ARRAY | VT_VARIANT))
        {
                try{
                        // Get the bounds of the outer safearray
                        TESTHR(SafeArrayGetLBound
(array_of_params.parray,1,&array_lbound));
                        TESTHR(SafeArrayGetUBound
(array_of_params.parray,1,&array_ubound));

                        while(array_lbound < array_ubound)
                        {

                                // Get the bounds of the inner safearray
                                TESTHR(SafeArrayGetLBound
(array_of_params.parray[array_lbound].parray,1,&param_lbound));
                                TESTHR(SafeArrayGetUBound
(array_of_params.parray[array_lbound].parray,1,&param_ubound));
                                // Check for null
                                if (param_ubound - param_lbound == 3)
                                {
                                        if(array_of_params.parray
[array_lbound].parray[3].vt == VT_BSTR) then
                                        {
                                                _bstr_t a_param
(array_of_params.parray[array_lbound].parray[3].&vElement,false);

                                        }

                                a_command->Parameters->Append(a_command-

Quote:
>CreateParameter(array_of_params.parray[array_lbound].parray[0], .parray

[array_lbound].parray[1], adParamInput, .parray[array_lbound].parray
[2], a_param));
                                array_lbound++;
                                }
                        }
                }
                catch (_com_error &e)
                {
                        printf("Error:\n");
                        printf("Code = %08lx\n", e.Error());
                        printf("Code meaning = %s\n", (char*)
e.ErrorMessage());
                        printf("Source = %s\n", (char*) e.Source());
                        printf("Description = %s\n", (char*)
e.Description());
                }

        }

Quote:
}

Snippet of VB Client code:
Public Function mp(ByVal PName As String, ByVal PType As
ADODB.DataTypeEnum, ByVal PSize As Long, ByVal PValue As Variant)
    mp = Array(PName, PType, PSize, PValue)
End Function

    dim m_dbh as dbWrapper
    Dim x As Variant

    x = m_dbh.RunSPReturnInteger("Broker_Buy", Array( _






Sent via Deja.com http://www.*-*-*.com/
Before you buy.



Sat, 31 May 2003 22:22:14 GMT  
 Accessing Safearray of Safearrays in C++
There is no such thing as safearray of safearrays. There is a
multidimensional safearray, or there is a safearray of variants, each (or
some) of which in turn store a safearray (you can have as complex a
structure as you need this way). First figure out what you are passed.
SafeArrayGetDim may help (it returns a number of dimensions).

You cannot use [] operator to get to the elements of safearray. Use
SafeArrayGetElement or SafeArrayAccessData / SafeArrayUnaccessData. I
strongly recommend a second approach especially if you have a safearray of
variants each holding a safearray. SafeArrayGetElement makes a copy of the
element and puts it in the buffer you provide. In case of variants, the
contents of the variant are deep-copied, which may cause a huge overhead if
the variant holds large amounts of data. SafeArrayAccessData gives you a raw
buffer pointer to the actual data stored in the safearray, but you must be
extra careful with your pointer arithmetic -  you have all the
responsibility for proper access, no bounds checking is performed by the
system.
--
With best wishes,
    Igor Tandetnik

Quote:

> I am new to variants and safearrays in C++ and I am attempting to
> write a C++ method that accepts a variant from a VB client which
> contains a safearray of safearrays of variant.
> I get compiler errors whenever I use the [] operater on either parray.

> What is the proper way to do such a thing in C++?

> Get this error on all code that uses [].
> error C2039: 'parray' : is not a member of 'tagSAFEARRAY'

> Below are snippets of client and an attempt at server code.

> Server code:
> // Internal helper method in C++ to unpackage safearry elements into
> parameter objects
> // Called internally from RunSPReturnInteger() which is called by
> client.
> void CDBWrapper::AddParameters(_CommandPtr& a_command, _variant_t&
> array_of_params)
> {
> long array_lbound, array_ubound = 0;
> long param_lbound, param_ubound = 0;
> SAFEARRAY *pSa;
> _variant_t param_array;

> if(array_of_params.vt == (VT_ARRAY | VT_VARIANT))
> {
> try{
> // Get the bounds of the outer safearray
> TESTHR(SafeArrayGetLBound
> (array_of_params.parray,1,&array_lbound));
> TESTHR(SafeArrayGetUBound
> (array_of_params.parray,1,&array_ubound));

> while(array_lbound < array_ubound)
> {

> // Get the bounds of the inner safearray
> TESTHR(SafeArrayGetLBound
> (array_of_params.parray[array_lbound].parray,1,&param_lbound));
> TESTHR(SafeArrayGetUBound
> (array_of_params.parray[array_lbound].parray,1,&param_ubound));
> // Check for null
> if (param_ubound - param_lbound == 3)
> {
> if(array_of_params.parray
> [array_lbound].parray[3].vt == VT_BSTR) then
> {
> _bstr_t a_param
> (array_of_params.parray[array_lbound].parray[3].&vElement,false);

> }

> a_command->Parameters->Append(a_command-
> >CreateParameter(array_of_params.parray[array_lbound].parray[0], .parray
> [array_lbound].parray[1], adParamInput, .parray[array_lbound].parray
> [2], a_param));
> array_lbound++;
> }
> }
> }
> catch (_com_error &e)
> {
> printf("Error:\n");
> printf("Code = %08lx\n", e.Error());
> printf("Code meaning = %s\n", (char*)
> e.ErrorMessage());
> printf("Source = %s\n", (char*) e.Source());
> printf("Description = %s\n", (char*)
> e.Description());
> }

> }
> }

> Snippet of VB Client code:
> Public Function mp(ByVal PName As String, ByVal PType As
> ADODB.DataTypeEnum, ByVal PSize As Long, ByVal PValue As Variant)
>     mp = Array(PName, PType, PSize, PValue)
> End Function

>     dim m_dbh as dbWrapper
>     Dim x As Variant

>     x = m_dbh.RunSPReturnInteger("Broker_Buy", Array( _






> Sent via Deja.com http://www.deja.com/
> Before you buy.



Sat, 31 May 2003 23:05:08 GMT  
 Accessing Safearray of Safearrays in C++
Igor,
Thanks for your suggestion.  I have a one dimensional safearray of
variants each of which in turn store a safearrary of variants.  I am
able to access everything OK, but I want to create ADO Parameter
objects out of each parameter that is passed.  For each parameter the
client passes (name,DataTypeEnum, size, value) these are stored as
variants.  The problem is I can't get a DataTypeEnum type from the
second variant.  I've tried casting it to a long, using _variant_t
various operators with out success.  For now I've hardcoded the
DataTypeEnum to a adBSTR and it works, but all my stored procedures
have to take in varchar() and convert the type internally.  Any ideas
on how to get a DataTypeEnum value from a variant????

Snippet of VB Client Code:
Public Function mp(ByVal PName As String, ByVal PType As
ADODB.DataTypeEnum, ByVal PSize As Long, ByVal PValue As Variant)
    mp = Array(PName, PType, PSize, PValue)
End Function
m_dbh.RunSPReturnInteger("Broker_Buy", Array( _



Snippet of Server Code:
TESTHR(SafeArrayAccessData(aparameter.parray,(void HUGEP**)
&pParameterArray));
   _variant_t param_name,param_type,param_size,param_value;

   param_name.Attach(pParameterArray[0]);
   param_type.Attach(pParameterArray[1]);
   param_size.Attach(pParameterArray[2]);
   param_value.Attach(pParameterArray[3]);

   if(pParameterArray[3].vt == VT_BSTR)
   {
        // Check for null
        if(!(_bstr_t)param_value)
           param_value = "Null";
    }
   // Three line below won't compile
   //DataTypeEnum data_type = (long)param_type;
   //DataTypeEnum data_type = param_type;
   //a_command->Parameters->Append(a_command->CreateParameter((_bstr_t)
param_name,data_type, adParamInput,(long)param_size,(_bstr_t)
param_value));
   // Hardcoding to adBSTR works, but limits stored procedure params.
   a_command->Parameters->Append(a_command->CreateParameter((_bstr_t)
param_name,adBSTR, adParamInput, ((_bstr_t)param_value).length(),
(_bstr_t)param_value));



Quote:
> There is no such thing as safearray of safearrays. There is a
> multidimensional safearray, or there is a safearray of variants, each
(or
> some) of which in turn store a safearray (you can have as complex a
> structure as you need this way). First figure out what you are passed.
> SafeArrayGetDim may help (it returns a number of dimensions).

> You cannot use [] operator to get to the elements of safearray. Use
> SafeArrayGetElement or SafeArrayAccessData / SafeArrayUnaccessData. I
> strongly recommend a second approach especially if you have a
safearray of
> variants each holding a safearray. SafeArrayGetElement makes a copy
of the
> element and puts it in the buffer you provide. In case of variants,
the
> contents of the variant are deep-copied, which may cause a huge
overhead if
> the variant holds large amounts of data. SafeArrayAccessData gives
you a raw
> buffer pointer to the actual data stored in the safearray, but you
must be
> extra careful with your pointer arithmetic -  you have all the
> responsibility for proper access, no bounds checking is performed by
the
> system.
> --
> With best wishes,
>     Igor Tandetnik




- Show quoted text -

Quote:
> > I am new to variants and safearrays in C++ and I am attempting to
> > write a C++ method that accepts a variant from a VB client which
> > contains a safearray of safearrays of variant.
> > I get compiler errors whenever I use the [] operater on either
parray.

> > What is the proper way to do such a thing in C++?

> > Get this error on all code that uses [].
> > error C2039: 'parray' : is not a member of 'tagSAFEARRAY'

> > Below are snippets of client and an attempt at server code.

> > Server code:
> > // Internal helper method in C++ to unpackage safearry elements into
> > parameter objects
> > // Called internally from RunSPReturnInteger() which is called by
> > client.
> > void CDBWrapper::AddParameters(_CommandPtr& a_command, _variant_t&
> > array_of_params)
> > {
> > long array_lbound, array_ubound = 0;
> > long param_lbound, param_ubound = 0;
> > SAFEARRAY *pSa;
> > _variant_t param_array;

> > if(array_of_params.vt == (VT_ARRAY | VT_VARIANT))
> > {
> > try{
> > // Get the bounds of the outer safearray
> > TESTHR(SafeArrayGetLBound
> > (array_of_params.parray,1,&array_lbound));
> > TESTHR(SafeArrayGetUBound
> > (array_of_params.parray,1,&array_ubound));

> > while(array_lbound < array_ubound)
> > {

> > // Get the bounds of the inner safearray
> > TESTHR(SafeArrayGetLBound
> > (array_of_params.parray[array_lbound].parray,1,&param_lbound));
> > TESTHR(SafeArrayGetUBound
> > (array_of_params.parray[array_lbound].parray,1,&param_ubound));
> > // Check for null
> > if (param_ubound - param_lbound == 3)
> > {
> > if(array_of_params.parray
> > [array_lbound].parray[3].vt == VT_BSTR) then
> > {
> > _bstr_t a_param
> > (array_of_params.parray[array_lbound].parray[3].&vElement,false);

> > }

> > a_command->Parameters->Append(a_command-
> > >CreateParameter(array_of_params.parray[array_lbound].parray
[0], .parray
> > [array_lbound].parray[1], adParamInput, .parray[array_lbound].parray
> > [2], a_param));
> > array_lbound++;
> > }
> > }
> > }
> > catch (_com_error &e)
> > {
> > printf("Error:\n");
> > printf("Code = %08lx\n", e.Error());
> > printf("Code meaning = %s\n", (char*)
> > e.ErrorMessage());
> > printf("Source = %s\n", (char*) e.Source());
> > printf("Description = %s\n", (char*)
> > e.Description());
> > }

> > }
> > }

> > Snippet of VB Client code:
> > Public Function mp(ByVal PName As String, ByVal PType As
> > ADODB.DataTypeEnum, ByVal PSize As Long, ByVal PValue As Variant)
> >     mp = Array(PName, PType, PSize, PValue)
> > End Function

> >     dim m_dbh as dbWrapper
> >     Dim x As Variant

> >     x = m_dbh.RunSPReturnInteger("Broker_Buy", Array( _






> > Sent via Deja.com http://www.deja.com/
> > Before you buy.

Sent via Deja.com
http://www.deja.com/


Fri, 06 Jun 2003 09:22:50 GMT  
 Accessing Safearray of Safearrays in C++

Try

DataTypeEnum data_type = V_I4(&param_type);

Make sure that param_type.vt is VT_I4. Also, you can use
_variant_t::ChangeType - this will try a number of standard conversions to
coerce a variant to whatever type you want.
--
With best wishes,
    Igor Tandetnik

Quote:

> Igor,
> Thanks for your suggestion.  I have a one dimensional safearray of
> variants each of which in turn store a safearrary of variants.  I am
> able to access everything OK, but I want to create ADO Parameter
> objects out of each parameter that is passed.  For each parameter the
> client passes (name,DataTypeEnum, size, value) these are stored as
> variants.  The problem is I can't get a DataTypeEnum type from the
> second variant.  I've tried casting it to a long, using _variant_t
> various operators with out success.  For now I've hardcoded the
> DataTypeEnum to a adBSTR and it works, but all my stored procedures
> have to take in varchar() and convert the type internally.  Any ideas
> on how to get a DataTypeEnum value from a variant????

> Snippet of VB Client Code:
> Public Function mp(ByVal PName As String, ByVal PType As
> ADODB.DataTypeEnum, ByVal PSize As Long, ByVal PValue As Variant)
>     mp = Array(PName, PType, PSize, PValue)
> End Function
> m_dbh.RunSPReturnInteger("Broker_Buy", Array( _



> Snippet of Server Code:
> TESTHR(SafeArrayAccessData(aparameter.parray,(void HUGEP**)
> &pParameterArray));
>    _variant_t param_name,param_type,param_size,param_value;

>    param_name.Attach(pParameterArray[0]);
>    param_type.Attach(pParameterArray[1]);
>    param_size.Attach(pParameterArray[2]);
>    param_value.Attach(pParameterArray[3]);

>    if(pParameterArray[3].vt == VT_BSTR)
>    {
> // Check for null
> if(!(_bstr_t)param_value)
>    param_value = "Null";
>     }
>    // Three line below won't compile
>    file://DataTypeEnum data_type = (long)param_type;
>    file://DataTypeEnum data_type = param_type;

file://a_command->Parameters->Append(a_command->CreateParameter((_bstr_t)

- Show quoted text -

Quote:
> param_name,data_type, adParamInput,(long)param_size,(_bstr_t)
> param_value));
>    // Hardcoding to adBSTR works, but limits stored procedure params.
>    a_command->Parameters->Append(a_command->CreateParameter((_bstr_t)
> param_name,adBSTR, adParamInput, ((_bstr_t)param_value).length(),
> (_bstr_t)param_value));



> > There is no such thing as safearray of safearrays. There is a
> > multidimensional safearray, or there is a safearray of variants, each
> (or
> > some) of which in turn store a safearray (you can have as complex a
> > structure as you need this way). First figure out what you are passed.
> > SafeArrayGetDim may help (it returns a number of dimensions).

> > You cannot use [] operator to get to the elements of safearray. Use
> > SafeArrayGetElement or SafeArrayAccessData / SafeArrayUnaccessData. I
> > strongly recommend a second approach especially if you have a
> safearray of
> > variants each holding a safearray. SafeArrayGetElement makes a copy
> of the
> > element and puts it in the buffer you provide. In case of variants,
> the
> > contents of the variant are deep-copied, which may cause a huge
> overhead if
> > the variant holds large amounts of data. SafeArrayAccessData gives
> you a raw
> > buffer pointer to the actual data stored in the safearray, but you
> must be
> > extra careful with your pointer arithmetic -  you have all the
> > responsibility for proper access, no bounds checking is performed by
> the
> > system.
> > --
> > With best wishes,
> >     Igor Tandetnik



> > > I am new to variants and safearrays in C++ and I am attempting to
> > > write a C++ method that accepts a variant from a VB client which
> > > contains a safearray of safearrays of variant.
> > > I get compiler errors whenever I use the [] operater on either
> parray.

> > > What is the proper way to do such a thing in C++?

> > > Get this error on all code that uses [].
> > > error C2039: 'parray' : is not a member of 'tagSAFEARRAY'

> > > Below are snippets of client and an attempt at server code.

> > > Server code:
> > > // Internal helper method in C++ to unpackage safearry elements into
> > > parameter objects
> > > // Called internally from RunSPReturnInteger() which is called by
> > > client.
> > > void CDBWrapper::AddParameters(_CommandPtr& a_command, _variant_t&
> > > array_of_params)
> > > {
> > > long array_lbound, array_ubound = 0;
> > > long param_lbound, param_ubound = 0;
> > > SAFEARRAY *pSa;
> > > _variant_t param_array;

> > > if(array_of_params.vt == (VT_ARRAY | VT_VARIANT))
> > > {
> > > try{
> > > // Get the bounds of the outer safearray
> > > TESTHR(SafeArrayGetLBound
> > > (array_of_params.parray,1,&array_lbound));
> > > TESTHR(SafeArrayGetUBound
> > > (array_of_params.parray,1,&array_ubound));

> > > while(array_lbound < array_ubound)
> > > {

> > > // Get the bounds of the inner safearray
> > > TESTHR(SafeArrayGetLBound
> > > (array_of_params.parray[array_lbound].parray,1,&param_lbound));
> > > TESTHR(SafeArrayGetUBound
> > > (array_of_params.parray[array_lbound].parray,1,&param_ubound));
> > > // Check for null
> > > if (param_ubound - param_lbound == 3)
> > > {
> > > if(array_of_params.parray
> > > [array_lbound].parray[3].vt == VT_BSTR) then
> > > {
> > > _bstr_t a_param
> > > (array_of_params.parray[array_lbound].parray[3].&vElement,false);

> > > }

> > > a_command->Parameters->Append(a_command-
> > > >CreateParameter(array_of_params.parray[array_lbound].parray
> [0], .parray
> > > [array_lbound].parray[1], adParamInput, .parray[array_lbound].parray
> > > [2], a_param));
> > > array_lbound++;
> > > }
> > > }
> > > }
> > > catch (_com_error &e)
> > > {
> > > printf("Error:\n");
> > > printf("Code = %08lx\n", e.Error());
> > > printf("Code meaning = %s\n", (char*)
> > > e.ErrorMessage());
> > > printf("Source = %s\n", (char*) e.Source());
> > > printf("Description = %s\n", (char*)
> > > e.Description());
> > > }

> > > }
> > > }

> > > Snippet of VB Client code:
> > > Public Function mp(ByVal PName As String, ByVal PType As
> > > ADODB.DataTypeEnum, ByVal PSize As Long, ByVal PValue As Variant)
> > >     mp = Array(PName, PType, PSize, PValue)
> > > End Function

> > >     dim m_dbh as dbWrapper
> > >     Dim x As Variant

> > >     x = m_dbh.RunSPReturnInteger("Broker_Buy", Array( _






> > > Sent via Deja.com http://www.deja.com/
> > > Before you buy.

> Sent via Deja.com
> http://www.deja.com/



Sat, 07 Jun 2003 03:43:26 GMT  
 
 [ 4 post ] 

 Relevant Pages 

1. Copy 1D safeArray to 2D safearray

2. How to create safearray or safearray?

3. Accessing SAFEARRAY

4. Problem with VB clients accessing SAFEARRAY passed from my ATL server

5. SAFEARRAY access a VB COM Server?

6. MFC client access a VB COM Server with SAFEARRAY argument

7. SAFEARRAY with structur (Client Access ????)

8. MFC client access a VB COM Server with SAFEARRAY argument

9. Help: Passing structure including SafeArrays to C++ DLL

10. Return Recordsets or SafeArrays to ASP from C++?

11. SAFEARRAY C++ template

12. Need Help Passing a Variant SafeArray to ASP from C++/ATL Object

 

 
Powered by phpBB® Forum Software