/*++ Copyright (c) 1992 Microsoft Corporation Module Name: taskman.c Abstract: This file contains the source for the windows Task Manager. Taskman basically is a dialog box, which enumerates active windows keep in the user window manager, then sets active focus to the selected dialog box element(ie active window). --*/ #define UNICODE #include "taskman.h" #include #include #include //LATER find correct define for NT #if !defined(NTWIN) && !defined(DOSWIN32) && !defined(WIN16) #define NTWIN 1 #endif #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) #define MAXPATHFIELD 260 #define INIT_MAX_FILES 4 #define FILES_KEY L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Program Manager\\Recent File List" #define MAXFILES_ENTRY L"Max Files" #define FILE_ENTRY L"File%lu" #define WM_CONTENTSCHANGED (WM_USER+5) TCHAR szPathField[MAXPATHFIELD]; TCHAR szDirField[MAXPATHFIELD]; TCHAR szTitle[MAXPATHFIELD]; TCHAR szMessage[MAXMSGBOXLEN]; TCHAR szUserHomeDir[MAXPATHFIELD]; TCHAR szWindowsDirectory[MAXPATHFIELD]; TCHAR szOOMExitMsg[64] = TEXT("Close an application and try again."); // 64 TCHAR szOOMExitTitle[32] = TEXT("Extremely Low on Memory"); // 32 TCHAR szNoRun[] = TEXT("NoRun"); // registry key for groups HANDLE hInst; BOOL bChangedDefaultButton; INT_PTR APIENTRY TaskmanDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam); WORD APIENTRY ExecProgram(LPTSTR lpszPath,LPTSTR lpDir,LPTSTR lpTitle); void APIENTRY SaveRecentFileList (HWND, LPTSTR); VOID GetPathInfo(PTSTR szPath,PTSTR *pszFileName,PTSTR *pszExt,WORD *pich,BOOL *pfUnc); VOID GetFilenameFromPath(PTSTR szPath, PTSTR szFilename); VOID GetDirectoryFromPath(PTSTR szFilePath, PTSTR szDir); BOOL IsUserAdmin(); BOOL OKToExec(); BOOL TestTokenForAdmin(HANDLE Token); VOID SetDefButton(HWND hwndDlg, INT idButton); WINUSERAPI VOID SwitchToThisWindow(HWND, BOOL); INT MyMessageBox(HWND hWnd,WORD idTitle,WORD idMessage,PWSTR psz,WORD wStyle); INT MyX = 0; INT MyY = 0; INT dxTaskman; INT dyTaskman; INT dxScreen; INT dyScreen; HWND ghwndDialog; BOOL fExecOK = TRUE; BOOL fMsgBox = FALSE; PVOID Alloc( DWORD Bytes) { HANDLE hMem; PVOID Buffer; hMem = LocalAlloc(LMEM_MOVEABLE, Bytes + sizeof(hMem)); if (hMem == NULL) { return(NULL); } Buffer = LocalLock(hMem); if (Buffer == NULL) { LocalFree(hMem); return(NULL); } *((PHANDLE)Buffer) = hMem; return (PVOID)(((PHANDLE)Buffer)+1); } BOOL Free( PVOID Buffer) { HANDLE hMem; hMem = *(((PHANDLE)Buffer) - 1); LocalUnlock(hMem); return(LocalFree(hMem) == NULL); } VOID HideWindow(HWND hwnd) { if (!fMsgBox) { if (fExecOK) { SetDlgItemText(ghwndDialog, IDD_PATH, TEXT("")); } // redundant? why do they do the reverse twice for show below? ShowWindow(ghwndDialog, SW_HIDE); SetWindowPos(ghwndDialog, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } // Erase dark border from depressed pushbuttons SendMessage(GetDlgItem(hwnd, IDCANCEL), // IDCANCEL BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0)); SendMessage(GetDlgItem(hwnd, IDD_TERMINATE), BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0)); SendMessage(GetDlgItem(hwnd, IDD_CASCADE), BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0)); SendMessage(GetDlgItem(hwnd, IDD_TILE), BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0)); SendMessage(GetDlgItem(hwnd, IDD_ARRANGEICONS), BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0)); } /* * We call HideTasklist() when we want to remove the tasklist window * from the screen but not select another window (ie. when we're about * to select another app. We call ShowWindow(SW_HIDE) directly when * we're doing something like tiling or cascading so a window other than * the tasklist will become the foreground window. */ VOID HideTasklist(VOID) { if (fExecOK) { SetDlgItemText(ghwndDialog, IDD_PATH, TEXT("")); } SetWindowPos(ghwndDialog, HWND_TOP, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); } VOID ShowTasklist( POINT pt) { /* * Retract the drop down listbox. */ if (fExecOK) { SendDlgItemMessage(ghwndDialog, IDD_PATH, CB_SHOWDROPDOWN,0,0); } SetWindowPos(ghwndDialog, HWND_TOPMOST, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE ); SetForegroundWindow(ghwndDialog); ShowWindow(ghwndDialog, SW_NORMAL); } /*** ActivateSelectedWindow -- Calls user, to set active window, selected * by the user. * * * ActivateSelectedWindow(HWND hwndLB) * * ENTRY - HWND hwndLB - handle to window, which is to become the active * window, with focus. * EXIT - * SYNOPSIS - This function takes the hwnd passed into it, calls user * to set active focus to that window. * WARNINGS - * EFFECTS - * */ VOID ActivateSelectedWindow( HWND hwndLB) { INT nIndex; HWND hwndT; HWND hwndLastActive; DWORD lTemp; /* * Get the hwnd of the item which was selected. */ nIndex = (int)SendMessage(hwndLB, LB_GETCURSEL, 0, 0); hwndT = (HWND)SendMessage(hwndLB, LB_GETITEMDATA, nIndex, 0); if (!IsWindow(hwndT)) { /* * We gotta make sure the window is valid before doing stuff with it. * An app may terminate itself in the background rendering these * window handles invalid. */ goto Beep; } /* * Switch to that task. * HACK! Activate the window in the hwndLastActive field of the WndStruct. */ hwndLastActive = GetLastActivePopup(hwndT); if (!IsWindow(hwndLastActive)) { goto Beep; } /* * But only if it isn't disabled. */ lTemp = GetWindowLong(hwndLastActive, GWL_STYLE); if (!(lTemp & WS_DISABLED)) { /* * HACK!! Use SwitchToThisWindow() to bring dialog parents as well. */ SwitchToThisWindow(hwndLastActive, TRUE); } else { Beep: MessageBeep(0); } } #ifdef NTWIN /*** DoEndTask -- * * void DoEndTask( HWND hwnd ) */ VOID DoEndTask( HWND hwnd ) { TCHAR szMsgBoxText[MAXMSGBOXLEN]; TCHAR szTempField[MAXTASKNAMELEN]; INT nch; if (!EndTask(hwnd, FALSE, FALSE)) { /* App does not want to close, ask user if * he wants to blow it away */ InternalGetWindowText(hwnd, (LPTSTR)szTempField, MAXTASKNAMELEN); /* Load the message box string, it is very long (greater than 255 chars * which is why we load it in two pieces */ nch = LoadString(NULL, IDS_MSGBOXSTR1, szMsgBoxText, MAXMSGBOXLEN); LoadString(NULL, IDS_MSGBOXSTR2, &szMsgBoxText[nch], MAXMSGBOXLEN-nch); if( MessageBox( NULL, szMsgBoxText, szTempField, MB_SETFOREGROUND | MB_SYSTEMMODAL | MB_YESNO ) == IDYES) { EndTask(hwnd, FALSE, TRUE); } } } /*** CallEndTask -- A separate thread to instigate EndTask * * CallEndTask( HWND hwnd ); * * ENTRY - HWND hwnd - window handle for the task to be killed * EXIT - * SYNOPSIS - This function calls EndTask on the given window to kill the * task that owns that window. * * WARNINGS - * EFFECTS - Kills the task that owns hwnd. * */ DWORD CallEndTask( HWND hwnd) { DoEndTask(hwnd); ExitThread(0); return 0; /* placate compiler */ } #endif /*** TaskmanDlgProc -- Dialog Procedure for Taskman Window * * * * TaskmanDlgProc(HWND hDlg, WORD wMSG, DWORD wParam, LPARAM lParam) * * ENTRY - HWND hhDlg - handle to dialog box. * WORD wMsg - message to be acted upon. * DWORD wParam - value specific to wMsg. * LPARAM lParam - value specific to wMsg. * * EXIT - True if success, False if not. * SYNOPSIS - Dialog box message processing function. * * WARNINGS - * EFFECTS - * */ INT_PTR TaskmanDlgProc( HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { int nIndex; RECT rc; HWND hwndLB; HWND hwndNext; TCHAR szTempField[MAXTASKNAMELEN]; POINT pt; HKEY hKey; DWORD dwDisp; DWORD dwDataType, dwMaxFiles=INIT_MAX_FILES, dwMaxFilesSize, dwCount; TCHAR szFileEntry[20]; TCHAR szFullPath[MAXPATHFIELD]; #ifndef NTWIN LONG lTemp; #endif hwndLB = GetDlgItem(hwnd, IDD_TASKLISTBOX); switch (wMsg) { case WM_INITDIALOG: /* * call private api to mark task man as a system app. This causes * it to be killed after all other non-system apps during shutdown. */ // MarkProcess(MP_SYSTEMAPP); GetWindowRect(hwnd, &rc); dxTaskman = rc.right - rc.left; dyTaskman = rc.bottom - rc.top; dxScreen = GetSystemMetrics(SM_CXSCREEN); dyScreen = GetSystemMetrics(SM_CYSCREEN); pt.x = (dxScreen - dxTaskman) / 2; pt.y = (dyScreen - dyTaskman) / 2; SetWindowPos(hwnd, HWND_NOTOPMOST, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); SendDlgItemMessage(hwnd, IDD_PATH, EM_LIMITTEXT, MAXPATHFIELD-4, 0L); szPathField[0] = TEXT('\0'); bChangedDefaultButton = FALSE; return FALSE; case WM_SHOWWINDOW: /* * If we're being shown fill in the listbox. We do this here * rather than in WM_ACTIVATE process so we can do it while the * dialog is still invisible. */ if (wParam != 0) { DWORD pidTaskMan = GetCurrentProcessId(); /* * First delete any previous entries. */ while ((int)SendMessage(hwndLB, LB_DELETESTRING, 0, 0) != LB_ERR); /* * Search the window list for enabled top level windows. */ hwndNext = GetWindow(hwnd, GW_HWNDFIRST); while (hwndNext) { /* * Only add non-owned, visible, non-Taskman, Top Level Windows. */ if ((hwndNext != hwnd) && (IsWindowVisible(hwndNext)) && (!GetWindow(hwndNext, GW_OWNER))) { DWORD pidNext; GetWindowThreadProcessId(hwndNext, &pidNext); if (pidNext != pidTaskMan) { if (InternalGetWindowText(hwndNext, (LPTSTR)szTempField, MAXTASKNAMELEN)) { nIndex = (int)SendMessage(hwndLB, LB_ADDSTRING, 0, (DWORD_PTR)(LPTSTR)szTempField); SendMessage(hwndLB, LB_SETITEMDATA, nIndex, (DWORD_PTR)hwndNext); } } } hwndNext = GetWindow(hwndNext, GW_HWNDNEXT); } SendMessage(hwndLB, LB_SETCURSEL, 0, 0); // // Set the default button to "Switch To" // SetDefButton(hwnd,IDD_SWITCH); // // Load the combobox with the recently used files. // if (GetDlgItem(hwnd, IDD_PATH)) { // // FIrst empty the combo box from the last time. // SendDlgItemMessage (hwnd, IDD_PATH, CB_RESETCONTENT, 0, 0); // // Load the combobox with recently used files from the registry. // // Query the max number of files first. // if (RegCreateKeyEx (HKEY_CURRENT_USER, FILES_KEY, 0, 0, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &dwDisp) == ERROR_SUCCESS) { if (dwDisp == REG_OPENED_EXISTING_KEY) { // // Query the max number of entries // dwMaxFilesSize = sizeof (DWORD); if (RegQueryValueEx (hKey, MAXFILES_ENTRY, NULL, &dwDataType, (LPBYTE)&dwMaxFiles, &dwMaxFilesSize) == ERROR_SUCCESS) { // // Now Query each entry and add it to the list box. // for (dwCount=0; dwCount < dwMaxFiles; dwCount++) { wsprintf (szFileEntry, FILE_ENTRY, dwCount); dwMaxFilesSize = MAXPATHFIELD+1; if (RegQueryValueEx (hKey, szFileEntry, NULL, &dwDataType, (LPBYTE) szFullPath, &dwMaxFilesSize) == ERROR_SUCCESS) { // // Found an entry. Add it to the combo box. // SendDlgItemMessage (hwnd, IDD_PATH, CB_ADDSTRING, 0, (LPARAM)szFullPath); } else { break; } } } } else { // // We are working with a new key, so we need to // set the default number of files. // RegSetValueEx (hKey, MAXFILES_ENTRY, 0, REG_DWORD, (CONST BYTE *) &dwMaxFiles, sizeof (DWORD)); } // // Close the registry key // RegCloseKey (hKey); } } // // Disable the Run button and set the focus to the // listbox. // EnableWindow(GetDlgItem(hwnd, IDD_RUN), FALSE); SetFocus(hwndLB); } break; case WM_ACTIVATE: /* * If we're being deactivated clear the listbox so we * can fill it in afresh when we're re-activated. */ if (wParam == 0) { /* * If we're not already invisible, hide ourself. */ if (IsWindowVisible(hwnd)) { HideWindow(hwnd); } } if (!bChangedDefaultButton) { SetDefButton(hwnd,IDD_SWITCH); } break; case WM_ACTIVATEAPP: if (wParam) return FALSE; /* * If we are not visible when we get this message it is because * we are already in the process of terminating. If we don't * ignore this we get into a weird race condition and the frame * of the window being activated doesn't get fully drawn. (BG) */ if (IsWindowVisible(hwnd)) { HideWindow(hwnd); } break; #ifdef JAPAN // bug fix // // Do nothing. Let the progman main thread do the work. // #else // not JAPAN case WM_WININICHANGE: // // Check if the user's environment variables have changed, if so // regenerate the environment, so that new apps started from // taskman will have the latest environment. // if (lParam && (!lstrcmpi((LPTSTR)lParam, (LPTSTR) TEXT("Environment")))) { PVOID pEnv; RegenerateUserEnvironment(&pEnv, TRUE); break; } else { return FALSE; } #endif // JAPAN case WM_CONTENTSCHANGED: if (fExecOK) { if (GetDlgItemText(hwnd, IDD_PATH, (LPTSTR)szPathField, MAXPATHFIELD)) { EnableWindow(GetDlgItem(hwnd, IDD_RUN), TRUE); if (!bChangedDefaultButton) { SetDefButton(hwnd,IDD_RUN); bChangedDefaultButton = TRUE; } } else { EnableWindow(GetDlgItem(hwnd, IDD_RUN), FALSE); if (bChangedDefaultButton) { SetDefButton(hwnd,IDD_SWITCH); bChangedDefaultButton = FALSE; } } } break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDD_TASKLISTBOX: switch(HIWORD(wParam)) { case LBN_DBLCLK: HideTasklist(); ActivateSelectedWindow(hwndLB); break; default: return FALSE; } break; case IDD_PATH: PostMessage (hwnd, WM_CONTENTSCHANGED, 0, 0); break; case IDOK: if (!bChangedDefaultButton) { goto Switchem; } case IDD_RUN: if (fExecOK) { TCHAR szFilename[MAXPATHFIELD+4]; WORD ret; GetDlgItemText(hwnd, IDD_PATH, szPathField, MAXPATHFIELD); DoEnvironmentSubst(szPathField, MAXPATHFIELD); GetDirectoryFromPath(szPathField, szDirField); if (*szDirField) { // Convert path into a .\foo.exe style thing. lstrcpy(szFilename, L".\\"); // Tag the filename and params on to the end of the dot slash. GetFilenameFromPath(szPathField, szFilename+2); if (*(szFilename+2) == L'"' ) { SheRemoveQuotes(szFilename+2); CheckEscapes(szFilename, ARRAYSIZE(szFilename)); } } else { GetFilenameFromPath(szPathField, szFilename); } ret = ExecProgram(szFilename, szDirField, szFilename); if (ret) { fMsgBox = TRUE; MyMessageBox( hwnd, IDS_EXECERRTITLE, ret, szPathField, MB_SYSTEMMODAL | MB_OK | MB_ICONEXCLAMATION ); fMsgBox = FALSE; SetFocus(GetDlgItem(hwnd, IDD_PATH)); } else { GetDlgItemText(hwnd, IDD_PATH, szPathField, MAXPATHFIELD); SaveRecentFileList (hwnd, szPathField); HideWindow(hwnd); } } break; Switchem: case IDD_SWITCH: HideTasklist(); ActivateSelectedWindow(hwndLB); break; case IDCANCEL: HideWindow(hwnd); break; case IDD_TERMINATE: /* * Get the hwnd of the item which was selected. */ nIndex = (int)SendMessage(hwndLB, LB_GETCURSEL, 0, 0); hwndNext = (HWND)SendMessage(hwndLB, LB_GETITEMDATA, nIndex, 0); if (!IsWindow(hwndNext)) { HideWindow(hwnd); MessageBeep(0); break; } #ifndef NTWIN /* Since NTWIN uses WM_ENDSESSION to kill the app, * It is OK to kill it when it is disabled */ /* * Test if the toplevel window is disabled. If it is * diabled, we don't want to send a WM_CLOSE message to * the parent. This is because the app could have a dialog * box up and it's not expecting a CLOSE message... * Nasty rips can happen... Instead, active the window so * that the user can dismis any dialog box or fix whatever * is causing the top level window to be disabled... */ lTemp = GetWindowLong(hwndNext, GWL_STYLE); if (lTemp & WS_DISABLED) { HideTasklist(); MessageBeep(0); ActivateSelectedWindow(hwndLB); } else #endif { /* Always activate the window first. This prevents * apps from going to Beep mode. Failing to do this * can cause re-entrancy problems in the app if we * do this again before activating the app. * * However, don't do this if it is a old app task. */ #ifdef WIN16 /* if NTWIN, then always do this, as is no winoldapp */ if (!IsWinoldapTask(GetTaskFromHwnd(hwndNext))) #endif HideWindow(hwnd); ActivateSelectedWindow(hwndLB); #ifdef NTWIN { DWORD idt; HANDLE hThread; hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CallEndTask, (LPVOID)hwndNext, 0, &idt); if (hThread == NULL) { /* * Can not create thread, just call EndTask * syncronously */ DoEndTask( hwndNext ); } else { CloseHandle(hThread); } } #else EndTask(hwndNext, FALSE, FALSE); #endif } break; case IDD_TILE: case IDD_CASCADE: { HWND hwndDesktop; HideWindow(hwnd); hwndDesktop = GetDesktopWindow(); if (wParam == IDD_CASCADE) { CascadeChildWindows(hwndDesktop, 0); } else { /* * If shift is down, tile vertically, else horizontally. */ TileChildWindows(hwndDesktop, ((GetKeyState(VK_SHIFT) & 0x8000) ? MDITILE_HORIZONTAL : MDITILE_VERTICAL)); } break; } case IDD_ARRANGEICONS: /* * Let's restore the saved bits before ArrangeIcons * FIX for Bug #4884; --SANKAR-- 10-02-89 */ HideWindow(hwnd); ArrangeIconicWindows(GetDesktopWindow()); break; } break; case WM_CLOSE: /* * If wParam != 0, this is a shutdown request, so exit. */ if (wParam != 0) ExitProcess(0); return FALSE; break; case WM_HOTKEY: if (wParam == 1) { pt.x = (dxScreen - dxTaskman) / 2; pt.y = (dyScreen - dyTaskman) / 2; ShowTasklist(pt); } break; case WM_LOGOFF: PostQuitMessage(0); break; default: return FALSE; } return TRUE; lParam; } //************************************************************* // // SetDefButton() // // Purpose: Sets the default button // // Parameters: HWND hDlg - Window handle of dialog box // INT idButton - ID of button // // Return: void // //************************************************************* VOID SetDefButton(HWND hwndDlg, INT idButton) { LRESULT lr; if (HIWORD(lr = SendMessage(hwndDlg, DM_GETDEFID, 0, 0)) == DC_HASDEFID) { HWND hwndOldDefButton = GetDlgItem(hwndDlg, LOWORD(lr)); SendMessage (hwndOldDefButton, BM_SETSTYLE, MAKEWPARAM(BS_PUSHBUTTON, 0), MAKELPARAM(TRUE, 0)); } SendMessage( hwndDlg, DM_SETDEFID, idButton, 0L ); SendMessage( GetDlgItem(hwndDlg, idButton), BM_SETSTYLE, MAKEWPARAM( BS_DEFPUSHBUTTON, 0 ), MAKELPARAM( TRUE, 0 )); } /*** SaveRecentFileList -- Save the list of recently used files * * void APIENTRY SaveRecentFileList (HWND hwnd, LPTSTR szCurrentFile); * * * * ENTRY - HWND hwnd - handle to dialog box. * LPTSTR szCurrentFile - pointer to selected filename * * EXIT - * SYNOPSIS - * * WARNINGS - * EFFECTS - * */ void APIENTRY SaveRecentFileList (HWND hwnd, LPTSTR szCurrentFile) { HKEY hKey; DWORD dwDisp; DWORD dwDataType, dwMaxFiles=INIT_MAX_FILES, dwMaxFilesSize, dwCount; TCHAR szFileEntry[20]; DWORD dwEnd=0; DWORD dwFileNum=0; DWORD dwDup; static TCHAR szRecentFilePath[MAXPATHFIELD+1]; // // Open registry key // if ( RegCreateKeyEx (HKEY_CURRENT_USER, FILES_KEY, 0, 0, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, &dwDisp) != ERROR_SUCCESS) { return; } // // Query the max number of files to save first. // dwMaxFilesSize = sizeof (DWORD); RegQueryValueEx (hKey, MAXFILES_ENTRY, NULL, &dwDataType, (LPBYTE)&dwMaxFiles, &dwMaxFilesSize); // // If the user request 0 entries, then exit now. // if (dwMaxFiles == 0) { RegCloseKey (hKey); return; } // // Find out how many items are in the list box. // dwEnd = (DWORD)SendDlgItemMessage (hwnd, IDD_PATH, CB_GETCOUNT, 0, 0); // // If the max number of items we want to save is less than the // number of entries, then change the ending point. // if (dwMaxFiles < dwEnd) { dwEnd = dwMaxFiles; } // // Add the first entry (the current file) // wsprintf (szFileEntry, FILE_ENTRY, dwFileNum++); dwMaxFilesSize = MAXPATHFIELD+1; RegSetValueEx (hKey, szFileEntry, 0, REG_SZ, (CONST BYTE *)szCurrentFile, sizeof (TCHAR) * (lstrlen (szCurrentFile)+1)); // // Check for a duplicate string. // dwDup = (DWORD)SendDlgItemMessage (hwnd, IDD_PATH, CB_FINDSTRING, (WPARAM) -1, (LPARAM) szCurrentFile); // // If we already have dwMaxFiles in the list and we don't have any // duplicates, then we only want to save dwMaxFiles - 1 entries // (drop the last entry). // // if ( (dwEnd == dwMaxFiles) && (dwDup == CB_ERR) ) { dwEnd--; } // // Now loop through the remaining entries // for (dwCount=0; dwCount < dwEnd; dwCount++) { // // Check to see if we are at the duplicate entry. If // so skip on to the next item. // if ((dwDup != CB_ERR) && (dwCount == dwDup)) { continue; } // // Get an entry out of the listbox. // SendDlgItemMessage (hwnd, IDD_PATH, CB_GETLBTEXT, (WPARAM) dwCount, (LPARAM) szRecentFilePath); // // If we get a NULL string, break out of the loop. // if (!(*szRecentFilePath) || !szRecentFilePath) { break; } // // Build the entry name // wsprintf (szFileEntry, FILE_ENTRY, dwFileNum); dwMaxFilesSize = MAXPATHFIELD+1; // // Save the entry // RegSetValueEx (hKey, szFileEntry, 0, REG_SZ,(CONST BYTE *) szRecentFilePath, sizeof (TCHAR) * (lstrlen (szRecentFilePath)+1)); // // Increment our current file number // dwFileNum++; } // // Close the key // RegCloseKey (hKey); } /*** Main -- Program entry point (was WinMain). * * * * Main(int argc, char *argv[], char *envp[]) * * ENTRY - int argc - argument count. * char *argv[] - argument list. * char *envp[] - environment. * * EXIT - TRUE if success, FALSE if not. * SYNOPSIS - Parses command line, for position to place dialog box, if no * position (came from ctl/esc) then center on screen. * Also make sure only one instance of taskman. * * WARNINGS - * EFFECTS - */ INT __cdecl main( INT argc, CHAR *argv[], CHAR *envp[]) { MSG msg; /* * First set the priority of taskman so it is higher than foreground apps * that spin in loops - this way it'll always come up when you hit * ctrl-esc. */ hInst = GetModuleHandle(NULL); SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); { // // Set the working set size to 200k. // QUOTA_LIMITS QuotaLimits; NTSTATUS status; status = NtQueryInformationProcess( NtCurrentProcess(), ProcessQuotaLimits, &QuotaLimits, sizeof(QUOTA_LIMITS), NULL ); if (NT_SUCCESS(status)) { QuotaLimits.MinimumWorkingSetSize = 300 * 1024; QuotaLimits.MaximumWorkingSetSize = 372 * 1024; NtSetInformationProcess( NtCurrentProcess(), ProcessQuotaLimits, &QuotaLimits, sizeof(QUOTA_LIMITS) ); } } /* * Taskman will work in the windows directory, and switch to the * original directory (home directory) before execing programs. * This is to prevent weird popups if a UNC original directory is * disconnected. */ GetCurrentDirectory(MAXPATHFIELD, szUserHomeDir); GetWindowsDirectory(szWindowsDirectory, MAXPATHFIELD); SetCurrentDirectory(szWindowsDirectory); fExecOK = OKToExec(); if (!IsUserAdmin() && !fExecOK) { ghwndDialog = CreateDialog(hInst, MAKEINTRESOURCE(WMPTASKMANDLG), NULL, TaskmanDlgProc); } else { ghwndDialog = CreateDialog(hInst, MAKEINTRESOURCE(PWRTASKMANDLG), NULL, TaskmanDlgProc); } if (ghwndDialog == NULL) return 0; LoadString(hInst, IDS_OOMEXITTITLE, szOOMExitTitle, 32); LoadString(hInst, IDS_OOMEXITMSG, szOOMExitMsg, 64); if (!RegisterHotKey(ghwndDialog, 1, MOD_CONTROL, VK_ESCAPE) || !RegisterTasklist(ghwndDialog)) { goto exit; } while (GetMessage(&msg, (HWND)NULL, (UINT)0, (UINT)0)) { if (!IsDialogMessage(ghwndDialog, &msg)) { if ((msg.message == WM_SYSCOMMAND) && (msg.wParam == SC_TASKLIST)) { POINT pt; GetCursorPos(&pt); pt.x = max(pt.x - (dyTaskman / 2), 0); pt.x = min(pt.x, dxScreen - dxTaskman); pt.y = max(pt.y - (GetSystemMetrics(SM_CYCAPTION) * 2), 0); pt.y = min(pt.y, dyScreen - dyTaskman); ShowTasklist(pt); } else { // // We need to have a regular message loop in order // to handle the DDE messages generated by spawning // an application via an association. // TranslateMessage (&msg); DispatchMessage (&msg); } } } exit: DestroyWindow(ghwndDialog); return 0; argc; argv; envp; } WORD APIENTRY ExecProgram( LPTSTR lpszPath, LPTSTR lpDir, LPTSTR lpTitle ) { WORD ret; HCURSOR hCursor; LPTSTR lpP; TCHAR cSeparator; TCHAR lpReservedFormat[] = TEXT("dde.%d,hotkey.%d"); TCHAR lpReserved[100]; // used for DDE request of icons from console apps // add for passing the hotkey associated with an item. HANDLE hProcess; ret = 0; /* * Set the current directory to the user's home directory if possible. */ SetCurrentDirectory(szUserHomeDir); hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); /* Don't mess with the mouse state; unless we're on a mouseless system. */ if (!GetSystemMetrics(SM_MOUSEPRESENT)) ShowCursor(TRUE); /* skip leading spaces */ while (*lpszPath == TEXT(' ')) lpszPath++; /* skip past path */ lpP = lpszPath; if (*lpszPath == TEXT('"')) { cSeparator = TEXT('"'); lpP++; } else { cSeparator = TEXT(' '); } for (; *lpP && *lpP != cSeparator; lpP = CharNext(lpP)) ; if (*lpP == TEXT('"')) { lpP++; } /* if stuff on end, separate it */ if (*lpP) *lpP++ = 0; /* Try to exec 'szCommandLine'. */ /*changed order, since wPendINstance is a 32b HANDLE, and ret is WORD*/ if (!lpP) lpP = TEXT(""); wsprintf(lpReserved, lpReservedFormat, 0, 0); ret = (WORD)RealShellExecute(ghwndDialog, NULL, lpszPath, lpP, lpDir, NULL, lpTitle, lpReserved, (WORD)SW_SHOWNORMAL, &hProcess); /*BUG BUG these are DOS exec function return codes, no map yet to NT return codes!*/ switch (ret) { case 0: case SE_ERR_OOM: // 8 ret = IDS_NOMEMORYMSG; break; case SE_ERR_FNF: // 2 ret = IDS_FILENOTFOUNDMSG; break; case SE_ERR_PNF: // 3 ret = IDS_BADPATHMSG; break; case 4: ret = IDS_MANYOPENFILESMSG; break; case 5: ret = IDS_ACCESSDENIED; break; case 10: ret = IDS_NEWWINDOWSMSG; break; case 12: ret = IDS_OS2APPMSG; break; case 15: /* KERNEL has already put up a messagebox for this one. */ ret = 0; break; case 16: ret = IDS_MULTIPLEDSMSG; break; case 18: ret = IDS_PMODEONLYMSG; break; case 19: ret = IDS_COMPRESSEDEXE; break; case 20: ret = IDS_INVALIDDLL; break; case SE_ERR_SHARE: ret = IDS_SHAREERROR; break; case SE_ERR_ASSOCINCOMPLETE: ret = IDS_ASSOCINCOMPLETE; break; case SE_ERR_DDETIMEOUT: case SE_ERR_DDEFAIL: case SE_ERR_DDEBUSY: ret = IDS_DDEFAIL; break; case SE_ERR_NOASSOC: ret = IDS_NOASSOCMSG; break; default: ret = 0; break; } if (!GetSystemMetrics(SM_MOUSEPRESENT)) { /* * We want to turn the mouse off here on mouseless systems, but * the mouse will already have been turned off by USER if the * app has GP'd so make sure everything's kosher. */ if (ShowCursor(FALSE) != -1) ShowCursor(TRUE); } SetCursor(hCursor); /* * Reset the working directory to the windows directory. */ SetCurrentDirectory(szWindowsDirectory); return(ret); } VOID GetDirectoryFromPath( PTSTR szFilePath, PTSTR szDir) { PTSTR pFileName; PTSTR pExt; WORD ich; BOOL fUnc; *szDir = TEXT('\0'); /* Get info about file path. */ GetPathInfo(szFilePath, &pFileName, &pExt, &ich, &fUnc); /* UNC paths don't (conceptually to Progman) have a directory component. */ if (fUnc) return; /* Does it have a directory component ? */ if (pFileName != szFilePath) { // Yep. /* copy path to temp. */ if (*szFilePath == TEXT('"')) { szFilePath++; } lstrcpy(szDir, szFilePath); /* check path style. */ if (ich <= 3 && *(szDir+1) == TEXT(':')) { /* * The path is "c:\foo.c" or "c:foo.c" style. * Don't remove the last slash/colon, just the filename. */ szDir[pFileName-szFilePath] = TEXT('\0'); } else if (ich == 1) { /* * something like "\foo.c" * Don't remove the last slash/colon, just the filename. */ szDir[pFileName-szFilePath] = TEXT('\0'); } else { /* * The filepath is a full normal path. * Could be something like "..\foo.c" or ".\foo.c" though. * Stomp on the last slash to get just the path. */ szDir[pFileName-szFilePath-1] = TEXT('\0'); } } /* else just a filename with no path. */ } VOID GetFilenameFromPath( PTSTR szPath, PTSTR szFilename) { DWORD dummy; PTSTR pFileName; BOOL fUNC; GetPathInfo(szPath, &pFileName, (PTSTR*) &dummy, (WORD*) &dummy, &fUNC); /* If it's a UNC then the 'filename' part is the whole thing. */ if (fUNC || (szPath == pFileName)) lstrcpy(szFilename, szPath); else { if (*szPath == TEXT('"')) { *szFilename++ = TEXT('"'); } lstrcpy(szFilename, pFileName); } } VOID GetPathInfo( PTSTR szPath, PTSTR *pszFileName, PTSTR *pszExt, WORD *pich, BOOL *pfUnc) { TCHAR *pch; // Temp variable. WORD ich = 0; // Temp. BOOL InQuotes; *pszExt = NULL; // If no extension, return NULL. *pszFileName = szPath; // If no seperate filename component, return path. *pich = 0; *pfUnc = FALSE; // Default to not UNC style. // // Check if path is in quotes. // if (InQuotes = (*szPath == TEXT('"'))) { szPath++; } // Check for UNC style paths. if (*szPath == TEXT('\\') && *(szPath+1) == TEXT('\\')) *pfUnc = TRUE; // Search forward to find the last backslash or colon in the path. // While we're at it, look for the last dot. for (pch = szPath; *pch; pch = CharNext(pch)) { if ((*pch == TEXT(' ')) && (!InQuotes)) { // Found a space - stop here. break; } if (*pch == TEXT('"')) { // Found a the second quote - stop here. pch++; break; } if (*pch == TEXT('\\') || *pch == TEXT(':')) { // Found it, record ptr to it and it's index. *pszFileName = pch+1; *pich = ich + (WORD)1; } if (*pch == TEXT('.')) { // Found a dot. *pszExt = pch; } ich++; } /* Check that the last dot is part of the last filename. */ if (*pszExt < *pszFileName) *pszExt = NULL; } BOOL IsUserAdmin() { BOOL UserIsAdmin = FALSE; HANDLE Token; PSID AdminAliasSid = NULL; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; // // Get the token of the current process. // if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &Token) ) { return(FALSE); } UserIsAdmin = TestTokenForAdmin(Token); CloseHandle(Token); return(UserIsAdmin); } BOOL TestTokenForAdmin( HANDLE Token ) { NTSTATUS Status; DWORD InfoLength; PTOKEN_GROUPS TokenGroupList; DWORD GroupIndex; PSID AdminSid; BOOL FoundAdmin; SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY; // // Get a list of groups in the token // Status = NtQueryInformationToken( Token, // Handle TokenGroups, // TokenInformationClass NULL, // TokenInformation 0, // TokenInformationLength &InfoLength // ReturnLength ); if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL)) { return(FALSE); } TokenGroupList = Alloc(InfoLength); if (TokenGroupList == NULL) { return(FALSE); } Status = NtQueryInformationToken( Token, // Handle TokenGroups, // TokenInformationClass TokenGroupList, // TokenInformation InfoLength, // TokenInformationLength &InfoLength // ReturnLength ); if (!NT_SUCCESS(Status)) { LocalFree(TokenGroupList); return(FALSE); } // // Create the admin sid // Status = RtlAllocateAndInitializeSid( &SystemSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdminSid); if (!NT_SUCCESS(Status)) { Free(TokenGroupList); return(FALSE); } // // Search group list for admin alias // FoundAdmin = FALSE; for (GroupIndex=0; GroupIndex < TokenGroupList->GroupCount; GroupIndex++ ) { if (RtlEqualSid(TokenGroupList->Groups[GroupIndex].Sid, AdminSid)) { FoundAdmin = TRUE; break; } } // // Tidy up // RtlFreeSid(AdminSid); Free(TokenGroupList); return(FoundAdmin); } BOOL OKToExec() { TCHAR szRestrict[] = TEXT("Restrictions"); TCHAR szProgramManager[] = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Program Manager"); HKEY hkeyProgramManager = NULL; // progman.ini key HKEY hkeyPMRestrict = NULL; DWORD cbData, dwType; BOOL fNoRun = FALSE; /* * Create/Open the registry keys corresponding to progman.ini sections. */ if (!RegCreateKeyEx(HKEY_CURRENT_USER, szProgramManager, 0, szProgramManager, 0, KEY_READ | KEY_WRITE, NULL, &hkeyProgramManager, NULL)) { RegCreateKeyEx(hkeyProgramManager, szRestrict, 0, szProgramManager, 0, KEY_READ, NULL, &hkeyPMRestrict, NULL); } else { return(FALSE); } if (hkeyPMRestrict) { cbData = sizeof(fNoRun); RegQueryValueEx(hkeyPMRestrict, szNoRun, 0, &dwType, (LPBYTE)&fNoRun, &cbData); } if (hkeyPMRestrict) { RegCloseKey(hkeyPMRestrict); hkeyPMRestrict = NULL; } RegCloseKey(hkeyProgramManager); return(!fNoRun); } INT MyMessageBox( HWND hWnd, WORD idTitle, WORD idMessage, PWSTR psz, WORD wStyle) { WCHAR szTempField[MAXMSGBOXLEN]; INT iMsgResult; if (!LoadString(hInst, idTitle, szTitle, ARRAYSIZE(szTitle))){ goto MessageBoxOOM; } if (idMessage < 32){ if (!LoadString(hInst, IDS_UNKNOWNMSG, szTempField, ARRAYSIZE(szTempField))){ goto MessageBoxOOM; } wsprintf(szMessage, szTempField, idMessage); } else{ if (!LoadString(hInst, idMessage, szTempField, ARRAYSIZE(szTempField))) goto MessageBoxOOM; if (psz) { wsprintf(szMessage, szTempField, (LPTSTR)psz); } else lstrcpy(szMessage, szTempField); } iMsgResult = MessageBox(hWnd, szMessage, szTitle, wStyle ); if (iMsgResult == -1){ MessageBoxOOM: MessageBox(hWnd, szOOMExitMsg, szOOMExitTitle, MB_SYSTEMMODAL | MB_ICONHAND | MB_OK); } return(iMsgResult); }