From de123901b6bbaf135a8894b66680a6a8528315bf Mon Sep 17 00:00:00 2001 From: seven-mile Date: Sat, 16 Sep 2023 12:30:51 +0800 Subject: [PATCH] dev: full functional isolation host manager --- UFCase.Host.Test/HostManager.cpp | 6 +- UFCase.Host.Test/HostManagerSingleton.cpp | 2 +- UFCase.Host/FeatureModel.cpp | 18 ++- UFCase.Host/FeatureModel.h | 5 +- UFCase.Host/SessionModel.h | 9 ++ UFCase.Host/StoreModel.h | 7 +- UFCase.Host/main.cpp | 8 +- UFCase.WinMD.HostManager/HostManager.idl | 2 +- UFCase/App.xaml.h | 4 + UFCase/ComponentViewModel.cpp | 36 +++--- UFCase/ComponentViewModel.h | 6 +- UFCase/ComponentViewModel.idl | 2 +- UFCase/ComponentsPageViewModel.cpp | 12 +- UFCase/FeatureViewModel.cpp | 27 ++--- UFCase/FeatureViewModel.h | 7 +- UFCase/FeatureViewModel.idl | 3 +- UFCase/FeaturesPageViewModel.cpp | 48 ++++---- UFCase/FeaturesPageViewModel.h | 43 +++---- UFCase/HostManager.cpp | 136 ++++++++++++++++++++++ UFCase/HostManager.h | 12 ++ UFCase/ImageSelectorHelper.cpp | 40 +++++-- UFCase/ImageSelectorViewModel.cpp | 1 - UFCase/ImageSelectorViewModel.h | 12 ++ UFCase/ImageSelectorViewModel.idl | 2 + UFCase/ImageViewModel.cpp | 34 ++---- UFCase/ImageViewModel.h | 21 ++-- UFCase/ImageViewModel.idl | 10 +- UFCase/MainNavigationService.cpp | 10 +- UFCase/PackageViewModel.cpp | 33 +++--- UFCase/PackageViewModel.h | 8 +- UFCase/PackageViewModel.idl | 4 +- UFCase/PackagesPageViewModel.cpp | 14 +-- UFCase/PackagesPageViewModel.h | 9 +- UFCase/SysInfoPage.cpp | 5 +- UFCase/SysInfoStaticViewModel.cpp | 5 +- UFCase/SysInfoStaticViewModel.h | 6 +- UFCase/SysInfoStaticViewModel.idl | 2 +- UFCase/UFCase.vcxproj | 6 +- 38 files changed, 393 insertions(+), 222 deletions(-) diff --git a/UFCase.Host.Test/HostManager.cpp b/UFCase.Host.Test/HostManager.cpp index 25a2628..1954633 100644 --- a/UFCase.Host.Test/HostManager.cpp +++ b/UFCase.Host.Test/HostManager.cpp @@ -22,9 +22,11 @@ namespace winrt::UFCase::Isolation::implementation .c_str()); wprintf(winrt::format(L"\t{} {}\n", img.Architecture(), img.IsWinPE()).c_str()); - for (auto obj : img.SxsStore().GetComponentCollection(L"HyperV-Worker-Control")) { + for (auto obj : img.SxsStore().GetComponentCollection(L"HyperV-Worker-Control")) + { auto comp = obj.as(); - wprintf(winrt::format(L"Component: {}\n\t{}\n", comp.TextForm(), comp.PayloadPath()).c_str()); + wprintf(winrt::format(L"Component: {}\n\t{}\n", comp.TextForm(), comp.PayloadPath()) + .c_str()); } host.Ping(); diff --git a/UFCase.Host.Test/HostManagerSingleton.cpp b/UFCase.Host.Test/HostManagerSingleton.cpp index e66b94c..f9d1215 100644 --- a/UFCase.Host.Test/HostManagerSingleton.cpp +++ b/UFCase.Host.Test/HostManagerSingleton.cpp @@ -9,4 +9,4 @@ namespace winrt::UFCase::Isolation::implementation { CoCreatableCppWinRtClass(HostManagerSingleton); -} // namespace winrt::UFCase::implementation +} // namespace winrt::UFCase::Isolation::implementation diff --git a/UFCase.Host/FeatureModel.cpp b/UFCase.Host/FeatureModel.cpp index 357c43b..aa93c4c 100644 --- a/UFCase.Host/FeatureModel.cpp +++ b/UFCase.Host/FeatureModel.cpp @@ -92,7 +92,7 @@ namespace winrt::UFCase::Isolation::implementation { com_ptr pPkg; check_hresult(GetInterface()->GetPackage(pPkg.put())); - if (auto self_pkg = m_package.get()) + if (auto self_pkg = m_package) { auto pkg = make(self_pkg.Session(), pPkg); return pkg; @@ -113,7 +113,8 @@ namespace winrt::UFCase::Isolation::implementation Windows::Foundation::Collections::IVector FeatureModel:: GetParentFeatureCollection() { - constexpr HRESULT CBS_E_ARRAY_MISSING_INDEX = 0x800F0809, CBS_E_UNKNOWN_UPDATE = 0x800F080C; + constexpr HRESULT CBS_E_ARRAY_MISSING_INDEX = 0x800F0809, CBS_E_UNKNOWN_UPDATE = 0x800F080C, + CBS_E_DUPLICATE_UPDATENAME = 0x800F0819; auto res = single_threaded_vector(); for (uint32_t idx = 0;; idx++) { @@ -130,7 +131,7 @@ namespace winrt::UFCase::Isolation::implementation try { - res.Append(m_package.get().OpenFeature(ws_parent_name.get())); + res.Append(m_package.OpenFeature(ws_parent_name.get())); } catch (hresult_error const &hr) { @@ -139,6 +140,17 @@ namespace winrt::UFCase::Isolation::implementation // unknown update, ignore it continue; } + else if (hr.code() == CBS_E_DUPLICATE_UPDATENAME) + { + // duplicate update name, fallback to enumeration + for (auto upd : m_package.GetFeatureCollection(CbsApplicabilityApplicable, + CbsSelectabilityAllClass)) { + if (upd.Name() == ws_parent_name.get()) { + res.Append(upd); + break; + } + } + } else { // rethrow diff --git a/UFCase.Host/FeatureModel.h b/UFCase.Host/FeatureModel.h index 22aeb4a..93d7eff 100644 --- a/UFCase.Host/FeatureModel.h +++ b/UFCase.Host/FeatureModel.h @@ -8,7 +8,8 @@ namespace winrt::UFCase::Isolation::implementation { struct FeatureModel : FeatureModelT { - FeatureModel(Isolation::PackageModel pkg, com_ptr feature) : m_feature(feature) + FeatureModel(Isolation::PackageModel pkg, com_ptr feature) + : m_feature(feature), m_package(pkg) { } @@ -30,7 +31,7 @@ namespace winrt::UFCase::Isolation::implementation private: com_ptr m_feature; - weak_ref m_package; + Isolation::PackageModel m_package; com_ptr GetInterface() { return m_feature; diff --git a/UFCase.Host/SessionModel.h b/UFCase.Host/SessionModel.h index 171345f..0091f40 100644 --- a/UFCase.Host/SessionModel.h +++ b/UFCase.Host/SessionModel.h @@ -14,6 +14,15 @@ namespace winrt::UFCase::Isolation::implementation Initialize(option); } + ~SessionModel() + { + if (m_session) + { + _CbsRequiredAction ra; + check_hresult(m_session->Finalize(&ra)); + } + } + void AddSource(hstring const &source_dir); Windows::Foundation::IAsyncActionWithProgress SaveChanges(); diff --git a/UFCase.Host/StoreModel.h b/UFCase.Host/StoreModel.h index dba61ee..4a27ed9 100644 --- a/UFCase.Host/StoreModel.h +++ b/UFCase.Host/StoreModel.h @@ -34,10 +34,9 @@ namespace winrt::UFCase::Isolation::implementation public: Isolation::ComponentModel OpenComponent(hstring id); - Windows::Foundation::Collections::IIterable - GetComponentCollection(); - Windows::Foundation::Collections::IIterable - GetComponentCollection(hstring ref_id); + Windows::Foundation::Collections::IIterable GetComponentCollection(); + Windows::Foundation::Collections::IIterable GetComponentCollection( + hstring ref_id); com_ptr m_sxs_store; com_ptr m_csi_store; diff --git a/UFCase.Host/main.cpp b/UFCase.Host/main.cpp index 690995c..3ab1ae1 100644 --- a/UFCase.Host/main.cpp +++ b/UFCase.Host/main.cpp @@ -54,7 +54,13 @@ int WINAPI wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPWSTR, _In_ int) host_mgr.RegisterHost(host); - host_mgr.UnregisterHost(host); + // process messages, for long run + MSG msg{}; + while (GetMessage(&msg, nullptr, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } return 0; } diff --git a/UFCase.WinMD.HostManager/HostManager.idl b/UFCase.WinMD.HostManager/HostManager.idl index 0b605b2..3b141b3 100644 --- a/UFCase.WinMD.HostManager/HostManager.idl +++ b/UFCase.WinMD.HostManager/HostManager.idl @@ -104,7 +104,7 @@ namespace UFCase.Isolation Windows.Foundation.IAsyncActionWithProgress SaveChanges(); PackageModel OpenPackage(String identity); - Windows.Foundation.Collections.IIterable GetPackageCollection( + Windows.Foundation.Collections.IVector GetPackageCollection( UInt32 option ); diff --git a/UFCase/App.xaml.h b/UFCase/App.xaml.h index 1fbc2d3..d72ee36 100644 --- a/UFCase/App.xaml.h +++ b/UFCase/App.xaml.h @@ -2,6 +2,8 @@ #include "App.xaml.g.h" +#include "HostGuard.h" + namespace winrt::UFCase::implementation { struct App : AppT @@ -13,6 +15,8 @@ namespace winrt::UFCase::implementation private: UFCase::MainWindow window{nullptr}; UFCase::SplashWindow splash{nullptr}; + + HostGuard host_guard; }; } // namespace winrt::UFCase::implementation diff --git a/UFCase/ComponentViewModel.cpp b/UFCase/ComponentViewModel.cpp index dd6d16d..d90eb1a 100644 --- a/UFCase/ComponentViewModel.cpp +++ b/UFCase/ComponentViewModel.cpp @@ -8,8 +8,7 @@ namespace winrt::UFCase::implementation { - ComponentViewModel::ComponentViewModel(uint64_t handle) - : m_model(ComponentModel::GetInstance(handle)) + ComponentViewModel::ComponentViewModel(Isolation::ComponentModel model) : m_model(model) { Prefetch(); } @@ -26,9 +25,12 @@ namespace winrt::UFCase::implementation hstring ComponentViewModel::NameRaw() { - if (auto name = m_model.GetAttribute(L"Name"); name.empty()) { + if (auto name = m_model.GetAttribute(L"Name"); name.empty()) + { return L"(unnamed)"; - } else { + } + else + { return name; } } @@ -67,15 +69,15 @@ namespace winrt::UFCase::implementation { switch (m_model.Status()) { - case CSI_COMPONENT_STATUS_PRESTAGED: + case Isolation::CsiComponentStatus::Prestaged: return L"Prestaged"; - case CSI_COMPONENT_STATUS_STAGED: + case Isolation::CsiComponentStatus::Staged: return L"Staged"; - case CSI_COMPONENT_STATUS_PINNED: + case Isolation::CsiComponentStatus::Pinned: return L"Pinned"; - case CSI_COMPONENT_STATUS_INSTALLED_MATCH: + case Isolation::CsiComponentStatus::Installed: return L"Installed"; - case CSI_COMPONENT_STATUS_INSTALLED_MISMATCH: + case Isolation::CsiComponentStatus::InstalledMismatch: return L"InstalledMismatch"; default: return L"Unknown"; @@ -91,20 +93,10 @@ namespace winrt::UFCase::implementation { auto result = multi_threaded_observable_vector(); - auto flag_to_hstring = [](DWORD file_flag) { - switch (file_flag) - { - case STORE_ASSEMBLY_FILE_STATUS_FLAG_PRESENT: - return L"Present"; - default: - return L"Unknown"; - } - }; - - for (auto &f : m_model.Files()) + for (auto f : m_model.GetFileCollection(ISTORE_ENUM_FILES_FLAG_INCLUDE_INSTALLED_FILES)) { - result.Append(ComponentFileViewModel{.Name = f.pszFileName, - .Status = flag_to_hstring(f.dwFileStatusFlags)}); + result.Append(ComponentFileViewModel{.Name = f.Name, + .Status = f.Status}); } return result; diff --git a/UFCase/ComponentViewModel.h b/UFCase/ComponentViewModel.h index f65022c..3edd5fd 100644 --- a/UFCase/ComponentViewModel.h +++ b/UFCase/ComponentViewModel.h @@ -2,7 +2,7 @@ #include "ComponentViewModel.g.h" -#include "ComponentModel.h" +#include #include "CacheUtil.h" #include "PropChgUtil.h" @@ -12,7 +12,7 @@ namespace winrt::UFCase::implementation struct ComponentViewModel : ComponentViewModelT, ImplPropertyChangedT { - ComponentViewModel(uint64_t handle); + ComponentViewModel(Isolation::ComponentModel model); hstring TextFormRaw(); hstring KeyFormRaw(); @@ -47,7 +47,7 @@ namespace winrt::UFCase::implementation // clang-format on private: - ComponentModel m_model; + Isolation::ComponentModel m_model; void Prefetch() { diff --git a/UFCase/ComponentViewModel.idl b/UFCase/ComponentViewModel.idl index 4848a7f..9c3c11b 100644 --- a/UFCase/ComponentViewModel.idl +++ b/UFCase/ComponentViewModel.idl @@ -10,7 +10,7 @@ namespace UFCase [default_interface] runtimeclass ComponentViewModel : Microsoft.UI.Xaml.Data.INotifyPropertyChanged { - ComponentViewModel(UInt64 hModel); + ComponentViewModel(UFCase.Isolation.ComponentModel model); String TextForm{ get; }; String KeyForm{ get; }; diff --git a/UFCase/ComponentsPageViewModel.cpp b/UFCase/ComponentsPageViewModel.cpp index a213ca6..91175f8 100644 --- a/UFCase/ComponentsPageViewModel.cpp +++ b/UFCase/ComponentsPageViewModel.cpp @@ -4,8 +4,7 @@ #include "ComponentsPageViewModel.g.cpp" #endif -#include "StoreModel.h" -#include "ComponentModel.h" +#include #include "AsyncUtil.h" #include "CbsUtil.h" @@ -29,18 +28,19 @@ namespace winrt::UFCase::implementation m_components.Clear(); - auto &store = StoreModel::GetInstance(m_image.Store()); + auto store = m_image.Store(); - auto comps = store.Components(); + auto comps = store.GetComponentCollection(); // if no reference restriction, estimate 10000 components // if there is reference restriction, this should be fast enough // and do not need a progress bar SIZE_T comps_count = 10000; - for (SIZE_T idx = 0; auto *comp : comps) + for (SIZE_T idx = 0; auto comp_ : comps) { - UFCase::ComponentViewModel comp_vm{comp->GetHandle()}; + auto comp = comp_.as(); + UFCase::ComponentViewModel comp_vm{comp}; RunUITask([=] { m_components.Append(comp_vm); }); ++idx; diff --git a/UFCase/FeatureViewModel.cpp b/UFCase/FeatureViewModel.cpp index 2d23bd8..a7be1b2 100644 --- a/UFCase/FeatureViewModel.cpp +++ b/UFCase/FeatureViewModel.cpp @@ -7,8 +7,6 @@ #include "FeatureViewModel.g.cpp" #endif -#include "PackageModel.h" - #include #include "AsyncUtil.h" @@ -20,7 +18,7 @@ namespace winrt::UFCase::implementation { - FeatureViewModel::FeatureViewModel(uint64_t hModel) : m_model(FeatureModel::GetInstance(hModel)) + FeatureViewModel::FeatureViewModel(Isolation::FeatureModel model) : m_model(model) { m_children.VectorChanged([self = get_strong()](auto const &, IVectorChangedEventArgs args) { switch (args.CollectionChange()) @@ -62,9 +60,9 @@ namespace winrt::UFCase::implementation auto state = m_model.RequestedState(); switch (state) { - case CbsInstallStateInstallRequested: - case CbsInstallStateInstalled: - // case CbsInstallStatePermanent: + case Isolation::CbsInstallState::CbsInstallStateInstallRequested: + case Isolation::CbsInstallState::CbsInstallStateInstalled: + // case Isolation::CbsInstallState::CbsInstallStatePermanent: if (std::optional opt = this->IsChecked(); opt.has_value()) { assert(*opt); @@ -72,11 +70,11 @@ namespace winrt::UFCase::implementation } else return FeatureState::PartiallyEnabled; - case CbsInstallStateUninstallRequested: - case CbsInstallStateStaged: - // case CbsInstallStateResolved: + case Isolation::CbsInstallState::CbsInstallStateUninstallRequested: + case Isolation::CbsInstallState::CbsInstallStateStaged: + // case Isolation::CbsInstallState::CbsInstallStateResolved: return FeatureState::Disabled; - case CbsInstallStateAbsent: + case Isolation::CbsInstallState::CbsInstallStateAbsent: return FeatureState::Unavailable; default: return FeatureState::Invalid; @@ -124,14 +122,9 @@ namespace winrt::UFCase::implementation return m_model.SetMembership(); } - UFCase::PackageViewModel FeatureViewModel::Package() - { - return UFCase::PackageViewModel(m_model.RawParentPackage()->GetHandle()); - } - UFCase::PackageViewModel FeatureViewModel::ContentPackage() { - return UFCase::PackageViewModel(m_model.RawFeaturePackage()->GetHandle()); + return UFCase::PackageViewModel(m_model.ContentPackage()); } FeatureViewModel::child_t FeatureViewModel::Children() @@ -154,7 +147,7 @@ namespace winrt::UFCase::implementation } if (cnt < m_children.Size()) return std::optional(std::nullopt); - if (m_model.RequestedState() >= CbsInstallStateInstallRequested) + if (static_cast(m_model.RequestedState()) >= CbsInstallStateInstallRequested) return true; return false; } diff --git a/UFCase/FeatureViewModel.h b/UFCase/FeatureViewModel.h index 18a6c8c..3084981 100644 --- a/UFCase/FeatureViewModel.h +++ b/UFCase/FeatureViewModel.h @@ -3,7 +3,7 @@ #include "CbsApi.h" #include "FeatureViewModel.g.h" -#include "FeatureModel.h" +#include #include "CacheUtil.h" #include "PropChgUtil.h" @@ -13,14 +13,14 @@ namespace winrt::UFCase::implementation struct FeatureViewModel : FeatureViewModelT, ImplPropertyChangedT { - FeatureModel m_model; + Isolation::FeatureModel m_model; using child_t = IObservableVector; child_t m_children = multi_threaded_observable_vector(); hstring m_mark = L""; - FeatureViewModel(uint64_t hModel); + FeatureViewModel(Isolation::FeatureModel model); hstring NameRaw(); hstring DescriptionRaw(); @@ -34,7 +34,6 @@ namespace winrt::UFCase::implementation hstring DownloadSizeRaw(); hstring SetMembershipRaw(); - UFCase::PackageViewModel Package(); UFCase::PackageViewModel ContentPackage(); child_t Children(); diff --git a/UFCase/FeatureViewModel.idl b/UFCase/FeatureViewModel.idl index de7d0d2..bcaa04b 100644 --- a/UFCase/FeatureViewModel.idl +++ b/UFCase/FeatureViewModel.idl @@ -15,7 +15,7 @@ namespace UFCase [default_interface] runtimeclass FeatureViewModel : Microsoft.UI.Xaml.Data.INotifyPropertyChanged { - FeatureViewModel(UInt64 hModel); + FeatureViewModel(UFCase.Isolation.FeatureModel model); String Name{ get; }; String Description{ get; }; @@ -29,7 +29,6 @@ namespace UFCase String DownloadSize{ get; }; String SetMembership{ get; }; - PackageViewModel Package{ get; }; PackageViewModel ContentPackage{ get; }; Windows.Foundation.Collections.IObservableVector Children{ get; }; diff --git a/UFCase/FeaturesPageViewModel.cpp b/UFCase/FeaturesPageViewModel.cpp index 49f9cd6..1526729 100644 --- a/UFCase/FeaturesPageViewModel.cpp +++ b/UFCase/FeaturesPageViewModel.cpp @@ -4,9 +4,7 @@ #include "FeaturesPageViewModel.g.cpp" #endif -#include "ImageModel.h" -#include "SessionModel.h" -#include "FeatureModel.h" +#include "CbsApi.h" #include #include @@ -14,7 +12,9 @@ namespace winrt::UFCase::implementation { - static std::unordered_map> child_ids; + // the children of nullptr is the root features + static std::unordered_map> child_models; + static std::unordered_map id_to_models; IAsyncActionWithProgress FeaturesPageViewModel::PullData() { @@ -22,15 +22,15 @@ namespace winrt::UFCase::implementation // switch thread context co_await resume_background(); - child_ids.clear(); + child_models.clear(); - auto &found = *Session().FoundationPackage(); + auto found = Session().FoundationPackage(); auto report_prog = co_await get_progress_token(); report_prog(10); - auto joinUpdates = - [](const std::vector &updates) -> IAsyncActionWithProgress { + auto joinUpdates = [](const std::vector &updates) + -> IAsyncActionWithProgress { auto report_prog = co_await get_progress_token(); const uint32_t ENUM_UPDATE_PROG = 30; // 30% @@ -49,18 +49,25 @@ namespace winrt::UFCase::implementation report_prog(ENUM_UPDATE_PROG + uint32_t(std::floor(1.0 * idx / all * (100 - ENUM_UPDATE_PROG)))); - auto &&parents = update->GetParentFeatureCollection(); - child_ids[parents.size() ? parents[0]->GetHandle() : 0].push_back( - update->GetHandle()); + id_to_models.emplace(update.Name(), update); + auto parents = update.GetParentFeatureCollection().First(); + child_models[parents.HasCurrent() ? parents.Current().Name() : L""].push_back( + update.Name()); idx++; } co_return; }; - auto op1 = joinUpdates(found.GetPackageFeatureCollection(CbsApplicabilityApplicable, - CbsSelectabilityRootClass)), - op2 = joinUpdates(found.GetPackageFeatureCollection(CbsApplicabilityNeedsParent, - CbsSelectabilityAllClass)); + std::vector it1, it2; + for (auto fm : + found.GetFeatureCollection(CbsApplicabilityApplicable, CbsSelectabilityRootClass)) + it1.push_back(fm); + + for (auto fm : + found.GetFeatureCollection(CbsApplicabilityNeedsParent, CbsSelectabilityAllClass)) + it2.push_back(fm); + + auto op1 = joinUpdates(it1), op2 = joinUpdates(it2); uint32_t prog1 = 0, prog2 = 0; op1.Progress([&](const auto &, const uint32_t &pr) { prog1 = pr; @@ -74,13 +81,14 @@ namespace winrt::UFCase::implementation co_await op1; co_await op2; - std::function, uint64_t)> dfs; - dfs = [&](IObservableVector child, uint64_t cur) { + std::function, Isolation::FeatureModel)> dfs; + dfs = [&](IObservableVector child, Isolation::FeatureModel cur) { child.Clear(); - for (auto child_id : child_ids[cur]) + for (auto child_name : child_models[cur ? cur.Name() : L""]) { - FeatureViewModel vm{child_id}; - dfs(vm.Children(), child_id); + auto child_model = id_to_models.at(child_name); + FeatureViewModel vm{child_model}; + dfs(vm.Children(), child_model); child.Append(vm); } }; diff --git a/UFCase/FeaturesPageViewModel.h b/UFCase/FeaturesPageViewModel.h index 23c1ad3..74170aa 100644 --- a/UFCase/FeaturesPageViewModel.h +++ b/UFCase/FeaturesPageViewModel.h @@ -3,9 +3,6 @@ #include "FeaturesPageViewModel.g.h" #include "ImageViewModel.g.h" -#include "SessionModel.h" -#include "PackageModel.h" - #include "XamlUtil.h" #include "PropChgUtil.h" @@ -78,21 +75,15 @@ namespace winrt::UFCase::implementation HandleCommandAsync(FeatureOpenExplorer, L"Open in explorer", L"\xE8DA") { - auto target = m_selected.Package().InstallLocation(); - if (target == L"" || !std::filesystem::exists(target.c_str())) - { - ContentDialog cd; - cd.XamlRoot(GlobalRes::MainWnd().Content().XamlRoot()); - cd.Title(box_value(L"Cannot open file")); - cd.Content(box_value(L"This package have no valid file path.")); - cd.PrimaryButtonText(L"OK"); - cd.DefaultButton(ContentDialogButton::Primary); - co_await cd.ShowAsync(); - - co_return; - } - ShellExecute(nullptr, L"open", L"explorer", - std::format(L"/select, {}", target.c_str()).c_str(), nullptr, SW_SHOW); + ContentDialog cd; + cd.XamlRoot(GlobalRes::MainWnd().Content().XamlRoot()); + cd.Title(box_value(L"Cannot open file")); + cd.Content(box_value(L"This package have no valid file path.")); + cd.PrimaryButtonText(L"OK"); + cd.DefaultButton(ContentDialogButton::Primary); + co_await cd.ShowAsync(); + + co_return; } HandleCommandAsync(FeatureOpenRegistry, L"Open in registry", L"") @@ -150,12 +141,11 @@ namespace winrt::UFCase::implementation { apartment_context ui_thread; // set change flag to save updates - Session().FoundationPackage()->Install(); + Session().FoundationPackage().Install(); co_await GlobalRes::MainProgServ().InsertTask(Session().SaveChanges(), 200); // dispose the finalized session - m_image.CloseSession(m_session); - m_session = 0; + m_session = nullptr; co_await ui_thread; @@ -179,20 +169,17 @@ namespace winrt::UFCase::implementation ImageViewModel m_image{nullptr}; IObservableVector m_features{nullptr}; FeatureViewModel m_selected{nullptr}; - uint64_t m_session = 0; + Isolation::SessionModel m_session{nullptr}; - uint64_t SessionHandle() + Isolation::SessionModel Session() { if (m_session) + { return m_session; + } return m_session = m_image.OpenSession(); } - SessionModel &Session() - { - return SessionModel::GetInstance(SessionHandle()); - } - void NotifyCommandsCanExecuteChanged() { FeatureEnableCommand().NotifyCanExecuteChanged(); diff --git a/UFCase/HostManager.cpp b/UFCase/HostManager.cpp index 0855ab4..cf96722 100644 --- a/UFCase/HostManager.cpp +++ b/UFCase/HostManager.cpp @@ -8,6 +8,45 @@ namespace winrt::UFCase::Isolation::implementation { + + static BOOL CreateProcessInJob(HANDLE hJob, LPCTSTR lpApplicationName, LPTSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, + DWORD dwCreationFlags, LPVOID lpEnvironment, + LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, + LPPROCESS_INFORMATION ppi) + { + BOOL fRc = + CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, + bInheritHandles, dwCreationFlags | CREATE_SUSPENDED, lpEnvironment, + lpCurrentDirectory, lpStartupInfo, ppi); + if (fRc) + { + fRc = AssignProcessToJobObject(hJob, ppi->hProcess); + if (fRc && !(dwCreationFlags & CREATE_SUSPENDED)) + { + fRc = ResumeThread(ppi->hThread) != (DWORD)-1; + } + if (!fRc) + { + TerminateProcess(ppi->hProcess, 0); + CloseHandle(ppi->hProcess); + CloseHandle(ppi->hThread); + ppi->hProcess = ppi->hThread = nullptr; + } + } + return fRc; + } + + HostManager::HostManager() + { + m_host_job = CreateJobObject(nullptr, nullptr); + JOBOBJECT_EXTENDED_LIMIT_INFORMATION info = {}; + info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + check_bool(SetInformationJobObject(m_host_job, JobObjectExtendedLimitInformation, &info, + sizeof(info))); + } + void HostManager::RegisterHost(Isolation::Host host) { std::unique_lock g{m_mtx}; @@ -15,7 +54,22 @@ namespace winrt::UFCase::Isolation::implementation host.Bootdrive()) .c_str()); host.Ping(); + + if (m_hosts.count(host.Bootdrive().c_str())) + { + OutputDebugString(L"warning: duplication of host registration, double creation?"); + + // dispose the object and the host will exit + host = nullptr; + + return; + } + + m_hosts.emplace(host.Bootdrive().c_str(), host); + + m_host_event.SetEvent(); } + void HostManager::UnregisterHost(Isolation::Host host) { std::unique_lock g{m_mtx}; @@ -23,5 +77,87 @@ namespace winrt::UFCase::Isolation::implementation winrt::to_hstring(host.Id()), host.Bootdrive()) .c_str()); host.Ping(); + + m_hosts.erase(host.Bootdrive().c_str()); + } + + inline static std::filesystem::path GetHostExePath() + { + WCHAR szPath[MAX_PATH]; + ::GetModuleFileName(::GetModuleHandle(NULL), szPath, MAX_PATH); + + winrt::check_win32(GetLastError()); + + std::filesystem::path mainExePath{szPath}; + { + auto hostExeDir = mainExePath.parent_path().parent_path() / L"UFCase.Host"; + auto hostExePath = hostExeDir / L"UFCase.Host.exe"; + if (std::filesystem::exists(hostExePath)) + { + return hostExePath; + } + } + + { + auto hostExeDir = mainExePath.parent_path(); + auto hostExePath = hostExeDir / L"UFCase.Host.exe"; + if (std::filesystem::exists(hostExePath)) + { + return hostExePath; + } + } + + THROW_WIN32(ERROR_FILE_NOT_FOUND); + } + + Isolation::Host HostManager::GetOrStartHost(std::filesystem::path bootdrive) + { + bootdrive = bootdrive.lexically_normal(); + { + std::unique_lock g{m_mtx}; + if (auto it = m_hosts.find(bootdrive); it != m_hosts.end()) + { + return it->second; + } + } + + auto hostExePath = GetHostExePath(); + auto hostExeDir = hostExePath.parent_path(); + + auto client_id = winrt::to_hstring(winrt::GuidHelper::CreateNewGuid()); + + for (int retry_cnt = 10; retry_cnt--;) + { + STARTUPINFO st_info{ + .cb = sizeof(st_info), + }; + PROCESS_INFORMATION proc_info{}; + if (!CreateProcessInJob( + m_host_job, hostExePath.c_str(), + const_cast( + winrt::format(L"{} {}", client_id, bootdrive.c_str()).c_str()), + NULL, NULL, FALSE, NULL, NULL, hostExeDir.c_str(), &st_info, &proc_info)) + { + winrt::check_hresult(HRESULT_FROM_WIN32(GetLastError())); + } + + if (m_host_event.wait(200)) + { + std::unique_lock g{m_mtx}; + if (auto it = m_hosts.find(bootdrive); it != m_hosts.end()) + { + return it->second; + } + } + + if (proc_info.hProcess) + { + check_bool(TerminateProcess(proc_info.hProcess, 0)); + } + OutputDebugString(L"no registration received from host, retrying"); + } + + OutputDebugString(L"failed to start host, aborting"); + THROW_WIN32(ERROR_TIMEOUT); } } // namespace winrt::UFCase::Isolation::implementation diff --git a/UFCase/HostManager.h b/UFCase/HostManager.h index 042a453..daa92f6 100644 --- a/UFCase/HostManager.h +++ b/UFCase/HostManager.h @@ -2,19 +2,31 @@ #include "HostManager.g.h" +#include + #include +#include #include +#include namespace winrt::UFCase::Isolation::implementation { struct HostManager : HostManagerT { + using callback_t = std::function; + + HostManager(); + void RegisterHost(Isolation::Host host); void UnregisterHost(Isolation::Host host); + Isolation::Host GetOrStartHost(std::filesystem::path bootdrive); + private: std::mutex m_mtx; std::unordered_map m_hosts; + wil::unique_event m_host_event{wil::EventOptions::None}; + HANDLE m_host_job; }; } // namespace winrt::UFCase::Isolation::implementation diff --git a/UFCase/ImageSelectorHelper.cpp b/UFCase/ImageSelectorHelper.cpp index be8d875..2009d46 100644 --- a/UFCase/ImageSelectorHelper.cpp +++ b/UFCase/ImageSelectorHelper.cpp @@ -1,7 +1,8 @@ #include "pch.h" #include "ImageSelectorHelper.h" -#include "ImageModel.h" +#include "HostManager.h" + #include "ImageViewModel.h" #include "PathUtil.h" @@ -17,14 +18,22 @@ namespace winrt::UFCase using list_t = IObservableVector; - static std::unordered_set model_set; + static std::unordered_set model_set; - IAsyncAction ImagePullData(ImageViewModel vm) + static IAsyncAction ImagePullData(ImageViewModel vm) { auto inner = get_self(vm); co_await RunUITaskAsync([&]() -> IAsyncAction { co_await inner->PullData(); }); } + static Isolation::Host GetOrStartHost(std::filesystem::path const &bootdrive) + { + Isolation::HostManagerSingleton sg{}; + auto mgr_ref = sg.Current(); + auto mgr = get_self(mgr_ref); + return mgr->GetOrStartHost(bootdrive); + } + IAsyncActionWithProgress SearchOnlineImage(ImageViewModel &vm) { auto report_prog = co_await winrt::get_progress_token(); @@ -32,9 +41,10 @@ namespace winrt::UFCase auto bootdrive = GetOnlineBootdrive(); report_prog(std::format(L"Initializing online image [{}]", bootdrive.c_str()).c_str()); - auto image = ImageModel::Create(bootdrive); + auto online_host = GetOrStartHost(bootdrive); + auto image = online_host.Image(); model_set.insert(image); - vm = ImageViewModel{image->GetHandle()}; + vm = UFCase::ImageViewModel{image}; report_prog(L"Loading information of online image"); co_await ImagePullData(vm); @@ -78,12 +88,19 @@ namespace winrt::UFCase DWORD dwType{}, cbData{}; winrt::check_win32(::RegGetValue(hkeyImgList.get(), nameGuid, L"Mount Path", NULL, &dwType, pathMount, &cbData)); - report_prog(L""); - auto image = ImageModel::Create(pathMount); + std::filesystem::path bootdrive = pathMount; + if (!std::filesystem::exists(bootdrive)) + { + continue; + } + report_prog(L"Initializing mounted image"); + + auto host = GetOrStartHost(bootdrive); + auto image = host.Image(); if (!model_set.count(image)) { model_set.insert(image); - ImageViewModel vm{image->GetHandle()}; + ImageViewModel vm{image}; report_prog( std::format(L"Loading information of mounted image [{}]", pathMount).c_str()); co_await ImagePullData(vm); @@ -101,17 +118,18 @@ namespace winrt::UFCase return std::filesystem::exists(path) && std::filesystem::exists(path / L"Windows"); }; - std::wstring bootdrive = L"A:"; + std::wstring bootdrive = L"A:\\"; for (auto &ch = bootdrive[0]; ch <= L'Z'; ch++) { report_prog(std::format(L"Initializing offline image [{}]", bootdrive).c_str()); if (ensure_bootdrive(bootdrive)) { - auto image = ImageModel::Create(bootdrive); + auto host = GetOrStartHost(bootdrive); + auto image = host.Image(); if (!model_set.count(image)) { model_set.insert(image); - ImageViewModel vm{image->GetHandle()}; + ImageViewModel vm{image}; report_prog( std::format(L"Loading information of offline image [{}]", bootdrive.c_str()) diff --git a/UFCase/ImageSelectorViewModel.cpp b/UFCase/ImageSelectorViewModel.cpp index f122c81..b048c2f 100644 --- a/UFCase/ImageSelectorViewModel.cpp +++ b/UFCase/ImageSelectorViewModel.cpp @@ -39,7 +39,6 @@ namespace winrt::UFCase::implementation return; m_selected_idx = value; - image.Select(); RunUITaskAsync([self_lambda = get_strong()]() -> IAsyncAction { auto self = self_lambda; diff --git a/UFCase/ImageSelectorViewModel.h b/UFCase/ImageSelectorViewModel.h index 2ede949..84f8e76 100644 --- a/UFCase/ImageSelectorViewModel.h +++ b/UFCase/ImageSelectorViewModel.h @@ -24,6 +24,18 @@ namespace winrt::UFCase::implementation int32_t SelectedIndex(); void SelectedIndex(int32_t); + UFCase::ImageViewModel SelectedImageViewModel() + { + if (m_selected_idx < 0) + return nullptr; + return m_images.GetAt(m_selected_idx); + } + + Isolation::ImageModel SelectedImageModel() + { + return SelectedImageViewModel().Model(); + } + IAsyncActionWithProgress PullData(); private: diff --git a/UFCase/ImageSelectorViewModel.idl b/UFCase/ImageSelectorViewModel.idl index 55c8600..30f90ae 100644 --- a/UFCase/ImageSelectorViewModel.idl +++ b/UFCase/ImageSelectorViewModel.idl @@ -10,6 +10,8 @@ namespace UFCase Windows.Foundation.Collections.IObservableVector Images{ get; }; Int32 SelectedIndex; + ImageViewModel SelectedImageViewModel{ get; }; + UFCase.Isolation.ImageModel SelectedImageModel{ get; }; Windows.Foundation.IAsyncActionWithProgress PullData(); } diff --git a/UFCase/ImageViewModel.cpp b/UFCase/ImageViewModel.cpp index cae1795..d784832 100644 --- a/UFCase/ImageViewModel.cpp +++ b/UFCase/ImageViewModel.cpp @@ -22,32 +22,32 @@ namespace winrt::UFCase::implementation Win11, }; - WindowsVersions ConvertVersion(FOUR_PART_VERSION raw_ver) + WindowsVersions ConvertVersion(Isolation::ImageVersion raw_ver) { - if (raw_ver.major < 6) + if (raw_ver.Major < 6) { throw hresult_not_implemented{}; } - if (raw_ver.major == 6) + if (raw_ver.Major == 6) { // includes vista - if (raw_ver.minor <= 1) + if (raw_ver.Minor <= 1) { return WindowsVersions::Win7; } else { - if (raw_ver.minor == 2) + if (raw_ver.Minor == 2) return WindowsVersions::Win8; else return WindowsVersions::WinBlue; } } - else if (raw_ver.major == 10) + else if (raw_ver.Major == 10) { // win11 pre-release is less than 22000 - if (raw_ver.build > 21900) + if (raw_ver.Build > 21900) { return WindowsVersions::Win11; } @@ -60,13 +60,13 @@ namespace winrt::UFCase::implementation return WindowsVersions::Win11; } - ImageViewModel::ImageViewModel(uint64_t hModel) : m_model(ImageModel::GetInstance(hModel)) + ImageViewModel::ImageViewModel(Isolation::ImageModel model) : m_model(model) { } hstring ImageViewModel::Type() { - return m_model.Type() == ImageType::Offline ? L"Offline" : L"Online"; + return m_model.Type() == Isolation::ImageType::Offline ? L"Offline" : L"Online"; } hstring ImageViewModel::Version() @@ -93,21 +93,9 @@ namespace winrt::UFCase::implementation return m_icon; } - void ImageViewModel::Select() + Isolation::SessionModel ImageViewModel::OpenSession() { - ::OutputDebugString( - std::format(L"Select image {} {}", this->Version(), this->Edition()).c_str()); - ImageModel::Current(&m_model); - } - - uint64_t ImageViewModel::OpenSession() - { - return m_model.OpenSession()->GetHandle(); - } - - void ImageViewModel::CloseSession(uint64_t handle) - { - m_model.CloseSession(handle); + return m_model.OpenSession(CbsSessionOptionNone); } IAsyncAction ImageViewModel::PullData() diff --git a/UFCase/ImageViewModel.h b/UFCase/ImageViewModel.h index c112de5..cca75fb 100644 --- a/UFCase/ImageViewModel.h +++ b/UFCase/ImageViewModel.h @@ -2,8 +2,7 @@ #include "ImageViewModel.g.h" -#include "ImageModel.h" -#include "StoreModel.h" +#include #include "PropChgUtil.h" @@ -11,7 +10,7 @@ namespace winrt::UFCase::implementation { struct ImageViewModel : ImageViewModelT, ImplPropertyChangedT { - ImageViewModel(uint64_t hModel); + ImageViewModel(Isolation::ImageModel model); hstring Type(); hstring Version(); @@ -19,25 +18,27 @@ namespace winrt::UFCase::implementation hstring Bootdrive(); Media::ImageSource Icon(); - void Select(); - - uint64_t OpenSession(); - void CloseSession(uint64_t handle); + Isolation::SessionModel OpenSession(); bool Selectable() { return m_state == LoadingState::Loaded; } - uint64_t Store() + Isolation::ImageModel Model() + { + return m_model; + } + + Isolation::StoreModel Store() { - return m_model.SxsStore()->GetHandle(); + return m_model.SxsStore(); } IAsyncAction PullData(); private: - ImageModel &m_model; + Isolation::ImageModel m_model; hstring m_version{L"Loading"}, m_edition; Media::ImageSource m_icon{nullptr}; diff --git a/UFCase/ImageViewModel.idl b/UFCase/ImageViewModel.idl index 0980cf6..fc54028 100644 --- a/UFCase/ImageViewModel.idl +++ b/UFCase/ImageViewModel.idl @@ -5,7 +5,7 @@ namespace UFCase [default_interface] runtimeclass ImageViewModel : Microsoft.UI.Xaml.Data.INotifyPropertyChanged { - ImageViewModel(UInt64 hModel); + ImageViewModel(UFCase.Isolation.ImageModel model); String Type{ get; }; String Version{ get; }; @@ -16,11 +16,9 @@ namespace UFCase Microsoft.UI.Xaml.Media.ImageSource Icon{ get; }; - void Select(); + UFCase.Isolation.SessionModel OpenSession(); - UInt64 OpenSession(); - void CloseSession(UInt64 hModel); - - UInt64 Store{ get; }; + UFCase.Isolation.ImageModel Model{ get; }; + UFCase.Isolation.StoreModel Store{ get; }; } } diff --git a/UFCase/MainNavigationService.cpp b/UFCase/MainNavigationService.cpp index 5a16d0d..1f59ae2 100644 --- a/UFCase/MainNavigationService.cpp +++ b/UFCase/MainNavigationService.cpp @@ -4,7 +4,6 @@ #include "MainNavigationService.g.cpp" #endif -#include "ImageModel.h" #include "AppConfig.h" #include "ErrorDialog.g.h" @@ -73,7 +72,8 @@ namespace winrt::UFCase::implementation } else if (page_name == L"Features") { - FeaturesPageViewModel vm{ImageViewModel{ImageModel::Current()->GetHandle()}}; + auto ivm = GlobalRes::MainWnd().ViewModel(); + FeaturesPageViewModel vm{ivm.SelectedImageViewModel()}; frame.Navigate(xaml_typename(), box_value(vm)); @@ -85,14 +85,16 @@ namespace winrt::UFCase::implementation } else if (page_name == L"Packages") { - PackagesPageViewModel vm{ImageViewModel{ImageModel::Current()->GetHandle()}, + auto ivm = GlobalRes::MainWnd().ViewModel(); + PackagesPageViewModel vm{ivm.SelectedImageViewModel(), navContext.as()}; frame.Navigate(xaml_typename(), box_value(vm)); co_return; } else if (page_name == L"Components") { - ComponentsPageViewModel vm{ImageViewModel{ImageModel::Current()->GetHandle()}}; + auto ivm = GlobalRes::MainWnd().ViewModel(); + ComponentsPageViewModel vm{ivm.SelectedImageViewModel()}; frame.Navigate(xaml_typename(), box_value(vm)); co_return; } diff --git a/UFCase/PackageViewModel.cpp b/UFCase/PackageViewModel.cpp index ff9e4cd..3be3ad4 100644 --- a/UFCase/PackageViewModel.cpp +++ b/UFCase/PackageViewModel.cpp @@ -10,16 +10,11 @@ namespace winrt::UFCase::implementation { - PackageViewModel::PackageViewModel(uint64_t hModel) : m_model(PackageModel::GetInstance(hModel)) + PackageViewModel::PackageViewModel(Isolation::PackageModel model) : m_model(model) { Prefetch(); } - uint64_t PackageViewModel::Handle() - { - return m_model.GetHandle(); - } - hstring PackageViewModel::ReleaseTypeRaw() { return m_model.ReleaseType(); @@ -30,31 +25,31 @@ namespace winrt::UFCase::implementation auto state = m_model.State(); switch (state) { - case CbsInstallStateAbsent: + case Isolation::CbsInstallState::CbsInstallStateAbsent: return L"Absent"; - case CbsInstallStateCancel: + case Isolation::CbsInstallState::CbsInstallStateCancel: return L"Cancel"; - case CbsInstallStatePartiallyInstalled: + case Isolation::CbsInstallState::CbsInstallStatePartiallyInstalled: return L"PartiallyInstalled"; - case CbsInstallStateUninstallRequested: + case Isolation::CbsInstallState::CbsInstallStateUninstallRequested: return L"UninstallRequested"; - case CbsInstallStateInstallRequested: + case Isolation::CbsInstallState::CbsInstallStateInstallRequested: return L"InstallRequested"; - case CbsInstallStateSuperseded: + case Isolation::CbsInstallState::CbsInstallStateSuperseded: return L"Superseded"; - case CbsInstallStateDefault: + case Isolation::CbsInstallState::CbsInstallStateDefault: return L"Default"; - case CbsInstallStatePermanent: + case Isolation::CbsInstallState::CbsInstallStatePermanent: return L"Permanent"; - case CbsInstallStateInstalled: + case Isolation::CbsInstallState::CbsInstallStateInstalled: return L"Installed"; - case CbsInstallStateStaged: + case Isolation::CbsInstallState::CbsInstallStateStaged: return L"Staged"; - case CbsInstallStateStaging: + case Isolation::CbsInstallState::CbsInstallStateStaging: return L"Staging"; - case CbsInstallStateResolving: + case Isolation::CbsInstallState::CbsInstallStateResolving: return L"Resolving"; - case CbsInstallStateResolved: + case Isolation::CbsInstallState::CbsInstallStateResolved: return L"Resolved"; default: return L"Unknown"; diff --git a/UFCase/PackageViewModel.h b/UFCase/PackageViewModel.h index 4d3d89b..30a016c 100644 --- a/UFCase/PackageViewModel.h +++ b/UFCase/PackageViewModel.h @@ -3,7 +3,7 @@ #include "CbsApi.h" #include "PackageViewModel.g.h" -#include "PackageModel.h" +#include #include "CacheUtil.h" @@ -11,11 +11,9 @@ namespace winrt::UFCase::implementation { struct PackageViewModel : PackageViewModelT { - PackageModel &m_model; + Isolation::PackageModel m_model; - PackageViewModel(uint64_t hModel); - - uint64_t Handle(); + PackageViewModel(Isolation::PackageModel model); hstring ListNameRaw(); hstring ListIdentityRaw(); diff --git a/UFCase/PackageViewModel.idl b/UFCase/PackageViewModel.idl index 69e500c..4f09d4d 100644 --- a/UFCase/PackageViewModel.idl +++ b/UFCase/PackageViewModel.idl @@ -22,9 +22,7 @@ namespace UFCase [default_interface] runtimeclass PackageViewModel { - PackageViewModel(UInt64 hModel); - - UInt64 Handle{ get; }; + PackageViewModel(UFCase.Isolation.PackageModel model); String ListName { get; }; String ListIdentity { get; }; diff --git a/UFCase/PackagesPageViewModel.cpp b/UFCase/PackagesPageViewModel.cpp index 906c3f2..ab3ac20 100644 --- a/UFCase/PackagesPageViewModel.cpp +++ b/UFCase/PackagesPageViewModel.cpp @@ -7,8 +7,6 @@ #include "PackagesPageViewModel.g.cpp" #endif -#include "SessionModel.h" -#include "PackageModel.h" #include "PackageViewModel.g.h" namespace winrt::UFCase::implementation @@ -22,23 +20,23 @@ namespace winrt::UFCase::implementation co_await resume_background(); auto report_prog = co_await get_progress_token(); - auto &session = SessionModel::GetInstance(m_image.OpenSession()); + auto session = m_image.OpenSession(); report_prog(25); - auto &&pkgs = session.Packages(0x50); + auto &&pkgs = session.GetPackageCollection(0x50); report_prog(50); uint32_t cnt = 0; - for (auto &&pkg : pkgs) + for (auto pkg : pkgs) { - UFCase::PackageViewModel pkg_vm(pkg->GetHandle()); - if (is_nav && m_nav_ctx && pkg->Identity() == m_nav_ctx.SelectPkgId()) + UFCase::PackageViewModel pkg_vm(pkg); + if (is_nav && m_nav_ctx && pkg.Identity() == m_nav_ctx.SelectPkgId()) { assert(!m_selected); m_selected = pkg_vm; } RunUITask([=] { m_packages.Append(pkg_vm); }); - report_prog(static_cast(50 + 50 * ++cnt / pkgs.size())); + report_prog(static_cast(50 + 50 * ++cnt / pkgs.Size())); } co_await ui_thread; diff --git a/UFCase/PackagesPageViewModel.h b/UFCase/PackagesPageViewModel.h index 290f60e..83077b2 100644 --- a/UFCase/PackagesPageViewModel.h +++ b/UFCase/PackagesPageViewModel.h @@ -5,13 +5,13 @@ #include #include +#include #include "XamlUtil.h" #include "PropChgUtil.h" -#include "ImageModel.h" - #include +#include namespace winrt::UFCase::implementation { @@ -79,8 +79,9 @@ namespace winrt::UFCase::implementation { if (!m_selected) co_return; - auto manifest_root = - ImageModel::Current()->Bootdrive() / L"Windows" / L"servicing" / L"Packages"; + std::filesystem::path bootdrive_path = + GlobalRes::MainWnd().ViewModel().SelectedImageModel().Bootdrive().c_str(); + auto manifest_root = bootdrive_path / L"Windows" / L"servicing" / L"Packages"; auto manifest_name = m_selected.DetailIdentity() + L".mum"; auto file = co_await Windows::Storage::StorageFile::GetFileFromPathAsync( (manifest_root / manifest_name.c_str()).c_str()); diff --git a/UFCase/SysInfoPage.cpp b/UFCase/SysInfoPage.cpp index ac6fd7f..e908e39 100644 --- a/UFCase/SysInfoPage.cpp +++ b/UFCase/SysInfoPage.cpp @@ -7,7 +7,7 @@ #include "SysInfoPage.g.cpp" #endif -#include "ImageModel.h" +#include "GlobalUtil.h" namespace winrt::UFCase::implementation { @@ -19,7 +19,8 @@ namespace winrt::UFCase::implementation { SysInfoPageT::InitializeComponent(); - m_static = UFCase::SysInfoStaticViewModel(ImageModel::Current()->GetHandle()); + auto ivm = GlobalRes::MainWnd().ViewModel(); + m_static = UFCase::SysInfoStaticViewModel(ivm.SelectedImageModel()); this->AutoRefreshSwitch().IsOn(AppConfig::GetSysinfoAutoRefresh()); } diff --git a/UFCase/SysInfoStaticViewModel.cpp b/UFCase/SysInfoStaticViewModel.cpp index ae941d0..357da87 100644 --- a/UFCase/SysInfoStaticViewModel.cpp +++ b/UFCase/SysInfoStaticViewModel.cpp @@ -22,8 +22,7 @@ namespace winrt::UFCase::implementation { // Static Part - SysInfoStaticViewModel::SysInfoStaticViewModel(uint64_t hImgModel) - : m_model(ImageModel::GetInstance(hImgModel)) + SysInfoStaticViewModel::SysInfoStaticViewModel(Isolation::ImageModel model) : m_model(model) { } @@ -40,7 +39,7 @@ namespace winrt::UFCase::implementation hstring SysInfoStaticViewModel::OSVersion() { auto &&ver = m_model.Version(); - return std::format(L"{}.{}.{}.{} {}", ver.major, ver.minor, ver.build, ver.revision, + return std::format(L"{}.{}.{}.{} {}", ver.Major, ver.Minor, ver.Build, ver.Revision, m_model.Edition()) .c_str(); } diff --git a/UFCase/SysInfoStaticViewModel.h b/UFCase/SysInfoStaticViewModel.h index 27b0d7f..acd235c 100644 --- a/UFCase/SysInfoStaticViewModel.h +++ b/UFCase/SysInfoStaticViewModel.h @@ -2,13 +2,13 @@ #include "SysInfoStaticViewModel.g.h" -#include "ImageModel.h" +#include namespace winrt::UFCase::implementation { struct SysInfoStaticViewModel : SysInfoStaticViewModelT { - SysInfoStaticViewModel(uint64_t hImgModel); + SysInfoStaticViewModel(Isolation::ImageModel model); // machine-specific online info static hstring FirmwareType(); @@ -22,7 +22,7 @@ namespace winrt::UFCase::implementation hstring IsWinPE(); private: - ImageModel &m_model; + Isolation::ImageModel m_model; }; } // namespace winrt::UFCase::implementation diff --git a/UFCase/SysInfoStaticViewModel.idl b/UFCase/SysInfoStaticViewModel.idl index c725137..dfd0a7e 100644 --- a/UFCase/SysInfoStaticViewModel.idl +++ b/UFCase/SysInfoStaticViewModel.idl @@ -4,7 +4,7 @@ namespace UFCase [default_interface] runtimeclass SysInfoStaticViewModel { - SysInfoStaticViewModel(UInt64 hImgModel); + SysInfoStaticViewModel(UFCase.Isolation.ImageModel model); // machine-specific online info static String FirmwareType(); diff --git a/UFCase/UFCase.vcxproj b/UFCase/UFCase.vcxproj index fc3d5e0..8d6cf74 100644 --- a/UFCase/UFCase.vcxproj +++ b/UFCase/UFCase.vcxproj @@ -612,8 +612,10 @@ - - {9330649e-061c-4631-97cf-3229574cae57} + + Content + Always + {ADA12D64-FDF8-4915-AED8-A8D41458F689}