Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce Register Overload for assets #2596

Merged
merged 6 commits into from
Jun 30, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions dev/AppNotifications/AppNotificationManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <winrt/Windows.Foundation.Collections.h>
#include <WindowsAppRuntime.SelfContained.h>
#include <ShellLocalization.h>
#include <filesystem>

using namespace std::literals;

Expand Down Expand Up @@ -150,6 +151,54 @@ namespace winrt::Microsoft::Windows::AppNotifications::implementation
}
}

void AppNotificationManager::Register(hstring const& displayName, winrt::Windows::Foundation::Uri const& iconUri)
{
if (!IsSupported())
{
return;
}

HRESULT hr{ S_OK };
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved

auto logTelemetry{ wil::scope_exit([&]() {
AppNotificationTelemetry::LogRegister(hr, m_appId);
}) };

try
{
THROW_HR_IF_MSG(E_ILLEGAL_METHOD_CALL, AppModel::Identity::IsPackagedProcess(), "Not applicable for packaged applications");

THROW_HR_IF(E_INVALIDARG, (displayName == winrt::hstring{}) || (iconUri == nullptr));
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved

AppNotificationAssets assets{ GetAssets(displayName.c_str(), iconUri.RawUri().c_str()) };

{
auto lock{ m_lock.lock_exclusive() };
THROW_HR_IF_MSG(HRESULT_FROM_WIN32(ERROR_OPERATION_IN_PROGRESS), m_registering, "Registration is in progress!");
m_registering = true;
}

auto registeringScopeExit{ wil::scope_exit([&]()
{
auto lock { m_lock.lock_exclusive() };
m_registering = false;
}) };

winrt::guid registeredClsid{ RegisterUnpackagedApp(assets) };

// Create event handle before COM Registration otherwise if a notification arrives will lead to race condition
m_waitHandleForArgs.create();

// Register the AppNotificationManager as a COM server for Shell to Activate and Invoke
RegisterComServer(registeredClsid);
}
catch (...)
{
hr = wil::ResultFromCaughtException();
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved
throw;
}
}

void AppNotificationManager::RegisterComServer(winrt::guid const& registeredClsid)
{
auto lock{ m_lock.lock_exclusive() };
Expand Down
1 change: 1 addition & 0 deletions dev/AppNotifications/AppNotificationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace winrt::Microsoft::Windows::AppNotifications::implementation
static winrt::Microsoft::Windows::AppNotifications::AppNotificationManager Default();
static winrt::Windows::Foundation::IInspectable AppNotificationDeserialize(winrt::Windows::Foundation::Uri const& uri);
void Register();
void Register(hstring const& displayName, winrt::Windows::Foundation::Uri const& iconUri);
void Unregister();
void UnregisterAll();
static bool IsSupported();
Expand Down
9 changes: 9 additions & 0 deletions dev/AppNotifications/AppNotificationUtility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,15 @@ AppNotificationAssets Microsoft::Windows::AppNotifications::Helpers::GetAssets()
return assets;
}

AppNotificationAssets Microsoft::Windows::AppNotifications::Helpers::GetAssets(std::wstring displayName,std::wstring iconFilePath)
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved
{
winrt::check_bool(std::filesystem::exists(iconFilePath));
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved

THROW_HR_IF_MSG(E_INVALIDARG, !IsIconFileExtensionSupported(std::filesystem::path{ iconFilePath }), "Icon format not supported");
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved

return AppNotificationAssets{ std::move(displayName), std::move(iconFilePath) };
}

void Microsoft::Windows::AppNotifications::Helpers::RegisterAssets(std::wstring const& appId, std::wstring const& clsid, AppNotificationAssets const& assets)
{
wil::unique_hkey hKey;
Expand Down
2 changes: 2 additions & 0 deletions dev/AppNotifications/AppNotificationUtility.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,6 @@ namespace Microsoft::Windows::AppNotifications::Helpers
std::wstring GetDisplayNameBasedOnProcessName();

Microsoft::Windows::AppNotifications::ShellLocalization::AppNotificationAssets GetAssets();

Microsoft::Windows::AppNotifications::ShellLocalization::AppNotificationAssets GetAssets(std::wstring displayName, std::wstring iconFilePath);
}
3 changes: 3 additions & 0 deletions dev/AppNotifications/AppNotifications.idl
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ namespace Microsoft.Windows.AppNotifications
// For Unpackaged apps, the caller process will be registered as the COM server. And assets like displayname and icon will be gleaned from Shell and registered as well.
void Register();

// For Unpackaged apps only, the caller process will be registered as the COM server.
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved
void Register(String displayName, Windows.Foundation.Uri iconUri);

// Unregisters the COM Service so that a subsequent activation will launch a new process
void Unregister();

Expand Down
8 changes: 3 additions & 5 deletions dev/AppNotifications/ShellLocalization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ void WriteHIconToPngFile(wil::unique_hicon const& hIcon, _In_ PCWSTR pszFileName
THROW_IF_FAILED(spStreamOut->Commit(STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE));
}

bool IsIconFileExtensionSupported(std::filesystem::path const& iconFilePath)

bool Microsoft::Windows::AppNotifications::ShellLocalization::IsIconFileExtensionSupported(std::filesystem::path const& iconFilePath)
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved
{
static PCWSTR c_supportedExtensions[]{ L".bmp", L".ico", L".jpg", L".png" };

Expand Down Expand Up @@ -258,10 +259,7 @@ HRESULT Microsoft::Windows::AppNotifications::ShellLocalization::DeleteIconFromC
std::path iconFilePath{ RetrieveLocalFolderPath() / (notificationAppId + c_pngExtension) };

// If DeleteFile returned FALSE, then deletion failed and we should return the corresponding error code.
if (DeleteFile(iconFilePath.c_str()) == FALSE)
{
THROW_HR(HRESULT_FROM_WIN32(GetLastError()));
}
winrt::check_bool(DeleteFileW(iconFilePath.c_str()) != FALSE);
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved

return S_OK;
}
Expand Down
2 changes: 2 additions & 0 deletions dev/AppNotifications/ShellLocalization.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ namespace Microsoft::Windows::AppNotifications::ShellLocalization
HRESULT RetrieveAssetsFromShortcut(_Out_ Microsoft::Windows::AppNotifications::ShellLocalization::AppNotificationAssets& assets) noexcept;

HRESULT DeleteIconFromCache() noexcept;

bool IsIconFileExtensionSupported(std::filesystem::path const& iconFilePath);
}
175 changes: 175 additions & 0 deletions test/TestApps/ToastNotificationsTestApp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1322,6 +1322,171 @@ bool VerifyIconPathExists_Unpackaged()
return true;
}

bool VerifyRegisterWithNullDisplayNameFail_Unpackaged()
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved
{
// Register is already called in main with an explicit appusermodelId
winrt::AppNotificationManager::Default().UnregisterAll();
try
{
winrt::AppNotificationManager::Default().Register(winrt::hstring{}, winrt::Uri{ LR"(C:\Windows\System32\WindowsSecurityIcon.png)" });


sharath2727 marked this conversation as resolved.
Show resolved Hide resolved
winrt::AppNotificationManager::Default().UnregisterAll();
}
catch (...)
{
return winrt::to_hresult() == E_INVALIDARG;
}

return false;
}

bool VerifyRegisterWithNullIconFail_Unpackaged()
{
// Register is already called in main with an explicit appusermodelId
winrt::AppNotificationManager::Default().UnregisterAll();
try
{
winrt::AppNotificationManager::Default().Register(L"AppNotificationApp", nullptr);

winrt::AppNotificationManager::Default().UnregisterAll();
}
catch (...)
{
return winrt::to_hresult() == E_INVALIDARG;
}

return false;
}

bool VerifyRegisterWithNullDisplayNameAndNullIconFail_Unpackaged()
{
// Register is already called in main with an explicit appusermodelId
winrt::AppNotificationManager::Default().UnregisterAll();
try
{
winrt::AppNotificationManager::Default().Register(winrt::hstring{}, nullptr);


winrt::AppNotificationManager::Default().UnregisterAll();
}
catch (...)
{
return winrt::to_hresult() == E_INVALIDARG;
}

return true;
}

bool VerifyRegisterWithDisplayNameAndIcon_Unpackaged()
{
// Register is already called in main with an explicit appusermodelId
winrt::AppNotificationManager::Default().UnregisterAll();
try
{
winrt::AppNotificationManager::Default().Register(L"AppNotificationApp", winrt::Uri{ LR"(C:\Windows\System32\WindowsSecurityIcon.png)" });
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved

winrt::AppNotificationManager::Default().UnregisterAll();
}
catch (...)
{
return false;
}

return true;
}

bool VerifyRegisterWithDisplayNameAndInvalidIconPathFail_Unpackaged()
{
// Register is already called in main with an explicit appusermodelId
winrt::AppNotificationManager::Default().UnregisterAll();
try
{
winrt::AppNotificationManager::Default().Register(L"AppNotificationApp", winrt::Uri{ LR"(C:\InvalidPath\)" });

winrt::AppNotificationManager::Default().UnregisterAll();
}
catch (...)
{
return winrt::to_hresult() == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}

return false;
}

bool VerifyRegisterWithEmptyDisplayNameFail_Unpackaged()
{
// Register is already called in main with an explicit appusermodelId
winrt::AppNotificationManager::Default().UnregisterAll();
try
{
// hstring treats L"" as assigning nullptr
winrt::AppNotificationManager::Default().Register(L"", winrt::Uri{ LR"(C:\Windows\System32\WindowsSecurityIcon.png)" });
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved

winrt::AppNotificationManager::Default().UnregisterAll();
}
catch (...)
{
return winrt::to_hresult() == E_INVALIDARG;
}

return false;
}

bool VerifyRegisterWithEmptyIconFail_Unpackaged()
{
// Register is already called in main with an explicit appusermodelId
winrt::AppNotificationManager::Default().UnregisterAll();
try
{
winrt::AppNotificationManager::Default().Register(L"AppNotificationApp", winrt::Uri{ L"" });
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved

winrt::AppNotificationManager::Default().UnregisterAll();
}
catch (...)
{
return winrt::to_hresult() == E_POINTER;
}

return false;
}

bool VerifyRegisterWithEmptyDisplayNameAndEmptyIconFail_Unpackaged()
{
// Register is already called in main with an explicit appusermodelId
winrt::AppNotificationManager::Default().UnregisterAll();
try
{
winrt::AppNotificationManager::Default().Register(L"", winrt::Uri{ L"" });
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved

winrt::AppNotificationManager::Default().UnregisterAll();
}
catch (...)
{
return winrt::to_hresult() == E_POINTER;
}

return false;
}

bool VerifyRegisterWithAssetsFail()
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved
{
// Register is already called in main with an explicit appusermodelId
winrt::AppNotificationManager::Default().UnregisterAll();
try
{
winrt::AppNotificationManager::Default().Register(L"AppNotificationApp", winrt::Uri{ LR"(C:\InvalidPath\)" });
sharath2727 marked this conversation as resolved.
Show resolved Hide resolved

winrt::AppNotificationManager::Default().UnregisterAll();
}
catch (...)
{
return winrt::to_hresult() == E_ILLEGAL_METHOD_CALL;
}

return false;
}

std::map<std::string, bool(*)()> const& GetSwitchMapping()
{
static std::map<std::string, bool(*)()> switchMapping = {
Expand Down Expand Up @@ -1380,6 +1545,16 @@ std::map<std::string, bool(*)()> const& GetSwitchMapping()
{ "VerifyToastProgressDataSequence0Fail", &VerifyToastProgressDataSequence0Fail },
{ "VerifyToastUpdateZeroSequenceFail_Unpackaged", &VerifyToastUpdateZeroSequenceFail_Unpackaged },
{ "VerifyIconPathExists_Unpackaged", &VerifyIconPathExists_Unpackaged},

{ "VerifyRegisterWithNullDisplayNameFail_Unpackaged", &VerifyRegisterWithNullDisplayNameFail_Unpackaged},
{ "VerifyRegisterWithNullIconFail_Unpackaged", &VerifyRegisterWithNullIconFail_Unpackaged},
{ "VerifyRegisterWithNullDisplayNameAndNullIconFail_Unpackaged", &VerifyRegisterWithNullDisplayNameAndNullIconFail_Unpackaged},
{ "VerifyRegisterWithDisplayNameAndIcon_Unpackaged", &VerifyRegisterWithDisplayNameAndIcon_Unpackaged},
{ "VerifyRegisterWithDisplayNameAndInvalidIconPathFail_Unpackaged", &VerifyRegisterWithDisplayNameAndInvalidIconPathFail_Unpackaged},
{ "VerifyRegisterWithEmptyDisplayNameFail_Unpackaged", &VerifyRegisterWithEmptyDisplayNameFail_Unpackaged},
{ "VerifyRegisterWithEmptyIconFail_Unpackaged", &VerifyRegisterWithEmptyIconFail_Unpackaged},
{ "VerifyRegisterWithEmptyDisplayNameAndEmptyIconFail_Unpackaged", &VerifyRegisterWithEmptyDisplayNameAndEmptyIconFail_Unpackaged},
{ "VerifyRegisterWithAssetsFail", &VerifyRegisterWithAssetsFail},
};

return switchMapping;
Expand Down
45 changes: 45 additions & 0 deletions test/ToastNotificationTests/APITests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,5 +583,50 @@ namespace Test::ToastNotifications
{
RunTestUnpackaged(L"VerifyIconPathExists_Unpackaged", testWaitTime());
}

TEST_METHOD(VerifyRegisterWithNullDisplayNameFail_Unpackaged)
{
RunTestUnpackaged(L"VerifyRegisterWithNullDisplayNameFail_Unpackaged", testWaitTime());
}

TEST_METHOD(VerifyRegisterWithNullIconFail_Unpackaged)
{
RunTestUnpackaged(L"VerifyRegisterWithNullIconFail_Unpackaged", testWaitTime());
}

TEST_METHOD(VerifyRegisterWithNullDisplayNameAndNullIconFail_Unpackaged)
{
RunTestUnpackaged(L"VerifyRegisterWithNullDisplayNameAndNullIconFail_Unpackaged", testWaitTime());
}

TEST_METHOD(VerifyRegisterWithDisplayNameAndIcon_Unpackaged)
{
RunTestUnpackaged(L"VerifyRegisterWithDisplayNameAndIcon_Unpackaged", testWaitTime());
}

TEST_METHOD(VerifyRegisterWithDisplayNameAndInvalidIconPathFail_Unpackaged)
{
RunTestUnpackaged(L"VerifyRegisterWithDisplayNameAndInvalidIconPathFail_Unpackaged", testWaitTime());
}

TEST_METHOD(VerifyRegisterWithEmptyDisplayNameFail_Unpackaged)
{
RunTestUnpackaged(L"VerifyRegisterWithEmptyDisplayNameFail_Unpackaged", testWaitTime());
}

TEST_METHOD(VerifyRegisterWithEmptyIconFail_Unpackaged)
{
RunTestUnpackaged(L"VerifyRegisterWithEmptyIconFail_Unpackaged", testWaitTime());
}

TEST_METHOD(VerifyRegisterWithEmptyDisplayNameAndEmptyIconFail_Unpackaged)
{
RunTestUnpackaged(L"VerifyRegisterWithEmptyDisplayNameAndEmptyIconFail_Unpackaged", testWaitTime());
}

TEST_METHOD(VerifyRegisterWithAssetsFail)
{
RunTest(L"VerifyRegisterWithAssetsFail", testWaitTime());
}
};
}