199 lines
6.7 KiB
C++
199 lines
6.7 KiB
C++
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
|
|
#include <windows.h>
|
|
#include <strsafe.h>
|
|
#include <shobjidl.h> // For ITaskbarList3
|
|
#include "resource.h"
|
|
|
|
#pragma comment(linker, "\"/manifestdependency:type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
|
|
|
HINSTANCE g_hInstance = NULL;
|
|
|
|
HRESULT CreateThumbnailToolbar(HWND hWnd)
|
|
{
|
|
ITaskbarList3 *pTaskbarList;
|
|
HRESULT hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pTaskbarList));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pTaskbarList->HrInit();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Figure out what bitmap to use for the thumbnail toolbar buttons - we
|
|
// make the decision based on the system's small icon width. This will make
|
|
// us DPI-friendly.
|
|
struct
|
|
{
|
|
PCWSTR pbmp;
|
|
int cx;
|
|
}
|
|
const bitmaps[3] =
|
|
{
|
|
{ MAKEINTRESOURCE(IDB_BUTTONIMAGES_96), 16 },
|
|
{ MAKEINTRESOURCE(IDB_BUTTONIMAGES_120), 20 },
|
|
{ MAKEINTRESOURCE(IDB_BUTTONIMAGES_144), 24 }
|
|
};
|
|
|
|
int const cxButton = GetSystemMetrics(SM_CXSMICON);
|
|
|
|
int iButtons = 0;
|
|
for (int i = 0; i < ARRAYSIZE(bitmaps); i++)
|
|
{
|
|
if (bitmaps[i].cx <= cxButton)
|
|
{
|
|
iButtons = i;
|
|
}
|
|
}
|
|
|
|
HIMAGELIST himl = ImageList_LoadImage(g_hInstance, bitmaps[iButtons].pbmp,
|
|
bitmaps[iButtons].cx, 0, RGB(255,0,255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
|
|
if (himl)
|
|
{
|
|
hr = pTaskbarList->ThumbBarSetImageList(hWnd, himl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
THUMBBUTTON buttons[3] = {};
|
|
|
|
// First button
|
|
buttons[0].dwMask = THB_BITMAP | THB_TOOLTIP | THB_FLAGS;
|
|
buttons[0].dwFlags = THBF_ENABLED | THBF_DISMISSONCLICK;
|
|
buttons[0].iId = IDTB_BUTTON1;
|
|
buttons[0].iBitmap = 0;
|
|
StringCchCopy(buttons[0].szTip, ARRAYSIZE(buttons[0].szTip), L"Button 1");
|
|
|
|
// Second button
|
|
buttons[1].dwMask = THB_BITMAP | THB_TOOLTIP | THB_FLAGS;
|
|
buttons[1].dwFlags = THBF_ENABLED | THBF_DISMISSONCLICK;
|
|
buttons[1].iId = IDTB_BUTTON2;
|
|
buttons[1].iBitmap = 1;
|
|
StringCchCopy(buttons[1].szTip, ARRAYSIZE(buttons[1].szTip), L"Button 2");
|
|
|
|
// Third button
|
|
buttons[2].dwMask = THB_BITMAP | THB_TOOLTIP | THB_FLAGS;
|
|
buttons[2].dwFlags = THBF_ENABLED | THBF_DISMISSONCLICK;
|
|
buttons[2].iId = IDTB_BUTTON3;
|
|
buttons[2].iBitmap = 2;
|
|
StringCchCopy(buttons[2].szTip, ARRAYSIZE(buttons[2].szTip), L"Button 3");
|
|
|
|
// Set the buttons to be the thumbnail toolbar
|
|
hr = pTaskbarList->ThumbBarAddButtons(hWnd, ARRAYSIZE(buttons), buttons);
|
|
}
|
|
ImageList_Destroy(himl);
|
|
}
|
|
}
|
|
|
|
// It's OK to release ITaskbarList3 here; the thumbnail toolbar will remain.
|
|
pTaskbarList->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static UINT s_uTBBC = WM_NULL;
|
|
|
|
if (s_uTBBC == WM_NULL)
|
|
{
|
|
// Compute the value for the TaskbarButtonCreated message
|
|
s_uTBBC = RegisterWindowMessage(L"TaskbarButtonCreated");
|
|
|
|
// In case the application is run elevated, allow the
|
|
// TaskbarButtonCreated and WM_COMMAND messages through.
|
|
ChangeWindowMessageFilter(s_uTBBC, MSGFLT_ADD);
|
|
ChangeWindowMessageFilter(WM_COMMAND, MSGFLT_ADD);
|
|
}
|
|
|
|
if (message == s_uTBBC)
|
|
{
|
|
// Once we get the TaskbarButtonCreated message, we can create
|
|
// our window's thumbnail toolbar.
|
|
CreateThumbnailToolbar(hWnd);
|
|
}
|
|
else switch (message)
|
|
{
|
|
case WM_COMMAND:
|
|
{
|
|
int const wmId = LOWORD(wParam);
|
|
switch (wmId)
|
|
{
|
|
case IDTB_BUTTON1:
|
|
case IDTB_BUTTON2:
|
|
case IDTB_BUTTON3:
|
|
{
|
|
WCHAR szMsg[100];
|
|
StringCchPrintf(szMsg, ARRAYSIZE(szMsg), L"Thumbnail toolbar button clicked, ID=%d", wmId);
|
|
MessageBox(hWnd, szMsg, L"Application", MB_OK);
|
|
break;
|
|
}
|
|
|
|
case IDM_EXIT:
|
|
DestroyWindow(hWnd);
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
PostQuitMessage(0);
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR /* pszCmdLine */, int nCmdShow)
|
|
{
|
|
g_hInstance = hInstance;
|
|
|
|
SetProcessDPIAware(); // Set ourselves to be a DPI-aware application
|
|
|
|
HRESULT hrInit = CoInitialize(NULL); // Initialize COM so we can call CoCreateInstance
|
|
if (SUCCEEDED(hrInit))
|
|
{
|
|
WCHAR const szWindowClass[] = L"ThumbnailToolbarWnd"; // The main window class name
|
|
|
|
WNDCLASSEX wcex = { sizeof(wcex) };
|
|
wcex.lpfnWndProc = WndProc;
|
|
wcex.hInstance = g_hInstance;
|
|
wcex.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_THUMBNAILTOOLBAR));
|
|
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
|
|
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_THUMBNAILTOOLBAR);
|
|
wcex.lpszClassName = szWindowClass;
|
|
|
|
RegisterClassEx(&wcex);
|
|
|
|
WCHAR szTitle[100];
|
|
LoadString(g_hInstance, IDS_APP_TITLE, szTitle, ARRAYSIZE(szTitle));
|
|
|
|
HWND hWnd = CreateWindowEx(0, szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, 400, 400, NULL, NULL, g_hInstance, NULL);
|
|
if (hWnd)
|
|
{
|
|
ShowWindow(hWnd, nCmdShow);
|
|
UpdateWindow(hWnd);
|
|
|
|
MSG msg;
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
CoUninitialize();
|
|
}
|
|
|
|
return 0;
|
|
}
|