Board index » cppbuilder » Import Type Library Wizard not working with events that utilise "retval"

Import Type Library Wizard not working with events that utilise "retval"


2007-10-17 09:31:28 AM
cppbuilder102
I have started a similar thread to this before, but feel it may be
appropriate to start afresh as the problem is a bit more defined now.
I have a third party ActiveX object that fires an event that uses
"retval" (ie: I should be able to modify the value and return it to the
server). However, the Import Type Library Wizard tries to handle this
within InvokeEvent, and also, unless one removes the reference to the
"retval" in the function it will not compile. It seems like I have to
handle this event differently to others but I can't work out how.
Any tips or ideas on this?
typedef void __fastcall (__closure *
TPartitionManagerPreTransmit)(System::TObject * Sender,
BSTR
Entry/*[in]*/,
BSTR*
updatedEntry/*[out,retval]*/);//Compiler fails unless I remove reference
to this !!
class PACKAGE TPartitionManager : public Oleserver::TOleServer
{
IPartitionManagerPtr m_DefaultIntf;
_di_IUnknown __fastcall GetDunk();
public:
__fastcall TPartitionManager(TComponent* owner) :
Oleserver::TOleServer(owner)
{}
IPartitionManagerPtr& GetDefaultInterface();
void __fastcall InitServerData();
void __fastcall Connect();
void __fastcall Disconnect();
void __fastcall BeforeDestruction();
void __fastcall ConnectTo(IPartitionManagerPtr intf);
virtual void __fastcall InvokeEvent(int DispID,
Oleserver::TVariantArray& params);
...
private:
...
TPartitionManagerPreTransmit FOnPreTransmit;
__published:
__property TPartitionManagerPreTransmit OnPreTransmit={
read=FOnPreTransmit, write=FOnPreTransmit };
};
void __fastcall TPartitionManager::InvokeEvent(int id,
Oleserver::TVariantArray& params)
{
switch(id)
{
...
case 6: {
if (OnPreTransmit) {
(OnPreTransmit)(this, TVariant(params[0]));//compiler wants an
extra parameter here, which is wrong!!!
}
break;
}
default:
break;
}
}
 
 

Re:Import Type Library Wizard not working with events that utilise "retval"

Only one.
Again.. fixing a weakness in the compiler is not a crime..
forgive this post length. a short sample is not possible.
steps taken.
( skip to step 7 if you are familiar with this issue.)
1 )build sample activeX module that fits issue )BSTR*
UpdateOrder/*[out,retval]*/)
interface IViewControl : public IDispatch
{
public:
virtual HRESULT STDMETHODCALLTYPE Transmit(BSTR Entry/*[in]*/, BSTR*
UpdateOrder/*[out,retval]*/) = 0; // [1]
#if !defined(__TLB_NO_INTERFACE_WRAPPERS)
BSTR __fastcall Transmit(BSTR Entry/*[in]*/)
{
BSTR UpdateOrder = 0;
OLECHECK(this->Transmit(Entry, (BSTR*)&UpdateOrder));
return UpdateOrder;
}
2 ) added event interface and coclass
event
interface IViewCtrlTestEvents : public TDispWrapper<IDispatch>
{
HRESULT __fastcall OnTransit(BSTR Entry/*[in]*/, BSTR*
updatedEntry/*[out,retval]*/)
{
_TDispID _dispid(/* OnTransit */ DISPID(1));
TAutoArgs<1>_args;
_args[1] = Entry /*[VT_BSTR:0]*/;
return OutRetValSetterPtr(updatedEntry /*[VT_BSTR:1]*/, _args,
OleFunction(_dispid, _args));
}
BSTR __fastcall OnTransit(BSTR Entry/*[in]*/)
{
BSTR updatedEntry;
this->OnTransit(Entry, (BSTR*)&updatedEntry);
return updatedEntry;
}
spared posting coclass..
3 ) build and register dll (activex lib)
4 ) IDE / import type lib.
5 ) installed as a component
typedef void __fastcall (__closure * TViewCtrlTestOnTransit)(System::TObject
* Sender,
BSTR
Entry/*[in]*/,
BSTR*
updatedEntry/*[out,retval]*/);
class PACKAGE TViewCtrlTest : public Oleserver::TOleServer
6 ) build and as Misha suggested
not enough params in ......
7 ) applied suggested code.
add fuction to handle thunk.
test param and supplly as needed..
void __fastcall TViewCtrlTest::InvokeEvent(int id, Oleserver::TVariantArray&
params)
{
switch(id)
{
case 1:
if (OnTransit)
{
// 1 ) comment this out..
// (OnTransit)(this, TVariant(params[0]));
// 2 ) : added func. handler
// assumes entry and upda{*word*249}try are equivalent unless
specified.
WideString wsUpdatedEntry = params[0];
DoTestOnTransit(this, TVariant(params[0]), &wsUpdatedEntry);
}
break;
default:
break;
}
}
...
8 ) alter control source ( of impl. class <coclass>) to fire event with
retval param ...
read the help blurb.. retVal MUST be last param.
STDMETHODIMP TViewCtrlTestImpl::Transmit(BSTR Entry, BSTR* UpdateOrder)
{
Fire_OnTransit(Entry, updatedEntry);
return S_OK;
}
9 ) build test app (host) inset control. etc ....
void __fastcall TForm1::ViewCtrlTest1Transit(TObject *Sender, BSTR Entry,
BSTR *updatedEntry)
{
//
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
WideString Entry = "anentry";
WideString upda{*word*249}try = "anentry";
ViewCtrlTest1->OnTransit(ViewCtrlTest1, Entry, &upda{*word*249}try);
}
If I have left something undone or if this sample is insufficient .. please
advise.
"Mischa Simmonds" wrote in message
Quote
I have started a similar thread to this before, but feel it may be
appropriate to start afresh as the problem is a bit more defined now.

I have a third party ActiveX object that fires an event that uses "retval"
(ie: I should be able to modify the value and return it to the server).
However, the Import Type Library Wizard tries to handle this within
InvokeEvent, and also, unless one removes the reference to the "retval" in
the function it will not compile. It seems like I have to handle this
event differently to others but I can't work out how.

Any tips or ideas on this?

 

Re:Import Type Library Wizard not working with events that utilise "retval"

still have doubt.. If I must.
int the component source..
void __fastcall TViewCtrlTest::DoTestOnTransit(System::TObject * Sender,
BSTR
Entry/*[in]*/,
BSTR*
updatedEntry/*[out,retval]*/)
{
if(OnTransit)
(OnTransit)(this, Entry, updatedEntry);
}
DoTestOnTransit now has params supplied..
int the test app.. don't call the control event. go directly to the source..
void __fastcall TForm1::Button1Click(TObject *Sender)
{
WideString Entry = "anentry";
WideString upda{*word*249}try = "anentry";
IViewControl *ViewControl = 0;
IViewCtrlTestPtr Ptr = ViewCtrlTest1->GetDefaultInterface ();
if(Ptr)
{
Ptr->QueryInterface(IID_IViewControl, (LPVOID*)&ViewControl);
if(ViewControl)
{
ViewControl->Transmit(Entry, &upda{*word*249}try);
ViewControl->Release();
}
}
//ViewCtrlTest1->Transmit (ViewCtrlTest1, Entry, &upda{*word*249}try);
}
void __fastcall TForm1::ViewCtrlTest1Transit(TObject *Sender, BSTR Entry,
BSTR *updatedEntry)
{
// do something here...
}
The java script example is likely throwing an exception in your server, It
is just that it is silent.
--\
Michael
 

{smallsort}

Re:Import Type Library Wizard not working with events that utilise "retval"

"Michael Harris" < XXXX@XXXXX.COM >wrote in message
Quote
fixing a weakness in the compiler is not a crime..
As I explained to Mischa in the other discussion thread on this topic, this
is not a compiler error. Borland's TEventDispatcher class, which the Import
wizard uses when generating the wrapper code, is simply not designed to
support COM events that have 'retval' parameters to begin with. I gave a
very detailed explanation of how to work around the issue, but he was not
able to make it work for his situation yet.
Quote
WideString wsUpdatedEntry = params[0];
DoTestOnTransit(this, TVariant(params[0]), &wsUpdatedEntry);
That is fine and good for allowing a "reval" parameter in the user's event
handler, but there is still no way to get the user's value back to the COM
object afterwards because there is simply no room for it in the Variant
array that TEventDispatcher sets up when calling InvokeEvent(). To remedy
this issue, CodeGear needs to re-write TEventDispatcher to support return
values (and while they are at it, they need to add error reporting
capabilities as well).
Gambit
 

Re:Import Type Library Wizard not working with events that utilise "retval"

I fully understand what you are saying.
I cannot post what I use, But I do not understand why this isn't working for
bstr*
HRESULT __fastcall OnTransit(BSTR Entry/*[in]*/, BSTR*
updatedEntry/*[out,retval]*/)
{
_TDispID _dispid(/* OnTransit */ DISPID(1));
TVariant *retVal = new TVariant;
TVariant varg[2];
DISPPARAMS dispparams;
varg[0].bstrVal = Entry;;
varg[1].bstrVal = SysAllocString(updatedEntry[0]);
// vt_byfer is required for retval
varg[1].ChangeType( VT_BYREF | VT_BSTR);
dispparams.cArgs = 2;
dispparams.rgvarg = (TVariant*)& varg;
dispparams.cNamedArgs = 0;
dispparams.rgdispidNamedArgs = NULL;
IDispatch * disp = static_cast<IDispatch*>(this);
disp->Invoke(_dispid, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, &dispparams, retVal, NULL, NULL);
// the param out/retval should return to retVal
delete retVal;
return S_OK;
}
with that said. if you trace into utils.h OutRetValSetterPtr
it does in fact allow for a return value. or param with same.
"Remy Lebeau (TeamB)" wrote in message
Quote

As I explained to Mischa in the other discussion thread on this topic,
this
is not a compiler error. Borland's TEventDispatcher class, which the
Import
wizard uses when generating the wrapper code, is simply not designed to
support COM events that have 'retval' parameters to begin with. I gave a
very detailed explanation of how to work around the issue, but he was not
able to make it work for his situation yet.

>WideString wsUpdatedEntry = params[0];
>DoTestOnTransit(this, TVariant(params[0]), &wsUpdatedEntry);

That is fine and good for allowing a "reval" parameter in the user's event
handler, but there is still no way to get the user's value back to the COM
object afterwards because there is simply no room for it in the Variant
array that TEventDispatcher sets up when calling InvokeEvent(). To remedy
this issue, CodeGear needs to re-write TEventDispatcher to support return
values (and while they are at it, they need to add error reporting
capabilities as well).


Gambit


 

Re:Import Type Library Wizard not working with events that utilise "retval"

after reviewing some code.. this is what I came up with testing on a bool
one param return Value.
the changes should be relevant to bstr* return;
1 ) added an event to activeX lib for return testing.
2 ) changed the impl class to reflect changes..
3 ) copied the result IN and OUT everywhere.
::Transmit(BSTR Entry, BSTR* UpdateOrder)
{
TOLEBOOL fConnected = VARIANT_FALSE;
Fire_OnTransmit(&fConnected);
AnsiString reslut = "FALSE";
if(fConnected == VARIANT_TRUE) reslut = "TRUE";
ShowMessage( reslut);
return S_OK;
}
4 )changes to toleserver control
TViewCtrlTest::InvokeEvent( ...
{
case 2:
{
TOLEBOOL fConnected = VARIANT_FALSE; // or params[0]
if(OnTransmit) OnTransmit(this, &fConnected);
params[0] = (TVariant)fConnected;
}
break;
}
5 ) changes to TLB emmited files ( XXX_ltb.h)
IViewCtrlTestEventsDispT<T>::OnTransmit(TOLEBOOL*
fConnected/*[out,retval]*/)
{
VARIANT vntArg;
VARIANT_BOOL vntbContinue = fConnected[0]; // or VARIANT_FALSE;
::VariantInit(&vntArg);
V_VT(&vntArg) = VT_BYREF | VT_BOOL;
V_BOOLREF(&vntArg) = &vntbContinue;
DISPPARAMS dispparams;
dispparams.cArgs = 1;
dispparams.rgvarg = &vntArg;
dispparams.cNamedArgs = 0;
dispparams.rgdispidNamedArgs = NULL;
m_Dispatch->Invoke(_dispid, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, &dispparams, NULL, NULL, NULL);
fConnected[0] = dispparams.rgvarg->boolVal;
::VariantClear(&vntArg);
}
6 )
form event thunk
ViewCtrlTest1Transmit(TObject *Sender,
TOLEBOOL *fConnected)
{
* fConnected = VARIANT_TRUE;
}
this method appears to be successful
 

Re:Import Type Library Wizard not working with events that utilise "retval"

Quote
>Any tips or ideas on this?
Yes, the method descibed works fine on bstr pointers and anything else I
tried..
--
Michael
 

Re:Import Type Library Wizard not working with events that utilise "retval"

"Michael Harris" < XXXX@XXXXX.COM >wrote in message
Quote
I do not understand why this isn't working for bstr*
Because that is not how "retval" parameters are handled to begin with. If
you are going to pass the information to Invoke(), you have to use its
pvarResult parameter, which Borland/CodeGear does not, and neither does your
example.
Quote
with that said. if you trace into utils.h OutRetValSetterPtr
it does in fact allow for a return value. or param with same.
But that is not used in event dispatching, though.
Gambit
 

Re:Import Type Library Wizard not working with events that utilise "retval"

"Michael Harris" < XXXX@XXXXX.COM >wrote in message
Quote
VARIANT_BOOL vntbContinue = fConnected[0]; // or VARIANT_FALSE;
"out" parameters do not have an input value. They are intialized to 0 upon
entry to the function. This is doubly so for "retval" parameters. You
can't have an input for a return value.
Quote
m_Dispatch->Invoke(_dispid, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, &dispparams, NULL, NULL, NULL);
You are still not using the pvarResult parameter of Invoke(). You need to,
ie:
IViewCtrlTestEventsDispT<T>::OnTransmit(TOLEBOOL*
fConnected/*[out,retval]*/)
{
TVariant vntRet;
V_VT(&vntRet) = VT_BOOL;
V_BOOL(&vntRet) = VARIANT_FALSE;
DISPPARAMS dispparams;
dispparams.cArgs = 0;
dispparams.rgvarg = NULL;
dispparams.cNamedArgs = 0;
dispparams.rgdispidNamedArgs = NULL;
m_Dispatch->Invoke(_dispid, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, &dispparams, &vntRet, NULL, NULL);
*fConnected = V_BOOL(&vntRet);
}
Gambit