_IAnalyzerEvents dispinterface
In order to retrieve the events from the USB Protocol Suite application, you must implement the _IAnalyzerEvents interface.
Since this interface is the default source interface for the UsbAnalyzer object, there is a very simple implementation from such languages as Visual Basic, VBA, VBScript, WSH, etc.
C++ implementation used in the examples below implements a sink object by deriving it from IDispEventImpl but not specifying the type library as a template argument. Instead, the type library and default source interface for the object are determined using AtlGetObjectSourceInterface(). A SINK_ENTRY() macro is used for each event from each source interface which is to be handled:
class CAnalyzerSink : public IDispEventImpl<IDC_SRCOBJ, CAnalyzerSink>
{
BEGIN_SINK_MAP(CAnalyzerSink)
//Make sure the Event Handlers have __stdcall calling convention
SINK_ENTRY(IDC_SRCOBJ, 1, OnTraceCreated)
SINK_ENTRY(IDC_SRCOBJ, 2, OnStatusReport)
END_SINK_MAP()
. . .
}
Then, after you establish the connection with the server, you need to advise your implementation of the event interface:
hr = CoCreateInstance( CLSID_UsbAdvisor, NULL,
CLSCTX_SERVER, IID_IUsbAnalyzer, (LPVOID *)&m_poUsbAnalyzer );
m_poAnalyzerSink = new CAnalyzerSink();
// Make sure the COM object corresponding to pUnk implements IProvideClassInfo2 or
// IPersist*. Call this method to extract info about source type library if you
// specified only 2 parameters to IDispEventImpl
hr = AtlGetObjectSourceInterface(m_poUsbAnalyzer, &m_poAnalyzerSink->m_libid,
&m_poAnalyzerSink->m_iid, &m_poAnalyzerSink->m_wMajorVerNum,
&m_poAnalyzerSink->m_wMinorVerNum);
if ( FAILED(hr) )
return 1;
// connect the sink and source, m_poUsbAnalyzer is the source COM object
hr = m_poAnalyzerSink->DispEventAdvise(m_poUsbAnalyzer, &m_poAnalyzerSink->m_iid);
if ( FAILED(hr) )
return 1;
_IAnalyzerEvents::OnTraceCreated
HRESULT OnTraceCreated (
[in] IDispatch* trace );
Fired when a trace is created. This event is a result of an IAnalyzer::StartRecording or IAnalyzer::StopRecording method call.
|
Parameters |
|
|---|---|
|
trace |
Address of a pointer to the UsbTrace object primary interface. |
Remarks
Make sure the event handlers have __stdcall calling convention.
Example: VBScript
<OBJECT
ID = Analyzer
CLASSID = "clsid:0B179BB3-DC61-11d4-9B71-000102566088" >
</OBJECT>
<P ALIGN=LEFT ID=StatusText></P>
<SCRIPT LANGUAGE="VBScript">
<!--
Dim CurrentTrace
Sub Analyzer_OnTraceCreated(ByRef Trace)
On Error Resume Next
Set CurrentTrace = Trace
If Err.Number <> 0 Then
MsgBox Err.Number & ":" & Err.Description
End If
StatusText.innerText = "Trace '" & CurrentTrace.GetName & "' created"
End Sub
-->
</SCRIPT>
Example: C++
HRESULT __stdcall OnTraceCreated( IDispatch* trace )
{
IUsbTrace* usb_trace;
HRESULT hr;
hr = trace->QueryInterface( IID_IUsbTrace, (void**)&usb_trace );
if (FAILED(hr))
{
_com_error er(hr);
if (er.Description().length() > 0)
::MessageBox( NULL, er.Description(), _T("UsbAnalyzer client"), MB_OK );
else
::MessageBox( NULL, er.ErrorMessage(),_T("UsbAnalyzer client"), MB_OK );
return hr;
}
. . .
return hr;
}
_IAnalyzerEvents::OnStatusReport
HRESULT OnStatusReport (
[in] short subsystem,
[in] short state,
[in] long percent_done );
Fires when there is a change in Analyzer state or there is a change in progress (percent_done) of the Analyzer state.
|
Parameters |
|
||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
subsystem |
Subsystem sending event has the following values: RECORDING_PROGRESS_REPORT ( 1 ) – recording subsystem GENERATION_PROGRESS_REPORT ( 2 ) – recording subsystem |
||||||||||||||||||||||||
|
state |
Current Analyzer state; has the following possible values:
|
||||||||||||||||||||||||
|
percent_done |
Shows the progress of currently performing operation (valid only if subsystem is RECORDING_PROGRESS_REPORT):
|
||||||||||||||||||||||||
Remarks
Make sure the event handlers have __stdcall calling convention.
Example: VBScript
<OBJECT
ID = Analyzer
CLASSID = "clsid:0B179BB3-DC61-11d4-9B71-000102566088" >
</OBJECT>
<P ALIGN=LEFT ID=StatusText></P>
<SCRIPT LANGUAGE="VBScript">
<!--
Function GetRecordingStatus(ByVal State, ByVal Percent)
Select Case State
Case -1: GetRecordingStatus = "Idle"
Case 0: GetRecordingStatus = "Recording - Waiting for trigger"
Case 1: GetRecordingStatus = "Recording - Triggered"
Case 2: GetRecordingStatus = "Uploading"
Case 3: GetRecordingStatus = "Saving Data"
Case Else: GetRecordingStatus = "Invalid recording status"
End Select
GetRecordingStatus = GetRecordingStatus & ", " & Percent & "% done"
End Function
Dim RecordingStatus
Sub Analyzer_OnStatusReport(ByVal System, ByVal State, ByVal Percent)
Select Case System
Case 1 RecordingStatus = GetRecordingStatus( State, Percent )
End Select
End Sub
-->
</SCRIPT>
Example: C++
#define RECORDING_PROGRESS_REPORT ( 1 )
#define ANALYZERSTATE_IDLE ( -1 )
#define ANALYZERSTATE_WAITING_TRIGGER ( 0 )
#define ANALYZERSTATE_RECORDING_TRIGGERED ( 1 )
#define ANALYZERSTATE_UPLOADING_DATA ( 2 )
#define ANALYZERSTATE_SAVING_DATA ( 3 )
HRESULT __stdcall OnStatusReport( short subsystem, short state, long percent_done )
{
switch ( subsystem )
{
case RECORDING_PROGRESS_REPORT:
UpdateRecStatus( state, percent_done );
break;
}
TCHAR buf[1024];
_stprintf( buf, _T("%s"), m_RecordingStatus );
::SetWindowText( m_hwndStatus, buf );
return S_OK;
}
void UpdateRecStatus( short state, long percent_done )
{
TCHAR status_buf[64];
switch ( state )
{
case ANALYZERSTATE_IDLE:
_tcscpy( status_buf, _T("Idle") );
break;
case ANALYZERSTATE_WAITING_TRIGGER:
_tcscpy( status_buf, _T("Recording - Waiting for trigger") );
break;
case ANALYZERSTATE_RECORDING_TRIGGERED:
_tcscpy( status_buf, _T("Recording - Triggered") );
break;
case ANALYZERSTATE_UPLOADING_DATA:
_tcscpy( status_buf, _T("Uploading") );
break;
case ANALYZERSTATE_SAVING_DATA:
_tcscpy( status_buf, _T("Saving data") );
break;
default:
_tcscpy( status_buf, _T("Unknown") );
break;
}
_stprintf( m_RecordingStatus, _T("%s, done %ld%%"), status_buf, percent_done );