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

487 lines
12 KiB
C

/*************** ************************************************************/
// tsappcmp.c
//
// Copyright (C) 1997-1999 Microsoft Corp.
/****************************************************************************/
#include "precomp.h"
#pragma hdrstop
extern void InitRegisterSupport();
PWINSTATIONQUERYINFORMATIONW pWinStationQueryInformationW;
extern DWORD gpTermsrvTlsIndex;
BOOL GetDefaultUserProfileName(LPWSTR lpProfileDir, LPDWORD lpcchSize);
extern WCHAR gpwszDefaultUserName[];
extern void FreeLDRTable();
DWORD g_dwFlags=0;
/*
* Read flags, if flags don't exit, then assume default behavior.
* The default behavior is the same as dwFlags = 0x0
* The default behavior will result is the loadlib func calls to be patched by our
* redirected func TLoadLibraryExW().
*
*/
void ReadImportTablePatchFLagsAndAppCompatMode( DWORD *pdwFlags, BOOLEAN *pInAppCompatMode )
{
NTSTATUS NtStatus;
UNICODE_STRING KeyName;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE KeyHandle;
UCHAR Buffer[100];
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) Buffer;
ULONG KeyValueLength = 100;
ULONG ResultLength;
*pdwFlags=0;
*pInAppCompatMode=FALSE;
RtlInitUnicodeString(
&KeyName,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Terminal Server"
);
InitializeObjectAttributes(
&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
0,
NULL
);
NtStatus = NtOpenKey(
&KeyHandle,
KEY_READ,
&ObjectAttributes
);
if (!NT_SUCCESS(NtStatus)) {
return; // so nothing found, just return since we do have a default behavior.
}
RtlInitUnicodeString(
&KeyName,
REG_TERMSRV_APPCOMPAT
);
NtStatus = NtQueryValueKey(
KeyHandle,
&KeyName,
KeyValuePartialInformation,
KeyValueInformation,
KeyValueLength,
&ResultLength
);
if (NT_SUCCESS(NtStatus))
{
//
// Check that the data is the correct size and type - a DWORD.
//
if ((KeyValueInformation->DataLength >= sizeof(DWORD)) &&
(KeyValueInformation->Type == REG_DWORD))
{
*pInAppCompatMode = * (PBOOLEAN) KeyValueInformation->Data;
}
}
RtlInitUnicodeString(
&KeyName,
TERMSRV_COMPAT_IAT_FLAGS
);
NtStatus = NtQueryValueKey(
KeyHandle,
&KeyName,
KeyValuePartialInformation,
KeyValueInformation,
KeyValueLength,
&ResultLength
);
if (NT_SUCCESS(NtStatus))
{
//
// Check that the data is the correct size and type - a DWORD.
//
if ((KeyValueInformation->DataLength >= sizeof(DWORD)) &&
(KeyValueInformation->Type == REG_DWORD))
{
*pdwFlags = * (PDWORD) KeyValueInformation->Data;
}
}
NtClose(KeyHandle);
}
BOOL WINAPI LibMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
static ULONG attachCount=0;
static BOOLEAN inAppCompatMode=FALSE;
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
{
PWCHAR pwch, pwchext;
WCHAR pwcAppName[MAX_PATH+1];
PRTL_USER_PROCESS_PARAMETERS pUserParam;
DWORD dwSize;
attachCount++;
ReadImportTablePatchFLagsAndAppCompatMode( &g_dwFlags , &inAppCompatMode ); // this will initialize our global flag for IAT and debug
if ( g_dwFlags & DEBUG_IAT )
{
DbgPrint("tsappcmp: LibMain: DLL_PROCESS_ATTACH called, attach count = %d \n", attachCount );
}
if ( inAppCompatMode )
{
// Get the path of the executable name
pUserParam = NtCurrentPeb()->ProcessParameters;
// Get the executable name, if there's no \ just use the name as it is
pwch = wcsrchr(pUserParam->ImagePathName.Buffer, L'\\');
if (pwch) {
pwch++;
} else {
pwch = pUserParam->ImagePathName.Buffer;
}
wcscpy(pwcAppName, pwch);
pwch = pwcAppName;
#if DBGX
DbgPrint("\nApp-name : %ws\n", pwch );
#endif
// Check if it's a DOS or Win16 app by checking if the app is ntvdm.exe
// Only disable ThreadLibrary calls if not ntvdm.
if (_wcsicmp(pwch, L"ntvdm.exe")) {
DisableThreadLibraryCalls (hInstance);
} else {
gpTermsrvTlsIndex = TlsAlloc();
ASSERT(gpTermsrvTlsIndex != 0xFFFFFFFF);
}
// Init support for the register command
InitRegisterSupport();
dwSize = MAX_PATH;
if (!GetDefaultUserProfileName(gpwszDefaultUserName, &dwSize)) {
gpwszDefaultUserName[0] = L'\0';
}
}
break;
}
case DLL_THREAD_ATTACH:
{
if (inAppCompatMode )
{
TlsSetValue(gpTermsrvTlsIndex,NULL);
}
}
case DLL_PROCESS_DETACH:
{
attachCount--;
if ( g_dwFlags & DEBUG_IAT )
{
DbgPrint("tsappcmp: LibMain: DLL_PROCESS_DETACH called, attach count = %d \n", attachCount );
}
if (inAppCompatMode )
{
if (attachCount==0 )
{
FreeLDRTable();
}
}
}
break;
}
return TRUE;
}
PWCHAR TermsrvFormatObjectName(LPCWSTR OldName)
{
PWCHAR pstrNewObjName = NULL;
#if 0
SIZE_T Size;
Size = ( wcslen(OldName) * sizeof(WCHAR)) + sizeof(L"Local\\") + sizeof(WCHAR);
pstrNewObjName = RtlAllocateHeap(RtlProcessHeap(),
LMEM_FIXED | LMEM_ZEROINIT,
Size);
if (pstrNewObjName) {
swprintf(pstrNewObjName,L"Local\\%ws",OldName);
}
#endif
return pstrNewObjName;
}
DWORD TermsrvGetComputerName( LPWSTR lpBuffer, LPDWORD nSize )
{
ULONG ulCompatFlags=0, ulAppType = 0;
WINSTATIONINFORMATIONW WSInfo;
ULONG ValueLength;
HMODULE hwinsta = NULL;
GetCtxAppCompatFlags(&ulCompatFlags, &ulAppType);
// Return the username instead of the computername?
if ((ulCompatFlags & TERMSRV_COMPAT_USERNAME) &&
(ulCompatFlags & ulAppType)) {
if ( !pWinStationQueryInformationW ) {
/*
* Get handle to winsta.dll
*/
if ( (hwinsta = LoadLibraryA( "WINSTA" )) != NULL ) {
pWinStationQueryInformationW = (PWINSTATIONQUERYINFORMATIONW)
GetProcAddress( hwinsta, "WinStationQueryInformationW" );
}
}
// Fetch the WinStation's basic information
if ( pWinStationQueryInformationW ) {
if ( (*pWinStationQueryInformationW)(SERVERNAME_CURRENT,
LOGONID_CURRENT,
WinStationInformation,
&WSInfo,
sizeof(WSInfo),
&ValueLength ) ) {
// Check if username will fit in buffer
if (wcslen(WSInfo.UserName) >= *nSize) {
return ERROR_BUFFER_OVERFLOW;
} else {
wcscpy(lpBuffer, WSInfo.UserName);
return ERROR_SUCCESS;
}
}
}
}
return ERROR_RETRY;
}
void TermsrvAdjustPhyMemLimits (
IN OUT LPDWORD TotalPhys,
IN OUT LPDWORD AvailPhys,
IN DWORD SysPageSize
)
{
ULONG ulAppType = 0;
DWORD PhysicalMemory;
if ( GetCtxPhysMemoryLimits(&ulAppType, &PhysicalMemory) ) {
if (*TotalPhys > PhysicalMemory ) {
*TotalPhys = PhysicalMemory;
}
}
if ( *AvailPhys > *TotalPhys ) {
// Reset the Available Physical Memory to be smaller than the
// Total Physical Memory. It is made smaller to avoid
// possible divide by zero errors when Available and Total are
// equal
*AvailPhys = *TotalPhys - SysPageSize;
}
return;
}
UINT
APIENTRY
TermsrvGetWindowsDirectoryA(
LPSTR lpBuffer,
UINT uSize
)
{
ANSI_STRING AnsiString;
NTSTATUS Status;
ULONG cbAnsiString;
UNICODE_STRING Path;
//
// If in install mode return the system windows dir
//
if (TermsrvAppInstallMode()) {
return 0;
}
if (!TermsrvPerUserWinDirMapping()) {
return 0;
}
// if buffer looks real, then init it to zero
if ( lpBuffer ) {
*lpBuffer = '\0'; // in case we have an error, the shell folks want this to be null
// BUG 453487
}
Path.Length = 0;
Path.MaximumLength = (USHORT)(uSize * sizeof( WCHAR ));
if ( Path.Buffer = LocalAlloc( LPTR, Path.MaximumLength ) ) {
Status = GetPerUserWindowsDirectory( &Path );
if ( NT_SUCCESS(Status) ) {
AnsiString.MaximumLength = (USHORT)(uSize);
AnsiString.Buffer = lpBuffer;
Status = RtlUnicodeStringToAnsiString(
&AnsiString,
&Path,
FALSE
);
} else if ( (Status == STATUS_BUFFER_TOO_SMALL) || (Status == STATUS_BUFFER_OVERFLOW ) ) {
DbgPrint( "KERNEL32: GetWindowsDirectoryA: User buffer too small (%u) need(%u)\n",
uSize, Path.Length >> 1 );
return( Path.Length >> 1 );
}
LocalFree( Path.Buffer );
} else {
Status = STATUS_NO_MEMORY;
DbgPrint( "KERNEL32: GetWindowsDirectoryA: No memory\n" );
}
if ( Status == STATUS_BUFFER_TOO_SMALL ) {
DbgPrint( "KERNEL32: GetWindowsDirectoryA: User buffer too small (%u) need(%u)\n",
uSize, Path.Length >> 1 );
return( Path.Length >> 1 );
} else if ( !NT_SUCCESS(Status) ) {
return 0;
}
return AnsiString.Length;
}
UINT
APIENTRY
TermsrvGetWindowsDirectoryW(
LPWSTR lpBuffer,
UINT uSize
)
{
UNICODE_STRING Path;
NTSTATUS Status;
//
// If in install mode return the system windows dir
//
if (TermsrvAppInstallMode()) {
return 0;
}
if (!TermsrvPerUserWinDirMapping()) {
return 0;
}
// if buffer looks real, then init it to zero
if ( lpBuffer ) {
*lpBuffer = '\0'; // in case we have an error, the shell folks want this to be null
// BUG 453487
}
/*
* If it fails, return 0
* If buffer too small, return len (not includding NULL)
* If buffer ok, return len (not inc. NULL) and fill buffer
* (GetPerUserWindowsDirectory will do all of this for us!)
*/
Path.Length = 0;
Path.MaximumLength = (USHORT)(uSize * sizeof( WCHAR ));
Path.Buffer = lpBuffer;
Status = GetPerUserWindowsDirectory( &Path );
if ( Status == STATUS_SUCCESS ) {
/*
* Add a NULL to the end (if it fits!)
*/
if ( Path.Length + sizeof( WCHAR ) <= Path.MaximumLength ) {
lpBuffer[(Path.Length>>1)] = UNICODE_NULL;
}
}
return( Path.Length / sizeof(WCHAR) );
}