Unified Diff

Remove Tabs From the Windows Taskbar

by Bob on 6 June 2009, under COM, Hacks, Win32 & MFC, Windows

I’m very picky about my desktop environment. I like windows, toolbars, icons, etc. to be arranged in a certain way. Typically, I turn off annoying prompts and nag screens in Windows, and unhide “scary” advanced options in OS X. One hard-to-fix pet peeve is when applications put an icon in the notification area (near the clock) AND leave a tab in the taskbar. This wastes valuable taskbar real estate.

I use Spark on my workstation to connect to the company’s internal IM server. The application works alright, but the contacts window always appears in the taskbar. So I started to think about ways I could programmatically solve my problem.

I could set the WS_EX_TOOLWINDOW style on the window, but that would alter the window’s appearance. What I really wanted was a way to tell Windows to remove the tab. A quick search on Google turned up the answer: use COM to create an instance of ITaskbarList. The interface has the function ITaskbarList::DeleteTab() which takes a window handle. Perfect!

Now I just needed to get the window’s handle. FindWindow() would have worked, but that meant hard-coding my username into the program. I felt a more elegant solution was to enumerate all of the windows, and look for the one with the right class and title prefix.

Since the tab would reappear every time I brought the contact list window to the foreground, I ended up wrapping my fix with a loop and a timer. Here’s the finished product:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/* NoSpark.cpp - Hides the Spark contacts window tab in the taskbar */
 
#include <windows.h>
#include <Shobjidl.h>
 
BOOL CALLBACK EnumWindowsProc(HWND, LPARAM);
 
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow )
{
	HANDLE htmr = CreateWaitableTimer(NULL, TRUE, L"CheckSpark");
	LARGE_INTEGER lidt;
	ITaskbarList* ptl;
 
	__int64 qwdt = -60 * 10000000; // 1 minute
	lidt.LowPart = (DWORD) (qwdt & 0xFFFFFFFF);
	lidt.HighPart = (LONG) (qwdt >> 32);
 
	while( TRUE ) {
		SetWaitableTimer(htmr, &lidt, 0, NULL, NULL, FALSE);
		WaitForSingleObject(htmr, INFINITE);
 
		HWND hsparkwnd = 0;
		EnumWindows(&EnumWindowsProc, (LPARAM) &hsparkwnd);
		if( hsparkwnd == 0 ) continue;
 
		CoInitialize(NULL);
		HRESULT ret = CoCreateInstance(
			CLSID_TaskbarList, 
			NULL, 
			CLSCTX_SERVER, 
			IID_ITaskbarList, 
			(LPVOID*) &ptl
		);
 
		if( ret == S_OK )
			ptl->DeleteTab(hsparkwnd);
 
		ptl->Release();
		CoUninitialize();
	}
 
	return 0;
}
 
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
	int tmpsz = 16;
	LPWSTR lptmp = (LPWSTR) malloc(sizeof(WCHAR) * tmpsz);
 
	RtlZeroMemory(lptmp, tmpsz);
	GetClassName(hwnd, lptmp, tmpsz);
 
	if( wcscmp(lptmp, L"SunAwtFrame") != 0 ) {
		free(lptmp);
		return TRUE;
	}
 
	RtlZeroMemory(lptmp, tmpsz);
	GetWindowText(hwnd, lptmp, tmpsz);
 
	if( wcscmp(lptmp, L"Spark -") > 0 ) {
		*((HWND*) lParam) = hwnd;
		free(lptmp);
		return FALSE;
	}
 
	free(lptmp);
	return TRUE;
}

To compile this program, create a new, empty Visual C++ project. Create a new cpp file and drop the code above inside. If you get compile errors about converting wchar_t* to const char* then change your character set from Multibyte to Unicode in the project properties.


Leave a Reply

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!