From 71dc17f69a75e15b31c935ce1323a269bc96ed62 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Wed, 8 Dec 2010 19:42:59 +0100
Subject: Update to new Snarl API.


diff --git a/3rdParty/Snarl/SnarlInterface.cpp b/3rdParty/Snarl/SnarlInterface.cpp
index b780140..0ae0b37 100644
--- a/3rdParty/Snarl/SnarlInterface.cpp
+++ b/3rdParty/Snarl/SnarlInterface.cpp
@@ -1,484 +1,412 @@
-// About:
-//   Snarl C++ interface implementation
-//   To understand what the different functions do and what they return, please
-//   have a look at the API on http://www.fullphat.net/dev/api.htm.
-//   Also have a look at mSnarl_i.bas found in the CVS/SVN repository for Snarl.
-//
-//   The functions in SnarlInterface both have ANSI(UTF8) and UNICODE versions.
-//   If the LPCWSTR (unicode) version of the functions are called, the strings
-//   are converted to UTF8 by SnarlInterface before sent to Snarl. So using the
-//   ANSI/UTF8/LPCSTR versions of the functions are faster!
-//   
-//
-// Difference to VB implementation:
-//   Please note that string functions return NULL when they fail and not an
-//   empty string. So check for NULL...
-//   Function names doesn't have the pre "sn".
-//
-// 
-// Authors:
-//   Written and maintained by Toke Noer N�ttrup
-//   Original C++ version by "Whitman"
-//
-// License etc. :
-//   Feel free to use this code and class as you see fit.
-//   If you improve the code, it would be nice of you to take contact to the
-//   authors, so all can get the benifit.
-//
-//   There is no guarantee that the code is correct or functional.
-//   USE AT YOUR OWN RISK
-//-----------------------------------------------------------------------------
-
-// History
-//  2008/12/31 : Implemented V39 API
-//             : Moved SnarlInterface into new Snarl namespace and moved enums etc. out of class
-//             : Added WCHAR overloads for all functions
-//  2008/08/27 : Fixed return value of IsMessageVisible and HideMessage (returns false on failure now)
-//             : Fixed critical error in the new overloaded UpdateMessage() function
-//  2008/08/27 : x64 compiler fix
-//  2008/08/24 : Renamed all functions to not have prepended "sn".
-//             : Memory allocation functions added. (Use FreeString to free strings returned by Snarl)
-//             : Added m_nLastMessageId to the class. (Use GetLastMessageId() to get it)
-//             : Overloaded a few functions, so one don't have include the message id. (UpdateMessage f.i.)
-
-//  2008/06/20 : Fixed snShowMessageEx so it actually sends the extended version - oops
-//             : Fixed compiler warning C4800: forcing value to bool 'true' or 'false' (performance warning)
-
-//  2008/05/19 : uSend and uSendEx would always set return value to M_OK on successfull call
-//  2008/04/14 : Updated to follow (what should be) the final Snarl 2.0 API
-//  2008/03/28 : Few fixes for Snarl 2.0
-//  2007/05/23 : snGetGlobalMsg & snGetSnarlWindow made static
-//  2007/03/25 : 1.6 RC1 fixup
-//  2007/03/04 : Added - snGetAppPath, snGetIconsPath, snGetVersionEx, 
-//                       snSetTimeout, uSendEx
-
+/// <summary>
+///  Snarl C++ interface implementation
+///
+///  Written and maintained by Toke Noer Nøttrup (toke@noer.it)
+///
+///  Please note the following changes compared to the VB6 (official API) dokumentation:
+///  - Function names doesn't have the prefix "sn". Naming of constants and variables are
+///    generally changed to follow Microsoft C# standard. This naming convention is kept for
+///    the C++ version, to keep them alike.
+///  - Grouped variables like SNARL_LAUNCHED, SNARL_QUIT is enums in SnarlEnums namespace.
+///  - Message events like SNARL_NOTIFICATION_CLICKED, is found in SnarlEnums::MessageEvent.
+///  - Please note that string functions return NULL when they fail and not an empty string.
+///  - Some functions in the VB API takes an appToken as first parameter. This token is a
+///    member variable in C++ version, so it is omitted from the functions.
+///    (Always call RegisterApp as first function!)
+///  - Functions manipulating messages (Update, Hide etc.) still takes a message token as
+///    parameter, but you can get the last message token calling GetLastMsgToken();
+///    Example: snarl.Hide(snarl.GetLastMsgToken());
+///
+///  The functions in SnarlInterface both have ANSI(UTF8) and UNICODE versions.
+///  If the LPCWSTR (unicode) version of the functions are called, the strings
+///  are converted to UTF8 by SnarlInterface before sent to Snarl. So using the
+///  ANSI/UTF8/LPCSTR versions of the functions are faster!
+///
+///  Funtions special to C++ V41 API compared to VB version:
+///    GetLastMsgToken()
+///    GetAppPath()
+///    GetIconsPath()
+/// </summary>
+///----------------------------------------------------------------------------
+/// <example>
+/// SnarlInterface snarl;
+/// snarl.RegisterApp(_T("CppTest"), _T("C++ test app"), NULL);
+/// snarl.AddClass(_T("Class1"), _T("Class 1"));
+/// snarl.EZNotify(_T("Class1"), _T("C++ example 1"), _T("Some text"), 10);
+/// snarl.UnregisterApp();
+///
+/// Please see the SimpleTest.cpp and SnarlV41Test.cpp for more example code.
+/// </example>
+///----------------------------------------------------------------------------
+/// <VersionHistory>
+///  2010-08-13 : First release of V41 Snarl API implementation
+/// </VersionHistory>
+
+#define _CRT_SECURE_NO_WARNINGS
 
 #include "SnarlInterface.h"
 
-using namespace Snarl;
 
+namespace Snarl {
+namespace V41 {
 
 //-----------------------------------------------------------------------------
 // Constructor/Destructor
 //-----------------------------------------------------------------------------
 SnarlInterface::SnarlInterface()
-: m_hwndFrom(NULL), m_nLastMessageId(0)
+	: appToken(0), lastMsgToken(0), localError(SnarlEnums::Success)
 {
-
 }
 
 SnarlInterface::~SnarlInterface()
 {
-
 }
 
+// ----------------------------------------------------------------------------
 
-//-----------------------------------------------------------------------------
-// snShowMessage()
-
-/// Displays a message with Title and Text. Timeout controls how long the
-/// message is displayed for (in seconds) (omitting this value means the message
-/// is displayed indefinately). IconPath specifies the location of a PNG image
-/// which will be displayed alongside the message text.
-/// <returns>Message Id on success or M_RESULT on failure</returns>
-
-LONG32 SnarlInterface::ShowMessage(LPCSTR szTitle, LPCSTR szText, LONG32 timeout, LPCSTR szIconPath, HWND hWndReply, WPARAM uReplyMsg)
+LONG32 SnarlInterface::RegisterApp(LPCSTR signature, LPCSTR title, LPCSTR icon, HWND hWndReply /* = NULL */, LONG32 msgReply /* = 0 */, SnarlEnums::AppFlags flags /* = SnarlEnums::AppDefault */)
 {
-	SNARLSTRUCT ss;
-	ZeroMemory((void*)&ss, sizeof(ss));
-
-	ss.Cmd = SNARL_SHOW;
-	StringCbCopyA((LPSTR)&ss.Title, SNARL_STRING_LENGTH, szTitle);
-	StringCbCopyA((LPSTR)&ss.Text,  SNARL_STRING_LENGTH, szText);
-	StringCbCopyA((LPSTR)&ss.Icon,  SNARL_STRING_LENGTH, szIconPath);
-	ss.Timeout = timeout;
+	SnarlMessage msg;
+	msg.Command = SnarlEnums::RegisterApp;
+	msg.Token = 0;
+	PackData(msg.PacketData, 
+		"id::%s#?title::%s#?icon::%s#?hwnd::%d#?umsg::%d#?flags::%d", 
+		signature, title, icon, hWndReply, msgReply, flags);
 
-	ss.LngData2 = reinterpret_cast<LONG32>(hWndReply);
-	ss.Id = static_cast<LONG32>(uReplyMsg);
+	appToken = Send(msg);
+	lastMsgToken = 0;
 
-	m_nLastMessageId = Send(ss);
-	return m_nLastMessageId;
+	return appToken;
 }
 
-LONG32 SnarlInterface::ShowMessage(LPCWSTR szTitle, LPCWSTR szText, LONG32 timeout, LPCWSTR szIconPath, HWND hWndReply, WPARAM uReplyMsg)
+LONG32 SnarlInterface::RegisterApp(LPCWSTR signature, LPCWSTR title, LPCWSTR icon, HWND hWndReply /* = NULL */, LONG32 msgReply /* = 0 */, SnarlEnums::AppFlags flags /* = SnarlEnums::AppDefault */)
 {
-	LPSTR szUTF8Title = WideToUTF8(szTitle);
-	LPSTR szUTF8Text  = WideToUTF8(szText);
-	LPSTR szUFT8IconPath = WideToUTF8(szIconPath);
+	LPCSTR szParam1 = WideToUTF8(signature);
+	LPCSTR szParam2 = WideToUTF8(title);
+	LPCSTR szParam3 = WideToUTF8(icon);
 	
-	LONG32 result = ShowMessage(szUTF8Title, szUTF8Text, timeout, szUFT8IconPath, hWndReply, uReplyMsg);
-	
-	delete [] szUTF8Title;
-	delete [] szUTF8Text;
-	delete [] szUFT8IconPath;
+	LONG32 result = RegisterApp(szParam1, szParam2, szParam3, hWndReply, msgReply, flags);
 	
+	delete [] szParam1;
+	delete [] szParam2;
+	delete [] szParam3;
+
 	return result;
 }
-	
-//-----------------------------------------------------------------------------
-// snShowMessageEx()
-
-/// Displays a notification. This function is identical to snShowMessage()
-/// except that Class specifies an alert previously registered with
-/// snRegisterAlert() and SoundFile can optionally specify a WAV sound to play
-/// when the notification is displayed on screen.
 
-/// <returns>Message Id on success or M_RESULT on failure</returns>
-
-LONG32 SnarlInterface::ShowMessageEx(LPCSTR szClass, LPCSTR szTitle, LPCSTR szText, LONG32 timeout, LPCSTR szIconPath, HWND hWndReply, WPARAM uReplyMsg, LPCSTR szSoundFile)
+LONG32 SnarlInterface::UnregisterApp()
 {
-	SNARLSTRUCTEX ssex;
-	ZeroMemory((void*)&ssex, sizeof(ssex));
-
-	ssex.Cmd = SNARL_EX_SHOW;
-	ssex.Timeout = timeout;
-	ssex.LngData2 = reinterpret_cast<LONG32>(hWndReply);
-	ssex.Id = static_cast<LONG32>(uReplyMsg);
+	SnarlMessage msg;
+	msg.Command = SnarlEnums::UnregisterApp;
+	msg.Token = appToken;
+	PackData(msg.PacketData, NULL);
 
-	StringCbCopyA((LPSTR)&ssex.Class, SNARL_STRING_LENGTH, szClass);
-	StringCbCopyA((LPSTR)&ssex.Title, SNARL_STRING_LENGTH, szTitle);
-	StringCbCopyA((LPSTR)&ssex.Text,  SNARL_STRING_LENGTH, szText);
-	StringCbCopyA((LPSTR)&ssex.Icon,  SNARL_STRING_LENGTH, szIconPath);
-	StringCbCopyA((LPSTR)&ssex.Extra, SNARL_STRING_LENGTH, szSoundFile);
+	appToken = 0;
+	lastMsgToken = 0;
 
-	m_nLastMessageId = Send(ssex);
-	return m_nLastMessageId;
+	return Send(msg);
 }
 
-LONG32 SnarlInterface::ShowMessageEx(LPCWSTR szClass, LPCWSTR szTitle, LPCWSTR szText, LONG32 timeout, LPCWSTR szIconPath, HWND hWndReply, WPARAM uReplyMsg, LPCWSTR szSoundFile)
+LONG32 SnarlInterface::UpdateApp(LPCSTR title /* = NULL */, LPCSTR icon /* = NULL */)
 {
-	LPSTR szUTF8Class = WideToUTF8(szClass);
-	LPSTR szUTF8Title = WideToUTF8(szTitle);
-	LPSTR szUTF8Text  = WideToUTF8(szText);
-	LPSTR szUFT8IconPath = WideToUTF8(szIconPath);
-	LPSTR szUFT8SoundFile = WideToUTF8(szSoundFile);
-	
-	LONG32 result = ShowMessageEx(szUTF8Class, szUTF8Title, szUTF8Text, timeout, szUFT8IconPath, hWndReply, uReplyMsg, szUFT8SoundFile);
+	if (title == NULL && icon == NULL)
+		return 0;
+
+	SnarlMessage msg;
+	msg.Command = SnarlEnums::UpdateApp;
+	msg.Token = appToken;
 	
-	delete [] szUTF8Class;
-	delete [] szUTF8Title;
-	delete [] szUTF8Text;
-	delete [] szUFT8IconPath;
-	delete [] szUFT8SoundFile;
+	// TODO: Uckly code ahead
+	if (title != NULL && title[0] != 0 && icon != NULL && icon[0] != 0)
+		PackData(msg.PacketData, "title::%s#?icon::%s", title, icon);
+	else if (title != NULL && title[0] != 0)
+		PackData(msg.PacketData, "title::%s", title);
+	else if (icon != NULL && icon[0] != 0)
+		PackData(msg.PacketData, "icon::%s", icon);
 	
-	return result;
+	return Send(msg);
 }
 
-//-----------------------------------------------------------------------------
-// snHideMessage()
-
-/// Hides the notification specified by Id. Id is the value returned by
-/// snShowMessage() or snShowMessageEx() when the notification was initially
-/// created. This function returns True if the notification was successfully
-/// hidden or False otherwise (for example, the notification may no longer exist).
-
-BOOL SnarlInterface::HideMessage(LONG32 Id)
+LONG32 SnarlInterface::UpdateApp(LPCWSTR title /* = NULL */, LPCWSTR icon /* = NULL */)
 {
-	SNARLSTRUCT ss;
-	ss.Cmd = SNARL_HIDE;
-	ss.Id = Id;
+	LPCSTR szParam1 = WideToUTF8(title);
+	LPCSTR szParam2 = WideToUTF8(icon);
+	
+	LONG32 result = UpdateApp(szParam1, szParam2);
+	
+	delete [] szParam1;
+	delete [] szParam2;
 
-	LONG32 n = Send(ss);
-	return (n == -1 || n == 1) ? TRUE : FALSE;
+	return result;
 }
 
-BOOL SnarlInterface::HideMessage()
+LONG32 SnarlInterface::AddClass(LPCSTR className, LPCSTR description, bool enabled /* = true */)
 {
-	return HideMessage(m_nLastMessageId);
-}
-
-//-----------------------------------------------------------------------------
-// snIsMessageVisible()
-
-/// Returns True if the notification specified by Id is still visible, or
-/// False if not. Id is the value returned by snShowMessage() or
-/// snShowMessageEx() when the notification was initially created.
+	SnarlMessage msg;
+	msg.Command = SnarlEnums::AddClass;
+	msg.Token = appToken;
+	PackData(msg.PacketData, "id::%s#?name::%s#?enabled::%d", className, description, (enabled ? 1 : 0));
 
-BOOL SnarlInterface::IsMessageVisible(LONG32 Id)
-{
-	SNARLSTRUCT ss;
-	ss.Cmd = SNARL_IS_VISIBLE;
-	ss.Id = Id;
-
-	// We are getting -1 when true, checking for 1 just in case. We don't want to return true for the other M_RESULT returns
-	LONG32 n = Send(ss);	
-	return (n == -1 || n == 1) ? TRUE : FALSE;
+	return Send(msg);
 }
 
-BOOL SnarlInterface::IsMessageVisible()
+LONG32 SnarlInterface::AddClass(LPCWSTR className, LPCWSTR description, bool enabled /* = true */)
 {
-	if (m_nLastMessageId == 0)
-		return FALSE;
+	LPCSTR szParam1 = WideToUTF8(className);
+	LPCSTR szParam2 = WideToUTF8(description);
+	
+	LONG32 result = AddClass(szParam1, szParam2, enabled);
+	
+	delete [] szParam1;
+	delete [] szParam2;
 
-	return IsMessageVisible(m_nLastMessageId);
+	return result;
 }
 
-//-----------------------------------------------------------------------------
-// snUpdateMessage()
-
-/// Changes the title and text in the message specified by Id to the values
-/// specified by Title and Text respectively. Id is the value returned by 
-/// snShowMessage() or snShowMessageEx() when the notification was originally
-/// created. To change the timeout parameter of a notification, use snSetTimeout()
-
-M_RESULT SnarlInterface::UpdateMessage(LONG32 id, LPCSTR szTitle, LPCSTR szText, LPCSTR szIconPath)
+LONG32 SnarlInterface::RemoveClass(LPCSTR className, bool forgetSettings /* = false */)
 {
-	SNARLSTRUCT ss;
-	ZeroMemory((void*)&ss, sizeof(ss));
-
-	ss.Cmd = SNARL_UPDATE;
-	ss.Id = id;
-	
-	StringCbCopyA((LPSTR)&ss.Title, SNARL_STRING_LENGTH, szTitle);
-	StringCbCopyA((LPSTR)&ss.Text,  SNARL_STRING_LENGTH, szText);
-	StringCbCopyA((LPSTR)&ss.Icon,  SNARL_STRING_LENGTH, szIconPath);
+	SnarlMessage msg;
+	msg.Command = SnarlEnums::RemoveClass;
+	msg.Token = appToken;
+	PackData(msg.PacketData, "id::%s#?forget::%d", className, (forgetSettings ? 1 : 0));
 
-	return static_cast<M_RESULT>(Send(ss));
+	return Send(msg);
 }
 
-M_RESULT SnarlInterface::UpdateMessage(LONG32 id, LPCWSTR szTitle, LPCWSTR szText, LPCWSTR szIconPath)
+LONG32 SnarlInterface::RemoveClass(LPCWSTR className, bool forgetSettings /* = false */)
 {
-	LPSTR szParam1 = WideToUTF8(szTitle);
-	LPSTR szParam2 = WideToUTF8(szText);
-	LPSTR szParam3 = WideToUTF8(szIconPath);
+	LPCSTR szParam1 = WideToUTF8(className);
 	
-	M_RESULT result = UpdateMessage(id, szParam1, szParam2, szParam3);
+	LONG32 result = RemoveClass(szParam1, forgetSettings);
 	
 	delete [] szParam1;
-	delete [] szParam2;
-	delete [] szParam3;
-	
+
 	return result;
 }
 
-M_RESULT SnarlInterface::UpdateMessage(LPCSTR szTitle, LPCSTR szText, LPCSTR szIconPath)
+LONG32 SnarlInterface::RemoveAllClasses(bool forgetSettings /* = false */)
 {
-	return UpdateMessage(m_nLastMessageId, szTitle, szText, szIconPath);
-}
+	SnarlMessage msg;
+	msg.Command = SnarlEnums::RemoveClass;
+	msg.Token = appToken;
+	PackData(msg.PacketData, "all::1#?forget::%d", (forgetSettings ? 1 : 0));
 
-M_RESULT SnarlInterface::UpdateMessage(LPCWSTR szTitle, LPCWSTR szText, LPCWSTR szIconPath)
-{
-	return UpdateMessage(m_nLastMessageId, szTitle, szText, szIconPath);
+	return Send(msg);
 }
 
-//-----------------------------------------------------------------------------
-// snRegisterConfig
-
-/// Registers an application's configuration interface with Snarl.
-/// AppName is the text that's displayed in the Applications list so it should
-/// be people friendly ("My cool app" rather than "my_cool_app").
-
-M_RESULT SnarlInterface::RegisterConfig(HWND hWnd, LPCSTR szAppName, LONG32 replyMsg)
+LONG32 SnarlInterface::EZNotify(LPCSTR className, LPCSTR title, LPCSTR text, LONG32 timeout /* = -1 */, LPCSTR icon /* = NULL */, LONG32 priority /* = 0 */, LPCSTR acknowledge /* = NULL */, LPCSTR value /* = NULL */)
 {
-	return RegisterConfig2(hWnd, szAppName, replyMsg, "");
-}
+	SnarlMessage msg;
+	msg.Command = SnarlEnums::Notify;
+	msg.Token = appToken;
+	PackData(msg.PacketData,
+		"id::%s#?title::%s#?text::%s#?timeout::%d#?icon::%s#?priority::%d#?ack::%s#?value::%s",
+		className, title, text, timeout, (icon ? icon : ""), priority, (acknowledge ? acknowledge : ""), (value ? value : ""));
 
-M_RESULT SnarlInterface::RegisterConfig(HWND hWnd, LPCWSTR szAppName, LONG32 replyMsg)
-{
-	return RegisterConfig2(hWnd, szAppName, replyMsg, L"");
+	lastMsgToken = Send(msg);
+	return lastMsgToken;
 }
 
-//-----------------------------------------------------------------------------
-// snRegisterConfig2
-
-/// Registers an application's configuration interface with Snarl.
-/// This function is identical to snRegisterConfig() except that Icon can be
-/// used to specify a PNG image which will be displayed against the
-/// application's entry in Snarl's Preferences panel.
-
-M_RESULT SnarlInterface::RegisterConfig2(HWND hWnd, LPCSTR szAppName, LONG32 replyMsg, LPCSTR szIcon)
+LONG32 SnarlInterface::EZNotify(LPCWSTR className, LPCWSTR title, LPCWSTR text, LONG32 timeout /* = -1 */, LPCWSTR icon /* = NULL */, LONG32 priority /* = 0 */, LPCWSTR acknowledge /* = NULL */, LPCWSTR value /* = NULL */)
 {
-	if (!szAppName || !szIcon)
-		return M_BAD_POINTER;
-
-	SNARLSTRUCT ss;
+	LPCSTR szParam1 = WideToUTF8(className);
+	LPCSTR szParam2 = WideToUTF8(title);
+	LPCSTR szParam3 = WideToUTF8(text);
+	LPCSTR szParam4 = WideToUTF8(icon);
+	LPCSTR szParam5 = WideToUTF8(acknowledge);
+	LPCSTR szParam6 = WideToUTF8(value);
+	
+	LONG32 result = EZNotify(szParam1, szParam2, szParam3, timeout, szParam4, priority, szParam5, szParam6);
+	
+	delete [] szParam1; delete [] szParam2; delete [] szParam3;
+	delete [] szParam4; delete [] szParam5; delete [] szParam6;
 
-	m_hwndFrom = hWnd;
+	return result;
+}
 
-	ss.Cmd = SNARL_REGISTER_CONFIG_WINDOW_2;
-	ss.LngData2 = reinterpret_cast<LONG32>(hWnd);
-	ss.Id = replyMsg;
-	StringCbCopyA((LPSTR)&ss.Title, SNARL_STRING_LENGTH, szAppName);
-	StringCbCopyA((LPSTR)&ss.Icon, SNARL_STRING_LENGTH, szIcon);
+LONG32 SnarlInterface::Notify(LPCSTR className, LPCSTR packetData)
+{
+	SnarlMessage msg;
+	msg.Command = SnarlEnums::Notify;
+	msg.Token = appToken;
+	PackData(msg.PacketData, "id::%s#?%s", className, packetData);
 
-	return static_cast<M_RESULT>(Send(ss));
+	lastMsgToken = Send(msg);
+	return lastMsgToken;
 }
 
-M_RESULT SnarlInterface::RegisterConfig2(HWND hWnd, LPCWSTR szAppName, LONG32 replyMsg, LPCWSTR szIcon)
+LONG32 SnarlInterface::Notify(LPCWSTR className, LPCWSTR packetData)
 {
-	LPSTR szParam1 = WideToUTF8(szAppName);
-	LPSTR szParam2 = WideToUTF8(szIcon);
-	
-	M_RESULT result = RegisterConfig2(hWnd, szParam1, replyMsg, szParam2);
+	LPCSTR szParam1 = WideToUTF8(className);
+	LPCSTR szParam2 = WideToUTF8(packetData);
+
+	LONG32 result = Notify(szParam1, szParam2);
 	
-	delete [] szParam1;
-	delete [] szParam2;
+	delete [] szParam1; delete [] szParam2;
 	
 	return result;
 }
 
-
-//-----------------------------------------------------------------------------
-// snRevokeConfig
-
-/// Removes the application previously registered using snRegisterConfig() or
-/// snRegisterConfig2(). hWnd should be the same as that used during registration.
-
-M_RESULT SnarlInterface::RevokeConfig(HWND hWnd)
+LONG32 SnarlInterface::EZUpdate(LONG32 msgToken, LPCSTR title /* = NULL */, LPCSTR text /* = NULL */, LONG32 timeout /* = -1 */, LPCSTR icon /* = NULL */)
 {
-	SNARLSTRUCT ss;
+	SnarlMessage msg;
+	msg.Command = SnarlEnums::UpdateNotification;
+	msg.Token = msgToken;
 	
-	m_hwndFrom = NULL;
+	// Create packed data
+	errno_t err = 0;
+	ZeroMemory(msg.PacketData, sizeof(msg.PacketData));
+	char* pData = reinterpret_cast<char*>(msg.PacketData);
 
-	ss.Cmd = SNARL_REVOKE_CONFIG_WINDOW;
-	ss.LngData2 = reinterpret_cast<LONG32>(hWnd);
+	if (title != NULL) {
+		err |= strncat_s(pData, SnarlPacketDataSize, (pData[0] != NULL) ? "#?title::" : "title::", _TRUNCATE); //StringCbCat(tmp, SnarlPacketDataSize, "title::%s");
+		err |= strncat_s(pData, SnarlPacketDataSize, title, _TRUNCATE);
+	}
+	if (text != NULL) {
+		err |= strncat_s(pData, SnarlPacketDataSize, (pData[0] != NULL) ? "#?text::" : "text::", _TRUNCATE);
+		err |= strncat_s(pData, SnarlPacketDataSize, text, _TRUNCATE);
+	}
+	if (icon != NULL) {
+		err |= strncat_s(pData, SnarlPacketDataSize, (pData[0] != NULL) ? "#?icon::" : "icon::", _TRUNCATE);
+		err |= strncat_s(pData, SnarlPacketDataSize, icon, _TRUNCATE);
+	}
+	if (timeout != -1) {
+		char tmp[32];
+		_itoa_s(timeout, tmp, 10);
+		
+		err |= strncat_s(pData, SnarlPacketDataSize, (pData[0] != NULL) ? "#?timeout::" : "timeout::", _TRUNCATE);
+		err |= strncat_s(pData, SnarlPacketDataSize, tmp, _TRUNCATE);
+	}
+	
+	// Check for strcat errors and exit on error
+	if (err != 0) {
+		localError = SnarlEnums::ErrorFailed;
+		return 0;
+	}
 
-	return static_cast<M_RESULT>(Send(ss));
+	return Send(msg);
 }
 
-
-//-----------------------------------------------------------------------------
-// snGetVersion()
-
-/// Checks if Snarl is currently running and, if it is, retrieves the major and
-/// minor release version numbers in Major and Minor respectively.
-/// Returns True if Snarl is running, False otherwise.
-
-BOOL SnarlInterface::GetVersion(WORD* Major, WORD* Minor)
+LONG32 SnarlInterface::EZUpdate(LONG32 msgToken, LPCWSTR title /* = NULL */, LPCWSTR text /* = NULL */, LONG32 timeout /* = -1 */, LPCWSTR icon /* = NULL */)
 {
-	SNARLSTRUCT ss;
-	ss.Cmd = SNARL_GET_VERSION;
-	LONG32 versionInfo = Send(ss);
-	if (versionInfo > 0 && versionInfo != M_FAILED && versionInfo != M_TIMED_OUT) {
-		*Major = HIWORD(versionInfo);
-		*Minor = LOWORD(versionInfo);
-		return TRUE;
-	}
-	return FALSE;
-}
+	LPCSTR szParam1 = WideToUTF8(title);
+	LPCSTR szParam2 = WideToUTF8(text);
+	LPCSTR szParam3 = WideToUTF8(icon);
 
+	LONG32 result = EZUpdate(msgToken, szParam1, szParam2, timeout, szParam3);
+	
+	delete [] szParam1; delete [] szParam2; delete [] szParam3;
+	
+	return result;
+}
 
-//-----------------------------------------------------------------------------
-// snGetVersionEx
+LONG32 SnarlInterface::Update(LONG32 msgToken, LPCSTR packetData)
+{
+	SnarlMessage msg;
+	msg.Command = SnarlEnums::UpdateNotification;
+	msg.Token = msgToken;
+	PackData(msg.PacketData, packetData);
 
-/// Returns the Snarl system version number. This is an integer value which
-/// represents the system build number and can be used to identify the specific
-/// version of Snarl running
+	return Send(msg);
+}
 
-LONG32 SnarlInterface::GetVersionEx()
+LONG32 SnarlInterface::Update(LONG32 msgToken, LPCWSTR packetData)
 {
-	SNARLSTRUCT ss;
-	ss.Cmd = SNARL_GET_VERSION_EX;
-	return Send(ss);
-}
+	LPCSTR szParam1 = WideToUTF8(packetData);
 
+	LONG32 result = Update(msgToken, szParam1);
+	
+	delete [] szParam1;
+	
+	return result;
+}
 
-//-----------------------------------------------------------------------------
-// snSetTimeout()
+LONG32 SnarlInterface::Hide(LONG32 msgToken)
+{
+	SnarlMessage msg;
+	msg.Command = SnarlEnums::HideNotification;
+	msg.Token = msgToken;
+	PackData(msg.PacketData, NULL);
 
-/// Sets the timeout of existing notification Id to Timeout seconds. Id is the
-/// value returned by snShowMessage() or snShowMessageEx() when the notification
-/// was first created. 
+	return Send(msg);
+}
 
-M_RESULT SnarlInterface::SetTimeout(LONG32 Id, LONG32 Timeout)
+LONG32 SnarlInterface::IsVisible(LONG32 msgToken)
 {
-	SNARLSTRUCT ss;
-	ss.Cmd = SNARL_SET_TIMEOUT;
-	ss.Id = Id;
-	ss.LngData2 = Timeout;
+	SnarlMessage msg;
+	msg.Command = SnarlEnums::IsNotificationVisible;
+	msg.Token = msgToken;
+	PackData(msg.PacketData, NULL);
 
-	return static_cast<M_RESULT>(Send(ss));
+	return Send(msg);
 }
 
-M_RESULT SnarlInterface::SetTimeout(LONG32 Timeout)
+SnarlEnums::SnarlStatus SnarlInterface::GetLastError()
 {
-	return SetTimeout(m_nLastMessageId, Timeout);
+	return localError;
 }
 
-//-----------------------------------------------------------------------------
-// snRegisterAlert()
-
-/// Registers an alert of Class for application AppName which must have previously
-/// been registered with either snRegisterConfig() or snRegisterConfig2().
-
-M_RESULT SnarlInterface::RegisterAlert(LPCSTR szAppName, LPCSTR szClass)
+// static
+BOOL SnarlInterface::IsSnarlRunning()
 {
-	SNARLSTRUCT ss;
-	ss.Cmd = SNARL_REGISTER_ALERT;
-	StringCbCopyA((LPSTR)&ss.Title, SNARL_STRING_LENGTH, szAppName);
-	StringCbCopyA((LPSTR)&ss.Text, SNARL_STRING_LENGTH, szClass);
-
-	return static_cast<M_RESULT>(Send(ss));
+	return IsWindow(GetSnarlWindow());
 }
 
-M_RESULT SnarlInterface::RegisterAlert(LPCWSTR szAppName, LPCWSTR szClass)
+LONG32 SnarlInterface::GetVersion()
 {
-	LPSTR szParam1 = WideToUTF8(szAppName);
-	LPSTR szParam2 = WideToUTF8(szClass);
-	
-	M_RESULT result = RegisterAlert(szParam1, szParam2);
-	
-	delete [] szParam1;
-	delete [] szParam2;
-	
-	return result;
-}
+	localError = SnarlEnums::Success;
 
-//-----------------------------------------------------------------------------
-// snGetGlobalMsg()
+	HWND hWnd = GetSnarlWindow();
+	if (!IsWindow(hWnd))
+	{
+		localError = SnarlEnums::ErrorNotRunning;
+		return 0;
+	}
 
-/// Returns the atom that corresponds to the "SnarlGlobalEvent" registered
-/// Windows message. This message is sent by Snarl when it is first starts and
-/// when it shuts down.
+	HANDLE hProp = GetProp(hWnd, _T("_version"));
+	return reinterpret_cast<int>(hProp);
+}
 
-LONG32 SnarlInterface::GetGlobalMsg()
+// static
+UINT SnarlInterface::Broadcast()
 {
-	return RegisterWindowMessage(SNARL_GLOBAL_MSG);
+	return RegisterWindowMessage(SnarlGlobalMsg);
 }
 
+// static
+UINT SnarlInterface::AppMsg()
+{
+	return RegisterWindowMessage(SnarlAppMsg);
+}
 
-//-----------------------------------------------------------------------------
-// snGetSnarlWindow
-
+// static
 HWND SnarlInterface::GetSnarlWindow()
 {
-	return FindWindow(NULL, _T("Snarl"));
+	return FindWindow(SnarlWindowClass, SnarlWindowTitle);;
 }
 
-
-//-----------------------------------------------------------------------------
-// snGetAppPath()
-
-/// Returns a pointer to the path.
-/// ** Remember to call FreeString
-
 LPCTSTR SnarlInterface::GetAppPath()
 {
 	HWND hWnd = GetSnarlWindow();
 	if (hWnd)
 	{
-		HWND hWndPath = FindWindowEx(hWnd, 0, _T("static"), NULL);
+		HWND hWndPath = FindWindowEx(hWnd, NULL, _T("static"), NULL);
 		if (hWndPath)
 		{
 			TCHAR strTmp[MAX_PATH] = {0};
-			int nReturn = GetWindowText(hWndPath, strTmp, MAX_PATH);
+			int nReturn = GetWindowText(hWndPath, strTmp, MAX_PATH-1);
 			if (nReturn > 0) {
 				TCHAR* strReturn = AllocateString(nReturn + 1);
-				StringCchCopy(strReturn, nReturn + 1, strTmp);
+				_tcsncpy(strReturn, strTmp, nReturn + 1);
+				strReturn[nReturn] = 0;
 				return strReturn;
 			}
 		}
 	}
+
 	return NULL;
 }
 
-
-//-----------------------------------------------------------------------------
-// snGetIconsPath()
-
-/// Returns a pointer to the iconpath.
-/// ** Remember to call FreeString when done with the string
-
 LPCTSTR SnarlInterface::GetIconsPath()
 {
 	TCHAR* szIconPath = NULL;
@@ -487,13 +415,14 @@ LPCTSTR SnarlInterface::GetIconsPath()
 		return NULL;
 
 	size_t nLen = 0;
-	if (SUCCEEDED(StringCbLength(szPath, MAX_PATH, &nLen)))
+	// TODO: _tcsnlen MAX_PATH
+	if (nLen = _tcsnlen(szPath, MAX_PATH))
 	{
 		nLen += 10 + 1; // etc\\icons\\ + NULL
 		szIconPath = AllocateString(nLen);
 
-		StringCbCopy(szIconPath, nLen * sizeof(TCHAR), szPath);
-		StringCbCat(szIconPath, nLen * sizeof(TCHAR), _T("etc\\icons\\"));
+		_tcsncpy(szIconPath, szPath, nLen);
+		_tcsncat(szIconPath, _T("etc\\icons\\"), nLen);
 	}
 	
 	FreeString(szPath);
@@ -501,312 +430,88 @@ LPCTSTR SnarlInterface::GetIconsPath()
 	return szIconPath;
 }
 
-
-//-----------------------------------------------------------------------------
-// snSetAsSnarlApp()
-
-/// Identifies an application as a Snarl App.  (V39)
-
-void SnarlInterface::SetAsSnarlApp(HWND hWndOwner, SNARL_APP_FLAGS Flags)
+LONG32 SnarlInterface::GetLastMsgToken() const
 {
-	if (IsWindow(hWndOwner)) {
-		SetProp(hWndOwner, _T("snarl_app"), reinterpret_cast<HANDLE>(1));
-		SetProp(hWndOwner, _T("snarl_app_flags"), reinterpret_cast<HANDLE>(Flags));
-	}
+	return lastMsgToken;
 }
 
 
 //-----------------------------------------------------------------------------
-// snGetAppMsg()
-
-/// Returns the global Snarl Application message  (V39)
-
-LONG32 SnarlInterface::GetAppMsg()
-{
-	return RegisterWindowMessage(SNARL_APP_MSG);
-}
-
-
-//-----------------------------------------------------------------------------
-// snRegisterApp()
-
-/// Registers an application with Snarl  (V39)
-
-M_RESULT SnarlInterface::RegisterApp(LPCSTR Application, LPCSTR SmallIcon, LPCSTR LargeIcon, HWND hWnd, LONG32 ReplyMsg)
-{
-	m_hwndFrom = hWnd;
-	  
-    SNARLSTRUCT ss;
-	ss.Cmd = SNARL_REGISTER_APP;
-	
-	StringCbCopyA((LPSTR)&ss.Title, SNARL_STRING_LENGTH, Application);
-	StringCbCopyA((LPSTR)&ss.Icon,  SNARL_STRING_LENGTH, SmallIcon);
-	StringCbCopyA((LPSTR)&ss.Text,  SNARL_STRING_LENGTH, LargeIcon);
-
-	ss.LngData2 = reinterpret_cast<LONG32>(hWnd);
-	ss.Id = ReplyMsg;
-	ss.Timeout = GetCurrentProcessId();
-
-	return static_cast<M_RESULT>(Send(ss));
-}
-
-M_RESULT SnarlInterface::RegisterApp(LPCWSTR Application, LPCWSTR SmallIcon, LPCWSTR LargeIcon, HWND hWnd, LONG32 ReplyMsg)
-{
-	LPSTR szParam1 = WideToUTF8(Application);
-	LPSTR szParam2 = WideToUTF8(SmallIcon);
-	LPSTR szParam3 = WideToUTF8(LargeIcon);
-	
-	M_RESULT result = RegisterApp(szParam1, szParam2, szParam3, hWnd, ReplyMsg);
-	
-	delete [] szParam1;
-	delete [] szParam2;
-	delete [] szParam3;
-	
-	return result;
-}
-
-
+// Private functions 
 //-----------------------------------------------------------------------------
-// snUnregisterApp()
-
-/// Unregisters an application with Snarl  (V39)
 
-M_RESULT SnarlInterface::UnregisterApp()
+LONG32 SnarlInterface::Send(SnarlMessage msg)
 {
-	SNARLSTRUCT ss;
-	ss.Cmd = SNARL_UNREGISTER_APP;
-	ss.LngData2 = GetCurrentProcessId();
-	
-	m_hwndFrom = NULL;
-	
-	return static_cast<M_RESULT>(Send(ss));
-}
-
+	DWORD_PTR nReturn = 0; // Failure
 
-//-----------------------------------------------------------------------------
-// snShowNotification()
-
-/// Displays a Snarl notification using registered class  (V39)
-/// <returns>Message Id on success or M_RESULT on failure</returns>
-
-LONG32 SnarlInterface::ShowNotification(LPCSTR Class, LPCSTR Title, LPCSTR Text, LONG32 Timeout, LPCSTR Icon, HWND hWndReply, LONG32 uReplyMsg, LPCSTR Sound)
-{
-	SNARLSTRUCTEX ssex;
-	ssex.Cmd = SNARL_SHOW_NOTIFICATION;
-	
-	StringCbCopyExA((LPSTR)&ssex.Title, SNARL_STRING_LENGTH, Title, NULL, NULL, STRSAFE_IGNORE_NULLS);
-	StringCbCopyExA((LPSTR)&ssex.Text,  SNARL_STRING_LENGTH, Text,  NULL, NULL, STRSAFE_IGNORE_NULLS);
-	StringCbCopyExA((LPSTR)&ssex.Icon,  SNARL_STRING_LENGTH, Icon,  NULL, NULL, STRSAFE_IGNORE_NULLS);
-
-	ssex.Timeout = Timeout;
-	ssex.LngData2 = reinterpret_cast<LONG32>(hWndReply);
-	ssex.Id = uReplyMsg;
-
-	StringCbCopyExA((LPSTR)&ssex.Extra, SNARL_STRING_LENGTH, Sound, NULL, NULL, STRSAFE_IGNORE_NULLS);
-	StringCbCopyA((LPSTR)&ssex.Class,  SNARL_STRING_LENGTH, Class);
-    
-	ssex.Reserved1 = GetCurrentProcessId();
-	
-	m_nLastMessageId = Send(ssex);
-	return m_nLastMessageId;
-}
-
-LONG32 SnarlInterface::ShowNotification(LPCWSTR Class, LPCWSTR Title, LPCWSTR Text, LONG32 Timeout, LPCWSTR Icon, HWND hWndReply, LONG32 uReplyMsg, LPCWSTR Sound)
-{
-	LPSTR szParam1 = WideToUTF8(Class);
-	LPSTR szParam2 = WideToUTF8(Title);
-	LPSTR szParam3 = WideToUTF8(Text);
-	LPSTR szParam4 = WideToUTF8(Icon);
-	LPSTR szParam5 = WideToUTF8(Sound);
-	
-	LONG32 result = ShowNotification(szParam1, szParam2, szParam3, Timeout, szParam4, hWndReply, uReplyMsg, szParam5);
-	
-	delete [] szParam1;
-	delete [] szParam2;
-	delete [] szParam3;
-	delete [] szParam4;
-	delete [] szParam5;
-	
-	return result;
-}
-
-
-//-----------------------------------------------------------------------------
-// snChangeAttribute()
-
-/// (V39)
+	HWND hWnd = GetSnarlWindow();
+	if (!IsWindow(hWnd))
+	{
+		localError = SnarlEnums::ErrorNotRunning;
+		return 0;
+	}
 
-M_RESULT SnarlInterface::ChangeAttribute(LONG32 Id, SNARL_ATTRIBUTES Attr, LPCSTR Value)
-{
-	SNARLSTRUCT ss;
-	ss.Cmd = SNARL_CHANGE_ATTR;
-	ss.Id = Id;
-	ss.LngData2 = Attr;
-	
-	StringCbCopyExA((LPSTR)&ss.Text, SNARL_STRING_LENGTH, Value, NULL, NULL, STRSAFE_IGNORE_NULLS);
-	
-	return static_cast<M_RESULT>(Send(ss));
-}
+	COPYDATASTRUCT cds;
+	cds.dwData = 0x534E4C02; // "SNL",2;
+	cds.cbData = sizeof(SnarlMessage);
+	cds.lpData = &msg;
 
-M_RESULT SnarlInterface::ChangeAttribute(LONG32 Id, SNARL_ATTRIBUTES Attr, LPCWSTR Value)
-{
-	LPSTR szParam1 = WideToUTF8(Value);
-	
-	M_RESULT result = ChangeAttribute(Id, Attr, szParam1);
-	
-	delete [] szParam1;
-	
-	return result;
-}
+	if (SendMessageTimeout(hWnd, WM_COPYDATA, (WPARAM)GetCurrentProcessId(), (LPARAM)&cds, SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG, 500, &nReturn) == 0)
+	{
+		// return zero on failure
+		if (GetLastError() == ERROR_TIMEOUT)
+			localError = SnarlEnums::ErrorTimedOut;
+		else
+			localError = SnarlEnums::ErrorFailed;
+		
+		return 0;
+	}
 
-M_RESULT SnarlInterface::ChangeAttribute(SNARL_ATTRIBUTES Attr, LPCSTR Value)
-{
-	return ChangeAttribute(m_nLastMessageId, Attr, Value);
-}
+	// return result and cache LastError
+	HANDLE hProp = GetProp(hWnd, _T("last_error"));
+	localError = static_cast<SnarlEnums::SnarlStatus>(reinterpret_cast<int>(hProp));
 
-M_RESULT SnarlInterface::ChangeAttribute(SNARL_ATTRIBUTES Attr, LPCWSTR Value)
-{
-	return ChangeAttribute(m_nLastMessageId, Attr, Value);
+	return nReturn;
 }
 
-
 //-----------------------------------------------------------------------------
-// snSetClassDefault()
 
-/// Sets the default value for an alert class  (V39)
-
-M_RESULT SnarlInterface::SetClassDefault(LPCSTR Class, SNARL_ATTRIBUTES Attr, LPCSTR Value)
+// Remember to delete [] returned string
+inline
+LPSTR SnarlInterface::WideToUTF8(LPCWSTR szWideStr)
 {
-	SNARLSTRUCT ss;
-	ss.Cmd = SNARL_SET_CLASS_DEFAULT;
-	ss.LngData2 = Attr;
-	ss.Timeout = GetCurrentProcessId();
-	
-	StringCbCopyExA((LPSTR)&ss.Text, SNARL_STRING_LENGTH, Class, NULL, NULL, STRSAFE_IGNORE_NULLS);
-	StringCbCopyExA((LPSTR)&ss.Icon, SNARL_STRING_LENGTH, Value, NULL, NULL, STRSAFE_IGNORE_NULLS);
-
-	return static_cast<M_RESULT>(Send(ss));
-}
+	if (szWideStr == NULL)
+		return NULL;
 
-M_RESULT SnarlInterface::SetClassDefault(LPCWSTR Class, SNARL_ATTRIBUTES Attr, LPCWSTR Value)
-{
-	LPSTR szParam1 = WideToUTF8(Class);
-	LPSTR szParam2 = WideToUTF8(Value);
+	int nSize = WideCharToMultiByte(CP_UTF8, 0, szWideStr, -1, NULL, 0, NULL, NULL);
+	LPSTR szUTF8 = new char[nSize];
+	WideCharToMultiByte(CP_UTF8, 0, szWideStr, -1, szUTF8, nSize, NULL, NULL);
 	
-	M_RESULT result = SetClassDefault(szParam1, Attr, szParam2);
-	
-	delete [] szParam1;
-	delete [] szParam2;
-	
-	return result;
-}
-
-
-//-----------------------------------------------------------------------------
-// snGetRevision()
-
-/// Gets the current Snarl revision (build) number  (V39)
-/// Returns the build version number, or M_RESULT on failure.
-
-LONG32 SnarlInterface::GetRevision()
-{
-	SNARLSTRUCT ss;
-	ss.Cmd = SNARL_GET_REVISION;
-	ss.LngData2 = 0xFFFE;
-
-	return Send(ss);
+	return szUTF8;
 }
 
-
-//-----------------------------------------------------------------------------
-// snAddClass()
-
-/// (V39)
-
-M_RESULT SnarlInterface::AddClass(LPCSTR Class, LPCSTR Description, SNARL_CLASS_FLAGS Flags, LPCSTR DefaultTitle, LPCSTR DefaultIcon, LONG32 DefaultTimeout)
+void SnarlInterface::PackData(BYTE* data, LPCSTR format, ...)
 {
-	SNARLSTRUCT ss;
-	ss.Cmd = SNARL_ADD_CLASS;
-	ss.LngData2 = Flags;
-	ss.Timeout = GetCurrentProcessId();
-	
-	StringCbCopyExA((LPSTR)&ss.Text,  SNARL_STRING_LENGTH, Class, NULL, NULL, STRSAFE_IGNORE_NULLS);
-	StringCbCopyExA((LPSTR)&ss.Title, SNARL_STRING_LENGTH, Description, NULL, NULL, STRSAFE_IGNORE_NULLS);
+	// Always zero array - Used to clear the array in member functions
+	ZeroMemory(data, SnarlPacketDataSize);
 
-	LONG32 result = Send(ss);
+	// Return if format string is empty
+	if (format == NULL || format[0] == 0)
+		return;
 
-	if (static_cast<M_RESULT>(result) == M_OK)
-	{
-		SetClassDefault(Class, SNARL_ATTRIBUTE_TITLE, DefaultTitle);
-		SetClassDefault(Class, SNARL_ATTRIBUTE_ICON, DefaultIcon);
-		if (DefaultTimeout > 0) {
-			char str[64] = {0};
-			StringCbPrintfA((LPSTR)&str, sizeof(str), "%d", DefaultTimeout);
-			SetClassDefault(Class, SNARL_ATTRIBUTE_TIMEOUT, str);
-		}
-		
-		return M_OK;
-	}
-	else
-		return M_FAILED;
-}
-
-M_RESULT SnarlInterface::AddClass(LPCWSTR Class, LPCWSTR Description, SNARL_CLASS_FLAGS Flags, LPCWSTR DefaultTitle, LPCWSTR DefaultIcon, LONG32 DefaultTimeout)
-{
-	LPCSTR szClass        = WideToUTF8(Class);
-	LPCSTR szDescription  = WideToUTF8(Description);
-	LPCSTR szDefaultTitle = WideToUTF8(DefaultTitle);
-	LPCSTR szDefaultIcon  = WideToUTF8(DefaultIcon);
+	int cchStrTextLen = 0;
+	va_list args;
+	va_start(args, format);
 	
-	M_RESULT result = AddClass(szClass, szDescription, Flags, szDefaultTitle, szDefaultIcon, DefaultTimeout);
-	
-	delete [] szClass;
-	delete [] szDescription;
-	delete [] szDefaultTitle;
-	delete [] szDefaultIcon;
-	
-	return result;
-}
+	// Get size of buffer
+	cchStrTextLen = _vscprintf(format, args) + 1; // + NULL
+	if (cchStrTextLen <= 1)
+		return;
 
-//-----------------------------------------------------------------------------
-// Private functions
-//-----------------------------------------------------------------------------
-
-template <class T>
-LONG32 SnarlInterface::Send(T ss)
-{
-	DWORD_PTR nReturn = M_FAILED;
+	// Create formated string - _TRUNCATE will ensure zero terminated
+	_vsnprintf_s((char*)data, SnarlPacketDataSize, _TRUNCATE, format, args);
 
-	HWND hWnd = GetSnarlWindow();
-	if (IsWindow(hWnd))
-	{
-		COPYDATASTRUCT cds;
-		cds.dwData = 2;
-		cds.cbData = sizeof(ss);
-		cds.lpData = &ss;
-
-		if (SendMessageTimeout(hWnd, WM_COPYDATA, (WPARAM)m_hwndFrom, (LPARAM)&cds, SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG, 1000, &nReturn) == 0)
-		{
-			if (GetLastError() == ERROR_TIMEOUT)
-				nReturn = M_TIMED_OUT;
-		}
-	}
-
-	return static_cast<LONG32>(nReturn);
+	va_end(args);
 }
 
-//-----------------------------------------------------------------------------
-
-// Remember to : delete [] returned string
-
-LPSTR SnarlInterface::WideToUTF8(LPCWSTR szWideStr)
-{
-	if (szWideStr == NULL)
-		return NULL;
-
-    int nSize = WideCharToMultiByte(CP_UTF8, 0, szWideStr, -1, NULL, 0, NULL, NULL);
-    LPSTR szUTF8 = new char[nSize];
-    WideCharToMultiByte(CP_UTF8, 0, szWideStr, -1, szUTF8, nSize, NULL, NULL);
-    
-    return szUTF8;
-}
+}} // namespace Snarl::V41
diff --git a/3rdParty/Snarl/SnarlInterface.h b/3rdParty/Snarl/SnarlInterface.h
index 137d597..9440451 100644
--- a/3rdParty/Snarl/SnarlInterface.h
+++ b/3rdParty/Snarl/SnarlInterface.h
@@ -1,218 +1,276 @@
-#ifndef SNARL_INTERFACE
-#define SNARL_INTERFACE
+#ifndef SNARL_INTERFACE_V41
+#define SNARL_INTERFACE_V41
 
 #include <tchar.h>
 #include <windows.h>
-#include <strsafe.h>
+#include <cstdio>
+
+#ifndef SMTO_NOTIMEOUTIFNOTHUNG
+	#define SMTO_NOTIMEOUTIFNOTHUNG 8
+#endif
 
 
 namespace Snarl {
+	namespace V41 {
 
-	static const LPCTSTR SNARL_GLOBAL_MSG = _T("SnarlGlobalEvent");
-	static const LPCTSTR SNARL_APP_MSG    = _T("SnarlAppMessage");
+	static const LPCTSTR SnarlWindowClass = _T("w>Snarl");
+	static const LPCTSTR SnarlWindowTitle = _T("Snarl");
 
-	static const int SNARL_STRING_LENGTH = 1024;
-	static const int SNARL_UNICODE_LENGTH = SNARL_STRING_LENGTH / 2;
+	static const LPCTSTR SnarlGlobalMsg = _T("SnarlGlobalEvent");
+	static const LPCTSTR SnarlAppMsg = _T("SnarlAppMessage");
 
-	static const LONG32 SNARL_LAUNCHED = 1;                // Snarl has just started running
-	static const LONG32 SNARL_QUIT = 2;                    // Snarl is about to stop running
-	static const LONG32 SNARL_ASK_APPLET_VER = 3;          // (R1.5) Reserved for future use
-	static const LONG32 SNARL_SHOW_APP_UI = 4;             // (R1.6) Application should show its UI
+	static const int SnarlPacketDataSize = 4096;
 
-	static const LONG32 SNARL_NOTIFICATION_CLICKED = 32;   // notification was right-clicked by user
-	static const LONG32 SNARL_NOTIFICATION_TIMED_OUT = 33;
-	static const LONG32 SNARL_NOTIFICATION_ACK = 34;       // notification was left-clicked by user
-	static const LONG32 SNARL_NOTIFICATION_MENU = 35;           // V39 - menu item selected
-	static const LONG32 SNARL_NOTIFICATION_MIDDLE_BUTTON = 36;  // V39 - notification middle-clicked by user
-	static const LONG32 SNARL_NOTIFICATION_CLOSED = 37;         // V39 - user clicked the close gadget
+	// Enums put in own namespace, because ANSI C++ doesn't decorate enums with tagname :(
+	namespace SnarlEnums {
 
-	static const LONG32 SNARL_NOTIFICATION_CANCELLED = SNARL_NOTIFICATION_CLICKED;  // Added in R1.6
+		/// <summary>
+		/// Global event identifiers.
+		/// Identifiers marked with a '*' are sent by Snarl in two ways:
+		///   1. As a broadcast message (uMsg = 'SNARL_GLOBAL_MSG')
+		///   2. To the window registered in snRegisterConfig() or snRegisterConfig2()
+		///      (uMsg = reply message specified at the time of registering)
+		/// In both cases these values appear in wParam.
+		///   
+		/// Identifiers not marked are not broadcast; they are simply sent to the application's registered window.
+		/// </summary>
+		enum GlobalEvent
+		{
+			SnarlLaunched = 1,      // Snarl has just started running*
+			SnarlQuit = 2,          // Snarl is about to stop running*
+			SnarlAskAppletVer = 3,  // (R1.5) Reserved for future use
+			SnarlShowAppUi = 4      // (R1.6) Application should show its UI
+		};
 
-	static const DWORD WM_SNARLTEST = WM_USER + 237;    // note hardcoded WM_USER value!
+		/// <summary>
+		/// Message event identifiers.
+		/// These are sent by Snarl to the window specified in RegisterApp() when the
+		/// Snarl Notification raised times out or the user clicks on it.
+		/// </summary>
+		enum MessageEvent
+		{
+			NotificationClicked = 32,      // Notification was right-clicked by user
+			NotificationCancelled = 32,    // Added in V37 (R1.6) -- same value, just improved the meaning of it
+			NotificationTimedOut = 33,     // 
+			NotificationAck = 34,          // Notification was left-clicked by user
+			NotificationMenu = 35,         // Menu item selected (V39)
+			NotificationMiddleButton = 36, // Notification middle-clicked by user (V39)
+			NotificationClosed = 37        // User clicked the close gadget (V39)
+		};
 
-	// --------------------------------------------------------------------
-	
-	typedef enum M_RESULT {
-		M_ABORTED         = 0x80000007,
-		M_ACCESS_DENIED   = 0x80000009,
-		M_ALREADY_EXISTS  = 0x8000000C,
-		M_BAD_HANDLE      = 0x80000006,
-		M_BAD_POINTER     = 0x80000005,
-		M_FAILED          = 0x80000008,
-		M_INVALID_ARGS    = 0x80000003,
-		M_NO_INTERFACE    = 0x80000004,
-		M_NOT_FOUND       = 0x8000000B,
-		M_NOT_IMPLEMENTED = 0x80000001,
-		M_OK              = 0x00000000,
-		M_OUT_OF_MEMORY   = 0x80000002,
-		M_TIMED_OUT       = 0x8000000A
-	};
+		/// <summary>
+		/// Error values returned by calls to GetLastError().
+		/// </summary>
+		enum SnarlStatus
+		{
+			Success = 0,
 
-	enum SNARL_COMMANDS {
-		SNARL_SHOW = 1,
-		SNARL_HIDE,
-		SNARL_UPDATE,
-		SNARL_IS_VISIBLE,
-		SNARL_GET_VERSION,
-		SNARL_REGISTER_CONFIG_WINDOW,
-		SNARL_REVOKE_CONFIG_WINDOW,
-
-		/* R1.6 onwards */
-		SNARL_REGISTER_ALERT,
-		SNARL_REVOKE_ALERT,   // for future use
-		SNARL_REGISTER_CONFIG_WINDOW_2,
-		SNARL_GET_VERSION_EX,
-		SNARL_SET_TIMEOUT,
-		
-		/* following introduced in Snarl V39 (R2.1) */
-		SNARL_SET_CLASS_DEFAULT,
-		SNARL_CHANGE_ATTR,
-		SNARL_REGISTER_APP,
-		SNARL_UNREGISTER_APP,
-		SNARL_ADD_CLASS,
-
-		/* extended commands (all use SNARLSTRUCTEX) */
-		SNARL_EX_SHOW = 0x20,
-		SNARL_SHOW_NOTIFICATION                // V39
-	};
-	
-	static const SNARL_COMMANDS SNARL_GET_REVISION = SNARL_REVOKE_ALERT;
-	
-	typedef enum SNARL_APP_FLAGS {
-		SNARL_APP_HAS_PREFS = 1,
-		SNARL_APP_HAS_ABOUT = 2
-	};
-	
-	static const LONG32 SNARL_APP_PREFS = 1;
-	static const LONG32 SNARL_APP_ABOUT = 2;
+			ErrorFailed = 101,        // miscellaneous failure
+			ErrorUnknownCommand,      // specified command not recognised
+			ErrorTimedOut,            // Snarl took too long to respond
 
-	
-	/* --------------- V39 additions --------------- */
-	
-	/* snAddClass() flags */
-	enum SNARL_CLASS_FLAGS {
-		SNARL_CLASS_ENABLED = 0,
-		SNARL_CLASS_DISABLED = 1,
-		SNARL_CLASS_NO_DUPLICATES = 2,         // means Snarl will suppress duplicate notifications
-		SNARL_CLASS_DELAY_DUPLICATES = 4       // means Snarl will suppress duplicate notifications within a pre-set time period
-	};
+			ErrorArgMissing = 109,    // required argument missing
+			ErrorSystem,              // internal system error
 
-	/* Class attributes */
-	typedef enum SNARL_ATTRIBUTES {
-		SNARL_ATTRIBUTE_TITLE = 1,
-		SNARL_ATTRIBUTE_TEXT,
-		SNARL_ATTRIBUTE_ICON,
-		SNARL_ATTRIBUTE_TIMEOUT,
-		SNARL_ATTRIBUTE_SOUND,
-		SNARL_ATTRIBUTE_ACK,               // file to run on ACK
-		SNARL_ATTRIBUTE_MENU
-	};
+			ErrorNotRunning = 201,    // Snarl handling window not found
+			ErrorNotRegistered,       // 
+			ErrorAlreadyRegistered,   // not used yet; RegisterApp() returns existing token
+			ErrorClassAlreadyExists,  // not used yet; AddClass() returns existing token
+			ErrorClassBlocked,
+			ErrorClassNotFound,
+			ErrorNotificationNotFound
+		};
 
-	/* ------------------- end of V39 additions ------------------ */
-	
-	struct SNARLSTRUCT {
-		SNARL_COMMANDS Cmd;
-		LONG32 Id;
-		LONG32 Timeout;
-		LONG32 LngData2;
-		char Title[SNARL_STRING_LENGTH];
-		char Text[SNARL_STRING_LENGTH];
-		char Icon[SNARL_STRING_LENGTH];
-	};
+		/// <summary>
+		/// Application flags - features this app supports.
+		/// </summary>
+		enum AppFlags
+		{
+			AppDefault = 0,
+			AppHasPrefs = 1,
+			AppHasAbout = 2,
+			AppIsWindowless = 0x8000
+		};
 
-	struct SNARLSTRUCTEX {
-		SNARL_COMMANDS Cmd;
-		LONG32 Id;
-		LONG32 Timeout;
-		LONG32 LngData2;
-		char Title[SNARL_STRING_LENGTH];
-		char Text[SNARL_STRING_LENGTH];
-		char Icon[SNARL_STRING_LENGTH];
-
-		char Class[SNARL_STRING_LENGTH];
-		char Extra[SNARL_STRING_LENGTH];
-		char Extra2[SNARL_STRING_LENGTH];
-		LONG32 Reserved1;
-		LONG32 Reserved2;
+		enum SnarlCommand
+		{
+			RegisterApp = 1,
+			UnregisterApp,
+			UpdateApp,
+			SetCallback,
+			AddClass,
+			RemoveClass,
+			Notify,
+			UpdateNotification,
+			HideNotification,
+			IsNotificationVisible,
+			LastError                  // deprecated but retained for backwards compatability
+		};
+	}
+
+	struct SnarlMessage
+	{
+		SnarlEnums::SnarlCommand Command;
+		LONG32 Token;
+		BYTE PacketData[SnarlPacketDataSize];
 	};
 
+	static const DWORD WM_SNARLTEST = WM_USER + 237;
 
 	
 	// ------------------------------------------------------------------------
-	// SnarlInterface class definition
+	/// SnarlInterface class definition
 	// ------------------------------------------------------------------------
-	
 	class SnarlInterface {
 		public:
 			SnarlInterface();
 			~SnarlInterface();
-
-			static HWND   GetSnarlWindow();		
-			static LONG32 GetGlobalMsg();
-
 			
 			LPTSTR AllocateString(size_t n) { return new TCHAR[n]; }
-			void FreeString(LPCTSTR str)    { delete [] str; str = NULL; }
+			void FreeString(LPTSTR str)     { delete [] str; str = NULL; }
+			void FreeString(LPCTSTR str)    { delete [] str; }
+
+			/// <summary>Register application with Snarl.</summary>
+			/// <returns>The application token or 0 on failure.</returns>
+			/// <remarks>The application token is saved in SnarlInterface member variable, so just use return value to check for error.</remarks>
+			LONG32 RegisterApp(LPCSTR signature, LPCSTR title, LPCSTR icon, HWND hWndReply = NULL, LONG32 msgReply = 0, SnarlEnums::AppFlags flags = SnarlEnums::AppDefault);
+			LONG32 RegisterApp(LPCWSTR  signature, LPCWSTR title, LPCWSTR icon, HWND hWndReply = NULL, LONG32 msgReply = 0, SnarlEnums::AppFlags flags = SnarlEnums::AppDefault);
+
+			/// <summary>Unregister application with Snarl when application is closing.</summary>
+			/// <returns>0 on failure.</returns>
+			LONG32 UnregisterApp();
+
+			/// <summary>Update information provided when calling RegisterApp.</summary>
+			/// <returns>0 on failure.</returns>
+			LONG32 UpdateApp(LPCSTR title = NULL, LPCSTR icon = NULL);
+			LONG32 UpdateApp(LPCWSTR title = NULL, LPCWSTR icon = NULL);
+
+			/// <summary>Add a notification class to Snarl.</summary>
+			/// <returns>0 on failure.</returns>
+			LONG32 AddClass(LPCSTR className, LPCSTR description, bool enabled = true);
+			LONG32 AddClass(LPCWSTR className, LPCWSTR description, bool enabled = true);
 			
+			/// <summary>Remove a notification class added with AddClass().</summary>
+			/// <returns>0 on failure.</returns>
+			LONG32 RemoveClass(LPCSTR className, bool forgetSettings = false);
+			LONG32 RemoveClass(LPCWSTR className, bool forgetSettings = false);
 
-			LONG32  ShowMessage(LPCSTR szTitle, LPCSTR szText, LONG32 timeout = 0, LPCSTR szIconPath = "", HWND hWndReply = NULL, WPARAM uReplyMsg = 0);
-			LONG32  ShowMessage(LPCWSTR szTitle, LPCWSTR szText, LONG32 timeout = 0, LPCWSTR szIconPath = L"", HWND hWndReply = NULL, WPARAM uReplyMsg = 0);
-			LONG32  ShowMessageEx(LPCSTR szClass, LPCSTR szTitle, LPCSTR szText, LONG32 timeout = 0, LPCSTR szIconPath = "", HWND hWndReply = NULL, WPARAM uReplyMsg = 0, LPCSTR szSoundFile = "");
-			LONG32  ShowMessageEx(LPCWSTR szClass, LPCWSTR szTitle, LPCWSTR szText, LONG32 timeout = 0, LPCWSTR szIconPath = L"", HWND hWndReply = NULL, WPARAM uReplyMsg = 0, LPCWSTR szSoundFile = L"");
-
-			LPCTSTR GetAppPath();    // ** Remember to FreeString when finished with the string !
-			LPCTSTR GetIconsPath();  // ** Remember to FreeString when finished with the string !
-
-			BOOL      GetVersion(WORD* Major, WORD* Minor);
-			LONG32    GetVersionEx();
-			BOOL      HideMessage();
-			BOOL      HideMessage(LONG32 Id);
-			BOOL      IsMessageVisible();
-			BOOL      IsMessageVisible(LONG32 Id);
-			M_RESULT  RegisterAlert(LPCSTR szAppName, LPCSTR szClass);
-			M_RESULT  RegisterAlert(LPCWSTR szAppName, LPCWSTR szClass);
-			M_RESULT  RegisterConfig(HWND hWnd, LPCSTR szAppName, LONG32 replyMsg);
-			M_RESULT  RegisterConfig(HWND hWnd, LPCWSTR szAppName, LONG32 replyMsg);
-			M_RESULT  RegisterConfig2(HWND hWnd, LPCSTR szAppName, LONG32 replyMsg, LPCSTR szIcon);
-			M_RESULT  RegisterConfig2(HWND hWnd, LPCWSTR szAppName, LONG32 replyMsg, LPCWSTR szIcon);
-			M_RESULT  RevokeConfig(HWND hWnd);
-			M_RESULT  SetTimeout(LONG32 Timeout);
-			M_RESULT  SetTimeout(LONG32 Id, LONG32 Timeout);
-			M_RESULT  UpdateMessage(LPCSTR szTitle, LPCSTR szText, LPCSTR szIconPath = "");
-			M_RESULT  UpdateMessage(LPCWSTR szTitle, LPCWSTR szText, LPCWSTR szIconPath = L"");
-			M_RESULT  UpdateMessage(LONG32 Id, LPCSTR szTitle, LPCSTR szText, LPCSTR szIconPath = "");
-			M_RESULT  UpdateMessage(LONG32 Id, LPCWSTR szTitle, LPCWSTR szText, LPCWSTR szIconPath = L"");
+			/// <summary>Remove all notification classes in one call.</summary>
+			/// <returns>0 on failure.</returns>
+			LONG32 RemoveAllClasses(bool forgetSettings = false);
 			
-			/* V39 */
-			M_RESULT  AddClass(LPCSTR Class, LPCSTR Description = NULL, SNARL_CLASS_FLAGS Flags = SNARL_CLASS_ENABLED, LPCSTR DefaultTitle = NULL, LPCSTR DefaultIcon = NULL, LONG32 DefaultTimeout = 0);
-			M_RESULT  AddClass(LPCWSTR Class, LPCWSTR Description = NULL, SNARL_CLASS_FLAGS Flags = SNARL_CLASS_ENABLED, LPCWSTR DefaultTitle = NULL, LPCWSTR DefaultIcon = NULL, LONG32 DefaultTimeout = 0);
-			M_RESULT  ChangeAttribute(SNARL_ATTRIBUTES Attr, LPCSTR Value);
-			M_RESULT  ChangeAttribute(SNARL_ATTRIBUTES Attr, LPCWSTR Value);
-			M_RESULT  ChangeAttribute(LONG32 Id, SNARL_ATTRIBUTES Attr, LPCSTR Value);			
-			M_RESULT  ChangeAttribute(LONG32 Id, SNARL_ATTRIBUTES Attr, LPCWSTR Value);			
-			LONG32    GetAppMsg();
-			LONG32    GetRevision();
+			/// <summary>Show a Snarl notification.</summary>
+			/// <returns>Returns the notification token or 0 on failure.</returns>
+			/// <remarks>You can use <see cref="GetLastMsgToken()" /> to get the last token.</remarks>
+			LONG32 EZNotify(LPCSTR className, LPCSTR title, LPCSTR text, LONG32 timeout = -1, LPCSTR icon = NULL, LONG32 priority = 0, LPCSTR acknowledge = NULL, LPCSTR value = NULL);
+			LONG32 EZNotify(LPCWSTR className, LPCWSTR title, LPCWSTR text, LONG32 timeout = -1, LPCWSTR icon = NULL, LONG32 priority = 0, LPCWSTR acknowledge = NULL, LPCWSTR value = NULL);
+
+			/// <summary>
+			///     Show a Snarl notification.
+			///     This function requires that you write your own packet data.
+			/// </summary>
+			/// <returns>Returns the notification token or 0 on failure.</returns>
+			/// <remarks>You can use <see cref="GetLastMsgToken()" /> to get the last token.</remarks>
+			LONG32 Notify(LPCSTR className, LPCSTR packetData);
+			LONG32 Notify(LPCWSTR className, LPCWSTR packetData);
+
+			/// <summary>Update the text or other parameters of a visible Snarl notification.</summary>
+			/// <returns>0 on failure.</returns>
+			LONG32 EZUpdate(LONG32 msgToken, LPCSTR title = NULL, LPCSTR text = NULL, LONG32 timeout = -1, LPCSTR icon = NULL);
+			LONG32 EZUpdate(LONG32 msgToken, LPCWSTR title = NULL, LPCWSTR text = NULL, LONG32 timeout = -1, LPCWSTR icon = NULL);
 			
-			M_RESULT  RegisterApp(LPCSTR Application, LPCSTR SmallIcon, LPCSTR LargeIcon, HWND hWnd = 0, LONG32 ReplyMsg = 0);
-			M_RESULT  RegisterApp(LPCWSTR Application, LPCWSTR SmallIcon, LPCWSTR LargeIcon, HWND hWnd = 0, LONG32 ReplyMsg = 0);
-			void      SetAsSnarlApp(HWND hWndOwner, SNARL_APP_FLAGS Flags = (SNARL_APP_FLAGS)(SNARL_APP_HAS_ABOUT | SNARL_APP_HAS_PREFS));
-			M_RESULT  SetClassDefault(LPCSTR Class, SNARL_ATTRIBUTES Attr, LPCSTR Value);
-			M_RESULT  SetClassDefault(LPCWSTR Class, SNARL_ATTRIBUTES Attr, LPCWSTR Value);
-			LONG32    ShowNotification(LPCSTR Class, LPCSTR Title = NULL, LPCSTR Text = NULL, LONG32 Timeout = 0, LPCSTR Icon = NULL, HWND hWndReply = NULL, LONG32 uReplyMsg = 0, LPCSTR Sound = NULL);
-			LONG32    ShowNotification(LPCWSTR Class, LPCWSTR Title = NULL, LPCWSTR Text = NULL, LONG32 Timeout = 0, LPCWSTR Icon = NULL, HWND hWndReply = NULL, LONG32 uReplyMsg = 0, LPCWSTR Sound = NULL);
-			M_RESULT  UnregisterApp();
+			/// <summary>
+			///     Update the text or other parameters of a visible Snarl notification.
+			///     This function requires that you write your own packet data.
+			/// </summary>
+			/// <returns>0 on failure.</returns>
+			LONG32 Update(LONG32 msgToken, LPCSTR packetData);
+			LONG32 Update(LONG32 msgToken, LPCWSTR packetData);
+
+			/// <summary>Hide a Snarl notification.</summary>
+			/// <returns>0 on failure.</returns>
+			LONG32 Hide(LONG32 msgToken);
+
+			/// <summary>Test if a Snarl notification is visible.</summary>
+			/// <returns>Returns -1 if message is visible. 0 if not visible or if an error occured.</returns>
+			LONG32 IsVisible(LONG32 msgToken);
+
+			/// <summary>Get the last error from Snarl. Call after other functions return 0 to know why it failed.</summary>
+			/// <returns>Returns one of the SnarlEnums::SnarlStatus values.</returns>
+			SnarlEnums::SnarlStatus GetLastError();
+
+			/// <summary>Get Snarl version, if it is running.</summary>
+			/// <returns>Returns a number indicating Snarl version.</returns>
+			LONG32 GetVersion();
+
+			/// <summary>
+			///     Get the path to where Snarl is installed.
+			///     ** Remember to call <see cref="FreeString(LPCTSTR)" /> on the returned string !!!
+			/// </summary>
+			/// <returns>Returns the path to where Snarl is installed.</returns>
+			/// <remarks>This is a V39 API method.</remarks>
+			LPCTSTR  GetAppPath();
+
+			/// <summary>
+			///     Get the path to where the default Snarl icons are located.
+			///     <para>** Remember to call <see cref="FreeString(LPCTSTR)" /> on the returned string !!!</para>
+			/// </summary>
+			/// <returns>Returns the path to where the default Snarl icons are located.</returns>
+			/// <remarks>This is a V39 API method.</remarks>
+			LPCTSTR  GetIconsPath();
+
+			/// <summary>GetLastMsgToken() returns token of the last message sent to Snarl.</summary>
+			/// <returns>Returns message token of last message.</returns>
+			/// <remarks>This function is not in the official API!</remarks>
+			LONG32 GetLastMsgToken() const;
 			
-			LONG32    GetLastMessageId() { return m_nLastMessageId; }
+			/// <summary>Check whether Snarl is running</summary>
+			/// <returns>Returns true if Snarl system was found running.</returns>
+			static BOOL IsSnarlRunning();
+
+			/// <summary>
+			///     Returns the value of Snarl's global registered message.
+			///     Notes:
+			///       Snarl registers SNARL_GLOBAL_MSG during startup which it then uses to communicate
+			///       with all running applications through a Windows broadcast message. This function can
+			///       only fail if for some reason the Windows RegisterWindowMessage() function fails
+			///       - given this, this function *cannnot* be used to test for the presence of Snarl.
+			/// </summary>
+			/// <returns>A 16-bit value (translated to 32-bit) which is the registered Windows message for Snarl.</returns>
+			static UINT Broadcast();
 
+			/// <summary>Returns the global Snarl Application message  (V39)</summary>
+			/// <returns>Returns Snarl application registered message.</returns>
+			static UINT AppMsg();
+
+			/// <summary>Returns a handle to the Snarl Dispatcher window  (V37)</summary>
+			/// <returns>Returns handle to Snarl Dispatcher window, or zero if it's not found.</returns>
+			/// <remarks>This is now the preferred way to test if Snarl is actually running.</remarks>
+			static HWND GetSnarlWindow();
+		
 		private:
-			template <class T> LONG32 Send(T ss);
+			/// <summary>Send message to Snarl.</summary>
+			/// <returns>Return zero on failure.</returns>
+			LONG32 Send(SnarlMessage msg);
+
+			/// <summary>Convert a unicode string to UTF8</summary>
+			/// <returns>Returns pointer to the new string - Remember to delete [] returned string !</returns>
+			/// <remarks>Remember to delete [] returned string !!!</remarks>
 			LPSTR  WideToUTF8(LPCWSTR szWideStr);
-			
-			LONG32 m_nLastMessageId;
-			HWND   m_hwndFrom; // set during snRegisterConfig() or snRegisterConfig2()
 
-	};
+			/// <summary>Pack data into the PackedData member field.</summary>
+			/// <param name="data">Should always be a pointer to the PackedData field</param>
+			/// <param name="format">The format string. Can be NULL or "" to just zero PackedData!</param>
+			/// <param name="...">Variable number of objects to convert</param>
+			void   PackData(BYTE* data, LPCSTR format, ...);
+
+			LONG32 appToken;
+			LONG32 lastMsgToken;
+			SnarlEnums::SnarlStatus localError;
+
+	}; // class
 
-}
+	} // namespace V41
+} // namespace Snarl
 
-#endif // SNARL_INTERFACE
+#endif // SNARL_INTERFACE_V41
diff --git a/SwifTools/Notifier/SnarlNotifier.cpp b/SwifTools/Notifier/SnarlNotifier.cpp
index eb4addc..9e82340 100644
--- a/SwifTools/Notifier/SnarlNotifier.cpp
+++ b/SwifTools/Notifier/SnarlNotifier.cpp
@@ -19,14 +19,14 @@ namespace Swift {
 
 SnarlNotifier::SnarlNotifier(const String& name, Win32NotifierWindow* window, const boost::filesystem::path& icon) : window(window) {
 	window->onMessageReceived.connect(boost::bind(&SnarlNotifier::handleMessageReceived, this, _1));
-	snarl.RegisterConfig2(window->getID(), name.getUTF8Data(), 0, icon.string().c_str());
+	snarl.RegisterApp(name.getUTF8Data(), name.getUTF8Data(), icon.string().c_str(), window->getID(), SWIFT_SNARLNOTIFIER_MESSAGE_ID);
 	foreach(Notifier::Type type, getAllTypes()) {
-		snarl.RegisterAlert(name.getUTF8Data(), typeToString(type).getUTF8Data());
+		snarl.AddClass(typeToString(type).getUTF8Data(), typeToString(type).getUTF8Data());
 	}
 }
 
 SnarlNotifier::~SnarlNotifier() {
-	snarl.RevokeConfig(window->getID());
+	snarl.UnregisterApp();
 	window->onMessageReceived.disconnect(boost::bind(&SnarlNotifier::handleMessageReceived, this, _1));
 	if (!notifications.empty()) {
 		std::cerr << "Warning: " << notifications.size() << " Snarl notifications pending" << std::endl;
@@ -34,8 +34,13 @@ SnarlNotifier::~SnarlNotifier() {
 }
 
 void SnarlNotifier::showMessage(Type type, const String& subject, const String& description, const boost::filesystem::path& picture, boost::function<void()> callback) {
-	int timeout = (type == Type::IncomingMessage || type == Type::SystemMessage) ? DEFAULT_MESSAGE_NOTIFICATION_TIMEOUT_SECONDS : DEFAULT_STATUS_NOTIFICATION_TIMEOUT_SECONDS;
-	int notificationID = snarl.ShowMessageEx(typeToString(type).getUTF8Data(), subject.getUTF8Data(), description.getUTF8Data(), timeout, picture.string().c_str(), window->getID(), SWIFT_SNARLNOTIFIER_MESSAGE_ID);
+	int timeout = (type == IncomingMessage || type == SystemMessage) ? DEFAULT_MESSAGE_NOTIFICATION_TIMEOUT_SECONDS : DEFAULT_STATUS_NOTIFICATION_TIMEOUT_SECONDS;
+	int notificationID = snarl.EZNotify(
+			typeToString(type).getUTF8Data(),
+			subject.getUTF8Data(),
+			description.getUTF8Data(),
+			timeout,
+			picture.string().c_str());
 	if (notificationID > 0) {
 		notifications.insert(std::make_pair(notificationID, callback));
 	}
@@ -44,11 +49,11 @@ void SnarlNotifier::showMessage(Type type, const String& subject, const String&
 void SnarlNotifier::handleMessageReceived(MSG* message) {
 	if (message->message == SWIFT_SNARLNOTIFIER_MESSAGE_ID) {
 		int action = message->wParam;
-		if (action == Snarl::SNARL_NOTIFICATION_TIMED_OUT || action == Snarl::SNARL_NOTIFICATION_ACK || action == Snarl::SNARL_NOTIFICATION_CLOSED) {
+		if (action == Snarl::V41::SnarlEnums::NotificationTimedOut || action == Snarl::V41::SnarlEnums::NotificationAck || action == Snarl::V41::SnarlEnums::NotificationClosed) {
 			int notificationID = message->lParam;
 			NotificationsMap::iterator i = notifications.find(notificationID);
 			if (i != notifications.end()) {
-				if (action == Snarl::SNARL_NOTIFICATION_ACK) {
+				if (action == Snarl::V41::SnarlEnums::NotificationAck) {
 					i->second();
 				}
 				notifications.erase(i);
diff --git a/SwifTools/Notifier/SnarlNotifier.h b/SwifTools/Notifier/SnarlNotifier.h
index 2350e29..8470326 100644
--- a/SwifTools/Notifier/SnarlNotifier.h
+++ b/SwifTools/Notifier/SnarlNotifier.h
@@ -25,7 +25,7 @@ namespace Swift {
 			void handleMessageReceived(MSG* message);
 
 		private:
-			Snarl::SnarlInterface snarl;
+			Snarl::V41::SnarlInterface snarl;
 			Win32NotifierWindow* window;
 			typedef std::map<int, boost::function<void()> > NotificationsMap;
 			NotificationsMap notifications;
-- 
cgit v0.10.2-6-g49f6