Add Control Panel Revival mod - #5219
Conversation
This mod restores legacy Control Panel applets in Windows 11 by bypassing the modern Settings app redirection. It requires ExplorerPatcher to function properly.
|
Thanks for the pull request! This repository uses a two-stage review: an AI review that you run yourself, followed by a human review. To get started, comment See the pull request review process for the full details. |
|
/ai-review |
|
@AdmXP8 Comment |
|
/ready-for-reviewer |
|
New commits were pushed, so this pull request left the human review queue and is back to waiting-for-author. Comment |
Implement Control Panel Revival mod to restore legacy Control Panel applets in Windows 11.
|
/ai-review |
Submission reviewNote: This review was done by Claude. Due to the amount of submissions, doing a fully manual review for each pull request is no longer feasible. Thank you for understanding. Remember: The AI reviewer can be wrong - it may misread code, flag correct code as broken, or suggest changes that make things worse. Treat its findings as suggestions to verify, not instructions to follow blindly. You're responsible for the code you submit, so if a finding doesn't hold up, say so instead of changing working code to satisfy it. Please address the following issues. The items in the collapsed sections are optional, so it's your call whether to address them. The core mechanism here — blindly scanning 1.
The correct approach is to hook the code that consults the hidden/redirected list, not to patch the data it reads. Windows 7 Legacy Applet Restorer and Restore the classic Personalization and other CPLs both do this by hooking the registry read APIs and synthesizing the answers, which is fully reversible. 2. The auto pCompFunc = bIgnoreCase ? wcsicmp : wcscmp;
if (0 == pCompFunc(lpString1, g_szAppletsToUnhide[i]) || ...)This is an out-of-bounds read on every counted-string call in Explorer. Guard on the terminated form, as Taskbar Grouping does: if (cchCount1 == -1 && cchCount2 == -1) { /* only then treat as C strings */ }3. The Scope it to the call you actually want to influence: set a thread-scoped flag around the specific shell32 call, and only apply the override when the flag is set. See Taskbar Grouping for the pattern ( 4. Hook HMODULE kernelBaseModule = GetModuleHandleW(L"kernelbase.dll");
auto pCompareStringOrdinal = (decltype(&CompareStringOrdinal))GetProcAddress(
kernelBaseModule, "CompareStringOrdinal");
WindhawkUtils::SetFunctionHook(pCompareStringOrdinal, CompareStringOrdinal_hook,
&CompareStringOrdinal_orig);5. The hook returns an invalid value on failure. if (!lpString1 || !lpString2) return ERROR_INVALID_PARAMETER; // wrongJust forward to the original in that case, or 6. The bool COpenControlPanel__MapLegacyName_hook(void *pThis, LPCWSTR pszLegacyName,
LPWSTR pszNewName, UINT uUnused, bool *nameChanged) {
if (nameChanged) *nameChanged = false;
if (pszNewName) *pszNewName = L'\0';
return false;
}
7. No 8. Dead placeholder loop. for (size_t i = 50; i < ARRAYSIZE(g_szAppletsToUnhide); i++) {
// Loop placeholder check handled safely below
}
9. Substantial overlap with existing mods. The applet list here is largely already covered by mods in the catalog:
The maintainer strongly prefers extending an existing mod (adding an option, or a PR to the original author's repo) over merging a near-duplicate. Please state explicitly in the PR description what this mod does that those don't, and if the delta is thin, consider contributing the difference to one of them instead. 10. The ExplorerPatcher requirement is unexplained and unenforced. The README says "Installing ExplorerPatcher is necessary for this mod to work", but nothing in the code references or depends on ExplorerPatcher. Please explain what specifically breaks without it and why — and ideally make the mod work standalone. A mod that only functions alongside a third-party patcher, with no stated reason, is hard to accept into the catalog. 11. All hook results are unchecked and there is no logging. 12. The symbol-hook array declares the wrong module. The comment above it says // explorer.exe, control.exe
const WindhawkUtils::SYMBOL_HOOK explorerControlHooks[] = { ... };
...
WindhawkUtils::HookSymbols(hShell32, explorerControlHooks, ARRAYSIZE(explorerControlHooks));The declaration must name the module the hooks are actually applied to. Rename the array to 13. The README needs a screenshot and more detail. This mod has a clearly visible effect, so a screenshot of the restored applets in Control Panel would help a lot. The README is also currently three lines — it should list which applets are restored, which Windows 11 builds it was tested on, and the ExplorerPatcher rationale from item 10. Optional improvements
Minor polish — none of this affects users, so it's your call.
Functionality notes
Non-critical observations and ideas about the feature behavior itself.
Next steps:
See the review process for details. |
Refactor Control Panel Revival mod to improve hooks and error handling.
|
/ai-review |
Submission reviewNote: This review was done by Claude. Due to the amount of submissions, doing a fully manual review for each pull request is no longer feasible. Thank you for understanding. Remember: The AI reviewer can be wrong - it may misread code, flag correct code as broken, or suggest changes that make things worse. Treat its findings as suggestions to verify, not instructions to follow blindly. You're responsible for the code you submit, so if a finding doesn't hold up, say so instead of changing working code to satisfy it. Please address the following issues. The items in the collapsed sections are optional, so it's your call whether to address them. The two mechanisms this mod is built on — a process-wide 1. Hooking
Also worth noting: this runs up to 28 The fix is to hook the specific function that makes the redirection decision, not a generic comparison primitive. The 2. The scan (lines 96-129) walks the whole mapped image byte-by-byte and zeroes the first byte-sequence match it finds anywhere in it. There is no section filter, no On top of that, when the mod is enabled mid-session (Explorer already running), the patch is written underneath live threads that may be reading those bytes, and This is the "workaround instead of root cause" pattern the project pushes back on. Please replace the memory patching with a targeted hook on whatever function consults the redirect list — patching data in a system DLL is not something that can be made safe by adding more guards around it. 3. The memory patches are applied at lines 201-206, before any hook is registered. Every This is not hypothetical: the Minimum fix: register all hooks first and apply the patches last, and revert every applied patch (plus 4. Substantial overlap with existing mods.
The project's preference is to extend an existing mod (add an option, or open an issue/PR on the original author's repo) rather than merge a parallel mod. Please state explicitly which cases this covers that the mods above don't. If the 5. "Requires ExplorerPatcher" is a hard external dependency. The README (line 22) states that installing ExplorerPatcher is necessary for the mod to work, but nothing in the code references or depends on ExplorerPatcher. A Windhawk mod should be self-contained and work on a stock system; requiring a third-party shell-replacement tool that hooks the same shell surfaces is both a design problem and a conflict risk. Please either explain precisely what EP provides here (and make the mod degrade gracefully without it), or drop the requirement from the README. 6. No screenshot in the README. The mod has a clearly visible effect (Control Panel applets opening instead of Settings). Please add a screenshot or short GIF — only Optional improvements
Minor polish — none of this affects users today, so it's your call.
Functionality notes
Non-critical observations and ideas about the feature behavior itself.
Next steps:
See the review process for details. |
Submission reviewNote: This review was done by Claude. Due to the amount of submissions, doing a fully manual review for each pull request is no longer feasible. Thank you for understanding. Remember: The AI reviewer can be wrong - it may misread code, flag correct code as broken, or suggest changes that make things worse. Treat its findings as suggestions to verify, not instructions to follow blindly. You're responsible for the code you submit, so if a finding doesn't hold up, say so instead of changing working code to satisfy it. Please address the following issues. The items in the collapsed sections are optional, so it's your call whether to address them. The 1. The unscoped
The README's stated reason for leaving it unscoped is that return-address scoping failed. That's the right diagnosis of the wrong technique — std::atomic<DWORD> g_compareStringOrdinalHookThreadId;
...
g_compareStringOrdinalHookThreadId = GetCurrentThreadId();
g_compareStringOrdinalAnySuffixEqual = true;
// ... call the shell function whose internal comparison you need to influence ...
g_compareStringOrdinalHookThreadId = 0;
g_compareStringOrdinalAnySuffixEqual = false;You don't need to know the exact inner call site for this to work — you only need an outer shell32 function you already hook ( 2. Debug diagnostics are left in the shipped code, and one of them is not free. The stack-walk block in 3. The mod ships with its targeting admittedly incomplete. The comment at lines 259-269 says the bare legacy-name spellings for the six target applets aren't known, that those calls "silently fall through", and instructs the user to read the log and add the missing strings to The answer is already in the repo: static const std::unordered_set<std::wstring> kNames = {
L"system", L"microsoft.system",
L"sound", L"microsoft.sound",
L"backupandrestore", L"microsoft.backupandrestore",
...
};Add the bare forms ( 4. Substantial overlap with Both mods hook 5. The The setting text says canonical names "must be at least 8 characters and contain a dot, same shape as Microsoft's own names". Optional improvements
Minor polish — none of this affects users, so it's your call.
Functionality notes
Non-critical observations and ideas about the feature behavior itself.
Next steps:
See the review process for details. |
Refactor comparison logic and improve applet handling.
|
/ai-review |
Submission reviewNote: This review was done by Claude. Due to the amount of submissions, doing a fully manual review for each pull request is no longer feasible. Thank you for understanding. Remember: The AI reviewer can be wrong - it may misread code, flag correct code as broken, or suggest changes that make things worse. Treat its findings as suggestions to verify, not instructions to follow blindly. You're responsible for the code you submit, so if a finding doesn't hold up, say so instead of changing working code to satisfy it. Please address the following issues. The items in the collapsed sections are optional, so it's your call whether to address them. The 1. The process-wide
constexpr std::wstring_view g_szBareLegacyNames[] = {
L"troubleshooting", L"installedupdates", L"defaultprograms",
L"devicesandprinters", L"fonts", L"system",
};Concrete consequences:
The README's argument that the blast radius is bounded because the hook "never touches a comparison unless the real result was already What to do instead — in order of preference:
Until it's scoped, please don't ship the unscoped version — "we couldn't scope it" isn't a limitation users can opt out of, since it applies to the whole process from the moment the mod loads. 2. Independently of how #1 is resolved: 3. The symbol hook is marked optional, so the "failed to hook" log can never fire. const WindhawkUtils::SYMBOL_HOOK shell32DllHooks[] = {
{ { L"private: bool __cdecl COpenControlPanel::_MapLegacyName(...)" },
(void**)&COpenControlPanel__MapLegacyName_orig,
(void*)COpenControlPanel__MapLegacyName_hook,
true } // <- optional
};Per 4. Overlap with That mod already hooks 5. The README is written for the reviewer, not for users. The README is what users read inside Windhawk. Right now it contains a development/negotiation log:
None of that means anything to someone installing the mod. Keep the README to: what it does, which applets, how to configure Optional improvements
Minor polish — none of this affects users, so it's your call.
Functionality notes
Non-critical observations and ideas about the feature behavior itself.
Next steps:
See the review process for details. |
This update changes the version from 0.9.9 to 1.0.0 and enhances the mod's functionality by improving the description of what the mod does and clarifying its limitations. It also refines the code for better readability and performance.
|
/ai-review |
|
This pull request has already had 3 AI reviews in the last 24 hours, which is the limit, so no review was posted this time. Comment |
|
I think that's enough; the remaining issues aren't significant, and replacing 'CompareStringOrdinal' would break the mod |
Restored original in-Control-Panel behavior and fixed shell32 hook application logic.
|
/ready-for-reviewer |
|
/ai-review |
Submission reviewNote: This review was done by Claude. Due to the amount of submissions, doing a fully manual review for each pull request is no longer feasible. Thank you for understanding. Remember: The AI reviewer can be wrong - it may misread code, flag correct code as broken, or suggest changes that make things worse. Treat its findings as suggestions to verify, not instructions to follow blindly. You're responsible for the code you submit, so if a finding doesn't hold up, say so instead of changing working code to satisfy it. Please address the following issues. The items in the collapsed sections are optional, so it's your call whether to address them. A lot has improved since the last round: the memory patching is gone, 1. The unscoped
constexpr std::wstring_view g_szBareLegacyNames[] = {
L"troubleshooting", L"installedupdates", L"defaultprograms",
L"devicesandprinters", L"fonts", L"system",
};So after this hook, any comparison in Two further points that aren't cosmetic:
I understand you don't want to ship a scoped version that doesn't work. Two concrete things you can do that don't require finding the call site first:
2. The comment above if (!WindhawkUtils::HookSymbols(hShell32, shell32DllHooks, ARRAYSIZE(shell32DllHooks))) {
Wh_Log(L"Failed to resolve/hook COpenControlPanel::_MapLegacyName - ...");
}On a build where the symbol changed, the user gets the process-wide 3. Review correspondence is shipped inside the mod source. Lines 494-518, after //The AI reviewer is right that an unscoped CompareStringOrdinal hook isn't ideal — I want to explain why it's shipping this way instead of just disagreeing with the finding.
//Four different scoping attempts were made, and each one broke the mod's actual functionality:
...
//I'm keeping this as-is rather than shipping a "safer-looking" scoped version that's actually broken.That belongs in this thread, not in the mod. The same applies to the four-attempt narrative at lines 302-323 and the 4. Please follow up on the collaboration offer in this thread.
Optional improvements
Minor polish — none of this affects users, so it's your call.
Functionality notes
Non-critical observations and ideas about the feature behavior itself.
Next steps:
See the review process for details. |
|
no listening to this guy makes the mod breaks |
|
/ready-for-reviewer |
|
What's the status of the collaboration you discussed? As the review explains, having multiple similar mods is sub-optimal. A single, polished and tested mod is preferred. |
Hi The core issue: I asked the author directly whether their mod could adopt in-place loading instead, since if it could, I'd genuinely rather merge into one polished mod than maintain two overlapping ones. Their answer: their mod's redirect handling is intentionally broader - it targets multiple redirect scenarios, not just the Control Panel-opening case this mod focuses on - and they agreed the two are "similar, but the feature is different," and suggested I keep this mod separate on that basis. So: same underlying symbol hooked, different mechanism, different scope, and confirmed as such by the other mod's author rather than just my own read of it. I'll add a compatibility note to both READMEs noting both mods hook |
This mod restores legacy Control Panel applets in Windows 11 by bypassing the modern Settings app redirection. It requires ExplorerPatcher to function properly.
Changelog
If this pull request updates an existing mod, describe the changes below:
Mod authorship
If this pull request introduces a new mod, please complete the section below.
This mod was created by:
Please select the options that best apply. Your selection does not affect the acceptance criteria, but it helps reviewers understand the context of the code and provide relevant feedback.