Skip to content

Commit e75fd58

Browse files
authored
Improve COM static store usage (port to 1.11) (#5685)
CP from #5680 Ported changes backward from the termination handling refactor.
1 parent 1474b6a commit e75fd58

File tree

11 files changed

+265
-56
lines changed

11 files changed

+265
-56
lines changed

src/AppInstallerCLICore/Commands/TestCommand.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "TableOutput.h"
1010
#include "Public/ConfigurationSetProcessorFactoryRemoting.h"
1111
#include "Workflows/ConfigurationFlow.h"
12+
#include <winget/RepositorySource.h>
1213
#include <winrt/Microsoft.Management.Configuration.h>
1314

1415
using namespace AppInstaller::CLI::Workflow;
@@ -215,6 +216,65 @@ namespace AppInstaller::CLI
215216
InvokeFindUnitProcessors;
216217
}
217218
};
219+
220+
struct TestCanUnloadNowCommand final : public Command
221+
{
222+
TestCanUnloadNowCommand(std::string_view parent) : Command("can-unload-now", {}, parent, Visibility::Hidden) {}
223+
224+
Resource::LocString ShortDescription() const override
225+
{
226+
return "Test DllCanUnloadNow"_lis;
227+
}
228+
229+
Resource::LocString LongDescription() const override
230+
{
231+
return "Verifies that the function that implements the inproc DllCanUnloadNow properly blocks unload due to static storage object."_lis;
232+
}
233+
234+
protected:
235+
void ExecuteInternal(Execution::Context& context) const override
236+
{
237+
Repository::Source source{ Repository::PredefinedSource::Installed };
238+
239+
ProgressCallback progress;
240+
source.Open(progress);
241+
242+
HMODULE self = GetModuleHandle(L"WindowsPackageManager.dll");
243+
if (!self)
244+
{
245+
LogAndReport(context, "Couldn't get WindowsPackageManager module");
246+
return;
247+
}
248+
249+
auto WindowsPackageManagerInProcModuleTerminate = reinterpret_cast<bool (__stdcall *)()>(GetProcAddress(self, "WindowsPackageManagerInProcModuleTerminate"));
250+
251+
// Report the object counts, attempt to terminate, report the object counts again
252+
ReportObjectCounts(context);
253+
LogAndReport(context, WindowsPackageManagerInProcModuleTerminate() ? "DllCanUnloadNow" : "DllCannotUnloadNow");
254+
ReportObjectCounts(context);
255+
}
256+
257+
private:
258+
void ReportObjectCounts(Execution::Context& context) const
259+
{
260+
std::ostringstream stream;
261+
stream << "Internal objects: " << GetInternalObjectCount() << '\n';
262+
stream << "External objects: " << GetExternalObjectCount();
263+
264+
LogAndReport(context, stream.str());
265+
}
266+
267+
uint32_t GetInternalObjectCount() const
268+
{
269+
return winrt::get_module_lock().operator unsigned int();
270+
}
271+
272+
unsigned long GetExternalObjectCount() const
273+
{
274+
auto module = Microsoft::WRL::GetModuleBase();
275+
return module ? module->GetObjectCount() : 0;
276+
}
277+
};
218278
}
219279

220280
std::vector<std::unique_ptr<Command>> TestCommand::GetCommands() const
@@ -224,6 +284,7 @@ namespace AppInstaller::CLI
224284
std::make_unique<TestAppShutdownCommand>(FullName()),
225285
std::make_unique<TestConfigurationExportCommand>(FullName()),
226286
std::make_unique<TestConfigurationFindUnitProcessorsCommand>(FullName()),
287+
std::make_unique<TestCanUnloadNowCommand>(FullName()),
227288
});
228289
}
229290

src/AppInstallerCLICore/ExecutionContext.cpp

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "Command.h"
88
#include "ExecutionContext.h"
99
#include <winget/Checkpoint.h>
10+
#include <winget/COMStaticStorage.h>
1011
#include <winget/Reboot.h>
1112
#include <winget/UserSettings.h>
1213
#include <winget/NetworkSettings.h>
@@ -22,10 +23,15 @@ namespace AppInstaller::CLI::Execution
2223
// Type to contain the CTRL signal and window messages handler.
2324
struct SignalTerminationHandler
2425
{
25-
static SignalTerminationHandler& Instance()
26+
static std::shared_ptr<SignalTerminationHandler> Instance()
2627
{
27-
static SignalTerminationHandler s_instance;
28-
return s_instance;
28+
struct Singleton : public WinRT::COMStaticStorageBase<SignalTerminationHandler>
29+
{
30+
Singleton() : COMStaticStorageBase(L"WindowsPackageManager.SignalTerminationHandler") {}
31+
};
32+
33+
static Singleton s_instance;
34+
return s_instance.Get();
2935
}
3036

3137
void AddContext(Context* context)
@@ -42,8 +48,14 @@ namespace AppInstaller::CLI::Execution
4248
std::lock_guard<std::mutex> lock{ m_contextsLock };
4349

4450
auto itr = std::find(m_contexts.begin(), m_contexts.end(), context);
45-
THROW_HR_IF(E_NOT_VALID_STATE, itr == m_contexts.end());
46-
m_contexts.erase(itr);
51+
if (itr == m_contexts.end())
52+
{
53+
AICLI_LOG(CLI, Warning, << "SignalTerminationHandler::RemoveContext did not find requested object");
54+
}
55+
else
56+
{
57+
m_contexts.erase(itr);
58+
}
4759
}
4860

4961
void StartAppShutdown()
@@ -66,7 +78,6 @@ namespace AppInstaller::CLI::Execution
6678
}
6779
#endif
6880

69-
private:
7081
SignalTerminationHandler()
7182
{
7283
if (Runtime::IsRunningAsAdmin() && Runtime::IsRunningInPackagedContext())
@@ -81,7 +92,7 @@ namespace AppInstaller::CLI::Execution
8192
auto progress = args.Progress();
8293
if (progress > minProgress)
8394
{
84-
SignalTerminationHandler::Instance().StartAppShutdown();
95+
SignalTerminationHandler::Instance()->StartAppShutdown();
8596
}
8697
});
8798
}
@@ -110,13 +121,14 @@ namespace AppInstaller::CLI::Execution
110121
// if there's no call to join.
111122
if (m_windowThread.joinable())
112123
{
113-
m_windowThread.join();
124+
m_windowThread.detach();
114125
}
115126
}
116127

128+
private:
117129
static BOOL WINAPI StaticCtrlHandlerFunction(DWORD ctrlType)
118130
{
119-
return Instance().CtrlHandlerFunction(ctrlType);
131+
return Instance()->CtrlHandlerFunction(ctrlType);
120132
}
121133

122134
static LRESULT WINAPI WindowMessageProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
@@ -125,7 +137,7 @@ namespace AppInstaller::CLI::Execution
125137
switch (uMsg)
126138
{
127139
case WM_QUERYENDSESSION:
128-
SignalTerminationHandler::Instance().StartAppShutdown();
140+
SignalTerminationHandler::Instance()->StartAppShutdown();
129141
return TRUE;
130142
case WM_ENDSESSION:
131143
case WM_CLOSE:
@@ -267,11 +279,11 @@ namespace AppInstaller::CLI::Execution
267279

268280
if (add)
269281
{
270-
SignalTerminationHandler::Instance().AddContext(context);
282+
SignalTerminationHandler::Instance()->AddContext(context);
271283
}
272284
else
273285
{
274-
SignalTerminationHandler::Instance().RemoveContext(context);
286+
SignalTerminationHandler::Instance()->RemoveContext(context);
275287
}
276288
}
277289

@@ -490,12 +502,12 @@ namespace AppInstaller::CLI::Execution
490502

491503
HWND GetWindowHandle()
492504
{
493-
return SignalTerminationHandler::Instance().GetWindowHandle();
505+
return SignalTerminationHandler::Instance()->GetWindowHandle();
494506
}
495507

496508
bool WaitForAppShutdownEvent()
497509
{
498-
return SignalTerminationHandler::Instance().WaitForAppShutdownEvent();
510+
return SignalTerminationHandler::Instance()->WaitForAppShutdownEvent();
499511
}
500512
#endif
501513

src/AppInstallerCLICore/pch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,5 @@
5454
#pragma warning( pop )
5555

5656
#include <wrl/client.h>
57+
#include <wrl/implements.h>
5758
#include <AppxPackaging.h>

src/AppInstallerCLIE2ETests/AppShutdownTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
namespace AppInstallerCLIE2ETests
88
{
99
using System;
10+
using System.Diagnostics;
1011
using System.IO;
1112
using System.Threading;
1213
using System.Threading.Tasks;
@@ -35,6 +36,12 @@ public void RegisterApplicationTest()
3536
Assert.Ignore("This test won't work on Window Server as non-admin");
3637
}
3738

39+
if (!Environment.Is64BitProcess)
40+
{
41+
// My guess is that HAM terminates us faster after the CTRL-C on x86...
42+
Assert.Ignore("This test is flaky when run as x86.");
43+
}
44+
3845
if (string.IsNullOrEmpty(TestSetup.Parameters.AICLIPackagePath))
3946
{
4047
throw new NullReferenceException("AICLIPackagePath");
@@ -95,5 +102,24 @@ public void RegisterApplicationTest()
95102
// Look for the output.
96103
Assert.True(testCmdTask.Result.StdOut.Contains("Succeeded waiting for app shutdown event"));
97104
}
105+
106+
/// <summary>
107+
/// Runs winget test can-unload-now expecting that it cannot be unloaded.
108+
/// </summary>
109+
[Test]
110+
public void CanUnloadNowTest()
111+
{
112+
var result = TestCommon.RunAICLICommand("test", "can-unload-now --verbose");
113+
114+
var lines = result.StdOut.Split('\n', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
115+
116+
Assert.AreEqual(5, lines.Length);
117+
Assert.True(lines[0].Contains("Internal objects:"));
118+
Assert.False(lines[0].Contains("Internal objects: 0"));
119+
Assert.True(lines[1].Contains("External objects: 0"));
120+
Assert.True(lines[2].Contains("DllCanUnloadNow"));
121+
Assert.True(lines[3].Contains("Internal objects: 0"));
122+
Assert.True(lines[4].Contains("External objects: 0"));
123+
}
98124
}
99125
}

src/AppInstallerRepositoryCore/Microsoft/PredefinedInstalledSourceFactory.cpp

Lines changed: 3 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include "Microsoft/SQLiteIndex.h"
77
#include "Microsoft/SQLiteIndexSource.h"
88
#include <winget/ManifestInstaller.h>
9-
9+
#include <winget/COMStaticStorage.h>
1010
#include <winget/Registry.h>
1111
#include <AppInstallerArchitecture.h>
1212
#include <winget/ExperimentalFeature.h>
@@ -262,41 +262,9 @@ namespace AppInstaller::Repository::Microsoft
262262

263263
struct CachedInstalledIndex
264264
{
265-
// https://devblogs.microsoft.com/oldnewthing/20210215-00/?p=104865
266-
struct Singleton
265+
struct Singleton : public WinRT::COMStaticStorageBase<CachedInstalledIndex>
267266
{
268-
struct Holder : public winrt::implements<Holder, winrt::Windows::Foundation::IInspectable>
269-
{
270-
static constexpr std::wstring_view Guid{ L"{48c47064-4fff-4eca-812c-dbb4f33a8fcb}" };
271-
std::shared_ptr<CachedInstalledIndex> m_shared{ std::make_shared<CachedInstalledIndex>() };
272-
};
273-
274-
std::weak_ptr<CachedInstalledIndex> m_weak;
275-
winrt::slim_mutex m_lock;
276-
277-
std::shared_ptr<CachedInstalledIndex> Get()
278-
{
279-
{
280-
const std::shared_lock lock{ m_lock };
281-
if (auto cachedIndex = m_weak.lock())
282-
{
283-
return cachedIndex;
284-
}
285-
}
286-
287-
auto value = winrt::make_self<Holder>();
288-
289-
const std::shared_lock lock{ m_lock };
290-
if (auto cachedIndex = m_weak.lock())
291-
{
292-
return cachedIndex;
293-
}
294-
295-
winrt::Windows::ApplicationModel::Core::CoreApplication::Properties().Insert(Holder::Guid, value.as<winrt::Windows::Foundation::IInspectable>());
296-
297-
m_weak = value->m_shared;
298-
return value->m_shared;
299-
}
267+
Singleton() : COMStaticStorageBase(L"WindowsPackageManager.CachedInstalledIndex") {}
300268
};
301269

302270
CachedInstalledIndex()

src/AppInstallerSharedLib/AppInstallerSharedLib.vcxproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@
349349
<ClInclude Include="Public\winget\AsyncTokens.h" />
350350
<ClInclude Include="Public\winget\Certificates.h" />
351351
<ClInclude Include="Public\winget\Compression.h" />
352+
<ClInclude Include="Public\winget\COMStaticStorage.h" />
352353
<ClInclude Include="Public\winget\ConfigurationSetProcessorHandlers.h" />
353354
<ClInclude Include="Public\winget\Filesystem.h" />
354355
<ClInclude Include="Public\winget\GroupPolicy.h" />
@@ -379,6 +380,7 @@
379380
<ClCompile Include="AppInstallerStrings.cpp" />
380381
<ClCompile Include="Certificates.cpp" />
381382
<ClCompile Include="Compression.cpp" />
383+
<ClCompile Include="COMStaticStorage.cpp" />
382384
<ClCompile Include="DateTime.cpp" />
383385
<ClCompile Include="Errors.cpp" />
384386
<ClCompile Include="Filesystem.cpp" />
@@ -436,4 +438,4 @@
436438
<Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.props'))" />
437439
<Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.Windows.CppWinRT.2.0.230706.1\build\native\Microsoft.Windows.CppWinRT.targets'))" />
438440
</Target>
439-
</Project>
441+
</Project>

src/AppInstallerSharedLib/AppInstallerSharedLib.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@
140140
<ClInclude Include="Public\winget\ModuleCountBase.h">
141141
<Filter>Public\winget</Filter>
142142
</ClInclude>
143+
<ClInclude Include="Public\winget\COMStaticStorage.h">
144+
<Filter>Public\winget</Filter>
145+
</ClInclude>
143146
</ItemGroup>
144147
<ItemGroup>
145148
<ClCompile Include="pch.cpp">
@@ -229,6 +232,9 @@
229232
<ClCompile Include="SQLiteDynamicStorage.cpp">
230233
<Filter>SQLite</Filter>
231234
</ClCompile>
235+
<ClCompile Include="COMStaticStorage.cpp">
236+
<Filter>Source Files</Filter>
237+
</ClCompile>
232238
</ItemGroup>
233239
<ItemGroup>
234240
<None Include="PropertySheet.props" />
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
#include "pch.h"
4+
#include "Public/winget/COMStaticStorage.h"
5+
6+
namespace AppInstaller::WinRT
7+
{
8+
COMStaticStorageStatics& COMStaticStorageStatics::Instance()
9+
{
10+
static COMStaticStorageStatics s_instance;
11+
return s_instance;
12+
}
13+
14+
void COMStaticStorageStatics::AddStaticStorageItem(const winrt::hstring& name, const winrt::Windows::Foundation::IInspectable& item)
15+
{
16+
COMStaticStorageStatics& instance = Instance();
17+
const winrt::slim_lock_guard lock{ instance.m_lock };
18+
winrt::Windows::ApplicationModel::Core::CoreApplication::Properties().Insert(name, item);
19+
instance.m_items.emplace(std::wstring{ name });
20+
}
21+
22+
void COMStaticStorageStatics::ResetAll() try
23+
{
24+
COMStaticStorageStatics& instance = Instance();
25+
std::set<std::wstring> localItems;
26+
27+
{
28+
const winrt::slim_lock_guard lock{ instance.m_lock };
29+
instance.m_items.swap(localItems);
30+
}
31+
32+
for (const auto& item : localItems)
33+
{
34+
winrt::Windows::ApplicationModel::Core::CoreApplication::Properties().TryRemove(item);
35+
}
36+
}
37+
CATCH_LOG();
38+
}

0 commit comments

Comments
 (0)