Last active
          January 4, 2025 20:48 
        
      - 
      
 - 
        
Save ileonte/7f564af15619b554745883cb9b99a149 to your computer and use it in GitHub Desktop.  
  
    
      This file contains hidden or 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
    
  
  
    
  | instance_id=0a087eb5 | |
| installation_name=VisualStudio/14.37.32822 | |
| installation_path=C:\MSVC | |
| installation_version=14.37.32822 | |
| display_name=Visual Studio Community 2022 | |
| display_desc=Powerful IDE, free for students, open-source contributors, and individuals | |
| sdk_version=10.0.22000.0 | |
| sdk_path=C:\MSVC\Windows Kits\10 | 
  
    
      This file contains hidden or 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
    
  
  
    
  | // cl /nologo /LD /EHsc /MT /std:c++17 /Fe:vs-setup-shim.dll vs-setup-shim.cpp /link /nologo Ole32.lib OleAut32.lib Advapi32.lib Pathcch.lib /DEF:vs-setup-shim.def | |
| #define WIN32_LEAN_AND_MEAN | |
| #include <windows.h> | |
| #include <combaseapi.h> | |
| #include <PathCch.h> | |
| #include <stdio.h> | |
| #include <assert.h> | |
| #include <io.h> | |
| #include <wchar.h> | |
| // Ole32.lib;OleAut32.lib;Advapi32.lib;Pathcch.lib; | |
| static HMODULE this_module; | |
| // https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.setup.configuration?view=visualstudiosdk-2022 | |
| // https://github.com/Kitware/CMake/blob/master/Utilities/cmvssetup/Setup.Configuration.h | |
| struct __declspec(uuid("B41463C3-8866-43B5-BC33-2B0676F7F42E") novtable) ISetupInstance; | |
| struct __declspec(uuid("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848") novtable) IEnumSetupInstances; | |
| struct __declspec(uuid("42843719-DB4C-46C2-8E7C-64F1816EFD5B") novtable) ISetupConfiguration; | |
| struct __declspec(uuid("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D")) SetupConfiguration; | |
| static constexpr GUID IID_ISetupInstance = __uuidof(ISetupInstance); | |
| static constexpr GUID IID_IEnumSetupInstances = __uuidof(IEnumSetupInstances); | |
| static constexpr GUID IID_ISetupConfiguration = __uuidof(ISetupConfiguration); | |
| static constexpr GUID CLSID_SetupConfiguration = __uuidof(SetupConfiguration); | |
| struct setup_instance { | |
| BSTR instance_id; | |
| FILETIME install_date; | |
| BSTR name; | |
| BSTR path; | |
| BSTR version; | |
| BSTR display_name; | |
| BSTR display_desc; | |
| BSTR sdk_version; | |
| BSTR sdk_path; | |
| operator bool () const { | |
| return (instance_id != nullptr) | |
| && (name != nullptr) | |
| && (path != nullptr) | |
| && (version != nullptr) | |
| && (display_name != nullptr) | |
| && (display_desc != nullptr) | |
| && (sdk_version != nullptr) | |
| && (sdk_path != nullptr); | |
| } | |
| }; | |
| static constexpr const long max_slots = 16; // should be enough for everybody | |
| static setup_instance slots[max_slots]; | |
| static long slot_count = 0; | |
| static wchar_t *config_data = nullptr; | |
| static int config_size = 0; | |
| struct __declspec(novtable uuid("B41463C3-8866-43B5-BC33-2B0676F7F42E")) ISetupInstance : public IUnknown { | |
| virtual __declspec(nothrow) HRESULT __stdcall GetInstanceId(_Out_ BSTR *pbstrInstanceId) = 0; | |
| virtual __declspec(nothrow) HRESULT __stdcall GetInstallDate(_Out_ LPFILETIME pInstallDate) = 0; | |
| virtual __declspec(nothrow) HRESULT __stdcall GetInstallationName(_Out_ BSTR *pbstrInstallationName) = 0; | |
| virtual __declspec(nothrow) HRESULT __stdcall GetInstallationPath(_Out_ BSTR *pbstrInstallationPath) = 0; | |
| virtual __declspec(nothrow) HRESULT __stdcall GetInstallationVersion(_Out_ BSTR *pbstrInstallationVersion) = 0; | |
| virtual __declspec(nothrow) HRESULT __stdcall GetDisplayName(_In_ LCID lcid, _Out_ BSTR *pbstrDisplayName) = 0; | |
| virtual __declspec(nothrow) HRESULT __stdcall GetDescription(_In_ LCID lcid, _Out_ BSTR *pbstrDescription) = 0; | |
| virtual __declspec(nothrow) HRESULT __stdcall ResolvePath(_In_opt_z_ LPCOLESTR pwszRelativePath, _Out_ BSTR *pbstrAbsolutePath) = 0; | |
| }; | |
| struct SetupInstance : public ISetupInstance { | |
| virtual HRESULT __stdcall QueryInterface(REFIID iid, void** pintf) override { | |
| if (iid == IID_IUnknown || iid == IID_ISetupInstance) { | |
| *pintf = (ISetupInstance*)this; | |
| AddRef(); | |
| return S_OK; | |
| } | |
| return E_NOTIMPL; | |
| } | |
| virtual ULONG __stdcall AddRef() override { return InterlockedIncrement(&ref_count_); } | |
| virtual ULONG __stdcall Release() override { | |
| auto count = InterlockedDecrement(&ref_count_); | |
| if (!count) delete this; | |
| return count; | |
| } | |
| virtual HRESULT __stdcall GetInstanceId(BSTR *pid) override { *pid = SysAllocString(inst_->instance_id); return S_OK; } | |
| virtual HRESULT __stdcall GetInstallDate(LPFILETIME pdate) override { *pdate = inst_->install_date; return S_OK; } | |
| virtual HRESULT __stdcall GetInstallationName(BSTR *pname) override { *pname = SysAllocString(inst_->name); return S_OK; } | |
| virtual HRESULT __stdcall GetInstallationPath(BSTR *ppath) override { *ppath = SysAllocString(inst_->path); return S_OK; } | |
| virtual HRESULT __stdcall GetInstallationVersion(BSTR *pver) override { *pver = SysAllocString(inst_->version); return S_OK; } | |
| virtual HRESULT __stdcall GetDisplayName(LCID, BSTR *pname) override { *pname = SysAllocString(inst_->display_name); return S_OK; } | |
| virtual HRESULT __stdcall GetDescription(LCID, BSTR *pdesc) override { *pdesc = SysAllocString(inst_->display_desc); return S_OK; } | |
| virtual HRESULT __stdcall ResolvePath(LPCOLESTR rel, BSTR *pout) override { | |
| auto len = UINT(wcslen(rel) + wcslen(inst_->path) + 2); | |
| auto ret = SysAllocStringLen(nullptr, len); | |
| if (!ret) return E_OUTOFMEMORY; | |
| auto hr = PathCchCombineEx(ret, len, inst_->path, rel, PATHCCH_ALLOW_LONG_PATHS); | |
| if (!SUCCEEDED(hr)) { | |
| SysFreeString(ret); | |
| *pout = nullptr; | |
| return hr; | |
| } | |
| *pout = ret; | |
| return S_OK; | |
| } | |
| SetupInstance(setup_instance const *inst) : inst_(inst), ref_count_(0) {} | |
| virtual ~SetupInstance() { inst_ = nullptr; } | |
| private: | |
| setup_instance const *inst_ = nullptr; | |
| ULONG ref_count_ = 0; | |
| }; | |
| struct __declspec(novtable uuid("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848")) IEnumSetupInstances : public IUnknown { | |
| virtual __declspec(nothrow) HRESULT __stdcall Next( | |
| _In_ ULONG celt, | |
| _Out_writes_to_(celt, *pceltFetched) ISetupInstance **rgelt, | |
| _Out_opt_ _Deref_out_range_(0, celt) ULONG *pceltFetched) = 0; | |
| virtual __declspec(nothrow) HRESULT __stdcall Skip(_In_ ULONG celt) = 0; | |
| virtual __declspec(nothrow) HRESULT __stdcall Reset() = 0; | |
| virtual __declspec(nothrow) HRESULT __stdcall Clone(_Deref_out_opt_ IEnumSetupInstances **ppenum) = 0; | |
| }; | |
| struct EnumSetupInstances : public IEnumSetupInstances { | |
| virtual HRESULT __stdcall QueryInterface(REFIID iid, void** pintf) override { | |
| if (iid == IID_IUnknown || iid == IID_IEnumSetupInstances) { | |
| *pintf = (IEnumSetupInstances*)this; | |
| AddRef(); | |
| return S_OK; | |
| } | |
| return E_NOTIMPL; | |
| } | |
| virtual ULONG __stdcall AddRef() override { return InterlockedIncrement(&ref_count_); } | |
| virtual ULONG __stdcall Release() override { | |
| auto count = InterlockedDecrement(&ref_count_); | |
| if (!count) delete this; | |
| return count; | |
| } | |
| virtual HRESULT __stdcall Next(ULONG celt, ISetupInstance **rgelt, ULONG *pceltFetched) override { | |
| if (pceltFetched) *pceltFetched = 0; | |
| for (ULONG i = 0; i < celt; i++) { | |
| if (next_ >= slot_count) break; | |
| rgelt[i] = new SetupInstance(slots + next_); | |
| rgelt[i]->AddRef(); | |
| next_ += 1; | |
| if (pceltFetched) *pceltFetched += 1; | |
| } | |
| return S_OK; | |
| } | |
| virtual HRESULT __stdcall Skip(ULONG celt) override { | |
| for (ULONG i = 0; i < celt; i++) { | |
| if (next_ >= slot_count) break; | |
| next_ += 1; | |
| } | |
| return S_OK; | |
| } | |
| virtual HRESULT __stdcall Reset() override { | |
| next_ = 0; | |
| return S_OK; | |
| } | |
| virtual HRESULT __stdcall Clone(IEnumSetupInstances **ppenum) override { | |
| auto ret = new EnumSetupInstances(); | |
| ret->next_ = next_; | |
| ret->AddRef(); | |
| *ppenum = ret; | |
| return S_OK; | |
| } | |
| private: | |
| ULONG ref_count_ = 0; | |
| int next_ = 0; | |
| }; | |
| struct __declspec(novtable uuid("42843719-DB4C-46C2-8E7C-64F1816EFD5B")) ISetupConfiguration : public IUnknown { | |
| virtual __declspec(nothrow) HRESULT __stdcall EnumInstances(_Out_ IEnumSetupInstances **ppEnumInstances) = 0; | |
| virtual __declspec(nothrow) HRESULT __stdcall GetInstanceForCurrentProcess(_Out_ ISetupInstance **ppInstance) = 0; | |
| virtual __declspec(nothrow) HRESULT __stdcall GetInstanceForPath(_In_z_ LPCWSTR wzPath, _Out_ ISetupInstance **ppInstance) = 0; | |
| }; | |
| struct __declspec(uuid("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D")) SetupConfiguration : public ISetupConfiguration { | |
| virtual HRESULT __stdcall QueryInterface(REFIID iid, void **pintf) override { | |
| if (iid == IID_IUnknown || iid == IID_ISetupConfiguration) { | |
| *pintf = (ISetupConfiguration *)this; | |
| AddRef(); | |
| return S_OK; | |
| } | |
| return E_NOTIMPL; | |
| } | |
| virtual ULONG __stdcall AddRef() override { return InterlockedIncrement(&ref_count_); } | |
| virtual ULONG __stdcall Release() override { | |
| auto count = InterlockedDecrement(&ref_count_); | |
| if (!count) delete this; | |
| return count; | |
| } | |
| virtual HRESULT __stdcall EnumInstances(IEnumSetupInstances **ppEnumInstances) override { | |
| *ppEnumInstances = new EnumSetupInstances(); | |
| (*ppEnumInstances)->AddRef(); | |
| return S_OK; | |
| } | |
| virtual HRESULT __stdcall GetInstanceForCurrentProcess(ISetupInstance **ppInstance) override { | |
| *ppInstance = new SetupInstance(slots); | |
| (*ppInstance)->AddRef(); | |
| return S_OK; | |
| } | |
| virtual HRESULT __stdcall GetInstanceForPath(LPCWSTR wzPath, ISetupInstance **ppInstance) override { | |
| *ppInstance = new SetupInstance(slots); | |
| (*ppInstance)->AddRef(); | |
| return S_OK; | |
| } | |
| private: | |
| ULONG ref_count_ = 0; | |
| }; | |
| struct SetupConfigurationClass : public IClassFactory { | |
| virtual HRESULT __stdcall QueryInterface(REFIID iid, void** pintf) override { | |
| if (iid == IID_IUnknown || iid == IID_IClassFactory) { | |
| *pintf = this; | |
| AddRef(); | |
| return S_OK; | |
| } | |
| return E_NOTIMPL; | |
| } | |
| virtual ULONG __stdcall AddRef() override { return 1; } | |
| virtual ULONG __stdcall Release() override { return 1; } | |
| virtual HRESULT __stdcall CreateInstance(IUnknown* pUnkOuter, REFIID iid, void** ppv) override { | |
| *ppv = nullptr; | |
| if (iid == IID_ISetupConfiguration) { | |
| auto inst = new SetupConfiguration(); | |
| if (!SUCCEEDED(inst->QueryInterface(iid, ppv))) return E_NOINTERFACE; | |
| return S_OK; | |
| } | |
| return E_NOINTERFACE; | |
| } | |
| virtual HRESULT __stdcall LockServer(BOOL fLock) override { return E_FAIL; } | |
| }; | |
| static bool line_empty(wchar_t const *line) { | |
| while (*line) { | |
| if (!iswspace(*line)) return false; | |
| line++; | |
| } | |
| return true; | |
| } | |
| static bool parse_line(wchar_t const *line, setup_instance *inst) { | |
| static constexpr const wchar_t id_marker[] = L"instance_id="; | |
| static constexpr const wchar_t iname_marker[] = L"installation_name="; | |
| static constexpr const wchar_t ipath_marker[] = L"installation_path="; | |
| static constexpr const wchar_t ver_marker[] = L"installation_version="; | |
| static constexpr const wchar_t dname_marker[] = L"display_name="; | |
| static constexpr const wchar_t ddesc_marker[] = L"display_desc="; | |
| static constexpr const wchar_t sdk_ver_marker[] = L"sdk_version="; | |
| static constexpr const wchar_t sdk_path_marker[] = L"sdk_path="; | |
| #define MLEN(marker) (sizeof((marker)) / sizeof((marker)[0]) - 1) | |
| if (!_wcsnicmp(line, id_marker, MLEN(id_marker))) { | |
| inst->instance_id = BSTR(line + MLEN(id_marker)); | |
| return !line_empty(inst->instance_id); | |
| } else if (!_wcsnicmp(line, iname_marker, MLEN(iname_marker))) { | |
| inst->name = BSTR(line + MLEN(iname_marker)); | |
| return !line_empty(inst->name); | |
| } else if (!_wcsnicmp(line, ipath_marker, MLEN(ipath_marker))) { | |
| inst->path = BSTR(line + MLEN(ipath_marker)); | |
| return !line_empty(inst->path); | |
| } else if (!_wcsnicmp(line, ver_marker, MLEN(ver_marker))) { | |
| inst->version = BSTR(line + MLEN(ver_marker)); | |
| return !line_empty(inst->version); | |
| } else if (!_wcsnicmp(line, dname_marker, MLEN(dname_marker))) { | |
| inst->display_name = BSTR(line + MLEN(dname_marker)); | |
| return !line_empty(inst->display_name); | |
| } else if (!_wcsnicmp(line, ddesc_marker, MLEN(ddesc_marker))) { | |
| inst->display_desc = BSTR(line + MLEN(ddesc_marker)); | |
| return !line_empty(inst->display_desc); | |
| } else if (!_wcsnicmp(line, sdk_ver_marker, MLEN(sdk_ver_marker))) { | |
| inst->sdk_version = BSTR(line + MLEN(sdk_ver_marker)); | |
| return !line_empty(inst->sdk_version); | |
| } else if (!_wcsnicmp(line, sdk_path_marker, MLEN(sdk_path_marker))) { | |
| inst->sdk_path = BSTR(line + MLEN(sdk_path_marker)); | |
| return !line_empty(inst->sdk_path); | |
| } else { | |
| return false; | |
| } | |
| #undef MLEN | |
| } | |
| static bool add_entry(int line, setup_instance *inst) { | |
| if (slot_count >= max_slots) { | |
| printf("Too many entries!\n"); | |
| return false; | |
| } | |
| if (!*inst) { | |
| printf("Incomplete entry at line %d\n", line); | |
| return false; | |
| } | |
| slots[slot_count++] = *inst; | |
| memset(inst, 0, sizeof(*inst)); | |
| return true; | |
| } | |
| static bool load_config(HMODULE hModule) { | |
| wchar_t path[1024]; | |
| auto len = GetModuleFileNameW(hModule, path, sizeof(path) / sizeof(path[0])); | |
| PathCchRemoveFileSpec(path, len); | |
| auto hr = PathCchCombineEx(path, sizeof(path) / sizeof(path[0]), path, L"installs.txt", PATHCCH_ALLOW_LONG_PATHS); | |
| if (!SUCCEEDED(hr)) { | |
| printf("PathCchCombineEx(): %08lx\n", hr); | |
| return false; | |
| } | |
| FILE *f; | |
| auto open_result = _wfopen_s(&f, path, L"rt"); | |
| if (open_result || !f) { | |
| printf("_wfopen_s('%S'): %08x\n", path, open_result); | |
| return false; | |
| } | |
| FILETIME ft; | |
| GetFileTime((HANDLE)_get_osfhandle(_fileno(f)), &ft, nullptr, nullptr); | |
| static constexpr const int alloc_inc_size = 2048; | |
| auto remaining = config_size; | |
| while (!feof(f)) { | |
| if (!remaining) { | |
| auto new_data = (wchar_t *)realloc(config_data, (config_size + alloc_inc_size) * sizeof(wchar_t)); | |
| if (!new_data) { | |
| fclose(f); | |
| return false; | |
| } | |
| config_data = new_data; | |
| remaining = alloc_inc_size; | |
| memset(config_data + config_size, 0, remaining * sizeof(wchar_t)); | |
| } | |
| auto ptr = config_data + config_size; | |
| if (!fgetws(ptr, remaining, f)) break; | |
| int count = 0; | |
| while ((count < remaining) && ptr[count] && (ptr[count++] != L'\n')) {} | |
| config_size += count; | |
| remaining -= count; | |
| } | |
| if (!remaining) { | |
| auto new_data = (wchar_t *)realloc(config_data, (config_size + 1) * sizeof(wchar_t)); | |
| if (!new_data) { | |
| fclose(f); | |
| return false; | |
| } | |
| config_data = new_data; | |
| config_data[config_size++] = 0; | |
| } | |
| fclose(f); | |
| int pos = 0; | |
| setup_instance current_instance; | |
| bool parsing_entry = false; | |
| int entry_line_start = 0; | |
| int line_count = 0; | |
| memset(¤t_instance, 0, sizeof(current_instance)); | |
| while (pos < config_size) { | |
| auto line = config_data + pos; | |
| auto line_found = false; | |
| while (!line_found && (pos < config_size)) { | |
| switch (config_data[pos]) { | |
| case L'\r': { | |
| config_data[pos++] = 0; | |
| break; | |
| } | |
| case L'\n': { | |
| config_data[pos++] = 0; | |
| line_found = true; | |
| break; | |
| } | |
| case 0: { | |
| line_found = true; | |
| break; | |
| } | |
| default: { | |
| pos++; | |
| break; | |
| } | |
| } | |
| } | |
| if (pos >= config_size) line_found = (line <= config_data + config_size - 1); | |
| if (!line_found) break; | |
| line_count += 1; | |
| if (line_empty(line)) { | |
| if (!parsing_entry) continue; | |
| parsing_entry = false; | |
| current_instance.install_date = ft; | |
| if (!add_entry(entry_line_start, ¤t_instance)) return false; | |
| } | |
| else { | |
| if (!parse_line(line, ¤t_instance)) { | |
| printf("Failed to parse line %d: '%S'\n", line_count, line); | |
| return false; | |
| } | |
| if (!parsing_entry) { | |
| parsing_entry = true; | |
| entry_line_start = line_count; | |
| } | |
| } | |
| } | |
| if (parsing_entry) { | |
| current_instance.install_date = ft; | |
| if (!add_entry(entry_line_start, ¤t_instance)) return false; | |
| } | |
| return (slot_count > 0); | |
| } | |
| static bool unload_config() { | |
| memset(slots, 0, sizeof(slots)); | |
| free(config_data); | |
| config_data = nullptr; | |
| config_size = 0; | |
| return true; | |
| } | |
| BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { | |
| switch (ul_reason_for_call) { | |
| case DLL_PROCESS_ATTACH: { | |
| this_module = hModule; | |
| return load_config(hModule) ? TRUE : FALSE; | |
| } | |
| case DLL_PROCESS_DETACH: return unload_config() ? TRUE : FALSE; | |
| } | |
| return TRUE; | |
| } | |
| static auto cls = SetupConfigurationClass(); | |
| _Check_return_ STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID *ppv) { | |
| if (rclsid != CLSID_SetupConfiguration) { | |
| *ppv = nullptr; | |
| return E_NOTIMPL; | |
| } | |
| *ppv = &cls; | |
| return S_OK; | |
| } | |
| static void print_status(LSTATUS status) { | |
| wchar_t msg[128]; | |
| memset(msg, 0, sizeof(msg)); | |
| FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, status, 0, msg, sizeof(msg) / sizeof(msg[0]), nullptr); | |
| wchar_t fmt[512]; | |
| swprintf_s(fmt, L"STATUS(%08lx): %s", status, msg); | |
| OutputDebugStringW(fmt); | |
| } | |
| _Check_return_ STDAPI DllRegisterServer() { | |
| wchar_t path[1024]; | |
| auto len = GetModuleFileNameW(this_module, path, sizeof(path) / sizeof(path[0])); | |
| wchar_t szKey[64]; | |
| auto clsid = CLSID_SetupConfiguration; | |
| swprintf_s(szKey, L"CLSID\\{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", | |
| clsid.Data1, clsid.Data2, clsid.Data3, | |
| clsid.Data4[0], clsid.Data4[1], clsid.Data4[2], clsid.Data4[3], | |
| clsid.Data4[4], clsid.Data4[5], clsid.Data4[6], clsid.Data4[7]); | |
| HKEY classKey, procKey; | |
| auto ret = RegCreateKeyExW(HKEY_CLASSES_ROOT, szKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &classKey, NULL); | |
| if (ret != ERROR_SUCCESS) { | |
| print_status(ret); | |
| return E_FAIL; | |
| } | |
| ret = RegCreateKeyExW(classKey, L"InprocServer32", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &procKey, NULL); | |
| if (ret != ERROR_SUCCESS) { | |
| print_status(ret); | |
| return E_FAIL; | |
| } | |
| RegSetValueExW(procKey, nullptr, 0, REG_SZ, (BYTE *)path, DWORD((wcslen(path) + 1) * sizeof(wchar_t))); | |
| RegSetValueExW(procKey, L"ThreadingModel", 0, REG_SZ, (BYTE *)L"Both", 5 * sizeof(wchar_t)); | |
| RegCloseKey(procKey); | |
| RegCloseKey(classKey); | |
| for (long i = 0; i < slot_count; i++) { | |
| wchar_t key_name[128]; | |
| wchar_t path[4096]; | |
| HKEY key; | |
| auto ver = slots[i].sdk_version; | |
| auto path_raw = slots[i].sdk_path; | |
| swprintf_s(path, L"%s", path_raw); | |
| PathCchAddBackslashEx(path, sizeof(path) / sizeof(path[0]), nullptr, nullptr); | |
| swprintf_s(key_name, L"SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots\\%s", ver); | |
| RegCreateKeyExW(HKEY_LOCAL_MACHINE, key_name, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL); | |
| RegCloseKey(key); | |
| swprintf_s(key_name, L"SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots"); | |
| RegCreateKeyExW(HKEY_LOCAL_MACHINE, key_name, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL); | |
| RegSetValueExW(key, L"KitsRoot10", 0, REG_SZ, (BYTE *)path, DWORD((wcslen(path) + 1) * sizeof(wchar_t))); | |
| RegCloseKey(key); | |
| swprintf_s(key_name, L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows Kits\\Installed Roots\\%s", ver); | |
| RegCreateKeyExW(HKEY_LOCAL_MACHINE, key_name, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL); | |
| RegCloseKey(key); | |
| swprintf_s(key_name, L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows Kits\\Installed Roots"); | |
| RegCreateKeyExW(HKEY_LOCAL_MACHINE, key_name, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL); | |
| RegSetValueExW(key, L"KitsRoot10", 0, REG_SZ, (BYTE *)path, DWORD((wcslen(path) + 1) * sizeof(wchar_t))); | |
| RegCloseKey(key); | |
| } | |
| return S_OK; | |
| } | |
| _Check_return_ STDAPI DllUnregisterServer() { | |
| wchar_t szKey[64]; | |
| auto clsid = CLSID_SetupConfiguration; | |
| swprintf_s(szKey, L"CLSID\\{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\\InprocServer32", | |
| clsid.Data1, clsid.Data2, clsid.Data3, | |
| clsid.Data4[0], clsid.Data4[1], clsid.Data4[2], clsid.Data4[3], | |
| clsid.Data4[4], clsid.Data4[5], clsid.Data4[6], clsid.Data4[7]); | |
| RegDeleteKeyW(HKEY_CLASSES_ROOT, szKey); | |
| swprintf_s(szKey, L"CLSID\\{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", | |
| clsid.Data1, clsid.Data2, clsid.Data3, | |
| clsid.Data4[0], clsid.Data4[1], clsid.Data4[2], clsid.Data4[3], | |
| clsid.Data4[4], clsid.Data4[5], clsid.Data4[6], clsid.Data4[7]); | |
| RegDeleteKeyW(HKEY_CLASSES_ROOT, szKey); | |
| return S_OK; | |
| } | 
  
    
      This file contains hidden or 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
    
  
  
    
  | EXPORTS | |
| DllGetClassObject PRIVATE | |
| DllRegisterServer PRIVATE | |
| DllUnregisterServer PRIVATE | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment