📄 alttab.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*---------------------------------------------------------------------------*\
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
*
*
* file: ALTTAB.CPP
* purpose: Implement Sample shell Task-manager-like dialog
*
\*---------------------------------------------------------------------------*/
#include "windows.h"
#include "windowsx.h"
#include <sipapi.h>
#include "minshell.h"
#include "minshrc.h"
#include "commdlg.h"
// Useful macros
#define cchsizeof(x) (sizeof(x)/sizeof(TCHAR))
#define RestoreForegroundWindow(hwnd) \
SetForegroundWindow((HWND)(((DWORD)hwnd) | 0x01))
// info passed to TaskMan_ReallyKill
typedef struct
{
HWND hwnd;
LPTSTR pszTitle;
}
KILLTARGETINFO;
// Local fns
int TaskMan_PopulateLB(HWND hwndLB, HWND hwndFG);
LRESULT CALLBACK TaskMan_ReallyKill(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
LRESULT CALLBACK RunDlgProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
BOOL IsOKToKill(HWND hwndApp);
// We dynamically determine whether the current OS configuration has the
// Fileopen component, by calling LoadLibrary & GetProcAddress. If we obtain
// the GetOpenFilename API then we display a Browse button on the Start-Run
// dialog. Otherwise we hide it.
typedef BOOL (APIENTRY* PFNGETOPENFILENAME)(LPOPENFILENAME lpofn);
PFNGETOPENFILENAME g_pfnGetOpenFileName;
//
// This is the dlgproc for the Takman dialog. The dialog has a listbox of all
// top-level windows, and Switch-To and End-Task buttons, which allow the user
// to switch between apps or terminate hung apps.
// The dialog also has a Run button that brings up Start-Run type dialog, and
// of course a Cancel button
//
// NOTE: The dialog is actually a permanent modeless dialog created on shell
// startup. Pressing ALt-Tab merely brings it to the front, and Cancel hides
// it, rather than actually destroying the dialog
//
int CALLBACK TaskMan_DlgProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
int iIndex, iCount;
HWND hwndLB = GetDlgItem(hwnd, IDC_LISTBOX);
HWND hwndFG;
DEBUGMSG(ZONE_TRACEMSGHF, (TEXT("AltTab Window Msg=%x wp=%x lp=%x\r\n"), msg, wp, lp));
switch(msg)
{
// created on program startup
case WM_INITDIALOG:
break;
// activated on user pressing Alt-Tab etc (see MINTASK.CPP)
case WM_ACTIVATE:
if(LOWORD(wp) != WA_INACTIVE)
{
CenterWindowSIPAware(hwnd, TRUE);
// We use DWL_USER tp remember the window that was foreground *before*
// this dialog came up, so that we can select it in our listbox
hwndFG = (HWND)GetWindowLong(hwnd, DWL_USER);
// Fill listbox with currently running top-level windows
iCount = TaskMan_PopulateLB(hwndLB, hwndFG);
// enable or disable SwitchTo & EndTask buttons, based on lisbox item count
EnableWindow(GetDlgItem(hwnd, IDC_ENDTASK), iCount);
EnableWindow(GetDlgItem(hwnd, IDOK), iCount);
SendMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)hwndLB, (LPARAM)TRUE);
}
break;
case WM_SETTINGCHANGE:
// Recenter dialog when SIP goes up (see details in the block
// comment at the head of the CenterWindowSIPAware function)
if(wp==SPI_SETSIPINFO)
CenterWindowSIPAware(hwnd, FALSE);
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wp,lp))
{
// Bring up a Start-Run type dialog
case IDC_RUN:
{
// Choose the dialog template based on screen-dimensions. See details in RC file
int idd = (GetSystemMetrics(SM_CXSCREEN) < GetSystemMetrics(SM_CYSCREEN))
? IDD_RUN_G : IDD_RUN;
if(-1 != DialogBox(g_hInst, MAKEINTRESOURCE(idd), hwnd, (DLGPROC)RunDlgProc))
{
// If user didnt cancel out of Run dialog, dismiss (hide) the Taskman dlg
ListBox_ResetContent(hwndLB);
ShowWindow(hwnd, SW_HIDE);
}
break;
}
// Try to terminate the task. First nicely (by sending WM_CLOSE), then
// if it doesn't respond, use TerminateProcess
case IDC_ENDTASK:
{
KILLTARGETINFO killinfo;
DECLAREWAITCURSOR;
if((iIndex = ListBox_GetCurSel(hwndLB)) != LB_ERR)
{
SetWaitCursor();
killinfo.hwnd = (HWND)ListBox_GetItemData(hwndLB, iIndex);
// post Close message whether window is enabled or not
// If it has child popups active it stil needs to be closed
PostMessage(killinfo.hwnd, WM_CLOSE, 0, 0);
// Wait for app to actually close
for(int i=0;IsWindow(killinfo.hwnd) && i<3;i++)
Sleep(1700); // sleep min 1.7s, max 5.1sec
// If app is still around prompt for TerminateProcess
// IMPORTANT: First check if it is not a system process
if (IsWindow(killinfo.hwnd) && IsOKToKill(killinfo.hwnd))
{
int iLen = ListBox_GetTextLen(hwndLB, iIndex);
// set up a killinfo struct with the HWND & title of the window
// and pass it into the ReallyKill dialog.
if(iLen && (killinfo.pszTitle=(LPTSTR)_alloca((iLen+1)*sizeof(WCHAR))))
{
int idd;
killinfo.pszTitle[0]=0;
ListBox_GetText(hwndLB, iIndex, killinfo.pszTitle);
ResetWaitCursor();
// Choose the dialog template based on screen-dimensions. See details in RC file
idd = (GetSystemMetrics(SM_CXSCREEN) < GetSystemMetrics(SM_CYSCREEN))
? IDD_REALLYKILL_G : IDD_REALLYKILL;
DialogBoxParam(g_hInst, MAKEINTRESOURCE(idd), hwnd,
(DLGPROC)TaskMan_ReallyKill, (LPARAM)(&killinfo));
// we're done -- hide the Taskman dialog
ListBox_ResetContent(hwndLB);
ShowWindow(hwnd, SW_HIDE);
break;
}
}
// We could not terminate it. But we're done anyway.
// Hide the Taskman dialog
ListBox_ResetContent(hwndLB);
ResetWaitCursor(); // this must come *before* SW_HIDE
ShowWindow(hwnd, SW_HIDE);
}
break;
}
case IDC_LISTBOX:
// double-click in listbox is takedn to be a "switch-to" & falls through to IDOK
if(HIWORD(wp) != LBN_DBLCLK)
break;
// else fall through
case IDOK:
// User pressed "Switch To"
if((iIndex = ListBox_GetCurSel(hwndLB)) != LB_ERR)
{
RestoreForegroundWindow((HWND)ListBox_GetItemData(hwndLB, iIndex));
ShowWindow(hwnd, SW_HIDE);
ListBox_ResetContent(hwndLB);
}
break;
// User pressed "Cancel"
case IDCANCEL:
ShowWindow(hwnd, SW_HIDE);
ListBox_ResetContent(hwndLB);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
// If the user manages to terminate one of these system processes, the system will
// crash, so disallow it. This situation can happen if, say, a device driver
// in device.exe puts up a dialog box & the user tries to terminate it
//
// Forbidden processes list. Must be all lower-case
LPTSTR rgVerboten[] = { L"device.exe", L"gwes.exe", L"nk.exe", L"filesys.exe", 0 };
// Check if a window belongs to a system process
BOOL IsOKToKill(HWND hwndApp)
{
HANDLE hProc;
WCHAR wszBuf[MAX_PATH];
int i;
DWORD dwProcessId;
// Get the window's owning process
GetWindowThreadProcessId(hwndApp, &dwProcessId);
// Open the process
hProc = OpenProcess(PROCESS_ALL_ACCESS,0,dwProcessId);
wszBuf[0] = 0;
// Get it's filename
GetModuleFileName((HINSTANCE)hProc, wszBuf, MAX_PATH);
CloseHandle(hProc);
// lowercase the filename so substring match will suceed
wcslwr(wszBuf);
DEBUGMSG(1, (L"Trying to kill process %s\r\n", wszBuf));
// Check if the process is in the Forbidden list
for(i=0; rgVerboten[i]; i++)
{
// Note: we use a substring match so path effects are eliminated
if(wcsstr(wszBuf, rgVerboten[i]))
{
RETAILMSG(1, (L"It is VERBOTEN to kill process %s\r\n", wszBuf));
return FALSE;
}
}
return TRUE;
}
//
// Walk the list of top-level windows & populate the Taskman listbox
//
int TaskMan_PopulateLB(HWND hwndLB, HWND hwndFG)
{
int iIndex, iCount;
HWND hwndApp;
DEBUGMSG(ZONE_TRACETASKMAN, (L"TaskMan: Populate: hwndFG=%x hwndTaskbar=%x hwndDesktop=%x\r\n", hwndFG, g_hwndTaskBar, g_hwndDesktop));
ListBox_ResetContent(hwndLB);
// Iterate through all windows. Ignore all non-top-level windows
// Also ignore taskbar & desktop. Normally we would ignore top-level popup/dialogs BUT
// since we're a minshell here & there's no other way to get to things such as RNAAPP
// we allow these to stay on the list.
for(iCount=0, hwndApp=GetWindow(g_hwndTaskBar, GW_HWNDLAST); hwndApp; hwndApp = GetWindow(hwndApp, GW_HWNDPREV))
{
if (IsWindowVisible(hwndApp) &&
(hwndApp != g_hwndTaskBar) &&
(hwndApp != g_hwndDesktop) &&
(hwndApp != g_hwndTaskMan) &&
!GetWindow(hwndApp, GW_OWNER) /*&&
!(GetWindowLong(hwndApp, GWL_STYLE) & WS_POPUP)*/)
{
WCHAR wszBuf[MAX_PATH];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -