Compare commits

..
6 Commits
Author SHA1 Message Date
ge0rdi 8713a69200 Sign with SignPath
Fixes #1732
2026-07-15 14:25:37 +02:00
ge0rdi b264f96525 Split build steps into binaries, installers, archives 2026-07-15 14:25:37 +02:00
ge0rdi 07ead0baf8 Utility: Fix clash with windows API 2026-07-15 14:25:36 +02:00
ge0rdi 566bb81c7e Fix "Explore" getting stuck after Windows 11 update 2026-07-15 14:14:10 +02:00
ge0rdi 4fd5545485 Fix "Open file location" getting stuck after Windows 11 update
We will run InvokeCommand API on separate STA thread and pump messages while waiting for them to finish.

Fixes #2303
Fixes #2321
Fixes #2375
2026-07-15 14:14:10 +02:00
ge0rdiandGitHub 86e8a24b16 [ExplorerPatcher] Improved EP taskbar detection (#2493)
EP changed their `ep_taskbar*.dll` naming scheme.
We will look for module whose name starts with `ep_taskbar` which
should be compatible with both old and new naming.

Fixes #2474
2026-07-15 14:12:25 +02:00
6 changed files with 163 additions and 26 deletions
+70 -18
View File
@@ -60,6 +60,7 @@ jobs:
run: Src\Setup\BuildBinaries.bat run: Src\Setup\BuildBinaries.bat
- name: Upload binaries - name: Upload binaries
if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master' # Only manual master builds
id: upload-binaries id: upload-binaries
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v7
with: with:
@@ -69,14 +70,16 @@ jobs:
!Src/Setup/Output/*.skin !Src/Setup/Output/*.skin
!Src/Setup/Output/*.skin7 !Src/Setup/Output/*.skin7
!Src/Setup/Output/*.zip !Src/Setup/Output/*.zip
retention-days: 1
- name: Sign binaries with SignPath - name: Sign binaries with SignPath
if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master' # Only manual master builds
uses: signpath/github-action-submit-signing-request@v2 uses: signpath/github-action-submit-signing-request@v2
with: with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}' api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: 'b34b60e3-e5bf-4a6e-a13c-dcf641b4362c' organization-id: 'b34b60e3-e5bf-4a6e-a13c-dcf641b4362c'
project-slug: 'Open-Shell-Menu' project-slug: 'Open-Shell-Menu'
signing-policy-slug: 'test-signing' signing-policy-slug: 'release-signing'
artifact-configuration-slug: 'Binaries' artifact-configuration-slug: 'Binaries'
github-artifact-id: '${{ steps.upload-binaries.outputs.artifact-id }}' github-artifact-id: '${{ steps.upload-binaries.outputs.artifact-id }}'
wait-for-completion: true wait-for-completion: true
@@ -89,59 +92,86 @@ jobs:
run: Src\Setup\_BuildEnglish.bat run: Src\Setup\_BuildEnglish.bat
- name: Upload installers - name: Upload installers
if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master' # Only manual master builds
id: upload-installers id: upload-installers
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v7
with: with:
name: MSI name: MSI
path: | path: |
Src/Setup/Temp/*.msi Src/Setup/Temp/*.msi
retention-days: 1
- name: Sign installers with SignPath - name: Sign installers with SignPath
if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master' # Only manual master builds
uses: signpath/github-action-submit-signing-request@v2 uses: signpath/github-action-submit-signing-request@v2
with: with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}' api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: 'b34b60e3-e5bf-4a6e-a13c-dcf641b4362c' organization-id: 'b34b60e3-e5bf-4a6e-a13c-dcf641b4362c'
project-slug: 'Open-Shell-Menu' project-slug: 'Open-Shell-Menu'
signing-policy-slug: 'test-signing' signing-policy-slug: 'release-signing'
artifact-configuration-slug: 'Installers' artifact-configuration-slug: 'Installers'
github-artifact-id: '${{ steps.upload-installers.outputs.artifact-id }}' github-artifact-id: '${{ steps.upload-installers.outputs.artifact-id }}'
wait-for-completion: true wait-for-completion: true
output-artifact-directory: 'Src/Setup/Temp/' output-artifact-directory: 'Src/Setup/Temp/'
- name: Build final - name: Build setup and symbols
shell: cmd shell: cmd
env: env:
CS_VERSION: ${{ steps.versioning.outputs.NEW_VERSION }} CS_VERSION: ${{ steps.versioning.outputs.NEW_VERSION }}
run: Src\Setup\BuildArchives.bat run: Src\Setup\BuildArchives.bat
- name: Upload final - name: Upload symbols
id: upload-final
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v7
with: with:
name: Final
path: | path: |
Src/Setup/Final/ Src/Setup/Final/OpenShellSymbols*.7z
!Src/Setup/Final/OpenShellLoc.zip archive: false
- name: Sign final artifacts with SignPath - name: Upload utility
uses: actions/upload-artifact@v7
with:
path: |
Src/Setup/Final/Utility.exe
archive: false
- name: Upload setup
id: upload-setup
uses: actions/upload-artifact@v7
with:
path: |
Src/Setup/Final/OpenShellSetup*.exe
archive: false
- name: Sign setup with SignPath
if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master' # Only manual master builds
uses: signpath/github-action-submit-signing-request@v2 uses: signpath/github-action-submit-signing-request@v2
with: with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}' api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: 'b34b60e3-e5bf-4a6e-a13c-dcf641b4362c' organization-id: 'b34b60e3-e5bf-4a6e-a13c-dcf641b4362c'
project-slug: 'Open-Shell-Menu' project-slug: 'Open-Shell-Menu'
signing-policy-slug: 'test-signing' signing-policy-slug: 'release-signing'
artifact-configuration-slug: 'Final' github-artifact-id: '${{ steps.upload-setup.outputs.artifact-id }}'
github-artifact-id: '${{ steps.upload-final.outputs.artifact-id }}'
wait-for-completion: true wait-for-completion: true
skip-decompress: true
output-artifact-directory: 'Src/Setup/Final/' output-artifact-directory: 'Src/Setup/Final/'
- name: Upload final (signed) # `overwrite: true` doesn't work with `archive: false`, so we have to delete the original first
# https://github.com/actions/upload-artifact/issues/769
# https://github.com/actions/upload-artifact/issues/785
- name: Delete setup
if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master' # Only manual master builds
uses: geekyeggo/delete-artifact@v6
with:
name: OpenShellSetup*.exe
- name: Upload setup (signed)
if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master' # Only manual master builds
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v7
with: with:
name: Final-signed
path: | path: |
Src/Setup/Final/ Src/Setup/Final/OpenShellSetup*.exe
!Src/Setup/Final/OpenShellLoc.zip archive: false
overwrite: true
release: release:
if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master' # Only manual master builds if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master' # Only manual master builds
@@ -150,7 +180,29 @@ jobs:
permissions: permissions:
contents: write # Elevate permissions ONLY for this job contents: write # Elevate permissions ONLY for this job
steps: steps:
- name: Download artifacts - name: Download setup
uses: actions/download-artifact@v8 uses: actions/download-artifact@v8
with: with:
name: OpenShell pattern: OpenShellSetup*.exe
- name: Download symbols
uses: actions/download-artifact@v8
with:
pattern: OpenShellSymbols*.7z
- name: Download utility
uses: actions/download-artifact@v8
with:
pattern: Utility.exe
- name: Create GitHub Release
uses: softprops/action-gh-release@v3
with:
tag_name: v${{ needs.build.outputs.new_version }}
name: ${{ needs.build.outputs.new_version }}
generate_release_notes: true
prerelease: true
files: |
OpenShellSetup*.exe
OpenShellSymbols_*.7z
Utility.exe
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+3
View File
@@ -23,6 +23,9 @@ You can find the latest stable version here:
[![GitHub All Releases](https://img.shields.io/github/downloads/Open-Shell/Open-Shell-Menu/total?style=for-the-badge&color=4bc2ee&logo=github)](https://github.com/Open-Shell/Open-Shell-Menu/releases/latest) [![GitHub All Releases](https://img.shields.io/github/downloads/Open-Shell/Open-Shell-Menu/total?style=for-the-badge&color=4bc2ee&logo=github)](https://github.com/Open-Shell/Open-Shell-Menu/releases/latest)
> [!NOTE]
> Free code signing provided by [SignPath.io](https://about.signpath.io/), certificate by [SignPath Foundation](https://signpath.org/)
> [!IMPORTANT] > [!IMPORTANT]
> #### Windows for ARM compatibility > #### Windows for ARM compatibility
> Open-Shell is compatible with Windows for ARM since version [4.4.196](https://github.com/Open-Shell/Open-Shell-Menu/releases/tag/v4.4.196). > Open-Shell is compatible with Windows for ARM since version [4.4.196](https://github.com/Open-Shell/Open-Shell-Menu/releases/tag/v4.4.196).
+2 -2
View File
@@ -160,10 +160,10 @@ cd ..
cd Setup cd Setup
copy /B ..\..\build\bin\Release\Utility.exe .\Final > nul copy /B Output\Utility.exe .\Final > nul
if defined APPVEYOR ( if defined APPVEYOR (
appveyor PushArtifact ..\..\build\bin\Release\Utility.exe appveyor PushArtifact Output\Utility.exe
) )
exit /b 0 exit /b 0
+1
View File
@@ -55,6 +55,7 @@ copy /B ..\..\build\bin\Setup\StartMenuHelper32.dll Output > nul
copy /B ..\..\build\bin\Release\Update.exe Output > nul copy /B ..\..\build\bin\Release\Update.exe Output > nul
copy /B ..\..\build\bin\Release\DesktopToasts.dll Output > nul copy /B ..\..\build\bin\Release\DesktopToasts.dll Output > nul
copy /B ..\..\build\bin\Release\SetupHelper.exe Output > nul copy /B ..\..\build\bin\Release\SetupHelper.exe Output > nul
copy /B ..\..\build\bin\Release\Utility.exe Output > nul
copy /B ..\..\build\bin\SetupARM64\ClassicExplorer64.dll Output\ARM64 > nul copy /B ..\..\build\bin\SetupARM64\ClassicExplorer64.dll Output\ARM64 > nul
copy /B ..\..\build\bin\SetupARM64\ClassicIEDLL_64.dll Output\ARM64 > nul copy /B ..\..\build\bin\SetupARM64\ClassicIEDLL_64.dll Output\ARM64 > nul
+56 -2
View File
@@ -24,6 +24,60 @@
#include <propvarutil.h> #include <propvarutil.h>
#include <algorithm> #include <algorithm>
#include <propkey.h> #include <propkey.h>
#include <thread>
// Execute function on a separate STA thread while pumping messages on caller thread.
template <typename TFunc>
static auto ExecuteOnSTAThread(TFunc&& func) -> decltype(func())
{
using ReturnType = decltype(func());
ReturnType result{};
std::thread worker([&func, &result]() mutable {
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
result = func();
CoUninitialize();
});
// Pump messages while waiting for the worker (dialog) to finish
while (true)
{
HANDLE hWorker = worker.native_handle();
if (MsgWaitForMultipleObjects(1, &hWorker, FALSE, INFINITE, QS_ALLINPUT) == WAIT_OBJECT_0)
break;
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
PostQuitMessage((int)msg.wParam);
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
worker.join();
return result;
}
// Wrapper for IContextMenu::InvokeCommand that runs on separate STA thread and pumps messages
static HRESULT InvokeCommandSafe(IContextMenu* pMenu, LPCMINVOKECOMMANDINFO pInfo)
{
return ExecuteOnSTAThread([&]() {
return pMenu->InvokeCommand(pInfo);
});
}
// Wrapper for SHOpenFolderAndSelectItems that runs on separate STA thread and pumps messages
static HRESULT SHOpenFolderAndSelectItemsSafe(PCIDLIST_ABSOLUTE pidlFolder, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD dwFlags)
{
return ExecuteOnSTAThread([=]() {
return SHOpenFolderAndSelectItems(pidlFolder, cidl, apidl, dwFlags);
});
}
static CString g_RenameText; static CString g_RenameText;
static POINT g_RenamePos; static POINT g_RenamePos;
@@ -2871,7 +2925,7 @@ void CMenuContainer::ActivateItem( int index, TActivateType type, const POINT *p
} }
else else
{ {
SHOpenFolderAndSelectItems(pItemPidl1,0,NULL,0); SHOpenFolderAndSelectItemsSafe(pItemPidl1,0,NULL,0);
} }
res=0; res=0;
} }
@@ -3113,7 +3167,7 @@ void CMenuContainer::ActivateItem( int index, TActivateType type, const POINT *p
} }
else else
{ {
HRESULT hr=pInvokeMenu->InvokeCommand((LPCMINVOKECOMMANDINFO)&info); HRESULT hr=InvokeCommandSafe(pInvokeMenu,(LPCMINVOKECOMMANDINFO)&info);
LOG_MENU(LOG_EXECUTE,L"Invoke command, ptr=%p, res=%d",this,hr); LOG_MENU(LOG_EXECUTE,L"Invoke command, ptr=%p, res=%d",this,hr);
executeSuccess=SUCCEEDED(hr); executeSuccess=SUCCEEDED(hr);
} }
+31 -4
View File
@@ -22,6 +22,7 @@
#include <dbghelp.h> #include <dbghelp.h>
#include <set> #include <set>
#include <Thumbcache.h> #include <Thumbcache.h>
#include <tlhelp32.h>
#define HOOK_DROPTARGET // define this to replace the IDropTarget of the start button #define HOOK_DROPTARGET // define this to replace the IDropTarget of the start button
#define START_TOUCH // touch support for the start button #define START_TOUCH // touch support for the start button
@@ -2936,6 +2937,35 @@ static void OpenCortana( void )
ShellExecute(NULL,NULL,L"shell:::{2559a1f8-21d7-11d4-bdaf-00c04f60b9f0}",NULL,NULL,SW_SHOWNORMAL); ShellExecute(NULL,NULL,L"shell:::{2559a1f8-21d7-11d4-bdaf-00c04f60b9f0}",NULL,NULL,SW_SHOWNORMAL);
} }
HMODULE GetModuleHandleByPrefix(const WCHAR* prefix)
{
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
if (snapshot == INVALID_HANDLE_VALUE)
return nullptr;
size_t prefixLength = wcslen(prefix);
MODULEENTRY32 me{};
me.dwSize = sizeof(me);
HMODULE result = nullptr;
if (Module32First(snapshot, &me))
{
do
{
if (_wcsnicmp(me.szModule, prefix, prefixLength) == 0)
{
result = reinterpret_cast<HMODULE>(me.modBaseAddr);
break;
}
} while (Module32Next(snapshot, &me));
}
CloseHandle(snapshot);
return result;
}
static void InitStartMenuDLL( void ) static void InitStartMenuDLL( void )
{ {
static bool initCalled = false; static bool initCalled = false;
@@ -2979,10 +3009,7 @@ static void InitStartMenuDLL( void )
auto module=GetModuleHandle(L"taskbar.dll"); auto module=GetModuleHandle(L"taskbar.dll");
if (!module) if (!module)
{ {
module = GetModuleHandle(L"ep_taskbar.5.dll"); module = GetModuleHandleByPrefix(L"ep_taskbar");
if (!module)
module = GetModuleHandle(L"ep_taskbar.2.dll");
if (module) if (module)
g_epTaskbar = true; g_epTaskbar = true;
} }