How to have my Win32 program 'pin to taskbar'?
Categories:
Pinning Your Win32 Application to the Windows Taskbar Programmatically

Learn how to programmatically pin your Win32 application to the Windows Taskbar, providing users with quick access to your software.
Pinning an application to the Windows Taskbar is a common user convenience feature, allowing quick access to frequently used programs. While users can manually pin applications, there are scenarios where a developer might want to programmatically suggest or perform this action, especially during installation or first-run experiences. This article will guide you through the process of programmatically pinning a Win32 application to the Taskbar using C/C++ and the Windows API.
Understanding the Pinning Mechanism
Windows does not provide a direct, officially documented API function like PinToTaskbar(LPCWSTR appPath)
for security and user control reasons. Programmatic pinning is generally discouraged by Microsoft to prevent malicious software from cluttering a user's Taskbar. However, there are well-known, albeit unsupported, methods that leverage shell verbs or COM interfaces to achieve this. These methods essentially simulate the user's right-click context menu action.
The primary approach involves using the IContextMenu
interface or shell verbs associated with the application's shortcut or executable. The key is to find the correct verb that corresponds to the 'Pin to Taskbar' action.
flowchart TD A[Start] --> B{Application Executable Path} B --> C[Create Shell Link (LNK)] C --> D{Get IContextMenu for LNK} D --> E{Find 'Pin to Taskbar' Verb} E --> F[Invoke Verb] F --> G[End]
Conceptual flow for programmatic Taskbar pinning
Method 1: Using Shell Verbs (IContextMenu)
This method involves creating a shell link (.lnk
file) to your application, then programmatically accessing its context menu to invoke the 'Pin to Taskbar' verb. This is a more robust method than directly manipulating the executable's context menu, as it works reliably even if the executable is not in a standard location.
First, you need to create a shortcut to your application. Then, you'll query the IContextMenu
interface for this shortcut and iterate through its verbs to find the one corresponding to 'Pin to Taskbar'. The verb's identifier can vary between Windows versions and locales, making it a bit fragile. A more reliable approach is to look for specific command strings or use known verb indices.
#include <windows.h>
#include <shlobj.h>
#include <shlguid.h>
#include <propvarutil.h>
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "propsys.lib")
// Function to create a shortcut (.lnk file)
HRESULT CreateShellLink(LPCWSTR lpszPathObj, LPCWSTR lpszPathLink, LPCWSTR lpszDesc)
{
HRESULT hres;
IShellLink* psl;
CoInitialize(NULL);
// Get a pointer to the IShellLink interface.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shell link object.
hres = psl->SetPath(lpszPathObj);
if (SUCCEEDED(hres))
{
// Set the description of the shell link object.
hres = psl->SetDescription(lpszDesc);
if (SUCCEEDED(hres))
{
// Query IShellLink for the IPersistFile interface, and save the shortcut.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
hres = ppf->Save(lpszPathLink, TRUE);
ppf->Release();
}
}
}
psl->Release();
}
CoUninitialize();
return hres;
}
// Function to pin an application to the Taskbar
BOOL PinToTaskbar(LPCWSTR lpszAppPath)
{
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (FAILED(hr)) return FALSE;
BOOL bResult = FALSE;
IShellItem* psi = NULL;
hr = SHCreateItemFromParsingName(lpszAppPath, NULL, IID_PPV_ARGS(&psi));
if (SUCCEEDED(hr))
{
IContextMenu* pcm = NULL;
hr = psi->BindToHandler(NULL, BHID_SFUIObject, IID_PPV_ARGS(&pcm));
if (SUCCEEDED(hr))
{
CMINVOKECOMMANDINFOEX ici = { sizeof(CMINVOKECOMMANDINFOEX) };
ici.fMask = CMIC_MASK_UNICODE | CMIC_MASK_FLAG_NO_UI;
ici.lpVerb = L"taskbarpin"; // This is the magic verb for pinning
ici.lpVerbW = L"taskbarpin";
ici.nShow = SW_SHOWNORMAL;
hr = pcm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
if (SUCCEEDED(hr))
{
bResult = TRUE;
}
pcm->Release();
}
psi->Release();
}
CoUninitialize();
return bResult;
}
int wmain(int argc, wchar_t* argv[])
{
if (argc < 2)
{
wprintf(L"Usage: %s <path_to_executable>\n", argv[0]);
return 1;
}
LPCWSTR appPath = argv[1];
// Optional: Create a temporary shortcut if you want to pin a specific shortcut
// rather than the executable directly. For direct executable pinning, this is not strictly needed.
// WCHAR szTempLinkPath[MAX_PATH];
// GetTempPathW(MAX_PATH, szTempLinkPath);
// wcscat_s(szTempLinkPath, MAX_PATH, L"MyApp.lnk");
// CreateShellLink(appPath, szTempLinkPath, L"My Application Shortcut");
// PinToTaskbar(szTempLinkPath); // Pin the shortcut
// DeleteFileW(szTempLinkPath); // Clean up temporary shortcut
if (PinToTaskbar(appPath))
{
wprintf(L"Successfully pinned %s to Taskbar.\n", appPath);
}
else
{
wprintf(L"Failed to pin %s to Taskbar. HRESULT: 0x%08X\n", appPath, GetLastError());
}
return 0;
}
C++ code to pin an application to the Taskbar using the 'taskbarpin' verb.
taskbarpin
verb is an undocumented internal verb. Its availability and behavior are subject to change with Windows updates. Relying on it might lead to your pinning functionality breaking in future Windows versions. Always test thoroughly across different Windows editions and updates.Method 2: Using ShellExecuteEx with Verbs (Less Reliable)
An alternative, often simpler but less reliable, method involves using ShellExecuteEx
with specific verbs. This method directly attempts to invoke the context menu action on the executable itself. However, ShellExecuteEx
often struggles with verbs that are not directly associated with file types or are dynamic, like 'Pin to Taskbar'.
For 'Pin to Taskbar', the verb is usually taskbarpin
or pintotaskbar
. However, ShellExecuteEx
might not correctly resolve these verbs for an executable, especially if the executable is not registered with a specific file type handler that exposes these verbs. This method is generally not recommended for programmatic pinning due to its inconsistency.
#include <windows.h>
#include <shellapi.h>
// This method is generally less reliable for 'Pin to Taskbar'
BOOL PinToTaskbarShellExecute(LPCWSTR lpszAppPath)
{
SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };
sei.lpFile = lpszAppPath;
sei.lpVerb = L"taskbarpin"; // Or L"pintotaskbar"
sei.nShow = SW_SHOWNORMAL;
sei.fMask = SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS;
if (ShellExecuteEx(&sei))
{
// Check if the operation was successful.
// ShellExecuteEx might return TRUE even if the verb wasn't executed.
// A more robust check would involve verifying the pin status, which is complex.
return TRUE;
}
return FALSE;
}
int wmain(int argc, wchar_t* argv[])
{
if (argc < 2)
{
wprintf(L"Usage: %s <path_to_executable>\n", argv[0]);
return 1;
}
LPCWSTR appPath = argv[1];
if (PinToTaskbarShellExecute(appPath))
{
wprintf(L"Attempted to pin %s to Taskbar using ShellExecuteEx. (Success is not guaranteed without further checks)\n", appPath);
}
else
{
wprintf(L"ShellExecuteEx failed to initiate pin action for %s. Error: %d\n", appPath, GetLastError());
}
return 0;
}
C++ code attempting to pin using ShellExecuteEx (less reliable).
Unpinning from Taskbar
The process for unpinning is very similar to pinning. The corresponding verb for unpinning is typically taskbarunpin
. You can adapt the PinToTaskbar
function by changing the verb string.
#include <windows.h>
#include <shlobj.h>
#include <shlguid.h>
#include <propvarutil.h>
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "propsys.lib")
BOOL UnpinFromTaskbar(LPCWSTR lpszAppPath)
{
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (FAILED(hr)) return FALSE;
BOOL bResult = FALSE;
IShellItem* psi = NULL;
hr = SHCreateItemFromParsingName(lpszAppPath, NULL, IID_PPV_ARGS(&psi));
if (SUCCEEDED(hr))
{
IContextMenu* pcm = NULL;
hr = psi->BindToHandler(NULL, BHID_SFUIObject, IID_PPV_ARGS(&pcm));
if (SUCCEEDED(hr))
{
CMINVOKECOMMANDINFOEX ici = { sizeof(CMINVOKECOMMANDINFOEX) };
ici.fMask = CMIC_MASK_UNICODE | CMIC_MASK_FLAG_NO_UI;
ici.lpVerb = L"taskbarunpin"; // The magic verb for unpinning
ici.lpVerbW = L"taskbarunpin";
ici.nShow = SW_SHOWNORMAL;
hr = pcm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
if (SUCCEEDED(hr))
{
bResult = TRUE;
}
pcm->Release();
}
psi->Release();
}
CoUninitialize();
return bResult;
}
int wmain(int argc, wchar_t* argv[])
{
if (argc < 2)
{
wprintf(L"Usage: %s <path_to_executable>\n", argv[0]);
return 1;
}
LPCWSTR appPath = argv[1];
if (UnpinFromTaskbar(appPath))
{
wprintf(L"Successfully unpinned %s from Taskbar.\n", appPath);
}
else
{
wprintf(L"Failed to unpin %s from Taskbar. HRESULT: 0x%08X\n", appPath, GetLastError());
}
return 0;
}
C++ code to unpin an application from the Taskbar.
shell32.lib
, ole32.lib
, and propsys.lib
libraries when compiling your C/C++ project.Best Practices and Considerations
While programmatic pinning is possible, it comes with several caveats:
- Undocumented APIs: The verbs used (
taskbarpin
,taskbarunpin
) are not officially documented or supported by Microsoft. This means they could change or be removed in future Windows versions, breaking your functionality. - User Control: Users generally prefer to have control over their desktop environment. Forcing an application onto the Taskbar can be perceived as intrusive.
- Security Context: The pinning operation must be performed in a context with sufficient permissions. If your application runs with limited user rights, it might fail to pin.
- Installation vs. Runtime: If you must pin, consider doing it during the application installation process (e.g., via an installer script) rather than at runtime within the application itself. Installers often run with elevated privileges and are a more appropriate place for such system-level modifications.
- Alternative: Start Menu Shortcuts: A more officially supported and less intrusive alternative is to ensure your application creates a proper shortcut in the Start Menu. Users can then easily drag and drop this shortcut to the Taskbar if they wish.