Board index » cppbuilder » Error when using Importing Type Library on COM object

Error when using Importing Type Library on COM object


2007-09-27 09:11:22 AM
cppbuilder84
The import type library creates the following code which will not
compile due to "Error: E2192 Too few parameters in call".
So I have modified it by adding "TVariant(params[1])". However, at
runtime it raises an exception System::DynArrayOutOfRange and I am
unable to use this event.
I have looked through examples from other imports I have done and don't
see any event classes that contain [out,retval] parameters, so wondering
if the problem could be related to that?
Hopefully someone can help me before I pull all of my hair out!! ;)
Thanks
Extract from Viewpoint_OCX.h showing what the import type library wizard
creates and what I modified
// *********************************************************************//
void __fastcall TPartitionManager::InvokeEvent(int id,
Oleserver::TVariantArray& params)
{
switch(id)
{
case 6: {
if (OnPreTransmit) {
// (OnPreTransmit)(this, TVariant(params[0])); //Error: E2192 Too
few parameters in call
(OnPreTransmit)(this, TVariant(params[0]),TVariant(params[1]));
//Compiles with this change
}
break;
}
default:
break;
}
}
However, this function raises exception class System::DynArrayOutOfRange
with message'Exception Object Address:0xD158d2' in the following
function within sysdyn.h ....
// *********************************************************************//
template <class T>T&
DynamicArray<T>::operator[](int index)
{
if (index < 0 || index>= this->Length)
throw DynArrayOutOfRange(index, this->Length);
if (!Data)
throw DynArrayNullData();
return *(Data + index);
}
The COM object work fine within javascript in HTML...
// *********************************************************************//
<SCRIPT>
var pm = new ActiveXObject("galileo.PartitionManager");
var sink = new ActiveXObject("GIUtils.sink");
function OnPreTransmit(s)
{
if(entry_text.value.length)
{
return entry_text.value;
}
else
{
return s;
}
}
function Connect()
{
sink.PreTransmit = OnPreTransmit;
sink.Advise(pm);
}
</SCRIPT>
The following are extracts from Viewpoint_TLB.h where PreTransmit is
defined...
// *********************************************************************//
interface IDispPartitionManagerEvents : public TDispWrapper<IDispatch>
{
HRESULT __fastcall PreTransmit(BSTR Entry/*[in]*/, BSTR*
updatedEntry/*[out,retval]*/)
{
_TDispID _dispid(/* PreTransmit */ DISPID(6));
TAutoArgs<1>_args;
_args[1] = Entry /*[VT_BSTR:0]*/;
return OutRetValSetterPtr(updatedEntry /*[VT_BSTR:1]*/, _args,
OleFunction(_dispid, _args));
}
BSTR __fastcall PreTransmit(BSTR Entry/*[in]*/)
{
BSTR updatedEntry;
this->PreTransmit(Entry, (BSTR*)&updatedEntry);
return updatedEntry;
}
};
// *********************************************************************//
template <class T>
class IDispPartitionManagerEventsDispT : public
TAutoDriver<IDispPartitionManagerEvents>
{
public:
IDispPartitionManagerEventsDispT(){}
void Attach(LPUNKNOWN punk)
{ m_Dispatch = static_cast<T*>(punk); }
HRESULT __fastcall PreTransmit(BSTR Entry/*[in]*/, BSTR*
updatedEntry/*[out,retval]*/);
BSTR __fastcall PreTransmit(BSTR Entry/*[in]*/);
};
// *********************************************************************//
template <class T>HRESULT __fastcall
IDispPartitionManagerEventsDispT<T>::PreTransmit(BSTR Entry/*[in]*/,
BSTR*
updatedEntry/*[out,retval]*/)
{
_TDispID _dispid(/* PreTransmit */ DISPID(6));
TAutoArgs<1>_args;
_args[1] = Entry /*[VT_BSTR:0]*/;
return OutRetValSetterPtr(updatedEntry /*[VT_BSTR:1]*/, _args,
OleFunction(_dispid, _args));
}
template <class T>BSTR __fastcall
IDispPartitionManagerEventsDispT<T>::PreTransmit(BSTR Entry/*[in]*/)
{
BSTR updatedEntry;
this->PreTransmit(Entry, (BSTR*)&updatedEntry);
return updatedEntry;
}
// *********************************************************************//
template <class T>
class TEvents_PartitionManager : public IConnectionPointImpl<T,
&DIID_IDispPartitionManagerEvents,
CComDynamicUnkArray<CONNECTIONPOINT_ARRAY_SIZE>>
//CComUnkArray<CONNECTIONPOINT_ARRAY_SIZE>>
/* Note: if encountering problems with events, please change
CComUnkArray to CComDynamicUnkArray in the line above. */
{
public:
HRESULT Fire_PreTransmit(BSTR Entry, BSTR* updatedEntry);
protected:
IDispPartitionManagerEventsDisp m_EventIntfObj;
};
// *********************************************************************//
template <class T>HRESULT
TEvents_PartitionManager<T>::Fire_PreTransmit(BSTR Entry, BSTR*
updatedEntry)
{
T * pT = (T*)this;
pT->Lock();
IUnknown ** pp = m_vec.begin();
while (pp < m_vec.end())
{
if (*pp != NULL)
{
m_EventIntfObj.Attach(*pp);
m_EventIntfObj.PreTransmit(Entry, updatedEntry);
m_EventIntfObj.Attach(0);
}
pp++;
}
pT->Unlock();
}
 
 

Re:Error when using Importing Type Library on COM object

"Mischa Simmonds" < XXXX@XXXXX.COM >wrote
in message news:46fb0338$ XXXX@XXXXX.COM ...
Quote
if (OnPreTransmit) {
// (OnPreTransmit)(this, TVariant(params[0])); //Error: E2192 Too
few parameters in call
(OnPreTransmit)(this, TVariant(params[0]),TVariant(params[1]));
//Compiles with this change
You did not show the declaration of the OnPreTransmit member. However, the
PreTransmit() event in the TypeLibrary has only one input parameter, not
two. It does have an output parameter, however the params array DOES NOT
include a slot for that value (TEventDispatcher ignores the pVarResult
parameter of IDispatch::Invoke()). So trying to use params[1] is wrong.
From the sounds of it, your OnPreTransmit member is expecting that output
parameter, though, so you will have to forgo using InvokeEvent() and
override Invoke() directly instead.
Quote
However, this function raises exception class System::DynArrayOutOfRange
with message'Exception Object Address:0xD158d2' in the following
function within sysdyn.h ....
I would expect that since there is no index 1 in the params array that is
being passed to InvokeEvent().
Gambit
 

Re:Error when using Importing Type Library on COM object

Thanks for that Remy. btw..Is Remy one person, or a whole team..You seem
to be everywhere?
Quote
You did not show the declaration of the OnPreTransmit member.
typedef void __fastcall (__closure *
TPartitionManagerPreTransmit)(System::TObject * Sender, BSTR
Entry/*[in]*/, BSTR* updatedEntry/*[out,retval]*/);
Quote
However, the PreTransmit() event in the TypeLibrary has only one input parameter, not two.
I appreciated that the Type Library only had provision for one input
value. What I don't understand is why the import wizard creates code
which gives the error in the first place, and by adding the extra
parameter (which is obviously wrong) it compiles.
Quote
It does have an output parameter, however the params array DOES NOT
include a slot for that value (TEventDispatcher ignores the pVarResult
parameter of IDispatch::Invoke()). So trying to use params[1] is wrong.
From the sounds of it, your OnPreTransmit member is expecting that output
parameter, though, so you will have to forgo using InvokeEvent() and
override Invoke() directly instead.


Yes, the event is supposed to give me the ability to see the value being
returned, and allow me to modify it if I want, as per the enclosed
javascript example.
And finally, not sure what you mean by overriding Invoke() at this stage.
 

{smallsort}

Re:Error when using Importing Type Library on COM object

"Mischa Simmonds" < XXXX@XXXXX.COM >wrote
in message news:46fb1963$ XXXX@XXXXX.COM ...
Quote
typedef void __fastcall (__closure *
TPartitionManagerPreTransmit)(System::TObject * Sender, BSTR
Entry/*[in]*/, BSTR* updatedEntry/*[out,retval]*/);
That is what I suspected. InvokeEvent() is not designed to work with
"retval" parameters.
Quote
What I don't understand is why the import wizard creates
code which gives the error in the first place, and by adding
the extra parameter (which is obviously wrong) it compiles.
It is ignoring the "retval" parameter. It has no way to pass that value to
InvokeEvent() for the application to fill in. Besides, it is not common
practice for COM events to have return values in the first place.
Quote
And finally, not sure what you mean by overriding Invoke() at this stage.
Your imported class derives from a TEventDispatcher-based class, which
overriding the virtual IDispatch::Invoke() method to call your code's
InvokeEvent() implementation. In order to handle the event's return value
correctly, you will have to manually change the auto-generated code for your
COM object class in order to override the Invoke() method directly. For
example (untested):
class TPartitionManager
// ancestors here ...
{
public:
//...
// IDispatch
HRESULT STDMETHODCALLTYPE Invoke(DISPID dispid, REFIID iid, LCID
lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO
*pExcepInfo, UINT *puArgError);
};
HRESULT STDMETHODCALLTYPE TPartitionManager::Invoke(DISPID dispid,
REFIID iid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT*
pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgError)
{
if( dispid != 6 )
return TEventDispatcher<TPartitionManager,
&DIID_IDispPartitionManagerEvents>::Invoke(dispid, iid, lcid, wFlags,
pDispParams, pVarResult, pExcepInfo, puArgError);
try
{
if( pDispParams->cNamedArgs != 0 )
return DISP_E_NONAMEDARGS;
if( pDispParams->cArgs != 1 )
return DISP_E_BADPARAMCOUNT;
VARIANTARG &arg = pDispParams->rgvarg[0];
WideString wResult;
if( V_VT(&arg) != VT_BSTR )
{
TVariant vTemp;
HRESULT hRes = VariantChangeTypeEx(&vTemp, &arg, lcid,
VARIANT_NOVALUEPROP, VT_BSTR);
if( hRes != S_OK )
{
if( (hRes == DISP_E_TYPEMISMATCH) && (puArgError) )
*puArgError = 0;
return hRes;
}
if( OnPreTransmit )
OnPreTransmit(this, V_BSTR(&vTemp), &wResult);
}
else
{
if( OnPreTransmit )
OnPreTransmit(this, V_BSTR(&arg), &wResult);
}
if( pVarResult )
{
V_VT(pVarResult) = VT_BSTR;
V_BSTR(pVarResult) = wResult.Detach();
}
}
catch(const Exception &e)
{
if( pExcepInfo )
{
pExcepInfo->wCode = 0;
pExcepInfo->wReserved = 0;
pExcepInfo->bstrSource =
WideString("PartitionManager").Detach();
pExcepInfo->bstrDescription =
WideString(e.Message).Detach();
pExcepInfo->bstrHelpFile = NULL;
pExcepInfo->dwHelpContext = 0;
pExcepInfo->pvReserved = NULL;
pExcepInfo->pfnDeferredFillIn = NULL;
pExcepInfo->scode = E_UNEXPECTED;
}
return DISP_E_EXCEPTION;
}
return S_OK;
}
Gambit
 

Re:Error when using Importing Type Library on COM object

Unfortunately, despite lots of research and experimentation I am still
struggling with this problem, where I am trying use a 'retval' in an
event...
Quote
HRESULT STDMETHODCALLTYPE TPartitionManager::Invoke(DISPID dispid,
REFIID iid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT*
pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgError)
{
if( dispid != 6 )
return TEventDispatcher<TPartitionManager,
&DIID_IDispPartitionManagerEvents>::Invoke(dispid, iid, lcid, wFlags,
pDispParams, pVarResult, pExcepInfo, puArgError);

I get the following error on the previous line when I try and compile.....
[C++ Error] Viewpoint_OCX.cpp(324): E2283 Use . or ->to call '__stdcall
TEventDispatcher<TPartitionManager,&DIID_IDispPartitionManagerEvents,TFakeComponentBase>::Invoke(long,const
_GUID &,unsigned long,unsigned short,tagDISPPARAMS *,tagVARIANT
*,tagEXCEPINFO *,unsigned int *)'
 

Re:Error when using Importing Type Library on COM object

"Mischa Simmonds" < XXXX@XXXXX.COM >wrote
in message news: XXXX@XXXXX.COM ...
Quote
Unfortunately, despite lots of research and experimentation
I am still struggling with this problem, where I am trying use
a 'retval' in an event...
Then you may have to stop trying to use a "retval" parameter in an event and
choose a different design altogether.
Quote
I get the following error on the previous line when I try and compile.....
The only way that error can happen is if your TPartitionManager class is not
derived from TEventDispatcher to begin with. Please show your
TPartitionManager's actual declaration.
Gambit
 

Re:Error when using Importing Type Library on COM object

Thanks for your assistance so far...
Quote
Then you may have to stop trying to use a "retval" parameter in an event and
choose a different design altogether.

Unfortunately I can't do this, as I am simply trying to use a third
party COM object that I know imports and works fine with the various
Visual Studio languages, but I want to use C++Builder, and it seems that
the C++Builder import library is unable to handle "retval" parameters.
And my skills are not good enough at that level to work out what is
going on.
Quote
The only way that error can happen is if your TPartitionManager class is not
derived from TEventDispatcher to begin with. Please show your
TPartitionManager's actual declaration.

class PACKAGE TPartitionManager : public Oleserver::TOleServer
 

Re:Error when using Importing Type Library on COM object

"Mischa Simmonds" < XXXX@XXXXX.COM >wrote
in message news:470f10dc$ XXXX@XXXXX.COM ...
Quote
class PACKAGE TPartitionManager : public Oleserver::TOleServer
Is that all it derives from? If so, then how was it receiving events to
begin with?
Gambit
 

Re:Error when using Importing Type Library on COM object

Same as any other TOleServer. for example
from Exchange SDK\SDK\Support\IM\msimhost.exe imported interfaces.
class PACKAGE TMSIMHost : public Oleserver::TOleServer wraps IMSIMHost
...
void __fastcall TMSIMHost::InitServerData()
{
static Oleserver::TServerData sd;
sd.ClassID = CLSID_MSIMHost;
sd.IntfIID = __uuidof(IMSIMHost);
sd.EventIID= __uuidof(DMSIMHostEvents);
ServerData = &sd;
}
where DMSIMHostEvents is the event interface of IMSIMHost
Interestingly enough. one of the events for
typedef void __fastcall (__closure * TMSIMHostOnDoubleClick)(System::TObject
* Sender,
TVariant*
pfHandled/*[in,out]*/);
supplies an out / retval in the functor prototype. pfHandled indicates the
event is handled at UI level, or not.
As far as Mischa problem. I might be tempted to force or atleast check the
params length in
void __fastcall TPartitionManager::InvokeEvent(int id,
Oleserver::TVariantArray& params)
{
switch(id)
{
case 6: {
if (OnPreTransmit) {
// (OnPreTransmit)(this, TVariant(params[0])); //Error: E2192 Too
few parameters in call
(OnPreTransmit)(this, TVariant(params[0]),TVariant(params[1]));
//Compiles with this change
}
Test params length. supply something suitable if it is found 'params[1]' is
invalid.
Question.. doesn't the supplied script sample suppress any error in this
situation.
"Remy Lebeau (TeamB)" wrote in message
Quote
Is that all it derives from? If so, then how was it receiving events to
begin with?


Gambit


 

Re:Error when using Importing Type Library on COM object

actually, pfHandled/*[in,out]*/) is an in/out not retval as suggested.
 

Re:Error when using Importing Type Library on COM object

Not sure.
But as I stated at the beginning of the thread, I simply used the Import
Type Library Wizard in C++Builder to atempt to use a third party COM
object that all works fine with javascript, but only which works with
all the events in C++Builder, except for the one that uses 'retval'.
Quote
Is that all it derives from? If so, then how was it receiving events to
begin with?