Skip to content

Instantly share code, notes, and snippets.

@kikuchy
Last active June 15, 2018 03:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kikuchy/a415613d5f1b11c18ef18162351e7bb7 to your computer and use it in GitHub Desktop.
Save kikuchy/a415613d5f1b11c18ef18162351e7bb7 to your computer and use it in GitHub Desktop.

mingwでもタスクトレイ常駐する系のアプリをWin32APIだけでつくりたい

  • タスクトレイを触るにウィンドウハンドラが必要なので、表示しなくても適当なウィンドウは作っておく必要がある
  • アイコンの扱いが面倒
  • とりあえずbrewでmingwだけ入れればビルドできる
  • mingwのg++で -mwindows -static -DUNICODE オプションが必要(つけないとlibstdc++あたりのdllがないって怒られるし文字化けする)
  • windresではオプションに -c 65001 を指定する必要あり(UTF-8)
  • wine 3.0系の問題なのか、Macでは32bitにしないとwineが起動しない
i686-w64-mingw32-windres -c 65001 menu.rc menu.o
i686-w64-mingw32-g++ -static -mwindows -DUNICODE diag.cpp menu.o
WINEARCH=win32 wine a.exe

Makefile作れって話ではある

参考

#define IDM_QUIT 40002
#include "menu.h"
CTX_MENU MENU{
POPUP "ファイル"{
MENUITEM "終了(&Q)", IDM_QUIT
}
}
#include <windows.h>
#include <winuser.h>
#include <iostream>
#include "menu.h"
#if defined(__MINGW32__)
# undef MAKEINTRESOURCE
# define MAKEINTRESOURCE(i) ((LPCWSTR)((ULONG_PTR)(i)))
#endif /* defined(__MINGW32__) */
#define WM_NOTIFYICON (WM_USER + 100)
class TrayIcon {
private:
HICON iconHandle;
public:
TrayIcon(HINSTANCE inst, LPCWSTR iconName);
~TrayIcon();
HICON handle();
};
TrayIcon::TrayIcon(HINSTANCE inst, LPCWSTR iconName) {
this->iconHandle = (HICON)LoadImage(
inst,
iconName,
IMAGE_ICON,
0,
0,
LR_DEFAULTSIZE
);
}
TrayIcon::~TrayIcon() {
DestroyIcon(this->iconHandle);
}
HICON TrayIcon::handle() { return this->iconHandle; }
class ContextMenu {
private:
HMENU parentMenu;
HMENU rootPopup;
public:
ContextMenu();
~ContextMenu();
void Show(HWND hWnd);
void OnMenuClicked(WORD itemID);
};
ContextMenu::ContextMenu() {
this->parentMenu = LoadMenu(NULL, TEXT("CTX_MENU"));
this->rootPopup = GetSubMenu(this->parentMenu, 0);
}
ContextMenu::~ContextMenu() {
DestroyMenu(this->parentMenu);
}
void ContextMenu::Show(HWND hWnd) {
POINT currentCursorPoint;
GetCursorPos(&currentCursorPoint);
TrackPopupMenu(
this->rootPopup,
0,
currentCursorPoint.x,
currentCursorPoint.y,
0,
hWnd,
NULL
);
}
void ContextMenu::OnMenuClicked(WORD itemID) {
switch (itemID) {
case IDM_QUIT:
PostQuitMessage(0);
}
}
class Tray {
private:
HWND windowHandler;
TrayIcon *currentIcon = NULL;
ContextMenu *currentMenu = NULL;
public:
Tray(HINSTANCE inst, int nCmdShow);
int AddIcon(TrayIcon *icon, ContextMenu *menu, LPCWSTR tipMessage);
void ClearIcon();
LRESULT CALLBACK WndProcDelegate(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
~Tray();
};
Tray::Tray(HINSTANCE inst, int nCmdShow) {
WNDCLASS wclass;
wclass.style = CS_HREDRAW | CS_VREDRAW;
wclass.lpfnWndProc = Tray::WndProc;
//wclass.lpfnWndProc = WndProc;
wclass.cbClsExtra = 0;
wclass.cbWndExtra = 0;
wclass.hIcon = LoadIcon(NULL , IDI_APPLICATION);
wclass.hInstance = inst;
wclass.lpszClassName = TEXT("TRAY");
if(!RegisterClass(&wclass)) throw std::runtime_error("Tray class must be registered.");
this->windowHandler = CreateWindowEx(
WS_EX_TOOLWINDOW,
TEXT("TRAY"),
TEXT("tray"),
WS_OVERLAPPEDWINDOW,
0,
0,
0,
0,
NULL,
NULL,
inst,
this
);
}
Tray::~Tray() {
}
int Tray::AddIcon(TrayIcon *icon, ContextMenu *menu, LPCWSTR tipMessage) {
this->currentIcon = icon;
this->currentMenu = menu;
NOTIFYICONDATA nid;
nid.cbSize = sizeof(nid);
nid.hWnd = this->windowHandler;
nid.uID = 0;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_NOTIFYICON;
nid.hIcon = icon->handle();
lstrcpy(nid.szTip, tipMessage);
return (int)Shell_NotifyIcon(NIM_ADD, &nid);
}
void Tray::ClearIcon() {
NOTIFYICONDATA nid;
nid.cbSize = sizeof(nid);
nid.hWnd = this->windowHandler;
nid.uID = 0;
nid.uFlags = 0;
Shell_NotifyIcon(NIM_DELETE, &nid);
this->currentMenu = NULL;
this->currentIcon = NULL;
}
LRESULT Tray::WndProcDelegate(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (lParam) {
case WM_LBUTTONDOWN:
if (MessageBox(NULL, TEXT("Quit?"), TEXT("Quit?"), MB_YESNO) == IDYES) {
PostQuitMessage(0);
return 0;
}
break;
case WM_RBUTTONDOWN:
this->currentMenu->Show(hWnd);
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
LRESULT Tray::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
Tray *tray = (Tray *)GetWindowLong(hWnd, GWL_USERDATA);
if (!tray) {
tray = (Tray *)(((LPCREATESTRUCT)lParam)->lpCreateParams);
if (tray) {
SetWindowLong(hWnd, GWL_USERDATA, (LONG)tray);
}
}
switch (msg) {
case WM_NOTIFYICON:
if (wParam == 0) {
return tray->WndProcDelegate(hWnd, msg, wParam, lParam);
}
break;
case WM_COMMAND:
tray->currentMenu->OnMenuClicked(LOWORD(wParam));
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
Tray tray(hInstance, nCmdShow);
TrayIcon *ti = new TrayIcon(NULL, MAKEINTRESOURCE(IDI_WINLOGO));
ContextMenu *ctxMenu = new ContextMenu();
LPCWSTR tip = TEXT("ほげほげ");
tray.AddIcon(ti, ctxMenu, tip);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
tray.ClearIcon();
delete ti;
delete ctxMenu;
return msg.wParam;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment