2 * ReactOS Compatibility Layer Shell Extension
3 * Copyright (C) 2004 - 2005 ReactOS Team
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * PROJECT: ReactOS Compatibility Layer Shell Extension
22 * FILE: lib/shellext/cplsample/cplsample.c
23 * PURPOSE: ReactOS Compatibility Layer Shell Extension
24 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
30 HINSTANCE hInstance
= NULL
;
31 static LONG dllrefs
= 0;
33 static ifaceICompatibilityPageVbtl efvt
=
35 /* IUnknown methods */
36 ICompatibilityPage_fnQueryInterface
,
37 ICompatibilityPage_fnAddRef
,
38 ICompatibilityPage_fnRelease
,
41 static ifaceIShellPropSheetExtVbtl efvtIShellPropSheetExt
=
43 /* IShellPropSheetExt */
44 ICompatibilityPage_fnAddPages
,
45 ICompatibilityPage_fnReplacePage
,
48 static ifaceIShellExtInitVbtl efvtIShellExtInit
=
51 ICompatibilityPage_fnInitialize
,
54 static ifaceIClassFactoryVbtl efvtIClassFactory
=
57 ICompatibilityPage_fnCreateInstance
,
58 ICompatibilityPage_fnLockServer
,
61 /******************************************************************************
63 ******************************************************************************/
66 ClearCItemList(LPCOMPATIBILITYPAGE info
)
70 for (item
= info
->CItems
;
75 HeapFree(GetProcessHeap(),
80 info
->CSelectedItem
= NULL
;
86 ReadDWORDFlag(HKEY hk
,
91 DWORD dwType
, dwSize
= sizeof(DWORD
);
92 LONG e
= RegQueryValueEx(hk
,
99 if (e
!= ERROR_SUCCESS
|| dwSize
!= sizeof(DWORD
))
101 *lpOutValue
= dwDefault
;
110 LoadAndParseAppCompatibilityFlags(LPCOMPATIBILITYPAGE info
,
115 DWORD dwType
, dwSize
;
118 e
= RegOpenKey(HKEY_CURRENT_USER
,
119 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"),
121 if (e
== ERROR_SUCCESS
)
123 dwSize
= sizeof(szStr
);
125 e
= RegQueryValueEx(hk
,
132 if (e
== ERROR_SUCCESS
)
134 /* FIXME - make sure the string is NULL-terminated! */
140 /* only the first word represents the compatibility mode */
141 /* FIXME - parse all words! */
149 info
->CSelectedItem
= NULL
;
150 if (_tcslen(szStr
) > 0)
154 for (item
= info
->CItems
;
158 if (!_tcsicmp(szStr
, item
->szKeyName
))
160 info
->CSelectedItem
= item
;
173 LoadCompatibilityModes(LPCOMPATIBILITYPAGE info
)
180 ClearCItemList(info
);
182 e
= RegOpenKey(HKEY_CURRENT_USER
,
183 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"),
186 if (e
== ERROR_SUCCESS
)
189 PCITEM lastitem
= NULL
;
192 (RegEnumKey(hk
, i
,szKey
, sizeof(szKey
) / sizeof(szKey
[0])) == ERROR_SUCCESS
);
199 if (e
== ERROR_SUCCESS
)
203 e
= RegQueryValueEx(hk2
,
210 if (e
!= ERROR_SUCCESS
|| (e
== ERROR_SUCCESS
&& dwType
== REG_SZ
))
214 item
= HeapAlloc(GetProcessHeap(),
219 DWORD cdb
= sizeof(item
->szName
);
222 e
= RegQueryValueEx(hk2
,
226 (LPBYTE
)item
->szName
,
229 /* make sure it is null-terminated */
230 if (cdb
> sizeof(item
->szName
) - sizeof(item
->szName
[0]))
232 item
->szName
[(sizeof(item
->szName
) / sizeof(item
->szName
[0])) - 1] = TEXT('\0');
235 if (e
!= ERROR_SUCCESS
||
236 cdb
< sizeof(item
->szName
[0]))
238 _tcscpy(item
->szName
, szKey
);
242 _tcscpy(item
->szKeyName
, szKey
);
246 TEXT("MajorVersion"),
250 TEXT("MinorVersion"),
262 TEXT("SPMajorVersion"),
263 &item
->SPMajorVersion
,
266 TEXT("SPMinorVersion"),
267 &item
->SPMinorVersion
,
270 if (e
== ERROR_SUCCESS
)
273 if (lastitem
!= NULL
)
275 lastitem
->next
= item
;
285 HeapFree(GetProcessHeap(),
295 if (e
!= ERROR_SUCCESS
)
303 Ret
= ((e
== ERROR_SUCCESS
|| e
== ERROR_NO_MORE_ITEMS
) ? TRUE
: FALSE
);
309 FillComboBoxWithCompatibilityModes(LPCOMPATIBILITYPAGE info
,
313 BOOL bDisableControlsIfEmpty
)
324 for (item
= info
->CItems
;
328 int iIndex
= (int)SendMessage(hCombo
,
331 (LPARAM
)item
->szName
);
333 if (item
== info
->CSelectedItem
&& bSelectItem
)
344 if (!sel
&& bSelectItem
&& i
> 0)
346 /* select the first item */
353 if (bDisableControlsIfEmpty
)
355 BOOL enable
= (i
> 0);
357 EnableWindow(GetDlgItem(hwndDlg
,
364 EnableWindow(GetDlgItem(hwndDlg
,
365 IDC_CHKRUNCOMPATIBILITY
),
368 CheckDlgButton(hwndDlg
,
369 IDC_CHKRUNCOMPATIBILITY
,
370 ((enable
&& sel
) ? BST_CHECKED
: BST_UNCHECKED
));
375 FillEditListBoxWithCompatibilityModes(LPCOMPATIBILITYPAGE info
,
378 BOOL bDisableControlsIfEmpty
)
383 SendMessage(hListBox
,
388 for (item
= info
->CItems
, i
= 0;
390 item
= item
->next
, i
++)
392 SendMessage(hListBox
,
395 (LPARAM
)item
->szName
);
398 if (bDisableControlsIfEmpty
)
403 static INT_PTR CALLBACK
404 EditCompatibilityModesProc(HWND hwndDlg
,
409 LPCOMPATIBILITYPAGE
this;
415 switch(LOWORD(wParam
))
439 HWND hList
= GetDlgItem(hwndDlg
,
440 IDC_COMPATIBILITYMODE
);
442 this = (LPCOMPATIBILITYPAGE
)lParam
;
443 SetWindowLongPtr(hwndDlg
,
447 FillEditListBoxWithCompatibilityModes(this,
459 InitializePage(LPCOMPATIBILITYPAGE
this,
464 LoadCompatibilityModes(this);
466 /* initialize the controls */
467 hList
= GetDlgItem(hwndDlg
,
468 IDC_COMPATIBILITYMODE
);
470 LoadAndParseAppCompatibilityFlags(this,
472 FillComboBoxWithCompatibilityModes(this,
480 ReportPropertyChange(LPCOMPATIBILITYPAGE
this,
483 this->Changed
= TRUE
;
485 SendMessage(GetParent(hwndDlg
),
492 ComposeFlags(LPCOMPATIBILITYPAGE
this,
495 if (this->CSelectedItem
!= NULL
)
498 this->CSelectedItem
->szKeyName
);
506 ApplySettings(LPCOMPATIBILITYPAGE
this,
512 BOOL enabled
= IsDlgButtonChecked(hwndDlg
,
513 IDC_CHKRUNCOMPATIBILITY
) == BST_CHECKED
;
517 HWND hCombo
= GetDlgItem(hwndDlg
,
518 IDC_COMPATIBILITYMODE
);
519 int index
= (int)SendMessage(hCombo
,
526 PCITEM sel
= this->CItems
;
528 /* map the index to a CITEM structure */
530 i
> 0 && sel
!= NULL
;
536 /* update the CSelectedItem member */
537 this->CSelectedItem
= sel
;
543 e
= RegOpenKey(HKEY_CURRENT_USER
,
544 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"),
546 if (e
== ERROR_SUCCESS
)
550 /* FIXME - only delete if nothing else is selected! */
551 e
= RegDeleteValue(hk
,
556 if (ComposeFlags(this,
559 e
= RegSetValueEx(hk
,
564 (_tcslen(szFlags
) + 1) * sizeof(TCHAR
));
568 e
= RegDeleteValue(hk
,
576 this->Changed
= FALSE
;
577 return (e
== ERROR_SUCCESS
);
580 static INT_PTR CALLBACK
581 CompatibilityPageProc(HWND hwndDlg
,
586 LPCOMPATIBILITYPAGE
this = (LPCOMPATIBILITYPAGE
)GetWindowLongPtr(hwndDlg
,
593 if (HIWORD(wParam
) == CBN_SELCHANGE
&& LOWORD(wParam
) == IDC_COMPATIBILITYMODE
)
595 ReportPropertyChange(this,
600 switch (LOWORD(wParam
))
602 case IDC_CHKRUNCOMPATIBILITY
:
604 HWND hList
= GetDlgItem(hwndDlg
,
605 IDC_COMPATIBILITYMODE
);
610 IsDlgButtonChecked(hwndDlg
,
611 IDC_CHKRUNCOMPATIBILITY
) == BST_CHECKED
);
616 case IDC_CHKRUNIN256COLORS
:
617 case IDC_CHKRUNIN640480RES
:
618 case IDC_CHKDISABLEVISUALTHEMES
:
619 ReportPropertyChange(this,
623 case IDC_EDITCOMPATIBILITYMODES
:
625 if (DialogBoxParam(hInstance
,
626 MAKEINTRESOURCE(IDD_EDITCOMPATIBILITYMODES
),
628 EditCompatibilityModesProc
,
629 (LPARAM
)this) == IDOK
)
643 NMHDR
*hdr
= (NMHDR
*)lParam
;
649 return ApplySettings(this,
659 LPPROPSHEETPAGE psp
= (LPPROPSHEETPAGE
)lParam
;
660 this = (LPCOMPATIBILITYPAGE
)psp
->lParam
;
661 SetWindowLongPtr(hwndDlg
,
675 CompatibilityPageCallback(HWND hwnd
,
677 LPPROPSHEETPAGE ppsp
)
679 LPCOMPATIBILITYPAGE
this = (LPCOMPATIBILITYPAGE
)ppsp
->lParam
;
687 ICompatibilityPage_fnRelease(this);
695 static LPCOMPATIBILITYPAGE
696 ICompatibilityPage_fnConstructor(VOID
)
698 LPCOMPATIBILITYPAGE cp
;
700 cp
= HeapAlloc(GetProcessHeap(),
702 sizeof(COMPATIBILITYPAGE
));
706 cp
->lpVtbl
->fn
.IShellPropSheetExt
= efvtIShellPropSheetExt
;
708 InterlockedIncrement(&dllrefs
);
714 HRESULT STDMETHODCALLTYPE
715 ICompatibilityPage_fnQueryInterface(LPCOMPATIBILITYPAGE
this,
720 &IID_IShellPropSheetExt
))
722 this->lpVtbl
->fn
.IShellPropSheetExt
= efvtIShellPropSheetExt
;
723 ICompatibilityPage_fnAddRef(this);
727 else if (IsEqualIID(iid
,
730 this->lpVtbl
->fn
.IShellExtInit
= efvtIShellExtInit
;
731 ICompatibilityPage_fnAddRef(this);
735 else if (IsEqualIID(iid
,
738 this->lpVtbl
->fn
.IClassFactory
= efvtIClassFactory
;
739 ICompatibilityPage_fnAddRef(this);
743 else if (IsEqualIID(iid
,
746 ICompatibilityPage_fnAddRef(this);
752 return E_NOINTERFACE
;
755 ULONG STDMETHODCALLTYPE
756 ICompatibilityPage_fnAddRef(LPCOMPATIBILITYPAGE
this)
758 return (ULONG
)InterlockedIncrement(&this->ref
);
761 ULONG STDMETHODCALLTYPE
762 ICompatibilityPage_fnRelease(LPCOMPATIBILITYPAGE
this)
766 rfc
= (ULONG
)InterlockedDecrement(&this->ref
);
769 HeapFree(GetProcessHeap(),
772 InterlockedDecrement(&dllrefs
);
777 HRESULT STDMETHODCALLTYPE
778 ICompatibilityPage_fnAddPages(LPCOMPATIBILITYPAGE
this,
779 LPFNADDPROPSHEETPAGE lpfnAddPage
,
782 PROPSHEETPAGE psp
= {0};
783 HPROPSHEETPAGE hPage
;
785 psp
.dwSize
= sizeof(psp
);
786 psp
.dwFlags
= PSP_DEFAULT
| PSP_USECALLBACK
;
787 psp
.hInstance
= hInstance
;
788 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_SLAYERSHEET
);
789 psp
.pfnDlgProc
= CompatibilityPageProc
;
790 psp
.lParam
= (LPARAM
)this;
791 psp
.pfnCallback
= CompatibilityPageCallback
;
793 hPage
= CreatePropertySheetPage(&psp
);
797 if (!lpfnAddPage(hPage
,
800 DestroyPropertySheetPage(hPage
);
801 return E_OUTOFMEMORY
;
804 ICompatibilityPage_fnAddRef(this);
811 HRESULT STDMETHODCALLTYPE
812 ICompatibilityPage_fnReplacePage(LPCOMPATIBILITYPAGE
this,
814 LPFNADDPROPSHEETPAGE lpfnReplacePage
,
820 HRESULT STDMETHODCALLTYPE
821 ICompatibilityPage_fnInitialize(LPCOMPATIBILITYPAGE
this,
822 LPCITEMIDLIST pidlFolder
,
834 fetc
.cfFormat
= CF_HDROP
;
836 fetc
.dwAspect
= DVASPECT_CONTENT
;
838 fetc
.tymed
= TYMED_HGLOBAL
;
840 if (SUCCEEDED(pdtobj
->lpVtbl
->GetData(pdtobj
,
844 UINT nFiles
= DragQueryFile(smdm
.hGlobal
,
847 sizeof(this->szFile
) / sizeof(this->szFile
[0]));
850 /* FIXME - support editing of multiple files later */
851 DragQueryFile(smdm
.hGlobal
,
853 sizeof(this->szFile
) / sizeof(this->szFile
[0]));
854 ReleaseStgMedium(&smdm
);
863 HRESULT STDMETHODCALLTYPE
864 ICompatibilityPage_fnCreateInstance(LPCOMPATIBILITYPAGE
this,
869 LPCOMPATIBILITYPAGE cp
;
871 if (pUnkOuter
!= NULL
&&
875 return CLASS_E_NOAGGREGATION
;
878 cp
= ICompatibilityPage_fnConstructor();
881 HRESULT ret
= ICompatibilityPage_fnQueryInterface(cp
,
884 ICompatibilityPage_fnRelease(cp
);
888 return E_OUTOFMEMORY
;
891 HRESULT STDMETHODCALLTYPE
892 ICompatibilityPage_fnLockServer(LPCOMPATIBILITYPAGE
this,
897 InterlockedIncrement(&dllrefs
);
901 InterlockedDecrement(&dllrefs
);
907 /******************************************************************************
909 ******************************************************************************/
912 DllGetClassObject(REFCLSID rclsid
,
921 if (IsEqualCLSID(&CLSID_ICompatibilityPage
,
924 LPCOMPATIBILITYPAGE iface
= ICompatibilityPage_fnConstructor();
927 HRESULT ret
= ICompatibilityPage_fnQueryInterface(iface
,
930 ICompatibilityPage_fnRelease(iface
);
933 return E_OUTOFMEMORY
;
936 return CLASS_E_CLASSNOTAVAILABLE
;
940 DllCanUnloadNow(VOID
)
942 return ((dllrefs
== 0) ? S_OK
: S_FALSE
);
946 UnregisterPropSheetHandler(LPTSTR szType
)
951 TEXT("%s\\shellex\\PropertySheetHandlers\\Compatibility Property Page"),
954 return RegDeleteKey(HKEY_CLASSES_ROOT
,
959 DllUnregisterServer(VOID
)
965 StringFromGUID2(&CLSID_ICompatibilityPage
,
967 sizeof(szGuid
) / sizeof(szGuid
[0]));
969 e
= RegOpenKey(HKEY_LOCAL_MACHINE
,
970 TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"),
972 if (e
== ERROR_SUCCESS
)
974 e
= RegDeleteValueW(hk
,
979 if (e
== ERROR_SUCCESS
)
981 e
= UnregisterPropSheetHandler(TEXT("exefile"));
984 if (e
== ERROR_SUCCESS
)
986 e
= RegOpenKey(HKEY_CLASSES_ROOT
,
989 if (e
== ERROR_SUCCESS
)
991 TCHAR szInprocKey
[255];
993 _stprintf(szInprocKey
,
994 TEXT("%ws\\InprocServer32"),
999 if (e
== ERROR_SUCCESS
)
1001 e
= RegDeleteKeyW(hk
,
1008 return ((e
== ERROR_SUCCESS
) ? S_OK
: E_ACCESSDENIED
);
1012 RegisterPropSheetHandler(LPTSTR szType
,
1020 TEXT("%s\\shellex\\PropertySheetHandlers\\Compatibility Property Page"),
1023 e
= RegCreateKey(HKEY_CLASSES_ROOT
,
1026 if (e
== ERROR_SUCCESS
)
1028 e
= RegSetValueExW(hk
,
1033 (wcslen(szGuid
) + 1) * sizeof(WCHAR
));
1041 DllRegisterServer(VOID
)
1043 LONG e
= E_ACCESSDENIED
;
1046 WCHAR szDescription
[255];
1047 TCHAR szModule
[MAX_PATH
+ 1];
1048 int lnszDescription
;
1050 if (!GetModuleFileName(hInstance
,
1052 sizeof(szModule
) / sizeof(szModule
[0])))
1054 return E_ACCESSDENIED
;
1057 /* unregister first */
1058 DllUnregisterServer();
1060 lnszDescription
= LoadStringW(hInstance
,
1062 szDescription
, sizeof(szDescription
) / sizeof(szDescription
[0]));
1063 if (lnszDescription
> 0)
1065 StringFromGUID2(&CLSID_ICompatibilityPage
,
1067 sizeof(szGuid
) / sizeof(szGuid
[0]));
1069 e
= RegOpenKey(HKEY_LOCAL_MACHINE
,
1070 TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"),
1072 if (e
== ERROR_SUCCESS
)
1074 e
= RegSetValueExW(hk
,
1078 (BYTE
*)szDescription
,
1079 (lnszDescription
+ 1) * sizeof(WCHAR
));
1083 if (e
== ERROR_SUCCESS
)
1085 TCHAR szInprocKey
[255];
1087 _stprintf(szInprocKey
,
1088 TEXT("CLSID\\%ws\\InprocServer32"),
1091 e
= RegCreateKey(HKEY_CLASSES_ROOT
,
1094 if (e
== ERROR_SUCCESS
)
1096 e
= RegSetValueEx(hk
,
1101 (_tcslen(szModule
) + 1) * sizeof(TCHAR
));
1102 if (e
== ERROR_SUCCESS
)
1104 const TCHAR szApartment
[] = TEXT("Apartment");
1106 e
= RegSetValueEx(hk
,
1107 TEXT("ThreadingModel"),
1111 (_tcslen(szApartment
) + 1) * sizeof(TCHAR
));
1118 if (e
== ERROR_SUCCESS
)
1120 e
= RegisterPropSheetHandler(TEXT("exefile"),
1125 return ((e
== ERROR_SUCCESS
) ? S_OK
: E_ACCESSDENIED
);
1129 DllMain(HINSTANCE hinstDLL
,
1135 case DLL_PROCESS_ATTACH
:
1136 hInstance
= hinstDLL
;
1137 DisableThreadLibraryCalls(hInstance
);