自アプリ(Win32ネイティブアプリ)でトースト表示するにあたり、手順を調べたので以下にメモしておく。
なお、本記事に張り付けたコード辺は自アプリの関連処理を切り出したものだけど、切り出したものに対する検証(ビルド、実行)はしていないため、何か不備はあるかも・・
アプリに対してAppUserModelIdを割り当てる
AppUserModelIdはGUID。guidgen.exeを使って自アプリ用のAppUserModelIdを作っておく。 トーストを表示する際、このAppUserModelIdを指定する必要がある。
AppUserModelIDを登録する(スタートメニューにアプリのショートカットを作成する)
スタートメニューにショートカットを作り、そのショートカットメニューのプロパティとして PKEY_AppUserModel_IDキーに紐づける形で前ステップで生成したAppUserModelIDを割り当てる。
以下のような形でショートカットを作成しておけばよい。
#include <propkey.h> #include <propvarutil.h> // 上記のほかに、CComPtrを使うための準備をしておく(関連ヘッダのinclude,CoInitializeなど) // 事前に確保しておく↓ constexpr LPCWSTR MYAPP_USERMODEL_ID = L"{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"; // pathToSave : ショートカットキー保存先パス // exePath : ショートカットのリンク先(実行ファイル)のパス bool registerShortcut(LPCWSTR pathToSave, LPCWSTR exePath) { CComPtr<IShellLink> shellLinkPtr; HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,IID_IShellLink,(void**)&shellLinkPtr); if (FAILED(hr)){ return false; } // 実行ファイルへのパス shellLinkPtr->SetPath(exePath); // 引数、カレントディレクトリなどは必要に応じて設定する shellLinkPtr->SetArguments(L""); shellLinkPtr->SetWorkingDirectory(L""); // AppUserModelIdをショートカットに設定する CComPtr<IPropertyStore> propStore; shellLinkPtr->QueryInterface(IID_IPropertyStore, (void**)&propStore); // AppUserModelIdをappIdPropVarに設定し、キーに書き込む PROPVARIANT appIdPropVar; InitPropVariantFromString(MYAPP_USERMODEL_ID, &appIdPropVar); propStore->SetValue(PKEY_AppUserModel_ID, appIdPropVar); propStore->Commit(); PropVariantClear(&appIdPropVar); CComPtr<IPersistFile> persistFilePtr; hr = shellLinkPtr->QueryInterface(IID_IPersistFile, (void**)&persistFilePtr); if(FAILED(hr)){ return false; } // ショートカットキーをファイルとして保存する hr = persistFilePtr->Save(pathToSave, TRUE); if(FAILED(hr)){ return false; } return true; }
トーストを表示する
ToastNotification
のインスタンスを作成し、これをToastNotificationManager
に対して渡すとトーストを表示することができる。
トーストに表示する内容はXMLベースのデータをこしらえて定義する。
テキストのほかに画像をおいたりハイパーリンクを設置したり、ボタンを置いたりなどできる。
また、クリック時の処理などいろいろ定義することができる。
ただし、クリック時の処理を定義しようとすると、そのための準備がいろいろ必要になるがここでは触れていない。
#include <winrt/Windows.UI.Notifications.h> #include <winrt/Windows.Data.Xml.Dom.h> using namespace winrt; using namespace winrt::Windows::UI::Notifications; using namespace winrt::Windows::Data::Xml::Dom; void ShowToast() { XmlDocument doc; doc.LoadXml(L" <toast>\ <visual>\ <binding template=\"ToastGeneric\">\ <text></text>\ <text></text>\ </binding>\ </visual>\ </toast>"); doc.DocumentElement().SetAttribute(L"launch", L"action=xxx&message=yyy"); // コールバック時にここで指定した文字列がえられる doc.SelectSingleNode(L"//text[1]").InnerText(L"こんにちは"); doc.SelectSingleNode(L"//text[2]").InnerText(L"テストです"); // トーストを表示する winrt::Windows::UI::Notifications::ToastNotification notif(doc); winrt::Windows::UI::Notifications::ToastNotificationManager toastManager; // CreateToastNotifierの引数に自アプリのAppUserModelIdを指定することにより、 // 自アプリの通知としてトースト表示される。 ToastNotifier toastNotifier(toastManager.CreateToastNotifier(MYAPP_USERMODEL_ID)); toastNotifier.Show(notif); }
その他メモ
Windows10/11環境では、
Shell_NotifyIcon
を使って、トースト表示をすることもできる- ただし、以下のような制約があるようだ
- クリックしたときの処理を定義できない
- 見た目の細かなカスタマイズはできない(せいぜいアイコンを指定するくらい)
- 通知センターに通知が残らない、
- ただし、以下のような制約があるようだ
自前でトースト表示する場合、トーストをクリックしたときの処理を自アプリで処理することができるが、その場合はコールバックを登録したり、コールバックを用意する必要がある
他アプリが登録したUserAppModeIdを流用することで、自アプリでAppUserModeIdを登録しなくてもトースト表示はできる
- ただし、流用元アプリとしてトースト表示が行われる
既存のAppUserModelIdを調べる
- Excplorerのアドレスバーに
shell:AppsFolder
と打つ - 何もない領域を右クリック(Win11環境であれば、シフトキー押しながら右クリック)し、
グループで表示
>その他
を選択する - 「詳細表示の設定」ダイアログが表示されるので、
AppUserModelId
をチェックしてOKボタンを押下する - 再度、 何もない領域を右クリックして、
表示
>詳細
を選択する
リスト表示にAppUserModelId
という列が表示されるので、ここからアプリごとのAppUserModelId
を確認することができる