From b8e405387eca702d93a88eb55842a65de7792cf5 Mon Sep 17 00:00:00 2001 From: Gilles Khouzam Date: Thu, 14 Aug 2014 14:52:53 -0700 Subject: [PATCH] VS: Mark Windows Phone and Store targets as App Containers * Add AppContainerApplication to non-UTILITY targets * Generate app manifest and related files if project does not provide them. Place them in a per-target directory to avoid clashes. * Mark WinRT components with WinMDAssembly * Import Windows Phone 8.0 targets in .vcxproj files when necessary, and reference platform.winmd. Inspired-by: Paul Annetts --- .gitattributes | 2 + Source/cmVisualStudio10TargetGenerator.cxx | 544 ++++++++++++++++++++- Source/cmVisualStudio10TargetGenerator.h | 11 + Templates/Windows/ApplicationIcon.png | Bin 0 -> 3392 bytes Templates/Windows/Logo.png | Bin 0 -> 801 bytes Templates/Windows/SmallLogo.png | Bin 0 -> 329 bytes Templates/Windows/SplashScreen.png | Bin 0 -> 2146 bytes Templates/Windows/StoreLogo.png | Bin 0 -> 429 bytes Templates/Windows/Windows_TemporaryKey.pfx | Bin 0 -> 2560 bytes 9 files changed, 554 insertions(+), 3 deletions(-) create mode 100644 Templates/Windows/ApplicationIcon.png create mode 100644 Templates/Windows/Logo.png create mode 100644 Templates/Windows/SmallLogo.png create mode 100644 Templates/Windows/SplashScreen.png create mode 100644 Templates/Windows/StoreLogo.png create mode 100644 Templates/Windows/Windows_TemporaryKey.pfx diff --git a/.gitattributes b/.gitattributes index d21f1dda0..d3f7280e2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12,6 +12,8 @@ configure crlf=input *.dsp -crlf *.dsptemplate -crlf *.dsw -crlf +*.pfx -crlf +*.png -crlf *.sln -crlf *.vcproj -crlf diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 76068acc8..c87bf71fb 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -160,6 +160,10 @@ cmVisualStudio10TargetGenerator(cmTarget* target, this->Platform = gg->GetPlatformName(); this->MSTools = true; this->BuildFileStream = 0; + this->IsMissingFiles = false; + this->DefaultArtifactDir = + this->Makefile->GetStartOutputDirectory() + std::string("/") + + this->LocalGenerator->GetTargetDirectory(*this->Target); } cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator() @@ -289,6 +293,7 @@ void cmVisualStudio10TargetGenerator::Generate() if(this->MSTools && this->Target->GetType() <= cmTarget::GLOBAL_TARGET) { this->WriteApplicationTypeSettings(); + this->VerifyNecessaryFiles(); } const char* vsProjectTypes = @@ -325,6 +330,11 @@ void cmVisualStudio10TargetGenerator::Generate() } } + if(this->Target->GetPropertyAsBool("VS_WINRT_COMPONENT")) + { + this->WriteString("true\n", 2); + } + const char* vsGlobalKeyword = this->Target->GetProperty("VS_GLOBAL_KEYWORD"); if(!vsGlobalKeyword) @@ -396,6 +406,7 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteString( "\n", 1); + this->WriteTargetSpecificReferences(); this->WriteString("\n", 1); if (this->GlobalGenerator->IsMasmEnabled()) { @@ -475,6 +486,22 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup() } } +void cmVisualStudio10TargetGenerator::WriteTargetSpecificReferences() +{ + if(this->MSTools) + { + if(this->GlobalGenerator->TargetsWindowsPhone() && + this->GlobalGenerator->GetSystemVersion() == "8.0") + { + this->WriteString( + "\n", 1); + } + } +} + void cmVisualStudio10TargetGenerator::WriteWinRTReferences() { std::vector references; @@ -483,6 +510,13 @@ void cmVisualStudio10TargetGenerator::WriteWinRTReferences() { cmSystemTools::ExpandListArgument(vsWinRTReferences, references); } + + if(this->GlobalGenerator->TargetsWindowsPhone() && + this->GlobalGenerator->GetSystemVersion() == "8.0" && + references.empty()) + { + references.push_back("platform.winmd"); + } if(!references.empty()) { this->WriteString("\n", 1); @@ -825,6 +859,49 @@ void cmVisualStudio10TargetGenerator::WriteGroups() this->WriteGroupSources(ti->first.c_str(), ti->second, sourceGroups); } + // Added files are images and the manifest. + if (!this->AddedFiles.empty()) + { + this->WriteString("\n", 1); + for(std::vector::const_iterator + oi = this->AddedFiles.begin(); oi != this->AddedFiles.end(); ++oi) + { + std::string fileName = cmSystemTools::LowerCase( + cmSystemTools::GetFilenameName(*oi)); + if (fileName == "wmappmanifest.xml") + { + this->WriteString("BuildFileStream) << *oi << "\">\n"; + this->WriteString("Resource Files\n", 3); + this->WriteString("\n", 2); + } + else if(cmSystemTools::GetFilenameExtension(fileName) == + ".appxmanifest") + { + this->WriteString("BuildFileStream) << *oi << "\">\n"; + this->WriteString("Resource Files\n", 3); + this->WriteString("\n", 2); + } + else if(cmSystemTools::GetFilenameExtension(fileName) == + ".pfx") + { + this->WriteString("BuildFileStream) << *oi << "\">\n"; + this->WriteString("Resource Files\n", 3); + this->WriteString("\n", 2); + } + else + { + this->WriteString("BuildFileStream) << *oi << "\">\n"; + this->WriteString("Resource Files\n", 3); + this->WriteString("\n", 2); + } + } + this->WriteString("\n", 1); + } + std::vector resxObjs; this->GeneratorTarget->GetResxSources(resxObjs, ""); if(!resxObjs.empty()) @@ -898,7 +975,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups() this->WriteString("\n", 2); } - if(!resxObjs.empty()) + if(!resxObjs.empty() || !this->AddedFiles.empty()) { this->WriteString("\n", 2); std::string guidName = "SG_Filter_Resource Files"; @@ -1281,6 +1358,11 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() (*this->BuildFileStream ) << cmVS10EscapeXML(obj) << "\" />\n"; } + if (this->IsMissingFiles) + { + this->WriteMissingFiles(); + } + this->WriteString("\n", 1); } @@ -2243,7 +2325,40 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile() break; } - if(!pfxFile.empty()) + if(this->IsMissingFiles && + !(this->GlobalGenerator->TargetsWindowsPhone() && + this->GlobalGenerator->GetSystemVersion() == "8.0")) + { + // Move the manifest to a project directory to avoid clashes + std::string artifactDir = + this->LocalGenerator->GetTargetDirectory(*this->Target); + this->ConvertToWindowsSlash(artifactDir); + this->WriteString("\n", 1); + this->WriteString("", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(artifactDir) << + "\\\n"; + this->WriteString("" + "$(TargetDir)resources.pri", 2); + + // If we are missing files and we don't have a certificate and + // aren't targeting WP8.0, add a default certificate + if(pfxFile.empty()) + { + std::string templateFolder = cmSystemTools::GetCMakeRoot() + + "/Templates/Windows"; + pfxFile = this->DefaultArtifactDir + "/Windows_TemporaryKey.pfx"; + cmSystemTools::CopyAFile(templateFolder + "/Windows_TemporaryKey.pfx", + pfxFile, false); + this->ConvertToWindowsSlash(pfxFile); + this->AddedFiles.push_back(pfxFile); + } + + this->WriteString("<", 2); + (*this->BuildFileStream) << "PackageCertificateKeyFile>" + << pfxFile << "\n"; + this->WriteString("\n", 1); + } + else if(!pfxFile.empty()) { this->WriteString("\n", 1); this->WriteString("<", 2); @@ -2267,6 +2382,7 @@ bool cmVisualStudio10TargetGenerator:: void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings() { + bool isAppContainer = false; bool const isWindowsPhone = this->GlobalGenerator->TargetsWindowsPhone(); bool const isWindowsStore = this->GlobalGenerator->TargetsWindowsStore(); std::string const& v = this->GlobalGenerator->GetSystemVersion(); @@ -2284,17 +2400,439 @@ void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings() // Visual Studio 12.0 is necessary for building 8.1 apps this->WriteString("12.0" "\n", 2); + + if (this->Target->GetType() < cmTarget::UTILITY) + { + isAppContainer = true; + } } else if (v == "8.0") { // Visual Studio 11.0 is necessary for building 8.0 apps this->WriteString("11.0" "\n", 2); + + if (isWindowsStore && this->Target->GetType() < cmTarget::UTILITY) + { + isAppContainer = true; + } + else if (isWindowsPhone && + this->Target->GetType() == cmTarget::EXECUTABLE) + { + this->WriteString("true\n", 2); + this->WriteString("", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(this->Name.c_str()) << + "_$(Configuration)_$(Platform).xap\n"; + } } } - if (this->Platform == "ARM") + if(isAppContainer) + { + this->WriteString("true" + "", 2); + } + else if (this->Platform == "ARM") { this->WriteString("true" "", 2); } } + +void cmVisualStudio10TargetGenerator::VerifyNecessaryFiles() +{ + // For Windows and Windows Phone executables, we will assume that if a + // manifest is not present that we need to add all the necessary files + if (this->Target->GetType() == cmTarget::EXECUTABLE) + { + std::vector manifestSources; + this->GeneratorTarget->GetAppManifest(manifestSources, ""); + { + std::string const& v = this->GlobalGenerator->GetSystemVersion(); + if(this->GlobalGenerator->TargetsWindowsPhone()) + { + if (v == "8.0") + { + // Look through the sources for WMAppManifest.xml + std::vector extraSources; + this->GeneratorTarget->GetExtraSources(extraSources, ""); + bool foundManifest = false; + for(std::vector::const_iterator si = + extraSources.begin(); si != extraSources.end(); ++si) + { + // Need to do a lowercase comparison on the filename + if("wmappmanifest.xml" == cmSystemTools::LowerCase( + (*si)->GetLocation().GetName())) + { + foundManifest = true; + break; + } + } + if (!foundManifest) + { + this->IsMissingFiles = true; + } + } + else if (v == "8.1") + { + if(manifestSources.empty()) + { + this->IsMissingFiles = true; + } + } + } + else if (this->GlobalGenerator->TargetsWindowsStore()) + { + if (manifestSources.empty()) + { + if (v == "8.0") + { + this->IsMissingFiles = true; + } + else if (v == "8.1") + { + this->IsMissingFiles = true; + } + } + } + } + } +} + +void cmVisualStudio10TargetGenerator::WriteMissingFiles() +{ + std::string const& v = this->GlobalGenerator->GetSystemVersion(); + if(this->GlobalGenerator->TargetsWindowsPhone()) + { + if (v == "8.0") + { + this->WriteMissingFilesWP80(); + } + else if (v == "8.1") + { + this->WriteMissingFilesWP81(); + } + } + else if (this->GlobalGenerator->TargetsWindowsStore()) + { + if (v == "8.0") + { + this->WriteMissingFilesWS80(); + } + else if (v == "8.1") + { + this->WriteMissingFilesWS81(); + } + } +} + +void cmVisualStudio10TargetGenerator::WriteMissingFilesWP80() +{ + std::string templateFolder = cmSystemTools::GetCMakeRoot() + + "/Templates/Windows"; + + // For WP80, the manifest needs to be in the same folder as the project + // this can cause an overwrite problem if projects aren't organized in + // folders + std::string manifestFile = this->Makefile->GetStartOutputDirectory() + + std::string("/WMAppManifest.xml"); + std::string artifactDir = + this->LocalGenerator->GetTargetDirectory(*this->Target); + this->ConvertToWindowsSlash(artifactDir); + std::string artifactDirXML = cmVS10EscapeXML(artifactDir); + std::string targetNameXML = cmVS10EscapeXML(this->Target->GetName()); + + cmGeneratedFileStream fout(manifestFile.c_str()); + fout.SetCopyIfDifferent(true); + + fout << + "\n" + "\n" + "\t\n" + "\tGUID << "}\"" + " Title=\"CMake Test Program\" RuntimeType=\"Modern Native\"" + " Version=\"1.0.0.0\" Genre=\"apps.normal\" Author=\"CMake\"" + " Description=\"Default CMake App\" Publisher=\"CMake\"" + " PublisherID=\"{" << this->GUID << "}\">\n" + "\t\t" + << artifactDirXML << "\\ApplicationIcon.png\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\t\t" + << artifactDirXML << "\\SmallLogo.png\n" + "\t\t\t\t\t0\n" + "\t\t\t\t\t" + << artifactDirXML << "\\Logo.png\n" + "\t\t\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\n" + "\n"; + + std::string sourceFile = this->ConvertPath(manifestFile, false); + this->ConvertToWindowsSlash(sourceFile); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(sourceFile) << "\">\n"; + this->WriteString("Designer\n", 3); + this->WriteString("\n", 2); + this->AddedFiles.push_back(sourceFile); + + std::string smallLogo = this->DefaultArtifactDir + "/SmallLogo.png"; + cmSystemTools::CopyAFile(templateFolder + "/SmallLogo.png", + smallLogo, false); + this->ConvertToWindowsSlash(smallLogo); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(smallLogo) << "\" />\n"; + this->AddedFiles.push_back(smallLogo); + + std::string logo = this->DefaultArtifactDir + "/Logo.png"; + cmSystemTools::CopyAFile(templateFolder + "/Logo.png", + logo, false); + this->ConvertToWindowsSlash(logo); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(logo) << "\" />\n"; + this->AddedFiles.push_back(logo); + + std::string applicationIcon = + this->DefaultArtifactDir + "/ApplicationIcon.png"; + cmSystemTools::CopyAFile(templateFolder + "/ApplicationIcon.png", + applicationIcon, false); + this->ConvertToWindowsSlash(applicationIcon); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(applicationIcon) << "\" />\n"; + this->AddedFiles.push_back(applicationIcon); +} + +void cmVisualStudio10TargetGenerator::WriteMissingFilesWP81() +{ + std::string manifestFile = + this->DefaultArtifactDir + "/package.appxManifest"; + std::string artifactDir = + this->LocalGenerator->GetTargetDirectory(*this->Target); + this->ConvertToWindowsSlash(artifactDir); + std::string artifactDirXML = cmVS10EscapeXML(artifactDir); + std::string targetNameXML = cmVS10EscapeXML(this->Target->GetName()); + + cmGeneratedFileStream fout(manifestFile.c_str()); + fout.SetCopyIfDifferent(true); + + fout << + "\n" + "\n" + "\tGUID << "\" Publisher=\"CN=CMake\"" + " Version=\"1.0.0.0\" />\n" + "\tGUID << "\"" + " PhonePublisherId=\"00000000-0000-0000-0000-000000000000\"/>\n" + "\t\n" + "\t\t" << targetNameXML << "\n" + "\t\tCMake\n" + "\t\t" << artifactDirXML << "\\StoreLogo.png\n" + "\t\n" + "\t\n" + "\t\t6.3.1\n" + "\t\t6.3.1\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\t\t\n" + "\t\t\t\t\t\t\n" + "\t\t\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\n" + "\n"; + + this->WriteCommonMissingFiles(manifestFile); +} + +void cmVisualStudio10TargetGenerator::WriteMissingFilesWS80() +{ + std::string manifestFile = + this->DefaultArtifactDir + "/package.appxManifest"; + std::string artifactDir = + this->LocalGenerator->GetTargetDirectory(*this->Target); + this->ConvertToWindowsSlash(artifactDir); + std::string artifactDirXML = cmVS10EscapeXML(artifactDir); + std::string targetNameXML = cmVS10EscapeXML(this->Target->GetName()); + + cmGeneratedFileStream fout(manifestFile.c_str()); + fout.SetCopyIfDifferent(true); + + fout << + "\n" + "\n" + "\tGUID << "\" Publisher=\"CN=CMake\"" + " Version=\"1.0.0.0\" />\n" + "\t\n" + "\t\t" << targetNameXML << "\n" + "\t\tCMake\n" + "\t\t" << artifactDirXML << "\\StoreLogo.png\n" + "\t\n" + "\t\n" + "\t\t6.2.1\n" + "\t\t6.2.1\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\n" + "\n"; + + this->WriteCommonMissingFiles(manifestFile); +} + +void cmVisualStudio10TargetGenerator::WriteMissingFilesWS81() +{ + std::string manifestFile = + this->DefaultArtifactDir + "/package.appxManifest"; + std::string artifactDir = + this->LocalGenerator->GetTargetDirectory(*this->Target); + this->ConvertToWindowsSlash(artifactDir); + std::string artifactDirXML = cmVS10EscapeXML(artifactDir); + std::string targetNameXML = cmVS10EscapeXML(this->Target->GetName()); + + cmGeneratedFileStream fout(manifestFile.c_str()); + fout.SetCopyIfDifferent(true); + + fout << + "\n" + "\n" + "\tGUID << "\" Publisher=\"CN=CMake\"" + " Version=\"1.0.0.0\" />\n" + "\t\n" + "\t\t" << targetNameXML << "\n" + "\t\tCMake\n" + "\t\t" << artifactDirXML << "\\StoreLogo.png\n" + "\t\n" + "\t\n" + "\t\t6.3\n" + "\t\t6.3\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\n" + "\t\n" + "\t\t\n" + "\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\t\t\n" + "\t\t\t\t\t\t\n" + "\t\t\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\t\n" + "\t\t\t\n" + "\t\t\n" + "\t\n" + "\n"; + + this->WriteCommonMissingFiles(manifestFile); +} + +void +cmVisualStudio10TargetGenerator +::WriteCommonMissingFiles(const std::string& manifestFile) +{ + std::string templateFolder = cmSystemTools::GetCMakeRoot() + + "/Templates/Windows"; + + std::string sourceFile = this->ConvertPath(manifestFile, false); + this->ConvertToWindowsSlash(sourceFile); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(sourceFile) << "\">\n"; + this->WriteString("Designer\n", 3); + this->WriteString("\n", 2); + this->AddedFiles.push_back(sourceFile); + + std::string smallLogo = this->DefaultArtifactDir + "/SmallLogo.png"; + cmSystemTools::CopyAFile(templateFolder + "/SmallLogo.png", + smallLogo, false); + this->ConvertToWindowsSlash(smallLogo); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(smallLogo) << "\" />\n"; + this->AddedFiles.push_back(smallLogo); + + std::string logo = this->DefaultArtifactDir + "/Logo.png"; + cmSystemTools::CopyAFile(templateFolder + "/Logo.png", + logo, false); + this->ConvertToWindowsSlash(logo); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(logo) << "\" />\n"; + this->AddedFiles.push_back(logo); + + std::string storeLogo = this->DefaultArtifactDir + "/StoreLogo.png"; + cmSystemTools::CopyAFile(templateFolder + "/StoreLogo.png", + storeLogo, false); + this->ConvertToWindowsSlash(storeLogo); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(storeLogo) << "\" />\n"; + this->AddedFiles.push_back(storeLogo); + + std::string splashScreen = this->DefaultArtifactDir + "/SplashScreen.png"; + cmSystemTools::CopyAFile(templateFolder + "/SplashScreen.png", + splashScreen, false); + this->ConvertToWindowsSlash(splashScreen); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(splashScreen) << "\" />\n"; + this->AddedFiles.push_back(splashScreen); + + // This file has already been added to the build so don't copy it + std::string keyFile = this->DefaultArtifactDir + "/Windows_TemporaryKey.pfx"; + this->ConvertToWindowsSlash(keyFile); + this->WriteString("BuildFileStream) << cmVS10EscapeXML(keyFile) << "\" />\n"; +} diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 827287b79..9d94365af 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -70,6 +70,14 @@ private: void WriteWinRTPackageCertificateKeyFile(); void WritePathAndIncrementalLinkOptions(); void WriteItemDefinitionGroups(); + void VerifyNecessaryFiles(); + void WriteMissingFiles(); + void WriteMissingFilesWP80(); + void WriteMissingFilesWP81(); + void WriteMissingFilesWS80(); + void WriteMissingFilesWS81(); + void WriteCommonMissingFiles(const std::string& manifestFile); + void WriteTargetSpecificReferences(); bool ComputeClOptions(); bool ComputeClOptions(std::string const& configName); @@ -130,6 +138,9 @@ private: cmGeneratedFileStream* BuildFileStream; cmLocalVisualStudio7Generator* LocalGenerator; std::set SourcesVisited; + bool IsMissingFiles; + std::vector AddedFiles; + std::string DefaultArtifactDir; typedef std::map ToolSourceMap; ToolSourceMap Tools; diff --git a/Templates/Windows/ApplicationIcon.png b/Templates/Windows/ApplicationIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..7d95d4e0810f4a4c85b5bb631ddd4d3a6be24ca7 GIT binary patch literal 3392 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 RA3>Rb!PC{xWt~$(69A&hN*MqE literal 0 HcmV?d00001 diff --git a/Templates/Windows/SmallLogo.png b/Templates/Windows/SmallLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..1eb0d9d528c42f132872e8af4dc563081b0b9aff GIT binary patch literal 329 zcmV-P0k-~$P)q$gGRCwC#*X;?zAP@%N+|i#I!$mrh zlQ>KU$Rdu>|JH&931_?y6Djl{gb>4nCV5pzDJ?S!mq|4ZejKj%i@j$H{#ML~2Y{DF z$=}bKPaz+UGt{v(4CTQQXym}&iW8{s!ew~XIE7NLjQpy#I2S$rous$~?f%DHT#B*+ zq=#!zc5=0FEqWFpB%UE(L807on!pidHPLgYO}XEgorrg;PB=8ipgQ5u5`&g_MQaRd zaU7Ao8XQMuuN21-s0PPTs1%38x_Yl3Fs-|Y4!C-;M-8g@n*v@1|s#GQ665=9@Rxy?u0YW0&WN+~=RXpPbVXXL4m7Aq=E6I0%{06TwRn=U9d8>exk> zD-Z%M3DNQ`bTLSEF=%NFyoHcAkD*CiXqljo*0E?o$GiDC4q}}|%*0WghLlK#npw?hecrM}Mw?`E(z5C8< z8&*b^!{>5?4aT89vdrgBgSc-x6JZD3F^l#*G(@OO*^1D%Eu7?HAy<3kTLqW9N{^#6vso zVQwY48q7)m{~xQ64RV7{E7Y=&T~?^05Ky`5oNQ8bLgFCPq9co^R09BVRS1OAmH;hU zC#q(N!gNqm!zU#%sv{r5mm-Uv8b-~a1F-;p^>)pnXfKge4s9?;;MFIr*fixPG}NBA z6_G5BEmeO6XXh(emkciB{7tA;iwC2^s^VzyU_h0@ae84ACMY`cIDEju=<`q|2QAEv zW_)W|i|9aknqdmS=#w73eW_csQ$8IhT^vY1^1;X3&J0{%*tcQq!gJpr3w?TJc~@5= zKV5sM{$3k>b#S$@CTkhIF*{v*u(F&$&Yq1naHxt8Mz2N%7aQ3(^VNRZahk1||7?Bl z*idzO_u)FhRj4cPzDO>YA>>lxAGaciEiX8Xzp1SVPv91};$OG3cC&8!v3{Jq^kH@8 UTIccK;hzT5*3#}uZuEx!0OwrBv;Y7A literal 0 HcmV?d00001 diff --git a/Templates/Windows/StoreLogo.png b/Templates/Windows/StoreLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..dcb672712c6823a0c91548ded70a8acb85536b4d GIT binary patch literal 429 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 literal 0 HcmV?d00001