windows-nt/Source/XPSP1/NT/termsrv/reskit/smc/tclient/lib/tclient.c
2020-09-26 16:20:57 +08:00

1076 lines
30 KiB
C

/*++
* File name:
* tclient.c
* Contents:
* Initialization code. Global feedback thread
*
* 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 <direct.h>
#include <winsock.h>
#include "tclient.h"
#define PROTOCOLAPI __declspec(dllexport)
#include "protocol.h"
#include "queues.h"
#include "bmpcache.h"
#include "rclx.h"
#include "extraexp.h"
/*
* Internal functions definitions
*/
BOOL _RegisterWindow(VOID);
LRESULT CALLBACK _FeedbackWndProc( HWND , UINT, WPARAM, LPARAM);
BOOL _CreateFeedbackThread(VOID);
VOID _DestroyFeedbackThread(VOID);
VOID _CleanStuff(VOID);
VOID _ReadINIValues(VOID);
/*
* Global data
*/
HWND g_hWindow = NULL; // Window handle for the feedback thread
HINSTANCE g_hInstance = NULL; // Dll instance
PWAIT4STRING g_pWaitQHead = NULL; // Linked list for waited events
PFNPRINTMESSAGE g_pfnPrintMessage= NULL;// Trace function (from smclient)
PCONNECTINFO g_pClientQHead = NULL; // LL of all threads
HANDLE g_hThread = NULL; // Feedback Thread handle
UINT WAIT4STR_TIMEOUT= 600000;
// Global timeout value. Default:10 mins
// Optional from smclient.ini,
// tclient section
// timeout=600 (in seconds)
UINT CONNECT_TIMEOUT = 35000;
// Connect timeout value
// Default is 35 seconds
// This value can be changed from
// smclient.ini [tclient]
// contimeout=XXX seconds
LPCRITICAL_SECTION g_lpcsGuardWaitQueue = NULL;
// Guards the access to all
// global variables
// Some strings we are expecting and response actions
// Those are used in SCConnect, _Logon and SCStart
WCHAR g_strStartRun[MAX_STRING_LENGTH]; // Indicates that start menu is up
WCHAR g_strStartRun_Act[MAX_STRING_LENGTH]; // Chooses "Run..." from start menu
WCHAR g_strRunBox[MAX_STRING_LENGTH]; // Indication for Run... box
WCHAR g_strWinlogon[MAX_STRING_LENGTH]; // Indication that winlogon is up
WCHAR g_strWinlogon_Act[MAX_STRING_LENGTH]; // Action when winlogon appears (chooses username)
WCHAR g_strPriorWinlogon[MAX_STRING_LENGTH]; // Idication before winlogon (for example
// if Options >> appears, i.e domain
// box is hidden
WCHAR g_strPriorWinlogon_Act[MAX_STRING_LENGTH]; // Shows the domain box (Alt+O)
WCHAR g_strNTSecurity[MAX_STRING_LENGTH]; // Indication of NT Security box
WCHAR g_strNTSecurity_Act[MAX_STRING_LENGTH]; // Action on that box (logoff)
WCHAR g_strSureLogoff[MAX_STRING_LENGTH]; // Inidcation of "Are you sure" box
WCHAR g_strSureLogoffAct[MAX_STRING_LENGTH]; // Action on "Are you sure"
WCHAR g_strStartLogoff[MAX_STRING_LENGTH]; // How to invode Windows Security dialog from the start menu
WCHAR g_strLogonErrorMessage[MAX_STRING_LENGTH];
// Caption of an error box
// which appears while logging in
// responce is <Enter>
// while loging off
WCHAR g_strLogonDisabled[MAX_STRING_LENGTH];
// Caption of the box when
// logon is disabled
CHAR g_strClientCaption[MAX_STRING_LENGTH];
CHAR g_strDisconnectDialogBox[MAX_STRING_LENGTH];
CHAR g_strYesNoShutdown[MAX_STRING_LENGTH];
CHAR g_strClientImg[MAX_STRING_LENGTH];
// Low Speed option
// Cache Bitmaps on disc option
// by default, client will not run
// in full screen
INT g_ConnectionFlags = TSFLAG_COMPRESSION|TSFLAG_BITMAPCACHE;
/*++
* Function:
* InitDone
*
* Description:
* Initialize/delete global data. Create/destroy
* feedback thread
*
* Arguments:
* hDllInst - Instance to the DLL
* bInit - TRUE if initialize
*
* Return value:
* TRUE if succeeds
*
--*/
int InitDone(HINSTANCE hDllInst, int bInit)
{
int rv = TRUE;
if (bInit)
{
CHAR szMyLibName[_MAX_PATH];
g_lpcsGuardWaitQueue = malloc(sizeof(*g_lpcsGuardWaitQueue));
if (!g_lpcsGuardWaitQueue)
{
rv = FALSE;
goto exitpt;
}
// Overreference the library
// The reason for that is beacuse an internal thread is created.
// When the library trys to unload it can't kill that thread
// and wait for its handle to get signaled, because
// the thread itself wants to go to DllEntry and this
// causes a deadlock. The best solution is to overreference the
// handle so the library is unload at the end of the process
if (!GetModuleFileName(hDllInst, szMyLibName, sizeof(szMyLibName)))
{
TRACE((ERROR_MESSAGE, "Can't overref the dll. Exit.\n"));
free(g_lpcsGuardWaitQueue);
rv = FALSE;
goto exitpt;
}
if (!LoadLibrary(szMyLibName))
{
TRACE((ERROR_MESSAGE, "Can't overref the dll. Exit.\n"));
free(g_lpcsGuardWaitQueue);
rv = FALSE;
goto exitpt;
}
g_hInstance = hDllInst;
InitializeCriticalSection(g_lpcsGuardWaitQueue);
InitCache();
_ReadINIValues();
if (_RegisterWindow()) // If failed to register the window,
_CreateFeedbackThread(); // means the feedback thread will
// not work
} else
{
if (g_pWaitQHead || g_pClientQHead)
{
TRACE((ERROR_MESSAGE,
"The Library unload is unclean. Will try to fix this\n"));
_CleanStuff();
}
_DestroyFeedbackThread();
DeleteCache();
if (g_lpcsGuardWaitQueue)
{
DeleteCriticalSection(g_lpcsGuardWaitQueue);
free(g_lpcsGuardWaitQueue);
}
g_lpcsGuardWaitQueue = NULL;
g_hInstance = NULL;
g_pfnPrintMessage = NULL;
}
exitpt:
return rv;
}
/*
* Used by perl script to break into the kernel debugger
*/
void MyBreak(void)
{
TRACE((INFO_MESSAGE, "Break is called\n"));
DebugBreak();
}
VOID
_ConvertAnsiToUnicode( LPWSTR wszDst, LPWSTR wszSrc )
{
#define _TOHEX(_d_) ((_d_ <= '9' && _d_ >= '0')?_d_ - '0': \
(_d_ <= 'f' && _d_ >= 'a')?_d_ - 'a' + 10: \
(_d_ <= 'F' && _d_ >= 'F')?_d_ - 'A' + 10:0)
while( wszSrc[0] && wszSrc[1] && wszSrc[2] && wszSrc[3] )
{
*wszDst = (_TOHEX(wszSrc[0]) << 4) + _TOHEX(wszSrc[1]) +
(((_TOHEX(wszSrc[2]) << 4) + _TOHEX(wszSrc[3])) << 8);
wszDst ++;
wszSrc += 4;
}
*wszDst = 0;
#undef _TOHEX
}
/*
*
* Wrappers for GetPrivateProfileW, on Win95 there's no UNICODE veriosn
* of this function
*
*/
DWORD
_WrpGetPrivateProfileStringW(
LPCWSTR lpAppName,
LPCWSTR lpKeyName,
LPCWSTR lpDefault,
LPWSTR lpReturnedString,
DWORD nSize,
LPCWSTR lpFileName)
{
DWORD rv = 0;
CHAR szAppName[MAX_STRING_LENGTH];
CHAR szKeyName[MAX_STRING_LENGTH];
CHAR szDefault[MAX_STRING_LENGTH];
CHAR szReturnedString[MAX_STRING_LENGTH];
CHAR szFileName[MAX_STRING_LENGTH];
rv = GetPrivateProfileStringW(
lpAppName,
lpKeyName,
lpDefault,
lpReturnedString,
nSize,
lpFileName);
if (rv)
goto exitpt;
// Call the ANSI version
_snprintf(szAppName, MAX_STRING_LENGTH, "%S", lpAppName);
_snprintf(szKeyName, MAX_STRING_LENGTH, "%S", lpKeyName);
_snprintf(szFileName, MAX_STRING_LENGTH, "%S", lpFileName);
_snprintf(szDefault, MAX_STRING_LENGTH, "%S", lpDefault);
rv = GetPrivateProfileString(
szAppName,
szKeyName,
szDefault,
szReturnedString,
sizeof(szReturnedString),
szFileName);
_snwprintf(lpReturnedString, nSize, L"%S", szReturnedString);
exitpt:
if ( L'\\' == lpReturnedString[0] &&
L'U' == towupper(lpReturnedString[1]))
_ConvertAnsiToUnicode( lpReturnedString, lpReturnedString + 2 );
return rv;
}
UINT
_WrpGetPrivateProfileIntW(
LPCWSTR lpAppName,
LPCWSTR lpKeyName,
INT nDefault,
LPCWSTR lpFileName)
{
UINT rv = (UINT)-1;
CHAR szAppName[MAX_STRING_LENGTH];
CHAR szKeyName[MAX_STRING_LENGTH];
CHAR szFileName[MAX_STRING_LENGTH];
rv = GetPrivateProfileIntW(
lpAppName,
lpKeyName,
nDefault,
lpFileName);
if (rv != (UINT)-1 && rv)
goto exitpt;
// Call the ANSI version
_snprintf(szAppName, MAX_STRING_LENGTH, "%S", lpAppName);
_snprintf(szKeyName, MAX_STRING_LENGTH, "%S", lpKeyName);
_snprintf(szFileName, MAX_STRING_LENGTH, "%S", lpFileName);
rv = GetPrivateProfileInt(
szAppName,
szKeyName,
nDefault,
szFileName);
exitpt:
return rv;
}
/*++
* Function:
* _ReadINIValues
*
* Description:
* Reads smclient.ini, section [tclient], variable "timeout"
* This is a global timeout for Wait4Str etc
* Also read some other values
* Arguments:
* none
* Return value:
* none
*
--*/
VOID _ReadINIValues(VOID)
{
UINT nNew;
WCHAR szIniFileName[_MAX_PATH];
WCHAR szBuff[ 4 * MAX_STRING_LENGTH];
WCHAR szBuffDef[MAX_STRING_LENGTH];
BOOL bFlag;
// Construct INI path
*szIniFileName = 0;
if (!_wgetcwd (
szIniFileName,
(int)(sizeof(szIniFileName)/sizeof(WCHAR) - wcslen(SMCLIENT_INI) - 1))
)
{
TRACE((ERROR_MESSAGE, "Current directory length too long.\n"));
}
wcscat(szIniFileName, SMCLIENT_INI);
// Get the timeout value
nNew = _WrpGetPrivateProfileIntW(
TCLIENT_INI_SECTION,
L"timeout",
600,
szIniFileName);
if (nNew)
{
WAIT4STR_TIMEOUT = nNew * 1000;
TRACE((INFO_MESSAGE, "New timeout: %d seconds\n", nNew));
}
nNew = _WrpGetPrivateProfileIntW(
TCLIENT_INI_SECTION,
L"contimeout",
35,
szIniFileName);
if (nNew)
{
CONNECT_TIMEOUT = nNew * 1000;
TRACE((INFO_MESSAGE, "New timeout: %d seconds\n", nNew));
}
g_ConnectionFlags = 0;
bFlag =
_WrpGetPrivateProfileIntW(
TCLIENT_INI_SECTION,
L"LowSpeed",
0,
szIniFileName);
if (bFlag)
g_ConnectionFlags |=TSFLAG_COMPRESSION;
bFlag =
_WrpGetPrivateProfileIntW(
TCLIENT_INI_SECTION,
L"PersistentCache",
0,
szIniFileName);
if (bFlag)
g_ConnectionFlags |=TSFLAG_BITMAPCACHE;
bFlag =
_WrpGetPrivateProfileIntW(
TCLIENT_INI_SECTION,
L"FullScreen",
0,
szIniFileName);
if (bFlag)
g_ConnectionFlags |=TSFLAG_FULLSCREEN;
// read the strings
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"StartRun",
RUN_MENU,
g_strStartRun,
MAX_STRING_LENGTH,
szIniFileName);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"StartLogoff",
START_LOGOFF,
g_strStartLogoff,
MAX_STRING_LENGTH,
szIniFileName);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"StartRunAct",
RUN_ACT,
g_strStartRun_Act,
MAX_STRING_LENGTH,
szIniFileName);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"RunBox",
RUN_BOX,
g_strRunBox,
MAX_STRING_LENGTH,
szIniFileName);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"WinLogon",
WINLOGON_USERNAME,
g_strWinlogon,
MAX_STRING_LENGTH,
szIniFileName);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"WinLogonAct",
WINLOGON_ACT,
g_strWinlogon_Act,
MAX_STRING_LENGTH,
szIniFileName);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"PriorWinLogon",
PRIOR_WINLOGON,
g_strPriorWinlogon,
MAX_STRING_LENGTH,
szIniFileName);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"PriorWinLogonAct",
PRIOR_WINLOGON_ACT,
g_strPriorWinlogon_Act,
MAX_STRING_LENGTH,
szIniFileName);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"NTSecurity",
WINDOWS_NT_SECURITY,
g_strNTSecurity,
MAX_STRING_LENGTH,
szIniFileName);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"NTSecurityAct",
WINDOWS_NT_SECURITY_ACT,
g_strNTSecurity_Act,
MAX_STRING_LENGTH,
szIniFileName);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"SureLogoff",
ARE_YOU_SURE,
g_strSureLogoff,
MAX_STRING_LENGTH,
szIniFileName);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"SureLogoffAct",
SURE_LOGOFF_ACT,
g_strSureLogoffAct,
MAX_STRING_LENGTH,
szIniFileName);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"LogonErrorMessage",
LOGON_ERROR_MESSAGE,
g_strLogonErrorMessage,
MAX_STRING_LENGTH,
szIniFileName);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"LogonDisabled",
LOGON_DISABLED_MESSAGE,
g_strLogonDisabled,
MAX_STRING_LENGTH,
szIniFileName);
_snwprintf(szBuffDef, sizeof(szBuffDef), L"%S", CLIENT_CAPTION);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"UIClientCaption",
szBuffDef,
szBuff,
MAX_STRING_LENGTH,
szIniFileName);
_snprintf(g_strClientCaption, MAX_STRING_LENGTH, "%S", szBuff);
_snwprintf(szBuffDef, sizeof(szBuffDef), L"%S", DISCONNECT_DIALOG_BOX);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"UIDisconnectDialogBox",
szBuffDef,
szBuff,
MAX_STRING_LENGTH,
szIniFileName);
_snprintf(g_strDisconnectDialogBox, MAX_STRING_LENGTH, "%S", szBuff);
_snwprintf(szBuffDef, sizeof(szBuffDef), L"%S", YES_NO_SHUTDOWN);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"UIYesNoDisconnect",
szBuffDef,
szBuff,
MAX_STRING_LENGTH,
szIniFileName);
_snprintf(g_strYesNoShutdown, MAX_STRING_LENGTH, "%S", szBuff);
_snwprintf(szBuffDef, sizeof(szBuffDef), L"%S", CLIENT_EXE);
_WrpGetPrivateProfileStringW(
TCLIENT_INI_SECTION,
L"ClientImage",
szBuffDef,
szBuff,
MAX_STRING_LENGTH,
szIniFileName);
_snprintf(g_strClientImg, MAX_STRING_LENGTH, "%S", szBuff);
}
/*++
* Function:
* _FeedbackWndProc
* Description:
* Window proc wich dispatches messages containing feedback
* The messages are usualy sent by RDP clients
*
--*/
LRESULT CALLBACK _FeedbackWndProc( HWND hwnd,
UINT uiMessage,
WPARAM wParam,
LPARAM lParam)
{
HANDLE hMapF = NULL;
switch (uiMessage)
{
case WM_FB_TEXTOUT:
_TextOutReceived((DWORD)wParam, (HANDLE)lParam);
break;
case WM_FB_GLYPHOUT:
_GlyphReceived((DWORD)wParam, (HANDLE)lParam);
break;
case WM_FB_DISCONNECT:
_SetClientDead(lParam);
_CheckForWorkerWaitingDisconnect(lParam);
_CancelWaitingWorker(lParam);
break;
case WM_FB_CONNECT:
_CheckForWorkerWaitingConnect((HWND)wParam, lParam);
break;
case WM_FB_LOGON:
TRACE((INFO_MESSAGE, "LOGON event, session ID=%d\n",
wParam));
_SetSessionID(lParam, (UINT)wParam);
break;
break;
case WM_FB_ACCEPTME:
return (_CheckIsAcceptable(lParam, FALSE) != NULL);
case WM_WSOCK: // Windows socket messages
RClx_DispatchWSockEvent((SOCKET)wParam, lParam);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, uiMessage, wParam, lParam);
}
return 0;
}
/*++
* Function:
* _RegisterWindow
* Description:
* Resgisters window class for the feedback dispatcher
* Arguments:
* none
* Return value:
* TRUE on success
*
--*/
BOOL _RegisterWindow(VOID)
{
WNDCLASS wc;
BOOL rv;
DWORD dwLastErr;
memset(&wc, 0, sizeof(wc));
wc.lpfnWndProc = _FeedbackWndProc;
wc.hInstance = g_hInstance;
wc.lpszClassName = _TSTNAMEOFCLAS;
if (!RegisterClass (&wc) &&
(dwLastErr = GetLastError()) &&
dwLastErr != ERROR_CLASS_ALREADY_EXISTS)
{
TRACE((ERROR_MESSAGE,
"Can't register class. GetLastError=%d\n",
GetLastError()));
goto exitpt;
}
rv = TRUE;
exitpt:
return rv;
}
/*++
* Function:
* _GoFeedback
* Description:
* Main function for the feedback thread. The thread is created for the
* lifetime of the DLL
* Arguments:
* lpParam is unused
* Return value:
* Thread exit code
--*/
DWORD WINAPI _GoFeedback(LPVOID lpParam)
{
MSG msg;
g_hWindow = CreateWindow(
_TSTNAMEOFCLAS,
NULL, // Window name
0, // dwStyle
0, // x
0, // y
0, // nWidth
0, // nHeight
NULL, // hWndParent
NULL, // hMenu
g_hInstance,
NULL); // lpParam
if (!g_hWindow)
{
TRACE((ERROR_MESSAGE, "No feedback window handle"));
goto exitpt;
} else {
if (!RClx_Init())
TRACE((ERROR_MESSAGE, "Can't initialize RCLX\n"));
while (GetMessage (&msg, NULL, 0, 0) && msg.message != WM_FB_END)
{
DispatchMessage (&msg);
}
RClx_Done();
}
TRACE((INFO_MESSAGE, "Window/Thread destroyed\n"));
FreeLibraryAndExitThread(g_hInstance, 0);
exitpt:
return 1;
}
/*++
* Function:
* _SetClientRegistry
* Description:
* Sets the registry prior running RDP client
* The format of the key is: smclient_PID_TID
* PID is the process ID and TID is the thread ID
* This key is deleated after the client disconnects
* Arguments:
* lpszServerName - server to which the client will connect
* xRes, yRes - clients resolution
* bLowSpeed - low speed (compression) option
* bCacheBitmaps - cache the bitmaps to the disc option
* bFullScreen - the client will be in full screen mode
* Called by:
* SCConnect
--*/
VOID
_SetClientRegistry(
LPCWSTR lpszServerName,
LPCWSTR lpszShell,
INT xRes,
INT yRes,
INT ConnectionFlags)
{
const CHAR *pData;
CHAR szServer[MAX_STRING_LENGTH];
register int i;
LONG sysrc;
HKEY key;
DWORD disposition;
DWORD dataSize;
DWORD ResId;
CHAR lpszRegistryEntry[4*MAX_STRING_LENGTH];
RECT rcDesktop = {0, 0, 0, 0};
INT desktopX, desktopY;
_snprintf(lpszRegistryEntry, sizeof(lpszRegistryEntry),
"%s\\" REG_FORMAT,
REG_BASE, GetCurrentProcessId(), GetCurrentThreadId());
// Get desktop size
GetWindowRect(GetDesktopWindow(), &rcDesktop);
desktopX = rcDesktop.right;
desktopY = rcDesktop.bottom;
// Adjust the resolution
if (desktopX < xRes || desktopY < yRes)
{
xRes = desktopX;
yRes = desktopY;
}
// Convert lpszServerName to proper format
for (i=0; i < sizeof(szServer)/sizeof(TCHAR)-1 && lpszServerName[i]; i++)
szServer[i] = (CHAR)lpszServerName[i];
szServer[i] = 0;
pData = szServer;
dataSize = (strlen(pData)+1);
// Before starting ducati client set registry with server name
sysrc = RegCreateKeyEx(HKEY_CURRENT_USER,
lpszRegistryEntry,
0, /* reserved */
NULL, /* class */
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL, /* security attributes */
&key,
&disposition);
if (sysrc != ERROR_SUCCESS)
{
TRACE((WARNING_MESSAGE, "RegCreateKeyEx failed, sysrc = %d\n", sysrc));
goto exitpt;
}
sysrc = RegSetValueEx(key,
TEXT("MRU0"),
0, // reserved
REG_SZ,
(LPBYTE)pData,
dataSize);
if (sysrc != ERROR_SUCCESS)
{
TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc));
}
// Set alternative shell (if specified
if (lpszShell)
{
sysrc = RegSetValueEx(key,
TEXT("Alternate Shell"),
0, // reserved
REG_BINARY,
(LPBYTE)lpszShell,
wcslen(lpszShell) * sizeof(*lpszShell));
if (sysrc != ERROR_SUCCESS)
{
TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc));
}
}
// Set the resolution
if (xRes >= 1600 && yRes >= 1200) ResId = 4;
else if (xRes >= 1280 && yRes >= 1024) ResId = 3;
else if (xRes >= 1024 && yRes >= 768) ResId = 2;
else if (xRes >= 800 && yRes >= 600) ResId = 1;
else ResId = 0; // 640x480
sysrc = RegSetValueEx(key,
"Desktop Size ID",
0,
REG_DWORD,
(LPBYTE)&ResId,
sizeof(ResId));
if (sysrc != ERROR_SUCCESS)
{
TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc));
}
ResId = 1;
sysrc = RegSetValueEx(key,
"Auto Connect",
0, // reserved
REG_DWORD,
(LPBYTE)&ResId,
sizeof(ResId));
if (sysrc != ERROR_SUCCESS)
{
TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc));
}
ResId = (ConnectionFlags & TSFLAG_BITMAPCACHE)?1:0;
sysrc = RegSetValueEx(key,
"BitmapCachePersistEnable",
0, // reserved
REG_DWORD,
(LPBYTE)&ResId,
sizeof(ResId));
if (sysrc != ERROR_SUCCESS)
{
TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc));
}
ResId = (ConnectionFlags & TSFLAG_COMPRESSION)?1:0;
sysrc = RegSetValueEx(key,
"Compression",
0, // reserved
REG_DWORD,
(LPBYTE)&ResId,
sizeof(ResId));
if (sysrc != ERROR_SUCCESS)
{
TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc));
}
if (ConnectionFlags & TSFLAG_FULLSCREEN)
{
ResId = 2;
sysrc = RegSetValueEx(key,
"Screen Mode ID",
0, // reserved
REG_DWORD,
(LPBYTE)&ResId,
sizeof(ResId));
if (sysrc != ERROR_SUCCESS)
{
TRACE((WARNING_MESSAGE,
"RegSetValue failed, status = %d\n", sysrc));
}
}
RegCloseKey(key);
ResId = 1;
sysrc = RegCreateKeyEx(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, "RegCreateKeyEx failed, sysrc = %d\n", sysrc));
goto exitpt;
}
sysrc = RegSetValueEx(key,
ALLOW_BACKGROUND_INPUT,
0,
REG_DWORD,
(LPBYTE)&ResId,
sizeof(ResId));
if (sysrc != ERROR_SUCCESS)
{
TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc));
}
RegCloseKey(key);
exitpt:
;
}
/*++
* Function:
* _DeleteClientRegistry
* Description:
* Deletes the key set by _SetClientRegistry
* Called by:
* SCDisconnect
--*/
VOID _DeleteClientRegistry(PCONNECTINFO pCI)
{
CHAR lpszRegistryEntry[4*MAX_STRING_LENGTH];
LONG sysrc;
_snprintf(lpszRegistryEntry, sizeof(lpszRegistryEntry),
"%s\\" REG_FORMAT,
REG_BASE, GetCurrentProcessId(), pCI->OwnerThreadId);
sysrc = RegDeleteKey(HKEY_CURRENT_USER, lpszRegistryEntry);
if (sysrc != ERROR_SUCCESS)
{
TRACE((WARNING_MESSAGE, "RegDeleteKey failed, status = %d\n", sysrc));
}
}
/*++
* Function:
* _CreateFeedbackThread
* Description:
* Creates the feedback thread
* Called by:
* InitDone
--*/
BOOL _CreateFeedbackThread(VOID)
{
BOOL rv = TRUE;
// Register feedback window class
WNDCLASS wc;
DWORD dwThreadId, dwLastErr;
g_hThread = (HANDLE)
_beginthreadex
(NULL,
0,
(unsigned (__stdcall *)(void*))_GoFeedback,
NULL,
0,
&dwThreadId);
if (!g_hThread) {
TRACE((ERROR_MESSAGE, "Couldn't create thread\n"));
rv = FALSE;
}
return rv;
}
/*++
* Function:
* _DestroyFeedbackThread
* Description:
* Destroys the thread created by _CreateFeedbackThread
* Called by:
* InitDone
--*/
VOID _DestroyFeedbackThread(VOID)
{
if (g_hThread)
{
DWORD dwWait;
CHAR szMyLibName[_MAX_PATH];
// Closing feedback thread
PostMessage(g_hWindow, WM_FB_END, 0, 0);
TRACE((INFO_MESSAGE, "Closing DLL thread\n"));
// Dedstroy the window
DestroyWindow(g_hWindow);
// CloseHandle(g_hThread);
g_hThread = NULL;
}
}
/*++
* Function:
* _CleanStuff
* Description:
* Cleans the global queues. Closes any resources
* Called by:
* InitDone
--*/
VOID _CleanStuff(VOID)
{
// Thread safe, bacause is executed from DllEntry
while (g_pClientQHead)
{
TRACE((WARNING_MESSAGE, "Cleaning connection info: 0x%x\n",
g_pClientQHead));
SCDisconnect(g_pClientQHead);
}
#if 0
if (g_pClientQHead)
{
PCONNECTINFO pNext, pIter = g_pClientQHead;
while (pIter)
{
int nEv;
DWORD wres;
TRACE((WARNING_MESSAGE, "Cleaning connection info: 0x%x\n", pIter));
// Clear Events
if (pIter->evWait4Str)
{
CloseHandle(pIter->evWait4Str);
pIter->evWait4Str = NULL;
}
for (nEv = 0; nEv < pIter->nChatNum; nEv ++)
CloseHandle(pIter->aevChatSeq[nEv]);
pIter->nChatNum = 0;
// Clear Processes
do {
SendMessage(pIter->hClient, WM_CLOSE, 0, 0);
} while((wres = WaitForSingleObject(pIter->hProcess, WAIT4STR_TIMEOUT/4) == WAIT_TIMEOUT));
if (wres == WAIT_TIMEOUT)
{
TRACE((WARNING_MESSAGE,
"Can't close process. WaitForSingleObject timeouts\n"));
TRACE((WARNING_MESSAGE,
"Process #%d will be killed\n",
pIter->dwProcessId ));
if (!TerminateProcess(pIter->hProcess, 1))
{
TRACE((WARNING_MESSAGE,
"Can't kill process #%d. GetLastError=%d\n",
pIter->dwProcessId, GetLastError()));
}
}
TRACE((WARNING_MESSAGE, "Closing process\n"));
if (pIter->hProcess)
CloseHandle(pIter->hProcess);
if (pIter->hThread)
CloseHandle(pIter->hThread);
pIter->hProcess = pIter->hThread = NULL;
// Free the structures
pNext = pIter->pNext;
free(pNext);
pIter = pNext;
}
}
#endif // 0
}
VOID _TClientAssert( LPCTSTR filename, INT line)
{
TRACE(( ERROR_MESSAGE, "ASSERT %s line: %d\n", filename, line));
DebugBreak();
}