diff --git a/examples/qt/main.cpp b/examples/qt/main.cpp index afb710f..630f74f 100644 --- a/examples/qt/main.cpp +++ b/examples/qt/main.cpp @@ -1,81 +1,81 @@ /* SnoreToast is capable to invoke Windows 8 toast notifications. Copyright (C) 2019 Hannah von Reth SnoreToast is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SnoreToast is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with SnoreToast. If not, see . */ #include #include #include #include #include #include #include int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QLocalServer *server = new QLocalServer(); QObject::connect(server, &QLocalServer::newConnection, server, [server](){ auto sock = server->nextPendingConnection(); sock->waitForReadyRead(); qDebug() << sock->bytesAvailable(); const QByteArray rawData = sock->readAll(); const QString data = QString::fromWCharArray(reinterpret_cast(rawData.constData()), rawData.size() / sizeof(wchar_t)); std::wcout << qPrintable(data) << std::endl; // TODO: parse data }); server->listen("foo"); std::wcout << qPrintable(server->fullServerName()) << std::endl; const QString appId = "SnoreToast.Qt.Example"; QProcess proc(&a); proc.start("SnoreToast.exe", { "-install", - "SnoteTestQt", + "SnoreToast/SnoreToastTestQt", a.applicationFilePath(), appId }); proc.waitForFinished(); std::wcout << proc.exitCode() << std::endl; std::wcout << qPrintable(proc.readAll()) << std::endl; QTimer *timer = new QTimer(&a); a.connect(timer, &QTimer::timeout, timer, [&]{ static int id = 0; if (id >= 10) { timer->stop(); } auto proc = new QProcess(&a); proc->start("SnoreToast.exe", { "-t", "test", "-m", "message", "-pipename", server->fullServerName(), "-w", "-id", QString::number(id++), "-appId", appId }); proc->connect(proc, QOverload::of(&QProcess::finished), proc, [proc]{ std::wcout << qPrintable(proc->errorString()) << std::endl; std::wcout << qPrintable(proc->readAll()) << std::endl; std::wcout << proc->exitCode() << std::endl; }); }); timer->start(1000); return a.exec(); } diff --git a/src/linkhelper.cpp b/src/linkhelper.cpp index 427714b..31e48c0 100644 --- a/src/linkhelper.cpp +++ b/src/linkhelper.cpp @@ -1,155 +1,140 @@ /* SnoreToast is capable to invoke Windows 8 toast notifications. Copyright (C) 2013-2019 Hannah von Reth SnoreToast is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SnoreToast is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with SnoreToast. If not, see . */ #include "linkhelper.h" #include "toasteventhandler.h" #include "utils.h" #include #include #include #include #include -#include +#include // compat with older sdk #ifndef INIT_PKEY_AppUserModel_ToastActivatorCLSID EXTERN_C const PROPERTYKEY DECLSPEC_SELECTANY PKEY_AppUserModel_ToastActivatorCLSID = { { 0x9F4C2855, 0x9F79, 0x4B39,{ 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3 } }, 26 }; #define INIT_PKEY_AppUserModel_ToastActivatorCLSID { { 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3 }, 26 } #endif //#ifndef INIT_PKEY_AppUserModel_ToastActivatorCLSID HRESULT LinkHelper::tryCreateShortcut(const std::wstring &shortcutPath, const std::wstring &exePath, const std::wstring &appID) { - HRESULT hr = S_OK; std::wstringstream lnkName; - - if (PathIsRelative(shortcutPath.c_str()) == TRUE) { - lnkName << startmenuPath(); + if (!std::filesystem::path(shortcutPath).is_relative()) + { + std::wcerr << L"The shortcut path must be relative" << std::endl; + return S_FALSE; } - lnkName << shortcutPath; + lnkName << startmenuPath() << L"SnoreToast/v" << SnoreToasts::version() << L"/" << shortcutPath; if (shortcutPath.rfind(L".lnk") == std::wstring::npos) { lnkName << L".lnk"; } - hr = mkdirs(lnkName.str()); - if (SUCCEEDED(hr)) { - - DWORD attributes = GetFileAttributes(lnkName.str().c_str()); - bool fileExists = attributes < 0xFFFFFFF; - - if (!fileExists) { - hr = installShortcut(lnkName.str(), exePath, appID); - } else { - hr = S_FALSE; - } + const std::filesystem::path path(lnkName.str()); + if (std::filesystem::exists(path)) + { + tLog << L"Path: " << path << L" already exists, skip creation of shortcut"; + return S_OK; } - Utils::registerActivator(); - return hr; + if (!std::filesystem::exists(path.parent_path()) && !std::filesystem::create_directories(path.parent_path())) + { + tLog << L"Failed to create dir: " << path.parent_path(); + return S_FALSE; + } + return installShortcut(path, exePath, appID); } HRESULT LinkHelper::tryCreateShortcut(const std::wstring &appID) { - std::wstringstream name; - name << L"SnoreToast v" << SnoreToasts::version() << L".lnk"; - return tryCreateShortcut(name.str(), Utils::selfLocate().c_str(), appID); + return tryCreateShortcut(L"SnoreToast.lnk", Utils::selfLocate().c_str(), appID); } // Install the shortcut HRESULT LinkHelper::installShortcut(const std::wstring &shortcutPath, const std::wstring &exePath, const std::wstring &appID) { - PCWSTR pszExePath = exePath.c_str(); std::wcout << L"Installing shortcut: " << shortcutPath << L" " << exePath << L" " << appID << std::endl; + tLog << L"Installing shortcut: " << shortcutPath << L" " << exePath << L" " << appID; /** * Add CToastNotificationActivationCallback to registry * Required to use the CToastNotificationActivationCallback for buttons and textbox interactions. * windows.ui.notifications does not support user interaction from cpp */; HRESULT hr = HRESULT_FROM_WIN32(::RegSetKeyValueW(HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\CLSID\\" TOAST_UUID L"\\LocalServer32", nullptr, REG_SZ, Utils::selfLocate().c_str(), static_cast(Utils::selfLocate().size() * sizeof(wchar_t)))); if (SUCCEEDED(hr)) { ComPtr shellLink; hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shellLink)); if (SUCCEEDED(hr)) { hr = shellLink->SetPath(exePath.c_str()); if (SUCCEEDED(hr)) { hr = shellLink->SetArguments(L""); if (SUCCEEDED(hr)) { ComPtr propertyStore; hr = shellLink.As(&propertyStore); if (SUCCEEDED(hr)) { PROPVARIANT appIdPropVar; hr = InitPropVariantFromString(appID.c_str(), &appIdPropVar); if (SUCCEEDED(hr)) { hr = propertyStore->SetValue(PKEY_AppUserModel_ID, appIdPropVar); if (SUCCEEDED(hr)) { PropVariantClear(&appIdPropVar); PROPVARIANT toastActivatorPropVar; toastActivatorPropVar.vt = VT_CLSID; toastActivatorPropVar.puuid = const_cast(&__uuidof(CToastNotificationActivationCallback)); hr = propertyStore->SetValue(PKEY_AppUserModel_ToastActivatorCLSID, toastActivatorPropVar); if (SUCCEEDED(hr)) { hr = propertyStore->Commit(); if (SUCCEEDED(hr)) { ComPtr persistFile; hr = shellLink.As(&persistFile); if (SUCCEEDED(hr)) { hr = persistFile->Save(shortcutPath.c_str(), TRUE); } } } } } } } } } } if (FAILED(hr)) { std::wcerr << "Failed to install shortcut " << shortcutPath << " error: " << _com_error(hr).ErrorMessage() << std::endl; } return hr; } -HRESULT LinkHelper::mkdirs(const std::wstring &dirs) -{ - HRESULT hr = S_OK; - static std::wregex seperator(L"\\\\|/"); - - for (std::wsregex_iterator i = std::wsregex_iterator(dirs.begin(), dirs.end(), seperator); SUCCEEDED(hr) && i != std::wsregex_iterator(); ++i) { - hr = _wmkdir(dirs.substr(0, i->position()).c_str()) != ENOENT ? S_OK : E_FAIL; - } - return hr; -} - std::wstring LinkHelper::startmenuPath() { wchar_t buffer[MAX_PATH]; std::wstringstream path; if (GetEnvironmentVariable(L"APPDATA", buffer , MAX_PATH) > 0) { path << buffer << L"\\Microsoft\\Windows\\Start Menu\\Programs\\"; } return path.str(); } diff --git a/src/linkhelper.h b/src/linkhelper.h index eb018c6..82536fa 100644 --- a/src/linkhelper.h +++ b/src/linkhelper.h @@ -1,34 +1,33 @@ /* SnoreToast is capable to invoke Windows 8 toast notifications. Copyright (C) 2013-2019 Hannah von Reth SnoreToast is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. SnoreToast is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with SnoreToast. If not, see . */ #pragma once #include "snoretoasts.h" class LinkHelper { public: static HRESULT tryCreateShortcut(const std::wstring &shortcutPath, const std::wstring &exePath, const std::wstring &appID); static HRESULT tryCreateShortcut(const std::wstring &appID); private: static HRESULT installShortcut(const std::wstring &shortcutPath, const std::wstring &exePath, const std::wstring &appID); - static HRESULT mkdirs(const std::wstring &dirs); static std::wstring startmenuPath(); };