/****************************** Module Header ******************************\ * Module Name: sethc.c * * Copyright (c) 1997, Microsoft Corporation * * SetHC -- exe to set or clear high contrast state. * * History: * 02-01-97 Fritz Sands Created * Bug fixes : a-anilk June 99 \***************************************************************************/ /*************************************************************************** * Use the following define if for some reason we have to go back to using * a message loop to let shell have time to update the UI * #define NEED_MSG_PUMP **************************************************************************/ #ifndef RC_INVOKED #include #include #include #endif #include #include #include #include #include #include #include #include #include #include #include "access.h" #pragma hdrstop HINSTANCE g_hInstance; #ifdef DBG #define DBPRINTF MyOutputDebugString void MyOutputDebugString( LPCTSTR lpOutputString, ...); #else #define DBPRINTF 1 ? (void)0 : (void) #endif /* * High Contrast Stuff */ #define HC_KEY TEXT("Control Panel\\Accessibility\\HighContrast") #define HIGHCONTRASTSCHEME TEXT("High Contrast Scheme") #define REGSTR_VAL_FLAGS TEXT("Flags") #define REGSTR_PATH_APPEARANCE TEXT("Control Panel\\Appearance") #define REGSTR_PATH_LOOKSCHEMES TEXT("Control Panel\\Appearance\\Schemes") #define APPEARANCESCHEME REGSTR_PATH_LOOKSCHEMES #define DEFSCHEMEKEY REGSTR_PATH_APPEARANCE #define DEFSCHEMENAME TEXT("Current") #define WHITEBLACK_HC TEXT("High Contrast Black (large)") #define CURHCSCHEME TEXT("Volatile HC Scheme") // the extension for an appearance filename #define THEME_EXT L".msstyles" // the following is a Windows Classic color scheme or a THEME_EXT file name #define PRE_HC_SCHEME TEXT("Pre-High Contrast Scheme") // the following is the color scheme when pre-HC was a .mstheme #define PRE_HC_THM_COLOR TEXT("Pre-High Contrast Color") // the following is the font size when pre-HC was a .mstheme #define PRE_HC_THM_SIZE TEXT("Pre-High Contrast Size") // the following is the wallpaper for pre-HC #define PRE_HC_WALLPAPER TEXT("Pre-High Contrast Wallpaper") // increase this value so we can store a theme filename #ifdef MAX_SCHEME_NAME_SIZE #undef MAX_SCHEME_NAME_SIZE #endif #define MAX_SCHEME_NAME_SIZE 512 #define ARRAYSIZE(x) sizeof(x)/sizeof(x[0]) /* * Note -- this must match the desktop applet */ #define SCHEME_VERSION 2 // Ver 2 == Unicode typedef struct { SHORT version; WORD wDummy; // for alignment NONCLIENTMETRICS ncm; LOGFONT lfIconTitle; COLORREF rgb[COLOR_MAX]; } SCHEMEDATA; typedef DWORD (WINAPI* PFNDIALOGRTN)(BOOL); PFNDIALOGRTN g_aRtn[] = { NULL, StickyKeysNotification, //ACCESS_STICKYKEYS FilterKeysNotification, //ACCESS_FILTERKEYS ToggleKeysNotification, //ACCESS_TOGGLEKEYS MouseKeysNotification, //ACCESS_MOUSEKEYS HighContNotification, //ACCESS_HIGHCONTRAST }; /*************************************************************************** * GetRegValue * * Passed the key, and the identifier, return the string data from the * registry. ***************************************************************************/ long GetRegValue(LPWSTR RegKey, LPWSTR RegEntry, LPWSTR RegVal, long Size) { HKEY hReg; // Registry handle for schemes DWORD Type; // Type of value long retval; DWORD ccbSize = Size; RegVal[0] = 0; // in case something fails always return null-terminated retval = RegCreateKey(HKEY_CURRENT_USER, RegKey, &hReg); if (retval != ERROR_SUCCESS) return retval; retval = RegQueryValueEx(hReg, RegEntry, NULL, (LPDWORD)&Type, (LPBYTE)RegVal, &ccbSize); // 'ccbSize' is in bytes if (retval == ERROR_SUCCESS && Type == REG_SZ && ccbSize > 0) { ccbSize /= 2; RegVal[ccbSize - 1] = 0; // ensure null-termination } else { RegVal[0] = 0; // if reg type is not string don't return anything } RegCloseKey(hReg); return retval; } /*************************************************************************** * SetRegValue * * Passed the key, and the identifier, set the string data from the * registry. ***************************************************************************/ long SetRegValue(LPTSTR RegKey, LPWSTR RegEntry, LPVOID RegVal, long Size, DWORD Type) { HKEY hReg; // Registry handle for schemes DWORD Reserved = 0; long retval; if (RegCreateKey(HKEY_CURRENT_USER,RegKey, &hReg) != ERROR_SUCCESS) return 0; // A common error is to omit the `+1', so we just smash the correct // value into place regardless. if (Type == REG_SZ) Size = (lstrlen(RegVal) + 1) * sizeof(WCHAR); retval = RegSetValueEx(hReg, RegEntry, 0, Type, RegVal, Size); RegCloseKey(hReg); return retval; } /*************************************************************************** * SaveAndRemoveWallpaper * * Gets the current wallpaper setting from the system and saves it in the * accessibility registry entries. No error return as there isn't anything * we can do. * * ISSUE we aren't getting all the active desktop properties; just wallpaper. * This isn't a regression in that we didn't even restore wallpaper in W2K. * ***************************************************************************/ void SaveAndRemoveWallpaper() { WCHAR szWallpaper[MAX_SCHEME_NAME_SIZE] = {0}; IActiveDesktop *p; HRESULT hr; hr = CoCreateInstance( &CLSID_ActiveDesktop , NULL , CLSCTX_INPROC_SERVER , &IID_IActiveDesktop , (void **)&p); if (SUCCEEDED(hr)) { hr = p->lpVtbl->GetWallpaper(p, szWallpaper, MAX_SCHEME_NAME_SIZE, 0); if (SUCCEEDED(hr)) { // save the current wallpaper setting SetRegValue(HC_KEY, PRE_HC_WALLPAPER, szWallpaper, 0, REG_SZ); // now remove the wallpaper, if necessary if (szWallpaper[0]) { szWallpaper[0] = 0; hr = p->lpVtbl->SetWallpaper(p, szWallpaper, 0); if (SUCCEEDED(hr)) hr = p->lpVtbl->ApplyChanges(p, AD_APPLY_ALL); } } p->lpVtbl->Release(p); } } /*************************************************************************** * RestoreWallpaper * * Restores the pre-high contrast wallpaper setting. Reads the setting * stored in the accessibility registry entries and restores the system * setting. No error return as there isn't anything we can do. * ***************************************************************************/ void RestoreWallpaper() { long lRv; TCHAR szWallpaper[MAX_SCHEME_NAME_SIZE] = {0}; lRv = GetRegValue(HC_KEY, PRE_HC_WALLPAPER, szWallpaper, sizeof(szWallpaper)); if (lRv == ERROR_SUCCESS && szWallpaper[0]) { IActiveDesktop *p; HRESULT hr; hr = CoCreateInstance( &CLSID_ActiveDesktop , NULL , CLSCTX_INPROC_SERVER , &IID_IActiveDesktop , (void **)&p); if (SUCCEEDED(hr)) { hr = p->lpVtbl->SetWallpaper(p, szWallpaper, 0); if (SUCCEEDED(hr)) hr = p->lpVtbl->ApplyChanges(p, AD_APPLY_ALL); p->lpVtbl->Release(p); } } } /*************************************************************************** * AppearanceRestored * * lpszName [in] the name of a theme file (mstheme). * * Function returns TRUE if lpszName is a theme file and it was restored * otherwise it returns FALSE. May return TRUE if restoring the theme * fails (not much we can do if theme api's fail). * ***************************************************************************/ BOOL AppearanceRestored(LPCWSTR lpszName) { HRESULT hr; DWORD dwThemeFlags; int cch = lstrlen(lpszName) - lstrlen(THEME_EXT); TCHAR szColor[MAX_SCHEME_NAME_SIZE] = {0}; TCHAR szSize[MAX_SCHEME_NAME_SIZE] = {0}; if (cch <= 0 || lstrcmpi(&lpszName[cch], THEME_EXT)) { DBPRINTF(TEXT("AppearanceRestored: %s is not a theme file\r\n"), lpszName); return FALSE; // this isn't a theme file } // This is a theme file, get the color and size parts of the theme GetRegValue(HC_KEY, PRE_HC_THM_COLOR, szColor, sizeof(szColor)); GetRegValue(HC_KEY, PRE_HC_THM_SIZE, szSize, sizeof(szSize)); // Load the theme file, color and size then apply it dwThemeFlags = AT_LOAD_SYSMETRICS | AT_SYNC_LOADMETRICS; hr = SetSystemVisualStyle(lpszName, szColor, szSize, dwThemeFlags); DBPRINTF(TEXT("AppearanceRestored: SetSystemVisualStyle(%s, %s, %s, 0x%x) returned 0x%x\r\n"), lpszName, szColor, szSize, dwThemeFlags, hr); return TRUE; } /*************************************************************************** * DelRegValue * * Passed the key and the subkey, delete the subkey. * ***************************************************************************/ long DelRegValue(LPTSTR RegKey, LPTSTR RegEntry) { HKEY hReg; // Registry handle for schemes DWORD Reserved = 0; long retval; retval = RegCreateKey(HKEY_CURRENT_USER,RegKey, &hReg); if (retval != ERROR_SUCCESS) return retval; retval = RegDeleteValue(hReg, RegEntry); RegCloseKey(hReg); return retval; } #define COLOR_MAX_400 (COLOR_INFOBK + 1) void FAR SetMagicColors(HDC, DWORD, WORD); /*************************************************************************** * * * SetCurrentSchemeName * * Input: szName -> name of scheme or theme to become current * Output: Boolean success/failure * ***************************************************************************/ typedef LONG (CALLBACK *APPLETPROC)(HWND, UINT, LPARAM, LPARAM); typedef BOOL (CALLBACK *SETSCHEME)(LPCTSTR); typedef BOOL (CALLBACK *SETSCHEMEA)(LPCSTR); BOOL SetCurrentSchemeName(LPCWSTR lpszName, BOOL fNoReg) { BOOL fRc = FALSE; if (fNoReg) { // Setting a non-persistent scheme; we come to this code path for // both setting or unsetting HC via hot keys HKEY hkSchemes; // For Whistler, because it may confuse users, we are always turning off // theming and any wallpaper. Otherwise, sometimes they'll loose these // settings (when they log off and log back on) and sometimes they won't // (when they use the hot keys to turn HC off). DBPRINTF(TEXT("SetCurrentSchemeName: To %s w/o persisting to registry\r\n"), lpszName); if (IsThemeActive()) { DBPRINTF(TEXT("SetCurrentSchemeName: Turning off active Themes\r\n")); ApplyTheme(NULL, 0, NULL); } if (RegOpenKey(HKEY_CURRENT_USER, REGSTR_PATH_LOOKSCHEMES, &hkSchemes) == ERROR_SUCCESS) { SCHEMEDATA sd; DWORD dwType, dwSize; BOOL b; HDC hdc; int iColors[COLOR_MAX]; int i; COLORREF rgbColors[COLOR_MAX]; dwType = REG_BINARY; dwSize = sizeof(sd); if (RegQueryValueEx(hkSchemes, lpszName, NULL, &dwType, (LPBYTE)&sd, &dwSize) == ERROR_SUCCESS && dwType == REG_BINARY) { int n; if (sd.version != SCHEME_VERSION) { RegCloseKey(hkSchemes); return FALSE; } n = (int)(dwSize - (sizeof(sd) - sizeof(sd.rgb))) / sizeof(COLORREF); sd.ncm.cbSize = sizeof(NONCLIENTMETRICS); b = SystemParametersInfo(SPI_SETNONCLIENTMETRICS, sizeof(sd.ncm), (void far *)&sd.ncm, 0); b = SystemParametersInfo(SPI_SETICONTITLELOGFONT, sizeof(LOGFONT), (void far *)(LPLOGFONT)&sd.lfIconTitle, 0); if (n == COLOR_MAX_400) { sd.rgb[COLOR_HOTLIGHT] = sd.rgb[COLOR_ACTIVECAPTION]; sd.rgb[COLOR_GRADIENTACTIVECAPTION] = RGB(0,0,0); sd.rgb[COLOR_GRADIENTINACTIVECAPTION] = RGB(0,0,0); } #if(WINVER >= 0x0501) // new Whistler colors sd.rgb[COLOR_MENUBAR] = sd.rgb[COLOR_MENU]; sd.rgb[COLOR_MENUHILIGHT] = sd.rgb[COLOR_HIGHLIGHT]; // reset "flatmenu" and "dropshadows" settings SystemParametersInfo(SPI_SETFLATMENU, 0, IntToPtr(FALSE), SPIF_SENDCHANGE); SystemParametersInfo(SPI_SETDROPSHADOW, 0, IntToPtr(FALSE), SPIF_SENDCHANGE); #endif /* WINVER >= 0x0501 */ // // restore magic colors back to Win31 defaults. // hdc = GetDC(NULL); SetMagicColors(hdc, 0x00c0dcc0, 8); // money green SetMagicColors(hdc, 0x00f0caa6, 9); // IBM blue SetMagicColors(hdc, 0x00f0fbff, 246); // off white ReleaseDC(NULL, hdc); for (i=0; i '9' ) { return 0; } } fSet = lpszCmdParam[0] - '0'; fWasSet = lpszCmdParam[1] - '0'; fNoReg = lpszCmdParam[2] - '0'; DBPRINTF(TEXT("WinMain: fSet=%d fWasSet=%d fNoReg=%d\r\n"), fSet, fWasSet, fNoReg); // this is to deal with HighContrast, StickyKey, ToggleKey, FilterKey and MouseKeys if ( fSet == 2 ) { // this is which Dialog will be displayed LONG lPopup = lpszCmdParam[1] - '0'; // This indicate wheather we will actually display the dialog or just do the work without asking BOOL fNotify = lpszCmdParam[2] - '0'; DBPRINTF(TEXT("WinMain: lPopup=%d fNotify=%d\r\n"), lPopup, fNotify ); // Make sure we don't access outside the bounds of the funtion pointer array if ( lPopup < 1 || lPopup > 5 ) return 0; // Index into a table of functions pointers and call the // funtion to bring up the right hotkey dialog. g_aRtn[lPopup]( fNotify ); CoUninitialize(); return 1; } #if NEED_MSG_PUMP // Create a message only window to process messages from theme api wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = 0; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = NULL; wcex.hCursor = NULL; wcex.hbrBackground = NULL; wcex.lpszMenuName = NULL; wcex.lpszClassName = pszWindowClass; wcex.hIconSm = NULL; RegisterClassEx(&wcex); hWnd = CreateWindow(pszWindowClass,NULL,0,0,0,0,0,HWND_MESSAGE,NULL,hInstance,NULL); if (!hWnd) { return 0; } #endif if (fSet) { SetHighContrast(fWasSet, fNoReg); } else { ClearHighContrast(fNoReg); } #if NEED_MSG_PUMP SetTimer(hWnd, 1, 4000, NULL); // The calls to set/unset visual style require that messages // be processed. When the timer goes we'll exit. while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } #endif CoUninitialize(); return 1; } #ifdef DEBUG void MyOutputDebugString( LPCTSTR lpOutputString, ...) { TCHAR achBuffer[500]; /* create the output buffer */ va_list args; va_start(args, lpOutputString); wvsprintf(achBuffer, lpOutputString, args); va_end(args); OutputDebugString(achBuffer); } #endif