Fix memory leaks in toast notifications

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/branches/gnustep_testplant_branch@39818 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Marcian Lytwyn 2016-05-29 20:28:36 +00:00
parent f8ce8e4ccd
commit f9303f7bbd
12 changed files with 171 additions and 64 deletions

View file

@ -68,7 +68,11 @@ static NSString * const kButtonActionKey = @"show";
@implementation NSImage (Private)
- (void)_setFilename:(NSString*)filename
{
#if 0
_fileName = [filename copy];
#else
ASSIGN(_fileName, filename);
#endif
}
- (NSString*)_filename
@ -115,7 +119,9 @@ static NSString * const kButtonActionKey = @"show";
appIcon = [self _iconFromImage:image];
appIconPath = [[image _filename] copy];
#if defined(DEBUG)
NSLog(@"%s:bundle: %@ image: %@ icon: %p path: %@", __PRETTY_FUNCTION__, classBundle, image, appIcon, appIconPath);
#endif
if (appIcon == NULL)
{
@ -165,7 +171,7 @@ static NSString * const kButtonActionKey = @"show";
{
pSendNotification = (SendNotificationFunctionPtr)GetProcAddress(hNotificationLib, "sendNotification");
pRemoveNotification = (RemoveNotificationFunctionPtr)GetProcAddress(hNotificationLib, "removeNotification");
#if 1 //defined(DEBUG)
#if defined(DEBUG)
NSLog(@"%s:DLL ptr: %p send notification ptr: %p remove ptr: %p", __PRETTY_FUNCTION__,
hNotificationLib, pSendNotification, pRemoveNotification);
#endif
@ -183,6 +189,9 @@ static NSString * const kButtonActionKey = @"show";
- (void) dealloc
{
#if defined(DEBUG)
NSLog(@"%s:", __PRETTY_FUNCTION__);
#endif
// Cleanup any icons we generated...
NSEnumerator *iter = [imageToIcon objectEnumerator];
HICON icon = NULL;
@ -191,8 +200,8 @@ static NSString * const kButtonActionKey = @"show";
DestroyIcon(icon);
}
RELEASE(appIconPath);
RELEASE(imageToIcon);
DESTROY(appIconPath);
DESTROY(imageToIcon);
[super dealloc];
}
@ -229,10 +238,10 @@ static NSString * const kButtonActionKey = @"show";
* must first check that any existing image of the same name has its
* name removed.
*/
[(NSImage*)[NSImage imageNamed: @"NSApplicationIcon"] setName: nil];
//[(NSImage*)[NSImage imageNamed: @"NSApplicationIcon"] setName: nil];
// We need to copy the image as we may have a proxy here
image = AUTORELEASE([image copy]);
[image setName: @"NSApplicationIcon"];
//[image setName: @"NSApplicationIcon"];
}
}
return image;

View file

@ -5,12 +5,12 @@ using namespace ABI::Windows::UI::Notifications;
ToastEventHandler::ToastEventHandler(_In_ HWND hToActivate, _In_ HWND hEdit) : _ref(1), _hToActivate(hToActivate), _hEdit(hEdit)
{
dll_dlog("");
dll_dlog("this: %p", this);
}
ToastEventHandler::~ToastEventHandler()
{
dll_dlog("");
dll_dlog("this: %p", this);
}
// DesktopToastActivatedEventHandler
@ -52,6 +52,7 @@ IFACEMETHODIMP ToastEventHandler::Invoke(_In_ IToastNotification* sender, _In_ I
}
dll_dlogw(L"IToastNotePtr: %p msg: %s", sender, outputText);
//notifier->RemoveFromSchedule
LRESULT succeeded = SendMessage(_hEdit, WM_SETTEXT, reinterpret_cast<WPARAM>(nullptr), reinterpret_cast<LPARAM>(outputText));
hr = succeeded ? S_OK : E_FAIL;
@ -67,3 +68,22 @@ IFACEMETHODIMP ToastEventHandler::Invoke(_In_ IToastNotification* /* sender */,
LRESULT succeeded = SendMessage(_hEdit, WM_SETTEXT, reinterpret_cast<WPARAM>(nullptr), reinterpret_cast<LPARAM>(L"The toast encountered an error."));
return succeeded ? S_OK : E_FAIL;
}
IFACEMETHODIMP_(ULONG) ToastEventHandler::AddRef()
{
LONG value = InterlockedIncrement(&_ref);
dll_dlog("ref: %d value: %d", _ref, value);
return value;
}
IFACEMETHODIMP_(ULONG) ToastEventHandler::Release()
{
ULONG l = InterlockedDecrement(&_ref);
dll_dlog("ref: %d value: %d", _ref, l);
if (l == 0)
{
dll_dlog("deleting this: %p", this);
delete this;
}
return l;
}

View file

@ -21,13 +21,9 @@ public:
IFACEMETHODIMP Invoke(_In_ ABI::Windows::UI::Notifications::IToastNotification *sender, _In_ ABI::Windows::UI::Notifications::IToastFailedEventArgs *e);
// IUnknown
IFACEMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&_ref); }
IFACEMETHODIMP_(ULONG) AddRef();
IFACEMETHODIMP_(ULONG) Release() {
ULONG l = InterlockedDecrement(&_ref);
if (l == 0) delete this;
return l;
}
IFACEMETHODIMP_(ULONG) Release();
IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _COM_Outptr_ void **ppv) {
if (IsEqualIID(riid, IID_IUnknown))

View file

@ -0,0 +1,61 @@
#include "stdafx.h"
#include "ToastNotification.h"
#include "ToastEventHandler.h"
using namespace ABI::Windows::UI::Notifications;
using namespace Microsoft::WRL;
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CToastNotification::CToastNotification(IToastNotification *toastNotification, HWND _hwnd)
{
dll_dlog("this: %p, toast: %p", this, toastNotification);
this->toastNotification = toastNotification;
// Register the event handlers
ComPtr<ToastEventHandler> eventHandler(new ToastEventHandler(_hwnd, _hwnd));
toastEventHandler = eventHandler.Get();
HRESULT hr = toastNotification->add_Activated(eventHandler.Get(), &activatedToken);
if (FAILED(hr))
{
dll_log("toast->add_Activated failed - status: %d", GetLastError());
}
else
{
dll_dlog("activatedToken: %d", activatedToken.value);
hr = toastNotification->add_Dismissed(eventHandler.Get(), &dismissedToken);
if (FAILED(hr))
{
dll_log("toast->add_Dismissed failed - status: %d", GetLastError());
}
else
{
dll_dlog("dismissedToken: %d", dismissedToken.value);
hr = toastNotification->add_Failed(eventHandler.Get(), &failedToken);
if (FAILED(hr))
{
dll_log("toast->add_Failed failed - status: %d", GetLastError());
}
else
{
dll_dlog("failedToken: %d - DONE", failedToken.value);
}
}
}
}
CToastNotification::~CToastNotification()
{
dll_dlog("this: %p toast: %p", this, toastNotification);
#if 0
toastNotification->remove_Activated(activatedToken);
toastNotification->remove_Dismissed(dismissedToken);
toastNotification->remove_Failed(failedToken);
#endif
delete toastEventHandler;
}

View file

@ -0,0 +1,20 @@
#pragma once
#include "afx.h"
class ToastEventHandler;
class CToastNotification : public CObject
{
public:
CToastNotification(ABI::Windows::UI::Notifications::IToastNotification * toastNotification, HWND _hwnd);
~CToastNotification();
protected:
private:
ABI::Windows::UI::Notifications::IToastNotification *toastNotification;
ToastEventHandler *toastEventHandler;
EventRegistrationToken activatedToken;
EventRegistrationToken dismissedToken;
EventRegistrationToken failedToken;
};

View file

@ -11,7 +11,7 @@
#include <Windows.ui.notifications.h>
#include <strsafe.h>
#include "ToastNotifications.h"
#include "ToastEventHandler.h"
#include "ToastNotification.h"
#include "../../../MSUserNotificationAPI.h"
#include <locale>
@ -51,7 +51,6 @@ using namespace Windows::Foundation;
// Please see MFC Technical Notes 33 and 58 for additional
// details.
//
// CToastNotificationsApp
BEGIN_MESSAGE_MAP(CToastNotificationsApp, CWinApp)
@ -62,12 +61,12 @@ CToastNotificationsApp::CToastNotificationsApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
dll_dlog("");
dll_dlog("this: %p", this);
}
CToastNotificationsApp::~CToastNotificationsApp()
{
dll_dlog("");
dll_dlog("this: %p", this);
}
// The one and only CToastNotificationsApp object
@ -79,10 +78,33 @@ CToastNotificationsApp theApp;
BOOL CToastNotificationsApp::InitInstance()
{
dll_dlog("this: %p", this);
CWinApp::InitInstance();
// Do our cleanup here AFTER invoking sub-class method...
return TRUE;
}
BOOL CToastNotificationsApp::ExitInstance()
{
dll_dlog("this: %p", this);
// Do our cleanup here BEFORE invoking sub-class method...
if (toasts.size() > 0)
{
dll_dlog("deleting toast - cnt: %d", toasts.size());
std::vector<CToastNotification*>::iterator toast;
for (toast = toasts.begin(); toast < toasts.end(); ++toast)
{
dll_dlog("toast ptr: %p", *toast);
delete *toast;
}
}
return CWinApp::ExitInstance();
}
// In order to display toasts, a desktop application must have a shortcut on the Start menu.
// Also, an AppUserModelID must be set on that shortcut.
// The shortcut should be created as part of the installer. The following code shows how to create
@ -91,7 +113,6 @@ BOOL CToastNotificationsApp::InitInstance()
//
// Included in this project is a wxs file that be used with the WiX toolkit
// to make an installer that creates the necessary shortcut. One or the other should be used.
HRESULT CToastNotificationsApp::TryCreateShortcut()
{
wchar_t shortcutPath[MAX_PATH];
@ -204,7 +225,7 @@ HRESULT CToastNotificationsApp::CreateToastXml(_In_ IToastNotificationManagerSta
// Get full path to image...
imagePath = _wfullpath(nullptr, imagePath, MAX_PATH);
dll_logw(TEXT("loading application image file: %s"), imagePath);
dll_dlogw(TEXT("loading application image file: %s"), imagePath);
hr = imagePath != nullptr ? S_OK : HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
if (FAILED(hr))
@ -231,6 +252,9 @@ HRESULT CToastNotificationsApp::CreateToastXml(_In_ IToastNotificationManagerSta
UINT32 textLengths[] = { wcslen(notificationTitle), wcslen(notificationDescription), 6 };
hr = SetTextValues(textValues, 3, textLengths, *inputXml);
}
// Delete/free imagePath from _wfullpath call above...
free(imagePath);
}
}
return hr;
@ -412,35 +436,10 @@ HRESULT CToastNotificationsApp::CreateToast(_In_ IToastNotificationManagerStatic
}
else
{
// Register the event handlers
EventRegistrationToken activatedToken, dismissedToken, failedToken;
ComPtr<ToastEventHandler> eventHandler(new ToastEventHandler(_hwnd, _hwnd));
toast->add_Activated(eventHandler.Get(), &activatedToken);
if (FAILED(hr))
{
dll_log("toast->add_Activated failed - status: %d", GetLastError());
}
else
{
hr = toast->add_Dismissed(eventHandler.Get(), &dismissedToken);
if (FAILED(hr))
{
dll_log("toast->add_Dismissed failed - status: %d", GetLastError());
}
else
{
hr = toast->add_Failed(eventHandler.Get(), &failedToken);
if (FAILED(hr))
{
dll_log("toast->add_Failed failed - status: %d", GetLastError());
}
else
{
hr = notifier->Show(toast.Get());
}
}
}
CToastNotification *toastNotification = new CToastNotification(toast.Get(), _hwnd);
hr = notifier->Show(toast.Get());
if (SUCCEEDED(hr))
toasts.push_back(toastNotification);
}
}
}
@ -519,6 +518,6 @@ extern "C" EXPORT BOOL __cdecl sendNotification(HWND hWnd, HICON icon, SEND_NOTE
extern "C" EXPORT BOOL __cdecl removeNotification(HICON icon, REMOVE_NOTE_INFO_T *noteinfo)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
dll_log("note %p uniqueID: %d", noteinfo, noteinfo->uniqueID);
dll_dlog("note %p uniqueID: %d", noteinfo, noteinfo->uniqueID);
return FALSE;
}

View file

@ -2,21 +2,20 @@
//
#pragma once
#
#ifndef __AFXWIN_H__
#error "include 'stdafx.h' before including this file for PCH"
#endif
#include "resource.h" // main symbols
#include <vector>
const wchar_t AppId[] = L"Testplant.Notifications.Eggplant";
// CToastNotificationsApp
// See ToastNotifications.cpp for the implementation of this class
//
class CToastNotification;
class CToastNotificationsApp : public CWinApp
{
@ -26,13 +25,13 @@ public:
// Overrides
public:
virtual BOOL InitInstance();
virtual BOOL InitInstance();
virtual BOOL ExitInstance();
DECLARE_MESSAGE_MAP()
friend class ToastEventHandler;
public:
//HRESULT DisplayToast(HWND hWnd, wchar_t* notificationTitle, wchar_t* notificationDescription);
HRESULT DisplayToast(HWND hWnd, wchar_t* notificationTitle, wchar_t* notificationDescription, wchar_t* imagePath);
HRESULT CreateToastXml(
_In_ ABI::Windows::UI::Notifications::IToastNotificationManagerStatics *toastManager,
@ -64,4 +63,5 @@ protected:
private:
HWND _hwnd;
HWND _hEdit;
std::vector<CToastNotification*> toasts;
};

View file

@ -109,6 +109,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="ToastEventHandler.cpp" />
<ClCompile Include="ToastNotification.cpp" />
<ClCompile Include="ToastNotifications.cpp" />
</ItemGroup>
<ItemGroup>
@ -117,6 +118,7 @@
<ClInclude Include="StringReferenceWrapper.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="ToastEventHandler.h" />
<ClInclude Include="ToastNotification.h" />
<ClInclude Include="ToastNotifications.h" />
</ItemGroup>
<ItemGroup>
@ -126,9 +128,6 @@
<ItemGroup>
<ResourceCompile Include="ToastNotifications.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="toastImageAndText.png" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View file

@ -27,6 +27,9 @@
<ClCompile Include="ToastEventHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ToastNotification.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ToastNotifications.h">
@ -47,6 +50,9 @@
<ClInclude Include="ToastEventHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ToastNotification.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="ToastNotifications.def">
@ -61,9 +67,4 @@
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Image Include="toastImageAndText.png">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
</Project>

View file

@ -3,12 +3,14 @@
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
#include <string>
#include <sstream>
void dll_log_s(const char *function, int line, const char *format, ...)
{
static const size_t STRBUFSIZE = 512;
static char str[STRBUFSIZE];
std::stringstream message;
va_list argptr;
va_start(argptr, format);
sprintf_s(str, STRBUFSIZE, "%s:%d: ", function, line);