 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
LarryJ Guest
|
Posted: Tue Mar 06, 2007 3:24 am Post subject: Asynchronous Callback |
|
|
Gambit,
I started new thread to discuss setting up an asynchronous callback using
the same ActiveX object we discussed in the previous thread.
I am creating my AxtiveX object using TC.CreateInstance( CLSID_Hooks );
seen below.
TCOMIHooks TC;
HRESULT hr = TC.CreateInstance( CLSID_Hooks );
To start the real-time data feed I call the function
TC->RequestSymbol(sSymbol, true); The server app returns data through a
call back function, OnQuoteChanged(ByVal sSymbol As String). I don't know
how to setup this call back function. The text under Processing Data
Structures describes how the call back OnQuoteChanged() works but not how to
manually set it up. If you scroll down to the text "Here is what Happens
When I use the Borland ActiveX Wrapper" I describe the exception that I get
when I use the OnQuoteChange() call back that is setup by the Borland
wrapper. I am hopping to manually setup the call backs so I can take more
control over the exceptions. I tried to manually duplicate the Borland
wrapper setup but that did not work. Can you show how I can setup this call
back.
Processing Data Structures
Some functions available through the eSignal Desktop API have associated
response events that return data structures. For example, the RequestSymbol
function results in the response event OnQuoteChanged. The OnQuoteChanged
event delivers the BasicQuote data structure. Figure
3-3, "Data Structures," provides an illustrated example of how the
BasicQuote data structure is delivered.
.Figure 3-3 Data Structures
.
esignal.RequestSymbol "MSFT", True
.
.
.
Private Sub esignal_OnQuoteChanged(ByVal sSymbol As String)
Dim quote As IESignal.BasicQuote
quote = esignal.GetBasicQuote(sSymbol)
edtBid.Text = Str$(quote.dBid)
edtAsk.Text = Str$(quote.dAsk)
edtLast.Text = Str$(quote.dLast)
End Sub
Some requests can result in a continuous flow of events and data updates.
In the above example, the True argument in the RequestSymbol request
function, instructs the eSignal Desktop API to notify the application each
time the quote for the specified symbol changes. To avoid missed data due
to an update event, it is important to get the data from the data structures
as quickly as possible. Once the data is captured it is safe to process
without fear of it being overwritten due to another update event.
//=======================================
// Here is what Happens When I use the Borland ActiveX Wrapper
//=======================================
When I use the Borland wrapper I start the real-time stock data feed by
calling the function, Hooks1->RequestSymbol(sSymbol, true);. The server
application returns the data through what I believe to be an asynchronous
callback named OnQuoteChanged(). The Borland wrapper has setup this as
Hooks1QuoteChanged() seen below. Processing this event will eventually
throw an exception that points to a failure of the function
Hooks1->GetBasicQuote[sSymbol]; The message boxes that appear identify the
file UTILCLS.H at line 154 which I have copied below and the type librarty
file IESignal_TLB.h line 547 which is the GetBasicQuote() function which I
have also copied below. In this call-back I am doing the minimum work to
complete the event as fast as possible because the incoming data is often
coming in very fast more then one per second. The more code I add to this
call-back Hooks1QuoteChanged() that faster the exception will be thrown. I
have the Hooks1->GetBasicQuote[sSymbol]; in a try catch but this does not
seem to have any affect.
void __fastcall TForm1::Hooks1QuoteChanged(TObject *Sender, BSTR sSymbol)
{
BasicQuote quote;
//Use GetBasicQuote function to get the data structure associated with the
symbol
try {quote = Hooks1->GetBasicQuote[sSymbol];
}
catch(const Exception&){
AdvStringGrid2->Cells[0][0]="FAIL";
return;
}
AdvStringGrid2->Cells[8][2] = sSymbol;
AdvStringGrid2->Cells[8][3] = Format("%f", ARRAYOFCONST( (quote.dLast)));
}
UTILCLS.H Line 154 where the exeption stops the code is the second line from
the bottom that reads " throw msg; // Hopefully we never get here: Need
something much better to throw!! "
////////////////////////////////////////////////////////////////////////////////
// Helper classes and functions for debugging.
////////////////////////////////////////////////////////////////////////////////
// Implementation of TRACE_HLPR
template <class T>
class TDebugHlpr
{
public:
static void __cdecl TRACE_HLPR(T* szFormat, ...);
};
// Helper used to throw an exception
template <class T>
void DebugHlpr_THROW(T* msg, HRESULT hr, T* file, bool /*assertFailed*/)
{
#if defined(ComObjHPP)
// NOTE: This does not retrieve rich error information, the way Delphi and
VB environments
// do. Eventually this 'throw' will either throw a rich
EOleException or some other
// OLE exception class (something equivalent to _com_error, maybe??)
//
// For now, you can specialized [T = TCHAR] 'DebugHlpr_THROW' to
retrieve rich error
// information and throw a VCL exception class, if you're using VCL
classes already,
// or throw a custom exception class.
//
// NOTE: Use the assertFailed parameter to distinguish between
Assertion and
// OLECHECK failures. (Maybe throw something different??)
throw EOleException(msg, hr, file, _T(""), 0);
#else
throw msg; // Hopefully we never get here: Need something much better to
throw!!
#endif
}
//============IESignal_TLB.h============
Iesignal_tlb::BasicQuote __fastcall get_GetBasicQuote(BSTR sSymbol)
{
Iesignal_tlb::BasicQuote pQuote;
OLECHECK(this->get_GetBasicQuote(sSymbol,
(Iesignal_tlb::BasicQuote*)&pQuote));
return pQuote; //line 547
}
Thank You
Larry Johnson |
|
| Back to top |
|
 |
Remy Lebeau (TeamB) Guest
|
Posted: Tue Mar 06, 2007 4:14 am Post subject: Re: Asynchronous Callback |
|
|
"LarryJ" <LarryJ33 (AT) austin (DOT) rr.com> wrote in message
news:45ec8b84$1 (AT) newsgroups (DOT) borland.com...
| Quote: | I don't know how to setup this call back function.
|
That depends on how the COM object implements its events to begin
with. Does it use connection points? Does it use a dispinterface?
Does it use a custom interface? It makes a big difference in how you
code for it.
Since you showed VB code that used the event, I'm quessing that it
uses a dispinterface, and maybe also connection points for non-VB
environments. Can you show what the type library actually contains
for that event?
| Quote: | The Borland wrapper has setup this as Hooks1QuoteChanged()
seen below. Processing this event will eventually throw an
exception
that points to a failure of the function
Hooks1->GetBasicQuote[sSymbol]; |
| Quote: | UTILCLS.H Line 154 where the exeption stops the code is the second
line
from the bottom that reads " throw msg; // Hopefully we never get
here:
Need something much better to throw!! "
|
You are not including ComObj.hpp to your code, so DebugHlpr_THROW will
not throw an EOleException (which you are trying to catch) but wil
throw a raw char* instead (which you are not catching at all).
Have you tried NOT using the wrapper method at all, but call the
interface method directly instead? Then you can do your own error
handling, ie:
void __fastcall TForm1::Hooks1QuoteChanged(TObject *Sender, BSTR
sSymbol)
{
Iesignal_tlb::BasicQuote quote;
if( SUCCEEDED(Hooks1->get_GetBasicQuote(sSymbol, "e)) )
{
AdvStringGrid2->Cells[8][2] = sSymbol;
AdvStringGrid2->Cells[8][3] = Format("%f", ARRAYOFCONST(
(quote.dLast)));
}
else
AdvStringGrid2->Cells[0][0]="FAIL";
}
Gambit |
|
| Back to top |
|
 |
Michael Harris Guest
|
Posted: Tue Mar 06, 2007 11:50 pm Post subject: Re: Asynchronous Callback |
|
|
"LarryJ" wrote in message
Couple of things I ned to know.
This looks like an ocx component wrapper class of type TOleControl.
'Hooks1QuoteChanged(TObject *Sender, BSTR sSymbol)'
is Sender the ole control ?
if so the ocx wrapper has something like
Def. Intf. Object: IxxxxDisp where xxxx is the interface identifier.
Later in the header you will find something like
// Default Interace of OCX
//
IxxxxDispm_OCXIntf;
Hooks1QuoteChanged(TObject *Sender, BSTR sSymbol)
{
Lock // custom , TCOMCriticleSection or OCXIntf->lock
process ...
UnLock
}
as far as ' I tried to manually duplicate the Borland
wrapper setup but that did not work. Can you show how I can setup this call
back.'
Yes, but it really depends on what you want to override.
The wrapper likely uses TAutoDriver<> OleProceedure to eventually call
OCXIntf::Invoke.(IDispatch::IVoke).
the wrapper code for the event interface looks something like
This is from ado just as a sample.
template <class T> HRESULT
TEvents_Connection<T>::Fire_ConnectComplete(Adodb_tlb::ErrorPtr pError,
Adodb_tlb::EventStatusEnum*
adStatus,
Adodb_tlb::_ConnectionPtr
pConnection)
{
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.ConnectComplete(pError, adStatus, pConnection);
m_EventIntfObj.Attach(0);
}
pp++;
}
pT->Unlock();
}
from the line
m_EventIntfObj.Attach(*pp);
this can be changed to the event interface in a hard cast if you like.
Depends on what you want to accomplish.
As someone mentioned.. You might just need to set COINT flags before the ocx
loads.
--
Michael |
|
| Back to top |
|
 |
LarryJ Guest
|
Posted: Wed Mar 07, 2007 1:47 am Post subject: Re: Asynchronous Callback |
|
|
| Quote: | You are not including ComObj.hpp to your code,
|
The file <comobj.hpp> is included in my project header. I have the
conditions NO_PROMPT_ON_HRCHECK_FAILURE and NO_PROMPT_ON_ASSERTE_FAILURE
added to the project options which affect the message boxes displayed. I
now removed these conditions.
| Quote: | Have you tried NOT using the wrapper method at all,
I have tried to call the function get_GetBasicQuote(...) directly and can |
make it compile in the try catch below. This function will run without an
exception if I do noting with the result from get_GetBasicQuote(). In this
case the CPU usage stays between 2%-10%. If I do anything with the result
like update a stringgrid as soon as there is a large amount of in coming
data the CPU usage will stay at 100% and the function get_GetBasicQuote()
will crash the same as when I use the Borland wrapper. In this case the two
popup messages HRCHECK and Debugger Exception Notification both occur before
my catch can handle the function failure.
try{ quote = Hooks1->get_GetBasicQuote(sSymbol);
}
catch(const Exception&){
AdvStringGrid2->Cells[0][0]="FAIL";
return;
}
I can not make get_GetBasicQuote() compile inside the SUCCEEDED() macro.
Below I show two setups inside the SUCCEEDED() and there error messages.
//Error 2227: Extra Parameter in get_GetBasicQuote(wchar_t*)
void __fastcall TForm1::Hooks1QuoteChanged(TObject *Sender, BSTR sSymbol)
{
Iesignal_tlb::BasicQuote quote;
if( SUCCEEDED(Hooks1->get_GetBasicQuote(sSymbol, "e)) )
{
}
}
//Error 2301: Can Not Cast From 'tagBasicQuote' to 'long'
void __fastcall TForm1::Hooks1QuoteChanged(TObject *Sender, BSTR sSymbol)
{
Iesignal_tlb::BasicQuote quote;
if( SUCCEEDED( quote = Hooks1->get_GetBasicQuote(sSymbol) ) )
{
}
}
| Quote: | That depends on how the COM object implements its events
I am not sure how the COM object is implemented. I have not had to dig into |
a COM object code this deep before. Below are all the occurances of the
get_GetBasicQuote() in the type library h file and the corresponding OCX.h
file.
\/\/\/\/\/\/\/\/\/\ From File IESignal_TLB.h \/\/\/\/\/\/\/\/\
// *********************************************************************//
// Interface: IHooks
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {C5916B45-A7EB-4919-A742-AD47AE3AE996}
// *********************************************************************//
interface IHooks : public IDispatch
{
public:
// [5] property GetBasicQuote
virtual HRESULT STDMETHODCALLTYPE get_GetBasicQuote(BSTR sSymbol,
Iesignal_tlb::BasicQuote*
pQuote/*[out,retval]*/) = 0;
Iesignal_tlb::BasicQuote __fastcall get_GetBasicQuote(BSTR sSymbol)
{
Iesignal_tlb::BasicQuote pQuote;
OLECHECK(this->get_GetBasicQuote(sSymbol,
(Iesignal_tlb::BasicQuote*)&pQuote));
return pQuote;
}
// *********************************************************************//
// SmartIntf: TCOMIHooks
// Interface: IHooks
// *********************************************************************//
template <class T /* IHooks */ >
class TCOMIHooksT : public TComInterface<IHooks>, public
TComInterfaceBase<IUnknown>
{
public:
HRESULT __fastcall get_GetBasicQuote(BSTR sSymbol,
Iesignal_tlb::BasicQuote*
pQuote/*[out,retval]*/);
Iesignal_tlb::BasicQuote __fastcall get_GetBasicQuote(BSTR sSymbol);
// *********************************************************************//
// DispIntf: IHooks
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {C5916B45-A7EB-4919-A742-AD47AE3AE996}
// *********************************************************************//
template<class T>
class IHooksDispT : public TAutoDriver<IHooks>
{
public:
HRESULT __fastcall get_GetBasicQuote(BSTR sSymbol,
/*AUTO_PARAM_ERROR(Iesignal_tlb::BasicQuote*
pQuote)*/ TVariant* pQuote);
// *********************************************************************//
// SmartIntf: TCOMIHooks
// Interface: IHooks
// *********************************************************************//
template <class T> HRESULT __fastcall
TCOMIHooksT<T>::get_GetBasicQuote(BSTR sSymbol, Iesignal_tlb::BasicQuote*
pQuote/*[out,retval]*/)
{
return (*this)->get_GetBasicQuote(sSymbol, pQuote);
}
template <class T> Iesignal_tlb::BasicQuote __fastcall
TCOMIHooksT<T>::get_GetBasicQuote(BSTR sSymbol)
{
Iesignal_tlb::BasicQuote pQuote;
OLECHECK(this->get_GetBasicQuote(, (Iesignal_tlb::BasicQuote*)&pQuote));
return pQuote;
}
// *********************************************************************//
// DispIntf: IHooks
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {C5916B45-A7EB-4919-A742-AD47AE3AE996}
// *********************************************************************//
template <class T> HRESULT __fastcall
IHooksDispT<T>::get_GetBasicQuote(BSTR sSymbol,
/*AUTO_PARAM_ERROR(Iesignal_tlb::BasicQuote*
pQuote)*/ TVariant* pQuote)
{
_TDispID _dispid(*this, OLETEXT("GetBasicQuote"), DISPID(5));
TAutoArgs<1> _args;
_args[1] = sSymbol /*[VT_BSTR:0]*/;
return OutRetValSetterPtr(pQuote /*[VT_USERDEFINED:1]*/, _args,
OlePropertyGet(_dispid, _args));
}
\/\/\/\/\/\/\/\/\/\ From File IESignal_OCX.h \/\/\/\/\/\/\/\/\
class PACKAGE THooks : public Oleserver::TOleServer
{
IHooksPtr m_DefaultIntf;
_di_IUnknown __fastcall GetDunk();
public:
__fastcall THooks(TComponent* owner) : Oleserver::TOleServer(owner)
{}
Iesignal_tlb::BasicQuote __fastcall get_GetBasicQuote(BSTR sSymbol)
{
return GetDefaultInterface()->get_GetBasicQuote(sSymbol);
}
__property Iesignal_tlb::BasicQuote GetBasicQuote[BSTR sSymbol]={
read=get_GetBasicQuote };
"Remy Lebeau (TeamB)" <no.spam (AT) no (DOT) spam.com> wrote in message
news:45ec9674$1 (AT) newsgroups (DOT) borland.com... |
|
| Back to top |
|
 |
Remy Lebeau (TeamB) Guest
|
Posted: Wed Mar 07, 2007 2:12 am Post subject: Re: Asynchronous Callback |
|
|
"LarryJ" <LarryJ33 (AT) austin (DOT) rr.com> wrote in message
news:45edc554$1 (AT) newsgroups (DOT) borland.com...
| Quote: | The file <comobj.hpp> is included in my project header.
|
But not before utilcls.h in included. If you look at
DebugHlpr_THROW(), it throws an EOleException if ComObj.hpp had
already been included before utilcls.h is compiled. But that is not
what you said is actually happening at runtime.
| Quote: | I have the conditions NO_PROMPT_ON_HRCHECK_FAILURE and
NO_PROMPT_ON_ASSERTE_FAILURE added to the project options
which affect the message boxes displayed. I now removed these
conditions. |
Which means that you are re-enabling the popup prompts that you wanted
to avoid.
| Quote: | I have tried to call the function get_GetBasicQuote(...) directly
and
can make it compile in the try catch below. This function will run
without an exception if I do noting with the result from
get_GetBasicQuote().
|
That was the whole point of my suggestion - doing your own error
checking manually. So you do not need the try..catch anymore in that
case.
| Quote: | In this case the CPU usage stays between 2%-10%. If I do anything
with the result like update a stringgrid as soon as there is a large
amount
of in coming data the CPU usage will stay at 100% and the function
get_GetBasicQuote() will crash the same as when I use the Borland
wrapper.
|
Then you are still doing something wrong in your own code. My guess
would be that the Quote object is not valid but you are not checking
for that condition.
| Quote: | In this case the two popup messages HRCHECK and Debugger
Exception Notification both occur before my catch can handle
the function failure.
|
As they should be, because you are running inside the debugger, which
is designed to process all exceptiosn before the code does. Simply
press F9 to passs the exception back to the code for normal handling.
| Quote: | quote = Hooks1->get_GetBasicQuote(sSymbol);
|
That is NOT calling the interface's get_GetBasicQuote() method
directly. That is calling Borland's wrapper method instead.
Interface methods always return an HRESULT, and return other values as
out parameters, ie:
TCOMIHooks TC;
HRESULT hr = TC.CreateInstance( CLSID_Hooks );
if( SUCCEEDED(hr) )
{
...
BasicQuote Quote;
hr = TC->get_GetBasicQuote(sSymbol, &Quote));
if( SUCCEEDED(hr) )
...
}
But since you are continuing to use Borland's wrapper component, you
will have to use the GetDefaultInterface() method whenever you want to
gain direct access to the interface, ie:
BasicQuote Quote;
hr = Hook1->GetDefaultInterface()->get_GetBasicQuote(sSymbol,
&Quote));
| Quote: | I can not make get_GetBasicQuote() compile inside the SUCCEEDED()
macro. |
Of course not, because you are not calling the interface's method
directly. You can't use SUCCEEDED with Borland's wrappers, because
they do not have HRESULT return values. They handle the HRESULT
values internally for you (the OLECHECK macro).
| Quote: | //Error 2227: Extra Parameter in get_GetBasicQuote(wchar_t*)
|
You are calling Borland's wrapper method, not the interface's method
directly.
| Quote: | //Error 2301: Can Not Cast From 'tagBasicQuote' to 'long'
|
You are trying to pass a BasicQuote to SUCCEEDED(), but it expects an
HRESULT instead.
| Quote: | I am not sure how the COM object is implemented.
|
I asked you before to show the actual contents of the Type Library.
You have not shown enough of it to know exactly what it is using.
Gambit |
|
| Back to top |
|
 |
LarryJ Guest
|
Posted: Wed Mar 07, 2007 4:26 am Post subject: Re: Asynchronous Callback |
|
|
I made my previous post confusing I am sorry for that. I am trying to NOT
use the Borland wrapper. I showed the Borland wrapper call-back named
OnQuoteChanged( ) because I don't know how else to show it. Here are the 4
steps I am trying to do. I can do all except Step 3 which is wait for the
Call-Back.. I don't know how to setup a call back. Below I have included
all the references to the Call-Back named OnQuoteChanged( ) from the type
library and OCX.
//Step 1: Create Object
TCOMIHooks TC;
HRESULT hr = TC.CreateInstance( CLSID_Hooks );
//Step 2: Tell The Server App I am Ready to Receive data
WideString sSymbol = "IBM";
TC->RequestSymbol(sSymbol, true);
//Step 3: Wait For Call-Back named OnQuoteChanged()
// I don't know how to setup this Call Back. The Borland wrapper sets this
up as a component event.
OnQuoteChanged( ){
}
//Step 4: When the Call-Back is Triggered call GetBasicQuote()
OnQuoteChanged( )
{
//Inside the Call-Back
BasicQuote Quote;
hr = TC->get_GetBasicQuote(sSymbol, &Quote));
if( SUCCEEDED(hr) ){
}
}
\/\/\/\/\/\/\/\/\/\/\/\/ IESignal_TLB.h \/\/\/\/\/\/\/\/\/\/\
// *********************************************************************//
// Interface: _IHooksEvents
// Flags: (4096) Dispatchable
// GUID: {3EBD5210-C4E9-4602-9268-20F0CB7B2584}
// *********************************************************************//
interface _IHooksEvents : public TDispWrapper<IDispatch>
{
HRESULT __fastcall OnQuoteChanged(BSTR sSymbol)
{
_TDispID _dispid(/* OnQuoteChanged */ DISPID(2));
TAutoArgs<1> _args;
_args[1] = sSymbol /*[VT_BSTR:0]*/;
return OleFunction(_dispid, _args);
}
// *********************************************************************//
// DispIntf: _IHooksEvents
// Flags: (4096) Dispatchable
// GUID: {3EBD5210-C4E9-4602-9268-20F0CB7B2584}
// *********************************************************************//
template <class T>
class _IHooksEventsDispT : public TAutoDriver<_IHooksEvents>
{
public:
_IHooksEventsDispT(){}
void Attach(LPUNKNOWN punk)
{ m_Dispatch = static_cast<T*>(punk); }
HRESULT __fastcall OnQuoteChanged(BSTR sSymbol);
// *********************************************************************//
// DispIntf: _IHooksEvents
// Flags: (4096) Dispatchable
// GUID: {3EBD5210-C4E9-4602-9268-20F0CB7B2584}
// *********************************************************************//
template <class T> HRESULT __fastcall
_IHooksEventsDispT<T>::OnQuoteChanged(BSTR sSymbol)
{
_TDispID _dispid(/* OnQuoteChanged */ DISPID(2));
TAutoArgs<1> _args;
_args[1] = sSymbol /*[VT_BSTR:0]*/;
return OleFunction(_dispid, _args);
}
// *********************************************************************//
// CONNECTIONPOINT/EVENT PROXY
// CoClass : Hooks
// Event Interface : _IHooksEvents
// *********************************************************************//
template <class T>
class TEvents_Hooks : public IConnectionPointImpl<T,
&DIID__IHooksEvents,
CComUnkArray<CONNECTIONPOINT_ARRAY_SIZE>
| Quote: |
/* Note: if encountering problems with events, please change CComUnkArray |
to CComDynamicUnkArray in the line above. */
{
public:
HRESULT Fire_OnQuoteChanged(BSTR sSymbol);
protected:
_IHooksEventsDisp m_EventIntfObj;
};
template <class T> HRESULT
TEvents_Hooks<T>::Fire_OnQuoteChanged(BSTR sSymbol)
{
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.OnQuoteChanged(sSymbol);
m_EventIntfObj.Attach(0);
}
pp++;
}
pT->Unlock();
}
\/\/\/\/\/\/\/\/\/\/\/\/ IESignal_OCX.h \/\/\/\/\/\/\/\/\/\/\
// *********************************************************************//
// COM Component Proxy Class Declaration
// Component Name : THooks
// Help String : Hooks Class
// Default Interface: IHooks
// Def. Intf. Object: IHooksPtr
// Def. Intf. DISP? : No
// Event Interface: _IHooksEvents
// TypeFlags : (2) CanCreate
// *********************************************************************//
typedef void __fastcall (__closure * THooksOnQuoteChanged)(System::TObject *
Sender,
BSTR sSymbol);
class PACKAGE THooks : public Oleserver::TOleServer
{
IHooksPtr m_DefaultIntf;
_di_IUnknown __fastcall GetDunk();
public:
__fastcall THooks(TComponent* owner) : Oleserver::TOleServer(owner)
{}
private:
THooksOnQuoteChanged FOnQuoteChanged;
__published:
__property THooksOnQuoteChanged OnQuoteChanged={ read=FOnQuoteChanged,
write=FOnQuoteChanged };
};
Thank you very much again
Larry Johnson
"Remy Lebeau (TeamB)" <no.spam (AT) no (DOT) spam.com> wrote in message
news:45edcb27$1 (AT) newsgroups (DOT) borland.com...
> |
|
| Back to top |
|
 |
Michael Harris Guest
|
Posted: Wed Mar 07, 2007 4:58 am Post subject: Re: Asynchronous Callback |
|
|
"LarryJ" wrote in message
| Quote: |
The file <comobj.hpp> is included in my project header. I have the
conditions NO_PROMPT_ON_HRCHECK_FAILURE and NO_PROMPT_ON_ASSERTE_FAILURE
added to the project options which affect the message boxes displayed. I
now removed these conditions.
|
go to the IDE menu. Project > Options [tab] directories/conditionals.
add these to 'conditional defines'
NO_PROMPT_ON_HRCHECK_FAILURE
NO_PROMPT_ON_ASSERTE_FAILURE
| Quote: | Have you tried NOT using the wrapper method at all,
I have tried to call the function get_GetBasicQuote(...) directly and can
make it compile in the try catch below. This function will run without an
exception if I do noting with the result from get_GetBasicQuote(). In
this case the CPU usage stays between 2%-10%. If I do anything with the
result like update a stringgrid as soon as there is a large amount of in
coming data the CPU usage will stay at 100% and the function
get_GetBasicQuote() will crash the same as when I use the Borland wrapper.
In this case the two
|
I went to the doctor once.. doc it hurts when I do this.. oh........
| Quote: | CPU usage will stay at 100%
happens everytime COM thrading tries to interact with windowed controls. |
The error is likely do to reentering the function before the grid updates...
you have several options as I mentioned.
A ) edit your file with= TForm1::Hooks1QuoteChanged
paste below utilcls.h
namespace /* GlobalThreadSys */ { // added for editing dataset while
flushbuffer is called..
static TCOMCriticalSection g_ThreadLock;
class DataLock // auto un / lock
{
public:
DataLock(void)
{ TCOMCriticalSection::Lock Lock(g_ThreadLock);
};
virtual ~DataLock(void)
{ TCOMCriticalSection::Lock Unlock(g_ThreadLock);
};
};
void __fastcall TForm1::Hooks1QuoteChanged(TObject *Sender, BSTR sSymbol)
{
DataLock Lock;
Iesignal_tlb::BasicQuote quote;
if( SUCCEEDED(Hooks1->get_GetBasicQuote(sSymbol, "e)) )
{
process ......
}
}
};
A will slow things down a bit.. but should cure your problem.
B ) make a mail system...
use a vector or map to store sSymbol, "e
TForm1::Hooks1QuoteChanged
update the vector.
use the applications->Onidle message event handler to process pending items.
B should fix it, but will not tell you what the issue was to start with.
If I had to bet. I think I would go with the Callback thread re-entering
TForm1::Hooks1QuoteChanged before the stringgrid updates are complete.
| Quote: | I am not sure how the COM object is implemented. I have not had to dig into
a COM object code this deep before. Below are all the occurances of the
get_GetBasicQuote() in the type library h file and the corresponding OCX.h
|
TAutoDriver or OleProcedure.
Try the above. If that doesn't work, we can go 'old school' to fix it.
--
Michael |
|
| Back to top |
|
 |
LarryJ Guest
|
Posted: Wed Mar 07, 2007 4:59 am Post subject: Re: Asynchronous Callback |
|
|
Michael,
Thanks for looking at this. I am making a ActiveX function call that returns
values through a callback so my app must monitor for the callback to be
triggered. For a different program I created the callback below which uses
a registered Windows massage. I believe I have to setup something like this
for the COM object callback named OnQuoteChanged( ) but I am not sure this
new callback should be setup. The Borland wrapper sets the callback up as a
component event but I am NOT using the Borland wrapper. Below are all the
references to the callback named OnQuoteChanged( ) in the type library and
OCX file which I believe is what you described in your previous post. Can
you see how I might set up this new callback in my program.
//>>>>>>>>>>>>>>>>>
s_wmPortfolioListComplete =
RegisterWindowMessage("PORTFOLIO_LIST_COMPLETE");
LRESULT CALLBACK NewWindowProc(HWND hWnd, UINT msg, WPARAM w, LPARAM l)
{
if(msg == s_wmPortfolioListComplete){
...
}
}
//>>>>>>>>>>>>>>>>>
In my project header I do have #include <comobj.hpp> on top of #include
<utilcls.h> which I believe is correct.
#include <vcl.h>
#include <comobj.hpp>
#include <utilcls.h>
Here are the four basic steps I am performing with the COM object.
//Step 1: Create Object
TCOMIHooks TC;
HRESULT hr = TC.CreateInstance( CLSID_Hooks );
//Step 2: Tell The Server App I am Ready to Receive data
WideString sSymbol = "IBM";
TC->RequestSymbol(sSymbol, true);
//Step 3: Wait For Call-Back named OnQuoteChanged()
// I don't know how to setup this Call Back.
OnQuoteChanged( ){
}
//Step 4: When the Call-Back is Triggered call GetBasicQuote()
OnQuoteChanged( )
{
//Inside the Call-Back
BasicQuote Quote;
hr = TC->get_GetBasicQuote(sSymbol, &Quote));
if( SUCCEEDED(hr) ){
}
}
\/\/\/\/\/\/\/\/\/\/\/\/ IESignal_TLB.h \/\/\/\/\/\/\/\/\/\/\
// *********************************************************************//
// Interface: _IHooksEvents
// Flags: (4096) Dispatchable
// GUID: {3EBD5210-C4E9-4602-9268-20F0CB7B2584}
// *********************************************************************//
interface _IHooksEvents : public TDispWrapper<IDispatch>
{
HRESULT __fastcall OnQuoteChanged(BSTR sSymbol)
{
_TDispID _dispid(/* OnQuoteChanged */ DISPID(2));
TAutoArgs<1> _args;
_args[1] = sSymbol /*[VT_BSTR:0]*/;
return OleFunction(_dispid, _args);
}
// *********************************************************************//
// DispIntf: _IHooksEvents
// Flags: (4096) Dispatchable
// GUID: {3EBD5210-C4E9-4602-9268-20F0CB7B2584}
// *********************************************************************//
template <class T>
class _IHooksEventsDispT : public TAutoDriver<_IHooksEvents>
{
public:
_IHooksEventsDispT(){}
void Attach(LPUNKNOWN punk)
{ m_Dispatch = static_cast<T*>(punk); }
HRESULT __fastcall OnQuoteChanged(BSTR sSymbol);
// *********************************************************************//
// DispIntf: _IHooksEvents
// Flags: (4096) Dispatchable
// GUID: {3EBD5210-C4E9-4602-9268-20F0CB7B2584}
// *********************************************************************//
template <class T> HRESULT __fastcall
_IHooksEventsDispT<T>::OnQuoteChanged(BSTR sSymbol)
{
_TDispID _dispid(/* OnQuoteChanged */ DISPID(2));
TAutoArgs<1> _args;
_args[1] = sSymbol /*[VT_BSTR:0]*/;
return OleFunction(_dispid, _args);
}
// *********************************************************************//
// CONNECTIONPOINT/EVENT PROXY
// CoClass : Hooks
// Event Interface : _IHooksEvents
// *********************************************************************//
template <class T>
class TEvents_Hooks : public IConnectionPointImpl<T,
&DIID__IHooksEvents,
CComUnkArray<CONNECTIONPOINT_ARRAY_SIZE>
| Quote: |
/* Note: if encountering problems with events, please change CComUnkArray |
to CComDynamicUnkArray in the line above. */
{
public:
HRESULT Fire_OnQuoteChanged(BSTR sSymbol);
protected:
_IHooksEventsDisp m_EventIntfObj;
};
template <class T> HRESULT
TEvents_Hooks<T>::Fire_OnQuoteChanged(BSTR sSymbol)
{
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.OnQuoteChanged(sSymbol);
m_EventIntfObj.Attach(0);
}
pp++;
}
pT->Unlock();
}
\/\/\/\/\/\/\/\/\/\/\/\/ IESignal_OCX.h \/\/\/\/\/\/\/\/\/\/\
// *********************************************************************//
// COM Component Proxy Class Declaration
// Component Name : THooks
// Help String : Hooks Class
// Default Interface: IHooks
// Def. Intf. Object: IHooksPtr
// Def. Intf. DISP? : No
// Event Interface: _IHooksEvents
// TypeFlags : (2) CanCreate
// *********************************************************************//
typedef void __fastcall (__closure * THooksOnQuoteChanged)(System::TObject *
Sender,
BSTR sSymbol);
class PACKAGE THooks : public Oleserver::TOleServer
{
IHooksPtr m_DefaultIntf;
_di_IUnknown __fastcall GetDunk();
public:
__fastcall THooks(TComponent* owner) : Oleserver::TOleServer(owner)
{}
private:
THooksOnQuoteChanged FOnQuoteChanged;
__published:
__property THooksOnQuoteChanged OnQuoteChanged={ read=FOnQuoteChanged,
write=FOnQuoteChanged };
};
"Michael Harris" <techonos-NO-SPAM-@attbi.com> wrote in message
news:45eda9d3$1 (AT) newsgroups (DOT) borland.com... |
|
| Back to top |
|
 |
Remy Lebeau (TeamB) Guest
|
Posted: Wed Mar 07, 2007 5:31 am Post subject: Re: Asynchronous Callback |
|
|
"LarryJ" <LarryJ33 (AT) austin (DOT) rr.com> wrote in message
news:45edeac7$1 (AT) newsgroups (DOT) borland.com...
| Quote: | Here are the 4 steps I am trying to do. I can do all except Step 3
which is wait for the Call-Back.. I don't know how to setup a call
back. |
The Type Library does provide the callback as a connection point. To
help with the IConnectionPointContainer management, you can derive a
new class from the VCL's TEventDispatcher class, override the
InvokeEvent() method to look for DISPID 2, then connect an instance of
that class to the COM object at runtime. For example:
#include <utilcls.h>
#include "IESignal_TLB.h"
class TMyHooksEvents : public TEventDispatcher<TMyHooksEvents,
&DIID__IHooksEvents>
{
private:
IHooks *pHooks;
protected:
virtual HRESULT InvokeEvent(DISPID id, TVariant* params = 0)
{
if( id == 2 )
{
BasicQuote Quote;
hr = pHooks->get_GetBasicQuote(V_BSTR(¶ms[0]),
&Quote));
if( SUCCEEDED(hr) )
{
...
}
}
return S_OK;
}
public:
TMyHooksEvents() : pHooks(NULL) {}
~TMyHooksEvents() { Disconnect(); }
void Connect(IHooks *server)
{
Disconnect();
pHooks = server;
if( pHooks )
{
pHooks->AddRef();
ConnectEvents(server);
}
}
void Disconnect()
{
if( pHooks )
{
DisconnectEvents(pHooks);
pHooks->Release();
pHooks = NULL;
}
}
};
{
TCOMIHooks TC;
TMyHooksEvents Events;
TC.CreateInstance(CLSID_Hooks);
Events.Connect(TC);
TC->RequestSymbol(WideString("IBM"), true);
...
}
Gambit |
|
| Back to top |
|
 |
Remy Lebeau (TeamB) Guest
|
Posted: Wed Mar 07, 2007 5:32 am Post subject: Re: Asynchronous Callback |
|
|
"LarryJ" <LarryJ33 (AT) austin (DOT) rr.com> wrote in message
news:45edf24f$1 (AT) newsgroups (DOT) borland.com...
| Quote: | I am making a ActiveX function call that returns values through a
callback so my app must monitor for the callback to be triggered.
|
See my other reply for a code example.
Gambit |
|
| Back to top |
|
 |
Michael Harris Guest
|
Posted: Wed Mar 07, 2007 6:00 am Post subject: Re: Asynchronous Callback |
|
|
"LarryJ" wrote in message
| Quote: | Can you see how I might set up this new callback in my program.
Not in 25 words or less<g |
You would need to write a class derived from IDispatch , TEventDispatcher or
_IHooksEvents.
Normally we use TEventDispatcher::Connect to connect.
other options are.
connect the class to TC events via Advise or the utlcls helpers
HRESULT COMHlpr_ConnectEvents(REFIID eventsIID, IUnknown* server, IUnknown*
sink, DWORD &cookie);
HRESULT COMHlpr_DisconnectEvents(REFIID eventsIID, IUnknown* server, DWORD
&cookie);
using TEventDispatcher would be something like.
1) write the event class
TEventDispatcher would be something like... // this class
DIID of event interface
class TCHooksEventsHandler : TEventDispatcher<TCHooksEventsHandler ,
&DIID__IHooksEvents>
{
private:
LPUNKNOWN m_pServer; // Unk_Outer
protected:
//overloaded from TEventDispatcher.
//
HRESULT InvokeEvent(DISPID id, TVariant *params)
{
// here it gets tricky.. note: DISPID in the header.. they will
pass thru here.
// _TDispID _dispid(/* OnQuoteChanged */ DISPID(2));
// be sure and note the params if any
switch(id)
{
case 2:
// convert params to the desired type. you might redo the
_closure typedef to use ansistring so conversion is only done once.
if(OnQuoteChanged) OnQuoteChanged(param_as_bstr)
break;
};
public:
TCHooksEventsHandler () : m_pServer (0) , OnQuoteChanged (0)
{
};
virtual ~TCHooksEventsHandler () {}
HRESULT Connect(LPUNKNOWN ppvServer)
{
if (m_pServer) return E_POINTER; // alread in use
m_pServer = ppvServer;
return ConnectEvents(m_pServer); // from TEventDispatcher
};
HRESULT Disconnect()
{
if(m_pServer) return DisconnectEvents(m_pServer);
return E_INTERFACE
};
// place to communicate
THooksOnQuoteChanged OnQuoteChanged;
};
2 ) in Form1 for example.
** add a method to form one matching the functor sig.
void __fastcall Form1::HooksOnQuoteChanged)(System::TObject *Sender, BSTR
sSymbol)
{
};
** create an instance of the class.
TCHooksEventsHandler * EventsHandler = new TCHooksEventsHandler ;
** assign the thunk.
EventsHandler -> OnQuoteChanged = Form1 -> HooksOnQuoteChanged
** connect to the server event dispatcher.<connection point>
EventsHandler -> Connect(TC)
** now do step 2
/Step 2: Tell The Server App I am Ready to Receive data
WideString sSymbol = "IBM";
TC->RequestSymbol(sSymbol, true);
all done .......
** disconnect
EventsHandler -> OnQuoteChanged = 0;
EventsHandler -> Disconnect()
--
Michael |
|
| Back to top |
|
 |
Michael Harris Guest
|
Posted: Wed Mar 07, 2007 6:02 am Post subject: Re: Asynchronous Callback |
|
|
ok, so Remmy types faster than I do <g>
--
Michael |
|
| Back to top |
|
 |
|
|
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
|
|