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>
29 HINSTANCE hInstance
= NULL
;
30 static LONG dllrefs
= 0;
32 static ifaceICompatibilityPageVbtl efvt
=
34 /* IUnknown methods */
35 ICompatibilityPage_fnQueryInterface
,
36 ICompatibilityPage_fnAddRef
,
37 ICompatibilityPage_fnRelease
,
40 static ifaceIShellPropSheetExtVbtl efvtIShellPropSheetExt
=
42 /* IShellPropSheetExt */
43 ICompatibilityPage_fnAddPages
,
44 ICompatibilityPage_fnReplacePage
,
47 static ifaceIShellExtInitVbtl efvtIShellExtInit
=
50 ICompatibilityPage_fnInitialize
,
53 static ifaceIClassFactoryVbtl efvtIClassFactory
=
56 ICompatibilityPage_fnCreateInstance
,
57 ICompatibilityPage_fnLockServer
,
60 /******************************************************************************
62 ******************************************************************************/
65 ClearCItemList(LPCOMPATIBILITYPAGE info
)
69 for (item
= info
->CItems
;
74 HeapFree(GetProcessHeap(),
79 info
->CSelectedItem
= NULL
;
85 ReadDWORDFlag(HKEY hk
,
90 DWORD dwType
, dwSize
= sizeof(DWORD
);
91 LONG e
= RegQueryValueEx(hk
,
98 if (e
!= ERROR_SUCCESS
|| dwSize
!= sizeof(DWORD
))
100 *lpOutValue
= dwDefault
;
109 LoadAndParseAppCompatibilityFlags(LPCOMPATIBILITYPAGE info
,
114 DWORD dwType
, dwSize
;
117 e
= RegOpenKey(HKEY_CURRENT_USER
,
118 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"),
120 if (e
== ERROR_SUCCESS
)
122 dwSize
= sizeof(szStr
);
124 e
= RegQueryValueEx(hk
,
131 if (e
== ERROR_SUCCESS
)
133 /* FIXME - make sure the string is NULL-terminated! */
139 /* only the first word represents the compatibility mode */
140 /* FIXME - parse all words! */
148 info
->CSelectedItem
= NULL
;
149 if (_tcslen(szStr
) > 0)
153 for (item
= info
->CItems
;
157 if (!_tcsicmp(szStr
, item
->szKeyName
))
159 info
->CSelectedItem
= item
;
172 LoadCompatibilityModes(LPCOMPATIBILITYPAGE info
)
179 ClearCItemList(info
);
181 e
= RegOpenKey(HKEY_CURRENT_USER
,
182 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"),
185 if (e
== ERROR_SUCCESS
)
188 PCITEM lastitem
= NULL
;
191 (RegEnumKey(hk
, i
,szKey
, sizeof(szKey
) / sizeof(szKey
[0])) == ERROR_SUCCESS
);
198 if (e
== ERROR_SUCCESS
)
202 e
= RegQueryValueEx(hk2
,
209 if (e
!= ERROR_SUCCESS
|| (e
== ERROR_SUCCESS
&& dwType
== REG_SZ
))
213 item
= HeapAlloc(GetProcessHeap(),
218 DWORD cdb
= sizeof(item
->szName
);
221 e
= RegQueryValueEx(hk2
,
225 (LPBYTE
)item
->szName
,
228 /* make sure it is null-terminated */
229 if (cdb
> sizeof(item
->szName
) - sizeof(item
->szName
[0]))
231 item
->szName
[(sizeof(item
->szName
) / sizeof(item
->szName
[0])) - 1] = TEXT('\0');
234 if (e
!= ERROR_SUCCESS
||
235 cdb
< sizeof(item
->szName
[0]))
237 _tcscpy(item
->szName
, szKey
);
241 _tcscpy(item
->szKeyName
, szKey
);
245 TEXT("MajorVersion"),
249 TEXT("MinorVersion"),
261 TEXT("SPMajorVersion"),
262 &item
->SPMajorVersion
,
265 TEXT("SPMinorVersion"),
266 &item
->SPMinorVersion
,
269 if (e
== ERROR_SUCCESS
)
272 if (lastitem
!= NULL
)
274 lastitem
->next
= item
;
284 HeapFree(GetProcessHeap(),
294 if (e
!= ERROR_SUCCESS
)
302 Ret
= ((e
== ERROR_SUCCESS
|| e
== ERROR_NO_MORE_ITEMS
) ? TRUE
: FALSE
);
308 FillComboBoxWithCompatibilityModes(LPCOMPATIBILITYPAGE info
,
312 BOOL bDisableControlsIfEmpty
)
323 for (item
= info
->CItems
;
327 int iIndex
= (int)SendMessage(hCombo
,
330 (LPARAM
)item
->szName
);
332 if (item
== info
->CSelectedItem
&& bSelectItem
)
343 if (!sel
&& bSelectItem
&& i
> 0)
345 /* select the first item */
352 if (bDisableControlsIfEmpty
)
354 BOOL enable
= (i
> 0);
356 EnableWindow(GetDlgItem(hwndDlg
,
363 EnableWindow(GetDlgItem(hwndDlg
,
364 IDC_CHKRUNCOMPATIBILITY
),
367 CheckDlgButton(hwndDlg
,
368 IDC_CHKRUNCOMPATIBILITY
,
369 ((enable
&& sel
) ? BST_CHECKED
: BST_UNCHECKED
));
374 FillEditListBoxWithCompatibilityModes(LPCOMPATIBILITYPAGE info
,
377 BOOL bDisableControlsIfEmpty
)
382 SendMessage(hListBox
,
387 for (item
= info
->CItems
, i
= 0;
389 item
= item
->next
, i
++)
391 SendMessage(hListBox
,
394 (LPARAM
)item
->szName
);
397 if (bDisableControlsIfEmpty
)
402 static INT_PTR CALLBACK
403 EditCompatibilityModesProc(HWND hwndDlg
,
408 LPCOMPATIBILITYPAGE
this;
414 switch(LOWORD(wParam
))
438 HWND hList
= GetDlgItem(hwndDlg
,
439 IDC_COMPATIBILITYMODE
);
441 this = (LPCOMPATIBILITYPAGE
)lParam
;
442 SetWindowLongPtr(hwndDlg
,
446 FillEditListBoxWithCompatibilityModes(this,
458 InitializePage(LPCOMPATIBILITYPAGE
this,
463 LoadCompatibilityModes(this);
465 /* initialize the controls */
466 hList
= GetDlgItem(hwndDlg
,
467 IDC_COMPATIBILITYMODE
);
469 LoadAndParseAppCompatibilityFlags(this,
471 FillComboBoxWithCompatibilityModes(this,
479 ReportPropertyChange(LPCOMPATIBILITYPAGE
this,
482 this->Changed
= TRUE
;
484 SendMessage(GetParent(hwndDlg
),
491 ComposeFlags(LPCOMPATIBILITYPAGE
this,
494 if (this->CSelectedItem
!= NULL
)
497 this->CSelectedItem
->szKeyName
);
505 ApplySettings(LPCOMPATIBILITYPAGE
this,
511 BOOL enabled
= IsDlgButtonChecked(hwndDlg
,
512 IDC_CHKRUNCOMPATIBILITY
) == BST_CHECKED
;
516 HWND hCombo
= GetDlgItem(hwndDlg
,
517 IDC_COMPATIBILITYMODE
);
518 int index
= (int)SendMessage(hCombo
,
525 PCITEM sel
= this->CItems
;
527 /* map the index to a CITEM structure */
529 i
> 0 && sel
!= NULL
;
535 /* update the CSelectedItem member */
536 this->CSelectedItem
= sel
;
542 e
= RegOpenKey(HKEY_CURRENT_USER
,
543 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"),
545 if (e
== ERROR_SUCCESS
)
549 /* FIXME - only delete if nothing else is selected! */
550 e
= RegDeleteValue(hk
,
555 if (ComposeFlags(this,
558 e
= RegSetValueEx(hk
,
563 (_tcslen(szFlags
) + 1) * sizeof(TCHAR
));
567 e
= RegDeleteValue(hk
,
575 this->Changed
= FALSE
;
576 return (e
== ERROR_SUCCESS
);
579 static INT_PTR CALLBACK
580 CompatibilityPageProc(HWND hwndDlg
,
585 LPCOMPATIBILITYPAGE
this = (LPCOMPATIBILITYPAGE
)GetWindowLongPtr(hwndDlg
,
592 if (HIWORD(wParam
) == CBN_SELCHANGE
&& LOWORD(wParam
) == IDC_COMPATIBILITYMODE
)
594 ReportPropertyChange(this,
599 switch (LOWORD(wParam
))
601 case IDC_CHKRUNCOMPATIBILITY
:
603 HWND hList
= GetDlgItem(hwndDlg
,
604 IDC_COMPATIBILITYMODE
);
609 IsDlgButtonChecked(hwndDlg
,
610 IDC_CHKRUNCOMPATIBILITY
) == BST_CHECKED
);
615 case IDC_CHKRUNIN256COLORS
:
616 case IDC_CHKRUNIN640480RES
:
617 case IDC_CHKDISABLEVISUALTHEMES
:
618 ReportPropertyChange(this,
622 case IDC_EDITCOMPATIBILITYMODES
:
624 if (DialogBoxParam(hInstance
,
625 MAKEINTRESOURCE(IDD_EDITCOMPATIBILITYMODES
),
627 EditCompatibilityModesProc
,
628 (LPARAM
)this) == IDOK
)
642 NMHDR
*hdr
= (NMHDR
*)lParam
;
648 return ApplySettings(this,
658 LPPROPSHEETPAGE psp
= (LPPROPSHEETPAGE
)lParam
;
659 this = (LPCOMPATIBILITYPAGE
)psp
->lParam
;
660 SetWindowLongPtr(hwndDlg
,
674 CompatibilityPageCallback(HWND hwnd
,
676 LPPROPSHEETPAGE ppsp
)
678 LPCOMPATIBILITYPAGE
this = (LPCOMPATIBILITYPAGE
)ppsp
->lParam
;
686 ICompatibilityPage_fnRelease(this);
694 static LPCOMPATIBILITYPAGE
695 ICompatibilityPage_fnConstructor(VOID
)
697 LPCOMPATIBILITYPAGE cp
;
699 cp
= HeapAlloc(GetProcessHeap(),
701 sizeof(COMPATIBILITYPAGE
));
705 cp
->lpVtbl
->fn
.IShellPropSheetExt
= efvtIShellPropSheetExt
;
707 InterlockedIncrement(&dllrefs
);
713 HRESULT STDMETHODCALLTYPE
714 ICompatibilityPage_fnQueryInterface(LPCOMPATIBILITYPAGE
this,
719 &IID_IShellPropSheetExt
))
721 this->lpVtbl
->fn
.IShellPropSheetExt
= efvtIShellPropSheetExt
;
722 ICompatibilityPage_fnAddRef(this);
726 else if (IsEqualIID(iid
,
729 this->lpVtbl
->fn
.IShellExtInit
= efvtIShellExtInit
;
730 ICompatibilityPage_fnAddRef(this);
734 else if (IsEqualIID(iid
,
737 this->lpVtbl
->fn
.IClassFactory
= efvtIClassFactory
;
738 ICompatibilityPage_fnAddRef(this);
742 else if (IsEqualIID(iid
,
745 ICompatibilityPage_fnAddRef(this);
751 return E_NOINTERFACE
;
754 ULONG STDMETHODCALLTYPE
755 ICompatibilityPage_fnAddRef(LPCOMPATIBILITYPAGE
this)
757 return (ULONG
)InterlockedIncrement(&this->ref
);
760 ULONG STDMETHODCALLTYPE
761 ICompatibilityPage_fnRelease(LPCOMPATIBILITYPAGE
this)
765 rfc
= (ULONG
)InterlockedDecrement(&this->ref
);
768 HeapFree(GetProcessHeap(),
771 InterlockedDecrement(&dllrefs
);
776 HRESULT STDMETHODCALLTYPE
777 ICompatibilityPage_fnAddPages(LPCOMPATIBILITYPAGE
this,
778 LPFNADDPROPSHEETPAGE lpfnAddPage
,
781 PROPSHEETPAGE psp
= {0};
782 HPROPSHEETPAGE hPage
;
784 psp
.dwSize
= sizeof(psp
);
785 psp
.dwFlags
= PSP_DEFAULT
| PSP_USECALLBACK
;
786 psp
.hInstance
= hInstance
;
787 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_SLAYERSHEET
);
788 psp
.pfnDlgProc
= CompatibilityPageProc
;
789 psp
.lParam
= (LPARAM
)this;
790 psp
.pfnCallback
= CompatibilityPageCallback
;
792 hPage
= CreatePropertySheetPage(&psp
);
796 if (!lpfnAddPage(hPage
,
799 DestroyPropertySheetPage(hPage
);
800 return E_OUTOFMEMORY
;
803 ICompatibilityPage_fnAddRef(this);
810 HRESULT STDMETHODCALLTYPE
811 ICompatibilityPage_fnReplacePage(LPCOMPATIBILITYPAGE
this,
813 LPFNADDPROPSHEETPAGE lpfnReplacePage
,
819 HRESULT STDMETHODCALLTYPE
820 ICompatibilityPage_fnInitialize(LPCOMPATIBILITYPAGE
this,
821 LPCITEMIDLIST pidlFolder
,
833 fetc
.cfFormat
= CF_HDROP
;
835 fetc
.dwAspect
= DVASPECT_CONTENT
;
837 fetc
.tymed
= TYMED_HGLOBAL
;
839 if (SUCCEEDED(pdtobj
->lpVtbl
->GetData(pdtobj
,
843 UINT nFiles
= DragQueryFile(smdm
.hGlobal
,
846 sizeof(this->szFile
) / sizeof(this->szFile
[0]));
849 /* FIXME - support editing of multiple files later */
850 DragQueryFile(smdm
.hGlobal
,
852 sizeof(this->szFile
) / sizeof(this->szFile
[0]));
853 ReleaseStgMedium(&smdm
);
862 HRESULT STDMETHODCALLTYPE
863 ICompatibilityPage_fnCreateInstance(LPCOMPATIBILITYPAGE
this,
868 LPCOMPATIBILITYPAGE cp
;
870 if (pUnkOuter
!= NULL
&&
874 return CLASS_E_NOAGGREGATION
;
877 cp
= ICompatibilityPage_fnConstructor();
880 HRESULT ret
= ICompatibilityPage_fnQueryInterface(cp
,
883 ICompatibilityPage_fnRelease(cp
);
887 return E_OUTOFMEMORY
;
890 HRESULT STDMETHODCALLTYPE
891 ICompatibilityPage_fnLockServer(LPCOMPATIBILITYPAGE
this,
896 InterlockedIncrement(&dllrefs
);
900 InterlockedDecrement(&dllrefs
);
906 /******************************************************************************
908 ******************************************************************************/
911 DllGetClassObject(REFCLSID rclsid
,
920 if (IsEqualCLSID(&CLSID_ICompatibilityPage
,
923 LPCOMPATIBILITYPAGE iface
= ICompatibilityPage_fnConstructor();
926 HRESULT ret
= ICompatibilityPage_fnQueryInterface(iface
,
929 ICompatibilityPage_fnRelease(iface
);
932 return E_OUTOFMEMORY
;
935 return CLASS_E_CLASSNOTAVAILABLE
;
939 DllCanUnloadNow(VOID
)
941 return ((dllrefs
== 0) ? S_OK
: S_FALSE
);
945 UnregisterPropSheetHandler(LPTSTR szType
)
950 TEXT("%s\\shellex\\PropertySheetHandlers\\Compatibility Property Page"),
953 return RegDeleteKey(HKEY_CLASSES_ROOT
,
958 DllUnregisterServer(VOID
)
964 StringFromGUID2(&CLSID_ICompatibilityPage
,
966 sizeof(szGuid
) / sizeof(szGuid
[0]));
968 e
= RegOpenKey(HKEY_LOCAL_MACHINE
,
969 TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"),
971 if (e
== ERROR_SUCCESS
)
973 e
= RegDeleteValueW(hk
,
978 if (e
== ERROR_SUCCESS
)
980 e
= UnregisterPropSheetHandler(TEXT("exefile"));
983 if (e
== ERROR_SUCCESS
)
985 e
= RegOpenKey(HKEY_CLASSES_ROOT
,
988 if (e
== ERROR_SUCCESS
)
990 TCHAR szInprocKey
[255];
992 _stprintf(szInprocKey
,
993 TEXT("%ws\\InprocServer32"),
998 if (e
== ERROR_SUCCESS
)
1000 e
= RegDeleteKeyW(hk
,
1007 return ((e
== ERROR_SUCCESS
) ? S_OK
: E_ACCESSDENIED
);
1011 RegisterPropSheetHandler(LPTSTR szType
,
1019 TEXT("%s\\shellex\\PropertySheetHandlers\\Compatibility Property Page"),
1022 e
= RegCreateKey(HKEY_CLASSES_ROOT
,
1025 if (e
== ERROR_SUCCESS
)
1027 e
= RegSetValueExW(hk
,
1032 (wcslen(szGuid
) + 1) * sizeof(WCHAR
));
1040 DllRegisterServer(VOID
)
1042 LONG e
= E_ACCESSDENIED
;
1045 WCHAR szDescription
[255];
1046 TCHAR szModule
[MAX_PATH
+ 1];
1047 int lnszDescription
;
1049 if (!GetModuleFileName(hInstance
,
1051 sizeof(szModule
) / sizeof(szModule
[0])))
1053 return E_ACCESSDENIED
;
1056 /* unregister first */
1057 DllUnregisterServer();
1059 lnszDescription
= LoadStringW(hInstance
,
1061 szDescription
, sizeof(szDescription
) / sizeof(szDescription
[0]));
1062 if (lnszDescription
> 0)
1064 StringFromGUID2(&CLSID_ICompatibilityPage
,
1066 sizeof(szGuid
) / sizeof(szGuid
[0]));
1068 e
= RegOpenKey(HKEY_LOCAL_MACHINE
,
1069 TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"),
1071 if (e
== ERROR_SUCCESS
)
1073 e
= RegSetValueExW(hk
,
1077 (BYTE
*)szDescription
,
1078 (lnszDescription
+ 1) * sizeof(WCHAR
));
1082 if (e
== ERROR_SUCCESS
)
1084 TCHAR szInprocKey
[255];
1086 _stprintf(szInprocKey
,
1087 TEXT("CLSID\\%ws\\InprocServer32"),
1090 e
= RegCreateKey(HKEY_CLASSES_ROOT
,
1093 if (e
== ERROR_SUCCESS
)
1095 e
= RegSetValueEx(hk
,
1100 (_tcslen(szModule
) + 1) * sizeof(TCHAR
));
1101 if (e
== ERROR_SUCCESS
)
1103 const TCHAR szApartment
[] = TEXT("Apartment");
1105 e
= RegSetValueEx(hk
,
1106 TEXT("ThreadingModel"),
1110 (_tcslen(szApartment
) + 1) * sizeof(TCHAR
));
1117 if (e
== ERROR_SUCCESS
)
1119 e
= RegisterPropSheetHandler(TEXT("exefile"),
1124 return ((e
== ERROR_SUCCESS
) ? S_OK
: E_ACCESSDENIED
);
1128 DllMain(HINSTANCE hinstDLL
,
1134 case DLL_PROCESS_ATTACH
:
1135 hInstance
= hinstDLL
;
1136 DisableThreadLibraryCalls(hInstance
);