/****************************** 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)); }