1170 lines
28 KiB
C
1170 lines
28 KiB
C
|
/*++
|
||
|
* 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:
|
||
|
* _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;
|
||
|
|
||
|
EnterCriticalSection(g_lpcsGuardWaitQueue);
|
||
|
|
||
|
pIter = g_pClientQHead;
|
||
|
while(pIter &&
|
||
|
(pIter->lProcessId != lProcessId || pIter->RClxMode != bRClxType))
|
||
|
{
|
||
|
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 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 (/*!pWait->waitstr[0] && */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 i;
|
||
|
// Save the string
|
||
|
for(i = 0; wszComp[i]; i++)
|
||
|
pCI->szWait4MultipleStrResult[i] = (char)wszComp[i];
|
||
|
// and the index
|
||
|
|
||
|
pCI->szWait4MultipleStrResult[i] = 0;
|
||
|
|
||
|
pCI->nWait4MultipleStrResult = idx;
|
||
|
bDone = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Advance to next string
|
||
|
wszComp += wcslen(wszComp) + 1;
|
||
|
idx ++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (pWait->WaitType == WAIT_CLIPBOARD &&
|
||
|
pWait->pOwner->bRClxClipboardReceived)
|
||
|
{
|
||
|
bDone = TRUE;
|
||
|
}
|
||
|
else if (pWait->WaitType == WAIT_DATA &&
|
||
|
pWait->pOwner->pRClxDataChain)
|
||
|
{
|
||
|
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);
|
||
|
|
||
|
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;
|
||
|
|
||
|
|
||
|
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 ++;
|
||
|
}
|
||
|
*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;
|
||
|
PCONNECTINFO pIterCl;
|
||
|
HANDLE hDupMapF;
|
||
|
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 (!DuplicateHandle(pIterCl->hProcess,
|
||
|
hMapF,
|
||
|
GetCurrentProcess(),
|
||
|
&hDupMapF,
|
||
|
FILE_MAP_READ,
|
||
|
FALSE,
|
||
|
0))
|
||
|
{
|
||
|
TRACE((ERROR_MESSAGE,
|
||
|
"TEXTOUT:Can't dup file handle, GetLastError = %d\n",
|
||
|
GetLastError()));
|
||
|
goto exitpt;
|
||
|
}
|
||
|
|
||
|
pView = MapViewOfFile(hDupMapF,
|
||
|
FILE_MAP_READ,
|
||
|
0,
|
||
|
0,
|
||
|
sizeof(*pView));
|
||
|
|
||
|
if (!pView)
|
||
|
{
|
||
|
TRACE((ERROR_MESSAGE,
|
||
|
"TEXTOUT:Can't map a view, GetLastError = %d\n",
|
||
|
GetLastError()));
|
||
|
goto exitpt1;
|
||
|
}
|
||
|
|
||
|
rv = _CheckForWaitingWorker(pView->string, lProcessId);
|
||
|
|
||
|
exitpt1:
|
||
|
UnmapViewOfFile(pView);
|
||
|
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 (!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 = 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 = 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;
|
||
|
} else {
|
||
|
}
|
||
|
|
||
|
rv = _CheckForWaitingWorker(wszFeed, lProcessId);
|
||
|
|
||
|
exitpt1:
|
||
|
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;
|
||
|
else
|
||
|
TRACE((WARNING_MESSAGE, "FEED: WAIT4 w/o owner structure"));
|
||
|
|
||
|
SetEvent(pIter->evWait);
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection(g_lpcsGuardWaitQueue);
|
||
|
|
||
|
return (pIter != NULL);
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
* 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);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*++
|
||
|
* 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);
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
* 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);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
_SetSessionID(LONG_PTR lProcessId, UINT uSessionId)
|
||
|
{
|
||
|
PCONNECTINFO pIter, 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);
|
||
|
}
|