1 //-----------------------------------------------------------------------------
2 // NOTICE:
3 // This version of Snarl Interface is depricated!
4 // Use V41 interface files instead. The files can be found in Snarl SVN:
5 // \trunk\hdr\C++
6 //-----------------------------------------------------------------------------
7 
8 //-----------------------------------------------------------------------------
9 // About:
10 //   Snarl C++ interface implementation
11 //   To understand what the different functions do and what they return, please
12 //   have a look at the API on http://www.fullphat.net/dev/api.htm.
13 //   Also have a look at mSnarl_i.bas found in the CVS/SVN repository for Snarl.
14 //
15 //   The functions in SnarlInterface both have ANSI(UTF8) and UNICODE versions.
16 //   If the LPCWSTR (unicode) version of the functions are called, the strings
17 //   are converted to UTF8 by SnarlInterface before sent to Snarl. So using the
18 //   ANSI/UTF8/LPCSTR versions of the functions are faster!
19 //
20 //
21 // Difference to VB implementation:
22 //   Please note that string functions return NULL when they fail and not an
23 //   empty string. So check for NULL...
24 //   Function names doesn't have the pre "sn".
25 //
26 //
27 // Authors:
28 //   Written and maintained by Toke Noer Nøttrup
29 //   Original C++ version by "Whitman"
30 //
31 // License etc. :
32 //   Feel free to use this code and class as you see fit.
33 //   If you improve the code, it would be nice of you to take contact to the
34 //   authors, so all can get the benifit.
35 //
36 //   There is no guarantee that the code is correct or functional.
37 //   USE AT YOUR OWN RISK
38 //-----------------------------------------------------------------------------
39 
40 // History
41 //  2010/08/13 : Moved to depricated status - Use the V41 API instead !
42 //  2010/08/02 : Removed some dependencies on safe string functions
43 //             : Added uckly casts of HWND to please MinGW64 (since Snarl is 32bit anyway, shouldn't matter.)
44 //  2008/12/31 : Implemented V39 API
45 //             : Moved SnarlInterface into new Snarl namespace and moved enums etc. out of class
46 //             : Added WCHAR overloads for all functions
47 //  2008/08/27 : Fixed return value of IsMessageVisible and HideMessage (returns false on failure now)
48 //             : Fixed critical error in the new overloaded UpdateMessage() function
49 //  2008/08/27 : x64 compiler fix
50 //  2008/08/24 : Renamed all functions to not have prepended "sn".
51 //             : Memory allocation functions added. (Use FreeString to free strings returned by Snarl)
52 //             : Added m_nLastMessageId to the class. (Use GetLastMessageId() to get it)
53 //             : Overloaded a few functions, so one don't have include the message id. (UpdateMessage f.i.)
54 
55 //  2008/06/20 : Fixed snShowMessageEx so it actually sends the extended version - oops
56 //             : Fixed compiler warning C4800: forcing value to bool 'true' or 'false' (performance warning)
57 
58 //  2008/05/19 : uSend and uSendEx would always set return value to M_OK on successfull call
59 //  2008/04/14 : Updated to follow (what should be) the final Snarl 2.0 API
60 //  2008/03/28 : Few fixes for Snarl 2.0
61 //  2007/05/23 : snGetGlobalMsg & snGetSnarlWindow made static
62 //  2007/03/25 : 1.6 RC1 fixup
63 //  2007/03/04 : Added - snGetAppPath, snGetIconsPath, snGetVersionEx,
64 //                       snSetTimeout, uSendEx
65 
66 #define _CRT_SECURE_NO_WARNINGS
67 
68 #include "SnarlInterface.h"
69 
70 namespace Snarl {
71 namespace V39 {
72 
73 //-----------------------------------------------------------------------------
74 // Constructor/Destructor
75 //-----------------------------------------------------------------------------
SnarlInterface()76 SnarlInterface::SnarlInterface()
77 : m_hwndFrom(NULL), m_nLastMessageId(0)
78 {
79 
80 }
81 
~SnarlInterface()82 SnarlInterface::~SnarlInterface()
83 {
84 
85 }
86 
87 
88 //-----------------------------------------------------------------------------
89 // snShowMessage()
90 
91 /// Displays a message with Title and Text. Timeout controls how long the
92 /// message is displayed for (in seconds) (omitting this value means the message
93 /// is displayed indefinately). IconPath specifies the location of a PNG image
94 /// which will be displayed alongside the message text.
95 /// <returns>Message Id on success or M_RESULT on failure</returns>
96 
ShowMessage(LPCSTR szTitle,LPCSTR szText,LONG32 timeout,LPCSTR szIconPath,HWND hWndReply,WPARAM uReplyMsg)97 LONG32 SnarlInterface::ShowMessage(LPCSTR szTitle, LPCSTR szText, LONG32 timeout, LPCSTR szIconPath, HWND hWndReply, WPARAM uReplyMsg)
98 {
99 	SNARLSTRUCT ss;
100 	ZeroMemory((void*)&ss, sizeof(ss));
101 
102 	ss.Cmd = SNARL_SHOW;
103 	strncpy((LPSTR)&ss.Title, szTitle, SNARL_STRING_LENGTH);
104 	strncpy((LPSTR)&ss.Text, szText, SNARL_STRING_LENGTH);
105 	strncpy((LPSTR)&ss.Icon, szIconPath, SNARL_STRING_LENGTH);
106 	ss.Timeout = timeout;
107 
108 	ss.LngData2 = static_cast<LONG32>(reinterpret_cast<DWORD_PTR>(hWndReply));
109 	ss.Id = static_cast<LONG32>(uReplyMsg);
110 
111 	m_nLastMessageId = Send(ss);
112 	return m_nLastMessageId;
113 }
114 
ShowMessage(LPCWSTR szTitle,LPCWSTR szText,LONG32 timeout,LPCWSTR szIconPath,HWND hWndReply,WPARAM uReplyMsg)115 LONG32 SnarlInterface::ShowMessage(LPCWSTR szTitle, LPCWSTR szText, LONG32 timeout, LPCWSTR szIconPath, HWND hWndReply, WPARAM uReplyMsg)
116 {
117 	LPSTR szUTF8Title = WideToUTF8(szTitle);
118 	LPSTR szUTF8Text  = WideToUTF8(szText);
119 	LPSTR szUFT8IconPath = WideToUTF8(szIconPath);
120 
121 	LONG32 result = ShowMessage(szUTF8Title, szUTF8Text, timeout, szUFT8IconPath, hWndReply, uReplyMsg);
122 
123 	delete [] szUTF8Title;
124 	delete [] szUTF8Text;
125 	delete [] szUFT8IconPath;
126 
127 	return result;
128 }
129 
130 //-----------------------------------------------------------------------------
131 // snShowMessageEx()
132 
133 /// Displays a notification. This function is identical to snShowMessage()
134 /// except that Class specifies an alert previously registered with
135 /// snRegisterAlert() and SoundFile can optionally specify a WAV sound to play
136 /// when the notification is displayed on screen.
137 
138 /// <returns>Message Id on success or M_RESULT on failure</returns>
139 
ShowMessageEx(LPCSTR szClass,LPCSTR szTitle,LPCSTR szText,LONG32 timeout,LPCSTR szIconPath,HWND hWndReply,WPARAM uReplyMsg,LPCSTR szSoundFile)140 LONG32 SnarlInterface::ShowMessageEx(LPCSTR szClass, LPCSTR szTitle, LPCSTR szText, LONG32 timeout, LPCSTR szIconPath, HWND hWndReply, WPARAM uReplyMsg, LPCSTR szSoundFile)
141 {
142 	SNARLSTRUCTEX ssex;
143 	ZeroMemory((void*)&ssex, sizeof(ssex));
144 
145 	ssex.Cmd = SNARL_EX_SHOW;
146 	ssex.Timeout = timeout;
147 	ssex.LngData2 = static_cast<LONG32>(reinterpret_cast<DWORD_PTR>(hWndReply));
148 	ssex.Id = static_cast<LONG32>(uReplyMsg);
149 
150 	strncpy((LPSTR)&ssex.Class, szClass, SNARL_STRING_LENGTH);
151 	strncpy((LPSTR)&ssex.Title, szTitle, SNARL_STRING_LENGTH);
152 	strncpy((LPSTR)&ssex.Text, szText, SNARL_STRING_LENGTH);
153 	strncpy((LPSTR)&ssex.Icon, szIconPath, SNARL_STRING_LENGTH);
154 	strncpy((LPSTR)&ssex.Extra, szSoundFile, SNARL_STRING_LENGTH);
155 
156 	m_nLastMessageId = Send(ssex);
157 	return m_nLastMessageId;
158 }
159 
ShowMessageEx(LPCWSTR szClass,LPCWSTR szTitle,LPCWSTR szText,LONG32 timeout,LPCWSTR szIconPath,HWND hWndReply,WPARAM uReplyMsg,LPCWSTR szSoundFile)160 LONG32 SnarlInterface::ShowMessageEx(LPCWSTR szClass, LPCWSTR szTitle, LPCWSTR szText, LONG32 timeout, LPCWSTR szIconPath, HWND hWndReply, WPARAM uReplyMsg, LPCWSTR szSoundFile)
161 {
162 	LPSTR szUTF8Class = WideToUTF8(szClass);
163 	LPSTR szUTF8Title = WideToUTF8(szTitle);
164 	LPSTR szUTF8Text  = WideToUTF8(szText);
165 	LPSTR szUFT8IconPath = WideToUTF8(szIconPath);
166 	LPSTR szUFT8SoundFile = WideToUTF8(szSoundFile);
167 
168 	LONG32 result = ShowMessageEx(szUTF8Class, szUTF8Title, szUTF8Text, timeout, szUFT8IconPath, hWndReply, uReplyMsg, szUFT8SoundFile);
169 
170 	delete [] szUTF8Class;
171 	delete [] szUTF8Title;
172 	delete [] szUTF8Text;
173 	delete [] szUFT8IconPath;
174 	delete [] szUFT8SoundFile;
175 
176 	return result;
177 }
178 
179 //-----------------------------------------------------------------------------
180 // snHideMessage()
181 
182 /// Hides the notification specified by Id. Id is the value returned by
183 /// snShowMessage() or snShowMessageEx() when the notification was initially
184 /// created. This function returns True if the notification was successfully
185 /// hidden or False otherwise (for example, the notification may no longer exist).
186 
HideMessage(LONG32 Id)187 BOOL SnarlInterface::HideMessage(LONG32 Id)
188 {
189 	SNARLSTRUCT ss;
190 	ss.Cmd = SNARL_HIDE;
191 	ss.Id = Id;
192 
193 	LONG32 n = Send(ss);
194 	return (n == -1 || n == 1) ? TRUE : FALSE;
195 }
196 
HideMessage()197 BOOL SnarlInterface::HideMessage()
198 {
199 	return HideMessage(m_nLastMessageId);
200 }
201 
202 //-----------------------------------------------------------------------------
203 // snIsMessageVisible()
204 
205 /// Returns True if the notification specified by Id is still visible, or
206 /// False if not. Id is the value returned by snShowMessage() or
207 /// snShowMessageEx() when the notification was initially created.
208 
IsMessageVisible(LONG32 Id)209 BOOL SnarlInterface::IsMessageVisible(LONG32 Id)
210 {
211 	SNARLSTRUCT ss;
212 	ss.Cmd = SNARL_IS_VISIBLE;
213 	ss.Id = Id;
214 
215 	// 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
216 	LONG32 n = Send(ss);
217 	return (n == -1 || n == 1) ? TRUE : FALSE;
218 }
219 
IsMessageVisible()220 BOOL SnarlInterface::IsMessageVisible()
221 {
222 	if (m_nLastMessageId == 0)
223 		return FALSE;
224 
225 	return IsMessageVisible(m_nLastMessageId);
226 }
227 
228 //-----------------------------------------------------------------------------
229 // snUpdateMessage()
230 
231 /// Changes the title and text in the message specified by Id to the values
232 /// specified by Title and Text respectively. Id is the value returned by
233 /// snShowMessage() or snShowMessageEx() when the notification was originally
234 /// created. To change the timeout parameter of a notification, use snSetTimeout()
235 
UpdateMessage(LONG32 id,LPCSTR szTitle,LPCSTR szText,LPCSTR szIconPath)236 M_RESULT SnarlInterface::UpdateMessage(LONG32 id, LPCSTR szTitle, LPCSTR szText, LPCSTR szIconPath)
237 {
238 	SNARLSTRUCT ss;
239 	ZeroMemory((void*)&ss, sizeof(ss));
240 
241 	ss.Cmd = SNARL_UPDATE;
242 	ss.Id = id;
243 
244 	strncpy((LPSTR)&ss.Title, szTitle, SNARL_STRING_LENGTH);
245 	strncpy((LPSTR)&ss.Text, szText, SNARL_STRING_LENGTH);
246 	strncpy((LPSTR)&ss.Icon, szIconPath, SNARL_STRING_LENGTH);
247 
248 	return static_cast<M_RESULT>(Send(ss));
249 }
250 
UpdateMessage(LONG32 id,LPCWSTR szTitle,LPCWSTR szText,LPCWSTR szIconPath)251 M_RESULT SnarlInterface::UpdateMessage(LONG32 id, LPCWSTR szTitle, LPCWSTR szText, LPCWSTR szIconPath)
252 {
253 	LPSTR szParam1 = WideToUTF8(szTitle);
254 	LPSTR szParam2 = WideToUTF8(szText);
255 	LPSTR szParam3 = WideToUTF8(szIconPath);
256 
257 	M_RESULT result = UpdateMessage(id, szParam1, szParam2, szParam3);
258 
259 	delete [] szParam1;
260 	delete [] szParam2;
261 	delete [] szParam3;
262 
263 	return result;
264 }
265 
UpdateMessage(LPCSTR szTitle,LPCSTR szText,LPCSTR szIconPath)266 M_RESULT SnarlInterface::UpdateMessage(LPCSTR szTitle, LPCSTR szText, LPCSTR szIconPath)
267 {
268 	return UpdateMessage(m_nLastMessageId, szTitle, szText, szIconPath);
269 }
270 
UpdateMessage(LPCWSTR szTitle,LPCWSTR szText,LPCWSTR szIconPath)271 M_RESULT SnarlInterface::UpdateMessage(LPCWSTR szTitle, LPCWSTR szText, LPCWSTR szIconPath)
272 {
273 	return UpdateMessage(m_nLastMessageId, szTitle, szText, szIconPath);
274 }
275 
276 //-----------------------------------------------------------------------------
277 // snRegisterConfig
278 
279 /// Registers an application's configuration interface with Snarl.
280 /// AppName is the text that's displayed in the Applications list so it should
281 /// be people friendly ("My cool app" rather than "my_cool_app").
282 
RegisterConfig(HWND hWnd,LPCSTR szAppName,LONG32 replyMsg)283 M_RESULT SnarlInterface::RegisterConfig(HWND hWnd, LPCSTR szAppName, LONG32 replyMsg)
284 {
285 	return RegisterConfig2(hWnd, szAppName, replyMsg, "");
286 }
287 
RegisterConfig(HWND hWnd,LPCWSTR szAppName,LONG32 replyMsg)288 M_RESULT SnarlInterface::RegisterConfig(HWND hWnd, LPCWSTR szAppName, LONG32 replyMsg)
289 {
290 	return RegisterConfig2(hWnd, szAppName, replyMsg, L"");
291 }
292 
293 //-----------------------------------------------------------------------------
294 // snRegisterConfig2
295 
296 /// Registers an application's configuration interface with Snarl.
297 /// This function is identical to snRegisterConfig() except that Icon can be
298 /// used to specify a PNG image which will be displayed against the
299 /// application's entry in Snarl's Preferences panel.
300 
RegisterConfig2(HWND hWnd,LPCSTR szAppName,LONG32 replyMsg,LPCSTR szIcon)301 M_RESULT SnarlInterface::RegisterConfig2(HWND hWnd, LPCSTR szAppName, LONG32 replyMsg, LPCSTR szIcon)
302 {
303 	if (!szAppName || !szIcon)
304 		return M_BAD_POINTER;
305 
306 	SNARLSTRUCT ss;
307 
308 	m_hwndFrom = hWnd;
309 
310 	ss.Cmd = SNARL_REGISTER_CONFIG_WINDOW_2;
311 	ss.LngData2 = static_cast<LONG32>(reinterpret_cast<DWORD_PTR>(hWnd));
312 	ss.Id = replyMsg;
313 	strncpy((LPSTR)&ss.Title, szAppName, SNARL_STRING_LENGTH);
314 	strncpy((LPSTR)&ss.Icon, szIcon, SNARL_STRING_LENGTH);
315 
316 	return static_cast<M_RESULT>(Send(ss));
317 }
318 
RegisterConfig2(HWND hWnd,LPCWSTR szAppName,LONG32 replyMsg,LPCWSTR szIcon)319 M_RESULT SnarlInterface::RegisterConfig2(HWND hWnd, LPCWSTR szAppName, LONG32 replyMsg, LPCWSTR szIcon)
320 {
321 	LPSTR szParam1 = WideToUTF8(szAppName);
322 	LPSTR szParam2 = WideToUTF8(szIcon);
323 
324 	M_RESULT result = RegisterConfig2(hWnd, szParam1, replyMsg, szParam2);
325 
326 	delete [] szParam1;
327 	delete [] szParam2;
328 
329 	return result;
330 }
331 
332 
333 //-----------------------------------------------------------------------------
334 // snRevokeConfig
335 
336 /// Removes the application previously registered using snRegisterConfig() or
337 /// snRegisterConfig2(). hWnd should be the same as that used during registration.
338 
RevokeConfig(HWND hWnd)339 M_RESULT SnarlInterface::RevokeConfig(HWND hWnd)
340 {
341 	SNARLSTRUCT ss;
342 
343 	m_hwndFrom = NULL;
344 
345 	ss.Cmd = SNARL_REVOKE_CONFIG_WINDOW;
346 	ss.LngData2 = static_cast<LONG32>(reinterpret_cast<DWORD_PTR>(hWnd));
347 
348 	return static_cast<M_RESULT>(Send(ss));
349 }
350 
351 
352 //-----------------------------------------------------------------------------
353 // snGetVersion()
354 
355 /// Checks if Snarl is currently running and, if it is, retrieves the major and
356 /// minor release version numbers in Major and Minor respectively.
357 /// Returns True if Snarl is running, False otherwise.
358 
GetVersion(WORD * Major,WORD * Minor)359 BOOL SnarlInterface::GetVersion(WORD* Major, WORD* Minor)
360 {
361 	SNARLSTRUCT ss;
362 	ss.Cmd = SNARL_GET_VERSION;
363 	LONG32 versionInfo = Send(ss);
364 	if (versionInfo > 0 && versionInfo != M_FAILED && versionInfo != M_TIMED_OUT) {
365 		*Major = HIWORD(versionInfo);
366 		*Minor = LOWORD(versionInfo);
367 		return TRUE;
368 	}
369 	return FALSE;
370 }
371 
372 
373 //-----------------------------------------------------------------------------
374 // snGetVersionEx
375 
376 /// Returns the Snarl system version number. This is an integer value which
377 /// represents the system build number and can be used to identify the specific
378 /// version of Snarl running
379 
GetVersionEx()380 LONG32 SnarlInterface::GetVersionEx()
381 {
382 	SNARLSTRUCT ss;
383 	ss.Cmd = SNARL_GET_VERSION_EX;
384 	return Send(ss);
385 }
386 
387 
388 //-----------------------------------------------------------------------------
389 // snSetTimeout()
390 
391 /// Sets the timeout of existing notification Id to Timeout seconds. Id is the
392 /// value returned by snShowMessage() or snShowMessageEx() when the notification
393 /// was first created.
394 
SetTimeout(LONG32 Id,LONG32 Timeout)395 M_RESULT SnarlInterface::SetTimeout(LONG32 Id, LONG32 Timeout)
396 {
397 	SNARLSTRUCT ss;
398 	ss.Cmd = SNARL_SET_TIMEOUT;
399 	ss.Id = Id;
400 	ss.LngData2 = Timeout;
401 
402 	return static_cast<M_RESULT>(Send(ss));
403 }
404 
SetTimeout(LONG32 Timeout)405 M_RESULT SnarlInterface::SetTimeout(LONG32 Timeout)
406 {
407 	return SetTimeout(m_nLastMessageId, Timeout);
408 }
409 
410 //-----------------------------------------------------------------------------
411 // snRegisterAlert()
412 
413 /// Registers an alert of Class for application AppName which must have previously
414 /// been registered with either snRegisterConfig() or snRegisterConfig2().
415 
RegisterAlert(LPCSTR szAppName,LPCSTR szClass)416 M_RESULT SnarlInterface::RegisterAlert(LPCSTR szAppName, LPCSTR szClass)
417 {
418 	SNARLSTRUCT ss;
419 	ss.Cmd = SNARL_REGISTER_ALERT;
420 	strncpy((LPSTR)&ss.Title, szAppName, SNARL_STRING_LENGTH);
421 	strncpy((LPSTR)&ss.Text, szClass, SNARL_STRING_LENGTH);
422 
423 	return static_cast<M_RESULT>(Send(ss));
424 }
425 
RegisterAlert(LPCWSTR szAppName,LPCWSTR szClass)426 M_RESULT SnarlInterface::RegisterAlert(LPCWSTR szAppName, LPCWSTR szClass)
427 {
428 	LPSTR szParam1 = WideToUTF8(szAppName);
429 	LPSTR szParam2 = WideToUTF8(szClass);
430 
431 	M_RESULT result = RegisterAlert(szParam1, szParam2);
432 
433 	delete [] szParam1;
434 	delete [] szParam2;
435 
436 	return result;
437 }
438 
439 //-----------------------------------------------------------------------------
440 // snGetGlobalMsg()
441 
442 /// Returns the atom that corresponds to the "SnarlGlobalEvent" registered
443 /// Windows message. This message is sent by Snarl when it is first starts and
444 /// when it shuts down.
445 
GetGlobalMsg()446 LONG32 SnarlInterface::GetGlobalMsg()
447 {
448 	return RegisterWindowMessage(SNARL_GLOBAL_MSG);
449 }
450 
451 
452 //-----------------------------------------------------------------------------
453 // snGetSnarlWindow
454 
GetSnarlWindow()455 HWND SnarlInterface::GetSnarlWindow()
456 {
457 	HWND hWnd = FindWindow(SNARL_WINDOW_CLASS, SNARL_WINDOW_TITLE);
458 	if (hWnd == NULL)
459 		hWnd = FindWindow(NULL, SNARL_WINDOW_TITLE);
460 
461 	return hWnd;
462 }
463 
464 
465 //-----------------------------------------------------------------------------
466 // snGetAppPath()
467 
468 /// Returns a pointer to the path.
469 /// ** Remember to call FreeString
470 
GetAppPath()471 LPCTSTR SnarlInterface::GetAppPath()
472 {
473 	HWND hWnd = GetSnarlWindow();
474 	if (hWnd)
475 	{
476 		HWND hWndPath = FindWindowEx(hWnd, NULL, _T("static"), NULL);
477 		if (hWndPath)
478 		{
479 			TCHAR strTmp[MAX_PATH] = {0};
480 			int nReturn = GetWindowText(hWndPath, strTmp, MAX_PATH-1);
481 			if (nReturn > 0) {
482 				TCHAR* strReturn = AllocateString(nReturn + 1);
483 				_tcsncpy(strReturn, strTmp, nReturn + 1);
484 								strReturn[nReturn] = 0;
485 				return strReturn;
486 			}
487 		}
488 	}
489 
490 	return NULL;
491 }
492 
493 
494 //-----------------------------------------------------------------------------
495 // snGetIconsPath()
496 
497 /// Returns a pointer to the iconpath.
498 /// ** Remember to call FreeString when done with the string
499 
GetIconsPath()500 LPCTSTR SnarlInterface::GetIconsPath()
501 {
502 	TCHAR* szIconPath = NULL;
503 	LPCTSTR szPath = GetAppPath();
504 	if (!szPath)
505 		return NULL;
506 
507 	size_t nLen = 0;
508 	// TODO: _tcsnlen MAX_PATH
509 	if (nLen = _tcslen(szPath))
510 	{
511 		nLen += 10 + 1; // etc\\icons\\ + NULL
512 		szIconPath = AllocateString(nLen);
513 
514 		_tcsncpy(szIconPath, szPath, nLen);
515 		_tcsncat(szIconPath, _T("etc\\icons\\"), nLen);
516 	}
517 
518 	FreeString(szPath);
519 
520 	return szIconPath;
521 }
522 
523 
524 //-----------------------------------------------------------------------------
525 // snSetAsSnarlApp()
526 
527 /// Identifies an application as a Snarl App.  (V39)
528 
SetAsSnarlApp(HWND hWndOwner,SNARL_APP_FLAGS Flags)529 void SnarlInterface::SetAsSnarlApp(HWND hWndOwner, SNARL_APP_FLAGS Flags)
530 {
531 	if (IsWindow(hWndOwner)) {
532 		SetProp(hWndOwner, _T("snarl_app"), reinterpret_cast<HANDLE>(1));
533 		SetProp(hWndOwner, _T("snarl_app_flags"), reinterpret_cast<HANDLE>(Flags));
534 	}
535 }
536 
537 
538 //-----------------------------------------------------------------------------
539 // snGetAppMsg()
540 
541 /// Returns the global Snarl Application message  (V39)
542 
GetAppMsg()543 LONG32 SnarlInterface::GetAppMsg()
544 {
545 	return RegisterWindowMessage(SNARL_APP_MSG);
546 }
547 
548 
549 //-----------------------------------------------------------------------------
550 // snRegisterApp()
551 
552 /// Registers an application with Snarl  (V39)
553 
RegisterApp(LPCSTR Application,LPCSTR SmallIcon,LPCSTR LargeIcon,HWND hWnd,LONG32 ReplyMsg)554 M_RESULT SnarlInterface::RegisterApp(LPCSTR Application, LPCSTR SmallIcon, LPCSTR LargeIcon, HWND hWnd, LONG32 ReplyMsg)
555 {
556 	m_hwndFrom = hWnd;
557 
558 	SNARLSTRUCT ss;
559 	ss.Cmd = SNARL_REGISTER_APP;
560 
561 	strncpy((LPSTR)&ss.Title, Application, SNARL_STRING_LENGTH);
562 	strncpy((LPSTR)&ss.Icon,  SmallIcon, SNARL_STRING_LENGTH);
563 	strncpy((LPSTR)&ss.Text,  LargeIcon, SNARL_STRING_LENGTH);
564 
565 	ss.LngData2 = static_cast<LONG32>(reinterpret_cast<DWORD_PTR>(hWnd));
566 	ss.Id = ReplyMsg;
567 	ss.Timeout = GetCurrentProcessId();
568 
569 	return static_cast<M_RESULT>(Send(ss));
570 }
571 
RegisterApp(LPCWSTR Application,LPCWSTR SmallIcon,LPCWSTR LargeIcon,HWND hWnd,LONG32 ReplyMsg)572 M_RESULT SnarlInterface::RegisterApp(LPCWSTR Application, LPCWSTR SmallIcon, LPCWSTR LargeIcon, HWND hWnd, LONG32 ReplyMsg)
573 {
574 	LPSTR szParam1 = WideToUTF8(Application);
575 	LPSTR szParam2 = WideToUTF8(SmallIcon);
576 	LPSTR szParam3 = WideToUTF8(LargeIcon);
577 
578 	M_RESULT result = RegisterApp(szParam1, szParam2, szParam3, hWnd, ReplyMsg);
579 
580 	delete [] szParam1;
581 	delete [] szParam2;
582 	delete [] szParam3;
583 
584 	return result;
585 }
586 
587 
588 //-----------------------------------------------------------------------------
589 // snUnregisterApp()
590 
591 /// Unregisters an application with Snarl  (V39)
592 
UnregisterApp()593 M_RESULT SnarlInterface::UnregisterApp()
594 {
595 	SNARLSTRUCT ss;
596 	ss.Cmd = SNARL_UNREGISTER_APP;
597 	ss.LngData2 = GetCurrentProcessId();
598 
599 	m_hwndFrom = NULL;
600 
601 	return static_cast<M_RESULT>(Send(ss));
602 }
603 
604 
605 //-----------------------------------------------------------------------------
606 // snShowNotification()
607 
608 /// Displays a Snarl notification using registered class  (V39)
609 /// <returns>Message Id on success or M_RESULT on failure</returns>
610 /// LPCSTR Icon = NULL, HWND hWndReply = NULL, LONG32 uReplyMsg = 0, LPCSTR Sound = NULL);
ShowNotification(LPCSTR Class,LPCSTR Title,LPCSTR Text,LONG32 Timeout,LPCSTR Icon,HWND hWndReply,LONG32 uReplyMsg,LPCSTR Sound)611 LONG32 SnarlInterface::ShowNotification(LPCSTR Class, LPCSTR Title, LPCSTR Text, LONG32 Timeout, LPCSTR Icon /* = NULL */, HWND hWndReply /* = NULL */, LONG32 uReplyMsg /* = 0 */, LPCSTR Sound /* = NULL */)
612 {
613 	SNARLSTRUCTEX ssex;
614 	ZeroMemory(&ssex, sizeof(SNARLSTRUCTEX));
615 
616 	ssex.Cmd = SNARL_SHOW_NOTIFICATION;
617 
618 	strncpy((LPSTR)&ssex.Title, Title, SNARL_STRING_LENGTH);
619 	strncpy((LPSTR)&ssex.Text,  Text,  SNARL_STRING_LENGTH);
620 	if (Icon != NULL)
621 		strncpy((LPSTR)&ssex.Icon,  Icon,  SNARL_STRING_LENGTH);
622 	if (Sound != NULL)
623 		strncpy((LPSTR)&ssex.Extra, Sound, SNARL_STRING_LENGTH);
624 	if (Class != NULL)
625 		strncpy((LPSTR)&ssex.Class, Class, SNARL_STRING_LENGTH);
626 
627 	ssex.Timeout = Timeout;
628 	ssex.LngData2 = static_cast<LONG32>(reinterpret_cast<DWORD_PTR>(hWndReply));
629 	ssex.Id = uReplyMsg;
630 	ssex.Reserved1 = GetCurrentProcessId();
631 
632 	m_nLastMessageId = Send(ssex);
633 	return m_nLastMessageId;
634 }
635 
ShowNotification(LPCWSTR Class,LPCWSTR Title,LPCWSTR Text,LONG32 Timeout,LPCWSTR Icon,HWND hWndReply,LONG32 uReplyMsg,LPCWSTR Sound)636 LONG32 SnarlInterface::ShowNotification(LPCWSTR Class, LPCWSTR Title, LPCWSTR Text, LONG32 Timeout, LPCWSTR Icon, HWND hWndReply, LONG32 uReplyMsg, LPCWSTR Sound)
637 {
638 	LPSTR szParam1 = WideToUTF8(Class);
639 	LPSTR szParam2 = WideToUTF8(Title);
640 	LPSTR szParam3 = WideToUTF8(Text);
641 	LPSTR szParam4 = WideToUTF8(Icon);
642 	LPSTR szParam5 = WideToUTF8(Sound);
643 
644 	LONG32 result = ShowNotification(szParam1, szParam2, szParam3, Timeout, szParam4, hWndReply, uReplyMsg, szParam5);
645 
646 	delete [] szParam1;
647 	delete [] szParam2;
648 	delete [] szParam3;
649 	delete [] szParam4;
650 	delete [] szParam5;
651 
652 	return result;
653 }
654 
655 
656 //-----------------------------------------------------------------------------
657 // snChangeAttribute()
658 
659 /// (V39)
660 
ChangeAttribute(LONG32 Id,SNARL_ATTRIBUTES Attr,LPCSTR Value)661 M_RESULT SnarlInterface::ChangeAttribute(LONG32 Id, SNARL_ATTRIBUTES Attr, LPCSTR Value)
662 {
663 	SNARLSTRUCT ss;
664 	ss.Cmd = SNARL_CHANGE_ATTR;
665 	ss.Id = Id;
666 	ss.LngData2 = Attr;
667 
668 	strncpy((LPSTR)&ss.Text, Value, SNARL_STRING_LENGTH);
669 
670 	return static_cast<M_RESULT>(Send(ss));
671 }
672 
ChangeAttribute(LONG32 Id,SNARL_ATTRIBUTES Attr,LPCWSTR Value)673 M_RESULT SnarlInterface::ChangeAttribute(LONG32 Id, SNARL_ATTRIBUTES Attr, LPCWSTR Value)
674 {
675 	LPSTR szParam1 = WideToUTF8(Value);
676 
677 	M_RESULT result = ChangeAttribute(Id, Attr, szParam1);
678 
679 	delete [] szParam1;
680 
681 	return result;
682 }
683 
ChangeAttribute(SNARL_ATTRIBUTES Attr,LPCSTR Value)684 M_RESULT SnarlInterface::ChangeAttribute(SNARL_ATTRIBUTES Attr, LPCSTR Value)
685 {
686 	return ChangeAttribute(m_nLastMessageId, Attr, Value);
687 }
688 
ChangeAttribute(SNARL_ATTRIBUTES Attr,LPCWSTR Value)689 M_RESULT SnarlInterface::ChangeAttribute(SNARL_ATTRIBUTES Attr, LPCWSTR Value)
690 {
691 	return ChangeAttribute(m_nLastMessageId, Attr, Value);
692 }
693 
694 
695 //-----------------------------------------------------------------------------
696 // snSetClassDefault()
697 
698 /// Sets the default value for an alert class  (V39)
699 
SetClassDefault(LPCSTR Class,SNARL_ATTRIBUTES Attr,LPCSTR Value)700 M_RESULT SnarlInterface::SetClassDefault(LPCSTR Class, SNARL_ATTRIBUTES Attr, LPCSTR Value)
701 {
702 	SNARLSTRUCT ss;
703 	ss.Cmd = SNARL_SET_CLASS_DEFAULT;
704 	ss.LngData2 = Attr;
705 	ss.Timeout = GetCurrentProcessId();
706 
707 	strncpy((LPSTR)&ss.Text, Class, SNARL_STRING_LENGTH);
708 	strncpy((LPSTR)&ss.Icon, Value, SNARL_STRING_LENGTH);
709 
710 	return static_cast<M_RESULT>(Send(ss));
711 }
712 
SetClassDefault(LPCWSTR Class,SNARL_ATTRIBUTES Attr,LPCWSTR Value)713 M_RESULT SnarlInterface::SetClassDefault(LPCWSTR Class, SNARL_ATTRIBUTES Attr, LPCWSTR Value)
714 {
715 	LPSTR szParam1 = WideToUTF8(Class);
716 	LPSTR szParam2 = WideToUTF8(Value);
717 
718 	M_RESULT result = SetClassDefault(szParam1, Attr, szParam2);
719 
720 	delete [] szParam1;
721 	delete [] szParam2;
722 
723 	return result;
724 }
725 
726 
727 //-----------------------------------------------------------------------------
728 // snGetRevision()
729 
730 /// Gets the current Snarl revision (build) number  (V39)
731 /// Returns the build version number, or M_RESULT on failure.
732 
GetRevision()733 LONG32 SnarlInterface::GetRevision()
734 {
735 	SNARLSTRUCT ss;
736 	ss.Cmd = SNARL_GET_REVISION;
737 	ss.LngData2 = 0xFFFE;
738 
739 	return Send(ss);
740 }
741 
742 
743 //-----------------------------------------------------------------------------
744 // snAddClass()
745 
746 /// (V39)
747 
AddClass(LPCSTR Class,LPCSTR Description,SNARL_CLASS_FLAGS Flags,LPCSTR DefaultTitle,LPCSTR DefaultIcon,LONG32 DefaultTimeout)748 M_RESULT SnarlInterface::AddClass(LPCSTR Class, LPCSTR Description, SNARL_CLASS_FLAGS Flags, LPCSTR DefaultTitle, LPCSTR DefaultIcon, LONG32 DefaultTimeout)
749 {
750 	SNARLSTRUCT ss;
751 	ss.Cmd = SNARL_ADD_CLASS;
752 	ss.LngData2 = Flags;
753 	ss.Timeout = GetCurrentProcessId();
754 
755 	strncpy((LPSTR)&ss.Text,  Class, SNARL_STRING_LENGTH);
756 	strncpy((LPSTR)&ss.Title, Description, SNARL_STRING_LENGTH);
757 
758 	LONG32 result = Send(ss);
759 
760 	if (static_cast<M_RESULT>(result) == M_OK)
761 	{
762 		SetClassDefault(Class, SNARL_ATTRIBUTE_TITLE, DefaultTitle);
763 		SetClassDefault(Class, SNARL_ATTRIBUTE_ICON, DefaultIcon);
764 		if (DefaultTimeout > 0) {
765 			char str[64] = {0};
766 			_snprintf((LPSTR)&str, sizeof(str), "%d", DefaultTimeout);
767 			SetClassDefault(Class, SNARL_ATTRIBUTE_TIMEOUT, str);
768 		}
769 
770 		return M_OK;
771 	}
772 	else
773 		return M_FAILED;
774 }
775 
AddClass(LPCWSTR Class,LPCWSTR Description,SNARL_CLASS_FLAGS Flags,LPCWSTR DefaultTitle,LPCWSTR DefaultIcon,LONG32 DefaultTimeout)776 M_RESULT SnarlInterface::AddClass(LPCWSTR Class, LPCWSTR Description, SNARL_CLASS_FLAGS Flags, LPCWSTR DefaultTitle, LPCWSTR DefaultIcon, LONG32 DefaultTimeout)
777 {
778 	LPCSTR szClass        = WideToUTF8(Class);
779 	LPCSTR szDescription  = WideToUTF8(Description);
780 	LPCSTR szDefaultTitle = WideToUTF8(DefaultTitle);
781 	LPCSTR szDefaultIcon  = WideToUTF8(DefaultIcon);
782 
783 	M_RESULT result = AddClass(szClass, szDescription, Flags, szDefaultTitle, szDefaultIcon, DefaultTimeout);
784 
785 	delete [] szClass;
786 	delete [] szDescription;
787 	delete [] szDefaultTitle;
788 	delete [] szDefaultIcon;
789 
790 	return result;
791 }
792 
793 //-----------------------------------------------------------------------------
794 // Private functions
795 //-----------------------------------------------------------------------------
796 
797 template <class T>
Send(T ss)798 LONG32 SnarlInterface::Send(T ss)
799 {
800 	DWORD_PTR nReturn = M_FAILED;
801 
802 	HWND hWnd = GetSnarlWindow();
803 	if (IsWindow(hWnd))
804 	{
805 		COPYDATASTRUCT cds;
806 		cds.dwData = 2;
807 		cds.cbData = sizeof(ss);
808 		cds.lpData = &ss;
809 
810 		if (SendMessageTimeout(hWnd, WM_COPYDATA, (WPARAM)m_hwndFrom, (LPARAM)&cds, SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG, 1000, &nReturn) == 0)
811 		{
812 			if (GetLastError() == ERROR_TIMEOUT)
813 				nReturn = M_TIMED_OUT;
814 		}
815 	}
816 
817 	return static_cast<LONG32>(nReturn);
818 }
819 
820 //-----------------------------------------------------------------------------
821 
822 // Remember to : delete [] returned string
823 
WideToUTF8(LPCWSTR szWideStr)824 LPSTR SnarlInterface::WideToUTF8(LPCWSTR szWideStr)
825 {
826 	if (szWideStr == NULL)
827 		return NULL;
828 
829 	int nSize = WideCharToMultiByte(CP_UTF8, 0, szWideStr, -1, NULL, 0, NULL, NULL);
830 	LPSTR szUTF8 = new char[nSize];
831 	WideCharToMultiByte(CP_UTF8, 0, szWideStr, -1, szUTF8, nSize, NULL, NULL);
832 
833 	return szUTF8;
834 }
835 
836 }
837 } // namespace Snarl::V39
838