Compare commits

..
Author SHA1 Message Date
ge0rdi dfb307b3b7 Fix C++23 warnings
warning C5333: backslash and newline separated by space is treated as a line continuation in C++23 and later
2026-05-13 20:07:54 +02:00
ge0rdiandGitHub b2070640ff Fix open/save file dialog getting stuck after Windows 11 update (#2457)
We will run those APIs on separate STA thread and pump messages while
waiting for the dialog to end.

fixes #2431
fixes #2426
fixes #2418
fixes #2417
fixes #2390
fixes #2372
fixes #2371
fixes #2370
fixes #2364
fixes #2361
fixes #2360
fixes #2343
fixes #2332
fixes #2322
fixes #2320
fixes #2319
fixes #2312
fixes #2299
2026-05-12 21:12:51 +02:00
coolvittoandGitHub 7566280973 Update font face names in Japanese localization (#2409) 2026-05-11 19:24:28 +02:00
32ad90f17d Fix search auto-selecting wrong item before programs finish loading (#2451)
fix: defer auto-select until programs loaded to prevent wrong search result selection

When search results refresh mid-collection, OnRefresh auto-selects the
first result item. If programs haven't loaded yet, Settings category
appears first and gets selected. If user hits Enter in that window,
wrong item launches.

Skip auto-select when search is still in progress and no programs
have been found yet. Next refresh after programs load will select
correctly.

Fixes Open-Shell/Open-Shell-Menu#456
Fixes Open-Shell/Open-Shell-Menu#1982
Fixes Open-Shell/Open-Shell-Menu#4

> 🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-18 15:18:23 +02:00
AnixxandGitHub e2758ec376 Support for unthemed taskbar (#2369)
* Support for unthemed taskbar

See this discussion:
https://github.com/Open-Shell/Open-Shell-Menu/discussions/2367

* Refactor color handling in StartMenuDLL
2026-01-24 11:26:25 +01:00
ge0rdiandGitHub dd57854da1 Scale custom button image according to current DPI (#2248)
Fixes #2246
2025-12-12 09:09:21 +01:00
ge0rdi 40d8f5b119 AppVeyor: New deployment token 2025-11-30 16:02:35 +01:00
9 changed files with 120 additions and 19 deletions
+2 -2
View File
@@ -1670,7 +1670,7 @@ LRESULT CSettingsDlg::OnBackup( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&
ofn.lpstrTitle=title; ofn.lpstrTitle=title;
ofn.lpstrDefExt=L".xml"; ofn.lpstrDefExt=L".xml";
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT|OFN_HIDEREADONLY|OFN_NOCHANGEDIR; 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); CString err=g_SettingsManager.SaveSettingsXml(path);
if (!err.IsEmpty()) if (!err.IsEmpty())
@@ -1699,7 +1699,7 @@ LRESULT CSettingsDlg::OnBackup( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&
CString title=LoadStringEx(IDS_XML_TITLE_LOAD); CString title=LoadStringEx(IDS_XML_TITLE_LOAD);
ofn.lpstrTitle=title; ofn.lpstrTitle=title;
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR; 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 SetCurTab(m_Index,true); // reload tab once to force-close any active edit boxes
CString error=g_SettingsManager.LoadSettingsXml(path); CString error=g_SettingsManager.LoadSettingsXml(path);
+88 -5
View File
@@ -15,6 +15,7 @@
#include <uxtheme.h> #include <uxtheme.h>
#include <map> #include <map>
#include <algorithm> #include <algorithm>
#include <thread>
const KNOWNFOLDERID FOLDERID_DesktopRoot={'DESK', 'TO', 'P', {'D', 'E', 'S', 'K', 'T', 'O', 'P', 0x00}}; const KNOWNFOLDERID FOLDERID_DesktopRoot={'DESK', 'TO', 'P', {'D', 'E', 'S', 'K', 'T', 'O', 'P', 0x00}};
@@ -1193,7 +1194,7 @@ bool BrowseCommandHelper( HWND parent, wchar_t *text )
ofn.lpstrFile=text; ofn.lpstrFile=text;
ofn.nMaxFile=_MAX_PATH; ofn.nMaxFile=_MAX_PATH;
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR|OFN_NODEREFERENCELINKS; ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR|OFN_NODEREFERENCELINKS;
if (GetOpenFileName(&ofn)) if (GetOpenFileNameSafe(&ofn))
{ {
wchar_t buf[_MAX_PATH]; wchar_t buf[_MAX_PATH];
UnExpandEnvStrings(text,buf,_countof(buf)); UnExpandEnvStrings(text,buf,_countof(buf));
@@ -1216,7 +1217,8 @@ bool BrowseCommandHelper( HWND parent, wchar_t *text )
return false; return false;
} }
bool BrowseLinkHelper( HWND parent, wchar_t *text, bool bFoldersOnly ) // Internal implementation that must be run on an STA thread with COM initialized.
static bool BrowseLinkHelperImpl( HWND parent, wchar_t *text, bool bFoldersOnly )
{ {
DoEnvironmentSubst(text,_MAX_PATH); DoEnvironmentSubst(text,_MAX_PATH);
@@ -1276,6 +1278,41 @@ bool BrowseLinkHelper( HWND parent, wchar_t *text, bool bFoldersOnly )
return pResult!=NULL; return pResult!=NULL;
} }
// Run IFileOpenDialog on a separate STA thread and pump messages on the caller while waiting.
bool BrowseLinkHelper( HWND parent, wchar_t *text, bool bFoldersOnly )
{
bool result = false;
std::thread worker([&parent, &text, &bFoldersOnly, &result]() mutable {
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
result = BrowseLinkHelperImpl(parent, text, bFoldersOnly);
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;
}
bool BrowseIconHelper( HWND parent, wchar_t *text ) bool BrowseIconHelper( HWND parent, wchar_t *text )
{ {
int id=0; int id=0;
@@ -2011,7 +2048,7 @@ LRESULT CBrowseForIconDlg::OnBrowse( WORD wNotifyCode, WORD wID, HWND hWndCtl, B
CString title=LoadStringEx(IDS_ICON_TITLE); CString title=LoadStringEx(IDS_ICON_TITLE);
ofn.lpstrTitle=title; ofn.lpstrTitle=title;
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR; ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
if (GetOpenFileName(&ofn)) if (GetOpenFileNameSafe(&ofn))
{ {
wchar_t buf[_MAX_PATH]; wchar_t buf[_MAX_PATH];
UnExpandEnvStrings(path,buf,_countof(buf)); UnExpandEnvStrings(path,buf,_countof(buf));
@@ -2210,7 +2247,7 @@ bool BrowseForBitmap( HWND hWndParent, wchar_t *path, bool bAllowJpeg )
CString title=LoadStringEx(IDS_BMP_TITLE); CString title=LoadStringEx(IDS_BMP_TITLE);
ofn.lpstrTitle=title; ofn.lpstrTitle=title;
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR; ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
if (GetOpenFileName(&ofn)) if (GetOpenFileNameSafe(&ofn))
{ {
wchar_t buf[_MAX_PATH]; wchar_t buf[_MAX_PATH];
UnExpandEnvStrings(path,buf,_countof(buf)); UnExpandEnvStrings(path,buf,_countof(buf));
@@ -2242,7 +2279,7 @@ bool BrowseForSound( HWND hWndParent, wchar_t *path )
CString title=LoadStringEx(IDS_WAV_TITLE); CString title=LoadStringEx(IDS_WAV_TITLE);
ofn.lpstrTitle=title; ofn.lpstrTitle=title;
ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR; ofn.Flags=OFN_DONTADDTORECENT|OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
if (GetOpenFileName(&ofn)) if (GetOpenFileNameSafe(&ofn))
{ {
wchar_t buf[_MAX_PATH]; wchar_t buf[_MAX_PATH];
UnExpandEnvStrings(path,buf,_countof(buf)); UnExpandEnvStrings(path,buf,_countof(buf));
@@ -3630,3 +3667,49 @@ DWORD ParseColor(const wchar_t* str)
wchar_t* end; wchar_t* end;
return wcstoul(str, &end, 16) & 0xFFFFFF; return wcstoul(str, &end, 16) & 0xFFFFFF;
} }
// Run GetOpenFileName/GetSaveFileName on a separate STA thread and pump messages on the caller
template <typename auto Fnc>
static BOOL GetFileNameSafe(OPENFILENAME* pOfn)
{
BOOL result = FALSE;
std::thread worker([&pOfn, &result]() mutable {
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
result = Fnc(pOfn);
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;
}
BOOL GetOpenFileNameSafe(OPENFILENAME* pOfn)
{
return GetFileNameSafe<GetOpenFileNameW>(pOfn);
}
BOOL GetSaveFileNameSafe(OPENFILENAME* pOfn)
{
return GetFileNameSafe<GetSaveFileNameW>(pOfn);
}
+4
View File
@@ -395,3 +395,7 @@ DWORD BgrToRgb(DWORD val);
// parse color from hexadecimal string // parse color from hexadecimal string
DWORD ParseColor(const wchar_t* str); DWORD ParseColor(const wchar_t* str);
// safe versions of GetOpenFileName/GetSaveFileName (run API on a separate STA thread and pump messages on the caller)
BOOL GetOpenFileNameSafe(OPENFILENAME* pOfn);
BOOL GetSaveFileNameSafe(OPENFILENAME* pOfn);
+1 -1
View File
@@ -31,7 +31,7 @@
<String Id="Advanced_Font_Bigger_Size" Overridable="yes">12</String> <String Id="Advanced_Font_Bigger_Size" Overridable="yes">12</String>
<String Id="Advanced_Font_Title_Size" Overridable="yes">9</String> <String Id="Advanced_Font_Title_Size" Overridable="yes">9</String>
<String Id="Advanced_Font_Emphasized_Size" Overridable="yes">8</String> <String Id="Advanced_Font_Emphasized_Size" Overridable="yes">8</String>
<String Id="Advanced_Font_FaceName" Overridable="yes">"MS UI Gothic", "MS PGothic", "MS Pゴシック", "MS Gothic", "MS ゴシック", Osaka, Tahoma</String> <String Id="Advanced_Font_FaceName" Overridable="yes">"MS UI Gothic", "MS PGothic", "MS Pゴシック", "MS Gothic", "MS ゴシック", Yu Gothic UI, Tahoma</String>
<String Id="BrowseDlg_Title" Overridable="yes">[ProductName] セットアップ</String> <String Id="BrowseDlg_Title" Overridable="yes">[ProductName] セットアップ</String>
<String Id="BrowseDlgComboLabel" Overridable="yes">場所(&amp;L):</String> <String Id="BrowseDlgComboLabel" Overridable="yes">場所(&amp;L):</String>
+1 -1
View File
@@ -383,7 +383,7 @@ private:
static DWORD CALLBACK StaticRefreshInfoThread( void *param ); static DWORD CALLBACK StaticRefreshInfoThread( void *param );
static DWORD CALLBACK SaveCacheFileThread( void *param ); static DWORD CALLBACK SaveCacheFileThread( void *param );
// all paths are in caps and end with \ // all paths are in caps and end with backslash
CString m_RootStartMenu1; CString m_RootStartMenu1;
CString m_RootStartMenu2; CString m_RootStartMenu2;
CString m_RootStartMenu3; CString m_RootStartMenu3;
+4 -1
View File
@@ -6366,7 +6366,10 @@ LRESULT CMenuContainer::OnRefresh( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
} }
} }
else if (m_Items[m_OriginalCount].id==MENU_SEARCH_CATEGORY) else if (m_Items[m_OriginalCount].id==MENU_SEARCH_CATEGORY)
hotItem=m_OriginalCount+1; {
if (!bSearching || !s_SearchResults.programs.empty())
hotItem=m_OriginalCount+1;
}
} }
else else
hotItem=-1; hotItem=-1;
+17 -6
View File
@@ -1624,7 +1624,7 @@ static void ComputeTaskbarColors( int *data )
{ {
bool bDefLook; bool bDefLook;
int look=GetSettingInt(L"TaskbarLook",bDefLook); int look=GetSettingInt(L"TaskbarLook",bDefLook);
if (GetWinVersion()<WIN_VER_WIN10 || look==TASKBAR_AEROGLASS || (look==TASKBAR_TRANSPARENT && g_TaskbarTexture)) if (GetWinVersion()<WIN_VER_WIN10 || !IsAppThemed() || look==TASKBAR_AEROGLASS || (look==TASKBAR_TRANSPARENT && g_TaskbarTexture))
{ {
memset(data,0,16); memset(data,0,16);
} }
@@ -1872,6 +1872,7 @@ static LRESULT CALLBACK SubclassTaskBarProc( HWND hWnd, UINT uMsg, WPARAM wParam
ComputeTaskbarColors(data); ComputeTaskbarColors(data);
WINCOMPATTRDATA attrData={0x13,&data,sizeof(data)}; WINCOMPATTRDATA attrData={0x13,&data,sizeof(data)};
SetWindowCompositionAttribute(hWnd,&attrData); SetWindowCompositionAttribute(hWnd,&attrData);
UpdateTaskBars(TASKBAR_UPDATE_TEXTURE);
return res; return res;
} }
if ((uMsg==WM_DWMCOLORIZATIONCOLORCHANGED || uMsg==WM_SETTINGCHANGE) && taskBar && taskBar->bCustomLook && SetWindowCompositionAttribute && GetWinVersion()<WIN_VER_WIN10) if ((uMsg==WM_DWMCOLORIZATIONCOLORCHANGED || uMsg==WM_SETTINGCHANGE) && taskBar && taskBar->bCustomLook && SetWindowCompositionAttribute && GetWinVersion()<WIN_VER_WIN10)
@@ -1932,7 +1933,7 @@ static LRESULT CALLBACK SubclassTaskBarProc( HWND hWnd, UINT uMsg, WPARAM wParam
WINCOMPATTRDATA attrData={0x13,&data,sizeof(data)}; WINCOMPATTRDATA attrData={0x13,&data,sizeof(data)};
SetWindowCompositionAttribute(hWnd,&attrData); SetWindowCompositionAttribute(hWnd,&attrData);
} }
if (g_TaskbarTexture && IsAppThemed()) if (g_TaskbarTexture)
{ {
// draw taskbar background (behind start button and separators) // draw taskbar background (behind start button and separators)
PAINTSTRUCT ps; PAINTSTRUCT ps;
@@ -2383,12 +2384,19 @@ void UpdateTaskBars( TUpdateTaskbar update )
} }
} }
} }
else if (GetWinVersion()<WIN_VER_WIN10 && (!bDefColor || !bDefOpacity)) else if ((GetWinVersion()<WIN_VER_WIN10 && (!bDefColor || !bDefOpacity)) || !IsAppThemed())
{ {
if (bDefColor && GetWinVersion()>WIN_VER_WIN7) if (bDefColor && GetWinVersion()>WIN_VER_WIN7)
{ {
color=GetSystemGlassColor8(); if (IsAppThemed())
color=((color&0xFF)<<16)|(color&0xFF00)|((color>>16)&0xFF); {
color=GetSystemGlassColor8();
color=((color&0xFF)<<16)|(color&0xFF00)|((color>>16)&0xFF);
}
else
{
color=GetSysColor(COLOR_BTNFACE);
}
} }
BITMAPINFO bi={0}; BITMAPINFO bi={0};
bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); bi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
@@ -3012,7 +3020,10 @@ static void InitStartMenuDLL( void )
if (GetWinVersion()<=WIN_VER_WIN81) if (GetWinVersion()<=WIN_VER_WIN81)
g_DrawThemeBackgroundHook=SetIatHook(module,"uxtheme.dll","DrawThemeBackground",DrawThemeBackground2); g_DrawThemeBackgroundHook=SetIatHook(module,"uxtheme.dll","DrawThemeBackground",DrawThemeBackground2);
g_DrawThemeTextHook=SetIatHook(module,"uxtheme.dll","DrawThemeText",DrawThemeText2); g_DrawThemeTextHook=SetIatHook(module,"uxtheme.dll","DrawThemeText",DrawThemeText2);
g_DrawThemeTextExHook=SetIatHook(module,"uxtheme.dll","DrawThemeTextEx",DrawThemeTextEx2); if (IsAppThemed())
{
g_DrawThemeTextExHook=SetIatHook(module,"uxtheme.dll","DrawThemeTextEx",DrawThemeTextEx2);
}
g_DrawThemeTextCtlHook=SetIatHook(GetModuleHandle(L"comctl32.dll"),"uxtheme.dll","DrawThemeText",DrawThemeText2); g_DrawThemeTextCtlHook=SetIatHook(GetModuleHandle(L"comctl32.dll"),"uxtheme.dll","DrawThemeText",DrawThemeText2);
if (GetWinVersion()>=WIN_VER_WIN10) if (GetWinVersion()>=WIN_VER_WIN10)
g_SetWindowCompositionAttributeHook=SetIatHook(module,"user32.dll","SetWindowCompositionAttribute",SetWindowCompositionAttribute2); g_SetWindowCompositionAttributeHook=SetIatHook(module,"user32.dll","SetWindowCompositionAttribute",SetWindowCompositionAttribute2);
+2 -2
View File
@@ -55,8 +55,8 @@ END_COM_MAP()
STDMETHODIMP InvokeCommand( CMINVOKECOMMANDINFO *pInfo ); STDMETHODIMP InvokeCommand( CMINVOKECOMMANDINFO *pInfo );
STDMETHODIMP GetCommandString( UINT_PTR idCmd, UINT uFlags, UINT* pwReserved, LPSTR pszName, UINT cchMax ); STDMETHODIMP GetCommandString( UINT_PTR idCmd, UINT uFlags, UINT* pwReserved, LPSTR pszName, UINT cchMax );
wchar_t m_PinFolder1[_MAX_PATH]; // ending with \ wchar_t m_PinFolder1[_MAX_PATH]; // ending with backslash
wchar_t m_PinFolder2[_MAX_PATH]; // ending with \ wchar_t m_PinFolder2[_MAX_PATH]; // ending with backslash
wchar_t m_FileName[_MAX_PATH]; wchar_t m_FileName[_MAX_PATH];
LPITEMIDLIST m_FilePidl; LPITEMIDLIST m_FilePidl;
bool m_bInPinFolder1, m_bInPinFolder2; bool m_bInPinFolder1, m_bInPinFolder2;
+1 -1
View File
@@ -21,5 +21,5 @@ deploy:
on: on:
APPVEYOR_ACCOUNT_NAME: passionate-coder APPVEYOR_ACCOUNT_NAME: passionate-coder
auth_token: auth_token:
secure: SOu6Y71k0oIxXJR35x+7ZTrqDa3HqUM4kLNJc+DbohPz9zhVHh9O8QYwmI7LI0qslug5L11fo9pZVfVgZttw4eBgooHaX9TNBTTA6sJItkXqMX+M6mKAG7tbI/O3Eg0v secure: SOu6Y71k0oIxXJR35x+7ZeU/+WRW8kaGnCWcbR3OVOd8HeCJwB1Tw3hUJa5EveLGKaGoMKGqAh01Pwc8tWX4xmphZsYYUr09IVjA0+rqgN5VT87CXD6OQxUxBJ7g+9IN
prerelease: true prerelease: true