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.
1348 lines
33 KiB
1348 lines
33 KiB
/*++
|
|
* File name:
|
|
* queues.c
|
|
* Contents:
|
|
* Supports the linked lists for the clients
|
|
* and events
|
|
* Two linked lists:
|
|
* g_pClientQHead - list of all clients running within smclient
|
|
* g_pWaitQHead - all events we are waiting for from smclient
|
|
*
|
|
* Copyright (C) 1998-1999 Microsoft Corp.
|
|
--*/
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <malloc.h>
|
|
#include <process.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
|
|
#include "tclient.h"
|
|
#include "protocol.h"
|
|
#include "gdata.h"
|
|
#include "bmpcache.h"
|
|
|
|
/*
|
|
*
|
|
* ClientQ functions
|
|
*
|
|
*/
|
|
|
|
/*++
|
|
* Function:
|
|
* _AddToClientQ
|
|
* Description:
|
|
* Adds a client on the top of the list
|
|
* Arguments:
|
|
* pClient - the client context
|
|
* Called by:
|
|
* SCConnect
|
|
--*/
|
|
VOID _AddToClientQ(PCONNECTINFO pClient)
|
|
{
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
pClient->pNext = g_pClientQHead;
|
|
g_pClientQHead = pClient;
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _RemoveFromClientQ
|
|
* Description:
|
|
* Removes a client context from the list
|
|
* Arguments:
|
|
* pClient - the client context
|
|
* Return value:
|
|
* TRUE on success
|
|
* Called by:
|
|
* SCDisconnect
|
|
--*/
|
|
BOOL _RemoveFromClientQ(PCONNECTINFO pClient)
|
|
{
|
|
PCONNECTINFO pIter, pPrev = NULL;
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pClientQHead;
|
|
while (pIter && pIter != pClient) {
|
|
pPrev = pIter;
|
|
pIter = pIter->pNext;
|
|
}
|
|
|
|
if (pIter) {
|
|
if (!pPrev) g_pClientQHead = pIter->pNext;
|
|
else pPrev->pNext = pIter->pNext;
|
|
|
|
pIter->pNext = NULL;
|
|
}
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
return (pIter != NULL);
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _SetClientDead
|
|
* Description:
|
|
* Marks a client context as dead
|
|
* Arguments:
|
|
* dwClientProcessId - ID for the client process
|
|
* Return value:
|
|
* TRUE on success
|
|
* Called by:
|
|
* _FeedbackWndProc within feedback thread
|
|
--*/
|
|
BOOL _SetClientDead(LONG_PTR lClientProcessId)
|
|
{
|
|
PCONNECTINFO pIter;
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pClientQHead;
|
|
while (pIter && pIter->lProcessId != lClientProcessId)
|
|
{
|
|
pIter = pIter->pNext;
|
|
}
|
|
|
|
if (pIter) pIter->dead = TRUE;
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
return (pIter != NULL);
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _ReplaceProcessId
|
|
* Description:
|
|
* the client notifys that the control is in anther process
|
|
* we have to close the old handles and open handles to
|
|
* the new pid
|
|
*
|
|
* Arguments:
|
|
* lOldPid - the old pid
|
|
* lNewPid - the pid to replace with
|
|
* Return value:
|
|
* TRUE on success
|
|
* Called by:
|
|
* _FeedbackWndProc within feedback thread
|
|
--*/
|
|
BOOL
|
|
_ReplaceProcessId(
|
|
LONG_PTR lOldPid,
|
|
LONG_PTR lNewPid
|
|
)
|
|
{
|
|
BOOL rv = FALSE;
|
|
HANDLE hNewProcess = NULL;
|
|
PCONNECTINFO pIter;
|
|
PWAIT4STRING pWait;
|
|
|
|
hNewProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE,
|
|
PtrToLong((PVOID) lNewPid ));
|
|
|
|
if ( NULL == hNewProcess )
|
|
{
|
|
TRACE((ERROR_MESSAGE, "_ReplaceProcessId: can't open a handle to "
|
|
"the new process. GetLastError=%d\n", GetLastError()));
|
|
goto exitpt;
|
|
}
|
|
|
|
//
|
|
// find the entry with the old process id
|
|
//
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pClientQHead;
|
|
while (pIter && pIter->lProcessId != lOldPid)
|
|
{
|
|
pIter = pIter->pNext;
|
|
}
|
|
|
|
if ( NULL == pIter )
|
|
{
|
|
TRACE((WARNING_MESSAGE, "_ReplaceProcessId: can't find old pid\n" ));
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
goto exitpt;
|
|
}
|
|
|
|
if ( NULL != pIter->hProcess )
|
|
CloseHandle( pIter->hProcess );
|
|
|
|
if ( NULL != pIter->hThread )
|
|
CloseHandle( pIter->hThread );
|
|
|
|
pIter->lProcessId = lNewPid;
|
|
pIter->hProcess = hNewProcess;
|
|
pIter->hThread = 0;
|
|
|
|
//
|
|
// process all waiters
|
|
//
|
|
pWait = g_pWaitQHead;
|
|
while(pWait)
|
|
{
|
|
if (pWait->lProcessId == lOldPid)
|
|
pWait->lProcessId = lNewPid;
|
|
|
|
pWait = pWait->pNext;
|
|
}
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
rv = TRUE;
|
|
|
|
exitpt:
|
|
if ( !rv && NULL != hNewProcess )
|
|
CloseHandle( hNewProcess );
|
|
|
|
return rv;
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _CheckIsAcceptable
|
|
* Description:
|
|
* Checks if we can accept feedback from this RDP client
|
|
* i.e. if this client is member of the client queue
|
|
* Arguments:
|
|
* dwProcessId - clients process Id
|
|
* Return value:
|
|
* Pointer to connection context. NULL if not found
|
|
* Called by:
|
|
* _FeedbackWndProc within feedback thread
|
|
--*/
|
|
PCONNECTINFO _CheckIsAcceptable(LONG_PTR lProcessId, BOOL bRClxType)
|
|
{
|
|
PCONNECTINFO pIter;
|
|
|
|
UNREFERENCED_PARAMETER(bRClxType);
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pClientQHead;
|
|
while(pIter &&
|
|
(pIter->lProcessId != lProcessId
|
|
#ifdef _RCLX
|
|
|| pIter->RClxMode != bRClxType
|
|
#endif // _RCLX
|
|
))
|
|
{
|
|
pIter = pIter->pNext;
|
|
}
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
return (pIter);
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _AddStrToClientBuffer
|
|
* Description:
|
|
* Add a string to the clients history buffer
|
|
* When smclient calls Wait4Str it first checks that buffer
|
|
* Arguments:
|
|
* str - the string
|
|
* dwProcessId - the client process Id
|
|
* Called by:
|
|
* _CheckForWaitingWorker
|
|
--*/
|
|
VOID _AddStrToClientBuffer(LPCWSTR str, LONG_PTR lProcessId)
|
|
{
|
|
PCONNECTINFO pIter;
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pClientQHead;
|
|
while(pIter && pIter->lProcessId != lProcessId)
|
|
{
|
|
pIter = pIter->pNext;
|
|
}
|
|
|
|
if (pIter)
|
|
{
|
|
INT_PTR strsize = wcslen(str);
|
|
if (strsize >= MAX_STRING_LENGTH) strsize = MAX_STRING_LENGTH-1;
|
|
|
|
wcsncpy( pIter->Feedback[pIter->nFBend],
|
|
str,
|
|
strsize);
|
|
pIter->Feedback[pIter->nFBend][strsize] = 0;
|
|
|
|
pIter->nFBend++;
|
|
pIter->nFBend %= FEEDBACK_SIZE;
|
|
if (pIter->nFBsize < FEEDBACK_SIZE)
|
|
pIter->nFBsize++;
|
|
|
|
}
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
}
|
|
|
|
/*
|
|
*
|
|
* WaitQ functions
|
|
*
|
|
*/
|
|
|
|
/*++
|
|
* Function:
|
|
* _AddToWaitQNoCheck
|
|
* Description:
|
|
* Adds an waiting event to the list with checking in the history list
|
|
* Arguments:
|
|
* pCI - client context
|
|
* pWait - the event
|
|
* Called by:
|
|
* RegisterChat
|
|
--*/
|
|
VOID _AddToWaitQNoCheck(PCONNECTINFO pCI, PWAIT4STRING pWait)
|
|
{
|
|
ASSERT(pCI);
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
pWait->pNext = g_pWaitQHead;
|
|
g_pWaitQHead = pWait;
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _AddToWaitQueue
|
|
* Description:
|
|
* Add an event to the list. If the event is waiting for string(s)
|
|
* the history buffer is checked first
|
|
* Arguments:
|
|
* pCI - client context
|
|
* pWait - the event
|
|
* Called by:
|
|
* _WaitSomething
|
|
--*/
|
|
VOID _AddToWaitQueue(PCONNECTINFO pCI, PWAIT4STRING pWait)
|
|
{
|
|
BOOL bDone = FALSE;
|
|
int i, strn;
|
|
|
|
ASSERT(pCI);
|
|
|
|
// exit if we are dead
|
|
if (
|
|
#ifdef _RCLX
|
|
!pWait->waitstr[0] &&
|
|
#endif // _RCLX
|
|
pCI->dead)
|
|
{
|
|
SetEvent(pWait->evWait);
|
|
goto exitpt;
|
|
}
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
// Check if we're already received this feedback
|
|
if (pWait->WaitType == WAIT_STRING)
|
|
// look if the string already came
|
|
for(i = 0; !bDone && i < pCI->nFBsize; i++)
|
|
{
|
|
|
|
strn = (FEEDBACK_SIZE + pCI->nFBend - i - 1) % FEEDBACK_SIZE;
|
|
|
|
if (!pCI->Feedback[strn][0]) continue;
|
|
bDone = (wcsstr(pCI->Feedback[strn], pWait->waitstr) != NULL);
|
|
}
|
|
// In case of waiting multiple strings
|
|
else if (pWait->WaitType == WAIT_MSTRINGS)
|
|
{
|
|
for(i = 0; !bDone && i < pCI->nFBsize; i++)
|
|
{
|
|
WCHAR *wszComp = pWait->waitstr;
|
|
WCHAR *wszLast = pWait->waitstr + pWait->strsize;
|
|
int idx = 0;
|
|
|
|
strn = (FEEDBACK_SIZE + pCI->nFBend - i - 1) % FEEDBACK_SIZE;
|
|
|
|
if (!pCI->Feedback[strn][0]) continue;
|
|
while (wszComp < wszLast && *wszComp && !bDone)
|
|
{
|
|
if (wcsstr(pCI->Feedback[strn], wszComp))
|
|
{
|
|
int j;
|
|
// Save the string
|
|
for(j = 0; wszComp[j]; j++)
|
|
pCI->szWait4MultipleStrResult[j] = (char)wszComp[j];
|
|
// and the index
|
|
|
|
pCI->szWait4MultipleStrResult[j] = 0;
|
|
|
|
pCI->nWait4MultipleStrResult = idx;
|
|
bDone = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Advance to next string
|
|
wszComp += wcslen(wszComp) + 1;
|
|
idx ++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (pWait->WaitType == WAIT_CLIPBOARD
|
|
#ifdef _RCLX
|
|
&&
|
|
pWait->pOwner->bRClxClipboardReceived
|
|
#endif // _RCLX
|
|
)
|
|
{
|
|
bDone = TRUE;
|
|
}
|
|
else if (pWait->WaitType == WAIT_DATA
|
|
#ifdef _RCLX
|
|
&&
|
|
pWait->pOwner->pRClxDataChain
|
|
#endif // _RCLX
|
|
)
|
|
{
|
|
bDone = TRUE;
|
|
}
|
|
|
|
// The string (or anything else) is in the history list
|
|
// Set the event
|
|
if (bDone)
|
|
{
|
|
SetEvent(pWait->evWait);
|
|
pCI->nFBsize = pCI->nFBend = 0;
|
|
}
|
|
pWait->pNext = g_pWaitQHead;
|
|
g_pWaitQHead = pWait;
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
exitpt:
|
|
;
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _RemoveFromWaitQueue
|
|
* Description:
|
|
* Removes an event from the list
|
|
* Arguments:
|
|
* pWait - the event
|
|
* Return value:
|
|
* TRUE if the event is found and removed
|
|
* Called by:
|
|
* _WaitSomething, _RemoveFromWaitQIndirect
|
|
--*/
|
|
BOOL _RemoveFromWaitQueue(PWAIT4STRING pWait)
|
|
{
|
|
PWAIT4STRING pIter, pPrev = NULL;
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pWaitQHead;
|
|
while (pIter && pIter != pWait) {
|
|
pPrev = pIter;
|
|
pIter = pIter->pNext;
|
|
}
|
|
|
|
if (pIter) {
|
|
if (!pPrev) g_pWaitQHead = pIter->pNext;
|
|
else pPrev->pNext = pIter->pNext;
|
|
|
|
pIter->pNext = NULL;
|
|
}
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
return (pIter != NULL);
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _RemoveFromWaitQIndirect
|
|
* Description:
|
|
* Same as _RemoveFromWaitQueue but identifies the event
|
|
* by client context and waited string
|
|
* Arguments:
|
|
* pCI - the client context
|
|
* lpszWait4 - the string
|
|
* Return value:
|
|
* the event
|
|
* Called by:
|
|
* UnregisterChat
|
|
--*/
|
|
PWAIT4STRING _RemoveFromWaitQIndirect(PCONNECTINFO pCI, LPCWSTR lpszWait4)
|
|
{
|
|
PWAIT4STRING pIter;
|
|
|
|
ASSERT(pCI);
|
|
|
|
// Search the list
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pWaitQHead;
|
|
while (pIter &&
|
|
(pIter->pOwner != pCI ||
|
|
wcscmp(pIter->waitstr, lpszWait4))
|
|
)
|
|
pIter = pIter->pNext;
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
if (pIter)
|
|
{
|
|
_RemoveFromWaitQueue(pIter);
|
|
}
|
|
|
|
return pIter;
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _RetrieveFromWaitQByEvent
|
|
* Description:
|
|
* Searches the waiting list by event handler
|
|
* Arguments:
|
|
* hEvent - the handler
|
|
* Return value:
|
|
* The event structure
|
|
* Called by:
|
|
* _WaitSomething when responds on chat sequence
|
|
--*/
|
|
PWAIT4STRING _RetrieveFromWaitQByEvent(HANDLE hEvent)
|
|
{
|
|
PWAIT4STRING pIter;
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pWaitQHead;
|
|
while (pIter &&
|
|
pIter->evWait != hEvent)
|
|
pIter = pIter->pNext;
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
return pIter;
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _RetrieveFromWaitQByOwner
|
|
* Description:
|
|
* Searches the waiting list by owner record
|
|
* Arguments:
|
|
* pCI - pointer to the owner context
|
|
* Return value:
|
|
* The event structure
|
|
* Called by:
|
|
* RClx_MsgReceived
|
|
--*/
|
|
PWAIT4STRING
|
|
_RetrieveFromWaitQByOwner(PCONNECTINFO pCI)
|
|
{
|
|
PWAIT4STRING pIter;
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pWaitQHead;
|
|
while (pIter &&
|
|
pIter->pOwner != pCI)
|
|
pIter = pIter->pNext;
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
return pIter;
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _FlushFromWaitQ
|
|
* Description:
|
|
* Flush everithing that we are waiting for from the list
|
|
* the client is going to DIE
|
|
* Arguments:
|
|
* pCI - client context
|
|
* Called by:
|
|
* _CloseConnectInfo
|
|
--*/
|
|
VOID _FlushFromWaitQ(PCONNECTINFO pCI)
|
|
{
|
|
PWAIT4STRING pIter, pPrev, pNext;
|
|
|
|
ASSERT(pCI);
|
|
|
|
pPrev = NULL;
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pWaitQHead;
|
|
do {
|
|
while (pIter && pIter->pOwner != pCI) {
|
|
pPrev = pIter;
|
|
pIter = pIter->pNext;
|
|
}
|
|
|
|
if (pIter) {
|
|
if (!pPrev) g_pWaitQHead = pIter->pNext;
|
|
else pPrev->pNext = pIter->pNext;
|
|
|
|
pNext = pIter->pNext;
|
|
pIter->pNext = NULL;
|
|
|
|
// Important stuff
|
|
if (pIter->evWait)
|
|
{
|
|
CloseHandle(pIter->evWait);
|
|
pIter->evWait = NULL;
|
|
}
|
|
|
|
free(pIter);
|
|
|
|
pIter = pNext;
|
|
}
|
|
} while (pIter);
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _CheckForWaitingWorker
|
|
* Description:
|
|
* Check the received string against the waited events
|
|
* Arguments:
|
|
* wszFeed - the received string
|
|
* dwProcessId - Id of the sender
|
|
* Return value:
|
|
* TRUE if an event is found and signaled
|
|
* Called by:
|
|
* _TextOutReceived, _GlyphReceived
|
|
--*/
|
|
BOOL _CheckForWaitingWorker(LPCWSTR wszFeed, LONG_PTR lProcessId)
|
|
{
|
|
PWAIT4STRING pIter;
|
|
BOOL bRun;
|
|
CHAR szBuff[ MAX_STRING_LENGTH ];
|
|
CHAR *szPBuff;
|
|
DWORD dwBuffLen;
|
|
LPCWSTR wszPFeed;
|
|
|
|
//
|
|
// Apply translation if specified
|
|
//
|
|
if ( g_bTranslateStrings )
|
|
{
|
|
UINT i;
|
|
UINT j;
|
|
UINT_PTR len;
|
|
LPWSTR szStr2;
|
|
|
|
len = wcslen( wszFeed );
|
|
__try {
|
|
szStr2 = (LPWSTR) _alloca( (len+1)*sizeof( *szStr2 ) );
|
|
}
|
|
__except ((GetExceptionCode() == STATUS_STACK_OVERFLOW)?
|
|
EXCEPTION_EXECUTE_HANDLER:
|
|
EXCEPTION_CONTINUE_SEARCH)
|
|
{
|
|
_resetstkoflw();
|
|
szStr2 = NULL;
|
|
}
|
|
|
|
if ( NULL == szStr2 )
|
|
return FALSE;
|
|
|
|
for ( i = 0, j = 0; i < len + 1; j += (szStr2[j] != L' ')?1:0, i++ )
|
|
{
|
|
if ( wszFeed[i] >= 3 && wszFeed[i] < 0x63 )
|
|
{
|
|
szStr2[j] = wszFeed[i] + L' ' - 3;
|
|
} else {
|
|
szStr2[j] = wszFeed[i];
|
|
}
|
|
}
|
|
wszFeed = szStr2;
|
|
}
|
|
|
|
if ( NULL != g_pfnPrintMessage )
|
|
{
|
|
|
|
wszPFeed = wszFeed;
|
|
while ( *wszPFeed )
|
|
{
|
|
if ( (unsigned short)(*wszPFeed) > 0xff )
|
|
break;
|
|
|
|
wszPFeed ++;
|
|
}
|
|
|
|
if ( *wszPFeed )
|
|
{
|
|
szBuff[0] = '\\';
|
|
szBuff[1] = 'u';
|
|
szPBuff = szBuff + 2;
|
|
wszPFeed = wszFeed;
|
|
dwBuffLen = MAX_STRING_LENGTH - 3;
|
|
|
|
while ( 4 <= dwBuffLen &&
|
|
0 != *wszPFeed)
|
|
{
|
|
DWORD dwLen;
|
|
|
|
if ( dwBuffLen < 4 )
|
|
break;
|
|
|
|
dwLen = _snprintf( szPBuff, dwBuffLen + 1, "%02x",
|
|
(BYTE)((*wszPFeed) & 0xff ));
|
|
szPBuff += dwLen;
|
|
dwBuffLen -= dwLen;
|
|
|
|
dwLen = _snprintf( szPBuff, dwBuffLen + 1, "%02x",
|
|
(BYTE)(((*wszPFeed) >> 8) & 0xff ));
|
|
szPBuff += dwLen;
|
|
dwBuffLen -= dwLen;
|
|
|
|
wszPFeed ++;
|
|
dwBuffLen--;
|
|
}
|
|
*szPBuff = 0;
|
|
TRACE((ALIVE_MESSAGE, "Received: %s\n", szBuff));
|
|
} else {
|
|
TRACE((ALIVE_MESSAGE, "Received: %S\n", wszFeed));
|
|
}
|
|
|
|
}
|
|
|
|
_AddStrToClientBuffer(wszFeed, lProcessId);
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pWaitQHead;
|
|
|
|
bRun = TRUE;
|
|
while(pIter && bRun)
|
|
{
|
|
if (pIter->lProcessId == lProcessId)
|
|
{
|
|
// Check for expected string (one)
|
|
if (pIter->WaitType == WAIT_STRING &&
|
|
wcsstr(wszFeed, pIter->waitstr))
|
|
bRun = FALSE;
|
|
else
|
|
// Check for expected strings (many)
|
|
if (pIter->WaitType == WAIT_MSTRINGS)
|
|
{
|
|
WCHAR *wszComp = pIter->waitstr;
|
|
WCHAR *wszLast = pIter->waitstr + pIter->strsize;
|
|
int idx = 0;
|
|
|
|
while (wszComp < wszLast && *wszComp && bRun)
|
|
{
|
|
if (wcsstr(wszFeed, wszComp))
|
|
{
|
|
int i;
|
|
PCONNECTINFO pOwner = pIter->pOwner;
|
|
|
|
// Save the string
|
|
for(i = 0; wszComp[i]; i++)
|
|
pOwner->szWait4MultipleStrResult[i] = (char)wszComp[i];
|
|
|
|
pOwner->szWait4MultipleStrResult[i] = 0;
|
|
|
|
pOwner->nWait4MultipleStrResult = idx;
|
|
bRun = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Advance to next string
|
|
wszComp += wcslen(wszComp) + 1;
|
|
idx ++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Advance to the next pointer
|
|
if (bRun)
|
|
pIter = pIter->pNext;
|
|
}
|
|
|
|
if (pIter)
|
|
{
|
|
SetEvent(pIter->evWait);
|
|
}
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
return (pIter != NULL);
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _TextOutReceived
|
|
* Description:
|
|
* TextOut order is received from the client, the string is
|
|
* in shared memory. Unmaps the memory and checks if the
|
|
* strings is waited by anybody. Also adds the string
|
|
* to the client history buffer
|
|
* Arguments:
|
|
* dwProcessId - senders Id
|
|
* hMapF - handle to shared memory, which contains the string
|
|
* Return value:
|
|
* TRUE if a client is found and signaled
|
|
* Called by:
|
|
* _FeedbackWndProc within feedback thread
|
|
--*/
|
|
BOOL _TextOutReceived(LONG_PTR lProcessId, HANDLE hMapF)
|
|
{
|
|
PFEEDBACKINFO pView = NULL;
|
|
PCONNECTINFO pIterCl;
|
|
HANDLE hDupMapF = NULL;
|
|
BOOL rv = FALSE;
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIterCl = g_pClientQHead;
|
|
while(pIterCl && pIterCl->lProcessId != lProcessId)
|
|
pIterCl = pIterCl->pNext;
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
if (!pIterCl)
|
|
goto exitpt;
|
|
|
|
if ( NULL == pIterCl->hProcess ||
|
|
!DuplicateHandle(pIterCl->hProcess,
|
|
hMapF,
|
|
GetCurrentProcess(),
|
|
&hDupMapF,
|
|
FILE_MAP_READ,
|
|
FALSE,
|
|
0))
|
|
{
|
|
pView = (PFEEDBACKINFO) MapViewOfFile( hMapF,
|
|
FILE_MAP_READ,
|
|
0,
|
|
0,
|
|
sizeof(*pView));
|
|
} else
|
|
pView = (PFEEDBACKINFO) MapViewOfFile(hDupMapF,
|
|
FILE_MAP_READ,
|
|
0,
|
|
0,
|
|
sizeof(*pView));
|
|
|
|
if (!pView)
|
|
{
|
|
TRACE((ALIVE_MESSAGE,
|
|
"TEXTOUT:Can't map a view, GetLastError = %d\n",
|
|
GetLastError()));
|
|
goto exitpt1;
|
|
}
|
|
|
|
rv = _CheckForWaitingWorker(pView->string, lProcessId);
|
|
|
|
exitpt1:
|
|
if ( NULL != pView )
|
|
UnmapViewOfFile(pView);
|
|
if ( NULL != hDupMapF )
|
|
CloseHandle(hDupMapF);
|
|
|
|
exitpt:
|
|
return rv;
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _GlyphReceived
|
|
* Description:
|
|
* Same as _TextOutReceived but for GlyphOut order
|
|
* the glyph is in shared memory. It is converted to
|
|
* string by calling Glyph2String!bmpcache.c
|
|
* Arguments:
|
|
* dwProcessId - senders Id
|
|
* hMapF - handle to shared memory
|
|
* Return value:
|
|
* TRUE if a client is found and signaled
|
|
* Called by:
|
|
* _FeedbackWndProc within feedback thread
|
|
--*/
|
|
BOOL _GlyphReceived(LONG_PTR lProcessId, HANDLE hMapF)
|
|
{
|
|
WCHAR wszFeed[MAX_STRING_LENGTH];
|
|
BOOL rv = FALSE;
|
|
PBMPFEEDBACK pView;
|
|
PCONNECTINFO pIterCl;
|
|
HANDLE hDupMapF;
|
|
UINT nSize;
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIterCl = g_pClientQHead;
|
|
while(pIterCl && pIterCl->lProcessId != lProcessId)
|
|
pIterCl = pIterCl->pNext;
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
if (!pIterCl)
|
|
goto exitpt;
|
|
|
|
if ( NULL == pIterCl->hProcess ||
|
|
!DuplicateHandle( pIterCl->hProcess,
|
|
hMapF,
|
|
GetCurrentProcess(),
|
|
&hDupMapF,
|
|
FILE_MAP_READ,
|
|
FALSE,
|
|
0))
|
|
{
|
|
TRACE((ERROR_MESSAGE,
|
|
"GLYPH:Can't dup file handle, GetLastError = %d\n",
|
|
GetLastError()));
|
|
goto exitpt;
|
|
}
|
|
|
|
pView = (PBMPFEEDBACK) MapViewOfFile(hDupMapF,
|
|
FILE_MAP_READ,
|
|
0,
|
|
0,
|
|
sizeof(*pView));
|
|
|
|
if (!pView)
|
|
{
|
|
TRACE((ERROR_MESSAGE,
|
|
"GLYPH:Can't map a view, GetLastError = %d\n",
|
|
GetLastError()));
|
|
goto exitpt1;
|
|
}
|
|
|
|
// Get bitmap size
|
|
nSize = pView->bmpsize;
|
|
if (!nSize)
|
|
goto exitpt1;
|
|
|
|
// unmap
|
|
UnmapViewOfFile(pView);
|
|
|
|
// remap the whole structure
|
|
pView = (PBMPFEEDBACK) MapViewOfFile(hDupMapF,
|
|
FILE_MAP_READ,
|
|
0,
|
|
0,
|
|
sizeof(*pView) + nSize);
|
|
|
|
if (!pView)
|
|
{
|
|
TRACE((ERROR_MESSAGE,
|
|
"GLYPH:Can't map a view, GetLastError = %d\n",
|
|
GetLastError()));
|
|
goto exitpt1;
|
|
}
|
|
|
|
if (!Glyph2String(pView, wszFeed, sizeof(wszFeed)/sizeof(WCHAR)))
|
|
{
|
|
goto exitpt1;
|
|
}
|
|
|
|
rv = _CheckForWaitingWorker(wszFeed, lProcessId);
|
|
|
|
exitpt1:
|
|
if ( NULL != pView )
|
|
{
|
|
UnmapViewOfFile(pView);
|
|
}
|
|
CloseHandle(hDupMapF);
|
|
|
|
exitpt:
|
|
return rv;
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _CheckForWorkerWaitingDisconnect
|
|
* Description:
|
|
* Signals a worker (client thread) wich waits for a disconnect event
|
|
* Arguments:
|
|
* dwProcessId - clients Id
|
|
* Return value:
|
|
* TRUE if a client is found and signaled
|
|
* Called by:
|
|
* _FeedbackWndProc within feedback thread
|
|
--*/
|
|
BOOL _CheckForWorkerWaitingDisconnect(LONG_PTR lProcessId)
|
|
{
|
|
PWAIT4STRING pIter;
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pWaitQHead;
|
|
while(pIter &&
|
|
(pIter->WaitType != WAIT_DISC ||
|
|
pIter->lProcessId != lProcessId))
|
|
{
|
|
pIter = pIter->pNext;
|
|
}
|
|
|
|
if (pIter)
|
|
{
|
|
SetEvent(pIter->evWait);
|
|
}
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
return (pIter != NULL);
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _CheckForWorkerWaitingConnect
|
|
* Description:
|
|
* Signals a worker waiting for a connection
|
|
* Arguments:
|
|
* hwndClient - clients window handle, this is needed for
|
|
* sending messages to the client
|
|
* dwProcessId - client Id
|
|
* Return value:
|
|
* TRUE if a client is found and signaled
|
|
* Called by:
|
|
* _FeedbackWndProc within feedback thread
|
|
--*/
|
|
BOOL _CheckForWorkerWaitingConnect(HWND hwndClient, LONG_PTR lProcessId)
|
|
{
|
|
PWAIT4STRING pIter;
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pWaitQHead;
|
|
while(pIter &&
|
|
(pIter->WaitType != WAIT_CONN ||
|
|
pIter->lProcessId != lProcessId))
|
|
{
|
|
pIter = pIter->pNext;
|
|
}
|
|
|
|
if (pIter)
|
|
{
|
|
PCONNECTINFO pOwner = pIter->pOwner;
|
|
|
|
if (pOwner)
|
|
{
|
|
pOwner->hClient = hwndClient;
|
|
pOwner->dead = FALSE;
|
|
} else
|
|
TRACE((WARNING_MESSAGE, "FEED: WAIT4 w/o owner structure"));
|
|
|
|
SetEvent(pIter->evWait);
|
|
}
|
|
|
|
if ( NULL == pIter )
|
|
{
|
|
PCONNECTINFO pCon;
|
|
//
|
|
// in autoreconnect the dead field might be TRUE
|
|
//
|
|
pCon = g_pClientQHead;
|
|
while ( NULL != pCon && pCon->lProcessId != lProcessId)
|
|
{
|
|
pCon = pCon->pNext;
|
|
}
|
|
|
|
if ( NULL != pCon)
|
|
{
|
|
pCon->dead = FALSE;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
return (pIter != NULL);
|
|
}
|
|
|
|
#ifdef _RCLX
|
|
/*++
|
|
* Function:
|
|
* _CheckForWorkerWaitingConnectAndSetId
|
|
* Description:
|
|
* This is intended for RCLX mode. dwProcessId is zero
|
|
* so this function look for such a client and sets its dwProcessId
|
|
* Signals a worker waiting for a connection
|
|
* Arguments:
|
|
* hwndClient - clients window handle, this is needed for
|
|
* sending messages to the client
|
|
* dwProcessId - client Id
|
|
* Return value:
|
|
* connection context, NULL if not found
|
|
* Called by:
|
|
* _FeedbackWndProc within feedback thread
|
|
--*/
|
|
PCONNECTINFO
|
|
_CheckForWorkerWaitingConnectAndSetId(HWND hwndClient, LONG_PTR lProcessId)
|
|
{
|
|
PWAIT4STRING pIter;
|
|
PCONNECTINFO pOwner = NULL;
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pWaitQHead;
|
|
while(pIter &&
|
|
(pIter->WaitType != WAIT_CONN ||
|
|
pIter->lProcessId))
|
|
{
|
|
pIter = pIter->pNext;
|
|
}
|
|
|
|
if (pIter)
|
|
{
|
|
pOwner = pIter->pOwner;
|
|
|
|
if (pOwner)
|
|
{
|
|
ASSERT(pOwner->RClxMode);
|
|
|
|
pOwner->hClient = hwndClient;
|
|
pOwner->lProcessId = lProcessId;
|
|
pIter->lProcessId = lProcessId; // Disable next lookup in
|
|
// the same entry
|
|
}
|
|
else
|
|
TRACE((WARNING_MESSAGE, "FEED: WAIT4 w/o owner structure"));
|
|
|
|
SetEvent(pIter->evWait);
|
|
}
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
return (pOwner);
|
|
}
|
|
|
|
/*++
|
|
* Function:
|
|
* _CheckForWorkerWaitingReconnectAndSetNewId
|
|
* Description:
|
|
* This is intended for RCLX mode. When mstsc wants to reconnect
|
|
* looks for dwLookupId as an ID to reconnect
|
|
* then sets the new ID
|
|
* then gets
|
|
* Arguments:
|
|
* hwndClient - clients window handle, this is needed for
|
|
* sending messages to the client
|
|
* dwLookupId, dwNewId
|
|
* Return value:
|
|
* connection context, NULL if not found
|
|
* Called by:
|
|
* _FeedbackWndProc within feedback thread
|
|
--*/
|
|
PCONNECTINFO
|
|
_CheckForWorkerWaitingReconnectAndSetNewId(
|
|
HWND hwndClient,
|
|
DWORD dwLookupId,
|
|
LONG_PTR lNewId)
|
|
{
|
|
PWAIT4STRING pIter;
|
|
PCONNECTINFO pOwner = NULL;
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pWaitQHead;
|
|
while(pIter &&
|
|
(pIter->WaitType != WAIT_CONN ||
|
|
!pIter->pOwner ||
|
|
pIter->pOwner->dwThreadId != dwLookupId ||
|
|
!(pIter->pOwner->bWillCallAgain)))
|
|
{
|
|
pIter = pIter->pNext;
|
|
}
|
|
|
|
if (pIter)
|
|
{
|
|
pOwner = pIter->pOwner;
|
|
|
|
if (pOwner)
|
|
{
|
|
ASSERT(pOwner->RClxMode);
|
|
|
|
|
|
pOwner->hClient = hwndClient;
|
|
pOwner->lProcessId = lNewId;
|
|
pIter->lProcessId = lNewId; // Disable next lookup in
|
|
// the same entry
|
|
pOwner->bWillCallAgain = FALSE;
|
|
}
|
|
else
|
|
TRACE((WARNING_MESSAGE, "FEED: WAIT4 w/o owner structure"));
|
|
|
|
SetEvent(pIter->evWait);
|
|
}
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
return (pOwner);
|
|
}
|
|
#endif // _RCLX
|
|
|
|
|
|
/*++
|
|
* Function:
|
|
* _CancelWaitingWorker
|
|
* Description:
|
|
* Releases a worker waiting for any event.
|
|
* Eventualy the client is disconnected
|
|
* Arguments:
|
|
* dwProcessId - client Id
|
|
* Return value:
|
|
* TRUE if a client is found and signaled
|
|
* Called by:
|
|
* _FeedbackWndProc within feedback thread
|
|
--*/
|
|
BOOL _CancelWaitingWorker(LONG_PTR lProcessId)
|
|
{
|
|
PWAIT4STRING pIter;
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pWaitQHead;
|
|
while(pIter &&
|
|
pIter->lProcessId != lProcessId)
|
|
{
|
|
pIter = pIter->pNext;
|
|
}
|
|
|
|
if (pIter)
|
|
{
|
|
SetEvent(pIter->evWait);
|
|
}
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
return (pIter != NULL);
|
|
}
|
|
|
|
#ifdef _RCLX
|
|
/*++
|
|
* Function:
|
|
* _CheckForWorkerWaitingClipboard
|
|
* Description:
|
|
* Releases a worker waiting for client's clipboard content.
|
|
* Arguments:
|
|
* dwProcessId - client Id
|
|
* Return value:
|
|
* TRUE if a client is found and signaled
|
|
* Called by:
|
|
* _FeedbackWndProc within feedback thread
|
|
--*/
|
|
BOOL _CheckForWorkerWaitingClipboard(
|
|
PCONNECTINFO pRClxOwner,
|
|
UINT uiFormat,
|
|
UINT nSize,
|
|
PVOID pClipboard,
|
|
LONG_PTR lProcessId)
|
|
{
|
|
PWAIT4STRING pIter = NULL;
|
|
HGLOBAL ghNewClipboard = NULL;
|
|
LPVOID pNewClipboard = NULL;
|
|
|
|
ASSERT(pRClxOwner);
|
|
|
|
TRACE((ALIVE_MESSAGE, "Clipboard received, FormatID=%d, Size=%d\n",
|
|
uiFormat, nSize));
|
|
|
|
if (nSize)
|
|
{
|
|
// Copy the clipboard content to new buffer
|
|
ghNewClipboard = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, nSize);
|
|
if (!ghNewClipboard)
|
|
{
|
|
TRACE((ERROR_MESSAGE, "_CheckForWorkerWaitingClipboard: can't allocate %d bytes\n", nSize));
|
|
goto exitpt;
|
|
}
|
|
|
|
pNewClipboard = GlobalLock(ghNewClipboard);
|
|
if (!pNewClipboard)
|
|
{
|
|
TRACE((ERROR_MESSAGE, "_CheckForWorkerWaitingClipboard: can't lock global memory\n"));
|
|
goto exitpt;
|
|
}
|
|
|
|
memcpy(pNewClipboard, pClipboard, nSize);
|
|
|
|
// Unlock the clipboard buffer
|
|
GlobalUnlock(ghNewClipboard);
|
|
pNewClipboard = NULL;
|
|
|
|
} else {
|
|
pClipboard = NULL;
|
|
}
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pWaitQHead;
|
|
while(pIter &&
|
|
(pIter->lProcessId != lProcessId ||
|
|
pIter->WaitType != WAIT_CLIPBOARD))
|
|
{
|
|
pIter = pIter->pNext;
|
|
}
|
|
|
|
if (pIter)
|
|
{
|
|
PCONNECTINFO pOwner = pIter->pOwner;
|
|
|
|
// Put the buffer in the worker's context
|
|
if (pOwner)
|
|
{
|
|
ASSERT(pOwner->RClxMode);
|
|
ASSERT(pOwner == pRClxOwner);
|
|
|
|
// pOwner->ghClipboard should be NULL
|
|
ASSERT(pOwner->ghClipboard == NULL);
|
|
|
|
pOwner->ghClipboard = ghNewClipboard;
|
|
pOwner->uiClipboardFormat = uiFormat;
|
|
pOwner->nClipboardSize = nSize;
|
|
}
|
|
else
|
|
TRACE((WARNING_MESSAGE, "FEED: WAIT4 w/o owner structure"));
|
|
|
|
SetEvent(pIter->evWait);
|
|
} else {
|
|
// Can't find anybody waiting, add it to the context owner
|
|
pRClxOwner->ghClipboard = ghNewClipboard;
|
|
pRClxOwner->uiClipboardFormat = uiFormat;
|
|
pRClxOwner->nClipboardSize = nSize;
|
|
}
|
|
pRClxOwner->bRClxClipboardReceived = TRUE;
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
exitpt:
|
|
if (!pIter)
|
|
// worker not found, clear the allocated buffer
|
|
{
|
|
if (ghNewClipboard)
|
|
GlobalFree(ghNewClipboard);
|
|
}
|
|
|
|
return (pIter != NULL);
|
|
}
|
|
#endif // _RCLX
|
|
|
|
BOOL
|
|
_SetSessionID(LONG_PTR lProcessId, UINT uSessionId)
|
|
{
|
|
PCONNECTINFO pIter;
|
|
// PCONNECTINFO pPrev = NULL;
|
|
|
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
pIter = g_pClientQHead;
|
|
while (pIter &&
|
|
pIter->lProcessId != lProcessId)
|
|
pIter = pIter->pNext;
|
|
|
|
if (pIter)
|
|
pIter->uiSessionId = (uSessionId)?uSessionId:-1;
|
|
|
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
|
|
|
return (pIter != NULL);
|
|
}
|