天天看點

【WM】如何判斷程序能否被終止(freeable)

我們在編寫程式時,可能會碰到類似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);

}

...

}

繼續閱讀