Как я могу иметь значок уведомления на панели задач Windows для внепроцессного COM-сервера, разработанного с использованием VS2019?
До сих пор я пытался просто добавить один с Shell_NotifyIconA(NIM_ADD, &n);
в соответствии с документация MSDN. . Однако, если я установлю NOTIFYICONDATA::m_hWnd
на 0
, тогда этот вызов будет отклонен с 0x80004005
(неверный дескриптор).
Поэтому я должен указать дескриптор окна, на который будут отправляться сообщения значка, но в настоящее время приложение не имеет окон. У него есть насос сообщений, который находится в ATL::CAtlExeModule<T>::RunMessageLoop()
(это часть шаблонного кода ATL), но я не вижу никаких упоминаний о том, где дескриптор окна должен отправлять сообщения в этот цикл.
Я пытался использовать окно только для сообщений, созданное с помощью CWindowImpl::Create, однако, когда программа запускается, поведение неожиданное. В области уведомлений появляется пустое место (значок не отображается должным образом), а наведение мыши или щелчок по пространству не приводит к входу в обработчик сообщений. Появится сообщение журнала, указывающее, что Shell_NotifyIcon()
выполнено успешно, и дескрипторы действительны, но дальнейших сообщений в журнале нет.
Как правильно это сделать в VS2019? (Я делал это раньше в C++Builder, который позволяет вам просто добавить форму, пометить ее как основную форму и добавить к ней компонент значка уведомления).
Код для ATLExeModule (это шаблонный код плюс мои модификации):
class CNotifyWnd : public CWindowImpl<CNotifyWnd>
{
public:
BEGIN_MSG_MAP(CMyCustomWnd)
MESSAGE_HANDLER(WM_USER+1, OnMsg)
END_MSG_MAP()
LRESULT OnMsg(UINT, WPARAM, LPARAM, BOOL&)
{
DEBUG_LOG("Received notification");
return 0;
}
};
static void create_notifyicon()
{
auto * pw = new CNotifyWnd;
HWND hwnd = pw->Create(HWND_MESSAGE);
auto hInst = GetModuleHandle(NULL);
NOTIFYICONDATAA n{};
n.cbSize = sizeof n;
n.hIcon = LoadIcon(NULL, IDI_SHIELD);
#pragma warning(disable : 4996)
strcpy(n.szTip, "Tooltip string");
n.dwInfoFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
n.uVersion = NOTIFYICON_VERSION;
n.hWnd = hwnd;
n.uID = 1234;
n.uCallbackMessage = WM_USER + 1;
int hr = Shell_NotifyIconA(NIM_ADD, &n);
DEBUG_LOG("Shell_NotifyIcon = {}; Icon handle {}, window {}",
hr, (uint64_t)n.hIcon, (uint64_t)n.hWnd);
}
class CMyProjectModule : public ATL::CAtlExeModuleT< CMyProjectModule >
{
public :
DECLARE_LIBID(LIBID_MyProjectLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_MYPROJECT, "{d0d2e9f7-8578-412a-9311-77ff62291751}")
using Parent = ATL::CAtlExeModuleT< CMyProjectModule >;
HRESULT PreMessageLoop(int nShowCmd) throw()
{
HRESULT hr = Parent::PreMessageLoop(nShowCmd);
create_notifyicon();
return hr;
}
};
CMyProjectModule _AtlModule;
extern "C" int WINAPI _tWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/,
LPTSTR /*lpCmdLine*/, int nShowCmd)
{
return _AtlModule.WinMain(nShowCmd);
}
CreateWindow/Ex()
напрямую, чтобы создать -level, не принадлежащее, скрытое окно, возможно, даже окно только для сообщений. Не используйте диалог для невизуальной работы. - person Remy Lebeau   schedule 23.04.2021