[ACPPAGE] Implement the base of the compatibility tab in explorer as shell extension.
authorMark Jansen <mark.jansen@reactos.org>
Sat, 9 Apr 2016 21:40:32 +0000 (21:40 +0000)
committerMark Jansen <mark.jansen@reactos.org>
Sat, 9 Apr 2016 21:40:32 +0000 (21:40 +0000)
Because the underlying shim infrastructure is not active yet, the page is disabled by default.
Hello Reactos :)
CORE-10375

svn path=/trunk/; revision=71131

13 files changed:
reactos/dll/appcompat/apphelp/apphelp.h
reactos/dll/shellext/CMakeLists.txt
reactos/dll/shellext/acppage/ACPPage.cpp [new file with mode: 0644]
reactos/dll/shellext/acppage/ACPPage.rc [new file with mode: 0644]
reactos/dll/shellext/acppage/CLayerUIPropPage.cpp [new file with mode: 0644]
reactos/dll/shellext/acppage/CLayerUIPropPage.hpp [new file with mode: 0644]
reactos/dll/shellext/acppage/CMakeLists.txt [new file with mode: 0644]
reactos/dll/shellext/acppage/acppage.spec [new file with mode: 0644]
reactos/dll/shellext/acppage/lang/en-US.rc [new file with mode: 0644]
reactos/dll/shellext/acppage/precomp.h [new file with mode: 0644]
reactos/dll/shellext/acppage/res/acppage.rgs [new file with mode: 0644]
reactos/dll/shellext/acppage/resource.h [new file with mode: 0644]
reactos/media/inf/syssetup.inf

index 8bed7b6..e04de01 100644 (file)
@@ -64,6 +64,13 @@ void SdbpFree(LPVOID mem);
 
 #endif
 
+
+/* layer.c */
+BOOL WINAPI AllowPermLayer(PCWSTR path);
+BOOL WINAPI SdbGetPermLayerKeys(PCWSTR wszPath, PWSTR pwszLayers, PDWORD pdwBytes, DWORD dwFlags);
+BOOL WINAPI SetPermLayerState(PCWSTR wszPath, PCWSTR wszLayer, DWORD dwFlags, BOOL bMachine, BOOL bEnable);
+
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 07c20ef..1049d5b 100644 (file)
@@ -1,4 +1,5 @@
 
+add_subdirectory(acppage)
 add_subdirectory(deskadp)
 add_subdirectory(deskmon)
 add_subdirectory(devcpux)
diff --git a/reactos/dll/shellext/acppage/ACPPage.cpp b/reactos/dll/shellext/acppage/ACPPage.cpp
new file mode 100644 (file)
index 0000000..7ff5378
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2015 Mark Jansen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "precomp.h"
+
+HMODULE g_hModule = NULL;
+LONG g_ModuleRefCnt = 0;
+
+class CLayerUIPropPageModule : public CComModule
+{
+public:
+    void Term()
+    {
+        CComModule::Term();
+    }
+};
+
+BEGIN_OBJECT_MAP(ObjectMap)
+    OBJECT_ENTRY(CLSID_CLayerUIPropPage, CLayerUIPropPage)
+END_OBJECT_MAP()
+
+CLayerUIPropPageModule gModule;
+
+EXTERN_C
+BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
+{
+    switch (dwReason)
+    {
+    case DLL_PROCESS_ATTACH:
+        DisableThreadLibraryCalls(hInstance);
+        g_hModule = hInstance;
+        gModule.Init(ObjectMap, hInstance, NULL);
+        break;
+    }
+
+    return(TRUE);
+}
+
+STDAPI DllCanUnloadNow()
+{
+    if (g_ModuleRefCnt)
+        return S_FALSE;
+    return gModule.DllCanUnloadNow();
+}
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
+{
+    return gModule.DllGetClassObject(rclsid, riid, ppv);
+}
+
+STDAPI DllRegisterServer()
+{
+    HRESULT hr;
+
+    hr = gModule.DllRegisterServer(FALSE);
+    if (FAILED(hr))
+        return hr;
+
+    hr = gModule.UpdateRegistryFromResource(IDR_ACPPAGE, TRUE, NULL);
+    if (FAILED(hr))
+        return hr;
+
+    return S_OK;
+}
+
+STDAPI DllUnregisterServer()
+{
+    HRESULT hr;
+
+    hr = gModule.DllUnregisterServer(FALSE);
+    if (FAILED(hr))
+        return hr;
+
+    hr = gModule.UpdateRegistryFromResource(IDR_ACPPAGE, FALSE, NULL);
+    if (FAILED(hr))
+        return hr;
+
+    return S_OK;
+}
+
+struct CCoInit
+{
+    CCoInit() { hres = CoInitialize(NULL); }
+    ~CCoInit() { if (SUCCEEDED(hres)) { CoUninitialize(); } }
+    HRESULT hres;
+};
+
+EXTERN_C
+BOOL WINAPI GetExeFromLnk(PCWSTR pszLnk, PWSTR pszExe, size_t cchSize)
+{
+    CCoInit init;
+    if (FAILED(init.hres))
+        return FALSE;
+
+    CComPtr<IShellLinkW> spShellLink;
+    if (FAILED(CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLinkW, &spShellLink))))
+        return FALSE;
+
+    CComPtr<IPersistFile> spPersistFile;
+    if (FAILED(spShellLink->QueryInterface(IID_PPV_ARG(IPersistFile, &spPersistFile))))
+        return FALSE;
+
+    if (FAILED(spPersistFile->Load(pszLnk, STGM_READ)) || FAILED(spShellLink->Resolve(NULL, SLR_NO_UI | SLR_NOUPDATE | SLR_NOSEARCH)))
+        return FALSE;
+
+    return SUCCEEDED(spShellLink->GetPath(pszExe, cchSize, NULL, SLGP_RAWPATH));
+}
diff --git a/reactos/dll/shellext/acppage/ACPPage.rc b/reactos/dll/shellext/acppage/ACPPage.rc
new file mode 100644 (file)
index 0000000..d19e022
--- /dev/null
@@ -0,0 +1,87 @@
+#include <windef.h>
+#include <winuser.h>
+
+#include "resource.h"
+
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION  "ReactOS Compatibility Layer Shell Extension"
+#define REACTOS_STR_INTERNAL_NAME     "acppage"
+#define REACTOS_STR_ORIGINAL_FILENAME "acppage.dll"
+#include <reactos/version.rc>
+
+#include <reactos/manifest_dll.rc>
+
+IDR_ACPPAGE REGISTRY "res/acppage.rgs"
+
+/* UTF-8 */
+#pragma code_page(65001)
+/*
+#ifdef LANGUAGE_BG_BG
+    #include "lang/bg-BG.rc"
+#endif
+#ifdef LANGUAGE_CS_CZ
+    #include "lang/cs-CZ.rc"
+#endif
+#ifdef LANGUAGE_DE_DE
+    #include "lang/de-DE.rc"
+#endif
+*/
+#ifdef LANGUAGE_EN_US
+    #include "lang/en-US.rc"
+#endif
+/*
+#ifdef LANGUAGE_ES_ES
+    #include "lang/es-ES.rc"
+#endif
+#ifdef LANGUAGE_EU_ES
+    #include "lang/eu-ES.rc"
+#endif
+#ifdef LANGUAGE_FR_FR
+    #include "lang/fr-FR.rc"
+#endif
+#ifdef LANGUAGE_HE_IL
+    #include "lang/he-IL.rc"
+#endif
+#ifdef LANGUAGE_HU_HU
+    #include "lang/hu-HU.rc"
+#endif
+#ifdef LANGUAGE_ID_ID
+    #include "lang/id-ID.rc"
+#endif
+#ifdef LANGUAGE_IT_IT
+    #include "lang/it-IT.rc"
+#endif
+#ifdef LANGUAGE_NL_NL
+    #include "lang/nl-NL.rc"
+#endif
+#ifdef LANGUAGE_NB_NO
+    #include "lang/no-NO.rc"
+#endif
+#ifdef LANGUAGE_PL_PL
+    #include "lang/pl-PL.rc"
+#endif
+#ifdef LANGUAGE_RO_RO
+    #include "lang/ro-RO.rc"
+#endif
+#ifdef LANGUAGE_RU_RU
+    #include "lang/ru-RU.rc"
+#endif
+#ifdef LANGUAGE_SK_SK
+    #include "lang/sk-SK.rc"
+#endif
+#ifdef LANGUAGE_SQ_AL
+    #include "lang/sq-AL.rc"
+#endif
+#ifdef LANGUAGE_SV_SE
+    #include "lang/sv-SE.rc"
+#endif
+#ifdef LANGUAGE_TR_TR
+    #include "lang/tr-TR.rc"
+#endif
+#ifdef LANGUAGE_UK_UA
+    #include "lang/uk-UA.rc"
+#endif
+#ifdef LANGUAGE_ZH_CN
+    #include "lang/zh-CN.rc"
+#endif
+*/
\ No newline at end of file
diff --git a/reactos/dll/shellext/acppage/CLayerUIPropPage.cpp b/reactos/dll/shellext/acppage/CLayerUIPropPage.cpp
new file mode 100644 (file)
index 0000000..6584a14
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Copyright 2015 Mark Jansen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "precomp.h"
+#include <windowsx.h>
+#include <sfc.h>
+
+const GUID CLSID_CLayerUIPropPage = { 0x513D916F, 0x2A8E, 0x4F51, { 0xAE, 0xAB, 0x0C, 0xBC, 0x76, 0xFB, 0x1A, 0xF8 } };
+#define ACP_WNDPROP L"{513D916F-2A8E-4F51-AEAB-0CBC76FB1AF8}.Prop"
+
+#define GPLK_USER 1
+#define GPLK_MACHINE 2
+#define MAX_LAYER_LENGTH 256
+
+void ACDBG_FN(PCSTR FunctionName, PCWSTR Format, ...)
+{
+    WCHAR Buffer[512];
+    WCHAR* Current = Buffer;
+    size_t Length = _countof(Buffer);
+
+    StringCchPrintfExW(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, L"[%-20S] ", FunctionName);
+    va_list ArgList;
+    va_start(ArgList, Format);
+    StringCchVPrintfExW(Current, Length, &Current, &Length, STRSAFE_NULL_ON_FAILURE, Format, ArgList);
+    va_end(ArgList);
+    OutputDebugStringW(Buffer);
+}
+
+#define ACDBG(fmt, ...)  ACDBG_FN(__FUNCTION__, fmt, ##__VA_ARGS__ )
+
+
+
+CLayerUIPropPage::CLayerUIPropPage()
+:m_Filename(NULL)
+, m_IsSfcProtected(FALSE)
+, m_AllowPermLayer(FALSE)
+, m_LayerQueryFlags(GPLK_USER)
+, m_RegistryOSMode(0)
+, m_OSMode(0)
+, m_RegistryEnabledLayers(0)
+, m_EnabledLayers(0)
+{
+}
+
+CLayerUIPropPage::~CLayerUIPropPage()
+{
+}
+
+
+#if 0
+HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers
+WINXPSP3 256COLOR 640X480 DISABLETHEMES DISABLEDWM HIGHDPIAWARE RUNASADMIN
+#endif
+
+static struct {
+    const PCWSTR Display;
+    const PCWSTR Name;
+} g_CompatModes[] = {
+    { L"Windows 95", L"WIN95" },
+    { L"Windows 98", L"WIN98" },
+    { L"Windows NT 4.0 (SP5)", L"NT4SP5" },
+    { L"Windows 2000", L"WIN2000" },
+    { L"Windows XP (SP2)", L"WINXPSP2" },
+    { L"Windows XP (SP3)", L"WINXPSP3" },
+    { L"Windows Server 2003 (SP1)", L"WINSRV03SP1" },
+#if 0
+    { L"Windows Server 2008 (SP1)", L"WINSRV08SP1" },
+    { L"Windows Vista", L"VISTARTM" },
+    { L"Windows Vista (SP1)", L"VISTASP1" },
+    { L"Windows Vista (SP2)", L"VISTASP2" },
+    { L"Windows 7", L"WIN7RTM" },
+#endif
+    { NULL, NULL }
+};
+
+static struct {
+    const PCWSTR Name;
+    DWORD Id;
+    BOOL Enabled;
+} g_Layers[] = {
+    { L"256COLOR", IDC_CHKRUNIN256COLORS, TRUE },
+    { L"640X480", IDC_CHKRUNIN640480RES, TRUE },
+    { L"DISABLETHEMES", IDC_CHKDISABLEVISUALTHEMES, TRUE },
+    { NULL, 0, FALSE }
+};
+
+static const WCHAR* g_AllowedExtensions[] = {
+    L".exe",
+    L".msi",
+    L".pif",
+    L".bat",
+    L".cmd",
+    0
+};
+
+HRESULT CLayerUIPropPage::InitFile(PCWSTR Filename)
+{
+    PCWSTR pwszExt = PathFindExtensionW(Filename);
+    if (!pwszExt)
+    {
+        ACDBG(L"Failed to find an extension: '%s'\r\n", Filename);
+        return E_FAIL;
+    }
+    if (!wcsicmp(pwszExt, L".lnk"))
+    {
+        WCHAR Buffer[MAX_PATH];
+        if (!GetExeFromLnk(Filename, Buffer, _countof(Buffer)))
+        {
+            ACDBG(L"Failed to read link target from: '%s'\r\n", Filename);
+            return E_FAIL;
+        }
+        if (!wcsicmp(Buffer, Filename))
+        {
+            ACDBG(L"Link redirects to itself: '%s'\r\n", Filename);
+            return E_FAIL;
+        }
+        return InitFile(Buffer);
+    }
+    for (size_t n = 0; g_AllowedExtensions[n]; ++n)
+    {
+        if (!wcsicmp(g_AllowedExtensions[n], pwszExt))
+        {
+            m_Filename = Filename;
+            ACDBG(L"Got: %s\r\n", Filename);
+            m_IsSfcProtected = SfcIsFileProtected(NULL, m_Filename);
+            m_AllowPermLayer = AllowPermLayer(Filename);
+            return S_OK;
+        }
+    }
+    ACDBG(L"Extension not included: '%s'\r\n", pwszExt);
+    return E_FAIL;
+}
+
+BOOL GetLayerInfo(BSTR Filename, DWORD QueryFlags, PDWORD OSMode, PDWORD Enabledlayers)
+{
+    *OSMode = *Enabledlayers = 0;
+    WCHAR wszLayers[MAX_LAYER_LENGTH] = { 0 };
+    DWORD dwBytes = sizeof(wszLayers);
+    if (!SdbGetPermLayerKeys(Filename, wszLayers, &dwBytes, QueryFlags))
+        return FALSE;
+
+    for (PWCHAR Layer = wcstok(wszLayers, L" "); Layer; Layer = wcstok(NULL, L" "))
+    {
+        size_t n;
+        for (n = 0; g_Layers[n].Name; ++n)
+        {
+            if (g_Layers[n].Enabled && !wcsicmp(g_Layers[n].Name, Layer))
+            {
+                *Enabledlayers |= (1<<n);
+                break;
+            }
+        }
+        if (!g_Layers[n].Name)
+        {
+            for (n = 0; g_CompatModes[n].Name; ++n)
+            {
+                if (!wcsicmp(g_CompatModes[n].Name, Layer))
+                {
+                    *OSMode = n+1;
+                    break;
+                }
+            }
+        }
+    }
+    return TRUE;
+}
+
+void CLayerUIPropPage::OnRefresh(HWND hWnd)
+{
+    if (!GetLayerInfo(m_Filename, m_LayerQueryFlags, &m_RegistryOSMode, &m_RegistryEnabledLayers))
+        m_RegistryOSMode = m_RegistryEnabledLayers = 0;
+
+    for (size_t n = 0; g_Layers[n].Name; ++n)
+        CheckDlgButton(hWnd, g_Layers[n].Id, (m_RegistryEnabledLayers & (1<<n)) ? BST_CHECKED : BST_UNCHECKED);
+    CheckDlgButton(hWnd, IDC_CHKRUNCOMPATIBILITY, m_RegistryOSMode ? BST_CHECKED : BST_UNCHECKED);
+    if (m_RegistryOSMode)
+        ComboBox_SetCurSel(GetDlgItem(hWnd, IDC_COMPATIBILITYMODE), m_RegistryOSMode-1);
+    UpdateControls(hWnd);
+}
+
+void CLayerUIPropPage::OnApply(HWND hWnd)
+{
+    if (m_RegistryEnabledLayers != m_EnabledLayers || m_RegistryOSMode != m_OSMode)
+    {
+        BOOL bMachine = m_LayerQueryFlags == GPLK_MACHINE;
+        for (size_t n = 0; g_CompatModes[n].Name; ++n)
+            SetPermLayerState(m_Filename, g_CompatModes[n].Name, 0, bMachine, (n+1) == m_OSMode);
+        for (size_t n = 0; g_Layers[n].Name; ++n)
+        {
+            if (g_Layers[n].Enabled)
+                SetPermLayerState(m_Filename, g_Layers[n].Name, 0, bMachine, ((1<<n) & m_EnabledLayers) != 0);
+        }
+        SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATHW, (BSTR)m_Filename, NULL);
+    }
+}
+
+INT_PTR CLayerUIPropPage::InitDialog(HWND hWnd)
+{
+    HWND cboMode = GetDlgItem(hWnd, IDC_COMPATIBILITYMODE);
+    for (size_t n = 0; g_CompatModes[n].Display; ++n)
+        ComboBox_AddString(cboMode, g_CompatModes[n].Display);
+    ComboBox_SetCurSel(cboMode, 5);
+    EnableWindow(GetDlgItem(hWnd, IDC_EDITCOMPATIBILITYMODES), 0);
+
+    CComBSTR explanation;
+    if (!m_AllowPermLayer)
+    {
+        explanation.LoadString(g_hModule, IDS_FAILED_NETWORK);
+        DisableControls(hWnd);
+        ACDBG(L"AllowPermLayer returned FALSE\r\n");
+    }
+    else if (m_IsSfcProtected)
+    {
+        explanation.LoadString(g_hModule, IDS_FAILED_PROTECTED);
+        DisableControls(hWnd);
+        ACDBG(L"Protected OS file\r\n");
+    }
+    else
+    {
+        return TRUE;
+    }
+    SetDlgItemTextW(hWnd, IDC_EXPLANATION, explanation);
+    return TRUE;
+}
+
+INT_PTR CLayerUIPropPage::DisableControls(HWND hWnd)
+{
+    EnableWindow(GetDlgItem(hWnd, IDC_COMPATIBILITYMODE), 0);
+    EnableWindow(GetDlgItem(hWnd, IDC_CHKRUNCOMPATIBILITY), 0);
+    for (size_t n = 0; g_Layers[n].Name; ++n)
+        EnableWindow(GetDlgItem(hWnd, g_Layers[n].Id), 0);
+    EnableWindow(GetDlgItem(hWnd, IDC_EDITCOMPATIBILITYMODES), 0);
+    return TRUE;
+}
+
+void CLayerUIPropPage::UpdateControls(HWND hWnd)
+{
+    m_OSMode = 0, m_EnabledLayers = 0;
+    BOOL ModeEnabled = IsDlgButtonChecked(hWnd, IDC_CHKRUNCOMPATIBILITY);
+    if (ModeEnabled)
+        m_OSMode = ComboBox_GetCurSel(GetDlgItem(hWnd, IDC_COMPATIBILITYMODE))+1;
+    EnableWindow(GetDlgItem(hWnd, IDC_COMPATIBILITYMODE), ModeEnabled);
+    for (size_t n = 0; g_Layers[n].Name; ++n)
+    {
+        if (g_Layers[n].Enabled)
+        {
+            m_EnabledLayers |= IsDlgButtonChecked(hWnd, g_Layers[n].Id) ? (1<<n) : 0;
+            ShowWindow(GetDlgItem(hWnd, g_Layers[n].Id), SW_SHOW);
+        }
+        else
+        {
+            ShowWindow(GetDlgItem(hWnd, g_Layers[n].Id), SW_HIDE);
+        }
+    }
+    if (m_RegistryOSMode != m_OSMode || m_RegistryEnabledLayers != m_EnabledLayers)
+    {
+        PropSheet_Changed(GetParent(hWnd), hWnd);
+    }
+    else
+    {
+        PropSheet_UnChanged(GetParent(hWnd), hWnd);
+    }
+}
+
+INT_PTR CLayerUIPropPage::OnCommand(HWND hWnd, WORD id)
+{
+    switch (id)
+    {
+    case IDC_CHKRUNCOMPATIBILITY:
+        UpdateControls(hWnd);
+        break;
+    case IDC_COMPATIBILITYMODE:
+        UpdateControls(hWnd);
+        break;
+    case IDC_CHKRUNIN256COLORS:
+    case IDC_CHKRUNIN640480RES:
+    case IDC_CHKDISABLEVISUALTHEMES:
+        UpdateControls(hWnd);
+        break;
+    case IDC_EDITCOMPATIBILITYMODES:
+        break;
+    }
+    return FALSE;
+}
+
+INT_PTR CALLBACK CLayerUIPropPage::PropDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    CLayerUIPropPage* page = NULL;
+
+    switch (uMsg)
+    {
+    case WM_INITDIALOG:
+        page = (CLayerUIPropPage*)((LPPROPSHEETPAGE)lParam)->lParam;
+        SetProp(hWnd, ACP_WNDPROP, page);
+        return page->InitDialog(hWnd);
+
+    case WM_ENDSESSION:
+    case WM_DESTROY:
+        page = (CLayerUIPropPage*)GetProp(hWnd, ACP_WNDPROP);
+        RemoveProp(hWnd, ACP_WNDPROP);
+        page->Release();
+        break;
+
+    case WM_COMMAND:
+        page = (CLayerUIPropPage*)GetProp(hWnd, ACP_WNDPROP);
+        return page->OnCommand(hWnd, LOWORD(wParam));
+    case WM_NOTIFY:
+        switch (((LPNMHDR)lParam)->code)
+        {
+        case PSN_SETACTIVE:
+            if (((LPNMHDR)lParam)->hwndFrom == GetParent(hWnd))
+            {
+                page = (CLayerUIPropPage*)GetProp(hWnd, ACP_WNDPROP);
+                page->OnRefresh(hWnd);
+            }
+            break;
+        case PSN_APPLY:
+            if (((LPNMHDR)lParam)->hwndFrom == GetParent(hWnd))
+            {
+                page = (CLayerUIPropPage*)GetProp(hWnd, ACP_WNDPROP);
+                page->OnApply(hWnd);
+            }
+            break;
+        case NM_CLICK:
+        case NM_RETURN:
+            if (((LPNMHDR)lParam)->idFrom == IDC_INFOLINK)
+            {
+                ShellExecute(NULL, L"open", L"https://www.reactos.org/forum/viewforum.php?f=4", NULL, NULL, SW_SHOW);
+            }
+            break;
+        default:
+            break;
+        }
+        break;
+    }
+
+    return FALSE;
+}
+
+STDMETHODIMP CLayerUIPropPage::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hkeyProgID)
+{
+    FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+    STGMEDIUM stg;
+    HRESULT hr = pDataObj->GetData(&etc, &stg);
+    if (FAILED(hr))
+    {
+        ACDBG(L"Failed to retrieve Data from pDataObj.\r\n");
+        return E_INVALIDARG;
+    }
+    hr = E_FAIL;
+    HDROP hdrop = (HDROP)GlobalLock(stg.hGlobal);
+    if (hdrop)
+    {
+        UINT uNumFiles = DragQueryFileW(hdrop, 0xFFFFFFFF, NULL, 0);
+        if (uNumFiles == 1)
+        {
+            WCHAR szFile[MAX_PATH * 2];
+            if (DragQueryFileW(hdrop, 0, szFile, _countof(szFile)))
+            {
+                this->AddRef();
+                hr = InitFile(szFile);
+            }
+            else
+            {
+                ACDBG(L"Failed to query the file.\r\n");
+            }
+        }
+        else
+        {
+            ACDBG(L"Invalid number of files: %d\r\n", uNumFiles);
+        }
+        GlobalUnlock(stg.hGlobal);
+    }
+    else
+    {
+        ACDBG(L"Could not lock stg.hGlobal\r\n");
+    }
+    ReleaseStgMedium(&stg);
+    return hr;
+}
+
+STDMETHODIMP CLayerUIPropPage::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
+{
+    PROPSHEETPAGEW psp = { 0 };
+    psp.dwSize = sizeof(psp);
+    psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE;
+    psp.hInstance = g_hModule;
+    psp.pszTemplate = MAKEINTRESOURCE(IDD_ACPPAGESHEET);
+    psp.pszTitle = MAKEINTRESOURCE(IDS_TABTITLE);
+    psp.pfnDlgProc = PropDlgProc;
+    psp.lParam = (LPARAM)this;
+    psp.pcRefParent = (PUINT)&g_ModuleRefCnt;
+    HPROPSHEETPAGE hPage = CreatePropertySheetPageW(&psp);
+    if (hPage && !pfnAddPage(hPage, lParam))
+        DestroyPropertySheetPage(hPage);
+
+    return S_OK;
+}
+
diff --git a/reactos/dll/shellext/acppage/CLayerUIPropPage.hpp b/reactos/dll/shellext/acppage/CLayerUIPropPage.hpp
new file mode 100644 (file)
index 0000000..de1fae4
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2015 Mark Jansen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+
+class CLayerUIPropPage :
+    public CComCoClass<CLayerUIPropPage, &CLSID_CLayerUIPropPage>,
+    public CComObjectRootEx<CComMultiThreadModelNoCS>,
+    public IShellExtInit,
+    public IShellPropSheetExt
+{
+public:
+    CLayerUIPropPage();
+    ~CLayerUIPropPage();
+
+    // IShellExtInit
+    STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pdtobj, HKEY hkeyProgID);
+
+
+    // IShellPropSheetExt
+    STDMETHODIMP AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam);
+    STDMETHODIMP ReplacePage(UINT, LPFNADDPROPSHEETPAGE, LPARAM)
+    {
+        return E_NOTIMPL;
+    }
+
+    HRESULT InitFile(PCWSTR Filename);
+    INT_PTR InitDialog(HWND hWnd);
+    INT_PTR OnCommand(HWND hWnd, WORD id);
+    void UpdateControls(HWND hWnd);
+    INT_PTR DisableControls(HWND hWnd);
+
+    void OnRefresh(HWND hWnd);
+    void OnApply(HWND hWnd);
+
+    static INT_PTR CALLBACK PropDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+    /*static INT_PTR CALLBACK EditModesProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);*/
+
+
+protected:
+    CComBSTR m_Filename;
+    HWND m_Wnd;
+    BOOL m_IsSfcProtected;
+    BOOL m_AllowPermLayer;
+    DWORD m_LayerQueryFlags;
+    DWORD m_RegistryOSMode, m_OSMode;
+    DWORD m_RegistryEnabledLayers, m_EnabledLayers;
+
+public:
+    DECLARE_REGISTRY_RESOURCEID(IDR_ACPPAGE)
+    DECLARE_NOT_AGGREGATABLE(CLayerUIPropPage)
+
+    DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+    BEGIN_COM_MAP(CLayerUIPropPage)
+        COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit)
+        COM_INTERFACE_ENTRY_IID(IID_IShellPropSheetExt, IShellPropSheetExt)
+    END_COM_MAP()
+};
diff --git a/reactos/dll/shellext/acppage/CMakeLists.txt b/reactos/dll/shellext/acppage/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3ad58ee
--- /dev/null
@@ -0,0 +1,34 @@
+project(appcompat)
+
+set_cpp(WITH_RUNTIME)
+if(NOT MSVC)
+    # HACK: this should be enabled globally!
+    add_compile_flags_language("-std=c++11" "CXX")
+endif()
+
+include_directories(
+    ${REACTOS_SOURCE_DIR}/lib/atl
+    ${REACTOS_SOURCE_DIR}/dll/appcompat/apphelp
+    ${REACTOS_SOURCE_DIR})
+spec2def(acppage.dll acppage.spec ADD_IMPORTLIB)
+
+list(APPEND SOURCE
+    ACPPage.cpp
+    CLayerUIPropPage.cpp
+    CLayerUIPropPage.hpp
+    acppage.spec
+    precomp.h
+    resource.h)
+
+add_library(acppage SHARED
+    ${SOURCE}
+    ACPPage.rc
+    ${CMAKE_CURRENT_BINARY_DIR}/acppage.def)
+
+set_module_type(acppage win32dll UNICODE)
+target_link_libraries(acppage atlnew wine uuid)
+add_delay_importlibs(acppage apphelp ole32 oleaut32 shlwapi comctl32 sfc_os)
+add_importlibs(acppage shell32 user32 advapi32 msvcrt kernel32)
+add_pch(acppage precomp.h SOURCE)
+add_cd_file(TARGET acppage DESTINATION reactos/system32 FOR all)
+
diff --git a/reactos/dll/shellext/acppage/acppage.spec b/reactos/dll/shellext/acppage/acppage.spec
new file mode 100644 (file)
index 0000000..a829703
--- /dev/null
@@ -0,0 +1,5 @@
+@ stdcall -private DllCanUnloadNow()
+@ stdcall -private DllGetClassObject(ptr ptr ptr)
+@ stdcall -private DllRegisterServer()
+@ stdcall -private DllUnregisterServer()
+@ stdcall GetExeFromLnk(wstr wstr long)
diff --git a/reactos/dll/shellext/acppage/lang/en-US.rc b/reactos/dll/shellext/acppage/lang/en-US.rc
new file mode 100644 (file)
index 0000000..3a292d0
--- /dev/null
@@ -0,0 +1,40 @@
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+IDD_ACPPAGESHEET DIALOGEX 0, 0, 224, 226
+STYLE DS_SHELLFONT | WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Compatibility"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+    LTEXT "If you have problems running this program in ReactOS, select an operating system ReactOS should report to the application.\nPlease note that this is a work in progress, and at this stage will not do anything.", IDC_EXPLANATION, 7, 7, 210, 31
+    GROUPBOX "Compatibility mode", IDC_COMPATGROUP, 7, 41, 210, 49
+    CHECKBOX "Run this program in compatibility mode for:", IDC_CHKRUNCOMPATIBILITY, 18, 57, 188, 10, BS_AUTOCHECKBOX | WS_TABSTOP
+    COMBOBOX IDC_COMPATIBILITYMODE, 18, 70, 188, 85, CBS_HASSTRINGS | CBS_DROPDOWNLIST | WS_TABSTOP | WS_DISABLED
+    GROUPBOX "Display settings", -1, 7, 99, 210, 61, BS_GROUPBOX | WS_DISABLED
+    CHECKBOX "Run in 256 colors", IDC_CHKRUNIN256COLORS, 18, 114, 188, 10, BS_AUTOCHECKBOX | WS_TABSTOP | WS_DISABLED
+    CHECKBOX "Run in 640x480 screenresolution", IDC_CHKRUNIN640480RES, 18, 129, 188, 10, BS_AUTOCHECKBOX | WS_TABSTOP | WS_DISABLED
+    CHECKBOX "Disable visual themes", IDC_CHKDISABLEVISUALTHEMES, 18, 144, 188, 10, BS_AUTOCHECKBOX | WS_TABSTOP | WS_DISABLED
+    PUSHBUTTON "E&dit compatibility modes...", IDC_EDITCOMPATIBILITYMODES, 117, 167, 100, 15
+    CONTROL "Learn more about <A>program compatibility</A>.", IDC_INFOLINK, "SysLink", WS_CHILD | WS_TABSTOP | WS_VISIBLE, 7, 207, 210, 10, WS_EX_NOPARENTNOTIFY
+END
+
+IDD_EDITCOMPATIBILITYMODES DIALOGEX 0, 0, 230, 139
+STYLE DS_SHELLFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Edit Compatibility Modes"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+    EDITTEXT IDC_NEWCOMPATIBILITYMODE, 9, 6, 148, 14, ES_AUTOHSCROLL
+    LISTBOX IDC_COMPATIBILITYMODE, 9, 25, 148, 86, LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | WS_BORDER
+    PUSHBUTTON "&Add...", IDC_ADD, 162, 6, 60, 14, WS_DISABLED
+    PUSHBUTTON "&Edit...", IDC_EDIT, 162, 24, 60, 14, WS_DISABLED
+    PUSHBUTTON "&Delete", IDC_DELETE, 162, 42, 60, 14, WS_DISABLED
+    PUSHBUTTON "&OK", IDOK, 95, 116, 60, 14
+    PUSHBUTTON "&Cancel", IDCANCEL, 162, 116, 60, 14
+END
+
+STRINGTABLE
+BEGIN
+    IDS_TABTITLE "Compatibility"
+    IDS_FAILED_NETWORK "Compatibility modes cannot be set on this program because it is on a network drive."
+    IDS_FAILED_PROTECTED "Compatibility modes cannot be set on this program because it is a part of ReactOS."
+END
+
diff --git a/reactos/dll/shellext/acppage/precomp.h b/reactos/dll/shellext/acppage/precomp.h
new file mode 100644 (file)
index 0000000..32627db
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef ACPPAGE_PRECOMP_H
+#define ACPPAGE_PRECOMP_H
+
+#include <stdarg.h>
+#include <assert.h>
+
+#define COBJMACROS
+#define WIN32_NO_STATUS
+#define _INC_WINDOWS
+#define COM_NO_WINDOWS_H
+#define NTOS_MODE_USER
+
+#include <windows.h>
+
+#include <windef.h>
+#include <winbase.h>
+#include <winreg.h>
+#include <winuser.h>
+
+#include <shlobj.h>
+#include <shlwapi.h>
+#include <shellapi.h>
+#include <tchar.h>
+#include <strsafe.h>
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlwin.h>
+ULONG DbgPrint(PCH Format,...);
+#include <shellutils.h>
+#include <prsht.h>
+#include <apphelp.h>
+
+extern const GUID CLSID_CLayerUIPropPage;
+extern HMODULE g_hModule;
+extern LONG g_ModuleRefCnt;
+
+EXTERN_C BOOL WINAPI GetExeFromLnk(PCWSTR pszLnk, PWSTR pszExe, size_t cchSize);
+
+#include "resource.h"
+#include "CLayerUIPropPage.hpp"
+
+#endif /* ACPPAGE_PRECOMP_H */
diff --git a/reactos/dll/shellext/acppage/res/acppage.rgs b/reactos/dll/shellext/acppage/res/acppage.rgs
new file mode 100644 (file)
index 0000000..b74c78f
--- /dev/null
@@ -0,0 +1,85 @@
+HKCR
+{
+    NoRemove CLSID
+    {
+        ForceRemove {513D916F-2A8E-4F51-AEAB-0CBC76FB1AF8} = s 'LayerUIPropPage'
+        {
+            InprocServer32 = s '%MODULE%'
+            {
+                val ThreadingModel = s 'Apartment'
+            }
+        }
+    }
+    NoRemove batfile
+    {
+        NoRemove shellex
+        {
+            NoRemove PropertySheetHandlers
+            {
+                ForceRemove ShimLayer Property Page = s '{513D916F-2A8E-4F51-AEAB-0CBC76FB1AF8}'
+                {
+                }
+            }
+        }
+    }
+    NoRemove cmdfile
+    {
+        NoRemove shellex
+        {
+            NoRemove PropertySheetHandlers
+            {
+                ForceRemove ShimLayer Property Page = s '{513D916F-2A8E-4F51-AEAB-0CBC76FB1AF8}'
+                {
+                }
+            }
+        }
+    }
+    NoRemove exefile
+    {
+        NoRemove shellex
+        {
+            NoRemove PropertySheetHandlers
+            {
+                ForceRemove ShimLayer Property Page = s '{513D916F-2A8E-4F51-AEAB-0CBC76FB1AF8}'
+                {
+                }
+            }
+        }
+    }
+    NoRemove lnkfile
+    {
+        NoRemove shellex
+        {
+            NoRemove PropertySheetHandlers
+            {
+                ForceRemove ShimLayer Property Page = s '{513D916F-2A8E-4F51-AEAB-0CBC76FB1AF8}'
+                {
+                }
+            }
+        }
+    }
+    NoRemove Msi.Package
+    {
+        NoRemove shellex
+        {
+            NoRemove PropertySheetHandlers
+            {
+                ForceRemove ShimLayer Property Page = s '{513D916F-2A8E-4F51-AEAB-0CBC76FB1AF8}'
+                {
+                }
+            }
+        }
+    }
+    NoRemove piffile
+    {
+        NoRemove shellex
+        {
+            NoRemove PropertySheetHandlers
+            {
+                ForceRemove ShimLayer Property Page = s '{513D916F-2A8E-4F51-AEAB-0CBC76FB1AF8}'
+                {
+                }
+            }
+        }
+    }
+}
diff --git a/reactos/dll/shellext/acppage/resource.h b/reactos/dll/shellext/acppage/resource.h
new file mode 100644 (file)
index 0000000..57d72e2
--- /dev/null
@@ -0,0 +1,30 @@
+#pragma once
+
+#define IDD_ACPPAGESHEET           100
+#define IDD_EDITCOMPATIBILITYMODES 101
+
+#define IDC_EXPLANATION            1000
+#define IDC_CHKRUNCOMPATIBILITY    1001
+#define IDC_COMPATIBILITYMODE      1002
+#define IDC_CHKRUNIN256COLORS      1003
+#define IDC_CHKRUNIN640480RES      1004
+#define IDC_CHKDISABLEVISUALTHEMES 1005
+#define IDC_EDITCOMPATIBILITYMODES 1006
+#define IDC_INFOLINK               1007
+#define IDC_COMPATGROUP            1008
+#define IDC_NEWCOMPATIBILITYMODE   1009
+#define IDC_ADD                    1010
+#define IDC_EDIT                   1011
+#define IDC_DELETE                 1012
+
+#define IDS_DESCRIPTION 101
+
+/* strings */
+#define IDS_TABTITLE                    2000
+#define IDS_FAILED_NETWORK              2001
+#define IDS_FAILED_PROTECTED            2002
+
+
+/* registry stuff */
+#define IDR_ACPPAGE                     8000
+
index 0f37246..88e65c4 100644 (file)
@@ -35,6 +35,7 @@ AddReg=Classes
 [OleControlDlls]\r
 11,,atl.dll,1\r
 11,,actxprxy.dll,1\r
+;11,,acppage.dll,1\r
 11,,amstream.dll,1\r
 11,,avifil32.dll,1\r
 11,,browseui.dll,1\r