[SHLWAPI][SDK][BOOTDATA] Implement SHGetAppCompatFlags (#8137)

Compatibility is a key that the system
works well.
JIRA issue: CORE-19278
- Add appcompat.c.
- Implement SHGetAppCompatFlags
  function.
- Add Str_SetPtrA prototype to
  <commctrl.h>.
- Add SHACF_... flags to
  <shlwapi_undoc.h>.
- Add comctl32 delay import
  (for Str_SetPtrA).
- Modify boot/bootdata/hivesft.inf
  for registry key
  HRESULTKLM\SOFTWARE\Microsoft\
  Windows\CurrentVersion\
  ShellCompatibility\Applications.
This commit is contained in:
Katayama Hirofumi MZ 2025-06-22 09:52:37 +09:00 committed by GitHub
parent 1a11aa059f
commit b199e9d05f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 595 additions and 5 deletions

View file

@ -222,6 +222,85 @@ HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer","NoSimpleStartMenu",0x00010003,1
; Application compatibility
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\coolcat.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\coolcat.exe","Version",2,"4.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\coolcat.exe","ANSIDISPLAYNAMES",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\coreldrw.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\coreldrw.exe","Version",2,"9.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\coreldrw.exe","OLDREGITEMGDN",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\creatr32.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\creatr32.exe","Version",2,"3.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\creatr32.exe","MYCOMPUTERFIRST",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\creatr32.exe","WIN95DEFVIEW",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\creatr32.exe","OLDCREATEVIEWWND",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\creatr32.exe","IGNOREENUMRESET",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\creatr32.exe","RequiredFile",2,"trkwrite.dll"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\cutftp32.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\cutftp32.exe","Version",2,"3.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\cutftp32.exe","OLDREGITEMGDN",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\diskjockey.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\diskjockey.exe","Version",2,"2,*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\diskjockey.exe","OLDREGITEMGDN",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\dlwin.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\dlwin.exe\DownLoader 6.*",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\dlwin.exe\DownLoader 6.*","Version",2,"6.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\dlwin.exe\DownLoader 6.*","FILEOPENBOGUSCTRLID",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\dlwin.exe\DownLoader 7.01",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\dlwin.exe\DownLoader 7.01","Version",2,"7.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\dlwin.exe\DownLoader 7.01","FILEOPENBOGUSCTRLID",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\fusion.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\fusion.exe","Version",2,"5.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\fusion.exe","FILEOPENNEEDSEXT",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\install.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\install.exe\Starcraft 1.03",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\install.exe\Starcraft 1.03","RequiredFile",2,"help\\star.htm"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\install.exe\Starcraft 1.03","Version",2,"Version 1.03"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\install.exe\Starcraft 1.03","OLDREGITEMGDN",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\msdev.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\msdev.exe","Version",2,"6.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\msdev.exe","FILEOPENNEEDSEXT",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\mswin.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\mswin.exe\Metastock 6.*",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\mswin.exe\Metastock 6.*","Version",2,"6.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\mswin.exe\Metastock 6.*","FILEOPENBOGUSCTRLID",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\mswin.exe\Metastock 7.01",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\mswin.exe\Metastock 7.01","Version",2,"7.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\mswin.exe\Metastock 7.01","FILEOPENBOGUSCTRLID",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\photoed.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\photoed.exe","Version",2,"3.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\photoed.exe","FILEOPENNEEDSEXT",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\pwrplay.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\pwrplay.exe","Version",2,"6.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\pwrplay.exe","FILEOPENBOGUSCTRLID",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\qstitch.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\qstitch.exe","Version",2,"1,*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\qstitch.exe","WIN95BINDTOOBJECT",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\qstitch.exe\Version 2",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\qstitch.exe\Version 2","Version",2,"2.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\qstitch.exe\Version 2","WIN95BINDTOOBJECT",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\recycle.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\recycle.exe","Version",2,"1,*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\recycle.exe","FILEOPENNEEDSEXT",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\sesapp.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\sesapp.exe","Version",2,"3.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\sesapp.exe","OLDREGITEMGDN",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\snapshot.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\snapshot.exe","RequiredFile",2,"ssres.dll"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\snapshot.exe","Version",2,"1.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\snapshot.exe","LOADCOLUMNHANDLER",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\trace.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\trace.exe","Version",2,"9.*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\trace.exe","OLDREGITEMGDN",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\uni.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\uni.exe","Version",2,"5, 5,*"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\uni.exe","ANSIDISPLAYNAMES",2,""
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\vcafe.exe",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\vcafe.exe","Version",2,"4.0"
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellCompatibility\Applications\vcafe.exe","FORCELFNIDLIST",2,""
; Extra Control Panel Applets
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Control Panel\Cpls",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Control Panel\Cpls","Console",0x00020000,"%SystemRoot%\system32\console.dll"

View file

@ -8,6 +8,7 @@ add_definitions(
spec2def(shlwapi.dll shlwapi.spec ADD_IMPORTLIB)
list(APPEND SOURCE
appcompat.c
clist.c
istream.c
msgbox.c
@ -50,7 +51,7 @@ add_dependencies(shlwapi_autocomp psdk)
set_module_type(shlwapi win32dll UNICODE)
target_link_libraries(shlwapi uuid wine cpprt)
add_delay_importlibs(shlwapi userenv oleaut32 ole32 comdlg32 mpr mlang urlmon shell32 winmm version)
add_delay_importlibs(shlwapi userenv oleaut32 ole32 comctl32 comdlg32 mpr mlang urlmon shell32 winmm version)
add_importlibs(shlwapi user32 gdi32 advapi32 wininet msvcrt kernel32 ntdll)
add_pch(shlwapi precomp.h "${PCH_SKIP_SOURCE}")
add_cd_file(TARGET shlwapi DESTINATION reactos/system32 FOR all)

View file

@ -0,0 +1,472 @@
/*
* PROJECT: ReactOS Shell
* LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
* PURPOSE: Shell application compatibility flags
* COPYRIGHT: Copyright 2025 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*/
#include "precomp.h"
#include <winreg.h>
#include <winver.h>
#include <commctrl.h>
#include <shlwapi_undoc.h>
WINE_DEFAULT_DEBUG_CHANNEL(shell);
// Indicates if the compatibility system has been initialized
static BOOL g_fAppCompatInitialized = FALSE;
static DWORD g_dwAppCompatFlags = 0; // Cached compatibility flags
// SHACF flags and their corresponding names
typedef struct tagFLAGMAP
{
DWORD flags;
LPCSTR name;
} FLAGMAP, *PFLAGMAP;
static FLAGMAP g_appCompatFlagMaps[] =
{
{ SHACF_CONTEXTMENU, "CONTEXTMENU" },
{ SHACF_CORELINTERNETENUM, "CORELINTERNETENUM" },
{ SHACF_OLDCREATEVIEWWND, "OLDCREATEVIEWWND" },
{ SHACF_WIN95DEFVIEW, "WIN95DEFVIEW" },
{ SHACF_DOCOBJECT, "DOCOBJECT" },
{ SHACF_FLUSHNOWAITALWAYS, "FLUSHNOWAITALWAYS" },
{ SHACF_MYCOMPUTERFIRST, "MYCOMPUTERFIRST" },
{ SHACF_OLDREGITEMGDN, "OLDREGITEMGDN" },
{ SHACF_LOADCOLUMNHANDLER, "LOADCOLUMNHANDLER" },
{ SHACF_ANSI, "ANSI" },
{ SHACF_STAROFFICE5PRINTER, "STAROFFICE5PRINTER" },
{ SHACF_NOVALIDATEFSIDS, "NOVALIDATEFSIDS" },
{ SHACF_WIN95SHLEXEC, "WIN95SHLEXEC" },
{ SHACF_FILEOPENNEEDSEXT, "FILEOPENNEEDSEXT" },
{ SHACF_WIN95BINDTOOBJECT, "WIN95BINDTOOBJECT" },
{ SHACF_IGNOREENUMRESET, "IGNOREENUMRESET" },
{ SHACF_ANSIDISPLAYNAMES, "ANSIDISPLAYNAMES" },
{ SHACF_FILEOPENBOGUSCTRLID, "FILEOPENBOGUSCTRLID" },
{ SHACF_FORCELFNIDLIST, "FORCELFNIDLIST" },
};
// Get compatibility flags from registry values
static DWORD
SHLWAPI_GetMappedFlags(_In_ HKEY hKey, _In_ const FLAGMAP *pEntries, _In_ UINT nEntries)
{
DWORD flags = 0;
for (UINT iEntry = 0; iEntry < nEntries; ++iEntry)
{
DWORD error = SHGetValueA(hKey, NULL, pEntries[iEntry].name, NULL, NULL, NULL);
if (error == ERROR_SUCCESS)
flags |= pEntries[iEntry].flags;
}
return flags;
}
#define MAJOR_VER_ONLY "\x01" // A mark to indicate that only major version will be compared.
// App compatibility info
// Extracted from: https://www.geoffchappell.com/studies/windows/shell/shlwapi/api/util/getappcompatflags.htm
typedef struct tagAPPCOMPATINFO
{
PCSTR pszAppName;
PCSTR pszAppVersion;
DWORD dwCompatFlags;
} APPCOMPATINFO, *PAPPCOMPATINFO;
static APPCOMPATINFO g_appCompatInfo[] =
{
{ "abcmm.exe", NULL, SHACF_LOADCOLUMNHANDLER },
{ "autorun.exe", "4.00.950", SHACF_ANSI },
{ "autorun.exe", "4.10.1998", SHACF_ANSI },
{ "coreldrw.exe", MAJOR_VER_ONLY "7", SHACF_OLDREGITEMGDN },
{ "dad9.exe", MAJOR_VER_ONLY "9", SHACF_CORELINTERNETENUM },
{ "filler51.exe", NULL, SHACF_OLDREGITEMGDN },
{ "hotdog4.exe", NULL, SHACF_DOCOBJECT },
{ "msmoney.exe", "7.05.1107", SHACF_WIN95SHLEXEC },
{ "pdexplo.exe", MAJOR_VER_ONLY "1", SHACF_CONTEXTMENU | SHACF_MYCOMPUTERFIRST },
{ "pdexplo.exe", MAJOR_VER_ONLY "2", SHACF_CONTEXTMENU | SHACF_MYCOMPUTERFIRST },
{ "pdexplo.exe", MAJOR_VER_ONLY "3", SHACF_MYCOMPUTERFIRST | SHACF_OLDREGITEMGDN },
{ "pdxwin32.exe", NULL, SHACF_CONTEXTMENU | SHACF_CORELINTERNETENUM | SHACF_OLDREGITEMGDN },
{ "pfim80.exe", NULL, SHACF_CONTEXTMENU | SHACF_CORELINTERNETENUM | SHACF_OLDREGITEMGDN },
{ "powerpnt.exe", MAJOR_VER_ONLY "8", SHACF_WIN95SHLEXEC },
{ "pp70.exe", NULL, SHACF_LOADCOLUMNHANDLER },
{ "pp80.exe", NULL, SHACF_LOADCOLUMNHANDLER },
{ "prwin70.exe", NULL, SHACF_CONTEXTMENU | SHACF_CORELINTERNETENUM },
{ "prwin8.exe", NULL, SHACF_CORELINTERNETENUM | SHACF_OLDREGITEMGDN },
{ "prwin9.exe", MAJOR_VER_ONLY "9", SHACF_CORELINTERNETENUM },
{ "ps80.exe", NULL, SHACF_CONTEXTMENU | SHACF_CORELINTERNETENUM | SHACF_OLDREGITEMGDN },
{ "ps80.exe", NULL, SHACF_OLDREGITEMGDN },
{ "qfinder.exe", NULL, SHACF_CORELINTERNETENUM | SHACF_OLDREGITEMGDN },
{ "qpw.exe", MAJOR_VER_ONLY "7", SHACF_CONTEXTMENU },
{ "qpw.exe", MAJOR_VER_ONLY "8", SHACF_CORELINTERNETENUM | SHACF_OLDREGITEMGDN | SHACF_ANSIDISPLAYNAMES },
{ "qpw.exe", MAJOR_VER_ONLY "9", SHACF_CORELINTERNETENUM },
{ "rnaapp.exe", NULL, SHACF_CONTEXTMENU },
{ "sitebuilder.exe", NULL, SHACF_CONTEXTMENU | SHACF_CORELINTERNETENUM | SHACF_OLDREGITEMGDN },
{ "sizemgr.exe", MAJOR_VER_ONLY "3", SHACF_CORELINTERNETENUM | SHACF_OLDREGITEMGDN },
{ "smartctr.exe", "96.0", SHACF_CONTEXTMENU },
{ "soffice.exe", MAJOR_VER_ONLY "5", SHACF_STAROFFICE5PRINTER },
{ "ua80.exe", NULL, SHACF_CONTEXTMENU | SHACF_CORELINTERNETENUM | SHACF_OLDREGITEMGDN },
{ "ue32.exe", "2.00.0.0", SHACF_OLDREGITEMGDN },
{ "wpwin7.exe", NULL, SHACF_CONTEXTMENU | SHACF_CORELINTERNETENUM },
{ "wpwin8.exe", NULL, SHACF_CORELINTERNETENUM | SHACF_OLDREGITEMGDN },
{ "wpwin9.exe", MAJOR_VER_ONLY "9", SHACF_CORELINTERNETENUM },
};
// Window class name and compatibility flags
typedef struct tagWNDCOMPATINFO
{
PCSTR pszLengthAndClassName;
DWORD dwCompatFlags;
} WNDCOMPATINFO, *PWNDCOMPATINFO;
static WNDCOMPATINFO g_wndCompatInfo[] =
{
// The first byte indicates the string length
{ "\x09" "bosa_sdm_", SHACF_UNKNOWN1 | SHACF_UNKNOWN2 },
{ "\x18" "File Open Message Window", SHACF_UNKNOWN1 | SHACF_UNKNOWN2 },
};
// Internal structure for SHLWAPI_WndCompatEnumProc
typedef struct tagAPPCOMPATENUM
{
PWNDCOMPATINFO pItems;
SIZE_T nItems;
DWORD dwProcessId;
INT iFound;
} APPCOMPATENUM, *PAPPCOMPATENUM;
static BOOL CALLBACK
SHLWAPI_WndCompatEnumProc(_In_ HWND hWnd, _In_ LPARAM lParam)
{
PAPPCOMPATENUM pEnum = (PAPPCOMPATENUM)lParam;
CHAR szClass[256];
if (!pEnum->nItems || !GetClassNameA(hWnd, szClass, _countof(szClass)))
return TRUE; // Ignore and continue
// Search for the target window in pEnum
const INT cchClass = lstrlenA(szClass);
for (UINT iItem = 0; iItem < pEnum->nItems; ++iItem)
{
PCSTR pszLengthAndClassName = pEnum->pItems[iItem].pszLengthAndClassName;
INT cchLength = pszLengthAndClassName[0]; // The first byte represents the length
if (cchClass < cchLength)
cchLength = cchClass; // Ignore trailing characters
// Compare the string
if (StrCmpNA(szClass, &pszLengthAndClassName[1], cchLength) == 0) // Class name matched
{
// Get the process ID
DWORD dwProcessId;
GetWindowThreadProcessId(hWnd, &dwProcessId);
if (dwProcessId == pEnum->dwProcessId) // Same process
{
pEnum->iFound = iItem; // Found
return FALSE; // Quit enumeration
}
}
}
return TRUE; // Continue enumeration
}
// English (US) UTF-16
#define PRODUCT_VER_ENGLISH_US_UTF16 "\\StringFileInfo\\040904E4\\ProductVersion"
// German (Germany) UTF-16
#define PRODUCT_VER_GERMAN_UTF16 "\\StringFileInfo\\040704E4\\ProductVersion"
// English (US) Western European
#define PRODUCT_VER_ENGLISH_US_WE "\\StringFileInfo\\040904B0\\ProductVersion"
// English (US) Neutral
#define PRODUCT_VER_ENGLISH_US_NEUTRAL "\\StringFileInfo\\04090000\\ProductVersion"
// Swedish (Sweden) Western European
#define PRODUCT_VER_SWEDISH_WE "\\StringFileInfo\\041D04B0\\ProductVersion"
typedef struct tagLANGANDCODEPAGE
{
WORD wLanguage;
WORD wCodePage;
} LANGANDCODEPAGE, *PLANGANDCODEPAGE;
static HRESULT
SHLWAPI_GetModuleVersion(_In_ PCSTR pszFileName, _Out_ PSTR *ppszDest)
{
DWORD dwHandle;
PBYTE pbData;
PVOID pvData;
*ppszDest = NULL;
// Obtain the version info
UINT size = GetFileVersionInfoSizeA(pszFileName, &dwHandle);
if (!size)
{
TRACE("No version info\n");
return E_FAIL;
}
pbData = (PBYTE)LocalAlloc(LPTR, size);
if (!pbData)
{
ERR("E_OUTOFMEMORY\n");
return E_OUTOFMEMORY;
}
GetFileVersionInfoA(pszFileName, dwHandle, size, pbData);
// Getting the product version
HRESULT hr = E_FAIL;
if ((VerQueryValueA(pbData, PRODUCT_VER_ENGLISH_US_UTF16, &pvData, &size) ||
VerQueryValueA(pbData, PRODUCT_VER_GERMAN_UTF16, &pvData, &size) ||
VerQueryValueA(pbData, PRODUCT_VER_ENGLISH_US_WE, &pvData, &size) ||
VerQueryValueA(pbData, PRODUCT_VER_ENGLISH_US_NEUTRAL, &pvData, &size) ||
VerQueryValueA(pbData, PRODUCT_VER_SWEDISH_WE, &pvData, &size)) && size)
{
// NOTE: *ppszDest must be freed using LocalFree later
*ppszDest = StrDupA((PSTR)pvData);
hr = *ppszDest ? S_OK : E_OUTOFMEMORY;
}
else if (VerQueryValueA(pbData, "\\VarFileInfo\\Translation", &pvData, &size))
{
PVOID pDataSaved = pvData;
PLANGANDCODEPAGE pEntry = (PLANGANDCODEPAGE)pvData;
for (; (PBYTE)pEntry + sizeof(LANGANDCODEPAGE) <= (PBYTE)pDataSaved + size; ++pEntry)
{
CHAR szPath[MAX_PATH];
wnsprintfA(szPath, _countof(szPath), "\\StringFileInfo\\%04X%04X\\ProductVersion",
pEntry->wLanguage, pEntry->wCodePage);
if (VerQueryValueA(pbData, szPath, &pvData, &size) && size)
{
// NOTE: *ppszDest must be freed using LocalFree later
*ppszDest = StrDupA((PSTR)pvData);
hr = *ppszDest ? S_OK : E_OUTOFMEMORY;
}
}
}
if (FAILED(hr))
WARN("hr: 0x%lX\n", hr);
LocalFree(pbData);
return hr;
}
static BOOL
SHLWAPI_DoesModuleVersionMatch(_In_ PCSTR pszFileName, _In_opt_ PCSTR pszVersionPattern)
{
if (!pszVersionPattern)
return TRUE;
PSTR pszModuleVersion = NULL;
HRESULT hr = SHLWAPI_GetModuleVersion(pszFileName, &pszModuleVersion);
if (FAILED(hr))
return FALSE;
BOOL ret = FALSE;
if (pszVersionPattern[0] == MAJOR_VER_ONLY[0]) // Special handling for major version only
{
// Truncate at comma (',') if present
PSTR pchComma = StrChrA(pszModuleVersion, ',');
if (pchComma)
*pchComma = ANSI_NULL;
// Truncate at dot ('.') if present
PSTR pchDot = StrChrA(pszModuleVersion, '.');
if (pchDot)
*pchDot = ANSI_NULL;
ret = (lstrcmpiA(pszModuleVersion, &pszVersionPattern[1]) == 0);
}
else // Otherwise, perform a normal match
{
PSTR pchAsterisk = StrChrA(pszVersionPattern, '*'); // Find an asterisk ('*')
if (pchAsterisk) // Asterisk found
{
// Check for a match, ignoring the substring after '*'
INT cchPrefix = (INT)(pchAsterisk - pszVersionPattern);
if (cchPrefix > 0)
ret = (StrCmpNIA(pszModuleVersion, pszVersionPattern, cchPrefix) == 0);
}
if (!ret)
ret = (lstrcmpiA(pszModuleVersion, pszVersionPattern) == 0); // Full match
}
LocalFree(pszModuleVersion);
return ret;
}
static DWORD
SHLWAPI_GetRegistryCompatFlags(_In_ PCSTR pszPath)
{
// Build the path to the "application compatibility" registry key
CHAR szText[MAX_PATH];
wnsprintfA(szText, _countof(szText),
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Applications\\%s",
PathFindFileNameA(pszPath));
// Open the key
HKEY hKey;
const REGSAM samDesired = KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS;
LSTATUS error = RegOpenKeyExA(HKEY_LOCAL_MACHINE, szText, 0, samDesired, &hKey);
if (error != ERROR_SUCCESS)
{
ERR("error: %lu\n", error);
return 0; // Failed
}
// Build the base directory
CHAR szBaseDir[MAX_PATH];
lstrcpynA(szBaseDir, pszPath, _countof(szBaseDir));
PathRemoveFileSpecA(szBaseDir);
// Search from the registry key
DWORD dwCompatFlags = 0;
szText[0] = ANSI_NULL; // The first attempt is for the non-subkey path
for (DWORD dwIndex = 0; error == ERROR_SUCCESS;)
{
HKEY hSubKey;
error = RegOpenKeyExA(hKey, szText, 0, KEY_QUERY_VALUE, &hSubKey);
if (error != ERROR_SUCCESS)
break;
// Get the "RequiredFile" value
CHAR szRequired[MAX_PATH];
DWORD cbData = sizeof(szRequired);
error = SHGetValueA(hSubKey, NULL, "RequiredFile", NULL, szRequired, &cbData);
BOOL bValueExists = (error == ERROR_SUCCESS);
BOOL bRequiredFileExists = FALSE;
if (bValueExists) // Does the "RequiredFile" value exist?
{
// Build required file path to szText
PathCombineA(szText, szBaseDir, szRequired);
TRACE("RequiredFile: %s\n", wine_dbgstr_a(szRequired));
TRACE("szText: %s\n", wine_dbgstr_a(szText));
// Now szText is a full path
bRequiredFileExists = (GetFileAttributesA(szText) != INVALID_FILE_ATTRIBUTES);
}
// If the "RequiredFile" value doesn't exist, or the file specified by szText exists:
if (!bValueExists || bRequiredFileExists)
{
// Check the "Version" value if necessary
error = SHGetValueA(hSubKey, NULL, "Version", NULL, szText, &cbData);
PCSTR pszVersionPattern = ((error == ERROR_SUCCESS) ? szText : NULL);
TRACE("pszVersionPattern: %s\n", wine_dbgstr_a(pszVersionPattern));
// Does the pattern match?
if (SHLWAPI_DoesModuleVersionMatch(pszPath, pszVersionPattern))
{
// Add additional flags from the registry key
dwCompatFlags |= SHLWAPI_GetMappedFlags(hSubKey, g_appCompatFlagMaps,
_countof(g_appCompatFlagMaps));
}
}
RegCloseKey(hSubKey);
// Go to the next sub-key
++dwIndex;
error = RegEnumKeyA(hKey, dwIndex, szText, _countof(szText));
}
RegCloseKey(hKey);
return dwCompatFlags;
}
static DWORD
SHLWAPI_InitAppCompat(VOID)
{
if (GetProcessVersion(0) >= MAKELONG(0, 5))
return 0; // Flags are not needed
// Get module pathname
CHAR szModulePathA[MAX_PATH];
if (!GetModuleFileNameA(NULL, szModulePathA, _countof(szModulePathA)))
return 0;
PCSTR pszFileName = PathFindFileNameA(szModulePathA); // Get the file title from the path
// Search the file title from g_appCompatInfo
DWORD dwAppCompatFlags = 0;
for (UINT iItem = 0; iItem < _countof(g_appCompatInfo); ++iItem)
{
const APPCOMPATINFO *pInfo = &g_appCompatInfo[iItem];
if (lstrcmpiA(pInfo->pszAppName, pszFileName) == 0 &&
SHLWAPI_DoesModuleVersionMatch(pszFileName, pInfo->pszAppVersion))
{
// Found, set the flags
dwAppCompatFlags = g_appCompatInfo[iItem].dwCompatFlags;
break;
}
}
// Add additional flags from the registry
dwAppCompatFlags |= SHLWAPI_GetRegistryCompatFlags(pszFileName);
return dwAppCompatFlags;
}
// These flags require SHLWAPI_InitAppCompat
#define SHACF_TO_INIT ( \
SHACF_CONTEXTMENU | \
SHACF_DOCOBJECT | \
SHACF_CORELINTERNETENUM | \
SHACF_MYCOMPUTERFIRST | \
SHACF_OLDREGITEMGDN | \
SHACF_LOADCOLUMNHANDLER | \
SHACF_ANSI | \
SHACF_WIN95SHLEXEC | \
SHACF_STAROFFICE5PRINTER | \
SHACF_NOVALIDATEFSIDS | \
SHACF_FILEOPENNEEDSEXT | \
SHACF_WIN95BINDTOOBJECT | \
SHACF_IGNOREENUMRESET | \
SHACF_ANSIDISPLAYNAMES | \
SHACF_FILEOPENBOGUSCTRLID | \
SHACF_FORCELFNIDLIST \
)
/*************************************************************************
* SHGetAppCompatFlags [SHLWAPI.461]
*
* Thanks to Geoff Chappell.
* @see https://www.geoffchappell.com/studies/windows/shell/shlwapi/api/util/getappcompatflags.htm
*/
DWORD WINAPI
SHGetAppCompatFlags(_In_ DWORD dwMask)
{
TRACE("(0x%lX)\n", dwMask);
// Initialize and retrieve flags if necessary
if (dwMask & SHACF_TO_INIT)
{
if (!g_fAppCompatInitialized)
{
DWORD dwAppCompatFlags = SHLWAPI_InitAppCompat();
InterlockedExchange((PLONG)&g_dwAppCompatFlags, dwAppCompatFlags);
g_fAppCompatInitialized = TRUE; // Mark as initialized
}
}
// Retrieve additional flags if necessary
DWORD dwAppCompatFlags = g_dwAppCompatFlags;
if (dwAppCompatFlags && (dwMask & (SHACF_UNKNOWN1 | SHACF_UNKNOWN2)))
{
// Find the target window and its flags using g_wndCompatInfo
APPCOMPATENUM data =
{
g_wndCompatInfo, _countof(g_wndCompatInfo), GetCurrentProcessId(), -1
};
EnumWindows(SHLWAPI_WndCompatEnumProc, (LPARAM)&data);
// Add the target flags if a match is found
if (data.iFound >= 0)
dwAppCompatFlags |= g_wndCompatInfo[data.iFound].dwCompatFlags;
dwAppCompatFlags |= SHACF_UNKNOWN3;
InterlockedExchange((PLONG)&g_dwAppCompatFlags, dwAppCompatFlags);
}
return dwAppCompatFlags;
}
// FIXME: SHGetObjectCompatFlags

View file

@ -4725,7 +4725,7 @@ VOID WINAPI FixSlashesAndColonW(LPWSTR lpwstr)
}
}
#ifndef __REACTOS__ /* See appcompat.c */
/*************************************************************************
* @ [SHLWAPI.461]
*/
@ -4734,7 +4734,7 @@ DWORD WINAPI SHGetAppCompatFlags(DWORD dwUnknown)
FIXME("(0x%08x) stub\n", dwUnknown);
return 0;
}
#endif
/*************************************************************************
* @ [SHLWAPI.549]

View file

@ -4879,12 +4879,24 @@ typedef struct {
_In_ LPARAM lParam,
_In_ UINT options);
WINCOMMCTRLAPI
BOOL
WINAPI Str_SetPtrA(
_Inout_ LPSTR *ppsz,
_In_opt_ LPCSTR psz);
WINCOMMCTRLAPI
BOOL
WINAPI Str_SetPtrW(
_Inout_ LPWSTR *ppsz,
_In_opt_ LPCWSTR psz);
#ifdef UNICODE
#define Str_SetPtr Str_SetPtrW
#else
#define Str_SetPtr Str_SetPtrA
#endif
typedef struct _DPASTREAMINFO {
int iPos;
void *pvItem;

View file

@ -397,8 +397,34 @@ HRESULT WINAPI SHRunIndirectRegClientCommand(_In_ HWND hWnd, _In_ PCWSTR pszClie
DWORD WINAPI SHGetObjectCompatFlags(IUnknown *pUnk, const CLSID *clsid);
#define SHACF_WIN95SHLEXEC 0x00000200 /* Geoff Chappell */
DWORD WINAPI SHGetAppCompatFlags(DWORD dwMask);
/* Flags for SHGetAppCompatFlags */
#define SHACF_CONTEXTMENU 0x00000001
#define SHACF_FLUSHNOWAITALWAYS SHACF_CONTEXTMENU
#define SHACF_DOCOBJECT 0x00000002
#define SHACF_CORELINTERNETENUM 0x00000004
#define SHACF_OLDCREATEVIEWWND SHACF_CORELINTERNETENUM
#define SHACF_WIN95DEFVIEW SHACF_CORELINTERNETENUM
#define SHACF_MYCOMPUTERFIRST 0x00000008
#define SHACF_OLDREGITEMGDN 0x00000010
// 0x00000020
#define SHACF_LOADCOLUMNHANDLER 0x00000040
#define SHACF_ANSI 0x00000080
#define SHACF_UNKNOWN1 0x00000100
#define SHACF_WIN95SHLEXEC 0x00000200
#define SHACF_STAROFFICE5PRINTER 0x00000400
#define SHACF_NOVALIDATEFSIDS 0x00000800
#define SHACF_FILEOPENNEEDSEXT 0x00001000
#define SHACF_WIN95BINDTOOBJECT 0x00002000
#define SHACF_IGNOREENUMRESET 0x00004000
// 0x00008000
#define SHACF_ANSIDISPLAYNAMES 0x00010000
#define SHACF_FILEOPENBOGUSCTRLID 0x00020000
#define SHACF_FORCELFNIDLIST 0x00040000
// 0x00080000
#define SHACF_UNKNOWN2 0x01000000
#define SHACF_UNKNOWN3 0x80000000
DWORD WINAPI SHGetAppCompatFlags(_In_ DWORD dwMask);
/*****************************************************************************
* IAssociationElementOld interface