我想做一個類似 OSD (on screen display) 的顯示,但我想採用的是『隱藏Windows任務欄中的應用程式』。
以下從網站找到的資料,但 LV 要如何才能實現呢?(不只是在 ini 裡寫入 HideRootWindow = True 而已):
-----------------------以下是找到的程式語言資料,如何才能用 LV 實現?--------------
關於隱藏Windows任務欄中的應用程式按鈕的幾種方法的介紹<?:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
一、問題的提出
首先,在Windows下編程的程式師都知道,當一個應用程式被創建後就會在Windows任務欄(Taskbar)中加入一個應用程式的按鈕,在Windows任務列表(即按Ctrl+Alt+Del後出現的列表)中加入應用程式的標題,Windows還會將應用程式的資訊加入按Alt+Tab後的列表中。這些資訊對於Windows的操作用戶是相當有用的,用戶可以通過滑鼠和鍵盤在各個應用程式間切換,對高級用戶還可以通過按Ctrl+Alt+Del來終止某一個應用程式。但是,在程式師設計程式時有時希望能創建一個在任務欄中(基至於在任務列表和按Alt+Tal後的列表中)沒有關於程式資訊的應用程式。筆者在工作中就遇到了這需求,以下是解決這一問題的方法的總結。
二、隱藏任務欄中的應用程式按鈕的第一種的方法
因該說這種方法是目前為止筆者找得到比較正式的解決方法,這一方法在MSDN中有比較詳盡的文檔,。讀者可以在MSDN中通過「索引」關鍵字「Talkbar」得到以下以下的條目:Modifying the Contents of the Taskbar。以下是該條目的中文譯文:
Microsoft Internet Explorer 4.0增加了改變任務欄中的內容的能力。你可以在一個應用程式中「添加」、「刪除」和「啟動」任務欄中的一個按鈕。「啟動」一個按鈕可以不同時啟動相應的視窗;它只是簡單地使按鈕「按下」。
任務欄的被改變是的執行者是一個OLE COM物件。這個物件通過使用CLSID_TaskbarList參數調用CoCreateInstance()來建立。你需要的這個介面物件是IDD_ITaskbarList。這將建立一個物件並且返回給你一個ITaskbarList介面指標。你必須調用ITaskbarList::HrInit方法來初始化這個物件。如果HrInit()方法調用成功,你將能使用ITaskbarList介面中的方法來改變任務欄中的內容。
我們按照MSDN文檔中提供的這個方法來「刪除」任務欄中的應用程式按鈕。
首先,我們必須聲明一個ITaskbarList對像:
DECLARE_INTERFACE_(ITaskbarList, IUnknown)
{
STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;
STDMETHOD(ActivateTab)(HWND) PURE;
STDMETHOD(AddTab)(HWND) PURE;
STDMETHOD(DeleteTab)(HWND) PURE;
STDMETHOD(HrInit)(HWND) PURE;
};
typedef ITaskbarList *LPITaskbarList;
然後,你需要去掉應用程式在任務欄中的按鈕的地方加入以下代碼:
LPITaskbarList pTaskbar = NULL;
CoInitialize(0);
CoCreateInstance(CLSID_TaskbarList,0,CLSCTX_INPROC_SERVER,IID_ITaskbarList,(void **)&pTaskbar);
pTaskbar->HrInit(hWnd); //hWnd為應用程式主視窗的控制碼
pTaskbar->DeleteTab(hWnd); //hWnd為應用程式主視窗的控制碼
如果你想在程式運行後立即去掉按鈕,在MFC類應用程式中可將以上代碼加入應用程式主視窗的OnPaint()方法中;在SDK應用程式中可將以上代碼加入WinMain()函數的消息迴圈前。應該說用Microsoft官方提供的這個方法是能夠正常工作的,但這一方法有一個很大的缺陷,那就是當應用程式的視窗被任務欄的任何一部分(包括開始功能表)遮住後,再啟動應用程式時按鈕就又出現了。這也是為什麼在MFC應用程式中要將DeleteTab(hWnd)放在OnPaint()方法中的原因,如果放在OnCreate()方法中的話雖然在OnCreate()時按鈕被去掉了,但在OnCreate()以後的運行過程中按鈕又出現了。Microsoft還提供了一種去掉任務欄上的應用程式按鈕的方法,這就是將要介紹的第二種方法。
三、隱藏任務欄中的應用程式按鈕的第二種的方法
使用CreateEx()方法創建視窗時可以設定視窗的擴展屬性,在MSDN中對這一屬性的解釋是:
「創建一個工具視窗,它將被有意地創建為浮動工具條的式樣。一個工具視窗的標題欄比一般視窗的標題欄窄,並且標題欄上將使用小一號的字體。工具視窗將不出現在任務欄上,並且將不出現在按ALT+TAB這後。」
按照以上原理我們可以很方便地創建一個所謂的工具視窗,使用MFC時只須在應用程式主視窗的PreCreateWindow()方法中加入以下代碼:
cs.dwExStyle |= WS_EX_TOOLWINDOW;
使用SDK時只須在創建主視窗時使用CreateEx()方法並在擴展屬性中加入WS_EX_TOOLWINDOW即可。
於第一種方法相比,這一種方法的實現是相當簡單的,而且沒有第一種方法中的缺陷。但是,這一方法仍有一些不足之處,首先,因為是視窗是工具視窗窄窄的標題欄看上去不是很好;其次,當使用MFC的基於對話方塊的程式時簡單地將主對話方塊設為Tool window並不能實現工具視窗。
四、隱藏任務欄中的應用程式按鈕的第三種的方法
在介紹第三種方法這前我們先來分析一下什麼樣的應用程式會在任務欄中出現按鈕,根據MSDN的文檔當一具應用程式具有以下幾個特點:
1、它是不屬於系統的視窗,即所謂的owned window;
2、它是應用程式的主視窗;
3、視窗是非隱藏視窗,未使用ShowWindow(WS_HIDE)功能。
凡是有以上三點特徵的應用程式都將在任務欄中出現一按鈕,既然如此,那麼我們是不是可能通過首先創建一個工具視窗然後再創建自己要使用的視窗呢。筆者為此那立了一個基於對話方塊的MFC工程(工程名為Test),在InitInstance()方法中作如下修改:
CFrameWnd* pFrame = new CFrameWnd;
m_pMainWnd = pFrame;
pFrame->Create(NULL,_T("")); //創建一新的框架並將主框架指向這個框架
CTestDlg dlg;
// m_pMainWnd = &dlg; //刪除將主框架指向主對話方塊的語句
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{}
else if (nResponse == IDCANCEL)
{}
return FALSE;
運行這個程式時在任務欄中應用程式的按鈕是沒有了,但在按Alt+Tab後仍有一個代表該程式的圖示。因此再作改進,將m_pMainWnd的父視窗也隱藏掉,程式改為:
LPCTSTR TestClass = AfxRegisterWndClass(0);
CWnd wndTest;
wndTest.CreateEx(WS_EX_TOOLWINDOW, TestClass, "", WS_OVERLAPPED,
0,0,0,0,NULL, 0); //創建一個工具視窗作為主框架的父視窗
CFrameWnd* pFrame = new CFrameWnd;
m_pMainWnd = pFrame; //將主框架指向自己定義的框架
//創建主框架
pFrame->Create(NULL,_T(""),WS_OVERLAPPED,CRect(0,0,0,0),&wndTest);
CTestDlg dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{}
else if (nResponse == IDCANCEL)
{}
return FALSE;
這樣創建後的應用程式在任務欄中沒有按鈕和在按Alt+Tab後也不會出現在其中。如果要創建基於其他類型的MFC程式可在主框架的PreCreateWindow()方法中換掉主框架的父視窗。
五、隱藏任務欄中的應用程式按鈕的第四種的方法
這一種方法比較複雜,考慮到使用「鉤子」可以改變消息的流向,因此,我想可以通過截獲系統發給任務欄的消息來阻止應用程式的按鈕在任務欄中出現。因為這一方法實現比較複雜,而上面已經有了很簡潔的方法,筆者並未對方法作進一步的研究。有興趣的讀者可以自己試試。
六、去掉應用程式在任務列表中的顯示
大家都知道在按下Ctrl+Alt+Tal後系統會列出正在運行的程式的列表,所以即使我們作了努力隱藏了程式在任務欄上的按鈕,用戶還是可以輕而易舉的終止我們的程式。以下筆者提供了去掉應用程式在任務列表中的方法:
typedef DWORD (WINAPI Fun)(DWORD,DWORD);
HINSTANCE hKDLL = ::AfxLoadLibrary("KERNEL32.DLL");// 裝入KERNEL32動態庫
// 取得服務介面
Fun* pFun = (Fun*)::GetProcAddress(hKDLL,"RegisterServiceProcess");
(*pFun)(NULL,1); //去掉任務列表中程式的標題
AfxFreeLibrary(hKDLL); // 釋放KERNEL32.DLL
七、總結
通過以上的介紹讀者可以創建一個使用普通用戶無法輕易關閉的應用程式,希望對讀者能有所幫助。但對於高級用戶來說仍是能夠偵測到該應用程式的存在,使用Visual Studio中的工具Process Viewer即可做到。