runner: initial automatic update (#2141)

This commit is contained in:
Andrey Nekrasov
2020-04-21 10:30:12 +03:00
committed by GitHub
parent e9ecdb3f56
commit 0354026292
37 changed files with 735 additions and 326 deletions

View File

@@ -0,0 +1 @@
#include "pch.h"

17
src/common/updating/pch.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
#ifndef PCH_H
#define PCH_H
#pragma warning(disable : 5205)
#include <winrt/base.h>
#pragma warning(default : 5205)
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <MsiQuery.h>
#include <Shlwapi.h>
#include <Shobjidl.h>
#include <Knownfolders.h>
#include <ShlObj_core.h>
#endif //PCH_H

View File

@@ -0,0 +1,244 @@
#include "pch.h"
#include "version.h"
#include "updating.h"
#include <msi.h>
#include <common/common.h>
#include <common/json.h>
#include <common/version.h>
#include <common/settings_helpers.h>
#include <common/winstore.h>
#include <common/notifications.h>
#include <winrt/Windows.Web.Http.h>
#include <winrt/Windows.Web.Http.Headers.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Management.Deployment.h>
#include <winrt/Windows.Networking.Connectivity.h>
#include "VersionHelper.h"
namespace
{
const wchar_t POWER_TOYS_UPGRADE_CODE[] = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}";
const wchar_t DONT_SHOW_AGAIN_RECORD_REGISTRY_PATH[] = L"delete_previous_powertoys_confirm";
const wchar_t USER_AGENT[] = L"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)";
const wchar_t LATEST_RELEASE_ENDPOINT[] = L"https://api.github.com/repos/microsoft/PowerToys/releases/latest";
const wchar_t MSIX_PACKAGE_NAME[] = L"Microsoft.PowerToys";
const wchar_t MSIX_PACKAGE_PUBLISHER[] = L"CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US";
}
namespace localized_strings
{
const wchar_t OFFER_UNINSTALL_MSI[] = L"We've detected a previous installation of PowerToys. Would you like to remove it?";
const wchar_t OFFER_UNINSTALL_MSI_TITLE[] = L"PowerToys: uninstall previous version?";
const wchar_t UNINSTALLATION_SUCCESS[] = L"Previous version of PowerToys was uninstalled successfully.";
const wchar_t UNINSTALLATION_UNKNOWN_ERROR[] = L"Error: please uninstall the previous version of PowerToys manually.";
const wchar_t GITHUB_NEW_VERSION_READY_TO_INSTALL[] = L"An update to PowerToys is ready to install.";
const wchar_t GITHUB_NEW_VERSION_UPDATE_NOW[] = L"Update now";
const wchar_t GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART[] = L"At next launch";
const wchar_t GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT[] = L"An update to PowerToys is available. Visit our GitHub page to get ";
const wchar_t GITHUB_NEW_VERSION_AGREE[] = L"Visit";
const wchar_t GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D[] = L"1 day";
const wchar_t GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D[] = L"5 days";
}
namespace updating
{
inline winrt::Windows::Web::Http::HttpClient create_http_client()
{
winrt::Windows::Web::Http::HttpClient client;
auto headers = client.DefaultRequestHeaders();
headers.UserAgent().TryParseAdd(USER_AGENT);
return client;
}
std::wstring get_msi_package_path()
{
std::wstring package_path;
wchar_t GUID_product_string[39];
if (const bool found = ERROR_SUCCESS == MsiEnumRelatedProductsW(POWER_TOYS_UPGRADE_CODE, 0, 0, GUID_product_string); !found)
{
return package_path;
}
if (const bool installed = INSTALLSTATE_DEFAULT == MsiQueryProductStateW(GUID_product_string); !installed)
{
return package_path;
}
DWORD package_path_size = 0;
if (const bool has_package_path = ERROR_SUCCESS == MsiGetProductInfoW(GUID_product_string, INSTALLPROPERTY_LOCALPACKAGE, nullptr, &package_path_size); !has_package_path)
{
return package_path;
}
package_path = std::wstring(++package_path_size, L'\0');
if (const bool got_package_path = ERROR_SUCCESS == MsiGetProductInfoW(GUID_product_string, INSTALLPROPERTY_LOCALPACKAGE, package_path.data(), &package_path_size); !got_package_path)
{
package_path = {};
return package_path;
}
package_path.resize(size(package_path) - 1); // trim additional \0 which we got from MsiGetProductInfoW
return package_path;
}
bool offer_msi_uninstallation()
{
const auto selection = SHMessageBoxCheckW(nullptr, localized_strings::OFFER_UNINSTALL_MSI, localized_strings::OFFER_UNINSTALL_MSI_TITLE, MB_ICONQUESTION | MB_YESNO, IDNO, DONT_SHOW_AGAIN_RECORD_REGISTRY_PATH);
return selection == IDYES;
}
bool uninstall_msi_version(const std::wstring& package_path)
{
const auto uninstall_result = MsiInstallProductW(package_path.c_str(), L"REMOVE=ALL");
if (ERROR_SUCCESS == uninstall_result)
{
notifications::show_toast(localized_strings::UNINSTALLATION_SUCCESS);
return true;
}
else if (auto system_message = get_last_error_message(uninstall_result); system_message.has_value())
{
try
{
notifications::show_toast(*system_message);
}
catch (...)
{
notifications::show_toast(localized_strings::UNINSTALLATION_UNKNOWN_ERROR);
}
}
return false;
}
std::future<std::optional<new_version_download_info>> get_new_github_version_info_async()
{
try
{
auto client = create_http_client();
auto response = co_await client.GetAsync(winrt::Windows::Foundation::Uri{ LATEST_RELEASE_ENDPOINT });
(void)response.EnsureSuccessStatusCode();
const auto body = co_await response.Content().ReadAsStringAsync();
auto json_body = json::JsonValue::Parse(body).GetObjectW();
auto new_version = json_body.GetNamedString(L"tag_name");
winrt::Windows::Foundation::Uri release_page_uri{ json_body.GetNamedString(L"html_url") };
VersionHelper github_version(winrt::to_string(new_version));
VersionHelper current_version(VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
if (github_version > current_version)
{
const std::wstring_view required_asset_extension = winstore::running_as_packaged() ? L".msix" : L".msi";
const std::wstring_view required_architecture = get_architecture_string(get_current_architecture());
constexpr const std::wstring_view required_filename_pattern = updating::installer_filename_pattern;
for (auto asset_elem : json_body.GetNamedArray(L"assets"))
{
auto asset{ asset_elem.GetObjectW() };
std::wstring filename_lower = asset.GetNamedString(L"name", {}).c_str();
std::transform(begin(filename_lower), end(filename_lower), begin(filename_lower), ::towlower);
const bool extension_matched = filename_lower.ends_with(required_asset_extension);
const bool architecture_matched = filename_lower.find(required_architecture) != std::wstring::npos;
const bool filename_matched = filename_lower.find(required_filename_pattern) != std::wstring::npos;
if (extension_matched && architecture_matched && filename_matched)
{
winrt::Windows::Foundation::Uri msi_download_url{ asset.GetNamedString(L"browser_download_url") };
co_return new_version_download_info{ std::move(release_page_uri), new_version.c_str(), std::move(msi_download_url), std::move(filename_lower) };
}
}
}
else
{
co_return std::nullopt;
}
}
catch (...)
{
co_return std::nullopt;
}
}
std::future<bool> uninstall_previous_msix_version_async()
{
winrt::Windows::Management::Deployment::PackageManager package_manager;
try
{
auto packages = package_manager.FindPackagesForUser({}, MSIX_PACKAGE_NAME, MSIX_PACKAGE_PUBLISHER);
VersionHelper current_version(VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
for (auto package : packages)
{
VersionHelper msix_version(package.Id().Version().Major, package.Id().Version().Minor, package.Id().Version().Revision);
if (msix_version < current_version)
{
co_await package_manager.RemovePackageAsync(package.Id().FullName());
co_return true;
}
}
}
catch (...)
{
}
co_return false;
}
bool could_be_costly_connection()
{
using namespace winrt::Windows::Networking::Connectivity;
ConnectionProfile internetConnectionProfile = NetworkInformation::GetInternetConnectionProfile();
return internetConnectionProfile.IsWwanConnectionProfile();
}
std::filesystem::path get_pending_updates_path()
{
auto path_str{ PTSettingsHelper::get_root_save_folder_location() };
path_str += L"\\Updates";
return { std::move(path_str) };
}
std::future<void> try_autoupdate(const bool download_updates_automatically)
{
const auto new_version = co_await get_new_github_version_info_async();
if (!new_version)
{
co_return;
}
using namespace localized_strings;
namespace storage = winrt::Windows::Storage;
if (download_updates_automatically && !could_be_costly_connection())
{
auto client = create_http_client();
auto response = co_await client.GetAsync(new_version->msi_download_url);
(void)response.EnsureSuccessStatusCode();
auto download_dst = get_pending_updates_path();
std::error_code _;
std::filesystem::create_directories(download_dst, _);
download_dst /= new_version->msi_filename;
auto msi_installer_file_stream = co_await storage::Streams::FileRandomAccessStream::OpenAsync(download_dst.c_str(), storage::FileAccessMode::ReadWrite, storage::StorageOpenOptions::AllowReadersAndWriters, storage::Streams::FileOpenDisposition::CreateAlways);
co_await response.Content().WriteToStreamAsync(msi_installer_file_stream);
notifications::toast_params toast_params{ L"PTUpdateReadyTag", false };
std::wstring new_version_ready{ GITHUB_NEW_VERSION_READY_TO_INSTALL };
new_version_ready += L" ";
new_version_ready += new_version->version_string;
notifications::show_toast_with_activations(std::move(new_version_ready), {}, { notifications::link_button{ GITHUB_NEW_VERSION_UPDATE_NOW, L"powertoys://update_now/" }, notifications::link_button{ GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART, L"powertoys://schedule_update/" }, notifications::snooze_button{ { { GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D, 24 * 60 }, { GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D, 120 * 60 } } } }, std::move(toast_params));
}
else
{
notifications::toast_params toast_params{ L"PTUpdateNotifyTag", false };
std::wstring contents = GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT;
contents += new_version->version_string;
contents += L'.';
notifications::show_toast_with_activations(std::move(contents), {}, { notifications::link_button{ GITHUB_NEW_VERSION_AGREE, new_version->release_page_uri.ToString().c_str() } }, std::move(toast_params));
}
}
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include <optional>
#include <string>
#include <future>
#include <filesystem>
#include <winrt/Windows.Foundation.h>
namespace updating
{
std::wstring get_msi_package_path();
bool uninstall_msi_version(const std::wstring& package_path);
bool offer_msi_uninstallation();
std::future<bool> uninstall_previous_msix_version_async();
struct new_version_download_info
{
winrt::Windows::Foundation::Uri release_page_uri;
std::wstring version_string;
winrt::Windows::Foundation::Uri msi_download_url;
std::wstring msi_filename;
};
std::future<std::optional<new_version_download_info>> get_new_github_version_info_async();
std::future<void> try_autoupdate(const bool download_updates_automatically);
std::filesystem::path get_pending_updates_path();
constexpr inline std::wstring_view installer_filename_pattern = L"powertoyssetup";
}

View File

@@ -0,0 +1,195 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{17DA04DF-E393-4397-9CF0-84DABE11032E}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>updating</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>updating</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>../../;$(IncludePath)</IncludePath>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>../../;$(IncludePath)</IncludePath>
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard>
<TreatWarningAsError>true</TreatWarningAsError>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalOptions>/await %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalLibraryDirectories>
</AdditionalLibraryDirectories>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpplatest</LanguageStandard>
<TreatWarningAsError>true</TreatWarningAsError>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalOptions>/await %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Lib>
<AdditionalLibraryDirectories>
</AdditionalLibraryDirectories>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="updating.h" />
<ClInclude Include="pch.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="updating.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\common.vcxproj">
<Project>{74485049-c722-400f-abe5-86ac52d929b3}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="updating.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="updating.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>