我們在編寫程式時,可能會碰到類似Task Killer方面的需求,要求我們在裝置資源不足的情況下,終止部分不重要或資源占用較多的程序。但在Windows Mobile 6.1及後續版本上有數個程序是不允許被終止的,一旦某個程序被終止通常會導緻OS不穩定或某些重要功能喪失。目前為止,共有7個程序,分别是:nk.exe、filesys.exe、device.exe、gwes.exe、services.exe、shell32.exe和connmgr.exe等。
大多數開發者會根據經驗确定哪些程序不能被終止,并維護一個程序清單供每次終止程序時核對。但這樣一來,帶來了不确定性:其一,開發者如何知道有幾個、分别是哪幾個程序不可終止;其二,微軟是否會在以後加入更多的不可終止程序(Windows Phone 7都釋出了,估計微軟沒啥精力去加了)。
這裡,筆者向大家介紹一個Win32 API函數判斷程序能否被終止,把所有的煩惱扔給微軟:
BOOL WINAPI SHIsAppFreeable(HWND hwnd);
其中,hwnd是應用程式的主視窗。通過判斷傳回值,我們可以獲知給定的應用程式能否被終止。
使用時請連結導入庫aygshell.lib。
為加深大家的了解,筆者根據反彙編所得,重新用C/C++還原了SHIsAppFreeable函數:
BOOL SHIsAppFreeable(HWND hwnd)
{
return SHSendShellMessage(WM_USER + 142, 0, hwnd, TRUE);
}
實作很簡單,隻是向HHTaskBar發送了一個消息。然後由shell32!HHTaskBarWndProc處理這個消息,直接調用shell32!IsFreeableAppWindow函數并将結果傳回給調用者:
struct NONFREEABLEAPPS
{
LPCTSTR pszAppName;
DWORD dwPID;
};
struct NONFREEABLEAPPS g_rgNonFreeableApps[] = {
{ TEXT("nk.exe"), 0 },
{ TEXT("filesys.exe"), 0 },
{ TEXT("device.exe"), 0 },
{ TEXT("gwes.exe"), 0 },
{ TEXT("services.exe"), 0 },
{ TEXT("shell32.exe"), 0 },
{ TEXT("connmgr.exe"), 0 }
};
DWORD g_dwNonFreeableAppCount = ARRAYSIZE(g_rgNonFreeableApps);
BOOL IsFreeableAppWindow(HWND hwndApp)
{
TCHAR szClass[64] = {0};
if (!GetClassName(hwndApp, szClass, 64))
{
szClass[0] = NULL;
}
if (!SHSameWindowProcesses(hwndApp, g_hwndDesktop))
{
if (!IsPhoneAppWindow(hwndApp, szClass))
{
return IsFreeableAppProcess(GetAppPID(hwndApp));
}
}
return FALSE;
}
DWORD GetAppPID(HWND hwndApp)
{
DWORD dwAppPID = 0;
if (hwndApp)
{
GetWindowThreadProcessId(hwndApp, &dwAppPID);
}
return dwAppPID;
}
BOOL IsFreeableAppProcess(DWORD dwAppPID)
{
for (DWORD i = 0; i < g_dwNonFreeableAppCount; i ++)
{
if (g_rgNonFreeableApps[i].dwPID == dwAppPID)
{
return FALSE;
}
}
return TRUE;
}
IsFreeableAppProcess函數最終用到了g_rgNonFreeableApps數組。該數組由GetNonFreeableProcessIDs函數生成:
VOID GetNonFreeableProcessIDs()
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0);
if (hSnapshot != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) };
if (Process32First(hSnapshot, &pe32))
{
do
{
LPTSTR lpszFileName = PathFindFileName(pe32.szExeFile);
if (!lpszFileName || !g_dwNonFreeableAppCount)
{
for (int i = 0; i < g_dwNonFreeableAppCount; i ++)
{
if (!g_rgNonFreeableApps[i].dwPID)
{
if (!lstrcmpi(lpszFileName, g_rgNonFreeableApps[i].pszAppName))
{
g_rgNonFreeableApps[i].dwPID = pe32.th32ProcessID;
break;
}
}
}
}
}
while (Process32Next(hSnapshot, &pe32));
}
CloseToolhelp32Snapshot(hSnapshot);
}
...
}