USB Monitoring Control - ActiveX Component Library for USB Data Monitoring, API for Software Developers
Download USB Monitoring Control Hide this button

Processing Sequence

This section describes the library's data processing sequence. Whenever a new data packet is captured by the USBMC, the following occurs:

  1. Library calls the INativeListener.ProcessRAWBuffer method of each registered native listener. The full data buffer is passed to the listener. A data buffer may contain several URB packets. It is listener's responsibility to separate and process them. If the listener sets the bStopParsing parameter to TRUE, no further processing is performed on this data buffer by the library.

  2. If none of native listeners deny the further processing, raw data is parsed. After that, for each URB in the buffer, USBMC calls INativeListener.OnPacketDown or INativeListener.OnPacketUp (_IMonitoringEvents.OnPacketDown or _IMonitoringEvents.OnPacketUp). Native listener can set the bStopParsing parameter to TRUE to stop further processing of each individual URB.

  3. USBMC parses the packet and calls the appropriate methods of the INativeListener or _IMonitoringEvents interfaces, depending on the type of the packet.

The following is a pseudo-code of library's data processing pipeline:

// pData is a pointer to data chunk, received from driver
void ProcessBuffer(void* pData, DWORD dwDataSize)
{
	// for each client
	for(...)
	{
		// this step is for NATIVE clients only 
		pClient->ProcessRawBuffer(...);
	}
		
	for (USBPACKET* packet=(USBPACKET *) pData, *stop=(USBPACKET*) ((BYTE *) pData + dwSize);
		packet < stop && packet->Size;
        (BYTE*&) packet+=packet->Size)
	{
		// for each client
		for(...)
		{
			if(packet->Flags & UPF_DOWN)
				pClient->OnPacketDown(...);
			else
				pClient->OnPacketUp(...);

			switch(packet->EventType)
			{
			case EVENT_URB:
				{
				// parsing urb here
				USBPACKET_URB* pUrb = (USBPACKET_URB *)pPacket;
				BYTE* pUrbData = ...;
				DWORD dwUrbSize = ...;
				pClient->OnUrb(pUrbData,dwUrbSize);

				switch (pUrb->urb.UrbHeader.Function)
				{
				case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
					pClient->OnGetDescriptorFromDevice();
					break;
				// ... 
				}

				break;
				}
			case EVENT_DEVICECONNECTED:
				pClient->OnConnection(...);
				break;
			// ... 
			}
		}
	}
};

Let's take a [OnGetDescriptorFromInterface] method as an example.

USBMC uses URB_CONTROL_DESCRIPTOR_REQUEST structure to get the data from a URB packet. Native listener has the following signature for OnGetDescriptorFromInterface method:

HRESULT OnGetDescriptorFromInterface (FILETIME *fTime, void* pData, ULONG Size,
    BYTE Index, BYTE DescriptorType, USHORT LanguageId);

pData points to the packet that has a type USBPACKET and can be cast to USBPACKET_URB. So, native client can manually parse this packet and extract fields it needs. Besides USBMC automatically decodes and provides several packet fields, such as Index, DescriptorType and LanguageId.

Manual parsing can be implemented in C++ in this way:

USBPACKET_URB* pUrb = (USBPACKET_URB*) pData;
_URB_CONTROL_DESCRIPTOR_REQUEST &r = pUrb->urb.UrbControlDescriptorRequest;
// use r variable here
```CPP

Please note that managed (dispatched) interface has a different method signature, without `pData` and `Size`:

```CPP
OnGetDescriptorFromInterface([in] DATE time,
    [in] BYTE Index, [in] BYTE DescriptorType, [in] USHORT LanguageId);

Nevertheless, several managed callback methods (such as _IMonitoringEvents.OnPacketDown, _IMonitoringEvents.OnPacketUp and _IMonitoringEvents.OnUrb) receive raw data by means of a safe array, allowing them to manually parse data.