摘 要:本文介绍了笔者在实践中得到的几种隐藏任务栏中的应用程序按钮的方法,并逐一对其中的每一种方法进行详细的分析,指出每一种方法的优缺点。本文将提供各方法的 主要源程序段。
关键词:Windows任务栏,Windows任务列表,COM
一、问题的提出
首先,在Windows下编程的程序员都知道,当一个应用程序被创建后就会在Windows任务栏中加入一个应用程序的按钮,在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即可做到。
|