You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
831 lines
18 KiB
831 lines
18 KiB
/*++
|
|
|
|
Copyright (c) 1998-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
vcint.cpp
|
|
|
|
Abstract:
|
|
|
|
This module contains virtual channel interface routines.
|
|
|
|
Author:
|
|
|
|
madan appiah (madana) 16-Sep-1998
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precom.h"
|
|
|
|
#define TRC_FILE "vcint"
|
|
|
|
#include "cclip.h"
|
|
#include "vcint.h"
|
|
#include "rdpdrcom.h"
|
|
#include "drdbg.h"
|
|
#include "rdpsndc.h"
|
|
|
|
VOID
|
|
VCAPITYPE
|
|
RDPDR_InitEventFnEx(
|
|
IN PVOID lpUserParam,
|
|
IN PVOID pInitHandle,
|
|
IN UINT event,
|
|
IN PVOID pData,
|
|
IN UINT dataLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles InitEvent callbacks by delegating to the connection manager.
|
|
|
|
Arguments:
|
|
|
|
- pInitHandle - a handle uniquely identifying this connection
|
|
- event - the event that has occurred - see CHANNEL_EVENT_XXX defines
|
|
- pData - data associated with the event - see CHANNEL_EVENT_XXX defines
|
|
- dataLength - length of the data.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
CRDPSound *pSound = NULL;
|
|
|
|
DC_BEGIN_FN("InitEventFn");
|
|
|
|
ASSERT(lpUserParam != NULL);
|
|
|
|
if(!lpUserParam)
|
|
{
|
|
return;
|
|
}
|
|
|
|
VCManager* pVCMgr = (VCManager*)lpUserParam;
|
|
ASSERT(pVCMgr != NULL);
|
|
if(!pVCMgr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
CClip* pClip = pVCMgr->GetClip();
|
|
|
|
ASSERT(pClip != NULL);
|
|
if(!pClip)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pVCMgr->ChannelInitEvent(pInitHandle, event, pData, dataLength);
|
|
|
|
pClip->ClipInitEventFn(pInitHandle, event, pData, dataLength);
|
|
|
|
if ( pVCMgr->GetInitData()->fEnableRedirectedAudio )
|
|
{
|
|
pSound = pVCMgr->GetSound();
|
|
if ( NULL != pSound )
|
|
{
|
|
pSound->InitEventFn( pInitHandle, event, pData, dataLength );
|
|
}
|
|
}
|
|
|
|
if(CHANNEL_EVENT_TERMINATED == event)
|
|
{
|
|
//CLEANUP
|
|
pSound = pVCMgr->GetSound();
|
|
if ( NULL != pSound )
|
|
delete pSound;
|
|
|
|
delete pVCMgr;
|
|
delete pClip;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
VCAPITYPE
|
|
RDPDR_OpenEventFn(
|
|
IN LPVOID lpUserParam,
|
|
IN ULONG openHandle,
|
|
IN UINT event,
|
|
IN PVOID pData,
|
|
IN UINT32 dataLength,
|
|
IN UINT32 totalLength,
|
|
IN UINT32 dataFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles OpenEvent callbacks by delegating to the connection manager.
|
|
|
|
Arguments:
|
|
|
|
openHandle - a handle uniquely identifying this channel
|
|
event - event that has occurred - see CHANNEL_EVENT_XXX below
|
|
pData - data received
|
|
dataLength - length of the data
|
|
totalLength - total length of data written by the Server
|
|
dataFlags - flags, zero, one or more of:
|
|
- 0x01 - beginning of data from a single write operation at the Server
|
|
- 0x02 - end of data from a single write operation at the Server.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DC_BEGIN_FN("OpenEventFn");
|
|
|
|
TRC_NRM((TB, _T("Event %x, handle %lx, datalength %ld, dataFlags %lx"),
|
|
event, openHandle, dataLength, dataFlags));
|
|
|
|
ASSERT(lpUserParam != NULL);
|
|
if(!lpUserParam)
|
|
{
|
|
return;
|
|
}
|
|
|
|
((VCManager*)lpUserParam)->ChannelOpenEvent(openHandle, event, pData, dataLength,
|
|
totalLength, dataFlags);
|
|
|
|
DC_END_FN();
|
|
return;
|
|
}
|
|
|
|
#ifdef OS_WIN32
|
|
BOOL DCAPI
|
|
#else //OS_WIN32
|
|
BOOL __loadds DCAPI
|
|
#endif //OS_WIN32
|
|
|
|
RDPDR_VirtualChannelEntryEx(
|
|
IN PCHANNEL_ENTRY_POINTS_EX pEntryPoints,
|
|
IN PVOID pInitHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Exported API called by the Virtual Channels
|
|
|
|
Arguments:
|
|
|
|
pEntryPoints - Entry point structure containing all callback methods.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL rv = FALSE;
|
|
VCManager* pcmMgr = NULL;
|
|
CClip* pClip = NULL;
|
|
CRDPSound *pSound = NULL;
|
|
CHANNEL_DEF aChannel[3];
|
|
UINT uiRet;
|
|
PCHANNEL_INIT_HANDLE pChanInitHandle;
|
|
PRDPDR_DATA pRdpDrInitSettings;
|
|
|
|
DC_BEGIN_FN("VirtualChannelEntry");
|
|
|
|
if( pEntryPoints->cbSize < sizeof(CHANNEL_ENTRY_POINTS_EX) ) {
|
|
|
|
//
|
|
// we don't have all entry points we need.
|
|
//
|
|
goto exitpt;
|
|
}
|
|
|
|
pChanInitHandle = (PCHANNEL_INIT_HANDLE)pInitHandle;
|
|
pRdpDrInitSettings = (PRDPDR_DATA)pChanInitHandle->lpInternalAddinParam;
|
|
ASSERT(pRdpDrInitSettings);
|
|
|
|
if(!pRdpDrInitSettings)
|
|
{
|
|
goto exitpt;
|
|
}
|
|
|
|
pcmMgr = new VCManager(pEntryPoints);
|
|
pRdpDrInitSettings->pUpdateDeviceObj = pcmMgr;
|
|
|
|
if( pcmMgr == NULL ) {
|
|
goto exitpt;
|
|
}
|
|
|
|
pcmMgr->SetInitData( pRdpDrInitSettings);
|
|
|
|
pClip = new CClip(pcmMgr);
|
|
|
|
if( pClip == NULL ) {
|
|
goto exitpt;
|
|
}
|
|
|
|
pcmMgr->SetClip( pClip);
|
|
pClip->SetVCInitHandle( pInitHandle);
|
|
|
|
pSound = new CRDPSound( pEntryPoints, pInitHandle );
|
|
if ( NULL == pSound ) {
|
|
goto exitpt;
|
|
}
|
|
pcmMgr->SetSound( pSound );
|
|
|
|
if (!pClip->ClipChannelEntry(pEntryPoints)) {
|
|
TRC_ALT((TB, _T("Clip rejected VirtualChannelEntry")));
|
|
goto exitpt;
|
|
}
|
|
|
|
memset(aChannel[0].name, 0, CHANNEL_NAME_LEN);
|
|
memcpy(aChannel[0].name, PRDR_VC_CHANNEL_NAME, strlen(PRDR_VC_CHANNEL_NAME));
|
|
|
|
aChannel[0].options = CHANNEL_OPTION_COMPRESS_RDP;
|
|
|
|
memset(aChannel[1].name, 0, CHANNEL_NAME_LEN);
|
|
memcpy(aChannel[1].name, CLIP_CHANNEL, sizeof(CLIP_CHANNEL));
|
|
aChannel[1].options = CHANNEL_OPTION_ENCRYPT_RDP |
|
|
CHANNEL_OPTION_COMPRESS_RDP |
|
|
CHANNEL_OPTION_SHOW_PROTOCOL;
|
|
|
|
memset( aChannel[2].name, 0, CHANNEL_NAME_LEN );
|
|
memcpy( aChannel[2].name, _SNDVC_NAME, sizeof( _SNDVC_NAME ));
|
|
aChannel[2].options = CHANNEL_OPTION_ENCRYPT_RDP;
|
|
|
|
uiRet = (pEntryPoints->pVirtualChannelInitEx)(pcmMgr,
|
|
pInitHandle,
|
|
aChannel,
|
|
3,
|
|
VIRTUAL_CHANNEL_VERSION_WIN2000,
|
|
RDPDR_InitEventFnEx);
|
|
|
|
TRC_NRM((TB, _T("VirtualChannelInit rc[%d]"), uiRet));
|
|
|
|
if( uiRet != CHANNEL_RC_OK ) {
|
|
goto exitpt;
|
|
}
|
|
|
|
rv = TRUE;
|
|
|
|
exitpt:
|
|
if ( !rv )
|
|
{
|
|
if ( NULL != pClip )
|
|
delete pClip;
|
|
|
|
if ( NULL != pSound )
|
|
delete pSound;
|
|
|
|
if ( NULL != pcmMgr )
|
|
delete pcmMgr;
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return(rv);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------*/
|
|
|
|
VCManager::VCManager(
|
|
IN PCHANNEL_ENTRY_POINTS_EX pEntries
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initilizes the system, and determines which processor to load for
|
|
the given operating system.
|
|
|
|
Arguments:
|
|
|
|
Id - Connection Id
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DC_BEGIN_FN("VCManager::VCManager");
|
|
|
|
_bState = STATE_UNKNOWN;
|
|
_ChannelEntries = *pEntries;
|
|
|
|
_pProcObj = NULL;
|
|
_hVCHandle = NULL;
|
|
_Buffer.uiLength = _Buffer.uiAvailLen = 0;
|
|
_Buffer.pbData = NULL;
|
|
_hVCOpenHandle = 0;
|
|
|
|
//_pRdpDrInitSettings receives settings from the core
|
|
_pRdpDrInitSettings = NULL;
|
|
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
VOID
|
|
VCManager::ChannelWrite(
|
|
IN LPVOID pData,
|
|
IN UINT uiLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Abstracts writing data to the channel for the processing components
|
|
|
|
If the write should fail, this function releases the outgoing buffer.
|
|
|
|
Arguments:
|
|
|
|
pData - Data to be written
|
|
uiLength - Length of data to write
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("VCManager::ChannelWrite");
|
|
TRC_NRM((TB, _T("Data[%p] Length[%d]"), pData, uiLength));
|
|
|
|
#if DBG
|
|
if( !IsValidHeader(pData) ) {
|
|
TRC_ERR((TB, _T("Sending an invalid dr header")));
|
|
}
|
|
#endif // DBG
|
|
|
|
UINT uiRet;
|
|
|
|
uiRet = (_ChannelEntries.pVirtualChannelWriteEx)( _hVCHandle,
|
|
_hVCOpenHandle,
|
|
pData,
|
|
uiLength,
|
|
(PVOID)pData);
|
|
|
|
TRC_NRM((TB, _T("VirtualChannelWrite Ret [%d]"), uiRet));
|
|
|
|
switch (uiRet) {
|
|
case CHANNEL_RC_OK:
|
|
break;
|
|
|
|
case CHANNEL_RC_NOT_INITIALIZED:
|
|
ASSERT(FALSE);
|
|
break;
|
|
|
|
case CHANNEL_RC_NOT_CONNECTED:
|
|
{
|
|
//Valid to receive this because we can be getting
|
|
//disconnected on another thread
|
|
TRC_ALT((TB,_T("Write failed with CHANNEL_RC_NOT_CONNECTED")));
|
|
}
|
|
break;
|
|
|
|
case CHANNEL_RC_BAD_CHANNEL_HANDLE:
|
|
ASSERT(FALSE);
|
|
break;
|
|
|
|
case CHANNEL_RC_NULL_DATA:
|
|
ASSERT(FALSE);
|
|
break;
|
|
|
|
case CHANNEL_RC_ZERO_LENGTH:
|
|
ASSERT(FALSE);
|
|
break;
|
|
|
|
default:
|
|
TRC_ALT((TB, _T("Unknown return value for VirtualChannelWrite[%d]\n"), uiRet));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Release the buffer on failure.
|
|
//
|
|
if (uiRet != CHANNEL_RC_OK) {
|
|
delete []((BYTE *)pData);
|
|
}
|
|
|
|
DC_END_FN();
|
|
return;
|
|
}
|
|
|
|
UINT
|
|
VCManager::ChannelWriteEx(
|
|
IN LPVOID pData,
|
|
IN UINT uiLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Abstracts writing data to the channel for the processing components.
|
|
This version returns the return value back
|
|
|
|
If this function fails the buffer is released.
|
|
|
|
Arguments:
|
|
|
|
pData - Data to be written
|
|
uiLength - Length of data to write
|
|
|
|
Return Value:
|
|
|
|
CHANNEL_RC_OK
|
|
CHANNEL_RC_NOT_INITIALIZED
|
|
CHANNEL_RC_NOT_CONNECTED
|
|
CHANNEL_RC_BAD_CHANNEL_HANDLE
|
|
CHANNEL_RC_NULL_DATA
|
|
CHANNEL_RC_ZERO_LENGTH
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("VCManager::ChannelWriteEx");
|
|
TRC_NRM((TB, _T("Data[%p] Length[%d]"), pData, uiLength));
|
|
|
|
#if DBG
|
|
if( !IsValidHeader(pData) ) {
|
|
TRC_ERR((TB, _T("Sending an invalid dr header")));
|
|
}
|
|
#endif // DBG
|
|
|
|
UINT uiRet;
|
|
|
|
uiRet = (_ChannelEntries.pVirtualChannelWriteEx)( _hVCHandle,
|
|
_hVCOpenHandle,
|
|
pData,
|
|
uiLength,
|
|
(PVOID)pData);
|
|
|
|
if (uiRet != CHANNEL_RC_OK) {
|
|
TRC_NRM((TB, _T("VirtualChannelWrite Ret [%d]"), uiRet));
|
|
delete []((BYTE *)pData);
|
|
}
|
|
|
|
return uiRet;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Closes the virtual channel
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
CHANNEL_RC_OK on Success - see VirtualChannelClose docs in MSDN
|
|
|
|
--*/
|
|
UINT
|
|
VCManager::ChannelClose()
|
|
{
|
|
UINT uiRet;
|
|
|
|
DC_BEGIN_FN("ChannelClose");
|
|
|
|
uiRet = (_ChannelEntries.pVirtualChannelCloseEx)( _hVCHandle,
|
|
_hVCOpenHandle);
|
|
|
|
if (uiRet != CHANNEL_RC_OK) {
|
|
TRC_ERR((TB, _T("VirtualChannelClose Ret [%d]"), uiRet));
|
|
}
|
|
|
|
DC_END_FN();
|
|
return uiRet;
|
|
}
|
|
|
|
VOID
|
|
VCManager::ChannelInitEvent(
|
|
IN PVOID pInitHandle,
|
|
IN UINT uiEvent,
|
|
IN PVOID pData,
|
|
IN UINT uiDataLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles InitEvent callbacks
|
|
|
|
Arguments:
|
|
|
|
pInitHandle - a handle uniquely identifying this connection
|
|
|
|
uiEvent - the event that has occurred - see CHANNEL_EVENT_XXX defines
|
|
|
|
pData - data associated with the event - see CHANNEL_EVENT_XXX defines
|
|
|
|
uiDataLength - length of the data.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DC_BEGIN_FN("VCManager::ChannelInitEvent");
|
|
|
|
UNREFERENCED_PARAMETER( pData );
|
|
UNREFERENCED_PARAMETER( uiDataLength );
|
|
|
|
UINT uiRetVal;
|
|
|
|
TRC_NRM((TB, _T("Event %d, handle %p"), uiEvent, pInitHandle));
|
|
|
|
if (_hVCHandle == NULL)
|
|
_hVCHandle = pInitHandle;
|
|
|
|
switch (uiEvent) {
|
|
case CHANNEL_EVENT_INITIALIZED :
|
|
|
|
ASSERT(_bState == STATE_UNKNOWN);
|
|
|
|
_bState = CHANNEL_EVENT_INITIALIZED;
|
|
break;
|
|
|
|
case CHANNEL_EVENT_CONNECTED :
|
|
|
|
ASSERT((_bState == CHANNEL_EVENT_INITIALIZED) ||
|
|
(_bState == CHANNEL_EVENT_DISCONNECTED));
|
|
|
|
//
|
|
// Create the platform-specific Processing instance
|
|
//
|
|
TRC_NRM((TB, _T("VCManager::ChannelnitEvent: Creating processor.")));
|
|
_pProcObj = ProcObj::Instantiate(this);
|
|
|
|
if( _pProcObj == NULL ) {
|
|
TRC_NRM((TB, _T("Error creating processor.")));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Initialize the proc obj instance
|
|
//
|
|
uiRetVal = (UINT) _pProcObj->Initialize();
|
|
|
|
if( uiRetVal != ERROR_SUCCESS ) {
|
|
delete _pProcObj;
|
|
_pProcObj = NULL;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Open the virtual channel interface.
|
|
//
|
|
uiRetVal =
|
|
(_ChannelEntries.pVirtualChannelOpenEx)(
|
|
_hVCHandle,
|
|
&_hVCOpenHandle,
|
|
PRDR_VC_CHANNEL_NAME,
|
|
&RDPDR_OpenEventFn);
|
|
|
|
TRC_NRM((TB, _T("VirtualChannelOpen Ret[%d]"), uiRetVal));
|
|
|
|
_bState = CHANNEL_EVENT_CONNECTED;
|
|
|
|
break;
|
|
|
|
case CHANNEL_EVENT_V1_CONNECTED :
|
|
ASSERT((_bState == CHANNEL_EVENT_INITIALIZED) ||
|
|
(_bState == CHANNEL_EVENT_DISCONNECTED));
|
|
|
|
_bState = CHANNEL_EVENT_V1_CONNECTED;
|
|
break;
|
|
|
|
case CHANNEL_EVENT_DISCONNECTED :
|
|
//ASSERT((_bState == CHANNEL_EVENT_CONNECTED) ||
|
|
// (_bState == CHANNEL_EVENT_V1_CONNECTED));
|
|
|
|
if (_pProcObj) {
|
|
delete _pProcObj;
|
|
_pProcObj = NULL;
|
|
}
|
|
|
|
_bState = CHANNEL_EVENT_DISCONNECTED;
|
|
break;
|
|
|
|
case CHANNEL_EVENT_TERMINATED :
|
|
/*
|
|
DbgAssert((_bState == CHANNEL_EVENT_DISCONNECTED) ||
|
|
(_bState == CHANNEL_EVENT_V1_CONNECTED) ||
|
|
(_bState == CHANNEL_EVENT_INITIALIZED),
|
|
("_bState[%d] is in inproper position to be TERMINATED",
|
|
_bState));
|
|
*/
|
|
|
|
if (_pProcObj) {
|
|
delete _pProcObj;
|
|
_pProcObj = NULL;
|
|
}
|
|
|
|
_bState = CHANNEL_EVENT_TERMINATED;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
TRC_ALT((TB, _T("Unknown Event in ChannelInitEvent recieved[%d]\n"),
|
|
uiEvent));
|
|
|
|
break;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
VCManager::ChannelOpenEvent(
|
|
IN ULONG ulOpenHandle,
|
|
IN UINT uiEvent,
|
|
IN PVOID pData,
|
|
IN UINT32 uiDataLength,
|
|
IN UINT32 uiTotalLength,
|
|
IN UINT32 uiDataFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handles OpenEvent callbacks
|
|
|
|
Arguments:
|
|
|
|
ulOpenHandle - a handle uniquely identifying this channel
|
|
uiEvent - event that has occurred - see CHANNEL_EVENT_XXX below
|
|
pData - data received
|
|
uiDataLength - length of the data
|
|
uiTotalLength - total length of data written by the Server
|
|
uiDataFlags - flags, zero, one or more of:
|
|
- 0x01 - beginning of data from a single write operation at the Server
|
|
- 0x02 - end of data from a single write operation at the Server.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("VCManager::ChannelOpenEvent");
|
|
|
|
TRC_NRM((TB, _T("Event[0x%x], uiDataLength[%ld], uiDataFlags[0x%lx]"),
|
|
uiEvent, uiDataLength, uiDataFlags));
|
|
|
|
ASSERT(ulOpenHandle == _hVCOpenHandle);
|
|
|
|
//
|
|
// not for us, simply return.
|
|
//
|
|
|
|
if( ulOpenHandle != _hVCOpenHandle ) {
|
|
return;
|
|
}
|
|
|
|
ASSERT(uiDataLength <= uiTotalLength);
|
|
|
|
//
|
|
// total length much less, give up.
|
|
//
|
|
|
|
if( uiDataLength > uiTotalLength ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// free data buffer on write complete.
|
|
//
|
|
|
|
if ((uiEvent == CHANNEL_EVENT_WRITE_COMPLETE) ||
|
|
(uiEvent == CHANNEL_EVENT_WRITE_CANCELLED)) {
|
|
|
|
delete []((BYTE *)pData);
|
|
TRC_NRM((TB, _T("VCManager::ChannelOpenEvent:S:WriteComplete")));
|
|
return;
|
|
}
|
|
|
|
ASSERT(uiEvent == CHANNEL_EVENT_DATA_RECEIVED);
|
|
|
|
//
|
|
// alocated new buffer for incoming data.
|
|
//
|
|
|
|
if( (uiDataFlags == CHANNEL_FLAG_FIRST) ||
|
|
(uiDataFlags == CHANNEL_FLAG_ONLY) ) {
|
|
|
|
TRC_NRM((TB, _T("Allocating %ld bytes"), uiTotalLength));
|
|
|
|
_Buffer.pbData = new BYTE[uiTotalLength];
|
|
|
|
if( _Buffer.pbData == NULL ) {
|
|
TRC_ERR((TB,_T("_Buffer.pbData is NULL")));
|
|
return;
|
|
}
|
|
|
|
_Buffer.uiLength = 0;
|
|
_Buffer.uiAvailLen = uiTotalLength;
|
|
}
|
|
|
|
if( _Buffer.pbData == NULL ) {
|
|
TRC_ERR((TB,_T("_Buffer.pbData is NULL")));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// copy first part of the data in the buffer.
|
|
//
|
|
|
|
if (uiDataFlags == CHANNEL_FLAG_FIRST) {
|
|
|
|
TRC_NRM((TB, _T("CHANNEL_FLAG_FIRST Creating:[%ld]"), uiTotalLength));
|
|
|
|
memcpy(_Buffer.pbData, pData, uiDataLength);
|
|
_Buffer.uiLength = uiDataLength;
|
|
|
|
TRC_NRM((TB, _T("VCManager::ChannelOpenEvent[1]")));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// add data to the buffer.
|
|
//
|
|
|
|
UINT32 uiLen;
|
|
uiLen = _Buffer.uiLength + uiDataLength;
|
|
ASSERT(_Buffer.uiAvailLen >= uiLen);
|
|
|
|
//
|
|
// too much data arrived.
|
|
//
|
|
|
|
if( _Buffer.uiAvailLen < uiLen ) {
|
|
TRC_ERR((TB,_T("Too much data arrived: avail:0x%x arrived:0x%x"),
|
|
_Buffer.uiAvailLen, uiLen));
|
|
|
|
//
|
|
// Disconnect the channel
|
|
//
|
|
ChannelClose();
|
|
return;
|
|
}
|
|
|
|
memcpy( _Buffer.pbData + _Buffer.uiLength, pData, uiDataLength );
|
|
_Buffer.uiLength = uiLen;
|
|
|
|
if (uiDataFlags == CHANNEL_FLAG_MIDDLE) {
|
|
TRC_NRM((TB, _T("VCManager::ChannelOpenEvent[2]")));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// complete data buffer available, process it.
|
|
//
|
|
|
|
_pProcObj->ProcessServerPacket(&_Buffer);
|
|
|
|
DC_END_FN();
|
|
return;
|
|
}
|
|
|
|
void
|
|
VCManager::OnDeviceChange(WPARAM wParam, LPARAM lParam)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Receive a device change notification from the control.
|
|
Pass it to the proc obj to handle.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (_pProcObj != NULL) {
|
|
_pProcObj->OnDeviceChange(wParam, lParam);
|
|
}
|
|
}
|
|
|