Last active
February 1, 2018 05:04
-
-
Save kennykerr/be66a7227f4ff42a2c3329746c1fbae3 to your computer and use it in GitHub Desktop.
Builds a WinRT factory quality report
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "winrt/base.h" | |
#include <set> | |
using namespace winrt; | |
using namespace Windows::Foundation; | |
using namespace std::chrono_literals; | |
extern "C" | |
{ | |
HRESULT __stdcall OS_RoGetActivationFactory(HSTRING classId, GUID const& iid, void** factory); | |
} | |
#ifdef _M_IX86 | |
#pragma comment(linker, "/alternatename:_OS_RoGetActivationFactory@12=_RoGetActivationFactory@12") | |
#else | |
#pragma comment(linker, "/alternatename:OS_RoGetActivationFactory=RoGetActivationFactory") | |
#endif | |
struct registry_traits | |
{ | |
using type = HKEY; | |
static void close(type value) noexcept | |
{ | |
WINRT_VERIFY_(ERROR_SUCCESS, RegCloseKey(value)); | |
} | |
static constexpr type invalid() noexcept | |
{ | |
return nullptr; | |
} | |
}; | |
using registry_key = handle_type<registry_traits>; | |
HRESULT GetActivationFactory(hstring const& class_name) noexcept | |
{ | |
try | |
{ | |
com_ptr<IAgileObject> factory; | |
return OS_RoGetActivationFactory(get_abi(class_name), guid_of<IAgileObject>(), factory.put_void()); | |
} | |
catch (...) | |
{ | |
return HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); | |
} | |
} | |
IAsyncOperation<HRESULT> GetActivationFactoryAsync(hstring class_name) | |
{ | |
co_await resume_background(); | |
co_return GetActivationFactory(class_name); | |
} | |
IAsyncOperation<hstring> GetFactoryReportAsync() | |
{ | |
co_await resume_background(); | |
registry_key key; | |
check_win32(RegOpenKeyEx(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\WindowsRuntime\ActivatableClassId)", 0, KEY_READ, key.put())); | |
std::array<wchar_t, 255> name_buffer; | |
std::set<hstring> agile; | |
std::set<hstring> non_agile; | |
std::map<HRESULT, std::set<hstring>> unknown; | |
std::set<hstring> crash; | |
std::set<hstring> hang; | |
for (DWORD index = 0; ; ++index) | |
{ | |
DWORD name_length{ static_cast<DWORD>(name_buffer.size()) }; | |
LONG const enum_result = RegEnumKeyEx(key.get(), index, name_buffer.data(), &name_length, nullptr, nullptr, nullptr, nullptr); | |
if (enum_result == ERROR_NO_MORE_ITEMS) | |
{ | |
break; | |
} | |
check_win32(enum_result); | |
hstring class_name{ name_buffer.data(), name_length }; | |
IAsyncOperation<HRESULT> async = GetActivationFactoryAsync(class_name); | |
slim_mutex m; | |
slim_condition_variable cv; | |
bool completed = false; | |
async.Completed([&](auto&&...) | |
{ | |
{ | |
slim_lock_guard const guard(m); | |
completed = true; | |
} | |
cv.notify_one(); | |
}); | |
slim_lock_guard guard(m); | |
cv.wait_for(m, 2s, [&] { return completed; }); | |
HRESULT activate_result = HRESULT_FROM_WIN32(ERROR_APP_HANG); | |
if (async.Status() == AsyncStatus::Completed) | |
{ | |
activate_result = async.GetResults(); | |
} | |
if (activate_result == S_OK) | |
{ | |
agile.insert(class_name); | |
} | |
else if (activate_result == E_NOINTERFACE) | |
{ | |
non_agile.insert(class_name); | |
} | |
else if (activate_result == HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)) | |
{ | |
crash.insert(class_name); | |
} | |
else if (activate_result == HRESULT_FROM_WIN32(ERROR_APP_HANG)) | |
{ | |
hang.insert(class_name); | |
} | |
else | |
{ | |
unknown[activate_result].insert(class_name); | |
} | |
} | |
std::wstring report; | |
report += L"\n\nNON-AGILE\n\n"; | |
for (std::wstring_view class_name : non_agile) | |
{ | |
report += class_name; | |
report += L"\n"; | |
} | |
report += L"\n\nCRASH\n\n"; | |
for (std::wstring_view class_name : crash) | |
{ | |
report += class_name; | |
report += L"\n"; | |
} | |
report += L"\n\nHANG\n\n"; | |
for (std::wstring_view class_name : hang) | |
{ | |
report += class_name; | |
report += L"\n"; | |
} | |
report += L"\n\nUNKNOWN\n\n"; | |
for (auto&& pair : unknown) | |
{ | |
hresult_error error(pair.first); | |
report += L"\n" + error.message() + L" (" + std::to_wstring(error.code()) + L")\n"; | |
for (std::wstring_view class_name : pair.second) | |
{ | |
report += class_name; | |
report += L"\n"; | |
} | |
} | |
co_return hstring(report); | |
} | |
int main() | |
{ | |
init_apartment(); | |
hstring report = GetFactoryReportAsync().get(); | |
printf("%ls\n", report.c_str()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment