[ACPPAGE] Implement custom compatibility mode selection + Expand paths CORE-10375
authorMark Jansen <mark.jansen@reactos.org>
Sat, 22 Apr 2017 17:11:52 +0000 (17:11 +0000)
committerMark Jansen <mark.jansen@reactos.org>
Sat, 22 Apr 2017 17:11:52 +0000 (17:11 +0000)
svn path=/trunk/; revision=74388

reactos/dll/shellext/acppage/CLayerStringList.hpp [new file with mode: 0644]
reactos/dll/shellext/acppage/CLayerUIPropPage.cpp
reactos/dll/shellext/acppage/CLayerUIPropPage.hpp
reactos/dll/shellext/acppage/CMakeLists.txt
reactos/dll/shellext/acppage/precomp.h
reactos/sdk/lib/atl/atlexcept.h

diff --git a/reactos/dll/shellext/acppage/CLayerStringList.hpp b/reactos/dll/shellext/acppage/CLayerStringList.hpp
new file mode 100644 (file)
index 0000000..c6c0303
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2015-2017 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
+ */
+
+
+/* TODO: Use HSDB instead of PDB */
+class CLayerStringList :
+    public CComObjectRootEx<CComMultiThreadModelNoCS>,
+    public IEnumString
+{
+public:
+    CLayerStringList()
+        :m_root(TAGID_NULL), m_layer(TAGID_NULL)
+    {
+        WCHAR buf[MAX_PATH];
+        SdbGetAppPatchDir(NULL, buf, MAX_PATH);
+        StringCchCatW(buf, _countof(buf), L"\\sysmain.sdb");
+        m_db = SdbOpenDatabase(buf, DOS_PATH);
+        Reset();
+    }
+
+    ~CLayerStringList()
+    {
+        SdbCloseDatabase(m_db);
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched)
+    {
+        if (pceltFetched)
+            *pceltFetched = 0;
+
+        while (celt && m_layer)
+        {
+            TAGID nameid = SdbFindFirstTag(m_db, m_layer, TAG_NAME);
+            if (!nameid)
+                return S_FALSE;
+
+            LPWSTR name = SdbGetStringTagPtr(m_db, nameid);
+            if (!name)
+                return S_FALSE;
+
+            ULONG Size = wcslen(name) + 1;
+
+            *rgelt = (LPOLESTR)::CoTaskMemAlloc(Size * sizeof(WCHAR));
+            StringCchCopyW(*rgelt, Size, name);
+
+            if (pceltFetched)
+                (*pceltFetched)++;
+
+            m_layer = SdbFindNextTag(m_db, m_root, m_layer);
+            celt--;
+            rgelt++;
+        }
+        return celt ? S_FALSE : S_OK;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt)
+    {
+        while (m_layer && celt)
+        {
+            m_layer = SdbFindNextTag(m_db, m_root, m_layer);
+            --celt;
+        }
+        return celt ? S_FALSE : S_OK;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE Reset()
+    {
+        m_root = m_layer = TAGID_NULL;
+        if (m_db)
+        {
+            m_root = SdbFindFirstTag(m_db, TAGID_ROOT, TAG_DATABASE);
+            if (m_root != TAGID_NULL)
+            {
+                m_layer = SdbFindFirstTag(m_db, m_root, TAG_LAYER);
+                return S_OK;
+            }
+        }
+        return E_FAIL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE Clone(IEnumString **ppenum)
+    {
+        return E_NOTIMPL;
+    }
+
+protected:
+    PDB m_db;
+    TAGID m_root;
+    TAGID m_layer;
+
+public:
+    BEGIN_COM_MAP(CLayerStringList)
+        COM_INTERFACE_ENTRY_IID(IID_IEnumString, IEnumString)
+    END_COM_MAP()
+};
+
index d66d48c..36c67e3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Mark Jansen
+ * Copyright 2015-2017 Mark Jansen
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -20,6 +20,7 @@
 
 #include <shlwapi.h>
 #include <shellapi.h>
+#include <shellutils.h>
 #include <strsafe.h>
 #include <apphelp.h>
 #include <windowsx.h>
@@ -32,45 +33,6 @@ const GUID CLSID_CLayerUIPropPage = { 0x513D916F, 0x2A8E, 0x4F51, { 0xAE, 0xAB,
 #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_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;
@@ -95,12 +57,16 @@ static struct {
 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 }
+    { L"256COLOR", IDC_CHKRUNIN256COLORS },
+    { L"640X480", IDC_CHKRUNIN640480RES },
+    { L"DISABLETHEMES", IDC_CHKDISABLEVISUALTHEMES },
+#if 0
+    { L"DISABLEDWM", IDC_??, TRUE },
+    { L"HIGHDPIAWARE", IDC_??, TRUE },
+    { L"RUNASADMIN", IDC_??, TRUE },
+#endif
+    { NULL, 0 }
 };
 
 static const WCHAR* g_AllowedExtensions[] = {
@@ -112,25 +78,82 @@ static const WCHAR* g_AllowedExtensions[] = {
     0
 };
 
+
+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_IsSfcProtected(FALSE)
+, m_AllowPermLayer(FALSE)
+, m_LayerQueryFlags(GPLK_USER)  /* TODO: When do we read from HKLM? */
+, m_RegistryOSMode(0)
+, m_OSMode(0)
+, m_RegistryEnabledLayers(0)
+, m_EnabledLayers(0)
+{
+}
+
+CLayerUIPropPage::~CLayerUIPropPage()
+{
+}
+
 HRESULT CLayerUIPropPage::InitFile(PCWSTR Filename)
 {
-    PCWSTR pwszExt = PathFindExtensionW(Filename);
+    CString ExpandedFilename;
+    DWORD dwRequired = ExpandEnvironmentStringsW(Filename, NULL, 0);
+    if (dwRequired > 0)
+    {
+        LPWSTR Buffer = ExpandedFilename.GetBuffer(dwRequired);
+        DWORD dwReturned = ExpandEnvironmentStringsW(Filename, Buffer, dwRequired);
+        if (dwRequired == dwReturned)
+        {
+            ExpandedFilename.ReleaseBufferSetLength(dwReturned - 1);
+            ACDBG(L"Expanded '%s' => '%s'\r\n", Filename, (PCWSTR)ExpandedFilename);
+        }
+        else
+        {
+            ExpandedFilename.ReleaseBufferSetLength(0);
+            ExpandedFilename = Filename;
+            ACDBG(L"Failed during expansion '%s'\r\n", Filename);
+        }
+    }
+    else
+    {
+        ACDBG(L"Failed to expand '%s'\r\n", Filename);
+        ExpandedFilename = Filename;
+    }
+    PCWSTR pwszExt = PathFindExtensionW(ExpandedFilename);
     if (!pwszExt)
     {
-        ACDBG(L"Failed to find an extension: '%s'\r\n", Filename);
+        ACDBG(L"Failed to find an extension: '%s'\r\n", (PCWSTR)ExpandedFilename);
         return E_FAIL;
     }
     if (!wcsicmp(pwszExt, L".lnk"))
     {
         WCHAR Buffer[MAX_PATH];
-        if (!GetExeFromLnk(Filename, Buffer, _countof(Buffer)))
+        if (!GetExeFromLnk(ExpandedFilename, Buffer, _countof(Buffer)))
         {
-            ACDBG(L"Failed to read link target from: '%s'\r\n", Filename);
+            ACDBG(L"Failed to read link target from: '%s'\r\n", (PCWSTR)ExpandedFilename);
             return E_FAIL;
         }
-        if (!wcsicmp(Buffer, Filename))
+        if (!wcsicmp(Buffer, ExpandedFilename))
         {
-            ACDBG(L"Link redirects to itself: '%s'\r\n", Filename);
+            ACDBG(L"Link redirects to itself: '%s'\r\n", (PCWSTR)ExpandedFilename);
             return E_FAIL;
         }
         return InitFile(Buffer);
@@ -139,10 +162,10 @@ HRESULT CLayerUIPropPage::InitFile(PCWSTR Filename)
     {
         if (!wcsicmp(g_AllowedExtensions[n], pwszExt))
         {
-            m_Filename = Filename;
-            ACDBG(L"Got: %s\r\n", Filename);
+            m_Filename = ExpandedFilename;
+            ACDBG(L"Got: %s\r\n", (PCWSTR)ExpandedFilename);
             m_IsSfcProtected = SfcIsFileProtected(NULL, m_Filename);
-            m_AllowPermLayer = AllowPermLayer(Filename);
+            m_AllowPermLayer = AllowPermLayer(ExpandedFilename);
             return S_OK;
         }
     }
@@ -150,11 +173,13 @@ HRESULT CLayerUIPropPage::InitFile(PCWSTR Filename)
     return E_FAIL;
 }
 
-BOOL GetLayerInfo(BSTR Filename, DWORD QueryFlags, PDWORD OSMode, PDWORD Enabledlayers)
+static BOOL GetLayerInfo(PCWSTR Filename, DWORD QueryFlags, PDWORD OSMode, PDWORD Enabledlayers, CSimpleArray<CString>& customLayers)
 {
-    *OSMode = *Enabledlayers = 0;
     WCHAR wszLayers[MAX_LAYER_LENGTH] = { 0 };
     DWORD dwBytes = sizeof(wszLayers);
+
+    *OSMode = *Enabledlayers = 0;
+    customLayers.RemoveAll();
     if (!SdbGetPermLayerKeys(Filename, wszLayers, &dwBytes, QueryFlags))
         return FALSE;
 
@@ -163,53 +188,109 @@ BOOL GetLayerInfo(BSTR Filename, DWORD QueryFlags, PDWORD OSMode, PDWORD Enabled
         size_t n;
         for (n = 0; g_Layers[n].Name; ++n)
         {
-            if (g_Layers[n].Enabled && !wcsicmp(g_Layers[n].Name, Layer))
+            if (!wcsicmp(g_Layers[n].Name, Layer))
             {
                 *Enabledlayers |= (1<<n);
                 break;
             }
         }
-        if (!g_Layers[n].Name)
+        /* Did we find it? */
+        if (g_Layers[n].Name)
+            continue;
+
+        for (n = 0; g_CompatModes[n].Name; ++n)
         {
-            for (n = 0; g_CompatModes[n].Name; ++n)
+            if (!wcsicmp(g_CompatModes[n].Name, Layer))
             {
-                if (!wcsicmp(g_CompatModes[n].Name, Layer))
-                {
-                    *OSMode = n+1;
-                    break;
-                }
+                *OSMode = n+1;
+                break;
             }
         }
+        /* Did we find it? */
+        if (g_CompatModes[n].Name)
+            continue;
+
+        /* Must be a 'custom' layer */
+        customLayers.Add(Layer);
     }
     return TRUE;
 }
 
 void CLayerUIPropPage::OnRefresh(HWND hWnd)
 {
-    if (!GetLayerInfo(m_Filename, m_LayerQueryFlags, &m_RegistryOSMode, &m_RegistryEnabledLayers))
+    if (!GetLayerInfo(m_Filename, m_LayerQueryFlags, &m_RegistryOSMode, &m_RegistryEnabledLayers, m_RegistryCustomLayers))
         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);
+
+    m_CustomLayers = m_RegistryCustomLayers;
+
+    /* TODO: visualize 'custom' layers! */
+
     UpdateControls(hWnd);
 }
 
+
+static BOOL ArrayEquals(const CSimpleArray<CString>& lhs, const CSimpleArray<CString>& rhs)
+{
+    if (lhs.GetSize() != rhs.GetSize())
+        return FALSE;
+
+    for (int n = 0; n < lhs.GetSize(); ++n)
+    {
+        if (lhs[n] != rhs[n])
+            return FALSE;
+    }
+    return TRUE;
+}
+
+BOOL CLayerUIPropPage::HasChanges() const
+{
+    if (m_RegistryEnabledLayers != m_EnabledLayers)
+        return TRUE;
+
+    if (m_RegistryOSMode != m_OSMode)
+        return TRUE;
+
+    if (!ArrayEquals(m_RegistryCustomLayers, m_CustomLayers))
+        return TRUE;
+
+    return FALSE;
+}
+
 void CLayerUIPropPage::OnApply(HWND hWnd)
 {
-    if (m_RegistryEnabledLayers != m_EnabledLayers || m_RegistryOSMode != m_OSMode)
+    if (HasChanges())
     {
         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);
+            SetPermLayerState(m_Filename, g_Layers[n].Name, 0, bMachine, ((1<<n) & m_EnabledLayers) != 0);
+        }
+
+        /* Disable all old values */
+        for (int j = 0; j < m_RegistryCustomLayers.GetSize(); j++)
+        {
+            SetPermLayerState(m_Filename, m_RegistryCustomLayers[j].GetString(), 0, bMachine, FALSE);
+        }
+
+        /* Enable all new values */
+        for (int j = 0; j < m_CustomLayers.GetSize(); j++)
+        {
+            SetPermLayerState(m_Filename, m_CustomLayers[j].GetString(), 0, bMachine, TRUE);
         }
-        SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATHW, (BSTR)m_Filename, NULL);
+
+        SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATHW, (PCWSTR)m_Filename, NULL);
     }
 }
 
@@ -219,7 +300,6 @@ INT_PTR CLayerUIPropPage::InitDialog(HWND hWnd)
     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)
@@ -259,19 +339,14 @@ void CLayerUIPropPage::UpdateControls(HWND hWnd)
     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);
-        }
+        m_EnabledLayers |= IsDlgButtonChecked(hWnd, g_Layers[n].Id) ? (1<<n) : 0;
+        ShowWindow(GetDlgItem(hWnd, g_Layers[n].Id), SW_SHOW);
     }
-    if (m_RegistryOSMode != m_OSMode || m_RegistryEnabledLayers != m_EnabledLayers)
+
+    if (HasChanges())
     {
         PropSheet_Changed(GetParent(hWnd), hWnd);
     }
@@ -297,6 +372,10 @@ INT_PTR CLayerUIPropPage::OnCommand(HWND hWnd, WORD id)
         UpdateControls(hWnd);
         break;
     case IDC_EDITCOMPATIBILITYMODES:
+        if (DialogBoxParam(g_hModule, MAKEINTRESOURCE(IDD_EDITCOMPATIBILITYMODES), hWnd, EditModesProc, (LPARAM)this) == IDOK)
+        {
+            UpdateControls(hWnd);
+        }
         break;
     }
     return FALSE;
@@ -356,6 +435,133 @@ INT_PTR CALLBACK CLayerUIPropPage::PropDlgProc(HWND hWnd, UINT uMsg, WPARAM wPar
     return FALSE;
 }
 
+static void ListboxChanged(HWND hWnd)
+{
+    int Sel = ListBox_GetCurSel(GetDlgItem(hWnd, IDC_COMPATIBILITYMODE));
+    EnableWindow(GetDlgItem(hWnd, IDC_EDIT), Sel >= 0);
+    EnableWindow(GetDlgItem(hWnd, IDC_DELETE), Sel >= 0);
+}
+
+INT_PTR CALLBACK CLayerUIPropPage::EditModesProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    CLayerUIPropPage* page = NULL;
+    switch (uMsg)
+    {
+    case WM_INITDIALOG:
+        page = (CLayerUIPropPage*)lParam;
+        page->AddRef();
+        SetProp(hWnd, ACP_WNDPROP, page);
+        {
+            CComPtr<IAutoComplete> autoComplete;
+            HRESULT hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IAutoComplete, &autoComplete));
+            if (SUCCEEDED(hr))
+            {
+                CComPtr<IAutoComplete2> autoComplete2;
+                hr = autoComplete->QueryInterface(IID_PPV_ARG(IAutoComplete2, &autoComplete2));
+                if (SUCCEEDED(hr))
+                {
+                    autoComplete2->SetOptions(ACO_AUTOSUGGEST | ACO_UPDOWNKEYDROPSLIST);
+                    HWND Edit = GetDlgItem(hWnd, IDC_NEWCOMPATIBILITYMODE);
+                    CComObject<CLayerStringList>* pList = new CComObject<CLayerStringList>();
+                    hr = autoComplete2->Init(Edit, pList, NULL, NULL);
+                }
+            }
+
+            HWND List = GetDlgItem(hWnd, IDC_COMPATIBILITYMODE);
+            for (int n = 0; n < page->m_CustomLayers.GetSize(); ++n)
+            {
+                const WCHAR* Str = page->m_CustomLayers[n].GetString();
+                int Index = ListBox_FindStringExact(List, -1, Str);
+                if (Index == LB_ERR)
+                    Index = ListBox_AddString(List, Str);
+            }
+        }
+        break;
+    case WM_ENDSESSION:
+    case WM_DESTROY:
+        page = (CLayerUIPropPage*)GetProp(hWnd, ACP_WNDPROP);
+        RemoveProp(hWnd, ACP_WNDPROP);
+        page->Release();
+        break;
+    case WM_COMMAND:
+        switch(LOWORD(wParam))
+        {
+        case IDC_ADD:
+        {
+            HWND Edit = GetDlgItem(hWnd, IDC_NEWCOMPATIBILITYMODE);
+            int Length = GetWindowTextLengthW(Edit);
+            CComBSTR Str(Length);
+            GetWindowTextW(Edit, Str, Length+1);
+            HWND List = GetDlgItem(hWnd, IDC_COMPATIBILITYMODE);
+            int Index = ListBox_FindStringExact(List, -1, Str);
+            if (Index == LB_ERR)
+                Index = ListBox_AddString(List, Str);
+            ListBox_SetCurSel(List, Index);
+            ListboxChanged(hWnd);
+            Edit_SetText(Edit, TEXT(""));
+            SetFocus(Edit);
+        }
+            break;
+        case IDC_EDIT:
+        {
+            HWND List = GetDlgItem(hWnd, IDC_COMPATIBILITYMODE);
+            int Cur = ListBox_GetCurSel(List);
+            int Length = ListBox_GetTextLen(List, Cur);
+            CComBSTR Str(Length);
+            ListBox_GetText(List, Cur, Str);
+            ListBox_DeleteString(List, Cur);
+            HWND Edit = GetDlgItem(hWnd, IDC_NEWCOMPATIBILITYMODE);
+            Edit_SetText(Edit, Str);
+            ListboxChanged(hWnd);
+            Edit_SetSel(Edit, 30000, 30000);
+            SetFocus(Edit);
+        }
+            break;
+        case IDC_DELETE:
+        {
+            HWND List = GetDlgItem(hWnd, IDC_COMPATIBILITYMODE);
+            ListBox_DeleteString(List, ListBox_GetCurSel(List));
+            ListboxChanged(hWnd);
+        }
+            break;
+        case IDC_COMPATIBILITYMODE:
+            ListboxChanged(hWnd);
+            break;
+        case IDC_NEWCOMPATIBILITYMODE:
+            EnableWindow(GetDlgItem(hWnd, IDC_ADD), Edit_GetTextLength(GetDlgItem(hWnd, IDC_NEWCOMPATIBILITYMODE)) > 0);
+            break;
+        case IDOK:
+            /* Copy from list! */
+        {
+            page = (CLayerUIPropPage*)GetProp(hWnd, ACP_WNDPROP);
+
+            HWND List = GetDlgItem(hWnd, IDC_COMPATIBILITYMODE);
+            int Count = ListBox_GetCount(List);
+            page->m_CustomLayers.RemoveAll();
+            for (int Cur = 0; Cur < Count; ++Cur)
+            {
+                int Length = ListBox_GetTextLen(List, Cur);
+                CString Str;
+                LPWSTR Buffer = Str.GetBuffer(Length + 1);
+                ListBox_GetText(List, Cur, Buffer);
+                Str.ReleaseBuffer(Length);
+                page->m_CustomLayers.Add(Str);
+            }
+        }
+        /* Fall trough */
+        case IDCANCEL:
+            EndDialog(hWnd, LOWORD(wParam));
+            break;
+        }
+        break;
+    case WM_CLOSE:
+        EndDialog(hWnd, IDCANCEL);
+        break;
+    }
+    return FALSE;
+}
+
+
 STDMETHODIMP CLayerUIPropPage::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hkeyProgID)
 {
     FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
@@ -415,4 +621,3 @@ STDMETHODIMP CLayerUIPropPage::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM
 
     return S_OK;
 }
-
index 1cda91f..734fca1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Mark Jansen
+ * Copyright 2015-2017 Mark Jansen
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -43,21 +43,23 @@ public:
     INT_PTR OnCommand(HWND hWnd, WORD id);
     void UpdateControls(HWND hWnd);
     INT_PTR DisableControls(HWND hWnd);
+    BOOL HasChanges() const;
 
     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);*/
+    static INT_PTR CALLBACK EditModesProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
 
 protected:
-    CComBSTR m_Filename;
+    CString m_Filename;
     BOOL m_IsSfcProtected;
     BOOL m_AllowPermLayer;
     DWORD m_LayerQueryFlags;
     DWORD m_RegistryOSMode, m_OSMode;
     DWORD m_RegistryEnabledLayers, m_EnabledLayers;
+    CSimpleArray<CString> m_RegistryCustomLayers, m_CustomLayers;
 
 public:
     DECLARE_REGISTRY_RESOURCEID(IDR_ACPPAGE)
index 38a2ba6..cfab164 100644 (file)
@@ -6,6 +6,9 @@ if(NOT MSVC)
     add_compile_flags_language("-std=c++11" "CXX")
 endif()
 
+add_definitions(
+    -D_ATL_NO_EXCEPTIONS)
+
 include_directories(
     ${REACTOS_SOURCE_DIR}/sdk/lib/atl
     ${REACTOS_SOURCE_DIR}/dll/appcompat/apphelp
@@ -16,6 +19,7 @@ list(APPEND SOURCE
     ACPPage.cpp
     CLayerUIPropPage.cpp
     CLayerUIPropPage.hpp
+    CLayerStringList.hpp
     acppage.spec
     precomp.h
     resource.h)
index b84f5bb..9675648 100644 (file)
 #include <windef.h>
 #include <winbase.h>
 #include <shlobj.h>
+#include <tchar.h>
+#include <strsafe.h>
 #include <atlbase.h>
 #include <atlcom.h>
+#include <atlsimpcoll.h>
+#include <atlstr.h>
 
 ULONG DbgPrint(PCH Format,...);
+#include <apphelp.h>
 
 extern const GUID CLSID_CLayerUIPropPage;
 extern HMODULE g_hModule;
@@ -22,6 +27,7 @@ extern LONG g_ModuleRefCnt;
 EXTERN_C BOOL WINAPI GetExeFromLnk(PCWSTR pszLnk, PWSTR pszExe, size_t cchSize);
 
 #include "resource.h"
+#include "CLayerStringList.hpp"
 #include "CLayerUIPropPage.hpp"
 
 #endif /* ACPPAGE_PRECOMP_H */
index b81c655..233dd09 100644 (file)
@@ -3,6 +3,13 @@
 #define __ATLEXCEPT_H__
 
 
+#ifdef _ATL_NO_EXCEPTIONS
+#if !defined(STATUS_NO_MEMORY) && defined(WIN32_NO_STATUS)
+#define STATUS_NO_MEMORY ((DWORD)0xC0000017)
+#endif
+#endif
+
+
 //FIXME: Enable when RaiseException is marked as NORETURN
 //DECLSPEC_NORETURN
 inline void AtlThrowImp(HRESULT hr)