BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

COM error -2147352571 (80020005) Type mismatch

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (ActiveX)
View previous topic :: View next topic  
Author Message
LarryJ
Guest





PostPosted: Fri Mar 16, 2007 3:45 pm    Post subject: COM error -2147352571 (80020005) Type mismatch Reply with quote



I am trying to make a direct call to the COM function GetAllChartLists(..).
The declaration for this function seen just below if from a type library H
file.


template <class T> HRESULT __fastcall
_cTC2000DispT<T>::GetAllChartLists(LPSAFEARRAY* ChartListNames/*[in,out]*/,
LPSAFEARRAY* ListType/*[in,out]*/)
{
_TDispID _dispid(*this, OLETEXT("GetAllChartLists"), DISPID(1610809350));
TAutoArgs<2> _args;
_args[1] = ChartListNames /*[VT_SAFEARRAY:1]*/;
_args[2] = ListType /*[VT_SAFEARRAY:1]*/;
return OleFunction(_dispid, _args);
}



In my function "My_Call_To_GetAllChartLists( )" I create the COM object,
setup the arrays that I need to pass into the function and start calling the
function like this, TC.Procedure( "GetAllChartLists", args, 2 ). which in
turn calls " Function( name, args, argn, NULL );"


When I finally make the call to the COM object using, hr = idisp->Invoke(
dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispparams, rarg,
NULL, &err ); The return value is, -2147352571. This error message is
described on the Microsoft web site as "-2147352571 (80020005) Type
mismatch." I believe this means I am passing the wrong arrays. I don't
know how else to set up the arrays that are passed. Can someone show how to
correctly set this up?



typedef TSafeArrayT<long, VT_I4, 1> TSafeArrayLong1;
typedef TSafeArrayT<BSTR, VT_BSTR, 1> TSafeArrayBSTR1;

void My_Call_To_GetAllChartLists( )
{
long RecCnt=0;
int x=0, i=0;
WideString Name;
VARIANT args[2];


TTC2000 TC;

TC.Create( "TC2000Dev.cTC2000" );

//++++++++++ Setup Arrays ++++++++
TSafeArrayDim1 DimChartListNames(0);
TSafeArrayDim1 DimListType(0);

TSafeArrayBSTR1 ChartListNames ( DimChartListNames );
TSafeArrayInt1 ListType( DimListType );

args[0].vt = VT_BSTR;
args[1].vt = VT_R4;

args[0].pparray = &(ChartListNames);
args[1].pparray = &(ListType);
//++++++++++++++++++++++++++++++++

//++++CALL FUNCTION+++++
if( TC.Procedure( "GetAllChartLists", args, 2 ) ) {
RecCnt = ChartListNames.BoundsLength[0];

//Test The Return Values
for(i=1; i<RecCnt+1; i++){
Name = ChartListNames[i];
}
}
return;
}


//------------------------------------------------------------

bool TOleAuto::Procedure( const char* name, VARIANT* args, unsigned int
argn ) {
return Function( name, args, argn, NULL );
}
//------------------------------------------------------------

bool TOleAuto::Function( const char* name,
VARIANT* args, unsigned int argn, VARIANT* rarg) {
DISPID dispid;
if( GetIDsOfNames( name, dispid ) ) {
dispparams.rgvarg = args;
dispparams.cArgs = argn;
hr = idisp->Invoke( dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD, &dispparams, rarg, NULL, &err );
}
return hr == 0;
}
//------------------------------------------------------------


bool TOleAuto::GetIDsOfNames( const char* name, DISPID& iid ) {
hr = idisp->GetIDsOfNames( IID_NULL, &WideString( name ), 1,
LOCALE_SYSTEM_DEFAULT, &iid );
return hr == 0;
}
//------------------------------------------------------------



Thanks
Larry Johnson.
Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Fri Mar 16, 2007 10:34 pm    Post subject: Re: COM error -2147352571 (80020005) Type mismatch Reply with quote



"LarryJ" <LarryJ33 (AT) austin (DOT) rr.com> wrote in message
news:45fa7544$1 (AT) newsgroups (DOT) borland.com...

Quote:
In my function "My_Call_To_GetAllChartLists( )" I create the
COM object, setup the arrays that I need to pass into the function
and start calling the function like this,
TC.Procedure( "GetAllChartLists", args, 2 ).

Why are you not calling the wrapper function that you showed?

LPSAFEARRAY ChartListNames, ListType;
// initialize arrays as needed, then...
hRes = TC.GetAllChartLists(&ChartListNames, &ListType);

Quote:
When I finally make the call to the COM object using,
hr = idisp->Invoke(...); The return value is, -2147352571.

That is DISP_E_TYPEMISMATCH:

"One or more of the arguments could not be coerced. The index
within rgvarg of the first parameter with the incorrect type is
returned in the puArgErr parameter."

The parameters being passed in to Invoke() are not set up correctly
for the COM method you are trying to call. Since you are ignoring the
wrapper function and calling Procedure() directly, the mismatch is in
your own code, because you are not passing the arrays correctly at
all.

Quote:
I believe this means I am passing the wrong arrays. I don't
know how else to set up the arrays that are passed. Can
someone show how to correctly set this up?

You could start by not calling Procedure() directly in the first
place. Let the wrapper class do the work for you.

Quote:
args[0].vt = VT_BSTR;
args[1].vt = VT_R4;

That is completely wrong. You are telling the method that you are
passing in a single string and a single float (which you are really
not), but the COM method is expecting you to pass in pointers to array
pointers instead (which you are doing, but not telling the method
that). The arrays themselves specify the data types that they hold.
You do not specify the array types in the VARIANTs that are being
passed to the method. You need to use the VT_ARRAY and VT_BYREF flags
instead, ie:

args[0].vt = VT_ARRAY | VT_BYREF;
args[1].vt = VT_ARRAY | VT_BYREF;


Gambit
Back to top
LarryJ
Guest





PostPosted: Sat Mar 17, 2007 3:56 am    Post subject: Re: COM error -2147352571 (80020005) Type mismatch Reply with quote



I have the wrapper setup and it works fine. Unfortunately the program I link
to changes the GUID each time they release a new build. This means my
program's COM link is dead every time they release a new build. I have two
chooses, 1) I can build my COM link into a DLL so I only need to distribute
a new DLL or 2) I can create the COM object dynamically and call the COM
functions directly. I am trying to setup option #2 but I have only been able
to get 1 of 3 functions working. Below is the GetPrices function from the
type library and the way I setup the call. This seems to work. But the
function shown in the previous post GetAllChartLists( ) I can't get to work.

For the function GetAllChartLists( ) I tried these two setups for args[0]
and args[1]. They both return the same -2147352571 error. Any advice for
getting the function GetAllChartLists( ) working would really help. Thanks
Larry Johnson.

args[0].vt = VT_ARRAY | VT_BYREF;
args[1].vt = VT_ARRAY | VT_BYREF;

args[0].vt = VT_BSTR | VT_ARRAY | VT_BYREF;
args[1].vt = VT_I4 | VT_ARRAY | VT_BYREF;





template <class T> HRESULT __fastcall
_cTC2000DispT<T>::GetPrices(long* WordenNum/*[in,out]*/, LPSAFEARRAY*
OpenPrices/*[in,out]*/,
LPSAFEARRAY* HighPrices/*[in,out]*/,
LPSAFEARRAY* LowPrices/*[in,out]*/
, LPSAFEARRAY* ClosePrices/*[in,out]*/,
LPSAFEARRAY* Volumes/*[in,out]*/
, LPSAFEARRAY* Dates/*[in,out]*/, long*
NumberOfPricesToGet/*[in,out]*/)
{
_TDispID _dispid(*this, OLETEXT("GetPrices"), DISPID(1610809365));
TAutoArgs<8> _args;
_args[1] = WordenNum /*[VT_I4:1]*/;
_args[2] = OpenPrices /*[VT_SAFEARRAY:1]*/;
_args[3] = HighPrices /*[VT_SAFEARRAY:1]*/;
_args[4] = LowPrices /*[VT_SAFEARRAY:1]*/;
_args[5] = ClosePrices /*[VT_SAFEARRAY:1]*/;
_args[6] = Volumes /*[VT_SAFEARRAY:1]*/;
_args[7] = Dates /*[VT_SAFEARRAY:1]*/;
_args[8] = NumberOfPricesToGet /*[VT_I4:1]*/;
return OleFunction(_dispid, _args);
}


typedef TSafeArrayT<float, VT_R4, 1> TSafeArrayFloat1;
typedef TSafeArrayFloat1 TPrice;

int MY_GetPrices( )
{
AnsiString Symb;
int date2=1, vol2=1, GetRec=0, Wnum=0, i=0;
unsigned long RecCnt;
VARIANT rarg, args[8];
float open2=1, high2=1, low2=1, close2=1;


TC.Create( "TC2000Dev.cTC2000" );

Symb = "IBM";
Wnum = 15;
GetRec = 252;


TAutoArgs<0> _args;
TOLEBOOL bbEnabled;
rarg.vt = VT_BOOL | VT_BYREF;
args[0].vt = VT_BOOL | VT_BYREF;


args[0].vt = VT_BSTR;
args[0].bstrVal = WideString( "IBM" );
rarg.vt = VT_I4;
TSafeArrayDim1 DimOpen(0);
TSafeArrayDim1 DimHigh(0);
TSafeArrayDim1 DimLow(0);
TSafeArrayDim1 DimClose(0);
TSafeArrayDim1 DimVolume(0);
TSafeArrayDim1 DimDate(0);
TPrice Open ( DimOpen );
TPrice High ( DimHigh );
TPrice Low ( DimLow );
TPrice Close( DimClose );
TSafeArrayInt1 Volume( DimVolume );
TSafeArrayInt1 Date ( DimDate );
args[7].vt = VT_I4;
args[7].lVal = Wnum;
args[6].vt = args[5].vt =
args[4].vt = args[3].vt = VT_R4 | VT_ARRAY | VT_BYREF;
args[2].vt = args[1].vt = VT_I4 | VT_ARRAY | VT_BYREF;
args[6].pparray = &(Open);
args[5].pparray = &(High);
args[4].pparray = &(Low);
args[3].pparray = &(Close);
args[2].pparray = &(Volume);
args[1].pparray = &(Date);
args[0].vt = VT_I4;
args[0].lVal = GetRec;


if( TC.Procedure( "GetPrices", args, 8 ) ) {

RecCnt = Date.BoundsLength[0];

//Check Values
for(i=1; i<RecCnt+1; i++){
date2 = Date[i];
open2 = Open[i];
high2 = High[i];
low2 = Low[i];
close2 = Close[i];
vol2 = Volume[i];
}

}else {
return(-1);
}
return(0);
}
//----------------------------------------------------------------------------






"Remy Lebeau (TeamB)" <no.spam (AT) no (DOT) spam.com> wrote in message
news:45fac759$1 (AT) newsgroups (DOT) borland.com...
>
Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Sat Mar 17, 2007 6:07 am    Post subject: Re: COM error -2147352571 (80020005) Type mismatch Reply with quote

"LarryJ" <LarryJ33 (AT) austin (DOT) rr.com> wrote in message
news:45fb20ce$1 (AT) newsgroups (DOT) borland.com...

Quote:
I have the wrapper setup and it works fine. Unfortunately the
program I link to changes the GUID each time they release a new
build.


We already talked about that in another discussion. That has nothing
to do with the topic at hand now.

Quote:
For the function GetAllChartLists( ) I tried these two setups for
args[0] and args[1]. They both return the same -2147352571 error.

Then your safearrays themselves are likely using the wrong data types
to begin with. What EXACTLY does GetAllChartLists() expect you to
pass in? What EXACTLY does it return? What EXACTLY does its
documentation say?

Quote:
args[0].bstrVal = WideString( "IBM" );

That is a crash waiting to happen. The WideString is temporary. It
will be freed when it gos out of scope. The BSTR that it allocates
will be freed immediately, leaving your VARIANT holding on to an
invalid pointer.

Quote:
if( TC.Procedure( "GetPrices", args, 8 ) ) {

As I told you earlier, you do not need to call Procedure() directly,
especially since you are not even setting up the arguments correctly
to begin with. The wrapper class already implements adequate methods
that handle all of that stuff for you. You should be using them, ie:

int MY_GetPrices( )
{
TC.Create( "TC2000Dev.cTC2000" );
if( TC )
{
TSafeArrayDim1 DimOpen(0);
TPrice Open(DimOpen);

TSafeArrayDim1 DimHigh(0);
TPrice High(DimHigh);

TSafeArrayDim1 DimLow(0);
TPrice Low(DimLow);

TSafeArrayDim1 DimClose(0);
TPrice Close(DimClose);

TSafeArrayDim1 DimVolume(0);
TSafeArrayInt1 Volume(DimVolume);

TSafeArrayDim1 DimDate(0);
TSafeArrayInt1 Date(DimDate);

long Wnum = 15;
long GetRec = 252;

TC.GetPrices(&Wnum, &Open, &High, &Low, &Close, &Volume,
&Date, &GetRec);

unsigned int RecCnt = Date.BoundsLength[0];
for(unsigned int i = 1; i < RecCnt+1; ++i)
{
//...
}
}

return 0;
}

Now, with that said, you haven't shown what your latest code that is
failing for GetAllChartLists() looks like.


Gambit
Back to top
LarryJ
Guest





PostPosted: Sat Mar 17, 2007 7:01 am    Post subject: Re: COM error -2147352571 (80020005) Type mismatch Reply with quote

Gambit,

At the bottom of the post I show all the information about how I am calling
GetAllChartLists( ) through Procedure().


What you posted makes me believe I am creating the COM object wrong. Let me
explain how I am doing that.

I created a Class named "class TOleAuto" that is shown below. In this class
I add the functions I can call such as Create(), Procedure(), Function(),
GetIDsOfNames(). The 2 Create functions are shown below. When I create the
COM object this way I do not have access to all the wrapper functions and
the wrapper H files are not even included in the project. I then call all
the COM functions using the Procedure() and Function() seen previously. This
seemed to be the only way I could get around using the hard coded GUID that
changes. If I try to call TC.GetPrices(&Wnum, &Open, &High, &Low, &Close,
&Volume, &Date, &GetRec); I will get the error "'GetPrices' is not a member
of TTC2000". Am I creating this COM object wrong?




TTC2000 TC;

TC.Create( "TC2000Dev.cTC2000" );

bool TOleAuto::Create( char* pszName ) {
bool bSuccess = true;
try {
iid = ProgIDToClassID( WideString( pszName ) );
}
catch ( const EOleSysError& ) { bSuccess = false; }
if ( bSuccess )
bSuccess = Create( iid );
return bSuccess;
}
//------------------------------------------------------------

bool TOleAuto::Create( GUID IID ) {
bool bResult = ( IID != GUID_NULL );
if( bResult ) {
iid = IID;
hr = CoCreateInstance( iid, NULL, CLSCTX_SERVER,
IID_IDispatch, (LPVOID*) &idisp );
bResult = ( hr == 0 );
}
return bResult;
}
//------------------------------------------------------------


// Simple modular Ole automation wrapper
class TOleAuto {
public:

TOleAuto() : idisp( NULL ), iid( GUID_NULL ) { init(); }
TOleAuto( IDispatch* iptr ) : idisp( iptr ) { init(); }
void init() { dispparams.rgdispidNamedArgs = NULL;
dispparams.cNamedArgs = 0;
TInitOle::Init(); }
bool isBound() const {return idisp != NULL;}
GUID GetID() { return iid; }
IDispatch* GetDispIntf() { return idisp; }
bool Create( char* pszName );
bool Create( GUID iid );
bool GetIDsOfNames( const char* name, DISPID& dispid );
bool Procedure( const char* name, VARIANT* args, unsigned int argn );
bool Procedure( DISPID& dispid, VARIANT* args, unsigned int argn );
bool Function ( const char* name, VARIANT* args, unsigned argn, VARIANT*
rarg );
bool Function ( DISPID& dispid, VARIANT* args, unsigned argn, VARIANT*
rarg );
bool Function ( DISPID& dispid, TAutoArgsBase& args );
IDispatch* GetIDisp() { return idisp; }

private:
HRESULT hr;
GUID iid;
IDispatch* idisp;
DISPPARAMS dispparams;
unsigned int err;
};


\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/



Here are all the references to the function GetAllChartLists() in the type
library file

//-----------------------------------------------------
virtual HRESULT STDMETHODCALLTYPE GetAllChartLists(LPSAFEARRAY*
ChartListNames/*[in,out]*/,
LPSAFEARRAY*
ListType/*[in,out]*/) = 0; // [1610809350]
//-----------------------------------------------------
HRESULT __fastcall GetAllChartLists(LPSAFEARRAY*
ChartListNames/*[in,out]*/,
LPSAFEARRAY*
ListType/*[in,out]*/);
//-----------------------------------------------------
HRESULT __fastcall GetAllChartLists(LPSAFEARRAY*
ChartListNames/*[in,out]*/,
LPSAFEARRAY*
ListType/*[in,out]*/);
//-----------------------------------------------------
//I believe TCOM_cTC2000 is the object whos GUID changes each build.
template <class T> HRESULT __fastcall
TCOM_cTC2000T<T>::GetAllChartLists(LPSAFEARRAY* ChartListNames/*[in,out]*/,
LPSAFEARRAY* ListType/*[in,out]*/)
{
return (*this)->GetAllChartLists(ChartListNames, ListType);
}
//-----------------------------------------------------
template <class T> HRESULT __fastcall
_cTC2000DispT<T>::GetAllChartLists(LPSAFEARRAY* ChartListNames/*[in,out]*/,
LPSAFEARRAY* ListType/*[in,out]*/)
{
_TDispID _dispid(*this, OLETEXT("GetAllChartLists"), DISPID(1610809350));
TAutoArgs<2> _args;
_args[1] = ChartListNames /*[VT_SAFEARRAY:1]*/;
_args[2] = ListType /*[VT_SAFEARRAY:1]*/;
return OleFunction(_dispid, _args);
}
//-----------------------------------------------------




//+++++++++In my H file+++++++++

typedef TSafeArrayT<long, VT_I4, 1> TSafeArrayLong1;
typedef TSafeArrayT<BSTR, VT_BSTR, 1> TSafeArrayBSTR1;
typedef TSafeArrayT<float, VT_R4, 1> TSafeArrayFloat1;

class TTC2000 : public TOleAuto {
};


//++++++In My CPP file+++++++++

TTC2000 TC

void My_Call_To_GetAllChartLists( )
{
long RecCnt=0;
int x=0, i=0;
WideString Name;
VARIANT rarg, args[2];

TAutoArgs<0> _args;
TOLEBOOL bbEnabled;
rarg.vt = VT_BOOL | VT_BYREF;



TC.Create( "TC2000Dev.cTC2000" );


TSafeArrayDim1 DimChartListNames(0);
TSafeArrayDim1 DimListType(0);

TSafeArrayBSTR1 ChartListNames ( DimChartListNames );
TSafeArrayLong1 ListType( DimListType );

// args[0].vt = VT_ARRAY | VT_BYREF;
// args[1].vt = VT_ARRAY | VT_BYREF;

args[0].vt = VT_BSTR | VT_ARRAY | VT_BYREF;
args[1].vt = VT_I4 | VT_ARRAY | VT_BYREF;

args[0].pparray = &(ChartListNames);
args[1].pparray = &(ListType);

if( TC.Procedure( "GetAllChartLists", args, 2 ) ) {
RecCnt = ChartListNames.BoundsLength[0];
//Test The Return Values
for(i=1; i<RecCnt+1; i++){
Name = ChartListNames[i];
}
}
return;
}
//------------------------------------------------------------------------
Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Sat Mar 17, 2007 8:10 am    Post subject: Re: COM error -2147352571 (80020005) Type mismatch Reply with quote

"LarryJ" <LarryJ33 (AT) austin (DOT) rr.com> wrote in message
news:45fb4bf3$1 (AT) newsgroups (DOT) borland.com...

Quote:
At the bottom of the post I show all the information about how
I am calling GetAllChartLists( ) through Procedure().

Which you are still setting up wrong. Why are you still using
Procedure()? You are not using it correctly.

Quote:
What you posted makes me believe I am creating the COM object wrong.

No, you are not. You are just not setting up the parameters correctly
when calling into it. I've explained to you several times now how to
use it correctly, but you are not using what I have shown you.

Quote:
Let me explain how I am doing that.

There is no explanation needed. There is only one way to create an
instance of a COM object. It either succeeds or fails. There is no
in-between.

Quote:
I created a Class named "class TOleAuto" that is shown below.

There was no need to do that. The TLB wrapper already handles
IDispatch for you. You are duplicating functionality that was already
available to you from the very beginning.

Quote:
I then call all the COM functions using the Procedure()
and Function() seen previously.

And you are doing so completely wrong, for reasons I have already
pointed out to you. You are not setting up the arguments properly.

Quote:
This seemed to be the only way I could get around using the
hard coded GUID that changes.

That is not true. You could have use the TLB wrapper just fine
without using the GUID at all. I explained to you a week ago how to
do that. Look back at the "COM Upgrade and back compatibility"
discussion. You never replied to it.

Quote:
If I try to call TC.GetPrices(...); I will get the error
"'GetPrices' is not a member of TTC2000".

That is because you did not add any methods to TTC2000. You never
said that you were writing your own classes. This whole time, I
thought you were using the TLB wrapper as-is. You should have made
that clearer earlier. Why are you not using the TLB wrapper as-is?
It will work fine, if you will just use it correctly in the first
place.

Quote:
I believe TCOM_cTC2000 is the object whos GUID changes each build.

That is irrelevant now. TCOM_cTC2000T is a wrapper for an interface
pointer, regardless of whether that pointer is instantiated via a GUID
or a ProgID. Use TCOM_cTC2000T as-is. It will work for you.
TOleAuto is wasting your time and efforts, until you get a better
unstanding of how to work with IDispatch::Invoke() arguments properly.

--- Cpp ---

TCOM_cTC2000 TC;

void My_Call_To_GetAllChartLists()
{
if( !TC )
TC.CreateInstance(L"TC2000Dev.cTC2000");

if( TC )
{
TSafeArrayDim1 EmptyDim(0);

TSafeArrayBSTR1 ChartListNames(EmptyDim);
TSafeArrayLong1 ListType(EmptyDim);

if( SUCCEEDED(TC->GetAllChartLists(&ChartListNames,
&ListType)) )
{
//...
}
}
}

void My_Call_To_GetPrices()
{
if( !TC )
TC.CreateInstance(L"TC2000Dev.cTC2000");

if( TC )
{
TSafeArrayDim1 EmptyDim(0);

TPrice Open(EmptyDim);
TPrice High(EmptyDim);
TPrice Low(EmptyDim);
TPrice Close(EmptyDim);
TSafeArrayInt1 Volume(EmptyDim);
TSafeArrayInt1 Date(EmptyDim);

long Wnum = 15;
long GetRec = 252;

if( SUCCEEDED(TC->GetPrices(&Wnum, &Open, &High, &Low,
&Close, &Volume, &Date, &GetRec)) )
{
//...
}
}
}


Gambit
Back to top
LarryJ
Guest





PostPosted: Sun Mar 18, 2007 8:47 pm    Post subject: Re: COM error -2147352571 (80020005) Type mismatch Reply with quote

I got this COM setup working. Thank you very much for your help.

Larry.


"Remy Lebeau (TeamB)" <no.spam (AT) no (DOT) spam.com> wrote in message
Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (ActiveX) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.