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.