Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1786 lines
42 KiB

/*+
* File name:
* clxtshar.c
* Contents:
* Client extension loaded by RDP client
*
* Copyright (C) 1998-1999 Microsoft Corp.
--*/
#include <windows.h>
#include <windowsx.h>
#include <winsock.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#ifndef OS_WINCE
#include <direct.h>
#endif // OS_WINCE
#ifndef OS_WINCE
#ifdef OS_WIN32
#include <process.h>
#endif // OS_WIN32
#endif // !OS_WINCE
#include "clxtshar.h"
#define WM_CLIPBOARD (WM_USER) // Internal notifcation to send
// our clipboard
#ifdef OS_WIN32
#ifndef OS_WINCE
/*++
* Function:
* DllMain
* Description:
* Dll entry point for win32 (no WinCE)
--*/
int APIENTRY DllMain(HINSTANCE hDllInst,
DWORD dwReason,
LPVOID fImpLoad)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
g_hInstance = hDllInst;
TRACE((INFO_MESSAGE, TEXT("Clx attached\n")));
#if 0
// Check the key "Allow Background Input"
// If not set pop a message for that
if (!_CheckRegistrySettings())
MessageBox(NULL, "CLXTSHAR.DLL: Can't find registry key:\n"
"HKEY_CURRENT_USER\\Software\\Microsoft\\Terminal Server Client\\"
"Allow Background Input.\n"
"In order to work properly "
"CLX needs this key to be set to 1", "Warning",
MB_OK);
#endif
_GetIniSettings();
}
if (dwReason == DLL_PROCESS_DETACH)
{
TRACE((INFO_MESSAGE, TEXT("Clx detached\n")));
}
return TRUE;
}
#endif // !OS_WINCE
#endif // OS_WIN32
#ifdef OS_WINCE
/*++
* Function:
* dllentry
* Description:
* Dll entry point for wince
--*/
BOOL __stdcall dllentry(HINSTANCE hDllInst,
DWORD dwReason,
LPVOID fImpLoad)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
g_hInstance = hDllInst;
TRACE((INFO_MESSAGE, TEXT("Clx attached\n")));
if (!_StartAsyncThread())
TRACE((ERROR_MESSAGE,
TEXT("Can't start AsyncThread. TCP unusable\n")));
_GetIniSettings();
}
if (dwReason == DLL_PROCESS_DETACH)
{
TRACE((INFO_MESSAGE, TEXT("Clx detached\n")));
_CloseAsyncThread();
}
return TRUE;
}
#endif // OS_WIN32
#ifdef OS_WIN16
/*++
* Function:
* LibMain
* Description:
* Dll entry point for win16
--*/
int CALLBACK LibMain(HINSTANCE hInstance,
WORD dataSeg,
WORD heapSize,
LPSTR pCmdLine)
{
// Check if we are already initialized
// Only one client is allowed in Win16 environment
// so, only one dll can be loaded at a time
if (g_hInstance)
goto exitpt;
g_hInstance = hInstance;
// Check the key "Allow Background Input"
// If not set pop a message for that
if (!_CheckIniSettings())
MessageBox(NULL, "CLXTSHAR.DLL: Can't find key: "
"Allow Background Input in mstsc.ini, section \"\"\n"
"In order to work properly "
"CLX needs this key to be set to 1", "Warning",
MB_OK);
_GetIniSettings();
exitpt:
return TRUE;
}
#endif // OS_WIN16
/*++
* Function:
* ClxInitialize
* Description:
* Initilizes a context for the current session
* reads the command line paramters and determines
* the mode wich will run the extension
* Win32/Win16/WinCE
* Arguments:
* pClInfo - RDP client info
* ppClx - context info
* Return value:
* TRUE on success
* Called by:
* !mstsc after the dll is loaded
--*/
BOOL
CLXAPI
ClxInitialize(PCLINFO pClInfo, PCLXINFO *ppClx)
{
BOOL rv = FALSE;
HWND hwndSMC;
TCHAR szTempBuf[_MAX_PATH];
PCLXINFO pClx = NULL;
#ifdef OS_WIN32
#ifndef OS_WINCE
// We have enough problems in stress with early unloaded
// dll, reference it now and keep it up until the process
// dies
LoadLibrary("clxtshar.dll");
#endif // !OS_WINCE
#endif // OS_WIN32
if ( NULL == ppClx )
{
TRACE((ERROR_MESSAGE, TEXT("ppClx is NULL\n")));
goto exitpt;
}
pClx = (PCLXINFO)_CLXALLOC(sizeof(**ppClx));
if (!pClx)
{
TRACE((ERROR_MESSAGE, TEXT("Can't allocate CLX context\n")));
goto exitpt;
}
// Clear the structure
memset(pClx, 0, sizeof(*pClx));
if ( !_ClxInitSendMessageThread( pClx ))
{
TRACE(( ERROR_MESSAGE, TEXT("Failed to init SendMessageThread\n" )));
goto exitpt;
}
hwndSMC = _ParseCmdLine(pClInfo->pszCmdLine, pClx);
#if 0
if (g_pClx)
// Should not be called twice
{
TRACE((WARNING_MESSAGE, TEXT("g_pClx is not null. Reentered ?!\n")));
goto exitpt;
}
#endif
g_pClx = (pClx);
// Remember client's input window
szTempBuf[0] = 0;
GetClassName( pClInfo->hwndMain, szTempBuf, sizeof( szTempBuf )/sizeof( szTempBuf[0] ));
if (!_CLX_strcmp(g_strMainWindowClass, szTempBuf))
// not our window
//
pClx->hwndMain = NULL;
else
pClx->hwndMain = pClInfo->hwndMain;
if (pClInfo->hwndMain)
#ifdef OS_WINCE
g_hRDPInst = GetCurrentProcessId();
#else // !OS_WINCE
#ifdef _WIN64
g_hRDPInst = (HINSTANCE)GetWindowLongPtr(pClx->hwndMain, GWLP_HINSTANCE);
#else // !_WIN64
#ifdef OS_WIN32
g_hRDPInst = (HINSTANCE)GetWindowLong(pClx->hwndMain, GWL_HINSTANCE);
#endif // OS_WIN32
#endif // _WIN64
#ifdef OS_WIN16
g_hRDPInst = (HINSTANCE)GetWindowWord(pClx->hwndMain, GWW_HINSTANCE);
#endif // OS_WIN16
#endif // !OS_WINCE
#ifndef OS_WINCE
#ifdef OS_WIN32
// and dwProcessId
if ( 0 == pClx->dwProcessId )
pClx->dwProcessId = GetCurrentProcessId();
#endif // OS_WIN32
#endif // !OS_WINCE
#ifdef OS_WIN32
#ifndef OS_WINCE
else {
if (!(pClx->hwndSMC = hwndSMC))
pClx->hwndSMC = _FindSMCWindow(pClx, 0);
}
#endif // !OS_WINCE
#endif // OS_WIN32
rv = TRUE;
exitpt:
if ( !rv && NULL != pClx )
{
_CLXFREE( pClx );
g_pClx = NULL;
pClx = NULL;
}
if ( NULL != ppClx )
{
*ppClx = pClx;
}
if ( !rv )
TRACE((ERROR_MESSAGE, TEXT("ClxInitialzie failed\n")));
return rv;
}
/*++
* Function:
* ClxEvent
* Description:
* Notifies tclient.dll that some event happend.
* Connect/disconnect.
* Win32/Win16/WinCE
* Arguments:
* pClx - context
* Event - can be one of the following:
* CLX_EVENT_CONNECT
* CLX_EVENT_DISCONNECT
* CLX_EVENT_LOGON
* Called by:
* !mstsc on event
* alse some of the internal functions call this, especialy
* to notify that the client can't connect:
* ClxTerminate
* _GarbageCollecting when an error box is popped
--*/
VOID
CLXAPI
ClxEvent(PCLXINFO pClx, CLXEVENT Event, WPARAM wResult)
{
UINT uiMessage = 0;
if (!pClx)
goto exitpt;
#ifdef VLADIMIS_NEW_CHANGE
if (Event == CLX_EVENT_SHADOWBITMAPDC)
{
pClx->hdcShadowBitmap = (HDC)wResult;
goto exitpt;
} else if (Event == CLX_EVENT_SHADOWBITMAP)
{
pClx->hShadowBitmap = (HBITMAP)wResult;
goto exitpt;
} else if (Event == CLX_EVENT_PALETTE)
{
pClx->hShadowPalette = (HPALETTE)wResult;
}
#endif // VLADIMIS
#ifndef OS_WINCE
{
if (!_CheckWindow(pClx))
goto exitpt;
if (Event == CLX_EVENT_DISCONNECT)
uiMessage = WM_FB_DISCONNECT;
else if (Event == CLX_EVENT_CONNECT)
{
uiMessage = WM_FB_CONNECT;
wResult = (WPARAM)pClx->hwndMain;
}
else if (Event == CLX_EVENT_LOGON)
// wResult contains the session ID
uiMessage = WM_FB_LOGON;
if (uiMessage)
{
#ifdef OS_WIN32
if (!_ClxAcquireSendMessageThread(pClx))
goto exitpt;
_ClxSendMessage(
pClx,
pClx->hwndSMC,
uiMessage,
wResult,
pClx->dwProcessId);
_ClxReleaseSendMessageThread(pClx);
#endif // OS_WIN32
#ifdef OS_WIN16
if (g_hRDPInst)
SendMessage(pClx->hwndSMC,
uiMessage,
g_hRDPInst,
(LRESULT)wResult);
#endif // OS_WIN16
}
}
#endif // !OS_WINCE
exitpt:
;
}
/*++
* Function:
* ClxTextOut
* Description:
* Notifies tclient.dll that TEXTOUT order is recieved.
* Passes the string to the dll. Supported only in Win32
* Win32/Win16/WinCE
* Arguments:
* pClx - context
* pText - buffer containing the string
* textLength - string length
* Called by:
* !mstsc on receiving textout order
--*/
VOID
CLXAPI
ClxTextOut(PCLXINFO pClx, PVOID pText, INT textLength)
{
BOOL bMsgThreadAcquired = FALSE;
if (!pClx || !(*((UINT16 *)pText)))
goto exitpt;
#ifdef OS_WIN32
#ifndef OS_WINCE
if (!_CheckWindow(pClx))
goto exitpt;
if (!_ClxAcquireSendMessageThread(pClx))
goto exitpt;
bMsgThreadAcquired = TRUE;
if (!pClx->hMapF)
if (!_OpenMapFile(0, &(pClx->hMapF), &(pClx->nMapSize)))
goto exitpt;
if (_SaveInMapFile(pClx->hMapF, pText, textLength, pClx->dwProcessId))
_ClxSendMessage(
pClx,
pClx->hwndSMC,
WM_FB_TEXTOUT,
(WPARAM)pClx->dwProcessId,
(LPARAM)pClx->hMapF);
#endif // !OS_WINCE
#endif // OS_WIN32
exitpt:
if ( bMsgThreadAcquired )
_ClxReleaseSendMessageThread(pClx);
}
/*++
* Function:
* ClxTerminate
* Description:
* Frees all alocations from ClxInitialize
* Win32/Win16/WinCE
* Arguments:
* pClx - context
* Called by:
* !mstsc before the dll is unloaded and client exit
--*/
VOID
CLXAPI
ClxTerminate(PCLXINFO pClx)
{
if (!pClx)
goto exitpt;
ClxEvent(pClx, CLX_EVENT_DISCONNECT, 0);
#ifdef OS_WIN32
#ifndef OS_WINCE
{
if(pClx->hMapF)
CloseHandle(pClx->hMapF);
if(pClx->hBMPMapF)
CloseHandle(pClx->hBMPMapF);
_ClxDestroySendMsgThread(pClx);
}
#endif // !OS_WINCE
#endif // OS_WIN32
_CLXFREE(pClx);
g_pClx = NULL;
exitpt:
;
}
/*
* Void functions exported to the RDP client
*/
VOID
CLXAPI
ClxConnect(PCLXINFO pClx, LPTSTR lpsz)
{
}
VOID
CLXAPI
ClxDisconnect(PCLXINFO pClx)
{
}
/*++
* Function:
* ClxDialog
* Description:
* The RDP client is ready with the connect dialog.
* Win32/Win16/WinCE
* Arguments:
* pClx - connection context
* hwnd - handle to the dialog window
* Called by:
* !mstsc when the connect dialog is ready
--*/
VOID
CLXAPI
ClxDialog(PCLXINFO pClx, HWND hwnd)
{
if (!pClx)
goto exitpt;
pClx->hwndDialog = hwnd;
if (hwnd == NULL)
// Dialog disappears
goto exitpt;
exitpt:
;
}
/*++
* Function:
* ClxBitmap
* Description:
* Send a received bitmap to tclient.dll
* Works on Win16/Win32/WinCE
* and on Win32 for local mode
* Arguments:
* pClx - context
* cxSize, cySize - size of the bitmap
* pBuffer - bitmap bits
* nBmiSize - size of BITMAPINFO
* pBmi - BITMAPINFO
* Called by:
* UHDrawMemBltOrder!mstsc
* ClxGlyphOut
--*/
VOID
CLXAPI
ClxBitmap(
PCLXINFO pClx,
UINT cxSize,
UINT cySize,
PVOID pBuffer,
UINT nBmiSize,
PVOID pBmi)
{
#ifndef OS_WINCE
#ifdef OS_WIN32
UINT nSize, nBmpSize;
PBMPFEEDBACK pView;
#endif // OS_WIN32
#endif // !OS_WINCE
BOOL bMsgThreadAcquired = FALSE;
if (!g_GlyphEnable)
goto exitpt;
if (!pClx)
goto exitpt;
if (nBmiSize && !pBmi)
goto exitpt;
#ifdef OS_WIN32
#ifndef OS_WINCE
if (!_CheckWindow(pClx))
goto exitpt;
if (!nBmiSize)
nBmpSize = (cxSize * cySize ) >> 3;
else
{
nBmpSize = ((PBITMAPINFO)pBmi)->bmiHeader.biSizeImage;
if (!nBmpSize)
nBmpSize = (cxSize * cySize *
((PBITMAPINFO)pBmi)->bmiHeader.biBitCount) >> 3;
}
nSize = nBmpSize + nBmiSize + sizeof(*pView);
if (!nSize)
goto exitpt;
if (!_ClxAcquireSendMessageThread(pClx))
goto exitpt;
bMsgThreadAcquired = TRUE;
if (!pClx->hBMPMapF)
if (!_OpenMapFile(nSize, &(pClx->hBMPMapF), &(pClx->nBMPMapSize)))
goto exitpt;
if (nSize > pClx->nBMPMapSize)
if (!_ReOpenMapFile( nSize, &(pClx->hBMPMapF), &(pClx->nBMPMapSize) ))
goto exitpt;
pView = (PBMPFEEDBACK)MapViewOfFile(pClx->hBMPMapF,
FILE_MAP_ALL_ACCESS,
0,
0,
nSize);
if (!pView)
goto exitpt;
pView->lProcessId = pClx->dwProcessId;
pView->bmpsize = nBmpSize;
pView->bmiSize = nBmiSize;
pView->xSize = cxSize;
pView->ySize = cySize;
if (pBmi)
CopyMemory(&(pView->BitmapInfo), pBmi, nBmiSize);
CopyMemory((BYTE *)(&(pView->BitmapInfo)) + nBmiSize, pBuffer, nBmpSize);
if (!nBmiSize)
{
// This is glyph, strip it to the skin
_StripGlyph((BYTE *)(&pView->BitmapInfo), &cxSize, cySize);
nBmpSize = (cxSize * cySize ) >> 3;
pView->bmpsize = nBmpSize;
pView->xSize = cxSize;
}
UnmapViewOfFile(pView);
_ClxSendMessage(
pClx,
pClx->hwndSMC,
WM_FB_BITMAP,
(WPARAM)pClx->dwProcessId,
(LPARAM)pClx->hBMPMapF);
#endif // !OS_WINCE
#endif // OS_WIN32
exitpt:
if ( bMsgThreadAcquired )
_ClxReleaseSendMessageThread(pClx);
}
/*++
* Function:
* ClxGlyphOut
* Description:
* Send a glyph to tclient.dll
* Win32/Win16/WinCE
* Arguments:
* pClx - context
* cxBits,cyBits - glyph size
* pBuffer - the glyph
* Called by:
* GHOutputBuffer!mstsc
--*/
VOID
CLXAPI
ClxGlyphOut(
PCLXINFO pClx,
UINT cxBits,
UINT cyBits,
PVOID pBuffer)
{
if (g_GlyphEnable)
ClxBitmap(pClx, cxBits, cyBits, pBuffer, 0, NULL);
}
/*++
* Function:
* ClxGlyphOut
* Description:
* Send a glyph to tclient.dll
* Win32/Win16/WinCE
* Arguments:
* pClx - context
* cxBits,cyBits - glyph size
* pBuffer - the glyph
* Called by:
* GHOutputBuffer!mstsc
--*/
BOOL
CLXAPI
ClxGetClientData(
PCLX_CLIENT_DATA pClntData
)
{
BOOL rv = FALSE;
if (!pClntData)
{
TRACE((ERROR_MESSAGE, TEXT("ClxGetClientData: parameter is NULL\n")));
goto exitpt;
}
memset(pClntData, 0, sizeof(*pClntData));
if (!g_pClx)
{
TRACE((ERROR_MESSAGE, TEXT("ClxGetClientData: Clx has no context\n")));
goto exitpt;
}
pClntData->hScreenDC = g_pClx->hdcShadowBitmap;
pClntData->hScreenBitmap = g_pClx->hShadowBitmap;
pClntData->hScreenPalette = g_pClx->hShadowPalette;
rv = TRUE;
exitpt:
return rv;
}
/*++
* Function:
* _ParseCmdLine
* Description:
* Retreives WHND of tclient.dll feedback window
* passed by the command line
* Win32/Win16/WinCE
* Arguments:
* szCmdLine - command line
* Return value:
* The window handle
* Called by:
* ClxInitialize
--*/
HWND _ParseCmdLine(LPCTSTR szCmdLine, PCLXINFO pClx)
{
HWND hwnd = NULL;
LPCTSTR pszwnd, pszdot, pszend;
INT nCounter;
if (!szCmdLine)
goto exitpt;
TRACE((INFO_MESSAGE, TEXT("Command line: %s\n"), szCmdLine));
pszwnd = _CLX_strstr(szCmdLine, TEXT(_COOKIE));
if (!pszwnd)
goto skip_cookie;
pszwnd += _CLX_strlen(TEXT(_COOKIE));
pClx->dwProcessId = (DWORD_PTR)_atoi64( pszwnd );
skip_cookie:
// Check for _HWNDOPT(hSMC) option
pszwnd = _CLX_strstr(szCmdLine, TEXT(_HWNDOPT));
if (!pszwnd)
goto findnext;
// Goto the parameter
pszwnd += _CLX_strlen(TEXT(_HWNDOPT));
// Find the end of the paramter
pszend = _CLX_strchr(pszwnd, TEXT(' '));
if (!pszend)
pszend = pszwnd + _CLX_strlen(pszwnd);
// Check if paramter is valid host name, i.e. not a number
pszdot = _CLX_strchr(pszwnd, TEXT('.'));
{
// local execution, hwnd passed
#ifdef _WIN64
hwnd = (HWND) _atoi64(pszwnd);
#else // !_WIN64
hwnd = (HWND) _CLX_atol(pszwnd);
#endif // !_WIN64
TRACE((INFO_MESSAGE,
TEXT("Local mode. Sending messages to smclient. HWND=0x%x\n"),
hwnd));
}
findnext:
#ifdef OS_WIN32
// check for replace pid command
pszwnd = szCmdLine;
pszwnd = _CLX_strstr(szCmdLine, TEXT("pid="));
if ( NULL != pszwnd )
{
WPARAM wParam;
LPARAM lParam;
HWND hClxWnd = hwnd;
pszwnd += 4 * sizeof(pszwnd[0]);
#ifdef _WIN64
wParam = _atoi64( pszwnd );
#else // !_WIN64
wParam = _CLX_atol( pszwnd );
#endif
lParam = GetCurrentProcessId();
if ( NULL == hClxWnd )
hClxWnd = _FindSMCWindow( pClx, (LPARAM)wParam );
if ( NULL != hClxWnd )
{
PostMessage(hClxWnd,
WM_FB_REPLACEPID,
wParam, lParam);
pClx->hwndSMC = hClxWnd;
}
}
#endif // OS_WIN32
exitpt:
return hwnd;
}
#ifndef OS_WINCE
/*++
* Function:
* _EnumWindowsProcForSMC
* Description:
* Searches for the feedback window by class name
* When found, sends a WM_FB_ACCEPTME to ensure that
* this is the right window handle
* Win32/Win16/!WinCE
* Arguments:
* hWnd - current window
* lParam - unused
* Return value:
* FALSE if found
* Called by:
* _FindSMCWindow thru EnumWindows
--*/
BOOL CALLBACK LOADDS _EnumWindowsProcForSMC( HWND hWnd, LPARAM lParam )
{
TCHAR classname[128];
BOOL bCont = TRUE;
if (GetClassName(hWnd, classname, sizeof(classname)))
{
if (!
_CLX_strcmp(classname, TEXT(_TSTNAMEOFCLAS)) &&
#ifdef OS_WIN32
SendMessage(hWnd, WM_FB_ACCEPTME, 0, *(LPARAM *)lParam))
#endif
#ifdef OS_WIN16
SendMessage(hWnd, WM_FB_ACCEPTME, (WPARAM)g_hRDPInst, 0))
#endif
{
*((HWND*)lParam) = hWnd;
bCont = FALSE;
}
}
return bCont;
}
/*++
* Function:
* _FindSMCWindow
* Description:
* Finds the tclient feedback window
* Win32/Win16/!WinCE
* Arguments:
* pClx - context
* lParam - if non zero override current process id
* in the query
* Return value:
* The window handle
* Called by:
* ClxInitialize, _CheckWindow
--*/
HWND _FindSMCWindow(PCLXINFO pClx, LPARAM lParam)
{
HWND hwndFound = NULL;
#ifdef OS_WIN32
if ( 0 == lParam )
lParam = pClx->dwProcessId;
#endif // OS_WIN32
if (!EnumWindows(_EnumWindowsProcForSMC, (LPARAM)&lParam))
hwndFound = (HWND)lParam;
return hwndFound;
}
/*++
* Function:
* _CheckWindow
* Description:
* Checks the feedback window and if neccessary finds it
* Win32/Win16/!WinCE
* Arguments:
* pClx - context
* Return value:
* Feedback window handle
* Called by:
* ClxEvetm ClxTextOut, ClxBitmap
--*/
HWND _CheckWindow(PCLXINFO pClx)
{
if (!pClx->hwndSMC)
{
pClx->hwndSMC = _FindSMCWindow(pClx, 0);
if (pClx->hwndSMC)
{
TRACE((INFO_MESSAGE,
TEXT("SMC window found:0x%x\n"),
pClx->hwndSMC));
}
} else {
#ifdef _WIN64
if (!GetWindowLongPtr(pClx->hwndSMC, GWLP_HINSTANCE))
#else // !_WIN64
#ifdef OS_WIN32
if (!GetWindowLong(pClx->hwndSMC, GWL_HINSTANCE))
#endif
#ifdef OS_WIN16
if (!GetWindowWord(pClx->hwndSMC, GWW_HINSTANCE))
#endif
#endif // _WIN64
{
TRACE((WARNING_MESSAGE, TEXT("SMC window lost\n")));
pClx->hwndSMC = NULL;
}
}
return (pClx->hwndSMC);
}
#endif // !OS_WINCE
#ifdef OS_WIN32
#ifndef OS_WINCE
/*++
* Function:
* _OpenMapFile
* Description:
* Opens a shared memeory for passing feedback to tclient.dll
* Win32/!Win16/!WinCE
* Return value:
* TRUE if handle is allocated successfully
* Called by:
* ClxTextOut, ClxBitmap
--*/
BOOL _OpenMapFile(
UINT nSize,
HANDLE *phNewMapF,
UINT *pnMapSize
)
{
HANDLE hMapF;
UINT nPageAligned;
if (!nSize)
nPageAligned = ((sizeof(FEEDBACKINFO) / CLX_ONE_PAGE) + 1) *
CLX_ONE_PAGE;
else
nPageAligned = ((nSize / CLX_ONE_PAGE) + 1) * CLX_ONE_PAGE;
hMapF = CreateFileMapping(INVALID_HANDLE_VALUE, //PG.SYS
NULL, // no security
PAGE_READWRITE,
0, // Size high
nPageAligned, // Size low (1 page)
NULL);
*pnMapSize = (hMapF)?nPageAligned:0;
*phNewMapF = hMapF;
return (hMapF != NULL);
}
/*++
* Function:
* _ReOpenMapFile
* Description:
* Closes and opens a new shared memory with larger size
* Win32/!Win16/!WinCE
* Arguments:
* pClx - context
* newSize - size of the new memory
* Return value:
* TRUE on success
* Called by:
* ClxBitmap
--*/
BOOL _ReOpenMapFile(
UINT newSize,
HANDLE *phNewMapF,
UINT *pnMapSize
)
{
HANDLE hNewMapF;
UINT nPageAligned;
nPageAligned = ((newSize / CLX_ONE_PAGE) + 1) * CLX_ONE_PAGE;
if (*phNewMapF)
CloseHandle(*phNewMapF);
hNewMapF = CreateFileMapping(INVALID_HANDLE_VALUE, //PG.SYS
NULL, // no security
PAGE_READWRITE,
0, // Size high
nPageAligned, // Size low
NULL);
*pnMapSize = (hNewMapF)?nPageAligned:0;
*phNewMapF = hNewMapF;
return (hNewMapF != NULL);
}
/*++
* Function:
* _SaveinMapFile
* Description:
* Saves a string into the shared memory
* Win32/!Win16/!WinCE
* Arguments:
* hMapF - handle to the map file
* str - the string
* strsize - size of the string
* dwProcessId - our process Id
* Return value:
* TRUE on success
* Called by:
* ClxTextOut
--*/
BOOL _SaveInMapFile(HANDLE hMapF, LPVOID str, int strsize, DWORD_PTR dwProcessId)
{
BOOL rv = FALSE, count = 0;
PFEEDBACKINFO pView;
DWORD laste;
pView = (PFEEDBACKINFO)MapViewOfFile(hMapF,
FILE_MAP_ALL_ACCESS,
0,
0,
sizeof(*pView));
if (!pView)
goto exitpt;
pView->dwProcessId = dwProcessId;
strsize = (strsize > sizeof(pView->string)/sizeof(WCHAR) - 1)?
PtrToInt( (PVOID)(sizeof(pView->string)/sizeof(WCHAR) - 1)):
strsize;
CopyMemory(pView->string, str, strsize*sizeof(WCHAR));
((WCHAR *)(pView->string))[strsize] = 0;
pView->strsize = strsize;
UnmapViewOfFile(pView);
rv = TRUE;
exitpt:
return rv;
}
/*++
* Function:
* _CheckRegistrySettings
* Description:
* Checks if the registry settings are OK for running clxtshar
* "Allow Background Input" must be set to 1 for proper work
* Win32/!Win16/!WinCE
* Return value:
* TRUE if the settings are OK
* Called by:
* DllMain
--*/
BOOL _CheckRegistrySettings(VOID)
{
HKEY key = NULL;
DWORD disposition;
DWORD keyType;
DWORD value;
DWORD cbData;
BOOL rv = FALSE;
LONG sysrc;
sysrc = RegCreateKeyExW(HKEY_CURRENT_USER,
REG_BASE,
0, /* reserved */
NULL, /* class */
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL, /* security attributes */
&key,
&disposition);
if (sysrc != ERROR_SUCCESS)
{
TRACE((WARNING_MESSAGE,
TEXT("RegCreateKeyEx failed, status = %d\n"), sysrc));
goto exitpt;
}
cbData = sizeof(value);
sysrc = RegQueryValueExW(key,
ALLOW_BACKGROUND_INPUT,
0, // reserved
&keyType, // returned type
(LPBYTE)&value, // data pointer
&cbData);
if (sysrc != ERROR_SUCCESS)
{
TRACE((WARNING_MESSAGE,
TEXT("RegQueryValueEx failed, status = %d\n"), sysrc));
goto exitpt;
}
if (keyType != REG_DWORD || cbData != sizeof(value))
{
TRACE((WARNING_MESSAGE,
TEXT("Mismatch in type/size of registry entry\n")));
goto exitpt;
}
rv = (value == 1);
exitpt:
return rv;
}
#endif // !OS_WINCE
#endif // OS_WIN32
#ifdef OS_WIN16
/*++
* Function:
* _CheckRegistrySettings
* Description:
* Checks if the ini settings are OK for running clxtshar
* "Allow Background Input" must be set to 1 for proper work
* !Win32/Win16/!WinCE
* Return value:
* TRUE if the settings are OK
* Called by:
* DllMain
--*/
BOOL _CheckIniSettings(VOID)
{
UINT nABI;
nABI = GetPrivateProfileInt("",
ALLOW_BACKGROUND_INPUT,
0,
"mstsc.ini");
return (nABI == 1);
}
#endif // OS_WIN16
/*++
* Function:
* _GetIniSettings
* Description:
* Gets the verbose level for printing debug messages
* ini file: smclient.ini
* section : clx
* key : verbose, value: 0-4 (0-(default) no debug spew, 4 all debug)
* key : GlyphEnable, value: 0(default), 1 - Enables/Disables glyph sending
* Win32/Win16/WinCE
* Called by:
* DllMain, dllentry, LibMain
--*/
VOID _GetIniSettings(VOID)
{
#ifdef OS_WINCE
g_VerboseLevel = 4;
g_GlyphEnable = 1;
#else // !OS_WINCE
CHAR szIniFileName[_MAX_PATH];
const CHAR smclient_ini[] = "\\smclient.ini";
const CHAR clx_ini_section[] = "clx";
memset( szIniFileName, 0, sizeof( szIniFileName ));
if (!_getcwd (
szIniFileName,
sizeof(szIniFileName) - strlen(smclient_ini) - 1)
)
{
TRACE((ERROR_MESSAGE, TEXT("Current directory length too long.\n")));
}
strcat(szIniFileName, smclient_ini);
// Get the timeout value
g_VerboseLevel = GetPrivateProfileInt(
clx_ini_section,
"verbose",
g_VerboseLevel,
szIniFileName);
g_GlyphEnable = GetPrivateProfileInt(
clx_ini_section,
"GlyphEnable",
g_GlyphEnable,
szIniFileName);
#endif // !OS_WINCE
GetPrivateProfileString(
TEXT("tclient"),
TEXT("UIYesNoDisconnect"),
TEXT(YES_NO_SHUTDOWN),
g_strYesNoShutdown,
sizeof(g_strYesNoShutdown),
szIniFileName
);
GetPrivateProfileString(
TEXT("tclient"),
TEXT("UIDisconnectDialogBox"),
TEXT(DISCONNECT_DIALOG_BOX),
g_strDisconnectDialogBox,
sizeof(g_strDisconnectDialogBox),
szIniFileName
);
GetPrivateProfileString(
TEXT("tclient"),
TEXT("UIClientCaption"),
TEXT(CLIENT_CAPTION),
g_strClientCaption,
sizeof(g_strClientCaption),
szIniFileName
);
GetPrivateProfileString(
TEXT("tclient"),
TEXT("UIMainWindowClass"),
TEXT("UIMainClass"),
g_strMainWindowClass,
sizeof(g_strMainWindowClass),
szIniFileName
);
}
/*++
* Function:
* _StripGlyph
* Description:
* Strips leading and trailing blank ... BITS
* Yes, bits. The glyph must be aligned from left and right on bit
* And glyph width must be aligned on word
* Win32/Win16/WinCE
* Arguments:
* pData - the glyph bits
* pxSize - glyph width
* ySize - glyph height
* Called by:
* ClxBitmap
--*/
VOID _StripGlyph(LPBYTE pData, UINT *pxSize, UINT ySize)
{
UINT xSize = *pxSize;
UINT leftBytes, leftBits;
UINT riteBytes, riteBits;
UINT xBytes = xSize >> 3;
UINT xScan, yScan, xFinal;
BOOL bScan, bAddByte;
BYTE mask;
BYTE *pSrc, *pDst;
if (!pData || !xBytes || !ySize)
goto exitpt;
leftBytes = riteBytes = 0;
leftBits = riteBits = 0;
*pxSize = 0; // Insurance for bad exit
// Scan from left for first nonzero byte
bScan = TRUE;
while(bScan)
{
for (yScan = 0; yScan < ySize && bScan; yScan ++)
bScan = (pData[yScan*xBytes + leftBytes] == 0);
if (bScan)
{
leftBytes++;
bScan = (leftBytes < xBytes);
}
}
// Trash if blank
if (leftBytes == xBytes)
goto exitpt;
// Scan from left for most left nonzero bit
for(yScan = 0; yScan < ySize; yScan ++)
{
UINT bitc = 0;
BYTE b = pData[yScan*xBytes + leftBytes];
while (b)
{
b >>= 1;
bitc ++;
}
if (bitc > leftBits)
leftBits = bitc;
}
if (!leftBits)
// There's something wrong
goto exitpt;
leftBits = 8 - leftBits;
// So far so good. Check the ri(gh)te side
bScan = TRUE;
while(bScan)
{
for(yScan = 0 ; yScan < ySize && bScan; yScan ++)
bScan = (pData[(yScan + 1)*xBytes - 1 - riteBytes] == 0);
if (bScan)
{
riteBytes ++;
bScan = (riteBytes < xBytes);
}
}
// Scan from rite for most rite nonzero bit
for(yScan = 0; yScan < ySize; yScan ++)
{
UINT bitc = 0;
BYTE b = pData[(yScan+1)*xBytes - 1 - riteBytes];
while(b)
{
b <<= 1;
bitc ++;
}
if (bitc > riteBits)
riteBits = bitc;
}
riteBits = 8 - riteBits;
// Cool, now get the final width
xFinal = xSize - riteBits - leftBits - ((leftBytes + riteBytes) << 3);
// align it and get bytes
xFinal = (xFinal + 8) >> 3;
// Now smoothly move the bitmap to the new location
pDst = pData;
mask = BitMask[leftBits];
bAddByte = xFinal & 1;
for (yScan = 0; yScan < ySize; yScan ++)
{
pSrc = pData + yScan*xBytes + leftBytes;
for(xScan = 0; xScan < xFinal; xScan ++, pDst++, pSrc++)
{
BYTE b = *pSrc;
BYTE r;
r = (pSrc[1] & mask) >> (8 - leftBits);
b <<= leftBits;
b |= r;
(*pDst) = b;
}
pDst[-1] &= BitMask[8 - (riteBits + leftBits) % 8];
if (bAddByte)
{
(*pDst) = 0;
pDst++;
}
}
// BUG: Yes, this is a real bug. But removing it means to
// rerecord all glyph database and the impact for
// glyph recognition is not so bad
//if (bAddByte)
// xFinal++;
*pxSize = xFinal << 3;
exitpt:
;
}
/*++
* Function:
* LocalPrintMessage
* Description:
* Prints debugging and warning/error messages
* Win32/Win16/WinCE
* Arguments:
* errlevel - level of the message to print
* format - print format
* Called by:
* every TRACE line
--*/
VOID __cdecl LocalPrintMessage(INT errlevel, LPCTSTR format, ...)
{
TCHAR szBuffer[256];
TCHAR *type;
va_list arglist;
int nchr;
if (errlevel >= g_VerboseLevel)
goto exitpt;
va_start (arglist, format);
nchr = _CLX_vsnprintf (szBuffer, sizeof(szBuffer)/sizeof( szBuffer[0] ), format, arglist);
va_end (arglist);
szBuffer[sizeof( szBuffer )/sizeof( szBuffer[0] ) - 1] = 0;
switch(errlevel)
{
case INFO_MESSAGE: type = TEXT("CLX INF:"); break;
case ALIVE_MESSAGE: type = TEXT("CLX ALV:"); break;
case WARNING_MESSAGE: type = TEXT("CLX WRN:"); break;
case ERROR_MESSAGE: type = TEXT("CLX ERR:"); break;
default: type = TEXT("UNKNOWN:");
}
OutputDebugString(type);
OutputDebugString(szBuffer);
exitpt:
;
}
/*++
* Function:
* _ClxAssert
* Description:
* Asserts boolean expression
* Win32/Win16/WinCE
* Arguments:
* bCond - boolean condition
* filename - source file of the assertion
* line - line of the assertion
* Called by:
* every ASSERT line
--*/
VOID _ClxAssert(BOOL bCond, LPCTSTR filename, INT line)
{
if (!bCond)
{
TRACE((ERROR_MESSAGE,
TEXT("ASSERT: %s line %d\n"), filename, line));
DebugBreak();
}
}
/*++
* Function:
* _EnumWindowsProc
* Description:
* Used to find a specific window
* Win32/Win16/WinCE
* Arguments:
* hWnd - current enumerated window handle
* lParam - pointer to SEARCHWND passed from
* _FindTopWindow
* Return value:
* TRUE on success but window is not found
* FALSE if the window is found
* Called by:
* _FindTopWindow thru EnumWindows
--*/
BOOL CALLBACK LOADDS _EnumWindowsProc( HWND hWnd, LPARAM lParam )
{
TCHAR classname[128];
TCHAR caption[128];
BOOL rv = TRUE;
_CLXWINDOWOWNER hInst;
PSEARCHWND pSearch = (PSEARCHWND)lParam;
if (pSearch->szClassName &&
!GetClassName(hWnd, classname, sizeof(classname)/sizeof(TCHAR)))
{
goto exitpt;
}
if (pSearch->szCaption && !GetWindowText(hWnd, caption, sizeof(caption)/sizeof(TCHAR)))
{
goto exitpt;
}
#ifdef OS_WINCE
{
DWORD procId = 0;
GetWindowThreadProcessId(hWnd, &procId);
hInst = procId;
}
#else // !OS_WINCE
#ifdef _WIN64
hInst = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
#else // !_WIN64
#ifdef OS_WIN32
hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE);
#endif // OS_WIN32
#endif // !OS_WINCE
#ifdef OS_WIN16
hInst = (HINSTANCE)GetWindowWord(hWnd, GWW_HINSTANCE);
#endif
#endif // _WIN64
if (
(!pSearch->szClassName || ! // Check for classname
_CLX_strcmp(classname, pSearch->szClassName))
&&
(!pSearch->szCaption || !
_CLX_strcmp(caption, pSearch->szCaption))
&&
hInst == pSearch->hInstance)
{
((PSEARCHWND)lParam)->hWnd = hWnd;
rv = FALSE;
}
exitpt:
return rv;
}
/*++
* Function:
* _FindTopWindow
* Description:
* Find specific window by classname and/or caption and/or process Id
* Win32/Win16/WinCE
* Arguments:
* classname - class name to search for, NULL ignore
* caption - caption to search for, NULL ignore
* hInst - instance handle, NULL ignore
* Return value:
* window handle found, NULL otherwise
* Called by:
* SCConnect, SCDisconnect, GetDisconnectResult
--*/
HWND _FindTopWindow(LPCTSTR classname, LPCTSTR caption, _CLXWINDOWOWNER hInst)
{
SEARCHWND search;
search.szClassName = classname;
search.szCaption = caption;
search.hWnd = NULL;
search.hInstance = hInst;
EnumWindows(_EnumWindowsProc, (LPARAM)&search);
return search.hWnd;
}
/*++
* Function:
* _FindWindow
* Description:
* Find child window by classname
* Win32/Win16/WinCE
* Arguments:
* hwndParent - the parent window handle
* srchclass - class name to search for, NULL - ignore
* Return value:
* window handle found, NULL otherwise
* Called by:
*
--*/
HWND _FindWindow(HWND hwndParent, LPCTSTR srchclass)
{
HWND hWnd, hwndTop, hwndNext;
BOOL bFound;
TCHAR classname[128];
hWnd = NULL;
hwndTop = GetWindow(hwndParent, GW_CHILD);
if (!hwndTop)
{
TRACE((INFO_MESSAGE, TEXT("GetWindow failed. hwnd=0x%x\n"), hwndParent));
goto exiterr;
}
bFound = FALSE;
hwndNext = hwndTop;
do {
hWnd = hwndNext;
if (srchclass && !GetClassName(hWnd, classname, sizeof(classname)/sizeof(TCHAR)))
{
TRACE((INFO_MESSAGE, TEXT("GetClassName failed. hwnd=0x%x\n")));
goto nextwindow;
}
if (!srchclass || !_CLX_strcmp(classname, srchclass))
bFound = TRUE;
nextwindow:
#ifndef OS_WINCE
hwndNext = GetNextWindow(hWnd, GW_HWNDNEXT);
#else // OS_WINCE
hwndNext = GetWindow(hWnd, GW_HWNDNEXT);
#endif // OS_WINCE
} while (hWnd && hwndNext != hwndTop && !bFound);
if (!bFound) goto exiterr;
return hWnd;
exiterr:
return NULL;
}
#ifndef OS_WINCE
#ifdef OS_WIN32
DWORD
__stdcall
_ClxSendMsgThread(VOID *param)
{
PCLXINFO pClx = (PCLXINFO)param;
while(1)
{
if (!pClx || WaitForSingleObject(pClx->semSendReady, INFINITE) !=
WAIT_OBJECT_0)
goto exitpt;
if (!pClx || pClx->bSendMsgThreadExit)
goto exitpt;
SendMessage(pClx->msg.hwnd,
pClx->msg.message,
pClx->msg.wParam,
pClx->msg.lParam);
// release next waiting worker
ReleaseSemaphore(pClx->semSendDone, 1, NULL);
}
exitpt:
return 0;
}
BOOL
_ClxInitSendMessageThread( PCLXINFO pClx )
{
BOOL rv = FALSE;
DWORD dwThreadId;
if (!pClx)
goto exitpt;
if (!pClx->semSendDone)
pClx->semSendDone = CreateSemaphore(NULL, 1, 10, NULL);
if (!pClx->semSendReady)
pClx->semSendReady = CreateSemaphore(NULL, 0, 10, NULL);
if (!pClx->semSendDone || !pClx->semSendReady)
goto exitpt;
if (!pClx->hSendMsgThread)
{
pClx->hSendMsgThread = CreateThread(
NULL,
0,
_ClxSendMsgThread,
pClx,
0,
&dwThreadId);
}
if (!pClx->hSendMsgThread)
goto exitpt;
rv = TRUE;
exitpt:
if ( !rv )
{
_ClxDestroySendMsgThread( pClx );
}
return rv;
}
BOOL
_ClxAcquireSendMessageThread( PCLXINFO pClx )
{
BOOL rv = FALSE;
if (!pClx)
goto exitpt;
if (!pClx->hSendMsgThread)
goto exitpt;
// Wait 10 mins send to complete
if (WaitForSingleObject(pClx->semSendDone, 600000) !=
WAIT_OBJECT_0)
goto exitpt;
rv = TRUE;
exitpt:
return rv;
}
VOID
_ClxReleaseSendMessageThread( PCLXINFO pClx )
{
ASSERT( pClx->semSendReady );
// Signal the thread for available message
ReleaseSemaphore(pClx->semSendReady, 1, NULL);
}
/*++
* Function:
* _ClxSendMessage
* Description:
* Calls SendMessage from separate thread
* prevents deadlock on SendMessage (#319816)
*
* Arguments:
* hBitmap - the main bitmap
* ppDIB - pointer to DIB data
* left, top, right, bottom - describes the rectangle
* - if all are == -1, returns the whole bitmap
* Return value:
* TRUE on success
* Called by:
* _ClxWndProc on WM_TIMER message
--*/
LRESULT
_ClxSendMessage(
PCLXINFO pClx,
HWND hWnd, // handle of destination window
UINT Msg, // message to send
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
LRESULT rv = 0;
ASSERT(pClx->semSendDone);
ASSERT(pClx->semSendReady);
ASSERT(pClx->hSendMsgThread);
pClx->msg.hwnd = hWnd;
pClx->msg.message = Msg;
pClx->msg.wParam = wParam;
pClx->msg.lParam = lParam;
exitpt:
return rv;
}
VOID
_ClxDestroySendMsgThread(PCLXINFO pClx)
{
if (!pClx)
goto exitpt1;
if (!pClx->semSendDone || !pClx->semSendReady || !pClx->hSendMsgThread)
goto exitpt;
// Wait 10 mins send to complete
WaitForSingleObject(pClx->semSendDone, 600000);
pClx->bSendMsgThreadExit = TRUE;
// signal the thread to exit
ReleaseSemaphore(pClx->semSendReady, 1, NULL);
// wait for the thread to exit
if (WaitForSingleObject(pClx->hSendMsgThread, 1200000) != WAIT_OBJECT_0)
{
TRACE((ERROR_MESSAGE, TEXT("SendThread can't exit, calling TerminateThread\n")));
TerminateThread(pClx->hSendMsgThread, 0);
}
CloseHandle(pClx->hSendMsgThread);
exitpt:
if (pClx->semSendDone)
{
CloseHandle(pClx->semSendDone);
pClx->semSendDone = NULL;
}
if (pClx->semSendReady)
{
CloseHandle(pClx->semSendReady);
pClx->semSendReady = NULL;
}
pClx->hSendMsgThread = 0;
exitpt1:
;
}
#endif // OS_WIN32
#endif // !OS_WINCE