diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 000000000..f6b1819bc
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,94 @@
+name: Build
+
+permissions:
+ contents: read # Default to secure
+
+on:
+ pull_request:
+ branches:
+ - master
+ paths:
+ - 'Src/**'
+ - 'Localization/**'
+ - '.github/workflows/build.yml'
+
+ workflow_dispatch: # allows manual trigger for main/master
+
+jobs:
+ build:
+ runs-on: windows-2022
+ outputs:
+ new_version: ${{ steps.versioning.outputs.NEW_VERSION }}
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v6
+ with:
+ fetch-depth: 0 # Essential to see all tags
+
+ - name: Prepare version
+ id: versioning
+ shell: pwsh
+ run: |
+ # Fetch latest tag
+ $latestTag = git describe --tags --abbrev=0 2>$null
+
+ if ($latestTag -notmatch '^v\d+\.\d+\.\d+$') {
+ Write-Error "Error: Could not find a valid vX.Y.Z tag in history. Found: '$latestTag'"
+ exit 1
+ }
+
+ # Parse and Increment
+ $version = [version]$latestTag.Substring(1)
+ $baseVersion = "$($version.Major).$($version.Minor).$($version.Build + 1)"
+
+ # Handle PR Suffix
+ if ("${{ github.event_name }}" -eq "pull_request") {
+ $shortSha = "${{ github.event.pull_request.head.sha }}".Substring(0, 7)
+ $finalVersion = "$baseVersion-pr-$shortSha"
+ } else {
+ $finalVersion = $baseVersion
+ }
+
+ # Export
+ "NEW_VERSION=$finalVersion" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
+ Write-Host "Building version: $finalVersion"
+
+ - name: Build
+ shell: cmd
+ env:
+ APPVEYOR_BUILD_VERSION: ${{ steps.versioning.outputs.NEW_VERSION }}
+ run: Src\Setup\__MakeFinal.bat
+
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v7
+ with:
+ name: OpenShell
+ path: |
+ Src/Setup/Final/
+ !Src/Setup/Final/OpenShellLoc.zip
+
+ release:
+ if: github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/master' # Only manual master builds
+ needs: build
+ runs-on: ubuntu-latest # Cheaper/faster than windows for just uploading
+ permissions:
+ contents: write # Elevate permissions ONLY for this job
+ steps:
+ - name: Download artifacts
+ uses: actions/download-artifact@v8
+ with:
+ name: OpenShell
+
+ - 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 }}
diff --git a/.gitignore b/.gitignore
index 283a3da2e..75591d3db 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,12 +20,15 @@
# Build results
[Dd]ebug/
[Dd]ebug64/
+[Dd]ebugARM64/
[Dd]ebugPublic/
[Rr]elease/
[Rr]elease64/
+[Rr]eleaseARM64/
[Rr]eleases/
x64/
x86/
+ARM64/
bld/
[Bb]in/
[Oo]bj/
diff --git a/README.md b/README.md
index b53baa2a8..f05fed121 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ A collection of utilities bringing back classic features to Windows.
*Originally* **[Classic Shell](http://www.classicshell.net)** *by [Ivo Beltchev](https://sourceforge.net/u/ibeltchev/profile/)*
-[](https://github.com/Open-Shell/Open-Shell-Menu/releases/latest) [](https://github.com/Open-Shell/Open-Shell-Menu/releases) [](https://ci.appveyor.com/project/passionate-coder/open-shell-menu/branch/master) [](https://gitq.com/passionate-coder/Classic-Start) [](https://gitter.im/open-shell/Lobby) [](https://discord.gg/7H6arr5)
+[](https://github.com/Open-Shell/Open-Shell-Menu/releases/latest) [](https://github.com/Open-Shell/Open-Shell-Menu/releases) [](https://github.com/Open-Shell/Open-Shell-Menu/actions/workflows/build.yml) [](https://ci.appveyor.com/project/passionate-coder/open-shell-menu/branch/master) [](https://gitq.com/passionate-coder/Classic-Start) [](https://gitter.im/open-shell/Lobby) [](https://discord.gg/7H6arr5)
[Open-Shell Homepage](https://open-shell.github.io/Open-Shell-Menu)
@@ -23,6 +23,12 @@ You can find the latest stable version here:
[](https://github.com/Open-Shell/Open-Shell-Menu/releases/latest)
+> [!IMPORTANT]
+> #### 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).
+>
+> If you install older one on a Windows for ARM installation (ex. using Parallels Desktop on an Apple Silicon Mac), you will no longer be able to log into your account the next time you reboot. Please refrain from installing Open-Shell on Windows for ARM.
+
### Temporary Translation/Language Solution
1. Download [language DLL](https://coddec.github.io/Classic-Shell/www.classicshell.net/translations/index.html)
2. Place it either in the Open-Shell's __install folder__ or in the `%ALLUSERSPROFILE%\OpenShell\Languages` folder
diff --git a/Src/BUILDME.txt b/Src/BUILDME.txt
index 2f3a43cff..b9ed47e5b 100644
--- a/Src/BUILDME.txt
+++ b/Src/BUILDME.txt
@@ -10,7 +10,7 @@ Visual Studio 2022 (Community Edition is enough)
- Windows 11 SDK (10.0.22621.0) for Desktop C++
- Visual C++ ATL support
HTML Help Workshop
-WiX 3.11
+WiX 3.14
7-Zip
It is possible to convert the projects to newer versions of Visual Studio and newer SDKs.
Newer versions of WiX will probably work fine.
diff --git a/Src/ClassicExplorer/ClassicExplorer.vcxproj b/Src/ClassicExplorer/ClassicExplorer.vcxproj
index 4280d8376..2ec90585b 100644
--- a/Src/ClassicExplorer/ClassicExplorer.vcxproj
+++ b/Src/ClassicExplorer/ClassicExplorer.vcxproj
@@ -1,6 +1,14 @@
+
+ Debug
+ ARM64
+
+
+ Debug
+ ARM64EC
+
Debug
Win32
@@ -9,6 +17,14 @@
Debug
x64
+
+ Release
+ ARM64
+
+
+ Release
+ ARM64EC
+
Release
Win32
@@ -17,6 +33,14 @@
Release
x64
+
+ Setup
+ ARM64
+
+
+ Setup
+ ARM64EC
+
Setup
Win32
@@ -53,6 +77,13 @@
$(ProjectName)64
+
+ $(ProjectName)64
+
+
+ $(ProjectName)64
+ true
+
true
diff --git a/Src/ClassicExplorer/ClassicExplorer.vcxproj.filters b/Src/ClassicExplorer/ClassicExplorer.vcxproj.filters
index 3b72d121a..419ebce35 100644
--- a/Src/ClassicExplorer/ClassicExplorer.vcxproj.filters
+++ b/Src/ClassicExplorer/ClassicExplorer.vcxproj.filters
@@ -146,4 +146,4 @@
Resource Files
-
+
\ No newline at end of file
diff --git a/Src/ClassicExplorer/ExplorerBHO.cpp b/Src/ClassicExplorer/ExplorerBHO.cpp
index edabf46cf..cfd456364 100644
--- a/Src/ClassicExplorer/ExplorerBHO.cpp
+++ b/Src/ClassicExplorer/ExplorerBHO.cpp
@@ -243,7 +243,7 @@ LRESULT CALLBACK CExplorerBHO::HookExplorer( int nCode, WPARAM wParam, LPARAM lP
if (GetClassName(parent,name,_countof(name)) && _wcsicmp(name,L"CabinetWClass")==0)
{
DWORD_PTR settings=0;
- if (GetWinVersion()==WIN_VER_WIN7 && GetSettingBool(L"FixFolderScroll"))
+ if (GetSettingBool(L"FixFolderScroll"))
settings|=1;
SetWindowSubclass(hWnd,SubclassTreeProc,'CLSH',settings);
PostMessage(hWnd,TVM_SETEXTENDEDSTYLE,TVS_EX_FADEINOUTEXPANDOS|TVS_EX_AUTOHSCROLL|0x80000000,0);
diff --git a/Src/ClassicExplorer/SettingsUI.cpp b/Src/ClassicExplorer/SettingsUI.cpp
index 8be0eedad..458500eba 100644
--- a/Src/ClassicExplorer/SettingsUI.cpp
+++ b/Src/ClassicExplorer/SettingsUI.cpp
@@ -621,7 +621,7 @@ void UpdateSettings( void )
UpdateSetting(L"ShowCaption",CComVariant(0),false); HideSetting(L"ShowCaption",true);
UpdateSetting(L"ShowIcon",CComVariant(0),false); HideSetting(L"ShowIcon",true);
- UpdateSetting(L"FixFolderScroll",CComVariant(0),false); HideSetting(L"FixFolderScroll",true);
+ UpdateSetting(L"FixFolderScroll",CComVariant(0),false);
UpdateSetting(L"ToolbarItems",CComVariant(g_DefaultToolbar2),false);
if (GetWinVersion()>=WIN_VER_WIN10)
diff --git a/Src/ClassicIE/ClassicIE.vcxproj b/Src/ClassicIE/ClassicIE.vcxproj
index 4a5b9a4b4..83f8308ba 100644
--- a/Src/ClassicIE/ClassicIE.vcxproj
+++ b/Src/ClassicIE/ClassicIE.vcxproj
@@ -1,6 +1,10 @@
+
+ Debug
+ ARM64
+
Debug
Win32
@@ -9,6 +13,10 @@
Debug
x64
+
+ Release
+ ARM64
+
Release
Win32
@@ -17,6 +25,10 @@
Release
x64
+
+ Setup
+ ARM64
+
Setup
Win32
@@ -53,6 +65,9 @@
$(ProjectName)_64
+
+ $(ProjectName)_64
+
NotUsing
diff --git a/Src/ClassicIE/ClassicIEDLL/ClassicIEDLL.vcxproj b/Src/ClassicIE/ClassicIEDLL/ClassicIEDLL.vcxproj
index 57068dd0c..10ea42734 100644
--- a/Src/ClassicIE/ClassicIEDLL/ClassicIEDLL.vcxproj
+++ b/Src/ClassicIE/ClassicIEDLL/ClassicIEDLL.vcxproj
@@ -1,6 +1,14 @@
+
+ Debug
+ ARM64
+
+
+ Debug
+ ARM64EC
+
Debug
Win32
@@ -9,6 +17,14 @@
Debug
x64
+
+ Release
+ ARM64
+
+
+ Release
+ ARM64EC
+
Release
Win32
@@ -17,6 +33,14 @@
Release
x64
+
+ Setup
+ ARM64
+
+
+ Setup
+ ARM64EC
+
Setup
Win32
@@ -53,6 +77,13 @@
$(ProjectName)_64
+
+ $(ProjectName)_64
+
+
+ $(ProjectName)_64
+ true
+
_USRDLL;CLASSICIEDLL_EXPORTS;%(PreprocessorDefinitions)
diff --git a/Src/ClassicIE/ClassicIEDLL/ClassicIEDLL.vcxproj.filters b/Src/ClassicIE/ClassicIEDLL/ClassicIEDLL.vcxproj.filters
index 8af204741..8f49852ad 100644
--- a/Src/ClassicIE/ClassicIEDLL/ClassicIEDLL.vcxproj.filters
+++ b/Src/ClassicIE/ClassicIEDLL/ClassicIEDLL.vcxproj.filters
@@ -98,4 +98,4 @@
Resource Files
-
+
\ No newline at end of file
diff --git a/Src/Common.props b/Src/Common.props
index 62a42c9fe..2a0a2ceee 100644
--- a/Src/Common.props
+++ b/Src/Common.props
@@ -16,6 +16,14 @@
$(MSBuildThisFileDirectory)..\build\bin\$(Configuration)64\
$(MSBuildThisFileDirectory)..\build\obj\$(ProjectName)\$(Configuration)64\
+
+ $(MSBuildThisFileDirectory)..\build\bin\$(Configuration)ARM64\
+ $(MSBuildThisFileDirectory)..\build\obj\$(ProjectName)\$(Configuration)ARM64\
+
+
+ $(MSBuildThisFileDirectory)..\build\bin\$(Configuration)ARM64EC\
+ $(MSBuildThisFileDirectory)..\build\obj\$(ProjectName)\$(Configuration)ARM64EC\
+
diff --git a/Src/Lib/IatHookHelper.cpp b/Src/Lib/IatHookHelper.cpp
index 4a34d315b..5305811ed 100644
--- a/Src/Lib/IatHookHelper.cpp
+++ b/Src/Lib/IatHookHelper.cpp
@@ -70,12 +70,17 @@ IatHookData *SetIatHook( IMAGE_DOS_HEADER *dosHeader, DWORD iatOffset, DWORD int
{
IatHookData *hook=g_IatHooks+g_IatHookCount;
g_IatHookCount++;
+#if defined(_M_AMD64) || defined(_M_IX86)
hook->jump[0]=hook->jump[1]=0x90; // NOP
hook->jump[2]=0xFF; hook->jump[3]=0x25; // JUMP
-#ifdef _WIN64
+#if defined(_M_AMD64)
hook->jumpOffs=0;
#else
hook->jumpOffs=(DWORD)(hook)+8;
+#endif
+#elif defined(_M_ARM64)
+ hook->jump[0]=0x48; hook->jump[1]=0x00; hook->jump[2]=0x00; hook->jump[3]=0x58; // LDR X8, newProc
+ hook->jump[4]=0x00; hook->jump[5]=0x01; hook->jump[6]=0x1F; hook->jump[7]=0xD6; // BR X8
#endif
hook->newProc=newProc;
hook->oldProc=(void*)thunk->u1.Function;
diff --git a/Src/Lib/IatHookHelper.h b/Src/Lib/IatHookHelper.h
index 2a4603f0d..d522bfbd7 100644
--- a/Src/Lib/IatHookHelper.h
+++ b/Src/Lib/IatHookHelper.h
@@ -6,8 +6,12 @@
struct IatHookData
{
+#if defined(_M_AMD64) || defined(_M_IX86)
unsigned char jump[4]; // jump instruction 0x90, 0x90, 0xFF, 0x25
DWORD jumpOffs; // jump instruction offset
+#elif defined(_M_ARM64)
+ unsigned char jump[8]; // LDR , BR
+#endif
void *newProc; // the address of the new proc
void *oldProc; // the address of the old proc
IMAGE_THUNK_DATA *thunk; // the IAT thunk
diff --git a/Src/Lib/Lib.vcxproj b/Src/Lib/Lib.vcxproj
index 7d7c023ba..8c29ee77c 100644
--- a/Src/Lib/Lib.vcxproj
+++ b/Src/Lib/Lib.vcxproj
@@ -1,6 +1,14 @@
+
+ Debug
+ ARM64
+
+
+ Debug
+ ARM64EC
+
Debug
Win32
@@ -9,6 +17,14 @@
Debug
x64
+
+ Release
+ ARM64
+
+
+ Release
+ ARM64EC
+
Release
Win32
@@ -42,6 +58,9 @@
$(IntDir)
+
+ true
+
_LIB;%(PreprocessorDefinitions)
diff --git a/Src/Lib/ResourceHelper.cpp b/Src/Lib/ResourceHelper.cpp
index 62a32fb8b..b7388a554 100644
--- a/Src/Lib/ResourceHelper.cpp
+++ b/Src/Lib/ResourceHelper.cpp
@@ -384,14 +384,14 @@ HICON CreateDisabledIcon( HICON hIcon, int iconSize )
}
// Loads an image file into a bitmap and optionally resizes it
-HBITMAP LoadImageFile( const wchar_t *path, const SIZE *pSize, bool bUseAlpha, bool bPremultiply, std::vector *pButtonAnim )
+HBITMAP LoadImageFile( const wchar_t *path, const SIZE *pSize, bool bUseAlpha, bool bPremultiply, std::vector *pButtonAnim, UINT dpi )
{
HBITMAP srcBmp=NULL;
if (_wcsicmp(PathFindExtension(path),L".bmp")==0)
{
srcBmp=(HBITMAP)LoadImage(NULL,path,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_LOADFROMFILE);
}
- if (srcBmp && !pSize)
+ if (srcBmp && !pSize && !dpi)
return srcBmp;
CComPtr pFactory;
if (FAILED(pFactory.CoCreateInstance(CLSID_WICImagingFactory)))
@@ -482,6 +482,12 @@ HBITMAP LoadImageFile( const wchar_t *path, const SIZE *pSize, bool bUseAlpha, b
else
frameHeightD=frameWidthD*frameHeightS/frameWidthS;
}
+
+ if (dpi)
+ {
+ frameWidthD=ScaleForDpi(dpi,frameWidthD);
+ frameHeightD=ScaleForDpi(dpi,frameHeightD);
+ }
}
BITMAPINFO bi={0};
@@ -946,7 +952,12 @@ UINT GetDpi(HWND hwnd)
return dpi;
}
+int ScaleForDpi(UINT dpi, int value)
+{
+ return MulDiv(value, dpi, USER_DEFAULT_SCREEN_DPI);
+}
+
int ScaleForDpi(HWND hwnd, int value)
{
- return MulDiv(value, GetDpi(hwnd), USER_DEFAULT_SCREEN_DPI);
+ return ScaleForDpi(GetDpi(hwnd), value);
}
diff --git a/Src/Lib/ResourceHelper.h b/Src/Lib/ResourceHelper.h
index d44eb6b59..5afc1d1dc 100644
--- a/Src/Lib/ResourceHelper.h
+++ b/Src/Lib/ResourceHelper.h
@@ -35,7 +35,7 @@ HICON ShExtractIcon( const char *path, int index, int iconSize );
HBITMAP BitmapFromIcon( HICON hIcon, int iconSize, unsigned int **pBits, bool bDestroyIcon );
// Loads an image file into a bitmap and optionally resizes it
-HBITMAP LoadImageFile( const wchar_t *path, const SIZE *pSize, bool bUseAlpha, bool bPremultiply, std::vector *pButtonAnim );
+HBITMAP LoadImageFile( const wchar_t *path, const SIZE *pSize, bool bUseAlpha, bool bPremultiply, std::vector *pButtonAnim, UINT dpi=0 );
// Loads a bitmap from a IMAGE resource
HBITMAP LoadImageResource( HMODULE hModule, const wchar_t *name, bool bTopDown, bool bPremultiply );
@@ -88,6 +88,8 @@ HFONT CreateFontSetting( const wchar_t *fontStr, int dpi );
// Return DPI of given window (or system DPI on older systems)
UINT GetDpi(HWND hwnd = nullptr);
+// Scale given value according to given DPI
+int ScaleForDpi(UINT dpi, int value);
// Scale given value according to DPI of window
int ScaleForDpi(HWND hwnd, int value);
diff --git a/Src/Lib/Settings.cpp b/Src/Lib/Settings.cpp
index 8937d4c39..599cb9fed 100644
--- a/Src/Lib/Settings.cpp
+++ b/Src/Lib/Settings.cpp
@@ -1670,7 +1670,7 @@ LRESULT CSettingsDlg::OnBackup( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&
ofn.lpstrTitle=title;
ofn.lpstrDefExt=L".xml";
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT|OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
- if (GetSaveFileName(&ofn))
+ if (GetSaveFileNameSafe(&ofn))
{
CString err=g_SettingsManager.SaveSettingsXml(path);
if (!err.IsEmpty())
@@ -1699,7 +1699,7 @@ LRESULT CSettingsDlg::OnBackup( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&
CString title=LoadStringEx(IDS_XML_TITLE_LOAD);
ofn.lpstrTitle=title;
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
- if (GetOpenFileName(&ofn))
+ if (GetOpenFileNameSafe(&ofn))
{
SetCurTab(m_Index,true); // reload tab once to force-close any active edit boxes
CString error=g_SettingsManager.LoadSettingsXml(path);
diff --git a/Src/Lib/SettingsUIHelper.cpp b/Src/Lib/SettingsUIHelper.cpp
index 9372677c5..9b988e282 100644
--- a/Src/Lib/SettingsUIHelper.cpp
+++ b/Src/Lib/SettingsUIHelper.cpp
@@ -15,6 +15,7 @@
#include
#include