/*++ * File name: * tclient.c * Contents: * Initialization code. Global feedback thread * * Copyright (C) 1998-1999 Microsoft Corp. * --*/ #include "stdafx.h" #include #include #include #include #include #include #include #include #include #include #define WIDE2ANSI(_p_, _s_) \ if ( NULL != _s_ ) \ { \ size_t len = wcslen( _s_ ) + 1; \ size_t wlen = sizeof(wchar_t) * len; \ char *wc = (char *)_alloca( wlen ); \ \ WideCharToMultiByte( \ CP_UTF8, 0, _s_, -1, wc, (int)wlen, NULL, NULL \ ); \ _p_ = wc; \ } else { \ _p_ = NULL; \ } #include "tclient.h" #define PROTOCOLAPI __declspec(dllexport) #include "protocol.h" #include "queues.h" #include "bmpcache.h" #include "extraexp.h" #include "scfuncs.h" // // COM support. // #include "resource.h" #include "initguid.h" #include "tclientax.h" #include "tclientaxobj.h" #include #include #define IID_DEFINED #include "tclientax_i.c" CComModule _Module; BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_CTClient, CTClientApi) END_OBJECT_MAP() // // Use C linkage for global data. // extern "C" { /* * stolen from tssec.h */ VOID _stdcall TSRNG_Initialize( VOID ); BOOL _stdcall TSRNG_GenerateRandomBits( LPBYTE pbRandomKey, DWORD dwRandomKeyLen ); BOOL _stdcall EncryptDecryptLocalData50( LPBYTE pbData, DWORD dwDataLen, LPBYTE pbSalt, DWORD dwSaltLen ); /* * Internal functions definitions */ BOOL _RegisterWindow(VOID); LRESULT CALLBACK _FeedbackWndProc( HWND , UINT, WPARAM, LPARAM); BOOL _CreateFeedbackThread(VOID); VOID _DestroyFeedbackThread(VOID); VOID _CleanStuff(VOID); /* * Global data */ OSVERSIONINFOEXW g_OsInfo; 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 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 CHAR g_strConsoleExtension[ MAX_STRING_LENGTH ]; // Ferit's extension for the // console // Low Speed option // Cache Bitmaps on disc option // by default, client will not run // in full screen INT g_ConnectionFlags = TSFLAG_COMPRESSION|TSFLAG_BITMAPCACHE|TSFLAG_DRIVES|TSFLAG_PORTS; // Apply translation so the english strings are human readable // when language packs are installed // INT g_bTranslateStrings = 0; /*++ * 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) { WCHAR szMyLibName[_MAX_PATH]; // // Initialize the COM module. // _Module.Init(ObjectMap, hDllInst); g_lpcsGuardWaitQueue = (LPCRITICAL_SECTION) 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 (!GetModuleFileNameW(hDllInst, szMyLibName, sizeof(szMyLibName) / sizeof(*szMyLibName))) { TRACE((ERROR_MESSAGE, "Can't overref the dll. Exit.\n")); free(g_lpcsGuardWaitQueue); rv = FALSE; goto exitpt; } else { szMyLibName[SIZEOF_ARRAY(szMyLibName) - 1] = 0; } if (!LoadLibraryW(szMyLibName)) { TRACE((ERROR_MESSAGE, "Can't overref the dll. Exit.\n")); free(g_lpcsGuardWaitQueue); rv = FALSE; goto exitpt; } // get the OS info ZeroMemory(&g_OsInfo, sizeof(g_OsInfo)); g_OsInfo.dwOSVersionInfoSize = sizeof(g_OsInfo); if (!GetVersionExW((LPOSVERSIONINFOW)&g_OsInfo)) { // // Windows 9x does not support OSVERSIONINFOEX, so retry with // OSVERSIONINFO. // ZeroMemory(&g_OsInfo, sizeof(g_OsInfo)); g_OsInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); if (!GetVersionExW((LPOSVERSIONINFOW)&g_OsInfo)) { TRACE((ERROR_MESSAGE, "GetVersionEx failed.Exit\n")); free(g_lpcsGuardWaitQueue); rv = FALSE; goto exitpt; } } g_hInstance = hDllInst; InitializeCriticalSection(g_lpcsGuardWaitQueue); InitCache(); 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; // // Terminate the COM module. // _Module.Term(); } exitpt: return rv; } #if 0 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 = (WCHAR)((_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 szReturnedStringNonExp[MAX_STRING_LENGTH]; CHAR szFileName[MAX_STRING_LENGTH]; LPWSTR szwReturnedString = NULL; ASSERT( 0 != nSize ); if ( nSize < wcslen( lpDefault )) wcsncpy( lpReturnedString, lpDefault, nSize - 1 ); else wcscpy( lpReturnedString, lpDefault ); __try { szwReturnedString = (LPWSTR) alloca(( nSize + 1 ) * sizeof( WCHAR )); } __except( EXCEPTION_EXECUTE_HANDLER ) { szwReturnedString = NULL; } if ( !szwReturnedString ) goto exitpt; if (ISNT()) { rv = GetPrivateProfileStringW( lpAppName, lpKeyName, lpDefault, szwReturnedString, 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 = GetPrivateProfileStringA( szAppName, szKeyName, szDefault, szReturnedStringNonExp, sizeof(szReturnedString), szFileName); ExpandEnvironmentStringsA( szReturnedStringNonExp, szReturnedString, sizeof(szReturnedString) ); _snwprintf(lpReturnedString, nSize, L"%S", szReturnedString); lpReturnedStrig[ nSize - 1 ] = 0; exitpt: if ( NULL != szwReturnedString ) { // expand the string // ExpandEnvironmentStringsW( szwReturnedString, lpReturnedString, nSize ); } 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 = GetPrivateProfileIntA( szAppName, szKeyName, nDefault, szFileName); exitpt: return rv; } LONG RegCreateKeyExWrp( HKEY hkey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, PDWORD lpdwDisposition ) { LONG rv; if (!ISWIN9X()) { return RegCreateKeyExW( hkey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition ); } __try { CHAR *lpSubKeyA; CHAR *lpClassA; WIDE2ANSI( lpSubKeyA, lpSubKey ); WIDE2ANSI( lpClassA, lpClass ); rv = RegCreateKeyExA( hkey, lpSubKeyA, Reserved, lpClassA, dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition ); } __except( (GetExceptionCode() == STATUS_STACK_OVERFLOW)? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) { rv = ERROR_STACK_OVERFLOW; } return rv; } LONG RegSetValueExWrp( HKEY hkey, LPCWSTR lpValueName, DWORD reserved, DWORD dwType, CONST BYTE *lpData, DWORD cbData ) { LONG rv; if (!ISWIN9X()) { return RegSetValueEx( hkey, lpValueName, reserved, dwType, lpData, cbData ); } __try { CHAR *lpValueNameA; CHAR *lpDataA; WIDE2ANSI( lpValueNameA, lpValueName ); if ( REG_SZ == dwType ) { WIDE2ANSI( lpDataA, ((LPCWSTR)lpData) ); lpData = (CONST BYTE *)lpDataA; cbData = (DWORD)strlen( lpDataA ); } rv = RegSetValueExA( hkey, lpValueNameA, reserved, dwType, lpData, cbData ); } __except( (GetExceptionCode() == STATUS_STACK_OVERFLOW) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) { rv = ERROR_STACK_OVERFLOW; } return rv; } LONG RegQueryValueExWrp( HKEY hKey, // handle to key LPCWSTR lpValueName, // value name PDWORD lpReserved, // reserved PDWORD lpType, // type buffer PBYTE lpData, // data buffer PDWORD lpcbData // size of data buffer ) { LONG rv; if (!ISWIN9X()) { return RegQueryValueEx( hKey, lpValueName, lpReserved, lpType, lpData, lpcbData ); } __try { CHAR *lpValueNameA; WIDE2ANSI( lpValueNameA, lpValueName ); rv = RegQueryValueExA( hKey, lpValueNameA, lpReserved, lpType, lpData, lpcbData ); } __except( (GetExceptionCode() == STATUS_STACK_OVERFLOW) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) { rv = ERROR_STACK_OVERFLOW; } return rv; } LONG RegDeleteKeyWrp( HKEY hkey, LPCWSTR lpSubKey ) { LONG rv; if ( !ISWIN9X() ) { return RegDeleteKeyW( hkey, lpSubKey ); } __try { CHAR *lpSubKeyA; WIDE2ANSI( lpSubKeyA, lpSubKey ); rv = RegDeleteKeyA( hkey, lpSubKeyA ); } __except( (GetExceptionCode() == STATUS_STACK_OVERFLOW) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) { rv = ERROR_STACK_OVERFLOW; } return rv; } INT GetClassNameWrp( HWND hwnd, LPWSTR szName, INT max ) { LPSTR szNameA; INT maxA; INT rv; if ( !ISWIN9X() ) { return GetClassNameW( hwnd, szName,max ); } maxA = max / sizeof( WCHAR ); __try { szNameA = (LPSTR)_alloca( maxA ); } __except( EXCEPTION_EXECUTE_HANDLER ) { SetLastError( ERROR_STACK_OVERFLOW ); rv = 0; goto exitpt; } rv = GetClassNameA( hwnd, szNameA, maxA ); MultiByteToWideChar( CP_UTF8, 0, szNameA, maxA, szName, max ); exitpt: return rv; } INT GetWindowTextWrp( HWND hwnd, LPWSTR szText, INT max ) { LPSTR szTextA; INT maxA; INT rv; if ( !ISWIN9X() ) { return GetWindowTextW( hwnd, szText ,max ); } maxA = max / sizeof( WCHAR ); __try { szTextA = (LPSTR)_alloca( maxA ); } __except( EXCEPTION_EXECUTE_HANDLER ) { SetLastError( ERROR_STACK_OVERFLOW ); rv = 0; goto exitpt; } rv = GetClassNameA( hwnd, szTextA, maxA ); MultiByteToWideChar( CP_UTF8, 0, szTextA, maxA, szText, max ); exitpt: return rv; } #endif // 0 /*++ * Function: * ConstructLogonString * * Description: * Constructs the client command line. The format is taken from * the INI file, supports the following parameters: * %srv% - destination server * %usr% - username * %psw% - password * %dom% - domain * * Arguments: * * Return value: * none * --*/ VOID ConstructLogonString( LPCWSTR lpszServerName, LPCWSTR lpszUserName, LPCWSTR lpszPassword, LPCWSTR lpszDomain, LPWSTR szLine, DWORD dwSize, PCONFIGINFO pConfig ) { DWORD_PTR dwFmtSize; LPWSTR szFmt; // // fix the parameters // if ( NULL == lpszServerName ) lpszServerName = L""; if ( NULL == lpszUserName ) lpszUserName = L""; if ( NULL == lpszPassword ) lpszPassword = L""; if ( NULL == lpszDomain ) lpszDomain = L""; if ( dwSize < 1 ) return; if ( NULL == pConfig ) return; szFmt = pConfig->strLogonFmt; dwFmtSize = wcslen( szFmt ); for( ; 0 != dwFmtSize && dwSize > 1 ; ) { // // optimize the code path // if ( L'%' != *szFmt ) goto copy_char; if ( dwFmtSize >= 5 ) { INT iNewLen; if ( !_wcsnicmp( szFmt, L"%srv%", 5 )) { iNewLen = _snwprintf( szLine, dwSize, L"%s", lpszServerName ); if ( iNewLen < 0 ) { break; } szLine += iNewLen; dwSize -= iNewLen; szFmt += 5; dwFmtSize -= 5; } else if ( !_wcsnicmp( szFmt, L"%usr%", 5 )) { iNewLen = _snwprintf( szLine, dwSize, L"%s", lpszUserName ); if ( iNewLen < 0 ) { break; } szLine += iNewLen; dwSize -= iNewLen; szFmt += 5; dwFmtSize -= 5; } else if ( !_wcsnicmp( szFmt, L"%psw%", 5 )) { iNewLen = _snwprintf( szLine, dwSize, L"%s", lpszPassword ); if ( iNewLen < 0 ) { break; } szLine += iNewLen; dwSize -= iNewLen; szFmt += 5; dwFmtSize -= 5; } else if ( !_wcsnicmp( szFmt, L"%dom%", 5 )) { iNewLen = _snwprintf( szLine, dwSize, L"%s", lpszDomain ); if ( iNewLen < 0 ) { break; } szLine += iNewLen; dwSize -= iNewLen; szFmt += 5; dwFmtSize -= 5; } else { goto copy_char; } continue; } copy_char: *szLine = *szFmt; szLine ++; szFmt ++; dwSize --; dwFmtSize --; } *szLine = 0; } /*++ * Function: * ConstructCmdLine * * Description: * Constructs the client command line. The format is taken from * the INI file, supports the following parameters: * %img% - the client's image * %srv% - destination server * %usr% - username * %psw% - password * %dom% - domain * %hrs% - horizontal resolution * %vrs% - vertical resolution * %wnd% - tclient's window handle, for accepting feedback * %reg% - registry referrence * %app% - starting app * %cwd% - (UNSUPPORTED) working directory for the app * %con% - /console if TSFLAG_RCONSOLE is defined * * Arguments: * * Return value: * none * --*/ VOID ConstructCmdLine( LPCWSTR lpszServerName, LPCWSTR lpszUserName, LPCWSTR lpszPassword, LPCWSTR lpszDomain, LPCWSTR lpszShell, IN const int xRes, IN const int yRes, IN const int ConnectionFlags, LPWSTR szCommandLine, DWORD dwCmdLineSize, PCONFIGINFO pConfig ) { DWORD_PTR dwFmtSize; LPWSTR szFmt; // // fix the parameters // if ( NULL == lpszServerName ) lpszServerName = L""; if ( NULL == lpszUserName ) lpszUserName = L""; if ( NULL == lpszPassword ) lpszPassword = L""; if ( NULL == lpszDomain ) lpszDomain = L""; if ( NULL == lpszShell ) lpszShell = L""; if ( dwCmdLineSize < 1 ) return; if ( NULL == pConfig ) return; szFmt = pConfig->strCmdLineFmt; dwFmtSize = wcslen( szFmt ); for( ; 0 != dwFmtSize && dwCmdLineSize > 1 ; ) { // // optimize the code path // if ( L'%' != *szFmt ) goto copy_char; if ( dwFmtSize >= 5 ) { INT iNewLen; if ( !_wcsnicmp( szFmt, L"%img%", 5 )) { iNewLen = _snwprintf( szCommandLine, dwCmdLineSize, L"%s", pConfig->strClientImg ); if ( iNewLen < 0 ) { break; } szCommandLine += iNewLen; dwCmdLineSize -= iNewLen; szFmt += 5; dwFmtSize -= 5; } else if ( !_wcsnicmp( szFmt, L"%srv%", 5 )) { iNewLen = _snwprintf( szCommandLine, dwCmdLineSize, L"%s", lpszServerName ); if ( iNewLen < 0 ) { break; } szCommandLine += iNewLen; dwCmdLineSize -= iNewLen; szFmt += 5; dwFmtSize -= 5; } else if ( !_wcsnicmp( szFmt, L"%usr%", 5 )) { iNewLen = _snwprintf( szCommandLine, dwCmdLineSize, L"%s", lpszUserName ); if ( iNewLen < 0 ) { break; } szCommandLine += iNewLen; dwCmdLineSize -= iNewLen; szFmt += 5; dwFmtSize -= 5; } else if ( !_wcsnicmp( szFmt, L"%psw%", 5 )) { iNewLen = _snwprintf( szCommandLine, dwCmdLineSize, L"%s", lpszPassword ); if ( iNewLen < 0 ) { break; } szCommandLine += iNewLen; dwCmdLineSize -= iNewLen; szFmt += 5; dwFmtSize -= 5; } else if ( !_wcsnicmp( szFmt, L"%dom%", 5 )) { iNewLen = _snwprintf( szCommandLine, dwCmdLineSize, L"%s", lpszDomain ); if ( iNewLen < 0 ) { break; } szCommandLine += iNewLen; dwCmdLineSize -= iNewLen; szFmt += 5; dwFmtSize -= 5; } else if ( !_wcsnicmp( szFmt, L"%hrs%", 5 )) { iNewLen = _snwprintf( szCommandLine, dwCmdLineSize, L"%d", xRes ); if ( iNewLen < 0 ) { break; } szCommandLine += iNewLen; dwCmdLineSize -= iNewLen; szFmt += 5; dwFmtSize -= 5; } else if ( !_wcsnicmp( szFmt, L"%vrs%", 5 )) { iNewLen = _snwprintf( szCommandLine, dwCmdLineSize, L"%d", yRes ); if ( iNewLen < 0 ) { break; } szCommandLine += iNewLen; dwCmdLineSize -= iNewLen; szFmt += 5; dwFmtSize -= 5; } else if ( !_wcsnicmp( szFmt, L"%con%", 5 )) { if (ConnectionFlags & TSFLAG_RCONSOLE) { iNewLen = _snwprintf( szCommandLine, dwCmdLineSize, L"-console" ); if ( iNewLen < 0 ) { break; } } else { iNewLen = 0; } szCommandLine += iNewLen; dwCmdLineSize -= iNewLen; szFmt += 5; dwFmtSize -= 5; } else if ( !_wcsnicmp( szFmt, L"%wnd%", 5 )) { iNewLen = _snwprintf( szCommandLine, dwCmdLineSize, #ifdef _WIN64 L"%I64d", #else // !_WIN64 L"%d", #endif // !_WIN64 (LONG_PTR)g_hWindow ); if ( iNewLen < 0 ) { break; } szCommandLine += iNewLen; dwCmdLineSize -= iNewLen; szFmt += 5; dwFmtSize -= 5; } else if ( !_wcsnicmp( szFmt, L"%reg%", 5 )) { iNewLen = _snwprintf( szCommandLine, dwCmdLineSize, REG_FORMAT, GetCurrentProcessId(), GetCurrentThreadId()); if ( iNewLen < 0 ) { break; } szCommandLine += iNewLen; dwCmdLineSize -= iNewLen; szFmt += 5; dwFmtSize -= 5; } else if ( !_wcsnicmp( szFmt, L"%app%", 5 )) { iNewLen = _snwprintf( szCommandLine, dwCmdLineSize, L"%s", lpszShell ); if ( iNewLen < 0 ) { break; } szCommandLine += iNewLen; dwCmdLineSize -= iNewLen; szFmt += 5; dwFmtSize -= 5; } else { goto copy_char; } continue; } copy_char: *szCommandLine = *szFmt; szCommandLine ++; szFmt ++; dwCmdLineSize --; dwFmtSize --; } *szCommandLine = 0; } /*++ * 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_FB_REPLACEPID: return (_ReplaceProcessId( wParam, lParam )); #ifdef _RCLX case WM_WSOCK: // Windows socket messages RClx_DispatchWSockEvent((SOCKET)wParam, lParam); break; #endif // _RCLX case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProcA(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) { WNDCLASSA wc; BOOL rv = FALSE; // DWORD dwLastErr; memset(&wc, 0, sizeof(wc)); wc.lpfnWndProc = _FeedbackWndProc; wc.hInstance = g_hInstance; wc.lpszClassName = _TSTNAMEOFCLAS; if (!RegisterClassA (&wc) && GetLastError() && GetLastError() != 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; UNREFERENCED_PARAMETER(lpParam); g_hWindow = CreateWindowA( _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 { #ifdef _RCLX if (!RClx_Init()) TRACE((ERROR_MESSAGE, "Can't initialize RCLX\n")); #endif // _RCLX while (GetMessageA (&msg, NULL, 0, 0) && msg.message != WM_FB_END) { DispatchMessageA (&msg); } #ifdef _RCLX RClx_Done(); #endif // _RCLX } TRACE((INFO_MESSAGE, "Window/Thread destroyed\n")); FreeLibraryAndExitThread(g_hInstance, 0); exitpt: return 1; } VOID SetAllowBackgroundInput( VOID ) { DWORD ResId; LONG sysrc; HKEY key; DWORD disposition; ResId = 1; // sysrc = RegCreateKeyExWrp(HKEY_CURRENT_USER, 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, "RegCreateKeyEx failed, sysrc = %d\n", sysrc)); goto exitpt; } // sysrc = RegSetValueExWrp(key, sysrc = RegSetValueExW(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: ; } /* * Disables prompting the user for redirected drives and ports (may be even more stuff) * */ BOOL _DisablePrompting( LPCWSTR szServerName, INT ConnectionFlags ) { BOOL rv = FALSE; LONG rc; HKEY hKey = NULL; DWORD dwType, dwSize, dwData, dwDisp; DWORD dwPromptFlags = 0; if ( ConnectionFlags & TSFLAG_DRIVES ) { dwPromptFlags |= 1; } if ( ConnectionFlags & TSFLAG_PORTS ) { dwPromptFlags |= 2; } if ( 0 == dwPromptFlags ) { rv = TRUE; goto exitpt; } // rc = RegCreateKeyExWrp( rc = RegCreateKeyExW( HKEY_CURRENT_USER, REG_BASE L"\\LocalDevices", 0, // options NULL, // class REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, // security &hKey, &dwDisp ); if ( ERROR_SUCCESS != rc ) { TRACE(( WARNING_MESSAGE, "RegOpenKeyEx failed (%d).Can't disable user prompt\n", rc )); goto exitpt; } dwSize = sizeof( dwData ); // rc = RegQueryValueExWrp( rc = RegQueryValueExW( hKey, szServerName, NULL, // reserved &dwType, (LPBYTE)&dwData, &dwSize ); if ( ERROR_SUCCESS != rc || REG_DWORD != dwType ) { dwData = 0; } dwData |= dwPromptFlags; // rc = RegSetValueExWrp( rc = RegSetValueExW( hKey, szServerName, 0, REG_DWORD, (LPBYTE)&dwData, sizeof( dwData ) ); if ( ERROR_SUCCESS != rc ) { TRACE(( WARNING_MESSAGE, "RegSetValueEx failed (%d). Can't disable user prompt\n", rc )); } rv = TRUE; exitpt: if ( NULL != hKey ) { RegCloseKey( hKey ); } return rv; } /*++ * 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 * ... - ... * KeyboardHook - keyboard hook mode * Called by: * SCConnect --*/ VOID _SetClientRegistry( LPCWSTR lpszServerName, LPCWSTR lpszShell, LPCWSTR lpszUsername, LPCWSTR lpszPassword, LPCWSTR lpszDomain, INT xRes, INT yRes, INT Bpp, INT AudioOpts, PCONNECTINFO *ppCI, INT ConnectionFlags, INT KeyboardHook) { // const CHAR *pData; // CHAR szServer[MAX_STRING_LENGTH]; // register int i; LONG sysrc; HKEY key; DWORD disposition; DWORD_PTR dataSize; DWORD ResId; WCHAR lpszRegistryEntry[4*MAX_STRING_LENGTH]; // RECT rcDesktop = {0, 0, 0, 0}; // INT desktopX, desktopY; _snwprintf(lpszRegistryEntry, sizeof(lpszRegistryEntry)/sizeof( lpszRegistryEntry[0] ), L"%s\\" REG_FORMAT, REG_BASE, GetCurrentProcessId(), GetCurrentThreadId()); lpszRegistryEntry[ sizeof(lpszRegistryEntry)/sizeof( lpszRegistryEntry[0] ) - 1 ] = 0; #if 0 // Get desktop size GetWindowRect(GetDesktopWindow(), &rcDesktop); desktopX = rcDesktop.right; desktopY = rcDesktop.bottom; // Adjust the resolution if (desktopX < xRes || desktopY < yRes) { xRes = desktopX; yRes = desktopY; } #endif dataSize = ( wcslen(lpszServerName) + 1 ) * sizeof( WCHAR ); // Before starting ducati client set registry with server name // sysrc = RegCreateKeyExWrp(HKEY_CURRENT_USER, sysrc = RegCreateKeyExW(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 = RegSetValueExWrp(key, sysrc = RegSetValueExW(key, L"MRU0", 0, // reserved REG_SZ, (LPBYTE)lpszServerName, (DWORD)dataSize); if (sysrc != ERROR_SUCCESS) { TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc)); } // Set alternative shell (if specified if (lpszShell) { // sysrc = RegSetValueExWrp(key, sysrc = RegSetValueExW(key, TEXT("Alternate Shell 50"), 0, // reserved REG_BINARY, (LPBYTE)lpszShell, (DWORD)(wcslen(lpszShell) * sizeof(*lpszShell))); if (sysrc != ERROR_SUCCESS) { TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc)); } } // set user name // if (lpszUsername) { // sysrc = RegSetValueExWrp(key, sysrc = RegSetValueExW(key, TEXT("UserName 50"), 0, // reserved REG_BINARY, (LPBYTE)lpszUsername, (DWORD)(wcslen(lpszUsername) * sizeof(*lpszUsername))); if (sysrc != ERROR_SUCCESS) { TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc)); } } // domain // if (lpszDomain) { WCHAR szBuff[MAX_STRING_LENGTH]; // // convert lpszDomain to lower case only // to force UpdateSessionPDU to be send from the server // wcsncpy( szBuff, lpszDomain, MAX_STRING_LENGTH - 1 ); _wcslwr( szBuff ); // sysrc = RegSetValueExWrp(key, sysrc = RegSetValueExW(key, TEXT("Domain 50"), 0, // reserved REG_BINARY, (LPBYTE)szBuff, (DWORD)(wcslen(lpszDomain) * sizeof(*lpszDomain))); 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 = RegSetValueExWrp(key, sysrc = RegSetValueExW(key, L"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 = RegSetValueExWrp(key, sysrc = RegSetValueExW(key, L"Auto Connect", 0, // reserved REG_DWORD, (LPBYTE)&ResId, sizeof(ResId)); if (sysrc != ERROR_SUCCESS) { TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc)); } if ( (*ppCI)->pConfigInfo->Autologon ) { WCHAR szEncPwd[127]; UINT cb; BYTE Salt[20]; // password // if ( NULL == lpszPassword ) goto skip_pwd; TSRNG_Initialize(); TSRNG_GenerateRandomBits( Salt, sizeof( Salt )); wcsncpy( szEncPwd, lpszPassword, sizeof( szEncPwd ) / sizeof( szEncPwd[0]) - 1 ); // BUGBUG: AV? szEncPwd[ sizeof( szEncPwd ) / sizeof( szEncPwd[0] ) - 1 ] = 0; cb = sizeof(szEncPwd); EncryptDecryptLocalData50( (LPBYTE)szEncPwd, cb, Salt, sizeof( Salt )); // sysrc = RegSetValueExWrp(key, sysrc = RegSetValueExW(key, L"Salt 50", 0, // reserved REG_BINARY, (LPBYTE)Salt, sizeof( Salt )); if (sysrc != ERROR_SUCCESS) { TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc)); } // sysrc = RegSetValueExWrp(key, sysrc = RegSetValueExW(key, L"Password 50", 0, // reserved REG_BINARY, (LPBYTE)szEncPwd, cb); if (sysrc != ERROR_SUCCESS) { TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc)); } skip_pwd: ResId = 1; // sysrc = RegSetValueExWrp(key, sysrc = RegSetValueExW(key, L"AutoLogon 50", 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 = RegSetValueExWrp(key, sysrc = RegSetValueExW(key, L"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 = RegSetValueExWrp(key, sysrc = RegSetValueExW(key, L"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 = RegSetValueExWrp(key, sysrc = RegSetValueExW(key, L"Screen Mode ID", 0, // reserved REG_DWORD, (LPBYTE)&ResId, sizeof(ResId)); if (sysrc != ERROR_SUCCESS) { TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc)); } } if (ConnectionFlags & TSFLAG_DRIVES) { ResId = 1; // sysrc = RegSetValueExWrp(key, sysrc = RegSetValueExW(key, L"RedirectDrives", 0, // reserved REG_DWORD, (LPBYTE)&ResId, sizeof(ResId)); if (sysrc != ERROR_SUCCESS) { TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc)); } } if (ConnectionFlags & TSFLAG_PORTS) { ResId = 1; // sysrc = RegSetValueExWrp(key, sysrc = RegSetValueExW(key, L"RedirectComPorts", 0, // reserved REG_DWORD, (LPBYTE)&ResId, sizeof(ResId)); if (sysrc != ERROR_SUCCESS) { TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc)); } } _DisablePrompting( lpszServerName, ConnectionFlags ); if ( 0 != Bpp ) { DWORD dw = Bpp; // sysrc = RegSetValueExWrp( sysrc = RegSetValueExW( key, L"Session Bpp", 0, REG_DWORD, (LPBYTE)&dw, sizeof( dw )); if (sysrc != ERROR_SUCCESS) { TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc)); } } if ( 0 != AudioOpts ) { DWORD dw = AudioOpts; // sysrc = RegSetValueExWrp( sysrc = RegSetValueExW( key, L"AudioMode", 0, REG_DWORD, (LPBYTE)&dw, sizeof( dw )); if (sysrc != ERROR_SUCCESS) { TRACE((WARNING_MESSAGE, "RegSetValue failed, status = %d\n", sysrc)); } } // // Set the keyboard-hook mode. // // sysrc = RegSetValueExWrp( sysrc = RegSetValueExW( key, L"KeyboardHook", 0, REG_DWORD, (LPBYTE)&KeyboardHook, sizeof(KeyboardHook)); 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) { WCHAR lpszRegistryEntry[4*MAX_STRING_LENGTH]; LONG sysrc; _snwprintf(lpszRegistryEntry, sizeof(lpszRegistryEntry)/sizeof(lpszRegistryEntry[0]), L"%s\\" REG_FORMAT, REG_BASE, GetCurrentProcessId(), pCI->OwnerThreadId); lpszRegistryEntry[ sizeof(lpszRegistryEntry)/sizeof(lpszRegistryEntry[0]) -1 ] = 0; // sysrc = RegDeleteKeyWrp(HKEY_CURRENT_USER, lpszRegistryEntry); sysrc = RegDeleteKeyW(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; UINT dwThreadId; // UINT 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 PostMessageA(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 { SendMessageA(pIter->hClient, WM_CLOSE, 0, 0); } while((wres = WaitForSingleObject(pIter->hProcess, pCI->pConfigInfo->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(BOOL bCond, LPCSTR filename, INT line, LPCSTR expression, BOOL bBreak) { if (!bCond) { TRACE((ERROR_MESSAGE, "ASSERT (%s) %s line: %d\n", expression, filename, line)); if (bBreak) { DebugBreak(); } } } /*++ * Function: * LoadSmClientFile * Description: * Loads the appropriate SMCLIENT.INI * Called by: * _FillConfigInfo --*/ VOID LoadSmClientFile(WCHAR *szIniFileName, DWORD dwIniFileNameLen, LPSTR szLang) { WCHAR wszLang[4]; // Construct INI path *szIniFileName = 0; if(!_wgetcwd ( szIniFileName, (int)(dwIniFileNameLen - wcslen(SMCLIENT_INI) - 8)) ) { TRACE((ERROR_MESSAGE, "Current directory length too long.\n")); } if ( 0 == *szIniFileName ) { CHAR szaIniFileName[_MAX_PATH]; TRACE((WARNING_MESSAGE, "Reading ASCII working dir\n")); DWORD_PTR dwINILen = wcslen(SMCLIENT_INI); if (!_getcwd ( szaIniFileName, (int)(sizeof(szaIniFileName) - dwINILen - 8)) ) { TRACE((ERROR_MESSAGE, "Current directory length too long.\n")); } else { _snwprintf(szIniFileName, dwIniFileNameLen, L"%S", szaIniFileName ); szIniFileName[ dwIniFileNameLen - 1 ] = 0; } if ( wcslen( szIniFileName ) > dwIniFileNameLen - wcslen(SMCLIENT_INI) - strlen(szLang) - 2 ) { TRACE(( ERROR_MESSAGE, "Current directory length too long.\n")); szIniFileName[0] = 0; return; } } // add '\' at the end if there isn't one if (szIniFileName[wcslen(szIniFileName)-1]!=L'\\') { wcscat(szIniFileName, L"\\"); } printf("Loading the smclient file \n"); wcscat(szIniFileName, SMCLIENT_INI); if( strcmp( szLang, "0409") ) { wcscat(szIniFileName, L"."); MultiByteToWideChar( CP_ACP, 0, szLang, -1, wszLang, sizeof(wszLang)/sizeof(wszLang[0]) ); wcscat(szIniFileName, wszLang); } ; //return VOID } /*++ * Function: * _FillConfigInfo * * Description: * Reads smclient.ini, section [tclient], variable "timeout" * Also read some other values * Arguments: * PCONFIGINFO * Return value: * none * --*/ VOID _FillConfigInfo(PCONFIGINFO pConfigInfo) // LPSTR szLang) { UINT nNew; WCHAR szIniFileName[_MAX_PATH]; // WCHAR szBuff[ 4 * MAX_STRING_LENGTH ]; WCHAR szBuffDef[MAX_STRING_LENGTH]; BOOL bFlag; DWORD dwIniFileNameLen = _MAX_PATH; /* Initializing variables here */ pConfigInfo->CONNECT_TIMEOUT = 35000; pConfigInfo->ConnectionFlags = TSFLAG_COMPRESSION|TSFLAG_BITMAPCACHE; pConfigInfo->Autologon = 0; pConfigInfo->UseRegistry = 1; pConfigInfo->LoginWait = 1; pConfigInfo->bTranslateStrings = 0; pConfigInfo->bUnicode = 0; pConfigInfo->KeyboardHook = TCLIENT_KEYBOARD_HOOK_FULLSCREEN; // // Clear the configuration info and the INI-file name. // ZeroMemory(pConfigInfo, sizeof(*pConfigInfo)); ZeroMemory(szIniFileName, sizeof(szIniFileName)); // LoadSmClientFile(szIniFileName, _MAX_PATH, szLang); if(!_wgetcwd ( szIniFileName, (int)(dwIniFileNameLen - wcslen(SMCLIENT_INI) - 1)) ) { TRACE((ERROR_MESSAGE, "Current directory length too long.\n")); } if ( 0 == *szIniFileName ) { CHAR szaIniFileName[_MAX_PATH]; TRACE((WARNING_MESSAGE, "Reading ASCII working dir\n")); DWORD_PTR dwINILen = wcslen(SMCLIENT_INI); if (!_getcwd ( szaIniFileName, (int)(sizeof(szaIniFileName) - dwINILen - 1)) ) { TRACE((ERROR_MESSAGE, "Current directory length too long.\n")); } else { _snwprintf(szIniFileName, dwIniFileNameLen, L"%S", szaIniFileName ); szIniFileName[ dwIniFileNameLen - 1 ] = 0; } //if ( wcslen( szIniFileName ) > dwIniFileNameLen - wcslen(SMCLIENT_INI) - strlen(szLang) - 2 ) if ( wcslen( szIniFileName ) > dwIniFileNameLen - wcslen(SMCLIENT_INI) - 2 ) { TRACE(( ERROR_MESSAGE, "Current directory length too long.\n")); szIniFileName[0] = 0; return; } } // add '\' at the end if there isn't one if (szIniFileName[wcslen(szIniFileName)-1]!=L'\\') { wcscat(szIniFileName, L"\\"); } wcscat(szIniFileName, SMCLIENT_INI); // nNew = _WrpGetPrivateProfileIntW( nNew = GetPrivateProfileIntW( TCLIENT_INI_SECTION, L"timeout", 600, szIniFileName); if (nNew) { pConfigInfo->WAIT4STR_TIMEOUT = nNew * 1000; TRACE((INFO_MESSAGE, "New timeout: %d seconds\n", nNew)); } // nNew = _WrpGetPrivateProfileIntW( nNew = GetPrivateProfileIntW( TCLIENT_INI_SECTION, L"contimeout", 35, szIniFileName); if (nNew) { pConfigInfo->CONNECT_TIMEOUT = nNew * 1000; TRACE((INFO_MESSAGE, "New timeout: %d seconds\n", nNew)); } pConfigInfo->Autologon = // _WrpGetPrivateProfileIntW( GetPrivateProfileIntW( TCLIENT_INI_SECTION, L"Autologon", 0, szIniFileName); pConfigInfo->UseRegistry = // _WrpGetPrivateProfileIntW( GetPrivateProfileIntW( TCLIENT_INI_SECTION, L"UseRegistry", 1, szIniFileName); pConfigInfo->LoginWait = // _WrpGetPrivateProfileIntW( GetPrivateProfileIntW( TCLIENT_INI_SECTION, L"LoginWait", 1, szIniFileName); pConfigInfo->bTranslateStrings = // _WrpGetPrivateProfileIntW( GetPrivateProfileIntW( TCLIENT_INI_SECTION, L"TranslateStrings", 0, szIniFileName); pConfigInfo->bUnicode = // _WrpGetPrivateProfileIntW( GetPrivateProfileIntW( TCLIENT_INI_SECTION, L"Unicode", 0, szIniFileName); pConfigInfo->KeyboardHook = // _WrpGetPrivateProfileIntW( GetPrivateProfileIntW( TCLIENT_INI_SECTION, L"KeyboardHook", 0, szIniFileName); pConfigInfo->ConnectionFlags = 0; bFlag = // _WrpGetPrivateProfileIntW( GetPrivateProfileIntW( TCLIENT_INI_SECTION, L"LowSpeed", 0, szIniFileName); if (bFlag) pConfigInfo->ConnectionFlags |=TSFLAG_COMPRESSION; bFlag = // _WrpGetPrivateProfileIntW( GetPrivateProfileIntW( TCLIENT_INI_SECTION, L"PersistentCache", 0, szIniFileName); if (bFlag) pConfigInfo->ConnectionFlags |=TSFLAG_BITMAPCACHE; bFlag = // _WrpGetPrivateProfileIntW( GetPrivateProfileIntW( TCLIENT_INI_SECTION, L"FullScreen", 0, szIniFileName); if (bFlag) pConfigInfo->ConnectionFlags |=TSFLAG_FULLSCREEN; // read the strings // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"StartRun", RUN_MENU, pConfigInfo->strStartRun, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"StartLogoff", START_LOGOFF, pConfigInfo->strStartLogoff, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"StartRunAct", RUN_ACT, pConfigInfo->strStartRun_Act, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"RunBox", RUN_BOX, pConfigInfo->strRunBox, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"WinLogon", WINLOGON_USERNAME, pConfigInfo->strWinlogon, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"WinLogonAct", WINLOGON_ACT, pConfigInfo->strWinlogon_Act, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"PriorWinLogon", PRIOR_WINLOGON, pConfigInfo->strPriorWinlogon, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"PriorWinLogonAct", PRIOR_WINLOGON_ACT, pConfigInfo->strPriorWinlogon_Act, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"NoSmartcard", NO_SMARTCARD_UI, pConfigInfo->strNoSmartcard, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"Smartcard", SMARTCARD_UI, pConfigInfo->strSmartcard, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"SmartcardAct", SMARTCARD_UI_ACT, pConfigInfo->strSmartcard_Act, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"LoginString", L"", pConfigInfo->strLogonFmt, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"NTSecurity", WINDOWS_NT_SECURITY, pConfigInfo->strNTSecurity, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"NTSecurityAct", WINDOWS_NT_SECURITY_ACT, pConfigInfo->strNTSecurity_Act, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"SureLogoff", ARE_YOU_SURE, pConfigInfo->strSureLogoff, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"SureLogoffAct", SURE_LOGOFF_ACT, pConfigInfo->strSureLogoffAct, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"LogonErrorMessage", LOGON_ERROR_MESSAGE, pConfigInfo->strLogonErrorMessage, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"LogonDisabled", LOGON_DISABLED_MESSAGE, pConfigInfo->strLogonDisabled, MAX_STRING_LENGTH, szIniFileName); _snwprintf(szBuffDef, sizeof(szBuffDef) / sizeof( WCHAR ) , L"%S", CLIENT_CAPTION); szBuffDef[MAX_STRING_LENGTH - 1] = 0; // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"UIClientCaption", szBuffDef, pConfigInfo->strClientCaption, MAX_STRING_LENGTH, szIniFileName); _snwprintf(szBuffDef, sizeof(szBuffDef) / sizeof( WCHAR ), L"%S", DISCONNECT_DIALOG_BOX); szBuffDef[MAX_STRING_LENGTH - 1] = 0; // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"UIDisconnectDialogBox", szBuffDef, pConfigInfo->strDisconnectDialogBox, MAX_STRING_LENGTH, szIniFileName); _snwprintf(szBuffDef, sizeof(szBuffDef) / sizeof( WCHAR ), L"%S", YES_NO_SHUTDOWN); szBuffDef[MAX_STRING_LENGTH - 1] = 0; // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"UIYesNoDisconnect", szBuffDef, pConfigInfo->strYesNoShutdown, MAX_STRING_LENGTH, szIniFileName); _snwprintf(szBuffDef, sizeof(szBuffDef) / sizeof( WCHAR ), L"%S", CLIENT_EXE); szBuffDef[MAX_STRING_LENGTH - 1] = 0; // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"ClientImage", szBuffDef, pConfigInfo->strClientImg, MAX_STRING_LENGTH, szIniFileName); szBuffDef[0] = 0; // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"ClientDebugger", szBuffDef, pConfigInfo->strDebugger, MAX_STRING_LENGTH, szIniFileName); _snwprintf(szBuffDef, sizeof(szBuffDef) / sizeof( WCHAR ), L"%s", NAME_MAINCLASS); szBuffDef[MAX_STRING_LENGTH - 1] = 0; // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"UIMainWindowClass", szBuffDef, pConfigInfo->strMainWindowClass, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"ClientCmdLine", L"", pConfigInfo->strCmdLineFmt, 4 * MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"ConsoleExtension", L"", pConfigInfo->strConsoleExtension, MAX_STRING_LENGTH, szIniFileName); // _WrpGetPrivateProfileStringW( GetPrivateProfileStringW( TCLIENT_INI_SECTION, L"sessionlist", L"", pConfigInfo->strSessionListDlg, MAX_STRING_LENGTH, szIniFileName); } /*++ * Function: * DllCanUnloadNow * * Description: * Used to determine whether the DLL can be unloaded by OLE * Arguments: * None. * Return value: * ... * --*/ STDAPI DllCanUnloadNow( VOID ) { return _Module.GetLockCount() == 0 ? S_OK : S_FALSE; } ///////////////////////////////////////////////////////////////////////////// /*++ * Function: * DllGetClassObject * * Description: * Returns a class factory to create an object of the requested type. * Arguments: * rclsid - ... * riid - ... * ppv - ... * Return value: * ... * --*/ STDAPI DllGetClassObject( IN REFCLSID rclsid, IN REFIID riid, OUT LPVOID* ppv ) { return _Module.GetClassObject(rclsid, riid, ppv); } /*++ * Function: * DllRegisterServer * * Description: * DllRegisterServer - Adds entries to the system registry * Arguments: * None. * Return value: * ... * --*/ STDAPI DllRegisterServer( VOID ) { // registers object, typelib and all interfaces in typelib return _Module.RegisterServer(TRUE); } /*++ * Function: * DllUnregisterServer * * Description: * DllUnregisterServer - Removes entries from the system registry * Arguments: * None. * Return value: * ... * --*/ STDAPI DllUnregisterServer( VOID ) { _Module.UnregisterServer(); return S_OK; } } // extern "C" #ifdef _M_IA64 //$WIN64: Don't know why _WndProcThunkProc isn't defined extern "C" LRESULT CALLBACK _WndProcThunkProc(HWND, UINT, WPARAM, LPARAM) { return 0; } #endif