Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

834 lines
22 KiB

/****************************** Module Header ******************************\
* Module Name: winutil.c
*
* Copyright (c) 1991, Microsoft Corporation
*
* Implements windows specific utility functions
*
* History:
* 12-09-91 Davidc Created.
\***************************************************************************/
#include "precomp.h"
#if DBG
char * DesktopNames[] = {"Winlogon", "ScreenSaver", "Application", "[Previous]"};
#define DbgGetDesktopName(x) (x < (sizeof(DesktopNames) / sizeof(char *)) ? DesktopNames[x] : "Unknown!")
#endif
HDESK
GetActiveDesktop(
PWinstaDescription pWindowStation,
BOOL * pCloseWhenDone,
BOOL * pLocked)
{
HDESK hDesk;
ActiveDesktops Desktop;
Desktop = pWindowStation->ActiveDesktop;
if (Desktop == -1)
{
Desktop = pWindowStation->PreviousDesktop;
}
switch ( Desktop )
{
case Desktop_Application:
hDesk = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
*pCloseWhenDone = TRUE;
*pLocked = FALSE;
break;
case Desktop_Winlogon:
hDesk = pWindowStation->hdeskWinlogon;
*pCloseWhenDone = FALSE;
*pLocked = TRUE;
break;
case Desktop_ScreenSaver:
hDesk = pWindowStation->hdeskScreenSaver;
*pCloseWhenDone = FALSE;
*pLocked = FALSE;
break;
default:
DebugLog((DEB_TRACE, "Unknown desktop: %d\n", Desktop));
*pCloseWhenDone = FALSE;
hDesk = NULL;
*pLocked = FALSE;
break;
}
return(hDesk);
}
BOOL
ToggleDesktopLock(
PWinstaDescription pWindowStation)
{
BOOL bRet;
if (pWindowStation->Locked)
{
bRet = UnlockWindowStation( pWindowStation->hwinsta );
pWindowStation->Locked = FALSE;
}
else
{
bRet = LockWindowStation( pWindowStation->hwinsta );
pWindowStation->Locked = TRUE;
}
return( bRet );
}
BOOL
SetReturnDesktop(
PWinstaDescription pWindowStation,
PWLX_DESKTOP pDesktop)
{
WCHAR DesktopName[TYPICAL_STRING_LENGTH];
DWORD Needed;
PWSTR pszDesktop;
BOOL FreeDesktopString = FALSE;
HDESK hDesk;
if ( pWindowStation->ActiveDesktop == Desktop_Application )
{
return( FALSE );
}
if ( (pDesktop->Flags & WLX_DESKTOP_NAME) == 0 )
{
if (!GetUserObjectInformation( pDesktop->hDesktop,
UOI_NAME,
DesktopName,
TYPICAL_STRING_LENGTH,
&Needed ) )
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER )
{
return( FALSE );
}
pszDesktop = LocalAlloc( LMEM_FIXED, Needed );
if ( !pszDesktop )
{
return( FALSE );
}
GetUserObjectInformation( pDesktop->hDesktop,
UOI_NAME,
pszDesktop,
Needed,
&Needed );
FreeDesktopString = TRUE;
}
else
{
pszDesktop = DesktopName;
FreeDesktopString = FALSE;
}
}
else
{
pszDesktop = pDesktop->pszDesktopName;
FreeDesktopString = FALSE;
}
hDesk = OpenDesktop( pszDesktop, 0, FALSE, MAXIMUM_ALLOWED );
if (!hDesk)
{
if (FreeDesktopString)
{
LocalFree( pszDesktop );
}
return( FALSE );
}
CloseDesktop( pWindowStation->hdeskPrevious );
pWindowStation->hdeskPrevious = hDesk;
if (FreeDesktopString)
{
LocalFree( pszDesktop );
}
return( TRUE );
}
BOOL
SetActiveDesktop(
PWinstaDescription pWindowStation,
ActiveDesktops Desktop)
{
HDESK hDesk;
HDESK hPrevious;
DWORD LengthNeeded;
if (Desktop == pWindowStation->ActiveDesktop)
{
return(TRUE);
}
if (pWindowStation->ActiveDesktop == Desktop_Application)
{
LockWindowStation(pWindowStation->hwinsta);
pWindowStation->hdeskPrevious = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
if (!GetUserObjectInformation( pWindowStation->hdeskPrevious,
UOI_NAME,
pWindowStation->pszDesktop,
pWindowStation->DesktopLength,
&LengthNeeded) )
{
if (pWindowStation->DesktopLength != TYPICAL_STRING_LENGTH)
{
LocalFree( pWindowStation->pszDesktop );
}
pWindowStation->pszDesktop = LocalAlloc( LMEM_FIXED, LengthNeeded );
if (pWindowStation->pszDesktop)
{
pWindowStation->DesktopLength = LengthNeeded;
if (!GetUserObjectInformation( pWindowStation->hdeskPrevious,
UOI_NAME,
pWindowStation->pszDesktop,
pWindowStation->DesktopLength,
&LengthNeeded))
{
pWindowStation->pszDesktop[0] = 0;
}
}
else
{
pWindowStation->DesktopLength = 0;
}
}
DebugLog((DEB_TRACE, "Source desktop was %ws\n", pWindowStation->pszDesktop));
}
switch (Desktop)
{
case Desktop_Winlogon:
hDesk = pWindowStation->hdeskWinlogon;
break;
case Desktop_ScreenSaver:
hDesk = pWindowStation->hdeskScreenSaver;
break;
case Desktop_Application:
if (pWindowStation->hdeskPrevious)
{
hDesk = pWindowStation->hdeskPrevious;
}
else
{
hDesk = pWindowStation->hdeskApplication;
}
break;
default:
DebugLog((DEB_ERROR, "Error: Invalid desktop specified %d\n", Desktop));
return(FALSE);
}
if (SwitchDesktop(hDesk))
{
DebugLog((DEB_TRACE, "Switching desktop from %s to %s\n",
DbgGetDesktopName(pWindowStation->ActiveDesktop),
DbgGetDesktopName(Desktop) ));
pWindowStation->PreviousDesktop = pWindowStation->ActiveDesktop;
pWindowStation->ActiveDesktop = Desktop;
//
// If we're switching back to the user's desktop, then unlock the
// window station, so that the user can switch desktops again. Also,
// close our handle to the desktop. Note! Unlock before close, so
// that if this is the last handle to the desktop, cleanup can occur
// correctly.
//
if (pWindowStation->ActiveDesktop == Desktop_Application)
{
UnlockWindowStation(pWindowStation->hwinsta);
if (pWindowStation->hdeskPrevious)
{
DebugLog((DEB_TRACE, "Closing handle %x to users desktop\n", pWindowStation->hdeskPrevious));
CloseDesktop(pWindowStation->hdeskPrevious);
pWindowStation->hdeskPrevious = NULL;
}
}
return(TRUE);
}
DebugLog((DEB_WARN, "Could not switch desktop!\n"));
return(FALSE);
}
/***************************************************************************\
* FUNCTION: AllocAndGetPrivateProfileString
*
* PURPOSE: Allocates memory for and returns pointer to a copy of the
* specified profile string
* The returned string should be freed using Free()
*
* RETURNS: Pointer to copy of profile string or NULL on failure.
*
* HISTORY:
*
* 12-Nov-92 Davidc Created.
*
\***************************************************************************/
LPTSTR
AllocAndGetPrivateProfileString(
LPCTSTR lpAppName,
LPCTSTR lpKeyName,
LPCTSTR lpDefault,
LPCTSTR lpFileName
)
{
LPTSTR String;
LONG LengthAllocated;
LONG LengthCopied;
//
// Pick a random buffer length, if it's not big enough reallocate
// it and try again until it is.
//
LengthAllocated = TYPICAL_STRING_LENGTH;
String = Alloc(LengthAllocated * sizeof(TCHAR));
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndGetPrivateProfileString : Failed to allocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
return(NULL);
}
while (TRUE) {
LengthCopied = GetPrivateProfileString( lpAppName,
lpKeyName,
lpDefault,
String,
LengthAllocated,
lpFileName
);
//
// If the returned value is our passed size - 1 (weird way for error)
// then our buffer is too small. Make it bigger and start over again.
//
if (LengthCopied == (LengthAllocated - 1)) {
DebugLog((DEB_TRACE, "AllocAndGetPrivateProfileString: Failed with buffer length = %d, reallocating and retrying", LengthAllocated));
LengthAllocated *= 2;
String = ReAlloc(String, LengthAllocated * sizeof(TCHAR));
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndGetPrivateProfileString : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
break;
}
//
// Go back and try to read it again
//
} else {
//
// Success!
//
break;
}
}
return(String);
}
/***************************************************************************\
* FUNCTION: WritePrivateProfileInt
*
* PURPOSE: Writes out an integer to a profile file
*
* RETURNS: TRUE on success, FALSE on failure
*
* HISTORY:
*
* 12-Nov-92 Davidc Created.
*
\***************************************************************************/
BOOL
WritePrivateProfileInt(
LPCTSTR lpAppName,
LPCTSTR lpKeyName,
UINT Value,
LPCTSTR lpFileName
)
{
NTSTATUS Status;
TCHAR String[30];
UNICODE_STRING UniString;
UniString.MaximumLength = 30;
UniString.Buffer = String;
Status = RtlIntegerToUnicodeString(Value,10,&UniString);
if (!NT_SUCCESS(Status)) {
return(FALSE);
}
return (WritePrivateProfileString(lpAppName, lpKeyName, UniString.Buffer, lpFileName));
}
/***************************************************************************\
* FUNCTION: AllocAndExpandEnvironmentStrings
*
* PURPOSE: Allocates memory for and returns pointer to buffer containing
* the passed string expanded to include environment strings
* The returned buffer should be freed using Free()
*
* RETURNS: Pointer to expanded string or NULL on failure.
*
* HISTORY:
*
* 21-Dec-92 Davidc Created.
*
\***************************************************************************/
LPTSTR
AllocAndExpandEnvironmentStrings(
LPCTSTR lpszSrc
)
{
LPTSTR String;
LONG LengthAllocated;
LONG LengthCopied;
//
// Pick a random buffer length, if it's not big enough reallocate
// it and try again until it is.
//
LengthAllocated = lstrlen(lpszSrc) + TYPICAL_STRING_LENGTH;
String = Alloc(LengthAllocated * sizeof(TCHAR));
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndExpandEnvironmentStrings : Failed to allocate %d bytes for string\n", LengthAllocated * sizeof(TCHAR)));
return(NULL);
}
while (TRUE) {
LengthCopied = ExpandEnvironmentStrings( lpszSrc,
String,
LengthAllocated
);
if (LengthCopied == 0) {
DebugLog((DEB_ERROR, "AllocAndExpandEnvironmentStrings : ExpandEnvironmentStrings failed, error = %d\n", GetLastError()));
Free(String);
String = NULL;
break;
}
//
// If the buffer was too small, make it bigger and try again
//
if (LengthCopied > LengthAllocated) {
DebugLog((DEB_TRACE, "AllocAndExpandEnvironmentStrings: Failed with buffer length = %d, reallocating to %d and retrying (retry should succeed)\n", LengthAllocated, LengthCopied));
String = ReAlloc(String, LengthCopied * sizeof(TCHAR));
LengthAllocated = LengthCopied;
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndExpandEnvironmentStrings : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
break;
}
//
// Go back and try to expand the string again
//
} else {
//
// Success!
//
break;
}
}
return(String);
}
/***************************************************************************\
* FUNCTION: AllocAndRegEnumKey
*
* PURPOSE: Allocates memory for and returns pointer to buffer containing
* the next registry sub-key name under the specified key
* The returned buffer should be freed using Free()
*
* RETURNS: Pointer to sub-key name or NULL on failure. The reason for the
* error can be obtains using GetLastError()
*
* HISTORY:
*
* 21-Dec-92 Davidc Created.
*
\***************************************************************************/
LPTSTR
AllocAndRegEnumKey(
HKEY hKey,
DWORD iSubKey
)
{
LPTSTR String;
LONG LengthAllocated;
//
// Pick a random buffer length, if it's not big enough reallocate
// it and try again until it is.
//
LengthAllocated = TYPICAL_STRING_LENGTH;
String = Alloc(LengthAllocated * sizeof(TCHAR));
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndRegEnumKey : Failed to allocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
return(NULL);
}
while (TRUE) {
DWORD Error = RegEnumKey(hKey, iSubKey, String, LengthAllocated);
if (Error == ERROR_SUCCESS) {
break;
}
if (Error != ERROR_MORE_DATA) {
if (Error != ERROR_NO_MORE_ITEMS) {
DebugLog((DEB_ERROR, "AllocAndRegEnumKey : RegEnumKey failed, error = %d", Error));
}
Free(String);
String = NULL;
SetLastError(Error);
break;
}
//
// The buffer was too small, make it bigger and try again
//
DebugLog((DEB_TRACE, "AllocAndRegEnumKey: Failed with buffer length = %d, reallocating and retrying", LengthAllocated));
LengthAllocated *= 2;
String = ReAlloc(String, LengthAllocated * sizeof(TCHAR));
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndRegEnumKey : Failed to reallocate %d bytes for string", LengthAllocated * sizeof(TCHAR)));
break;
}
}
return(String);
}
/***************************************************************************\
* FUNCTION: AllocAndRegQueryValueEx
*
* PURPOSE: Version of RegQueryValueEx that returns value in allocated buffer.
* The returned buffer should be freed using Free()
*
* RETURNS: Pointer to key value or NULL on failure. The reason for the
* error can be obtains using GetLastError()
*
* HISTORY:
*
* 15-Jan-93 Davidc Created.
*
\***************************************************************************/
LPTSTR
AllocAndRegQueryValueEx(
HKEY hKey,
LPTSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType
)
{
LPTSTR String;
DWORD BytesAllocated;
//
// Pick a random buffer length, if it's not big enough reallocate
// it and try again until it is.
//
BytesAllocated = TYPICAL_STRING_LENGTH * sizeof(TCHAR);
String = Alloc(BytesAllocated);
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : Failed to allocate %d bytes for string", BytesAllocated));
return(NULL);
}
while (TRUE) {
DWORD Error;
DWORD BytesReturned = BytesAllocated;
Error = RegQueryValueEx(hKey,
lpValueName,
lpReserved,
lpType,
(LPBYTE)String,
&BytesReturned);
if (Error == ERROR_SUCCESS) {
break;
}
if (Error != ERROR_MORE_DATA) {
DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : RegQueryValueEx failed, error = %d", Error));
Free(String);
String = NULL;
SetLastError(Error);
break;
}
//
// The buffer was too small, make it bigger and try again
//
DebugLog((DEB_TRACE, "AllocAndRegQueryValueEx: Failed with buffer length = %d bytes, reallocating and retrying", BytesAllocated));
BytesAllocated *= 2;
String = ReAlloc(String, BytesAllocated);
if (String == NULL) {
DebugLog((DEB_ERROR, "AllocAndRegQueryValueEx : Failed to reallocate %d bytes for string", BytesAllocated));
break;
}
}
return(String);
}
/***************************************************************************\
* CentreWindow
*
* Purpose : Positions a window so that it is centred in its parent
*
* History:
* 12-09-91 Davidc Created.
\***************************************************************************/
VOID
CentreWindow(
HWND hwnd
)
{
RECT rect;
LONG dx, dy;
LONG dxParent, dyParent;
LONG Style;
// Get window rect
GetWindowRect(hwnd, &rect);
dx = rect.right - rect.left;
dy = rect.bottom - rect.top;
// Get parent rect
Style = GetWindowLong(hwnd, GWL_STYLE);
if ((Style & WS_CHILD) == 0) {
// Return the desktop windows size (size of main screen)
dxParent = GetSystemMetrics(SM_CXSCREEN);
dyParent = GetSystemMetrics(SM_CYSCREEN);
} else {
HWND hwndParent;
RECT rectParent;
hwndParent = GetParent(hwnd);
if (hwndParent == NULL) {
hwndParent = GetDesktopWindow();
}
GetWindowRect(hwndParent, &rectParent);
dxParent = rectParent.right - rectParent.left;
dyParent = rectParent.bottom - rectParent.top;
}
// Centre the child in the parent
rect.left = (dxParent - dx) / 2;
rect.top = (dyParent - dy) / 3;
// Move the child into position
SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, 0, 0, SWP_NOSIZE);
SetForegroundWindow(hwnd);
}
/***************************************************************************\
* SetupSystemMenu
*
* Purpose : Does any manipulation required for a dialog system menu.
* Should be called during WM_INITDIALOG processing for a dialog
*
* History:
* 12-09-91 Davidc Created.
\***************************************************************************/
VOID
SetupSystemMenu(
HWND hDlg
)
{
// Remove the Close item from the system menu if we don't
// have a CANCEL button
if (GetDlgItem(hDlg, IDCANCEL) == NULL) {
HMENU hMenu = GetSystemMenu(hDlg, FALSE);
DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
}
}
/***************************************************************************\
* FUNCTION: OpenIniFileUserMapping
*
* PURPOSE: Forces the ini file mapping apis to reference the current user's
* registry.
*
* RETURNS: TRUE on success, FALSE on failure
*
* HISTORY:
*
* 24-Aug-92 Davidc Created.
*
\***************************************************************************/
BOOL
OpenIniFileUserMapping(
PGLOBALS pGlobals
)
{
BOOL Result;
HANDLE ImpersonationHandle;
//
// Impersonate the user
//
if (pGlobals->IniRef == 0)
{
ImpersonationHandle = ImpersonateUser(&pGlobals->UserProcessData, NULL);
if (ImpersonationHandle == NULL) {
DebugLog((DEB_ERROR, "OpenIniFileUserMapping failed to impersonate user"));
return(FALSE);
}
DebugLog((DEB_TRACE, "Actually opening user mapping. User %s logged on\n",
pGlobals->UserLoggedOn ? "is" : "is not"));
Result = OpenProfileUserMapping();
if (!Result) {
DebugLog((DEB_ERROR, "OpenProfileUserMapping failed, error = %d", GetLastError()));
}
//
// Revert to being 'ourself'
//
if (!StopImpersonating(ImpersonationHandle)) {
DebugLog((DEB_ERROR, "OpenIniFileUserMapping failed to revert to self"));
}
}
else
{
Result = TRUE;
}
pGlobals->IniRef++;
DebugLog((DEB_TRACE, "ProfileUserMapping Refs = %d\n", pGlobals->IniRef));
return(Result);
}
/***************************************************************************\
* FUNCTION: CloseIniFileUserMapping
*
* PURPOSE: Closes the ini file mapping to the user's registry such
* that future use of the ini apis will fail if they reference
* the user's registry.
*
* RETURNS: Nothing
*
* HISTORY:
*
* 24-Aug-92 Davidc Created.
*
\***************************************************************************/
VOID
CloseIniFileUserMapping(
PGLOBALS pGlobals
)
{
BOOL Result;
if (pGlobals->IniRef)
{
if (--pGlobals->IniRef == 0)
{
DebugLog((DEB_TRACE, "Actually closing user mapping\n"));
Result = CloseProfileUserMapping();
if (!Result) {
DebugLog((DEB_ERROR, "CloseProfileUserMapping failed, error = %d", GetLastError()));
}
}
}
DebugLog((DEB_TRACE, "ProfileUserMapping Refs = %d\n", pGlobals->IniRef));
}