2 * ReactOS Compatibility Layer Shell Extension
3 * Copyright (C) 2004 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
;
33 /* FIXME - they should be exported somewhere instead of defined here... */
34 DEFINE_SHLGUID(IID_IPropSheetPage
, 0x000214F6L
, 0, 0);
35 DEFINE_SHLGUID(IID_IShellPropSheetExt
, 0x000214E9L
, 0, 0);
37 static ifaceICompatibilityPageVbtl efvt
=
39 /* IUnknown methods */
40 ICompatibilityPage_fnQueryInterface
,
41 ICompatibilityPage_fnAddRef
,
42 ICompatibilityPage_fnRelease
,
45 static ifaceIShellPropSheetExtVbtl efvtIShellPropSheetExt
=
47 /* IShellPropSheetExt */
48 ICompatibilityPage_fnAddPages
,
49 ICompatibilityPage_fnReplacePage
,
52 static ifaceIShellExtInitVbtl efvtIShellExtInit
=
55 ICompatibilityPage_fnInitialize
,
58 static ifaceIClassFactoryVbtl efvtIClassFactory
=
61 ICompatibilityPage_fnCreateInstance
,
62 ICompatibilityPage_fnLockServer
,
65 /******************************************************************************
67 ******************************************************************************/
70 ClearCItemList(LPCOMPATIBILITYPAGE info
)
74 for(item
= info
->CItems
;
79 HeapFree(GetProcessHeap(), 0, item
);
82 info
->CSelectedItem
= NULL
;
88 ReadDWORDFlag(HKEY hk
, LPTSTR szValueName
, LPDWORD lpOutValue
, DWORD dwDefault
)
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
, LPTSTR szValueName
)
113 DWORD dwType
, dwSize
;
116 e
= RegOpenKey(HKEY_CURRENT_USER
,
117 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"),
119 if(e
== ERROR_SUCCESS
)
121 dwSize
= sizeof(szStr
);
122 e
= RegQueryValueEx(hk
,
128 if(e
== ERROR_SUCCESS
)
130 /* FIXME - make sure the string is NULL-terminated! */
132 for(c
= szStr
; *c
!= TEXT('\0'); c
++)
134 /* only the first word represents the compatibility mode */
135 /* FIXME - parse all words! */
143 info
->CSelectedItem
= NULL
;
144 if(_tcslen(szStr
) > 0)
148 for(item
= info
->CItems
; item
!= NULL
; item
= item
->next
)
150 if(!_tcsicmp(szStr
, item
->szKeyName
))
152 info
->CSelectedItem
= item
;
165 LoadCompatibilityModes(LPCOMPATIBILITYPAGE info
)
172 ClearCItemList(info
);
174 e
= RegOpenKey(HKEY_CURRENT_USER
,
175 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"),
177 if(e
== ERROR_SUCCESS
)
180 PCITEM lastitem
= NULL
;
183 (RegEnumKey(hk
, i
,szKey
, sizeof(szKey
) / sizeof(szKey
[0])) == ERROR_SUCCESS
);
189 if(e
== ERROR_SUCCESS
)
193 e
= RegQueryValueEx(hk2
,
199 if(e
!= ERROR_SUCCESS
|| (e
== ERROR_SUCCESS
&& dwType
== REG_SZ
))
203 item
= HeapAlloc(GetProcessHeap(), 0, sizeof(CITEM
));
206 DWORD cdb
= sizeof(item
->szName
);
209 e
= RegQueryValueEx(hk2
,
213 (LPBYTE
)item
->szName
,
216 /* make sure it is null-terminated */
217 if(cdb
> sizeof(item
->szName
) - sizeof(item
->szName
[0]))
219 item
->szName
[(sizeof(item
->szName
) / sizeof(item
->szName
[0])) - 1] = TEXT('\0');
221 if(e
!= ERROR_SUCCESS
||
222 cdb
< sizeof(item
->szName
[0]))
224 _tcscpy(item
->szName
, szKey
);
227 _tcscpy(item
->szKeyName
, szKey
);
230 ReadDWORDFlag(hk2
, TEXT("MajorVersion"), &item
->MajorVersion
, 0);
231 ReadDWORDFlag(hk2
, TEXT("MinorVersion"), &item
->MinorVersion
, 0);
232 ReadDWORDFlag(hk2
, TEXT("BuildNumber"), &item
->BuildNumber
, 0);
233 ReadDWORDFlag(hk2
, TEXT("PlatformId"), &item
->PlatformId
, 0);
234 ReadDWORDFlag(hk2
, TEXT("SPMajorVersion"), &item
->SPMajorVersion
, 0);
235 ReadDWORDFlag(hk2
, TEXT("SPMinorVersion"), &item
->SPMinorVersion
, 0);
237 if(e
== ERROR_SUCCESS
)
242 lastitem
->next
= item
;
252 HeapFree(GetProcessHeap(), 0, item
);
260 if(e
!= ERROR_SUCCESS
)
268 Ret
= ((e
== ERROR_SUCCESS
|| e
== ERROR_NO_MORE_ITEMS
) ? TRUE
: FALSE
);
274 FillComboBoxWithCompatibilityModes(LPCOMPATIBILITYPAGE info
, HWND hwndDlg
, HWND hCombo
, BOOL bSelectItem
, BOOL bDisableControlsIfEmpty
)
280 SendMessage(hCombo
, CB_RESETCONTENT
, 0, 0);
282 for(item
= info
->CItems
; item
!= NULL
; item
= item
->next
)
284 int iIndex
= (int)SendMessage(hCombo
, CB_ADDSTRING
, 0, (LPARAM
)item
->szName
);
285 if(item
== info
->CSelectedItem
&& bSelectItem
)
287 SendMessage(hCombo
, CB_SETCURSEL
, (WPARAM
)iIndex
, 0);
293 if(!sel
&& bSelectItem
&& i
> 0)
295 /* select the first item */
296 SendMessage(hCombo
, CB_SETCURSEL
, 0, 0);
299 if(bDisableControlsIfEmpty
)
301 BOOL enable
= (i
> 0);
302 EnableWindow(GetDlgItem(hwndDlg
, IDC_COMPATGROUP
), enable
);
303 EnableWindow(hCombo
, (enable
&& sel
));
304 EnableWindow(GetDlgItem(hwndDlg
, IDC_CHKRUNCOMPATIBILITY
), enable
);
305 CheckDlgButton(hwndDlg
, IDC_CHKRUNCOMPATIBILITY
, ((enable
&& sel
) ? BST_CHECKED
: BST_UNCHECKED
));
310 FillEditListBoxWithCompatibilityModes(LPCOMPATIBILITYPAGE info
, HWND hwndDlg
, HWND hListBox
, BOOL bDisableControlsIfEmpty
)
315 SendMessage(hListBox
, LB_RESETCONTENT
, 0, 0);
317 for(item
= info
->CItems
; item
!= NULL
; item
= item
->next
)
319 SendMessage(hListBox
, LB_ADDSTRING
, 0, (LPARAM
)item
->szName
);
323 if(bDisableControlsIfEmpty
)
329 EditCompatibilityModesProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
331 LPCOMPATIBILITYPAGE
this;
337 switch(LOWORD(wParam
))
340 EndDialog(hwndDlg
, IDOK
);
344 EndDialog(hwndDlg
, IDCANCEL
);
351 EndDialog(hwndDlg
, IDCANCEL
);
356 HWND hList
= GetDlgItem(hwndDlg
, IDC_COMPATIBILITYMODE
);
357 this = (LPCOMPATIBILITYPAGE
)lParam
;
358 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)this);
359 FillEditListBoxWithCompatibilityModes(this, hwndDlg
, hList
, FALSE
);
367 InitializePage(LPCOMPATIBILITYPAGE
this, HWND hwndDlg
)
371 LoadCompatibilityModes(this);
373 /* initialize the controls */
374 hList
= GetDlgItem(hwndDlg
, IDC_COMPATIBILITYMODE
);
375 LoadAndParseAppCompatibilityFlags(this, this->szFile
);
376 FillComboBoxWithCompatibilityModes(this, hwndDlg
, hList
, TRUE
, TRUE
);
380 ReportPropertyChange(LPCOMPATIBILITYPAGE
this, HWND hwndDlg
)
382 this->Changed
= TRUE
;
383 SendMessage(GetParent(hwndDlg
), PSM_CHANGED
, (WPARAM
)hwndDlg
, 0);
387 ComposeFlags(LPCOMPATIBILITYPAGE
this, LPTSTR szFlags
)
389 if(this->CSelectedItem
!= NULL
)
391 _tcscpy(szFlags
, this->CSelectedItem
->szKeyName
);
399 ApplySettings(LPCOMPATIBILITYPAGE
this, HWND hwndDlg
)
404 BOOL enabled
= IsDlgButtonChecked(hwndDlg
, IDC_CHKRUNCOMPATIBILITY
) == BST_CHECKED
;
408 HWND hCombo
= GetDlgItem(hwndDlg
, IDC_COMPATIBILITYMODE
);
409 int index
= (int)SendMessage(hCombo
, CB_GETCURSEL
, 0, 0);
413 PCITEM sel
= this->CItems
;
415 /* map the index to a CITEM structure */
416 for(i
= index
; i
> 0 && sel
!= NULL
; i
--)
421 /* update the CSelectedItem member */
422 this->CSelectedItem
= sel
;
428 e
= RegOpenKey(HKEY_CURRENT_USER
,
429 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"),
431 if(e
== ERROR_SUCCESS
)
435 /* FIXME - only delete if nothing else is selected! */
436 e
= RegDeleteValue(hk
, this->szFile
);
440 if(ComposeFlags(this, szFlags
))
442 e
= RegSetValueEx(hk
,
447 (_tcslen(szFlags
) + 1) * sizeof(TCHAR
));
451 e
= RegDeleteValue(hk
, this->szFile
);
458 this->Changed
= FALSE
;
459 return (e
== ERROR_SUCCESS
);
463 CompatibilityPageProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
465 LPCOMPATIBILITYPAGE
this = (LPCOMPATIBILITYPAGE
)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
471 if(HIWORD(wParam
) == CBN_SELCHANGE
&& LOWORD(wParam
) == IDC_COMPATIBILITYMODE
)
473 ReportPropertyChange(this, hwndDlg
);
477 switch(LOWORD(wParam
))
479 case IDC_CHKRUNCOMPATIBILITY
:
481 HWND hList
= GetDlgItem(hwndDlg
, IDC_COMPATIBILITYMODE
);
484 EnableWindow(hList
, IsDlgButtonChecked(hwndDlg
, IDC_CHKRUNCOMPATIBILITY
) == BST_CHECKED
);
488 case IDC_CHKRUNIN256COLORS
:
489 case IDC_CHKRUNIN640480RES
:
490 case IDC_CHKDISABLEVISUALTHEMES
:
491 ReportPropertyChange(this, hwndDlg
);
493 case IDC_EDITCOMPATIBILITYMODES
:
495 if(DialogBoxParam(hInstance
,
496 MAKEINTRESOURCE(IDD_EDITCOMPATIBILITYMODES
),
498 EditCompatibilityModesProc
,
499 (LPARAM
)this) == IDOK
)
501 InitializePage(this, hwndDlg
);
512 NMHDR
*hdr
= (NMHDR
*)lParam
;
518 return ApplySettings(this, hwndDlg
);
527 LPPROPSHEETPAGE psp
= (LPPROPSHEETPAGE
)lParam
;
528 this = (LPCOMPATIBILITYPAGE
)psp
->lParam
;
529 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)this);
531 InitializePage(this, hwndDlg
);
540 CompatibilityPageCallback(HWND hwnd
, UINT uMsg
, LPPROPSHEETPAGE ppsp
)
542 LPCOMPATIBILITYPAGE
this = (LPCOMPATIBILITYPAGE
)ppsp
->lParam
;
550 ICompatibilityPage_fnRelease(this);
558 static LPCOMPATIBILITYPAGE
559 ICompatibilityPage_fnConstructor(VOID
)
561 LPCOMPATIBILITYPAGE cp
;
563 cp
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(COMPATIBILITYPAGE
));
567 cp
->lpVtbl
->fn
.IShellPropSheetExt
= efvtIShellPropSheetExt
;
569 InterlockedIncrement(&dllrefs
);
575 HRESULT STDMETHODCALLTYPE
576 ICompatibilityPage_fnQueryInterface(LPCOMPATIBILITYPAGE
this, REFIID iid
, PVOID
*pvObject
)
578 if(IsEqualIID(iid
, &IID_IShellPropSheetExt
))
580 this->lpVtbl
->fn
.IShellPropSheetExt
= efvtIShellPropSheetExt
;
581 ICompatibilityPage_fnAddRef(this);
585 else if(IsEqualIID(iid
, &IID_IShellExtInit
))
587 this->lpVtbl
->fn
.IShellExtInit
= efvtIShellExtInit
;
588 ICompatibilityPage_fnAddRef(this);
592 else if(IsEqualIID(iid
, &IID_IClassFactory
))
594 this->lpVtbl
->fn
.IClassFactory
= efvtIClassFactory
;
595 ICompatibilityPage_fnAddRef(this);
599 else if(IsEqualIID(iid
, &IID_IUnknown
))
601 ICompatibilityPage_fnAddRef(this);
607 return E_NOINTERFACE
;
610 ULONG STDMETHODCALLTYPE
611 ICompatibilityPage_fnAddRef(LPCOMPATIBILITYPAGE
this)
613 return (ULONG
)InterlockedIncrement(&this->ref
);
616 ULONG STDMETHODCALLTYPE
617 ICompatibilityPage_fnRelease(LPCOMPATIBILITYPAGE
this)
621 rfc
= (ULONG
)InterlockedDecrement(&this->ref
);
624 HeapFree(GetProcessHeap(), 0, this);
625 InterlockedDecrement(&dllrefs
);
630 HRESULT STDMETHODCALLTYPE
631 ICompatibilityPage_fnAddPages(LPCOMPATIBILITYPAGE
this, LPFNADDPROPSHEETPAGE lpfnAddPage
, LPARAM lParam
)
634 HPROPSHEETPAGE hPage
;
636 ZeroMemory(&psp
, sizeof(psp
));
638 psp
.dwSize
= sizeof(psp
);
639 psp
.dwFlags
= PSP_DEFAULT
| PSP_USECALLBACK
;
640 psp
.hInstance
= hInstance
;
641 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_SLAYERSHEET
);
642 psp
.pfnDlgProc
= CompatibilityPageProc
;
643 psp
.lParam
= (LPARAM
)this;
644 psp
.pfnCallback
= CompatibilityPageCallback
;
646 hPage
= CreatePropertySheetPage(&psp
);
650 if(!lpfnAddPage(hPage
, lParam
))
652 DestroyPropertySheetPage(hPage
);
653 return E_OUTOFMEMORY
;
656 ICompatibilityPage_fnAddRef(this);
663 HRESULT STDMETHODCALLTYPE
664 ICompatibilityPage_fnReplacePage(LPCOMPATIBILITYPAGE
this, UINT uPageID
, LPFNADDPROPSHEETPAGE lpfnReplacePage
, LPARAM lParam
)
669 HRESULT STDMETHODCALLTYPE
670 ICompatibilityPage_fnInitialize(LPCOMPATIBILITYPAGE
this,
671 LPCITEMIDLIST pidlFolder
,
683 fetc
.cfFormat
= CF_HDROP
;
685 fetc
.dwAspect
= DVASPECT_CONTENT
;
687 fetc
.tymed
= TYMED_HGLOBAL
;
689 if(SUCCEEDED(pdtobj
->lpVtbl
->GetData(pdtobj
, &fetc
, &smdm
)))
691 UINT nFiles
= DragQueryFile(smdm
.hGlobal
, 0xFFFFFFFF, this->szFile
, sizeof(this->szFile
) / sizeof(this->szFile
[0]));
694 /* FIXME - support editing of multiple files later */
695 DragQueryFile(smdm
.hGlobal
, 0, this->szFile
, sizeof(this->szFile
) / sizeof(this->szFile
[0]));
696 ReleaseStgMedium(&smdm
);
705 HRESULT STDMETHODCALLTYPE
706 ICompatibilityPage_fnCreateInstance(LPCOMPATIBILITYPAGE
this,
711 LPCOMPATIBILITYPAGE cp
;
713 if(pUnkOuter
!= NULL
&&
714 !IsEqualIID(riid
, &IID_IUnknown
))
716 return CLASS_E_NOAGGREGATION
;
719 cp
= ICompatibilityPage_fnConstructor();
722 HRESULT ret
= ICompatibilityPage_fnQueryInterface(cp
, riid
, ppvObject
);
723 ICompatibilityPage_fnRelease(cp
);
727 return E_OUTOFMEMORY
;
730 HRESULT STDMETHODCALLTYPE
731 ICompatibilityPage_fnLockServer(LPCOMPATIBILITYPAGE
this,
736 InterlockedIncrement(&dllrefs
);
740 InterlockedDecrement(&dllrefs
);
746 /******************************************************************************
748 ******************************************************************************/
751 DllGetClassObject(REFCLSID rclsid
, REFIID iid
, LPVOID
*ppv
)
758 if(IsEqualCLSID(&CLSID_ICompatibilityPage
, rclsid
))
760 LPCOMPATIBILITYPAGE iface
= ICompatibilityPage_fnConstructor();
763 HRESULT ret
= ICompatibilityPage_fnQueryInterface(iface
, iid
, ppv
);
764 ICompatibilityPage_fnRelease(iface
);
767 return E_OUTOFMEMORY
;
770 return CLASS_E_CLASSNOTAVAILABLE
;
774 DllCanUnloadNow(VOID
)
776 return ((dllrefs
== 0) ? S_OK
: S_FALSE
);
780 UnregisterPropSheetHandler(LPTSTR szType
)
784 _stprintf(szKey
, TEXT("%s\\shellex\\PropertySheetHandlers\\Compatibility Property Page"), szType
);
785 return RegDeleteKey(HKEY_CLASSES_ROOT
,
790 DllUnregisterServer(VOID
)
796 StringFromGUID2(&CLSID_ICompatibilityPage
, szGuid
, sizeof(szGuid
) / sizeof(szGuid
[0]));
797 e
= RegOpenKey(HKEY_LOCAL_MACHINE
,
798 TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"),
800 if(e
== ERROR_SUCCESS
)
802 e
= RegDeleteValueW(hk
, szGuid
);
806 if(e
== ERROR_SUCCESS
)
808 e
= UnregisterPropSheetHandler(TEXT("exefile"));
811 if(e
== ERROR_SUCCESS
)
813 e
= RegOpenKey(HKEY_CLASSES_ROOT
,
816 if(e
== ERROR_SUCCESS
)
818 TCHAR szInprocKey
[255];
819 _stprintf(szInprocKey
, TEXT("%ws\\InprocServer32"), szGuid
);
823 if(e
== ERROR_SUCCESS
)
825 e
= RegDeleteKeyW(hk
,
832 return ((e
== ERROR_SUCCESS
) ? S_OK
: E_ACCESSDENIED
);
836 RegisterPropSheetHandler(LPTSTR szType
, LPWSTR szGuid
)
842 _stprintf(szKey
, TEXT("%s\\shellex\\PropertySheetHandlers\\Compatibility Property Page"), szType
);
843 e
= RegCreateKey(HKEY_CLASSES_ROOT
,
846 if(e
== ERROR_SUCCESS
)
848 e
= RegSetValueExW(hk
,
853 (wcslen(szGuid
) + 1) * sizeof(WCHAR
));
861 DllRegisterServer(VOID
)
866 WCHAR szDescription
[255];
867 TCHAR szModule
[MAX_PATH
+ 1];
870 if(!GetModuleFileName(hInstance
, szModule
, sizeof(szModule
) / sizeof(szModule
[0])))
872 return E_ACCESSDENIED
;
875 /* unregister first */
876 DllUnregisterServer();
878 lnszDescription
= LoadStringW(hInstance
, IDS_DESCRIPTION
, szDescription
, sizeof(szDescription
) / sizeof(szDescription
[0]));
879 if(lnszDescription
> 0)
881 StringFromGUID2(&CLSID_ICompatibilityPage
, szGuid
, sizeof(szGuid
) / sizeof(szGuid
[0]));
883 e
= RegOpenKey(HKEY_LOCAL_MACHINE
,
884 TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"),
886 if(e
== ERROR_SUCCESS
)
888 e
= RegSetValueExW(hk
,
892 (BYTE
*)szDescription
,
893 (lnszDescription
+ 1) * sizeof(WCHAR
));
897 if(e
== ERROR_SUCCESS
)
899 TCHAR szInprocKey
[255];
900 _stprintf(szInprocKey
, TEXT("CLSID\\%ws\\InprocServer32"), szGuid
);
902 e
= RegCreateKey(HKEY_CLASSES_ROOT
,
905 if(e
== ERROR_SUCCESS
)
907 e
= RegSetValueEx(hk
,
912 (_tcslen(szModule
) + 1) * sizeof(TCHAR
));
913 if(e
== ERROR_SUCCESS
)
915 const LPTSTR szApartment
= TEXT("Apartment");
916 e
= RegSetValueEx(hk
,
917 TEXT("ThreadingModel"),
921 (_tcslen(szApartment
) + 1) * sizeof(TCHAR
));
928 if(e
== ERROR_SUCCESS
)
930 e
= RegisterPropSheetHandler(TEXT("exefile"), szGuid
);
934 return ((e
== ERROR_SUCCESS
) ? S_OK
: E_ACCESSDENIED
);
938 DllMain(HINSTANCE hinstDLL
,
944 case DLL_PROCESS_ATTACH
:
945 hInstance
= hinstDLL
;
946 DisableThreadLibraryCalls(hInstance
);