Remove Tabs From the Windows Taskbar

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:

/* 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.