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
20 * PROJECT: ReactOS Compatibility Layer Shell Extension
21 * FILE: lib/shellext/cplsample/cplsample.c
22 * PURPOSE: ReactOS Compatibility Layer Shell Extension
23 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
30 #define WIN32_NO_STATUS
32 #define COM_NO_WINDOWS_H
44 HINSTANCE hInstance
= NULL
;
45 static LONG dllrefs
= 0;
47 static ifaceICompatibilityPageVbtl efvt
=
49 /* IUnknown methods */
50 ICompatibilityPage_fnQueryInterface
,
51 ICompatibilityPage_fnAddRef
,
52 ICompatibilityPage_fnRelease
,
55 static ifaceIShellPropSheetExtVbtl efvtIShellPropSheetExt
=
57 /* IShellPropSheetExt */
58 ICompatibilityPage_fnAddPages
,
59 ICompatibilityPage_fnReplacePage
,
62 static ifaceIShellExtInitVbtl efvtIShellExtInit
=
65 ICompatibilityPage_fnInitialize
,
68 static ifaceIClassFactoryVbtl efvtIClassFactory
=
71 ICompatibilityPage_fnCreateInstance
,
72 ICompatibilityPage_fnLockServer
,
75 /******************************************************************************
77 ******************************************************************************/
80 ClearCItemList(LPCOMPATIBILITYPAGE info
)
84 for (item
= info
->CItems
;
89 HeapFree(GetProcessHeap(),
94 info
->CSelectedItem
= NULL
;
100 ReadDWORDFlag(HKEY hk
,
105 DWORD dwType
, dwSize
= sizeof(DWORD
);
106 LONG e
= RegQueryValueEx(hk
,
113 if (e
!= ERROR_SUCCESS
|| dwSize
!= sizeof(DWORD
))
115 *lpOutValue
= dwDefault
;
124 LoadAndParseAppCompatibilityFlags(LPCOMPATIBILITYPAGE info
,
129 DWORD dwType
, dwSize
;
132 e
= RegOpenKey(HKEY_CURRENT_USER
,
133 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"),
135 if (e
== ERROR_SUCCESS
)
137 dwSize
= sizeof(szStr
);
139 e
= RegQueryValueEx(hk
,
146 if (e
== ERROR_SUCCESS
)
148 /* FIXME - make sure the string is NULL-terminated! */
154 /* only the first word represents the compatibility mode */
155 /* FIXME - parse all words! */
163 info
->CSelectedItem
= NULL
;
164 if (_tcslen(szStr
) > 0)
168 for (item
= info
->CItems
;
172 if (!_tcsicmp(szStr
, item
->szKeyName
))
174 info
->CSelectedItem
= item
;
187 LoadCompatibilityModes(LPCOMPATIBILITYPAGE info
)
194 ClearCItemList(info
);
196 e
= RegOpenKey(HKEY_CURRENT_USER
,
197 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"),
200 if (e
== ERROR_SUCCESS
)
203 PCITEM lastitem
= NULL
;
206 (RegEnumKey(hk
, i
,szKey
, sizeof(szKey
) / sizeof(szKey
[0])) == ERROR_SUCCESS
);
213 if (e
== ERROR_SUCCESS
)
217 e
= RegQueryValueEx(hk2
,
224 if (e
!= ERROR_SUCCESS
|| (e
== ERROR_SUCCESS
&& dwType
== REG_SZ
))
228 item
= HeapAlloc(GetProcessHeap(),
233 DWORD cdb
= sizeof(item
->szName
);
236 e
= RegQueryValueEx(hk2
,
240 (LPBYTE
)item
->szName
,
243 /* make sure it is null-terminated */
244 if (cdb
> sizeof(item
->szName
) - sizeof(item
->szName
[0]))
246 item
->szName
[(sizeof(item
->szName
) / sizeof(item
->szName
[0])) - 1] = TEXT('\0');
249 if (e
!= ERROR_SUCCESS
||
250 cdb
< sizeof(item
->szName
[0]))
252 _tcscpy(item
->szName
, szKey
);
256 _tcscpy(item
->szKeyName
, szKey
);
260 TEXT("MajorVersion"),
264 TEXT("MinorVersion"),
276 TEXT("SPMajorVersion"),
277 &item
->SPMajorVersion
,
280 TEXT("SPMinorVersion"),
281 &item
->SPMinorVersion
,
284 if (e
== ERROR_SUCCESS
)
287 if (lastitem
!= NULL
)
289 lastitem
->next
= item
;
299 HeapFree(GetProcessHeap(),
309 if (e
!= ERROR_SUCCESS
)
317 Ret
= ((e
== ERROR_SUCCESS
|| e
== ERROR_NO_MORE_ITEMS
) ? TRUE
: FALSE
);
323 FillComboBoxWithCompatibilityModes(LPCOMPATIBILITYPAGE info
,
327 BOOL bDisableControlsIfEmpty
)
338 for (item
= info
->CItems
;
342 int iIndex
= (int)SendMessage(hCombo
,
345 (LPARAM
)item
->szName
);
347 if (item
== info
->CSelectedItem
&& bSelectItem
)
358 if (!sel
&& bSelectItem
&& i
> 0)
360 /* select the first item */
367 if (bDisableControlsIfEmpty
)
369 BOOL enable
= (i
> 0);
371 EnableWindow(GetDlgItem(hwndDlg
,
378 EnableWindow(GetDlgItem(hwndDlg
,
379 IDC_CHKRUNCOMPATIBILITY
),
382 CheckDlgButton(hwndDlg
,
383 IDC_CHKRUNCOMPATIBILITY
,
384 ((enable
&& sel
) ? BST_CHECKED
: BST_UNCHECKED
));
389 FillEditListBoxWithCompatibilityModes(LPCOMPATIBILITYPAGE info
,
392 BOOL bDisableControlsIfEmpty
)
397 SendMessage(hListBox
,
402 for (item
= info
->CItems
, i
= 0;
404 item
= item
->next
, i
++)
406 SendMessage(hListBox
,
409 (LPARAM
)item
->szName
);
412 if (bDisableControlsIfEmpty
)
417 static INT_PTR CALLBACK
418 EditCompatibilityModesProc(HWND hwndDlg
,
423 LPCOMPATIBILITYPAGE
this;
429 switch(LOWORD(wParam
))
453 HWND hList
= GetDlgItem(hwndDlg
,
454 IDC_COMPATIBILITYMODE
);
456 this = (LPCOMPATIBILITYPAGE
)lParam
;
457 SetWindowLongPtr(hwndDlg
,
461 FillEditListBoxWithCompatibilityModes(this,
473 InitializePage(LPCOMPATIBILITYPAGE
this,
478 LoadCompatibilityModes(this);
480 /* initialize the controls */
481 hList
= GetDlgItem(hwndDlg
,
482 IDC_COMPATIBILITYMODE
);
484 LoadAndParseAppCompatibilityFlags(this,
486 FillComboBoxWithCompatibilityModes(this,
494 ReportPropertyChange(LPCOMPATIBILITYPAGE
this,
497 this->Changed
= TRUE
;
499 SendMessage(GetParent(hwndDlg
),
506 ComposeFlags(LPCOMPATIBILITYPAGE
this,
509 if (this->CSelectedItem
!= NULL
)
512 this->CSelectedItem
->szKeyName
);
520 ApplySettings(LPCOMPATIBILITYPAGE
this,
526 BOOL enabled
= IsDlgButtonChecked(hwndDlg
,
527 IDC_CHKRUNCOMPATIBILITY
) == BST_CHECKED
;
531 HWND hCombo
= GetDlgItem(hwndDlg
,
532 IDC_COMPATIBILITYMODE
);
533 int index
= (int)SendMessage(hCombo
,
540 PCITEM sel
= this->CItems
;
542 /* map the index to a CITEM structure */
544 i
> 0 && sel
!= NULL
;
550 /* update the CSelectedItem member */
551 this->CSelectedItem
= sel
;
557 e
= RegOpenKey(HKEY_CURRENT_USER
,
558 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"),
560 if (e
== ERROR_SUCCESS
)
564 /* FIXME - only delete if nothing else is selected! */
565 e
= RegDeleteValue(hk
,
570 if (ComposeFlags(this,
573 e
= RegSetValueEx(hk
,
578 (_tcslen(szFlags
) + 1) * sizeof(TCHAR
));
582 e
= RegDeleteValue(hk
,
590 this->Changed
= FALSE
;
591 return (e
== ERROR_SUCCESS
);
594 static INT_PTR CALLBACK
595 CompatibilityPageProc(HWND hwndDlg
,
600 LPCOMPATIBILITYPAGE
this = (LPCOMPATIBILITYPAGE
)GetWindowLongPtr(hwndDlg
,
607 if (HIWORD(wParam
) == CBN_SELCHANGE
&& LOWORD(wParam
) == IDC_COMPATIBILITYMODE
)
609 ReportPropertyChange(this,
614 switch (LOWORD(wParam
))
616 case IDC_CHKRUNCOMPATIBILITY
:
618 HWND hList
= GetDlgItem(hwndDlg
,
619 IDC_COMPATIBILITYMODE
);
624 IsDlgButtonChecked(hwndDlg
,
625 IDC_CHKRUNCOMPATIBILITY
) == BST_CHECKED
);
630 case IDC_CHKRUNIN256COLORS
:
631 case IDC_CHKRUNIN640480RES
:
632 case IDC_CHKDISABLEVISUALTHEMES
:
633 ReportPropertyChange(this,
637 case IDC_EDITCOMPATIBILITYMODES
:
639 if (DialogBoxParam(hInstance
,
640 MAKEINTRESOURCE(IDD_EDITCOMPATIBILITYMODES
),
642 EditCompatibilityModesProc
,
643 (LPARAM
)this) == IDOK
)
657 NMHDR
*hdr
= (NMHDR
*)lParam
;
663 return ApplySettings(this,
673 LPPROPSHEETPAGE psp
= (LPPROPSHEETPAGE
)lParam
;
674 this = (LPCOMPATIBILITYPAGE
)psp
->lParam
;
675 SetWindowLongPtr(hwndDlg
,
689 CompatibilityPageCallback(HWND hwnd
,
691 LPPROPSHEETPAGE ppsp
)
693 LPCOMPATIBILITYPAGE
this = (LPCOMPATIBILITYPAGE
)ppsp
->lParam
;
701 ICompatibilityPage_fnRelease(this);
709 static LPCOMPATIBILITYPAGE
710 ICompatibilityPage_fnConstructor(VOID
)
712 LPCOMPATIBILITYPAGE cp
;
714 cp
= HeapAlloc(GetProcessHeap(),
716 sizeof(COMPATIBILITYPAGE
));
720 cp
->lpVtbl
->fn
.IShellPropSheetExt
= efvtIShellPropSheetExt
;
722 InterlockedIncrement(&dllrefs
);
728 HRESULT STDMETHODCALLTYPE
729 ICompatibilityPage_fnQueryInterface(LPCOMPATIBILITYPAGE
this,
734 &IID_IShellPropSheetExt
))
736 this->lpVtbl
->fn
.IShellPropSheetExt
= efvtIShellPropSheetExt
;
737 ICompatibilityPage_fnAddRef(this);
741 else if (IsEqualIID(iid
,
744 this->lpVtbl
->fn
.IShellExtInit
= efvtIShellExtInit
;
745 ICompatibilityPage_fnAddRef(this);
749 else if (IsEqualIID(iid
,
752 this->lpVtbl
->fn
.IClassFactory
= efvtIClassFactory
;
753 ICompatibilityPage_fnAddRef(this);
757 else if (IsEqualIID(iid
,
760 ICompatibilityPage_fnAddRef(this);
766 return E_NOINTERFACE
;
769 ULONG STDMETHODCALLTYPE
770 ICompatibilityPage_fnAddRef(LPCOMPATIBILITYPAGE
this)
772 return (ULONG
)InterlockedIncrement(&this->ref
);
775 ULONG STDMETHODCALLTYPE
776 ICompatibilityPage_fnRelease(LPCOMPATIBILITYPAGE
this)
780 rfc
= (ULONG
)InterlockedDecrement(&this->ref
);
783 HeapFree(GetProcessHeap(),
786 InterlockedDecrement(&dllrefs
);
791 HRESULT STDMETHODCALLTYPE
792 ICompatibilityPage_fnAddPages(LPCOMPATIBILITYPAGE
this,
793 LPFNADDPROPSHEETPAGE lpfnAddPage
,
796 PROPSHEETPAGE psp
= {0};
797 HPROPSHEETPAGE hPage
;
799 psp
.dwSize
= sizeof(psp
);
800 psp
.dwFlags
= PSP_DEFAULT
| PSP_USECALLBACK
;
801 psp
.hInstance
= hInstance
;
802 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_SLAYERSHEET
);
803 psp
.pfnDlgProc
= CompatibilityPageProc
;
804 psp
.lParam
= (LPARAM
)this;
805 psp
.pfnCallback
= CompatibilityPageCallback
;
807 hPage
= CreatePropertySheetPage(&psp
);
811 if (!lpfnAddPage(hPage
,
814 DestroyPropertySheetPage(hPage
);
815 return E_OUTOFMEMORY
;
818 ICompatibilityPage_fnAddRef(this);
825 HRESULT STDMETHODCALLTYPE
826 ICompatibilityPage_fnReplacePage(LPCOMPATIBILITYPAGE
this,
828 LPFNADDPROPSHEETPAGE lpfnReplacePage
,
834 HRESULT STDMETHODCALLTYPE
835 ICompatibilityPage_fnInitialize(LPCOMPATIBILITYPAGE
this,
836 LPCITEMIDLIST pidlFolder
,
848 fetc
.cfFormat
= CF_HDROP
;
850 fetc
.dwAspect
= DVASPECT_CONTENT
;
852 fetc
.tymed
= TYMED_HGLOBAL
;
854 if (SUCCEEDED(pdtobj
->lpVtbl
->GetData(pdtobj
,
858 UINT nFiles
= DragQueryFile(smdm
.hGlobal
,
861 sizeof(this->szFile
) / sizeof(this->szFile
[0]));
864 /* FIXME - support editing of multiple files later */
865 DragQueryFile(smdm
.hGlobal
,
867 sizeof(this->szFile
) / sizeof(this->szFile
[0]));
868 ReleaseStgMedium(&smdm
);
877 HRESULT STDMETHODCALLTYPE
878 ICompatibilityPage_fnCreateInstance(LPCOMPATIBILITYPAGE
this,
883 LPCOMPATIBILITYPAGE cp
;
885 if (pUnkOuter
!= NULL
&&
889 return CLASS_E_NOAGGREGATION
;
892 cp
= ICompatibilityPage_fnConstructor();
895 HRESULT ret
= ICompatibilityPage_fnQueryInterface(cp
,
898 ICompatibilityPage_fnRelease(cp
);
902 return E_OUTOFMEMORY
;
905 HRESULT STDMETHODCALLTYPE
906 ICompatibilityPage_fnLockServer(LPCOMPATIBILITYPAGE
this,
911 InterlockedIncrement(&dllrefs
);
915 InterlockedDecrement(&dllrefs
);
921 /******************************************************************************
923 ******************************************************************************/
926 DllGetClassObject(REFCLSID rclsid
,
935 if (IsEqualCLSID(&CLSID_ICompatibilityPage
,
938 LPCOMPATIBILITYPAGE iface
= ICompatibilityPage_fnConstructor();
941 HRESULT ret
= ICompatibilityPage_fnQueryInterface(iface
,
944 ICompatibilityPage_fnRelease(iface
);
947 return E_OUTOFMEMORY
;
950 return CLASS_E_CLASSNOTAVAILABLE
;
954 DllCanUnloadNow(VOID
)
956 return ((dllrefs
== 0) ? S_OK
: S_FALSE
);
960 UnregisterPropSheetHandler(LPTSTR szType
)
965 TEXT("%s\\shellex\\PropertySheetHandlers\\Compatibility Property Page"),
968 return RegDeleteKey(HKEY_CLASSES_ROOT
,
973 DllUnregisterServer(VOID
)
979 StringFromGUID2(&CLSID_ICompatibilityPage
,
981 sizeof(szGuid
) / sizeof(szGuid
[0]));
983 e
= RegOpenKey(HKEY_LOCAL_MACHINE
,
984 TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"),
986 if (e
== ERROR_SUCCESS
)
988 e
= RegDeleteValueW(hk
,
993 if (e
== ERROR_SUCCESS
)
995 e
= UnregisterPropSheetHandler(TEXT("exefile"));
998 if (e
== ERROR_SUCCESS
)
1000 e
= RegOpenKey(HKEY_CLASSES_ROOT
,
1003 if (e
== ERROR_SUCCESS
)
1005 TCHAR szInprocKey
[255];
1007 _stprintf(szInprocKey
,
1008 TEXT("%ws\\InprocServer32"),
1011 e
= RegDeleteKey(hk
,
1013 if (e
== ERROR_SUCCESS
)
1015 e
= RegDeleteKeyW(hk
,
1022 return ((e
== ERROR_SUCCESS
) ? S_OK
: E_ACCESSDENIED
);
1026 RegisterPropSheetHandler(LPTSTR szType
,
1034 TEXT("%s\\shellex\\PropertySheetHandlers\\Compatibility Property Page"),
1037 e
= RegCreateKey(HKEY_CLASSES_ROOT
,
1040 if (e
== ERROR_SUCCESS
)
1042 e
= RegSetValueExW(hk
,
1047 (wcslen(szGuid
) + 1) * sizeof(WCHAR
));
1055 DllRegisterServer(VOID
)
1057 LONG e
= E_ACCESSDENIED
;
1060 WCHAR szDescription
[255];
1061 TCHAR szModule
[MAX_PATH
+ 1];
1062 int lnszDescription
;
1064 if (!GetModuleFileName(hInstance
,
1066 sizeof(szModule
) / sizeof(szModule
[0])))
1068 return E_ACCESSDENIED
;
1071 /* unregister first */
1072 DllUnregisterServer();
1074 lnszDescription
= LoadStringW(hInstance
,
1076 szDescription
, sizeof(szDescription
) / sizeof(szDescription
[0]));
1077 if (lnszDescription
> 0)
1079 StringFromGUID2(&CLSID_ICompatibilityPage
,
1081 sizeof(szGuid
) / sizeof(szGuid
[0]));
1083 e
= RegOpenKey(HKEY_LOCAL_MACHINE
,
1084 TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"),
1086 if (e
== ERROR_SUCCESS
)
1088 e
= RegSetValueExW(hk
,
1092 (BYTE
*)szDescription
,
1093 (lnszDescription
+ 1) * sizeof(WCHAR
));
1097 if (e
== ERROR_SUCCESS
)
1099 TCHAR szInprocKey
[255];
1101 _stprintf(szInprocKey
,
1102 TEXT("CLSID\\%ws\\InprocServer32"),
1105 e
= RegCreateKey(HKEY_CLASSES_ROOT
,
1108 if (e
== ERROR_SUCCESS
)
1110 e
= RegSetValueEx(hk
,
1115 (_tcslen(szModule
) + 1) * sizeof(TCHAR
));
1116 if (e
== ERROR_SUCCESS
)
1118 const TCHAR szApartment
[] = TEXT("Apartment");
1120 e
= RegSetValueEx(hk
,
1121 TEXT("ThreadingModel"),
1125 (_tcslen(szApartment
) + 1) * sizeof(TCHAR
));
1132 if (e
== ERROR_SUCCESS
)
1134 e
= RegisterPropSheetHandler(TEXT("exefile"),
1139 return ((e
== ERROR_SUCCESS
) ? S_OK
: E_ACCESSDENIED
);
1143 DllMain(HINSTANCE hinstDLL
,
1149 case DLL_PROCESS_ATTACH
:
1150 hInstance
= hinstDLL
;
1151 DisableThreadLibraryCalls(hInstance
);