diff --git a/CHANGELOG.md b/CHANGELOG.md index 12c9ed9..18549ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ This document includes the same release notes as in the [Releases](https://github.com/valinet/ExplorerPatcher/releases) section on GitHub. +## 22000.194.0.21 + +Tested on build: 22000.194. + +* Implemented configuration GUI; to access it, right click the Start button (or press `Win`+`X`) and choose "Properties" + ## 22000.194.0.20 Tested on build: 22000.194. diff --git a/ExplorerPatcher/ExplorerPatcher.rc b/ExplorerPatcher/ExplorerPatcher.rc index 9ef5b10..444cb38 100644 --- a/ExplorerPatcher/ExplorerPatcher.rc +++ b/ExplorerPatcher/ExplorerPatcher.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 22000,194,0,20 - PRODUCTVERSION 22000,194,0,20 + FILEVERSION 22000,194,0,21 + PRODUCTVERSION 22000,194,0,21 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -69,12 +69,12 @@ BEGIN BEGIN VALUE "CompanyName", "VALINET Solutions SRL" VALUE "FileDescription", "ExplorerPatcher" - VALUE "FileVersion", "22000.194.0.20" + VALUE "FileVersion", "22000.194.0.21" VALUE "InternalName", "ExplorerPatcher.dll" VALUE "LegalCopyright", "Copyright (C) 2006-2021 VALINET Solutions SRL. All rights reserved." VALUE "OriginalFilename", "ExplorerPatcher.dll" VALUE "ProductName", "ExplorerPatcher" - VALUE "ProductVersion", "22000.194.0.20" + VALUE "ProductVersion", "22000.194.0.21" END END BLOCK "VarFileInfo" @@ -83,6 +83,31 @@ BEGIN END END + +///////////////////////////////////////////////////////////////////////////// +// +// RCDATA +// + +IDR_REGISTRY1 RCDATA "settings.reg" + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_PRODUCTNAME "ExplorerPatcher" + IDS_COPYRIGHT "Copyright (C) 2006-2021 VALINET Solutions SRL. All rights reserved." + IDS_VERSION "Version %d.%d.%d.%d" + IDS_PRODUCTTAG "This project aims to bring back a productive working environment\r\non Windows 11. Proudly programmed by Valentin-Gabriel Radu." + IDS_VISITGITHUB "Visit project Github" + IDS_VISITWEBSITE "Visit web site" + IDS_LICENSEINFO "E-mail author" +END + #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/ExplorerPatcher/ExplorerPatcher.vcxproj b/ExplorerPatcher/ExplorerPatcher.vcxproj index fd2dc10..4885bbc 100644 --- a/ExplorerPatcher/ExplorerPatcher.vcxproj +++ b/ExplorerPatcher/ExplorerPatcher.vcxproj @@ -195,6 +195,9 @@ + + + @@ -205,6 +208,9 @@ + + + @@ -217,6 +223,9 @@ + + + diff --git a/ExplorerPatcher/ExplorerPatcher.vcxproj.filters b/ExplorerPatcher/ExplorerPatcher.vcxproj.filters index e04e158..5c9fca2 100644 --- a/ExplorerPatcher/ExplorerPatcher.vcxproj.filters +++ b/ExplorerPatcher/ExplorerPatcher.vcxproj.filters @@ -45,6 +45,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + @@ -76,5 +85,17 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + + \ No newline at end of file diff --git a/ExplorerPatcher/GUI.c b/ExplorerPatcher/GUI.c new file mode 100644 index 0000000..4048d53 --- /dev/null +++ b/ExplorerPatcher/GUI.c @@ -0,0 +1,938 @@ +#include "GUI.h" + +static HRESULT GUI_AboutProc( + HWND hwnd, + UINT uNotification, + WPARAM wParam, + LPARAM lParam, + LONG_PTR lpRefData +) +{ + switch (uNotification) + { + case TDN_BUTTON_CLICKED: + { + if (wParam == IDOK || wParam == IDCANCEL) + { + return S_OK; + } + else if (wParam == IDS_VISITGITHUB) + { + ShellExecuteA( + NULL, + "open", + "https://github.com/valinet/ExplorerPatcher", + NULL, + NULL, + SW_SHOWNORMAL + ); + } + else if (wParam == IDS_VISITWEBSITE) + { + ShellExecuteA( + NULL, + "open", + "https://www.valinet.ro", + NULL, + NULL, + SW_SHOWNORMAL + ); + } + else if (wParam == IDS_LICENSEINFO) + { + ShellExecuteA( + NULL, + "open", + "mailto:valentingabrielradu@gmail.com", + NULL, + NULL, + SW_SHOWNORMAL + ); + } + } + } + return S_OK; +} + +static BOOL GUI_Build(HDC hDC, HWND hwnd, POINT pt) +{ + GUI* _this; + LONG_PTR ptr = GetWindowLongPtr(hwnd, GWLP_USERDATA); + _this = (int*)(ptr); + double dx = _this->dpi.x / 96.0, dy = _this->dpi.y / 96.0; + _this->padding.left = GUI_PADDING_LEFT * dx; + _this->padding.right = GUI_PADDING_RIGHT * dx; + _this->padding.top = GUI_PADDING_TOP * dy; + _this->padding.bottom = GUI_PADDING_BOTTOM * dy; + + RECT rc; + GetClientRect(hwnd, &rc); + HRSRC hRscr = FindResourceA( + hModule, + MAKEINTRESOURCEA(IDR_REGISTRY1), + RT_RCDATA + ); + if (!hRscr) + { + return FALSE; + } + HGLOBAL hgRscr = LoadResource( + hModule, + hRscr + ); + if (!hgRscr) + { + return FALSE; + } + PVOID pRscr = LockResource(hgRscr); + DWORD cbRscr = SizeofResource( + hModule, + hRscr + ); + + LOGFONT logFont; + memset(&logFont, 0, sizeof(logFont)); + logFont.lfHeight = GUI_CAPTION_FONT_SIZE * dy; + logFont.lfWeight = FW_BOLD; + wcscpy_s(logFont.lfFaceName, 32, L"Segoe UI"); + HFONT hFontCaption = CreateFontIndirect(&logFont); + logFont.lfHeight = GUI_TITLE_FONT_SIZE * dy; + HFONT hFontTitle = CreateFontIndirect(&logFont); + logFont.lfWeight = FW_REGULAR; + logFont.lfUnderline = 1; + HFONT hFontUnderline = CreateFontIndirect(&logFont); + logFont.lfWeight = FW_REGULAR; + logFont.lfUnderline = 0; + HFONT hFontRegular = CreateFontIndirect(&logFont); + HFONT hOldFont = NULL; + + DTTOPTS DttOpts; + DttOpts.dwSize = sizeof(DTTOPTS); + DttOpts.dwFlags = DTT_COMPOSITED | DTT_TEXTCOLOR; + DttOpts.crText = GUI_TEXTCOLOR; + DWORD dwTextFlags = DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS; + RECT rcText; + DWORD dwCL = 0; + + HDC hdcPaint = NULL; + BP_PAINTPARAMS params = { sizeof(BP_PAINTPARAMS) }; + params.dwFlags = BPPF_ERASE; + HPAINTBUFFER hBufferedPaint = BeginBufferedPaint(hDC, &rc, BPBF_TOPDOWNDIB, ¶ms, &hdcPaint); + + if (!hDC || (hDC && hdcPaint)) + { + FILE* f = fmemopen(pRscr, cbRscr, "r"); + char* line = malloc(MAX_LINE_LENGTH * sizeof(char)); + wchar_t* text = malloc(MAX_LINE_LENGTH * sizeof(wchar_t)); + wchar_t* name = malloc(MAX_LINE_LENGTH * sizeof(wchar_t)); + wchar_t* section = malloc(MAX_LINE_LENGTH * sizeof(wchar_t)); + size_t bufsiz = 0, numChRd = 0; + while ((numChRd = getline(&line, &bufsiz, f)) != -1) + { + if (strcmp(line, "Windows Registry Editor Version 5.00\r\n") && strcmp(line, "\r\n")) + { + if (!strncmp(line, "[", 1)) + { + ZeroMemory(section, MAX_LINE_LENGTH * sizeof(wchar_t)); + MultiByteToWideChar( + CP_UTF8, + MB_PRECOMPOSED, + line[1] == '-' ? line + 2 : line + 1, + numChRd - (line[1] == '-' ? 5 : 4), + section, + MAX_LINE_LENGTH + ); + //wprintf(L"%s\n", section); + } + + DWORD dwLineHeight = GUI_LINE_HEIGHT; + + rcText.left = _this->padding.left; + rcText.top = _this->padding.top + dwCL; + rcText.right = (rc.right - rc.left) - _this->padding.right; + rcText.bottom = dwCL + dwLineHeight * dy - _this->padding.bottom; + + if (!strncmp(line, ";T ", 3)) + { + hOldFont = SelectObject(hDC ? hdcPaint : GetDC(hwnd), hFontTitle); + } + else if (!strncmp(line, ";M ", 3)) + { + hOldFont = SelectObject(hDC ? hdcPaint : GetDC(hwnd), hFontCaption); + } + else if (!strncmp(line, ";u ", 3)) + { + hOldFont = SelectObject(hDC ? hdcPaint : GetDC(hwnd), hFontUnderline); + } + else + { + hOldFont = SelectObject(hDC ? hdcPaint : GetDC(hwnd), hFontRegular); + } + + if (!strncmp(line, ";T ", 3) || !strncmp(line, ";t ", 3) || !strncmp(line, ";u ", 3) || !strncmp(line, ";M ", 3)) + { + ZeroMemory(text, MAX_LINE_LENGTH * sizeof(wchar_t)); + MultiByteToWideChar( + CP_UTF8, + MB_PRECOMPOSED, + line + 3, + numChRd - 3, + text, + MAX_LINE_LENGTH + ); + if (!strncmp(line, ";M ", 3)) + { + rcText.bottom += GUI_CAPTION_LINE_HEIGHT - dwLineHeight; + dwLineHeight = GUI_CAPTION_LINE_HEIGHT; + _this->extent.cyTopHeight = rcText.bottom; + } + if (hDC) + { + DrawThemeTextEx( + _this->hTheme, + hdcPaint, + hOldFont ? 0 : 8, + 0, + text, + -1, + dwTextFlags, + &rcText, + &DttOpts + ); + } + else + { + RECT rcTemp; + rcTemp = rcText; + DrawText( + GetDC(hwnd), + text, + -1, + &rcTemp, + DT_CALCRECT + ); + rcTemp.bottom = rcText.bottom; + if (!strncmp(line, ";u ", 3) && PtInRect(&rcTemp, pt)) + { + numChRd = getline(&line, &bufsiz, f); + char* p = strchr(line, '\r'); + if (p) *p = 0; + p = strchr(line, '\n'); + if (p) *p = 0; + if (!strncmp(line + 1, "restart", 7)) + { + PROCESSENTRY32 pe32 = { 0 }; + pe32.dwSize = sizeof(PROCESSENTRY32); + HANDLE hSnapshot = CreateToolhelp32Snapshot( + TH32CS_SNAPPROCESS, + 0 + ); + if (Process32First(hSnapshot, &pe32) == TRUE) + { + do + { + if (!wcscmp(pe32.szExeFile, TEXT("sihost.exe"))) + { + HANDLE hSihost = OpenProcess( + PROCESS_TERMINATE, + FALSE, + pe32.th32ProcessID + ); + TerminateProcess(hSihost, 0); + CloseHandle(hSihost); + return TRUE; + } + } while (Process32Next(hSnapshot, &pe32) == TRUE); + } + CloseHandle(hSnapshot); + } + else if (!strncmp(line + 1, "reset", 5)) + { + wchar_t wszPath[MAX_PATH]; + ZeroMemory( + wszPath, + MAX_PATH * sizeof(wchar_t) + ); + SHGetFolderPathW( + NULL, + SPECIAL_FOLDER, + NULL, + SHGFP_TYPE_CURRENT, + wszPath + ); + wcscat_s( + wszPath, + MAX_PATH, + TEXT(APP_RELATIVE_PATH) + ); + CreateDirectoryW(wszPath, NULL); + wcscat_s( + wszPath, + MAX_PATH, + L"\\settings.reg" + ); + wprintf(L"%s\n", wszPath); + HANDLE hFile = CreateFileW( + wszPath, + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + if (hFile) + { + DWORD dwNumberOfBytesWritten = 0; + if (WriteFile( + hFile, + pRscr, + cbRscr, + &dwNumberOfBytesWritten, + NULL + )) + { + CloseHandle(hFile); + + SHELLEXECUTEINFO ShExecInfo = { 0 }; + ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); + ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; + ShExecInfo.hwnd = NULL; + ShExecInfo.lpVerb = NULL; + ShExecInfo.lpFile = wszPath; + ShExecInfo.lpParameters = L""; + ShExecInfo.lpDirectory = NULL; + ShExecInfo.nShow = SW_SHOW; + ShExecInfo.hInstApp = NULL; + ShellExecuteEx(&ShExecInfo); + WaitForSingleObject(ShExecInfo.hProcess, INFINITE); + DWORD dwExitCode = 0; + GetExitCodeProcess(ShExecInfo.hProcess, &dwExitCode); + if (!dwExitCode) + { + PostMessage(hwnd, WM_CLOSE, 0, 0); + } + CloseHandle(ShExecInfo.hProcess); + DeleteFileW(wszPath); + } + } + } + else if (!strncmp(line + 1, "about", 5)) + { + DWORD dwLeftMost = 0; + DWORD dwSecondLeft = 0; + DWORD dwSecondRight = 0; + DWORD dwRightMost = 0; + + QueryVersionInfo(hModule, VS_VERSION_INFO, &dwLeftMost, &dwSecondLeft, &dwSecondRight, &dwRightMost); + + TCHAR wszIDS_VISITGITHUB[100]; + LoadString(hModule, IDS_VISITGITHUB, wszIDS_VISITGITHUB, 100); + TCHAR wszIDS_VISITWEBSITE[100]; + LoadString(hModule, IDS_VISITWEBSITE, wszIDS_VISITWEBSITE, 100); + TCHAR wszIDS_LICENSEINFO[100]; + LoadString(hModule, IDS_LICENSEINFO, wszIDS_LICENSEINFO, 100); + TCHAR wszIDS_PRODUCTNAME[100]; + LoadString(hModule, IDS_PRODUCTNAME, wszIDS_PRODUCTNAME, 100); + TCHAR wszIDS_VERSION[100]; + LoadString(hModule, IDS_VERSION, wszIDS_VERSION, 100); + TCHAR wszIDS_PRODUCTTAG[406]; + wsprintf(wszIDS_PRODUCTTAG, wszIDS_VERSION, dwLeftMost, dwSecondLeft, dwSecondRight, dwRightMost); + wcscat_s( + wszIDS_PRODUCTTAG, + 406, + L"\r\n" + ); + LoadString(hModule, IDS_COPYRIGHT, wszIDS_PRODUCTTAG + wcslen(wszIDS_PRODUCTTAG), 100); + wcscat_s( + wszIDS_PRODUCTTAG, + 406, + L"\r\n\r\n" + ); + LoadString(hModule, IDS_PRODUCTTAG, wszIDS_PRODUCTTAG + wcslen(wszIDS_PRODUCTTAG), 200); + + TASKDIALOG_BUTTON buttons[3]; + buttons[0].nButtonID = IDS_VISITGITHUB; + buttons[0].pszButtonText = wszIDS_VISITGITHUB; + buttons[1].nButtonID = IDS_VISITWEBSITE; + buttons[1].pszButtonText = wszIDS_VISITWEBSITE; + buttons[2].nButtonID = IDS_LICENSEINFO; + buttons[2].pszButtonText = wszIDS_LICENSEINFO; + + TASKDIALOGCONFIG td; + ZeroMemory(&td, sizeof(TASKDIALOGCONFIG)); + td.cbSize = sizeof(TASKDIALOGCONFIG); + td.hwndParent = hwnd; + td.hInstance = hModule; + td.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_SIZE_TO_CONTENT | TDF_USE_COMMAND_LINKS; + td.dwCommonButtons = TDCBF_OK_BUTTON; + td.pszWindowTitle = L" "; + td.pszMainIcon = TD_INFORMATION_ICON; + td.pszMainInstruction = wszIDS_PRODUCTNAME; + td.pszContent = wszIDS_PRODUCTTAG; + td.cButtons = sizeof(buttons) / sizeof(buttons[0]); + td.pButtons = buttons; + td.nDefaultButton = IDOK; + td.cRadioButtons = 0; + td.pRadioButtons = NULL; + td.cxWidth = 0; + td.pszFooter = L""; + td.pfCallback = GUI_AboutProc; + td.lpCallbackData = 0; + int ret; + HRESULT hr = TaskDialogIndirect( + &td, + &ret, + NULL, + NULL + ); + } + } + } + dwCL += dwLineHeight * dy; + } + else if (!strncmp(line, ";l ", 3) || !strncmp(line, ";c ", 3) || !strncmp(line, ";b ", 3) || !strncmp(line, ";i ", 3) || !strncmp(line, ";d ", 3) || !strncmp(line, ";v ", 3)) + { + ZeroMemory(text, MAX_LINE_LENGTH * sizeof(wchar_t)); + text[0] = L'\u2795'; + text[1] = L' '; + text[2] = L' '; + MultiByteToWideChar( + CP_UTF8, + MB_PRECOMPOSED, + !strncmp(line, ";c ", 3) ? strchr(line + 3, ' ') + 1 : line + 3, + numChRd - 3, + text + 3, + MAX_LINE_LENGTH + ); + wchar_t* x = wcschr(text, L'\n'); + if (x) *x = 0; + x = wcschr(text, L'\r'); + if (x) *x = 0; + if (!strncmp(line, ";c ", 3) || !strncmp(line, ";b ", 3) || !strncmp(line, ";i ", 3) || !strncmp(line, ";d ", 3) || !strncmp(line, ";v ", 3)) + { + HMENU hMenu = NULL; + BOOL bChoice = !strncmp(line, ";c ", 3); + BOOL bInvert = !strncmp(line, ";i ", 3); + BOOL bJustCheck = !strncmp(line, ";d ", 3); + BOOL bBool = !strncmp(line, ";b ", 3); + BOOL bValue = !strncmp(line, ";v ", 3); + DWORD numChoices = 0; + if (bChoice) + { + char* p = strchr(line + 3, ' '); + if (p) *p = 0; + numChoices = atoi(line + 3); + hMenu = CreatePopupMenu(); + for (unsigned int i = 0; i < numChoices; ++i) + { + char* l = malloc(MAX_LINE_LENGTH * sizeof(char)); + numChRd = getline(&l, &bufsiz, f); + if (strncmp(l, ";x ", 3)) + { + i--; + continue; + } + char* p = strchr(l + 3, ' '); + if (p) *p = 0; + char* ln = p + 1; + p = strchr(p + 1, '\r'); + if (p) *p = 0; + p = strchr(p + 1, '\n'); + if (p) *p = 0; + + MENUITEMINFOA menuInfo; + ZeroMemory(&menuInfo, sizeof(MENUITEMINFOA)); + menuInfo.cbSize = sizeof(MENUITEMINFOA); + menuInfo.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA | MIIM_STATE; + menuInfo.wID = atoi(l + 3) + 1; + menuInfo.dwItemData = l; + menuInfo.fType = MFT_STRING; + menuInfo.dwTypeData = ln; + menuInfo.cch = strlen(ln); + InsertMenuItemA( + hMenu, + i, + TRUE, + &menuInfo + ); + } + } + numChRd = getline(&line, &bufsiz, f); + ZeroMemory(name, MAX_LINE_LENGTH * sizeof(wchar_t)); + MultiByteToWideChar( + CP_UTF8, + MB_PRECOMPOSED, + line[0] == '"' ? line + 1 : line, + numChRd, + name, + MAX_LINE_LENGTH + ); + wchar_t* d = wcschr(name, L'='); + if (d) *d = 0; + wchar_t* p = wcschr(name, L'"'); + if (p) *p = 0; + HKEY hKey; + DWORD dwDisposition; + DWORD dwSize = sizeof(DWORD); + DWORD value = FALSE; + + //wprintf(L"%s %s %s\n", section, name, d + 1); + if (!wcsncmp(d + 1, L"dword:", 6)) + { + wchar_t* x = wcschr(d + 1, L':'); + x++; + value = _wtoi(x); + } + + if (!bJustCheck) + { + RegCreateKeyExW( + HKEY_CURRENT_USER, + wcschr(section, L'\\') + 1, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | (hDC ? 0 : KEY_WRITE), + NULL, + &hKey, + &dwDisposition + ); + RegQueryValueExW( + hKey, + name, + 0, + NULL, + &value, + &dwSize + ); + if (hDC && bInvert) + { + value = !value; + } + } + else + { + RegOpenKeyExW( + HKEY_CURRENT_USER, + wcschr(section, L'\\') + 1, + REG_OPTION_NON_VOLATILE, + KEY_READ | (hDC ? 0 : KEY_WRITE), + &hKey + ); + value = hKey; + } + if (bInvert || bBool || bJustCheck) + { + if (value) + { + text[0] = L'\u2714'; + } + else + { + text[0] = L'\u274C'; + } + text[1] = L' '; + text[2] = L' '; + } + else if (bValue) + { + wcscat_s( + text, + MAX_LINE_LENGTH, + L" : " + ); + wchar_t buf[100]; + _itow_s(value, buf, 100, 10); + wcscat_s( + text, + MAX_LINE_LENGTH, + buf + ); + } + else if (bChoice) + { + wcscat_s( + text, + MAX_LINE_LENGTH, + L" : " + ); + MENUITEMINFOA menuInfo; + ZeroMemory(&menuInfo, sizeof(MENUITEMINFOA)); + menuInfo.cbSize = sizeof(MENUITEMINFOA); + menuInfo.fMask = MIIM_STRING; + GetMenuItemInfoA(hMenu, value + 1, FALSE, &menuInfo); + char* buf = malloc(sizeof(char) * (menuInfo.cch + 1)); + menuInfo.dwTypeData = buf; + menuInfo.cch += 1; + GetMenuItemInfoA(hMenu, value + 1, FALSE, &menuInfo); + MultiByteToWideChar( + CP_UTF8, + MB_PRECOMPOSED, + buf, + menuInfo.cch, + text + wcslen(text), + MAX_LINE_LENGTH + ); + } + RECT rcTemp; + rcTemp = rcText; + DrawText( + GetDC(hwnd), + text, + -1, + &rcTemp, + DT_CALCRECT + ); + rcTemp.bottom = rcText.bottom; + if (!hDC && PtInRect(&rcTemp, pt)) + { + if (bJustCheck) + { + if (hKey) + { + RegCloseKey(hKey); + RegDeleteKeyExW( + HKEY_CURRENT_USER, + wcschr(section, L'\\') + 1, + REG_OPTION_NON_VOLATILE, + 0 + ); + } + else + { + RegCreateKeyExW( + HKEY_CURRENT_USER, + wcschr(section, L'\\') + 1, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_WRITE, + NULL, + &hKey, + &dwDisposition + ); + if (d[1] == '"') + { + wchar_t* p = wcschr(d + 2, L'"'); + if (p) *p = 0; + RegSetValueExW( + hKey, + !wcsncmp(name, L"@", 1) ? NULL : name, + 0, + REG_SZ, + d + 2, + wcslen(d + 2) * sizeof(wchar_t) + ); + } + } + } + else + { + if (bChoice) + { + POINT p; + p.x = rcText.left; + p.y = rcText.bottom; + ClientToScreen( + hwnd, + &p + ); + DWORD val = TrackPopupMenu( + hMenu, + TPM_RETURNCMD | TPM_RIGHTBUTTON, + p.x, + p.y, + 0, + hwnd, + 0 + ); + if (val > 0) value = val - 1; + } + else if (bValue) + { + + } + else + { + value = !value; + } + RegSetValueExW( + hKey, + name, + 0, + REG_DWORD, + &value, + sizeof(DWORD) + ); + } + InvalidateRect(hwnd, NULL, FALSE); + } + RegCloseKey(hKey); + if (bChoice) + { + for (unsigned int i = 0; i < numChoices; ++i) + { + MENUITEMINFOA menuInfo; + ZeroMemory(&menuInfo, sizeof(MENUITEMINFOA)); + menuInfo.cbSize = sizeof(MENUITEMINFOA); + menuInfo.fMask = MIIM_DATA; + GetMenuItemInfoA(hMenu, i, TRUE, &menuInfo); + if (menuInfo.dwItemData) + { + free(menuInfo.dwItemData); + } + } + DestroyMenu(hMenu); + } + } + if (!hDC && !strncmp(line, ";l ", 3)) + { + RECT rcTemp; + rcTemp = rcText; + DrawText( + GetDC(hwnd), + text, + -1, + &rcTemp, + DT_CALCRECT + ); + rcTemp.bottom = rcText.bottom; + //printf("%d %d %d %d %d %d %d %d\n", rcText.left, rcText.top, rcText.right, rcText.bottom, rcTemp.left, rcTemp.top, rcTemp.right, rcTemp.bottom); + if (PtInRect(&rcTemp, pt)) + { + numChRd = getline(&line, &bufsiz, f); + char* p = strchr(line, '\r'); + if (p) *p = 0; + p = strchr(line, '\n'); + if (p) *p = 0; + ShellExecuteA( + NULL, + "open", + line + 1, + NULL, + NULL, + SW_SHOWNORMAL + ); + } + } + if (hDC) + { + DrawThemeTextEx( + _this->hTheme, + hdcPaint, + 0, + 0, + text, + -1, + dwTextFlags, + &rcText, + &DttOpts + ); + } + dwCL += dwLineHeight * dy; + } + } + } + fclose(f); + + if (hDC) + { + SelectObject(hdcPaint, hOldFont); + DeleteObject(hFontRegular); + DeleteObject(hFontTitle); + DeleteObject(hFontUnderline); + DeleteObject(hFontCaption); + } + EndBufferedPaint(hBufferedPaint, TRUE); + } + return TRUE; +} + +static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + GUI* _this; + if (uMsg == WM_CREATE) + { + CREATESTRUCT* pCreate = (CREATESTRUCT*)(lParam); + _this = (int*)(pCreate->lpCreateParams); + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)_this); + UINT dpiX, dpiY, dpiXP, dpiYP; + POINT ptCursor, ptZero; + ptZero.x = 0; + ptZero.y = 0; + GetCursorPos(&ptCursor); + HMONITOR hMonitor = MonitorFromPoint(ptCursor, MONITOR_DEFAULTTOPRIMARY); + HMONITOR hPrimaryMonitor = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY); + HRESULT hr = GetDpiForMonitor( + hMonitor, + MDT_DEFAULT, + &dpiX, + &dpiY + ); + hr = GetDpiForMonitor( + hPrimaryMonitor, + MDT_DEFAULT, + &dpiXP, + &dpiYP + ); + MONITORINFO mi; + mi.cbSize = sizeof(MONITORINFO); + GetMonitorInfo(hMonitor, &mi); + double dx = dpiX / 96.0, dy = dpiY / 96.0, dxp = dpiXP / 96.0, dyp = dpiYP / 96.0; + _this->dpi.x = dpiX; + _this->dpi.y = dpiY; + SetWindowPos( + hWnd, + hWnd, + mi.rcWork.left + ((mi.rcWork.right - mi.rcWork.left) / 2 - (_this->size.cx * dx) / 2), + mi.rcWork.top + ((mi.rcWork.bottom - mi.rcWork.top) / 2 - (_this->size.cy * dy) / 2), + _this->size.cx * dxp, + _this->size.cy * dyp, + SWP_NOZORDER | SWP_NOACTIVATE + ); + } + else + { + LONG_PTR ptr = GetWindowLongPtr(hWnd, GWLP_USERDATA); + _this = (int*)(ptr); + } + if (uMsg == WM_DESTROY) + { + PostQuitMessage(0); + return 0; + } + else if (uMsg == WM_NCHITTEST) + { + POINT pt; + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + ScreenToClient(hWnd, &pt); + if (pt.y < _this->extent.cyTopHeight) + { + return HTCAPTION; + } + } + else if (uMsg == WM_LBUTTONDOWN) + { + POINT pt; + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + GUI_Build(0, hWnd, pt); + } + else if (uMsg == WM_DPICHANGED) + { + _this->dpi.x = LOWORD(wParam); + _this->dpi.y = HIWORD(wParam); + RECT* rc = lParam; + SetWindowPos( + hWnd, + hWnd, + rc->left, + rc->top, + rc->right - rc->left, + rc->bottom - rc->top, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS + ); + return 0; + } + else if (uMsg == WM_PAINT) + { + MARGINS marGlassInset = { -1, -1, -1, -1 }; // -1 means the whole window + DwmExtendFrameIntoClientArea(hWnd, &marGlassInset); + + PAINTSTRUCT ps; + HDC hDC = BeginPaint(hWnd, &ps); + + RECT rc; + GetClientRect(hWnd, &rc); + + POINT pt; + pt.x = 0; + pt.y = 0; + GUI_Build(hDC, hWnd, pt); + + EndPaint(hWnd, &ps); + return 0; + } + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +__declspec(dllexport) int ZZGUI(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow) +{ + /* + FILE* conout; + AllocConsole(); + freopen_s( + &conout, + "CONOUT$", + "w", + stdout + ); + */ + + printf("Started \"GUI\" thread.\n"); + + SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + + GUI _this; + _this.hBackgroundBrush = (HBRUSH)GetStockObject(BLACK_BRUSH); + _this.location.x = GUI_POSITION_X; + _this.location.y = GUI_POSITION_Y; + _this.size.cx = GUI_POSITION_WIDTH; + _this.size.cy = GUI_POSITION_HEIGHT; + _this.padding.left = GUI_PADDING_LEFT; + _this.padding.right = GUI_PADDING_RIGHT; + _this.padding.top = GUI_PADDING_TOP; + _this.padding.bottom = GUI_PADDING_BOTTOM; + _this.hTheme = OpenThemeData(NULL, TEXT(GUI_WINDOWSWITCHER_THEME_CLASS)); + + WNDCLASS wc = { 0 }; + ZeroMemory(&wc, sizeof(WNDCLASSW)); + wc.style = CS_DBLCLKS; + wc.lpfnWndProc = WindowProc; + wc.hbrBackground = _this.hBackgroundBrush; + wc.hInstance = hModule; + wc.lpszClassName = L"ExplorerPatcherGUI"; + wc.hCursor = LoadCursorW(NULL, IDC_ARROW); + RegisterClassW(&wc); + + TCHAR title[260]; + LoadStringW(GetModuleHandleW(L"ExplorerFrame.dll"), 726, title, 260); + + HWND hwnd = CreateWindowEx( + NULL, + L"ExplorerPatcherGUI", + title, + WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX, + 0, + 0, + 0, + 0, + NULL, NULL, hModule, &_this + ); + if (!hwnd) + { + return 1; + } + BOOL value = 1; + DwmSetWindowAttribute(hwnd, 1029, &value, sizeof(BOOL)); + WTA_OPTIONS ops; + ops.dwFlags = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON; + ops.dwMask = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON; + SetWindowThemeAttribute( + hwnd, + WTA_NONCLIENT, + &ops, + sizeof(WTA_OPTIONS) + ); + ShowWindow(hwnd, SW_SHOW); + + MSG msg = { 0 }; + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + printf("Ended \"GUI\" thread.\n"); +} \ No newline at end of file diff --git a/ExplorerPatcher/GUI.h b/ExplorerPatcher/GUI.h new file mode 100644 index 0000000..f62d605 --- /dev/null +++ b/ExplorerPatcher/GUI.h @@ -0,0 +1,62 @@ +#ifndef _H_GUI_H_ +#define _H_GUI_H_ +#include +#pragma comment(lib, "Version.lib") +#include +#include +#include +#pragma comment(lib, "Shcore.lib") +#include +#include +#include +#pragma comment(lib, "UxTheme.lib") +#include +#pragma comment(lib, "Dwmapi.lib") +#include "resource.h" +#include "getline.h" +#include "fmemopen.h" +#include "utility.h" + +#define MAX_LINE_LENGTH 2000 +extern HMODULE hModule; + +#define GUI_POSITION_X CW_USEDEFAULT +#define GUI_POSITION_Y CW_USEDEFAULT +#define GUI_POSITION_WIDTH 467 +#define GUI_POSITION_HEIGHT 790 +#define GUI_WINDOWSWITCHER_THEME_CLASS "ControlPanelStyle" +#define GUI_CAPTION_FONT_SIZE -22 +#define GUI_TITLE_FONT_SIZE -12 +#define GUI_LINE_HEIGHT 30 +#define GUI_CAPTION_LINE_HEIGHT 42 +#define GUI_TEXTCOLOR RGB(0, 0, 0) +#define GUI_PADDING 5 +#define GUI_PADDING_LEFT GUI_PADDING * 3 +#define GUI_PADDING_RIGHT GUI_PADDING * 3 +#define GUI_PADDING_TOP GUI_PADDING +#define GUI_PADDING_BOTTOM GUI_PADDING +typedef struct _GUI +{ + POINT location; + SIZE size; + RECT padding; + HBRUSH hBackgroundBrush; + HTHEME hTheme; + POINT dpi; + MARGINS extent; +} GUI; + +static HRESULT GUI_AboutProc( + HWND hwnd, + UINT uNotification, + WPARAM wParam, + LPARAM lParam, + LONG_PTR lpRefData +); + +static BOOL GUI_Build(HDC hDC, HWND hWnd); + +static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +__declspec(dllexport) int ZZGUI(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow); +#endif diff --git a/ExplorerPatcher/dllmain.c b/ExplorerPatcher/dllmain.c index 0e93fa7..a56686b 100644 --- a/ExplorerPatcher/dllmain.c +++ b/ExplorerPatcher/dllmain.c @@ -27,6 +27,7 @@ #include "SettingsMonitor.h" #include "HideExplorerSearchBar.h" #include "StartMenu.h" +#include "GUI.h" #define SB_MICA_EFFECT_SUBCLASS_OFFSET 0x5C70 #define SB_INIT1 0x26070 @@ -245,6 +246,32 @@ DWORD ShowLauncherTipContextMenu( { goto finalize; } + + TCHAR buffer[260]; + LoadStringW(GetModuleHandleW(L"ExplorerFrame.dll"), 50222, buffer + 1, 260); + buffer[0] = L'&'; + wchar_t* p = wcschr(buffer, L'('); + if (p) + { + p--; + *p = 0; + } + + MENUITEMINFOW menuInfo; + ZeroMemory(&menuInfo, sizeof(MENUITEMINFOW)); + menuInfo.cbSize = sizeof(MENUITEMINFOW); + menuInfo.fMask = MIIM_ID | MIIM_STRING | MIIM_DATA | MIIM_STATE; + menuInfo.wID = 3999; + menuInfo.dwItemData = 0; + menuInfo.fType = MFT_STRING; + menuInfo.dwTypeData = buffer; + menuInfo.cch = wcslen(buffer); + InsertMenuItemW( + *((HMENU*)((char*)params->_this + 0xe8)), + GetMenuItemCount(*((HMENU*)((char*)params->_this + 0xe8))) - 1, + TRUE, + &menuInfo + ); INT64* unknown_array = calloc(4, sizeof(INT64)); ImmersiveContextMenuHelper_ApplyOwnerDrawToMenuFunc( @@ -272,9 +299,19 @@ DWORD ShowLauncherTipContextMenu( ); free(unknown_array); + RemoveMenu( + *((HMENU*)((char*)params->_this + 0xe8)), + 3999, + MF_BYCOMMAND + ); + if (res > 0) { - if (res < 4000) + if (res == 3999) + { + CreateThread(0, 0, ZZGUI, 0, 0, 0); + } + else if (res < 4000) { INT64 info = *(INT64*)((char*)(*(INT64*)((char*)params->_this + 0xa8 - 0x58)) + (INT64)res * 8 - 8); CLauncherTipContextMenu_ExecuteCommandFunc( @@ -1073,7 +1110,7 @@ __declspec(dllexport) DWORD WINAPI main( DWORD bAllocConsole = FALSE; RegQueryValueExW( hKey, - TEXT("bAllocConsole"), + TEXT("AllocConsole"), 0, NULL, &bAllocConsole, @@ -1119,7 +1156,7 @@ __declspec(dllexport) DWORD WINAPI main( RegQueryValueExW( hKey, - TEXT("bHideExplorerSearchBar"), + TEXT("HideExplorerSearchBar"), 0, NULL, &bHideExplorerSearchBar, @@ -1127,7 +1164,7 @@ __declspec(dllexport) DWORD WINAPI main( ); RegQueryValueExW( hKey, - TEXT("bMicaEffectOnTitlebar"), + TEXT("MicaEffectOnTitlebar"), 0, NULL, &bMicaEffectOnTitlebar, @@ -1135,7 +1172,7 @@ __declspec(dllexport) DWORD WINAPI main( ); RegQueryValueExW( hKey, - TEXT("bHideControlCenterButton"), + TEXT("HideControlCenterButton"), 0, NULL, &bHideControlCenterButton, @@ -1143,7 +1180,7 @@ __declspec(dllexport) DWORD WINAPI main( ); RegQueryValueExW( hKey, - TEXT("bSkinMenus"), + TEXT("SkinMenus"), 0, NULL, &bSkinMenus, @@ -1151,7 +1188,7 @@ __declspec(dllexport) DWORD WINAPI main( ); RegQueryValueExW( hKey, - TEXT("bSkinIcons"), + TEXT("SkinIcons"), 0, NULL, &bSkinIcons, @@ -1365,7 +1402,7 @@ __declspec(dllexport) DWORD WINAPI main( DWORD delay = 0; RegQueryValueExW( hKey, - TEXT("vExplorerReadyDelay"), + TEXT("ExplorerReadyDelay"), 0, NULL, &delay, @@ -1401,7 +1438,7 @@ __declspec(dllexport) DWORD WINAPI main( DWORD bEnableArchivePlugin = 0; RegQueryValueExW( hKey, - TEXT("bArchiveMenu"), + TEXT("ArchiveMenu"), 0, NULL, &bEnableArchivePlugin, diff --git a/ExplorerPatcher/fmemopen.c b/ExplorerPatcher/fmemopen.c new file mode 100644 index 0000000..6fbd02b --- /dev/null +++ b/ExplorerPatcher/fmemopen.c @@ -0,0 +1,67 @@ +/*- + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of Novell nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fmemopen.h" + +FILE* +fmemopen(void* buf, size_t size, const char* mode) +{ + char temppath[MAX_PATH + 1]; + char tempnam[MAX_PATH + 1]; + DWORD l; + HANDLE fh; + FILE* fp; + + if (strcmp(mode, "r") != 0 && strcmp(mode, "r+") != 0) + return 0; + l = GetTempPathA(MAX_PATH, temppath); + if (!l || l >= MAX_PATH) + return 0; + if (!GetTempFileNameA(temppath, "solvtmp", 0, tempnam)) + return 0; + fh = CreateFileA(tempnam, DELETE | GENERIC_READ | GENERIC_WRITE, 0, + NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, + NULL); + if (fh == INVALID_HANDLE_VALUE) + return 0; + fp = _fdopen(_open_osfhandle((intptr_t)fh, 0), "w+b"); + if (!fp) + { + CloseHandle(fh); + return 0; + } + if (buf && size && fwrite(buf, size, 1, fp) != 1) + { + fclose(fp); + return 0; + } + rewind(fp); + return fp; +} \ No newline at end of file diff --git a/ExplorerPatcher/fmemopen.h b/ExplorerPatcher/fmemopen.h new file mode 100644 index 0000000..4b6060a --- /dev/null +++ b/ExplorerPatcher/fmemopen.h @@ -0,0 +1,8 @@ +#ifndef _H_FMEMOPEN_H_ +#define _H_FMEMOPEN_H_ +#include +#include +#include +#include +FILE* fmemopen(void* buf, size_t size, const char* mode); +#endif \ No newline at end of file diff --git a/ExplorerPatcher/getline.c b/ExplorerPatcher/getline.c new file mode 100644 index 0000000..658c301 --- /dev/null +++ b/ExplorerPatcher/getline.c @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "getline.h" + +ssize_t +getdelim(char** buf, size_t* bufsiz, int delimiter, FILE* fp) +{ + char* ptr, * eptr; + + + if (*buf == NULL || *bufsiz == 0) { + *bufsiz = BUFSIZ; + if ((*buf = (char*)malloc(*bufsiz)) == NULL) + return -1; + } + + for (ptr = *buf, eptr = *buf + *bufsiz;;) { + int c = fgetc(fp); + if (c == -1) { + if (feof(fp)) { + ssize_t diff = (ssize_t)(ptr - *buf); + if (diff != 0) { + *ptr = '\0'; + return diff; + } + } + return -1; + } + *ptr++ = c; + if (c == delimiter) { + *ptr = '\0'; + return ptr - *buf; + } + if (ptr + 2 >= eptr) { + char* nbuf; + size_t nbufsiz = *bufsiz * 2; + ssize_t d = ptr - *buf; + if ((nbuf = (char*)realloc(*buf, nbufsiz)) == NULL) + return -1; + *buf = nbuf; + *bufsiz = nbufsiz; + eptr = nbuf + nbufsiz; + ptr = nbuf + d; + } + } +} + +ssize_t +getline(char** buf, size_t* bufsiz, FILE* fp) +{ + return getdelim(buf, bufsiz, '\n', fp); +} \ No newline at end of file diff --git a/ExplorerPatcher/getline.h b/ExplorerPatcher/getline.h new file mode 100644 index 0000000..6760bc1 --- /dev/null +++ b/ExplorerPatcher/getline.h @@ -0,0 +1,12 @@ +#ifndef _H_GETLINE_H_ +#define _H_GETLINE_H_ +#include +#include +#include +typedef SSIZE_T ssize_t; + +ssize_t getdelim(char** buf, size_t* bufsiz, int delimiter, FILE* fp); + +ssize_t getline(char** buf, size_t* bufsiz, FILE* fp); + +#endif \ No newline at end of file diff --git a/ExplorerPatcher/resource.h b/ExplorerPatcher/resource.h index 90c388b..b4d0f35 100644 --- a/ExplorerPatcher/resource.h +++ b/ExplorerPatcher/resource.h @@ -2,12 +2,20 @@ // Microsoft Visual C++ generated include file. // Used by ExplorerPatcher.rc // +#define IDR_REGISTRY1 101 +#define IDS_PRODUCTNAME 102 +#define IDS_COPYRIGHT 103 +#define IDS_VERSION 104 +#define IDS_PRODUCTTAG 105 +#define IDS_VISITGITHUB 106 +#define IDS_VISITWEBSITE 107 +#define IDS_LICENSEINFO 108 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 diff --git a/ExplorerPatcher/settings.reg b/ExplorerPatcher/settings.reg new file mode 100644 index 0000000..85a8d4b --- /dev/null +++ b/ExplorerPatcher/settings.reg @@ -0,0 +1,93 @@ +Windows Registry Editor Version 5.00 + +;M Properties + +;T Shell +;l Enable missing system tray icons +;shell:::{05d7b0f4-2121-4eff-bf6b-ed3f69b894d9}\SystemIcons +[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced] +;c 3 Combine taskbar icons on main taskbar * +;x 0 Always combine +;x 1 Combine when taskbar is full +;x 2 Never combine +"TaskbarGlomLevel"=dword:00000002 +;c 3 Combine taskbar icons on other taskbars * +;x 0 Always combine +;x 1 Combine when taskbar is full +;x 2 Never combine +"MMTaskbarGlomLevel"=dword:00000002 +[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ExplorerPatcher] +;b Disable Control Center button * +"HideControlCenterButton"=dword:00000000 +;b Apply immersive style to system tray icon menus * +"SkinMenus"=dword:00000001 +;b Apply Windows 11 style to system tray icons (requires StartIsBack64.dll) * +"SkinIcons"=dword:00000001 + +;T File Explorer +[-HKEY_CURRENT_USER\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32] +;d Disable immersive context menu * +@="" +[-HKEY_CURRENT_USER\Software\Classes\CLSID\{d93ed569-3b3e-4bff-8355-3c44f6a52bb5}\InprocServer32] +;d Disable command bar * +@="" +[-HKEY_CURRENT_USER\Software\Classes\CLSID\{1d64637d-31e9-4b06-9124-e83fb178ac6e}\TreatAs] +;d Disable modern search bar +@="{64bc32b5-4eec-4de7-972d-bd8bd0324537}" +[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ExplorerPatcher] +;b Hide search bar completely * +"HideExplorerSearchBar"=dword:00000000 +;b Mica effect on title bar (requires StartIsBack64.dll) * +"MicaEffectOnTitlebar"=dword:00000000 + +;T Start menu +[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage] +;b Open Start to All apps by default +"MakeAllAppsDefault"=dword:00000000 +[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced] +;c 22 Maximum number of frequent apps to show in Start +;x 0 None +;x 1 1 +;x 2 2 +;x 3 3 +;x 4 4 +;x 5 5 +;x 6 6 (default) +;x 7 7 +;x 8 8 +;x 9 9 +;x 10 10 +;x 11 11 +;x 12 12 +;x 13 13 +;x 14 14 +;x 15 15 +;x 16 16 +;x 17 17 +;x 18 18 +;x 19 19 +;x 20 20 +;x 99999 Unlimited +"Start_MaximumFrequentApps"=dword:00000006 + +;T Advanced +[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ExplorerPatcher] +;b Enable console * +"AllocConsole"=dword:00000000 +;c 7 Supplimentary delay at logon * +;x 0 None (default) +;x 300 300 ms +;x 600 600 ms +;x 1000 1 second +;x 1500 1.5 seconds +;x 2000 2 seconds +;x 3000 3 seconds +"ExplorerReadyDelay"=dword:00000000 + +;t Settings marked with an (*) require restarting the File Explorer process. +;u Restart File Explorer +;restart +;u Restore default settings +;reset +;u About ExplorerPatcher +;about \ No newline at end of file diff --git a/ExplorerPatcher/symbols.c b/ExplorerPatcher/symbols.c index f94ccd7..96ae80e 100644 --- a/ExplorerPatcher/symbols.c +++ b/ExplorerPatcher/symbols.c @@ -125,7 +125,7 @@ DWORD DownloadSymbols(DownloadSymbolsParams* params) ); SHGetFolderPathA( NULL, - CSIDL_APPDATA, + SPECIAL_FOLDER, NULL, SHGFP_TYPE_CURRENT, szSettingsPath @@ -133,7 +133,7 @@ DWORD DownloadSymbols(DownloadSymbolsParams* params) strcat_s( szSettingsPath, MAX_PATH, - SYMBOLS_RELATIVE_PATH + APP_RELATIVE_PATH ); CreateDirectoryA(szSettingsPath, NULL); strcat_s( @@ -440,7 +440,7 @@ DWORD DownloadSymbols(DownloadSymbolsParams* params) } RegSetValueExW( hKey, - TEXT("szOSBuild"), + TEXT("OSBuild"), 0, REG_SZ, szReportedVersion, @@ -683,7 +683,7 @@ BOOL LoadSymbols(symbols_addr* symbols_PTRS) dwSize = MAX_PATH; RegQueryValueExW( hKey, - TEXT("szOSBuild"), + TEXT("OSBuild"), 0, NULL, szStoredVersion, diff --git a/ExplorerPatcher/symbols.h b/ExplorerPatcher/symbols.h index 02c5987..94ce7bc 100644 --- a/ExplorerPatcher/symbols.h +++ b/ExplorerPatcher/symbols.h @@ -9,7 +9,6 @@ #define EXIT_CODE_EXPLORER 1 -#define SYMBOLS_RELATIVE_PATH "\\ExplorerPatcher" #define TWINUI_PCSHELL_SB_NAME "twinui.pcshell" #define TWINUI_PCSHELL_SB_0 "CImmersiveContextMenuOwnerDrawHelper::s_ContextMenuWndProc" #define TWINUI_PCSHELL_SB_1 "CLauncherTipContextMenu::GetMenuItemsAsync" diff --git a/ExplorerPatcher/utility.c b/ExplorerPatcher/utility.c index 66dc894..72a48e6 100644 --- a/ExplorerPatcher/utility.c +++ b/ExplorerPatcher/utility.c @@ -355,4 +355,34 @@ POINT GetDefaultWinXPosition(BOOL bUseRcWork, BOOL* lpBottom, BOOL* lpRight) } } return point; +} + +void QueryVersionInfo(HMODULE hModule, WORD Resource, DWORD* dwLeftMost, DWORD* dwSecondLeft, DWORD* dwSecondRight, DWORD* dwRightMost) +{ + HRSRC hResInfo; + DWORD dwSize; + HGLOBAL hResData; + LPVOID pRes, pResCopy; + UINT uLen; + VS_FIXEDFILEINFO* lpFfi; + + hResInfo = FindResource(hModule, MAKEINTRESOURCE(Resource), RT_VERSION); + dwSize = SizeofResource(hModule, hResInfo); + hResData = LoadResource(hModule, hResInfo); + pRes = LockResource(hResData); + pResCopy = LocalAlloc(LMEM_FIXED, dwSize); + CopyMemory(pResCopy, pRes, dwSize); + FreeResource(hResData); + + VerQueryValue(pResCopy, TEXT("\\"), (LPVOID*)&lpFfi, &uLen); + + DWORD dwFileVersionMS = lpFfi->dwFileVersionMS; + DWORD dwFileVersionLS = lpFfi->dwFileVersionLS; + + *dwLeftMost = HIWORD(dwFileVersionMS); + *dwSecondLeft = LOWORD(dwFileVersionMS); + *dwSecondRight = HIWORD(dwFileVersionLS); + *dwRightMost = LOWORD(dwFileVersionLS); + + LocalFree(pResCopy); } \ No newline at end of file diff --git a/ExplorerPatcher/utility.h b/ExplorerPatcher/utility.h index 89e4037..fea4f3b 100644 --- a/ExplorerPatcher/utility.h +++ b/ExplorerPatcher/utility.h @@ -9,6 +9,8 @@ #define APPID L"Microsoft.Windows.Explorer" #define REGPATH "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ExplorerPatcher" +#define SPECIAL_FOLDER CSIDL_APPDATA +#define APP_RELATIVE_PATH "\\ExplorerPatcher" #pragma region "Weird stuff" INT64 nimpl4_1(INT64 a1, DWORD* a2); @@ -43,4 +45,6 @@ __declspec(dllexport) CALLBACK ZZLaunchExplorer(HWND hWnd, HINSTANCE hInstance, __declspec(dllexport) CALLBACK ZZLaunchExplorerDelayed(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow); POINT GetDefaultWinXPosition(BOOL bUseRcWork, BOOL* lpBottom, BOOL* lpRight); + +void QueryVersionInfo(HMODULE hModule, WORD Resource, DWORD*, DWORD*, DWORD*, DWORD*); #endif \ No newline at end of file diff --git a/README.md b/README.md index 7666e56..63d86bc 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,11 @@ This project aims to bring back a productive working environment on Windows 11.
About ExplorerPatcher and StartIsBack The well-known [StartIsBack](https://www.startisback.com/) application recently introduced support for Windows 11. Currently, regarding Windows 11 functionality, it offers the same features as this patcher, plus all the functionalities from the older releases of the software; thus the differences between the two at the moment, besides their internal implementation (probably) resort in the cost, licensing, support and development model: StartIsBack is a paid app, proprietary, closed source and comes with support, while ExplorerPatcher is free ([gratis and libre - as in free beer and free speech](https://en.wikipedia.org/wiki/Gratis_versus_libre)), open source and is provided as-is, with support offered in a best-effort attempt. - ExplorerPatcher is offered more like a tool for people to study the source code and the techniques used, to learn and adapt it in order and to enable people to build each on top of the work of the others. The aim is to benefit both the community and its users. You are encouraged to take a look at the source and adapt it to your needs. While the source and the application in its current form will always be available here, I cannot make any guarantes over how long it will work in newer Windows 11 builds. Thus, these things being considered, if you would like, you can check out the beta test for StartIsBack [here](http://startisback.com/tbd/) and report any issues and make suggestions to its developer. It will probably mature in a release that will be better supported from a consumer point of view than ExplorerPatcher.
+ + Screenshots: [<1>](https://gist.githubusercontent.com/valinet/d0f72ff09773702584e77c46065b95e0/raw/94036ed3e38218b87744a29ae5c40b06be637daf/ep_img0.png) [<2>](https://user-images.githubusercontent.com/6503598/131937638-d513ca72-ead7-459b-a8ce-619fb302b7da.png) ## dxgi.dll - the patcher @@ -34,7 +35,25 @@ Also, if you place the `StartIsBack64.dll` file from StartIsBack(TBD) Preview 2 After you have completed the above setup, make sure you have an active Internet connection and restart the Explorer process using Task Manager or by issuing the following command: `taskkill /f /im explorer.exe`. Once File Explorer restarts, some necessary files (symbol files) will be downloaded from Microsoft (around 50MB). This should be relatively quick, depending on your Internet connection speed. When this is done, File Explorer will restart again and will be ready for use. Notifications should show up informing you about the progress, and you can also use Task Manager to watch for network activity. This process only happens when a new Windows 11 build is installed on the machine. -Now, the classic taskbar should be enabled. Still, there is some more setup to do, depending on your preferences. +Now, the classic taskbar should be enabled. Still, there is some more setup to do, depending on your preferences. + +## Configuration interface + +To configure the most common options, the application now comes with a configuration user interface. To open it, right click the Start button (or press `Win`+`X`) and choose "Properties". + + + +The icon near an option signifies its current state: + +* ✔️ enabled +* ❌ disabled +* ➕ performs an action that allows you to change that option (usually, the current value is located after the colon in its description) + +The links at the bottom allow you to perform the most frequent actions. + +## Manual configuration + +To learn how to configure all the options manually, read on: ### Enable system tray icons As you have noticed, some system tray icons are missing (for example, the clock, notification center button, network, battery, sound etc). To enable these icons, open the following using Run: @@ -121,37 +140,64 @@ To disable the blue highlight in the context menu and return to the classic gray ### Disable window rounded corners You can try one of my other utilities available [here](https://github.com/valinet/Win11DisableRoundedCorners). -## Configuration -Now that you have set up the basic stuff, you can choose to enable additional settings to enhance the experience even more. For this, edit the file `%appdata%\ExplorerPatcher\settings.ini` and add the following section to it (change to `0` the setting that you do not want to enable): +### Patcher settings +Now that you have set up the basic stuff, you can choose to enable additional settings to enhance the experience even more. For this, customize the following commands by changing the number acording to your needs: -``` -[General] -HideExplorerSearchBar=1 -HideControlCenterButton=1 -MicaEffectOnTitlebar=1 -SkinMenus=1 -SkinIcons=1 -AllocConsole=1 -``` +* `HideExplorerSearchBar` completely removes the search box in File Explorer (default = 0) -* `HideExplorerSearchBar` completely removes the search box in File Explorer -* `HideControlCenterButton` disables the Control Center button and its associated shortcut key (`Win`+`A`) -* `MicaEffectOnTitlebar` enables Mica effect on File Explorer windows (requires `StartIsBack64.dll`) -* `SkinMenus` applies the immersive skin to "Safe to Remove Hardware" and "Bluetooth" pop-up menus -* `SkinIcons` applies Windows 11 icon skins to taskbar buttons (requires `StartIsBack64.dll`) -* `AllocConsole` will display a console window (for debugging purposes) + ``` + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ExplorerPatcher" /f /v "bHideExplorerSearchBar" /t REG_DWORD /d 1 + ``` + +* `HideControlCenterButton` disables the Control Center button and its associated shortcut key (`Win`+`A`) (default = 0) + + ``` + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ExplorerPatcher" /f /v "bHideControlCenterButton" /t REG_DWORD /d 1 + ``` + +* `MicaEffectOnTitlebar` enables Mica effect on File Explorer windows (requires `StartIsBack64.dll`) (default = 0) + + ``` + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ExplorerPatcher" /f /v "bMicaEffectOnTitlebar" /t REG_DWORD /d 1 + ``` + +* `SkinMenus` applies the immersive skin to "Safe to Remove Hardware" and "Bluetooth" pop-up menus (default = 1) + + ``` + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ExplorerPatcher" /f /v "bSkinMenus" /t REG_DWORD /d 1 + ``` + +* `SkinIcons` applies Windows 11 icon skins to taskbar buttons (requires `StartIsBack64.dll`) (default = 1) + + ``` + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ExplorerPatcher" /f /v "bSkinIcons" /t REG_DWORD /d 1 + ``` + +* `AllocConsole` will display a console window (for debugging purposes) (default = 0, for advanced users only) + + ``` + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ExplorerPatcher" /f /v "bAllocConsole" /t REG_DWORD /d 1 + ``` + +* `ExplorerReadyDelay` adds even more delay before the shell is announced that Explorer is ready loading (helps if you experience a delay at logon) - the unit is ms (milliseconds), 1000ms = 1 second (default = 0, for advanced users only) + + ``` + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ExplorerPatcher" /f /v "vExplorerReadyDelay" /t REG_DWORD /d 1000 + ``` Also, if you chose to place the patcher in `C:\Windows\SystemApps\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy` as well, use the following commands to configure Start menu options: * Open Start menu to "All apps" directly (replace with 0 to disable) -``` -reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage /f /v "MakeAllAppsDefault" /t REG_DWORD /d 1 -``` -* Show only 4 most recent apps (change the number to customize) -``` -reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced /f /v "Start_MaximumFrequentApps" /t REG_DWORD /d 4 -``` + ``` + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StartPage /f /v "MakeAllAppsDefault" /t REG_DWORD /d 1 + ``` + +* Show only 4 most recent apps (change the number to customize) + + ``` + reg.exe add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced /f /v "Start_MaximumFrequentApps" /t REG_DWORD /d 4 + ``` ## More configuration Even more registry configuration settings are described in the following document, make sure to take a look on it [here](https://github.com/valinet/ExplorerPatcher/issues/9).