|
|
/*++
* 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); }
|