diff --git a/README.md b/README.md
index 2b2793e..128b6df 100644
--- a/README.md
+++ b/README.md
@@ -1,82 +1,82 @@
Snoretoast
==========
-A command line application which is capable of creating Windows Toast notifications on Windows 8 or later.
+A command line application capable of creating Windows Toast notifications on Windows 8 or later.
If SnoreToast is used without the parameter --appID an default appID is used and a shortcut to SnoreToast.exe is created in the startmenu, notifications created that way will be asigned to SnoreToast.
If you wan't to brand your notifications you need to create the application startmenu entry with `snoretoast.exe --install "MyApp\MyApp.lnk" "C:\myApp.exe" "My.APP_ID"`.
This appID then needs to be passed to snoretoast.exe with the `--appID`` parameter.
# Releases and Binaries
Releases and binaries can be found [here](https://binary-factory.kde.org/job/SnoreToast_Nightly_win64/).
----------------------------------------------------------
```
Welcome to SnoreToast 0.5.99.
-A command line application which is capable of creating Windows Toast notifications.
+A command line application capable of creating Windows Toast notifications.
---- Usage ----
SnoreToast [Options]
---- Options ----
[-t]
| Displayed on the first line of the toast.
[-m] | Displayed on the remaining lines, wrapped.
[-b] | Displayed on the bottom line, can list multiple buttons separated by ;
[-tb] | Displayed a textbox on the bottom line, only if buttons are not presented.
[-p] | Display toast with an image, local files only.
[-id] | sets the id for a notification to be able to close it later.
[-s] | Sets the sound of the notifications, for possible values see http://msdn.microsoft.com/en-us/library/windows/apps/hh761492.aspx.
[-silent] | Don't play a sound file when showing the notifications.
[-appID] | Don't create a shortcut but use the provided app id.
[-pipeName] <\.\pipe\pipeName\> | Provide a name pipe which is used for callbacks.
[-application] | Provide a application that might be started if the pipe does not exist.
-close | Closes a currently displayed notification.
-install | Creates a shortcut in the start menu which point to the executable , appID used for the notifications.
-v | Print the version and copying information.
-h | Print these instructions. Same as no args.
Exit Status : Exit Code
Failed : -1
Success : 0
Hidden : 1
Dismissed : 2
TimedOut : 3
ButtonPressed : 4
TextEntered : 5
---- Image Notes ----
Images must be .png with:
maximum dimensions of 1024x1024
size <= 200kb
These limitations are due to the Toast notification system.
```
----------------------------------------------------------
# Shortcut creation with Nsis
```
!include LogicLib.nsh
!include WordFunc.nsh
Function SnoreWinVer
ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
${VersionCompare} "6.2" $R0 $R0
${If} $R0 == 1
Push "NotWin8"
${Else}
Push "AtLeastWin8"
${EndIf}
FunctionEnd
!macro SnoreShortcut path exe appID
Call SnoreWinVer
Pop $0
${If} $0 == "AtLeastWin8"
nsExec::ExecToLog '"${SnoreToastExe}" -install "${path}" "${exe}" "${appID}"'
${Else}
CreateShortCut "${path}" "${exe}"
${EndIf}
!macroend
```
diff --git a/src/main.cpp b/src/main.cpp
index 5da5b85..e331367 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,320 +1,319 @@
/*
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 "snoretoasts.h"
#include "toasteventhandler.h"
#include "snoretoastactioncenterintegration.h"
#include "linkhelper.h"
#include
#include
#include
#include
#include
#include
#include
#include
using namespace Windows::Foundation;
void help(const std::wstring &error)
{
if (!error.empty()) {
std::wcerr << error << std::endl;
} else {
std::wcerr << L"Welcome to SnoreToast " << SnoreToasts::version() << "." << std::endl
- << L"A command line application which is capable of creating Windows Toast "
- L"notifications."
+ << L"A command line application capable of creating Windows Toast notifications."
<< std::endl;
}
std::wcerr
<< std::endl
<< L"---- Usage ----" << std::endl
<< L"SnoreToast [Options]" << std::endl
<< std::endl
<< L"---- Options ----" << std::endl
<< L"[-t] \t| Displayed on the first line of the toast." << std::endl
<< L"[-m] \t| Displayed on the remaining lines, wrapped." << std::endl
<< L"[-b] | Displayed on the bottom line, can list multiple "
L"buttons separated by ;"
<< std::endl
<< L"[-tb]\t\t\t| Displayed a textbox on the bottom line, only if buttons are not "
L"presented."
<< std::endl
<< L"[-p] \t| Display toast with an image, local files only." << std::endl
<< L"[-id] \t\t| sets the id for a notification to be able to close it later."
<< std::endl
<< L"[-s] \t| Sets the sound of the notifications, for possible values see "
L"http://msdn.microsoft.com/en-us/library/windows/apps/hh761492.aspx."
<< std::endl
<< L"[-silent] \t\t| Don't play a sound file when showing the notifications."
<< std::endl
<< L"[-appID] \t| Don't create a shortcut but use the provided app id."
<< std::endl
<< L"[-pipeName] <\\.\\pipe\\pipeName\\>\t| Provide a name pipe which is used for "
L"callbacks."
<< std::endl
<< L"[-application] \t| Provide a application that might be started if "
L"the pipe does not exist."
<< std::endl
<< L"-close \t\t| Closes a currently displayed notification." << std::endl
<< std::endl
<< L"-install | Creates a shortcut in the start "
L"menu which point to the executable , appID used for the "
L"notifications."
<< std::endl
<< std::endl
<< L"-v \t\t\t| Print the version and copying information." << std::endl
<< L"-h\t\t\t| Print these instructions. Same as no args." << std::endl
<< L"Exit Status\t: Exit Code" << std::endl
<< L"Failed\t\t: " << static_cast(SnoreToastActions::Actions::Error) << std::endl
<< std::endl
<< "Success\t\t: " << static_cast(SnoreToastActions::Actions::Clicked)
<< std::endl
<< "Hidden\t\t: " << static_cast(SnoreToastActions::Actions::Hidden) << std::endl
<< "Dismissed\t: " << static_cast(SnoreToastActions::Actions::Dismissed)
<< std::endl
<< "TimedOut\t: " << static_cast(SnoreToastActions::Actions::Timedout)
<< std::endl
<< "ButtonPressed\t: " << static_cast(SnoreToastActions::Actions::ButtonClicked)
<< std::endl
<< "TextEntered\t: " << static_cast(SnoreToastActions::Actions::TextEntered)
<< std::endl
<< std::endl
<< L"---- Image Notes ----" << std::endl
<< L"Images must be .png with:" << std::endl
<< L"\tmaximum dimensions of 1024x1024" << std::endl
<< L"\tsize <= 200kb" << std::endl
<< L"These limitations are due to the Toast notification system." << std::endl;
}
void version()
{
std::wcerr << L"SnoreToast version " << SnoreToasts::version() << std::endl
<< L"Copyright (C) 2019 Hannah von Reth " << std::endl
<< L"SnoreToast is free software: you can redistribute it and/or modify" << std::endl
<< L"it under the terms of the GNU Lesser General Public License as published by"
<< std::endl
<< L"the Free Software Foundation, either version 3 of the License, or" << std::endl
<< L"(at your option) any later version." << std::endl;
}
SnoreToastActions::Actions parse(std::vector args)
{
HRESULT hr = S_OK;
std::wstring appID;
std::filesystem::path pipe;
std::filesystem::path application;
std::wstring title;
std::wstring body;
std::filesystem::path image;
std::wstring id;
std::wstring sound(L"Notification.Default");
std::wstring buttons;
bool silent = false;
bool closeNotify = false;
bool isTextBoxEnabled = false;
auto nextArg = [&](std::vector::const_iterator &it,
const std::wstring &helpText) -> std::wstring {
if (it != args.cend()) {
return *it++;
} else {
help(helpText);
exit(static_cast(SnoreToastActions::Actions::Error));
}
};
auto it = args.begin() + 1;
while (it != args.end()) {
std::wstring arg(nextArg(it, L""));
std::transform(arg.begin(), arg.end(), arg.begin(),
[](int i) -> int { return ::tolower(i); });
if (arg == L"-m") {
body = nextArg(it,
L"Missing argument to -m.\n"
L"Supply argument as -m \"message string\"");
} else if (arg == L"-t") {
title = nextArg(it,
L"Missing argument to -t.\n"
L"Supply argument as -t \"bold title string\"");
} else if (arg == L"-p") {
std::wstring path = nextArg(it,
L"Missing argument to -p."
L"Supply argument as -p \"image path\"");
if (path.substr(0, 8) != L"file:///") {
image = L"file:///";
path = _wfullpath(nullptr, path.c_str(), MAX_PATH);
}
image.append(path);
} else if (arg == L"-s") {
sound = nextArg(it,
L"Missing argument to -s.\n"
L"Supply argument as -s \"sound name\"");
} else if (arg == L"-id") {
id = nextArg(it,
L"Missing argument to -id.\n"
L"Supply argument as -id \"id\"");
} else if (arg == L"-silent") {
silent = true;
} else if (arg == L"-appid") {
appID = nextArg(it,
L"Missing argument to -appID.\n"
L"Supply argument as -appID \"Your.APP.ID\"");
} else if (arg == L"-pipename") {
pipe = nextArg(it,
L"Missing argument to -pipeName.\n"
L"Supply argument as -pipeName \"\\.\\pipe\\foo\\\"");
} else if (arg == L"-application") {
application = nextArg(it,
L"Missing argument to -pipeName.\n"
L"Supply argument as -applicatzion \"C:\\foo.exe\"");
} else if (arg == L"-b") {
buttons = nextArg(it,
L"Missing argument to -b.\n"
L"Supply argument for buttons as -b \"button1;button2\"");
} else if (arg == L"-tb") {
isTextBoxEnabled = true;
} else if (arg == L"-install") {
const std::wstring shortcut(
nextArg(it,
L"Missing argument to -install.\n"
L"Supply argument as -install \"path to your shortcut\" \"path to the "
L"application the shortcut should point to\" \"App.ID\""));
const std::wstring exe(
nextArg(it,
L"Missing argument to -install.\n"
L"Supply argument as -install \"path to your shortcut\" \"path to the "
L"application the shortcut should point to\" \"App.ID\""));
appID = nextArg(it,
L"Missing argument to -install.\n"
L"Supply argument as -install \"path to your shortcut\" \"path to the "
L"application the shortcut should point to\" \"App.ID\"");
return SUCCEEDED(LinkHelper::tryCreateShortcut(
shortcut, exe, appID, SnoreToastActionCenterIntegration::uuid()))
? SnoreToastActions::Actions::Clicked
: SnoreToastActions::Actions::Error;
} else if (arg == L"-close") {
id = nextArg(it,
L"Missing agument to -close"
L"Supply argument as -close \"id\"");
closeNotify = true;
} else if (arg == L"-v") {
version();
return SnoreToastActions::Actions::Clicked;
} else if (arg == L"-h") {
help(L"");
return SnoreToastActions::Actions::Clicked;
} else {
std::wstringstream ws;
ws << L"Unknown argument: " << arg << std::endl;
help(ws.str());
return SnoreToastActions::Actions::Error;
}
}
if (appID.empty()) {
std::wstringstream _appID;
_appID << L"Snore.DesktopToasts." << SnoreToasts::version();
appID = _appID.str();
hr = LinkHelper::tryCreateShortcut(std::filesystem::path(L"SnoreToast")
/ SnoreToasts::version() / L"SnoreToast",
appID, SnoreToastActionCenterIntegration::uuid());
if (!SUCCEEDED(hr)) {
return SnoreToastActions::Actions::Error;
}
}
if (closeNotify) {
if (!id.empty()) {
SnoreToasts app(appID);
app.setId(id);
if (app.closeNotification()) {
return SnoreToastActions::Actions::Clicked;
}
} else {
help(L"Close only works if an -id id was provided.");
}
} else {
hr = (title.length() > 0 && body.length() > 0) ? S_OK : E_FAIL;
if (SUCCEEDED(hr)) {
if (isTextBoxEnabled) {
if (pipe.empty()) {
std::wcerr << L"TextBox notifications only work if a pipe for the result "
L"was provided"
<< std::endl;
return SnoreToastActions::Actions::Error;
}
}
SnoreToasts app(appID);
app.setPipeName(pipe);
app.setApplication(application);
app.setSilent(silent);
app.setSound(sound);
app.setId(id);
app.setButtons(buttons);
app.setTextBoxEnabled(isTextBoxEnabled);
app.displayToast(title, body, image);
return app.userAction();
} else {
help(L"");
return SnoreToastActions::Actions::Clicked;
}
}
return SnoreToastActions::Actions::Error;
}
SnoreToastActions::Actions handleEmbedded()
{
SnoreToasts::waitForCallbackActivation();
return SnoreToastActions::Actions::Clicked;
}
int WINAPI wWinMain(HINSTANCE, HINSTANCE, wchar_t *, int)
{
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
FILE *dummy;
_wfreopen_s(&dummy, L"CONOUT$", L"w", stdout);
setvbuf(stdout, nullptr, _IONBF, 0);
_wfreopen_s(&dummy, L"CONOUT$", L"w", stderr);
setvbuf(stderr, nullptr, _IONBF, 0);
std::ios::sync_with_stdio();
}
const auto commandLine = GetCommandLineW();
int argc;
wchar_t **argv = CommandLineToArgvW(commandLine, &argc);
SnoreToastActions::Actions action = SnoreToastActions::Actions::Clicked;
HRESULT hr = Initialize(RO_INIT_MULTITHREADED);
if (SUCCEEDED(hr)) {
if (std::wstring(commandLine).find(L"-Embedding") != std::wstring::npos) {
action = handleEmbedded();
} else {
action = parse(std::vector(argv, argv + argc));
}
Uninitialize();
}
return static_cast(action);
}