From b3951a46fb5ca75d152cd6942e66d57eab6b87c4 Mon Sep 17 00:00:00 2001 From: Scott Darnell <20483794+aeloros@users.noreply.github.com> Date: Fri, 30 Oct 2020 20:50:59 -0700 Subject: [PATCH] User/aeloros/get args (#268) * Initial template for the AppLifecycle object and it's tests. * Initial set of components * Basic Launch and Protocol support * Move registration methods to new runtimeclass. Stub out new ancillary interfaces on the event args classes. * Remove samples from the project dll. * Remove work for file type associations for now. Remove shared samples completely. * Block registration for packaged apps (they should use their manifest for v1). Make GetActivatedEventArgs defer to the platform for packaged apps. * Add LaunchActivatedEventArgs test. * Remove unneeded interfaces. * use a static const wstring instead of a C define for comparison. * PR feedback around default constructor. * PR feedback * PR feedback * PR Feedback * PR Feedback --- ProjectReunion.sln | 27 ++--- build/CopyFilesToStagingDir.ps1 | 1 - .../ProjectReunionFrameworkPackage.nuspec | 1 - dev/AppLifecycle/ActivatedEventArgsBase.h | 37 +++++++ .../ActivationRegistrationManager.cpp | 76 +++++++++++++ .../ActivationRegistrationManager.h | 33 ++++++ dev/AppLifecycle/AppLifecycle.cpp | 62 +++++++++++ dev/AppLifecycle/AppLifecycle.h | 22 ++++ dev/AppLifecycle/AppLifecycle.idl | 23 ++++ dev/AppLifecycle/AppLifecycle.vcxitems | 29 +++++ dev/AppLifecycle/LaunchActivatedEventArgs.h | 36 +++++++ dev/AppLifecycle/ProtocolActivatedEventArgs.h | 31 ++++++ dev/AppLifecycle/Shared.cpp | 101 ++++++++++++++++++ dev/AppLifecycle/Shared.h | 16 +++ dev/ProjectReunion_DLL/ProjectReunion.def | 4 - .../ProjectReunion_DLL.vcxproj | 3 +- dev/ProjectReunion_DLL/pch.h | 7 +- dev/SampleFlatC/README.md | 59 ---------- dev/SampleFlatC/SampleFlatC.cpp | 41 ------- dev/SampleFlatC/SampleFlatC.h | 30 ------ dev/SampleWinRT/README.md | 52 --------- dev/SampleWinRT/SampleWinRT.cpp | 6 -- dev/SampleWinRT/SampleWinRT.h | 54 ---------- dev/SampleWinRT/SampleWinRT.idl | 15 --- dev/SampleWinRT/SampleWinRT.vcxitems | 29 ----- test/AppLifecycle/ApiTests.cpp | 38 +++++++ .../AppLifecycle/AppLifecycle.vcxitems | 14 +-- test/CppShared/TestMany.cpp | 45 -------- test/CppTest/CppTest.vcxproj | 3 + test/CppTest/pch.h | 3 +- test/CppTest_UWP/CppTest_UWP.vcxproj | 3 + test/CppTest_UWP/pch.h | 3 +- 32 files changed, 534 insertions(+), 370 deletions(-) create mode 100644 dev/AppLifecycle/ActivatedEventArgsBase.h create mode 100644 dev/AppLifecycle/ActivationRegistrationManager.cpp create mode 100644 dev/AppLifecycle/ActivationRegistrationManager.h create mode 100644 dev/AppLifecycle/AppLifecycle.cpp create mode 100644 dev/AppLifecycle/AppLifecycle.h create mode 100644 dev/AppLifecycle/AppLifecycle.idl create mode 100644 dev/AppLifecycle/AppLifecycle.vcxitems create mode 100644 dev/AppLifecycle/LaunchActivatedEventArgs.h create mode 100644 dev/AppLifecycle/ProtocolActivatedEventArgs.h create mode 100644 dev/AppLifecycle/Shared.cpp create mode 100644 dev/AppLifecycle/Shared.h delete mode 100644 dev/SampleFlatC/README.md delete mode 100644 dev/SampleFlatC/SampleFlatC.cpp delete mode 100644 dev/SampleFlatC/SampleFlatC.h delete mode 100644 dev/SampleWinRT/README.md delete mode 100644 dev/SampleWinRT/SampleWinRT.cpp delete mode 100644 dev/SampleWinRT/SampleWinRT.h delete mode 100644 dev/SampleWinRT/SampleWinRT.idl delete mode 100644 dev/SampleWinRT/SampleWinRT.vcxitems create mode 100644 test/AppLifecycle/ApiTests.cpp rename dev/SampleFlatC/SampleFlatC.vcxitems => test/AppLifecycle/AppLifecycle.vcxitems (59%) diff --git a/ProjectReunion.sln b/ProjectReunion.sln index a2d3cb271..ae24d870b 100644 --- a/ProjectReunion.sln +++ b/ProjectReunion.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 16.0.30011.22 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dev", "dev", "{448ED2E5-0B37-4D97-9E6B-8C10A507976A}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SampleWinRT", "SampleWinRT", "{428CCA9E-ADC5-4917-B51B-7D13E35950C5}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{F3659DFF-232D-46E0-967E-61FCC9A1132F}" ProjectSection(SolutionItems) = preProject docs\contributor-guide.md = docs\contributor-guide.md @@ -15,12 +13,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{F3659DFF-2 docs\roadmap.md = docs\roadmap.md EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleWinRT", "dev\SampleWinRT\SampleWinRT.vcxitems", "{0DE4FEFE-5471-4B50-B74B-D817A02B7F0D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SampleFlatC", "SampleFlatC", "{8A5C2FE6-86D7-4AAA-BE2E-924B8E03B888}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleFlatC", "dev\SampleFlatC\SampleFlatC.vcxitems", "{CDCE22EC-F7BF-43D4-95D8-2E786229A4E5}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8630F7AA-2969-4DC9-8700-9B468C1DC21D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CppShared", "test\CppShared\CppShared.vcxitems", "{682DED8C-3A27-48CD-866D-E853EA2024DE}" @@ -31,15 +23,19 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CppTest_Win32", "test\CppTe EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CppTest_UWP", "test\CppTest_UWP\CppTest_UWP.vcxproj", "{B1A6F5EC-5418-4354-BACF-F7D998EE960D}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AppLifecycle", "AppLifecycle", "{3DE93B2F-F887-437D-B512-6B1024ABA290}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppLifecycle", "dev\AppLifecycle\AppLifecycle.vcxitems", "{E3A522A3-6635-4A42-BDED-1AF46A15F63C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppLifecycle", "test\AppLifecycle\AppLifecycle.vcxitems", "{80E07022-9E99-44FE-B875-901FB6C82F52}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution - dev\SampleWinRT\SampleWinRT.vcxitems*{0de4fefe-5471-4b50-b74b-d817a02b7f0d}*SharedItemsImports = 9 test\CppShared\CppShared.vcxitems*{682ded8c-3a27-48cd-866d-e853ea2024de}*SharedItemsImports = 9 + test\AppLifecycle\AppLifecycle.vcxitems*{80e07022-9e99-44fe-b875-901fb6c82f52}*SharedItemsImports = 9 test\CppShared\CppShared.vcxitems*{b1a6f5ec-5418-4354-bacf-f7d998ee960d}*SharedItemsImports = 4 - dev\SampleFlatC\SampleFlatC.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 - dev\SampleWinRT\SampleWinRT.vcxitems*{b73ad907-6164-4294-88fb-f3c9c10da1f1}*SharedItemsImports = 4 test\CppShared\CppShared.vcxitems*{c62688a1-16a0-4729-b6ed-842f4faa29f3}*SharedItemsImports = 4 - dev\SampleFlatC\SampleFlatC.vcxitems*{cdce22ec-f7bf-43d4-95d8-2e786229a4e5}*SharedItemsImports = 9 + dev\AppLifecycle\AppLifecycle.vcxitems*{e3a522a3-6635-4a42-bded-1af46a15f63c}*SharedItemsImports = 9 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug_test|Any CPU = Debug_test|Any CPU @@ -157,14 +153,13 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {428CCA9E-ADC5-4917-B51B-7D13E35950C5} = {448ED2E5-0B37-4D97-9E6B-8C10A507976A} - {0DE4FEFE-5471-4B50-B74B-D817A02B7F0D} = {428CCA9E-ADC5-4917-B51B-7D13E35950C5} - {8A5C2FE6-86D7-4AAA-BE2E-924B8E03B888} = {448ED2E5-0B37-4D97-9E6B-8C10A507976A} - {CDCE22EC-F7BF-43D4-95D8-2E786229A4E5} = {8A5C2FE6-86D7-4AAA-BE2E-924B8E03B888} {682DED8C-3A27-48CD-866D-E853EA2024DE} = {8630F7AA-2969-4DC9-8700-9B468C1DC21D} {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {448ED2E5-0B37-4D97-9E6B-8C10A507976A} {C62688A1-16A0-4729-B6ED-842F4FAA29F3} = {8630F7AA-2969-4DC9-8700-9B468C1DC21D} {B1A6F5EC-5418-4354-BACF-F7D998EE960D} = {8630F7AA-2969-4DC9-8700-9B468C1DC21D} + {3DE93B2F-F887-437D-B512-6B1024ABA290} = {448ED2E5-0B37-4D97-9E6B-8C10A507976A} + {E3A522A3-6635-4A42-BDED-1AF46A15F63C} = {3DE93B2F-F887-437D-B512-6B1024ABA290} + {80E07022-9E99-44FE-B875-901FB6C82F52} = {8630F7AA-2969-4DC9-8700-9B468C1DC21D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4B3D7591-CFEC-4762-9A07-ABE99938FB77} diff --git a/build/CopyFilesToStagingDir.ps1 b/build/CopyFilesToStagingDir.ps1 index e6c45adf8..d53a6fe61 100644 --- a/build/CopyFilesToStagingDir.ps1 +++ b/build/CopyFilesToStagingDir.ps1 @@ -33,7 +33,6 @@ function PublishFile { PublishFile -IfExists $FullBuildOutput\projectreunion_dll\Microsoft.ProjectReunion.dll $FullPublishDir\Microsoft.ProjectReunion\ PublishFile -IfExists $FullBuildOutput\projectreunion_dll\Microsoft.ProjectReunion.lib $FullPublishDir\Microsoft.ProjectReunion\ -PublishFile -IfExists $FullBuildOutput\projectreunion_dll\SampleFlatC.h $FullPublishDir\Microsoft.ProjectReunion\ #PublishFile -IfExists $FullBuildOutput\projectreunion_dll\Microsoft.ProjectReunion.pri $FullPublishDir\Microsoft.ProjectReunion\ #UNDONE - xaml vcxproj re-runs an mdmerge into the sdk node, we are skipping this for now and leaving the winmd in its normal outdir #PublishFile -IfExists $FullBuildOutput\projectreunion_dll\sdk\Microsoft.ProjectReunion.winmd $FullPublishDir\Microsoft.ProjectReunion\sdk\ diff --git a/build/NuSpecs/ProjectReunionFrameworkPackage.nuspec b/build/NuSpecs/ProjectReunionFrameworkPackage.nuspec index 8a8296aa7..b9dc6dc1a 100644 --- a/build/NuSpecs/ProjectReunionFrameworkPackage.nuspec +++ b/build/NuSpecs/ProjectReunionFrameworkPackage.nuspec @@ -25,7 +25,6 @@ - diff --git a/dev/AppLifecycle/ActivatedEventArgsBase.h b/dev/AppLifecycle/ActivatedEventArgsBase.h new file mode 100644 index 000000000..7ee52c346 --- /dev/null +++ b/dev/AppLifecycle/ActivatedEventArgsBase.h @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +#pragma once + +namespace winrt::Microsoft::ProjectReunion::implementation +{ + using namespace winrt::Windows::ApplicationModel::Activation; + + class ActivatedEventArgsBase : public winrt::implements + { + public: + // IActivatedEventArgs + ActivationKind Kind() + { + return m_kind; + } + + ApplicationExecutionState PreviousExecutionState() + { + return m_previousState; + } + + SplashScreen SplashScreen() + { + return m_splashScreen; + } + + protected: + ActivatedEventArgsBase() = default; + + ActivationKind m_kind = ActivationKind::Launch; + ApplicationExecutionState m_previousState; + winrt::Windows::ApplicationModel::Activation::SplashScreen m_splashScreen{ nullptr }; + }; +} + diff --git a/dev/AppLifecycle/ActivationRegistrationManager.cpp b/dev/AppLifecycle/ActivationRegistrationManager.cpp new file mode 100644 index 000000000..e53806410 --- /dev/null +++ b/dev/AppLifecycle/ActivationRegistrationManager.cpp @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +#include +#include +#include + +#include "LaunchActivatedEventArgs.h" +#include "ProtocolActivatedEventArgs.h" +#include "Shared.h" + +namespace winrt::Microsoft::ProjectReunion::implementation +{ + void ActivationRegistrationManager::RegisterForFileTypeActivation(hstring const& groupName, + hstring const& logo, array_view supportedFileTypes, + array_view supportedVerbs) + { + throw hresult_not_implemented(); + } + + void ActivationRegistrationManager::RegisterForProtocolActivation(hstring const& scheme, + hstring const& displayName) + { + if (scheme.empty() || displayName.empty()) + { + throw winrt::hresult_invalid_argument(); + } + + if (HasIdentity()) + { + throw hresult_not_implemented(); + } + + RegisterProtocol(scheme.c_str(), displayName.c_str()); + } + + void ActivationRegistrationManager::RegisterForStartupActivation(hstring const& taskId, + bool isEnabled, hstring const& displayName) + { + throw hresult_not_implemented(); + } + + void ActivationRegistrationManager::RegisterForToastActivation(hstring const& displayName) + { + throw hresult_not_implemented(); + } + + void ActivationRegistrationManager::UnregisterForFileTypeActivation(hstring const& groupName) + { + throw hresult_not_implemented(); + } + + void ActivationRegistrationManager::UnregisterForProtocolActivation(hstring const& scheme) + { + if (scheme.empty()) + { + throw winrt::hresult_invalid_argument(); + } + + if (HasIdentity()) + { + throw hresult_not_implemented(); + } + + UnregisterProtocol(scheme.c_str()); + } + + void ActivationRegistrationManager::UnregisterForStartupActivation() + { + throw hresult_not_implemented(); + } + + void ActivationRegistrationManager::UnregisterForToastActivation() + { + throw hresult_not_implemented(); + } +} diff --git a/dev/AppLifecycle/ActivationRegistrationManager.h b/dev/AppLifecycle/ActivationRegistrationManager.h new file mode 100644 index 000000000..1466f246e --- /dev/null +++ b/dev/AppLifecycle/ActivationRegistrationManager.h @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +#pragma once + +#include + +namespace winrt::Microsoft::ProjectReunion::implementation +{ + struct ActivationRegistrationManager + { + ActivationRegistrationManager() = default; + + static void RegisterForFileTypeActivation(hstring const& groupName, hstring const& logo, + array_view supportedFileTypes, array_view supportedVerbs); + static void RegisterForProtocolActivation(hstring const& scheme, hstring const& displayName); + static void RegisterForStartupActivation(hstring const& taskId, bool isEnabled, + hstring const& displayName); + static void RegisterForToastActivation(hstring const& displayName); + + static void UnregisterForFileTypeActivation(hstring const& groupName); + static void UnregisterForProtocolActivation(hstring const& scheme); + static void UnregisterForStartupActivation(); + static void UnregisterForToastActivation(); + }; +} + +namespace winrt::Microsoft::ProjectReunion::factory_implementation +{ + struct ActivationRegistrationManager : ActivationRegistrationManagerT + { + }; +} diff --git a/dev/AppLifecycle/AppLifecycle.cpp b/dev/AppLifecycle/AppLifecycle.cpp new file mode 100644 index 000000000..b620ee58e --- /dev/null +++ b/dev/AppLifecycle/AppLifecycle.cpp @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#include +#include +#include + +#include "LaunchActivatedEventArgs.h" +#include "ProtocolActivatedEventArgs.h" +#include "Shared.h" + +namespace winrt::Microsoft::ProjectReunion::implementation +{ + std::tuple ParseCommandLine(std::wstring commandLine) + { + auto argsStart = commandLine.rfind(L"----") + 4; + if (argsStart == std::wstring::npos) + { + return {L"", L""}; + } + + // We explicitly use find_first_of here, so that the resulting data may contain : as a valid character. + auto argsEnd = commandLine.find_first_of(L":", argsStart); + if (argsEnd == std::wstring::npos) + { + return {L"", L""}; + } + + if (argsStart > argsEnd) + { + throw std::overflow_error("commandLine"); + } + + auto argsLength = argsEnd - argsStart; + auto dataStart = argsEnd + 1; + + return {commandLine.substr(argsStart, argsLength), commandLine.substr(dataStart)}; + } + + Windows::ApplicationModel::Activation::IActivatedEventArgs AppLifecycle::GetActivatedEventArgs() + { + if (HasIdentity()) + { + return Windows::ApplicationModel::AppInstance::GetActivatedEventArgs(); + } + else + { + // Generate IActivatedEventArgs for non-Packaged applications. + std::wstring contractId; + std::wstring contractData; + auto commandLine = std::wstring(GetCommandLine()); + std::tie(contractId, contractData) = ParseCommandLine(commandLine); + + if (!contractId.empty() && contractId == c_protocolArgumentString) + { + return winrt::make(contractData); + } + + return winrt::make(commandLine); + } + } +} diff --git a/dev/AppLifecycle/AppLifecycle.h b/dev/AppLifecycle/AppLifecycle.h new file mode 100644 index 000000000..636ed0a5c --- /dev/null +++ b/dev/AppLifecycle/AppLifecycle.h @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +#pragma once + +#include + +namespace winrt::Microsoft::ProjectReunion::implementation +{ + struct AppLifecycle + { + AppLifecycle() = default; + + static Windows::ApplicationModel::Activation::IActivatedEventArgs GetActivatedEventArgs(); + }; +} + +namespace winrt::Microsoft::ProjectReunion::factory_implementation +{ + struct AppLifecycle : AppLifecycleT + { + }; +} diff --git a/dev/AppLifecycle/AppLifecycle.idl b/dev/AppLifecycle/AppLifecycle.idl new file mode 100644 index 000000000..c4fe3383f --- /dev/null +++ b/dev/AppLifecycle/AppLifecycle.idl @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +namespace Microsoft.ProjectReunion +{ + static runtimeclass AppLifecycle + { + static Windows.ApplicationModel.Activation.IActivatedEventArgs GetActivatedEventArgs(); + } + + static runtimeclass ActivationRegistrationManager + { + static void RegisterForFileTypeActivation(String groupName, String logo, String[] supportedFileTypes, String[] supportedVerbs); + static void RegisterForProtocolActivation(String scheme, String displayName); + static void RegisterForStartupActivation(String taskId, Boolean isEnabled, String displayName); + static void RegisterForToastActivation(String displayName); + + static void UnregisterForFileTypeActivation(String groupName); + static void UnregisterForProtocolActivation(String scheme); + static void UnregisterForStartupActivation(); + static void UnregisterForToastActivation(); + }; +} diff --git a/dev/AppLifecycle/AppLifecycle.vcxitems b/dev/AppLifecycle/AppLifecycle.vcxitems new file mode 100644 index 000000000..956f3789d --- /dev/null +++ b/dev/AppLifecycle/AppLifecycle.vcxitems @@ -0,0 +1,29 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {E3A522A3-6635-4A42-BDED-1AF46A15F63C} + AppLifecycle + + + + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dev/AppLifecycle/LaunchActivatedEventArgs.h b/dev/AppLifecycle/LaunchActivatedEventArgs.h new file mode 100644 index 000000000..b70ca645a --- /dev/null +++ b/dev/AppLifecycle/LaunchActivatedEventArgs.h @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +#pragma once + +#include "ActivatedEventArgsBase.h" + +namespace winrt::Microsoft::ProjectReunion::implementation +{ + using namespace winrt::Windows::ApplicationModel::Activation; + + class LaunchActivatedEventArgs : public winrt::implements + { + public: + LaunchActivatedEventArgs(const std::wstring& args) : + m_args(args) + { + m_kind = ActivationKind::Launch; + } + + // ILaunchActivatedEventArgs + winrt::hstring Arguments() + { + return m_args.c_str(); + } + + winrt::hstring TileId() + { + // This implementation is only used for Win32 which don't support secondary tiles. + return L""; + } + + private: + std::wstring m_args; + }; +} diff --git a/dev/AppLifecycle/ProtocolActivatedEventArgs.h b/dev/AppLifecycle/ProtocolActivatedEventArgs.h new file mode 100644 index 000000000..d53eaa3cc --- /dev/null +++ b/dev/AppLifecycle/ProtocolActivatedEventArgs.h @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +#pragma once + +#include +#include "ActivatedEventArgsBase.h" + +namespace winrt::Microsoft::ProjectReunion::implementation +{ + using namespace winrt::Windows::Foundation::Collections; + using namespace winrt::Windows::ApplicationModel::Activation; + + class ProtocolActivatedEventArgs : public winrt::implements + { + public: + ProtocolActivatedEventArgs(const std::wstring& uri) : m_uri(winrt::Windows::Foundation::Uri(uri)) + { + m_kind = ActivationKind::Protocol; + } + + // IProtocolActivatedEventArgs + winrt::Windows::Foundation::Uri Uri() + { + return m_uri; + } + + private: + winrt::Windows::Foundation::Uri m_uri{nullptr}; + }; +} diff --git a/dev/AppLifecycle/Shared.cpp b/dev/AppLifecycle/Shared.cpp new file mode 100644 index 000000000..ed0cb51f7 --- /dev/null +++ b/dev/AppLifecycle/Shared.cpp @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +#include +#include "Shared.h" + +namespace winrt::Microsoft::ProjectReunion::implementation +{ + std::wstring GetFullIdentityString() + { + std::wstring identityString; + WCHAR idNameBuffer[PACKAGE_FULL_NAME_MAX_LENGTH+1]; + UINT32 idNameBufferLen = ARRAYSIZE(idNameBuffer); + if (::GetCurrentPackageFullName(&idNameBufferLen, idNameBuffer) == ERROR_SUCCESS) + { + identityString = idNameBuffer; + } + + return identityString; + } + + bool HasIdentity() + { + return !(GetFullIdentityString()).empty(); + } + + std::wstring GetModulePath() + { + std::wstring path(100, L'?'); + uint32_t path_size{}; + DWORD actual_size{}; + + do + { + path_size = static_cast(path.size()); + actual_size = ::GetModuleFileName(nullptr, path.data(), path_size); + + if (actual_size + 1 > path_size) + { + path.resize(path_size * 2, L'?'); + } + } while (actual_size + 1 > path_size); + + path.resize(actual_size); + return path; + } + + std::wstring CreateAssocKeyPath(PCWSTR assocName) + { + std::wstring path{ LR"(SOFTWARE\Classes\)" }; + path += assocName; + return path; + } + + void RegisterProtocol(PCWSTR scheme, PCWSTR displayName, _In_opt_ const GUID* delegateExecute) + { + std::wstring key_path{ CreateAssocKeyPath(scheme) }; + wil::unique_hkey key; + + THROW_IF_WIN32_ERROR(::RegCreateKeyEx(HKEY_CURRENT_USER, key_path.c_str(), 0, nullptr, 0, + KEY_WRITE, nullptr, key.put(), nullptr)); + + std::wstring defaultValue{ L"URL:" }; + defaultValue += displayName; + THROW_IF_WIN32_ERROR(::RegSetValueEx(key.get(), nullptr, 0, REG_SZ, + reinterpret_cast(defaultValue.c_str()), + static_cast((defaultValue.size() + 1) * sizeof(wchar_t)))); + + std::wstring urlProtocolValue{ L"" }; + defaultValue += displayName; + THROW_IF_WIN32_ERROR(::RegSetValueEx(key.get(), L"URL Protocol", 0, REG_SZ, + reinterpret_cast(urlProtocolValue.c_str()), + static_cast((urlProtocolValue.size() + 1) * sizeof(wchar_t)))); + + key_path += LR"(\shell\open\command)"; + key.reset(); + THROW_IF_WIN32_ERROR(::RegCreateKeyEx(HKEY_CURRENT_USER, key_path.c_str(), 0, nullptr, 0, + KEY_WRITE, nullptr, key.put(), nullptr)); + + auto command = GetModulePath(); + command += L" ----" + c_protocolArgumentString + L":%1"; + THROW_IF_WIN32_ERROR(::RegSetValueEx(key.get(), nullptr, 0, REG_SZ, + reinterpret_cast(command.c_str()), + static_cast((command.size() + 1) * sizeof(wchar_t)))); + + if (delegateExecute) + { + std::wstring delegateClsid{ LR"({????????-????-????-????-????????????})" }; + ::StringFromGUID2(*delegateExecute, delegateClsid.data(), 39); + + THROW_IF_WIN32_ERROR(::RegSetValueEx(key.get(), L"DelegateExecute", 0, REG_SZ, + reinterpret_cast(delegateClsid.c_str()), + static_cast((delegateClsid.size() + 1) * sizeof(wchar_t)))); + } + } + + void UnregisterProtocol(PCWSTR scheme) + { + std::wstring key_path{ CreateAssocKeyPath(scheme) }; + ::RegDeleteTree(HKEY_CURRENT_USER, key_path.c_str()); + } +} diff --git a/dev/AppLifecycle/Shared.h b/dev/AppLifecycle/Shared.h new file mode 100644 index 000000000..3ab0800bc --- /dev/null +++ b/dev/AppLifecycle/Shared.h @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +#pragma once + +namespace winrt::Microsoft::ProjectReunion::implementation +{ + + static const std::wstring c_protocolArgumentString = L"ms-protocol"; //L"ms-protocol" + + std::wstring GetFullIdentityString(); + bool HasIdentity(); + std::wstring GetModulePath(); + std::wstring CreateAssocKeyPath(PCWSTR assocName); + void RegisterProtocol(PCWSTR scheme, PCWSTR displayName, _In_opt_ const GUID* delegateExecute = nullptr); + void UnregisterProtocol(PCWSTR scheme); +} diff --git a/dev/ProjectReunion_DLL/ProjectReunion.def b/dev/ProjectReunion_DLL/ProjectReunion.def index 12f33c35a..aa57cf658 100644 --- a/dev/ProjectReunion_DLL/ProjectReunion.def +++ b/dev/ProjectReunion_DLL/ProjectReunion.def @@ -1,7 +1,3 @@ EXPORTS DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE - - SampleFlatApiCreate - CloseSampleFlatApi - GetSampleFlatApiString diff --git a/dev/ProjectReunion_DLL/ProjectReunion_DLL.vcxproj b/dev/ProjectReunion_DLL/ProjectReunion_DLL.vcxproj index c5279f24a..0cd37932e 100644 --- a/dev/ProjectReunion_DLL/ProjectReunion_DLL.vcxproj +++ b/dev/ProjectReunion_DLL/ProjectReunion_DLL.vcxproj @@ -104,8 +104,7 @@ - - + diff --git a/dev/ProjectReunion_DLL/pch.h b/dev/ProjectReunion_DLL/pch.h index 9b50d2c27..c31e10ef3 100644 --- a/dev/ProjectReunion_DLL/pch.h +++ b/dev/ProjectReunion_DLL/pch.h @@ -1,7 +1,10 @@ #pragma once #include +#include #include #include +#include +#include #include #include #include @@ -9,4 +12,6 @@ #include #include #include - +#include +#include +#include diff --git a/dev/SampleFlatC/README.md b/dev/SampleFlatC/README.md deleted file mode 100644 index 12c3c3556..000000000 --- a/dev/SampleFlatC/README.md +++ /dev/null @@ -1,59 +0,0 @@ -# Adding a new Flat C API Component - -This directory is a sample of adding an API with a "flat C" style to Project Reunion. -Flat C APIs define an ABI using C-based headers exported from a DLL. Apps can use the -APIs from an import library or through a projection that applies a wrapper. - -## Adding the shared project - -1. In Visual Studio, right-click the `dev` node in the Solution and choose "New Solution Folder" -2. Pick a name for your new project (the rest of this example uses `Muffins`) -3. Right-click the `Muffins` solution folder and use "Add > New Project" -4. Use the "Shared Items Project", set the name (`Muffins`) -4. For path use the solution root plus `\\dev` - the final path will be in `\\dev\\Muffins` - -## Reference the project - -1. Right-click the **ProjectReunion** project, use "Add > Reference" -2. Choose `Muffins` from the list of "Shared" items - -## Add public header - -1. Right-click the shared project and use "Add > New Item" -2. From the "Installed > Visual C++ > Code" list, select "Header (.h)" -3. Pick a good name (for the rest of this example, we'll use `Muffins` again, so "muffins.h") -5. Define the ABI for the implementation - -Follow the example of [SampleFlatC](./SampleFlatC.h): - -* Use `STDAPI` and `STDAPI_(type)` to define entrypoints -* Use scoped enumerations (like `enum class`) instead of preprocessor definitions - -## Add implementation - -1. Add `.cpp` files that implement the APIs in the usual way -2. For code using C++-with-exceptions use an appropriate exception guard - -## Publish header - -1. In the `.vcxitems` for the new project, manually add something like this, per [SampleFlatC.vcxitems](./SampleFlatC.vcxitems) - -```xml - - - - -``` - -## Adding exports - -1. In [ProjectReunion.def](../dll/ProjectReunion.def) add the list of exported methods - -## Other notes - -Be sure to add the copyright and license marker to all source files: - -```c++ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See LICENSE in the project root for license information. -``` \ No newline at end of file diff --git a/dev/SampleFlatC/SampleFlatC.cpp b/dev/SampleFlatC/SampleFlatC.cpp deleted file mode 100644 index 34408aeaf..000000000 --- a/dev/SampleFlatC/SampleFlatC.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See LICENSE in the project root for license information. - -#include "pch.h" -#include "SampleFlatC.h" -#include - -struct MyRealType -{ - std::wstring theString; -}; - -STDAPI SampleFlatApiCreate( - _In_ LPCWSTR theString, - _Outptr_ HSAMPLEFLATAPI* sampleFlat) try -{ - RETURN_HR_IF(E_INVALIDARG, !theString); - auto real = std::make_unique(); - real->theString = theString; - *sampleFlat = reinterpret_cast(real.release()); - return S_OK; -} -CATCH_RETURN(); - -STDAPI_(VOID) CloseSampleFlatApi(HSAMPLEFLATAPI sampleFlat) try -{ - auto real = std::unique_ptr(reinterpret_cast(sampleFlat)); - // Do something with 'real', the destructor will clean it up -} -CATCH_LOG(); - -STDAPI GetSampleFlatApiString( - _In_ HSAMPLEFLATAPI sampleFlat, - _Outptr_ LPWSTR* theString) try -{ - auto real = reinterpret_cast(sampleFlat); - auto cloned = wil::make_cotaskmem_string(real->theString.data()); - *theString = cloned.release(); - return S_OK; -} -CATCH_RETURN(); diff --git a/dev/SampleFlatC/SampleFlatC.h b/dev/SampleFlatC/SampleFlatC.h deleted file mode 100644 index c57ebcf7d..000000000 --- a/dev/SampleFlatC/SampleFlatC.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See LICENSE in the project root for license information. - -#pragma once -#include - -DECLARE_HANDLE(HSAMPLEFLATAPI); - -STDAPI SampleFlatApiCreate( - _In_ LPCWSTR theString, - _Outptr_ HSAMPLEFLATAPI* sampleFlat); - -STDAPI_(VOID) CloseSampleFlatApi( - HSAMPLEFLATAPI sampleFlat); - -STDAPI GetSampleFlatApiString( - _In_ HSAMPLEFLATAPI sampleFlat, - _Outptr_ LPWSTR* theString); - -// Include from the NuGet package Microsoft.Windows.ImplementationLibrary -// before this file to have this handy lifecycle helper for C++ light up - -#ifdef __WIL_RESOURCE - -namespace wil -{ - using unique_sampleflat_handle = unique_any; -} - -#endif diff --git a/dev/SampleWinRT/README.md b/dev/SampleWinRT/README.md deleted file mode 100644 index 0d2573f56..000000000 --- a/dev/SampleWinRT/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Adding a new WinRT Component - -This directory is a sample of adding a WinRT component to Project Reunion. -WinRT-based APIs are defined using [MIDL3](https://docs.microsoft.com/en-us/uwp/midl-3/) -and typically [implemented with C++/WinRT](https://github.com/Microsoft/cppwinrt). It's -straightforward to add a new component in this manner. - -## Adding the shared project - -1. In Visual Studio, right-click the `dev` node in the Solution and choose "New Solution Folder" -2. Pick a name for your new project (the rest of this example uses `Muffins`) -3. Right-click the `Muffins` solution folder and use "Add > New Project" -4. Use the "Shared Items Project", set the name (`Muffins`) -4. For path use the solution root plus `\\dev` - the final path will be in `\\dev\\Muffins` - -## Reference the project - -1. Right-click the **ProjectReunion** project, use "Add > Reference" -2. Choose `Muffins` from the list of "Shared" items - -## Add IDL and implementation - -1. Right-click the shared project and use "Add > New Item" -2. From the Installed > Visual C++ > Code list, select "Midl File (.idl)" -3. Pick a good name (for the rest of this example, we'll use `Muffins` again, so "muffins.idl") -4. Remove the default `import ...` statements that visual studio generates - -Follow the example of [SampleWinRT](./SampleWinRT.idl): - -* Use `Microsoft.Muffins` as the namespace -* Add types and classes as necessary - -Add a header and `.cpp` file and an implementation. - -Be sure to add the copyright and license marker to all source files: - -```c++ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See LICENSE in the project root for license information. -``` - -Add any C++/WinRT projected headers used by the implementation to -the [pch.h](../ProjectReunion_DLL/pch.h) to reduce compilation times. - -## Testing - -1. Add a new file to the [CppShared](../../test/CppShared/CppShared.vcxitems) -2. Follow the existing pattern of adding a `TEST_CLASS` with `TEST_METHOD` for facets of your implementation -3. Build the project and use the Visual Studio Test Explorer to run all tests - -For very large surfaces with lots of tests, add a new directory under `test` -with its own shared items project. diff --git a/dev/SampleWinRT/SampleWinRT.cpp b/dev/SampleWinRT/SampleWinRT.cpp deleted file mode 100644 index 8c9e9f6d1..000000000 --- a/dev/SampleWinRT/SampleWinRT.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See LICENSE in the project root for license information. - -#include -#include -#include diff --git a/dev/SampleWinRT/SampleWinRT.h b/dev/SampleWinRT/SampleWinRT.h deleted file mode 100644 index 59498bbf5..000000000 --- a/dev/SampleWinRT/SampleWinRT.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See LICENSE in the project root for license information. - -#pragma once - -#include - -namespace winrt::Microsoft::ProjectReunion::implementation -{ - struct Common - { - Common() = default; - - static void Initialize() - { - } - - static hstring AppIdentity() - { - static winrt::hstring fullName = GetFullIdentityString(); - return fullName; - } - - static bool IsAppContainer() - { - static bool isAppContainer = wil::get_token_is_app_container(); - return isAppContainer; - } - - static bool HasIdentity() - { - return !AppIdentity().empty(); - } - - static winrt::hstring GetFullIdentityString() - { - winrt::hstring identityString; - WCHAR idNameBuffer[PACKAGE_FULL_NAME_MAX_LENGTH]; - UINT32 idNameBufferLen = ARRAYSIZE(idNameBuffer); - if (::GetCurrentPackageFullName(&idNameBufferLen, idNameBuffer) == ERROR_SUCCESS) - { - identityString = idNameBuffer; - } - - return identityString; - } - }; -} -namespace winrt::Microsoft::ProjectReunion::factory_implementation -{ - struct Common : CommonT - { - }; -} diff --git a/dev/SampleWinRT/SampleWinRT.idl b/dev/SampleWinRT/SampleWinRT.idl deleted file mode 100644 index dfd83fd96..000000000 --- a/dev/SampleWinRT/SampleWinRT.idl +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See LICENSE in the project root for license information. - -namespace Microsoft.ProjectReunion -{ - static runtimeclass Common - { - static void Initialize(); - - static String AppIdentity { get; }; - - static Boolean IsAppContainer{ get; }; - static Boolean HasIdentity{ get; }; - }; -} diff --git a/dev/SampleWinRT/SampleWinRT.vcxitems b/dev/SampleWinRT/SampleWinRT.vcxitems deleted file mode 100644 index c1a254ef2..000000000 --- a/dev/SampleWinRT/SampleWinRT.vcxitems +++ /dev/null @@ -1,29 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - {0de4fefe-5471-4b50-b74b-d817a02b7f0d} - SampleWinRT - - - - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/AppLifecycle/ApiTests.cpp b/test/AppLifecycle/ApiTests.cpp new file mode 100644 index 000000000..53c0f27db --- /dev/null +++ b/test/AppLifecycle/ApiTests.cpp @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#include "pch.h" + +using namespace winrt::Windows::ApplicationModel; +using namespace winrt::Windows::ApplicationModel::Activation; +using namespace winrt::Microsoft::ProjectReunion; +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +namespace ProjectReunionCppTest +{ + TEST_CLASS(AppLifecycleApiTests) + { +#if PRTEST_MODE_UWP + // UWP currently is not supported by these tests. + TEST_METHOD(GetActivatedEventArgsIsNull) + { + Assert::IsTrue(winrt::Microsoft::ProjectReunion::AppLifecycle::GetActivatedEventArgs() == nullptr); + } +#else + TEST_METHOD(GetActivatedEventArgsIsNotNull) + { + Assert::IsTrue(winrt::Microsoft::ProjectReunion::AppLifecycle::GetActivatedEventArgs() != nullptr); + } + + TEST_METHOD(GetActivatedEventArgsForLaunch) + { + auto args = winrt::Microsoft::ProjectReunion::AppLifecycle::GetActivatedEventArgs(); + Assert::IsTrue(args != nullptr); + Assert::IsTrue(args.Kind() == ActivationKind::Launch); + + auto launchArgs = args.as(); + Assert::IsTrue(launchArgs != nullptr); + } +#endif + }; +} diff --git a/dev/SampleFlatC/SampleFlatC.vcxitems b/test/AppLifecycle/AppLifecycle.vcxitems similarity index 59% rename from dev/SampleFlatC/SampleFlatC.vcxitems rename to test/AppLifecycle/AppLifecycle.vcxitems index 3a78bbcd6..c024f29dd 100644 --- a/dev/SampleFlatC/SampleFlatC.vcxitems +++ b/test/AppLifecycle/AppLifecycle.vcxitems @@ -3,7 +3,7 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) true - {cdce22ec-f7bf-43d4-95d8-2e786229a4e5} + {80E07022-9E99-44FE-B875-901FB6C82F52} @@ -14,16 +14,6 @@ - - - - - - - - - - - + \ No newline at end of file diff --git a/test/CppShared/TestMany.cpp b/test/CppShared/TestMany.cpp index 95eecf18e..660f7ae20 100644 --- a/test/CppShared/TestMany.cpp +++ b/test/CppShared/TestMany.cpp @@ -7,49 +7,4 @@ using namespace Microsoft::VisualStudio::CppUnitTestFramework; namespace ProjectReunionCppTest { - TEST_CLASS(FlatApiTests) - { - public: - - TEST_METHOD(Creates) - { - wil::unique_sampleflat_handle temp; - Assert::IsTrue(SUCCEEDED(::SampleFlatApiCreate(L"kittens", &temp))); - Assert::IsTrue(SUCCEEDED(::SampleFlatApiCreate(L"puppies", &temp))); - Assert::IsTrue(FAILED(::SampleFlatApiCreate(nullptr, &temp))); - } - - TEST_METHOD(CloseNullOk) - { - CloseSampleFlatApi(nullptr); - } - - TEST_METHOD(StringRoundTrip) - { - const wchar_t* tasty = L"muffins"; - wil::unique_sampleflat_handle temp; - THROW_IF_FAILED(::SampleFlatApiCreate(tasty, &temp)); - wil::unique_cotaskmem_string stored; - Assert::IsTrue(SUCCEEDED(::GetSampleFlatApiString(temp.get(), &stored))); - Assert::IsNotNull(stored.get()); - Assert::AreEqual(tasty, stored.get()); - } - }; - - TEST_CLASS(WinRtApiTests) - { -#if PRTEST_MODE_UWP - TEST_METHOD(ContainerTests) - { - Assert::IsTrue(winrt::Microsoft::ProjectReunion::Common::IsAppContainer()); - Assert::IsTrue(winrt::Microsoft::ProjectReunion::Common::HasIdentity()); - } -#else - TEST_METHOD(ContainerTests) - { - Assert::IsFalse(winrt::Microsoft::ProjectReunion::Common::IsAppContainer()); - Assert::IsFalse(winrt::Microsoft::ProjectReunion::Common::HasIdentity()); - } -#endif - }; } diff --git a/test/CppTest/CppTest.vcxproj b/test/CppTest/CppTest.vcxproj index bea22d152..232905afb 100644 --- a/test/CppTest/CppTest.vcxproj +++ b/test/CppTest/CppTest.vcxproj @@ -111,6 +111,9 @@ + + + diff --git a/test/CppTest/pch.h b/test/CppTest/pch.h index 7e0c18c51..29e5aaf01 100644 --- a/test/CppTest/pch.h +++ b/test/CppTest/pch.h @@ -10,6 +10,7 @@ #include #include "CppUnitTest.h" +#include + // Test-specific headers, lifted here -#include #include diff --git a/test/CppTest_UWP/CppTest_UWP.vcxproj b/test/CppTest_UWP/CppTest_UWP.vcxproj index 40f501ffb..edf8424bd 100644 --- a/test/CppTest_UWP/CppTest_UWP.vcxproj +++ b/test/CppTest_UWP/CppTest_UWP.vcxproj @@ -75,6 +75,9 @@ + + + diff --git a/test/CppTest_UWP/pch.h b/test/CppTest_UWP/pch.h index 1d1c4d158..d8939e108 100644 --- a/test/CppTest_UWP/pch.h +++ b/test/CppTest_UWP/pch.h @@ -19,6 +19,7 @@ #include #include +#include + // Test-specific headers, lifted here -#include #include