[FMIFS]
[reactos.git] / reactos / dll / shellext / slayer / slayer.c
1 /*
2 * ReactOS Compatibility Layer Shell Extension
3 * Copyright (C) 2004 - 2005 ReactOS Team
4 *
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.
9 *
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.
14 *
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
18 */
19 /*
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>
24 * UPDATE HISTORY:
25 * 09/25/2004 Created
26 */
27
28 #include <stdarg.h>
29
30 #define WIN32_NO_STATUS
31 #define _INC_WINDOWS
32 #define COM_NO_WINDOWS_H
33
34 #include <windef.h>
35 #include <winbase.h>
36 #include <winreg.h>
37 #include <shellapi.h>
38 #include <shlobj.h>
39 #include <tchar.h>
40
41 #include "resource.h"
42 #include "slayer.h"
43
44 HINSTANCE hInstance = NULL;
45 static LONG dllrefs = 0;
46
47 static ifaceICompatibilityPageVbtl efvt =
48 {
49 /* IUnknown methods */
50 ICompatibilityPage_fnQueryInterface,
51 ICompatibilityPage_fnAddRef,
52 ICompatibilityPage_fnRelease,
53 };
54
55 static ifaceIShellPropSheetExtVbtl efvtIShellPropSheetExt =
56 {
57 /* IShellPropSheetExt */
58 ICompatibilityPage_fnAddPages,
59 ICompatibilityPage_fnReplacePage,
60 };
61
62 static ifaceIShellExtInitVbtl efvtIShellExtInit =
63 {
64 /* IShellExtInit */
65 ICompatibilityPage_fnInitialize,
66 };
67
68 static ifaceIClassFactoryVbtl efvtIClassFactory =
69 {
70 /* IClassFactory */
71 ICompatibilityPage_fnCreateInstance,
72 ICompatibilityPage_fnLockServer,
73 };
74
75 /******************************************************************************
76 ICompatibilityPage
77 ******************************************************************************/
78
79 static VOID
80 ClearCItemList(LPCOMPATIBILITYPAGE info)
81 {
82 PCITEM item, next;
83
84 for (item = info->CItems;
85 item != NULL;
86 item = next)
87 {
88 next = item->next;
89 HeapFree(GetProcessHeap(),
90 0,
91 item);
92 }
93
94 info->CSelectedItem = NULL;
95 info->CItems = NULL;
96 info->nItems = 0;
97 }
98
99 static BOOL
100 ReadDWORDFlag(HKEY hk,
101 LPTSTR szValueName,
102 LPDWORD lpOutValue,
103 DWORD dwDefault)
104 {
105 DWORD dwType, dwSize = sizeof(DWORD);
106 LONG e = RegQueryValueEx(hk,
107 szValueName,
108 0,
109 &dwType,
110 (LPBYTE)lpOutValue,
111 &dwSize);
112
113 if (e != ERROR_SUCCESS || dwSize != sizeof(DWORD))
114 {
115 *lpOutValue = dwDefault;
116
117 return TRUE;
118 }
119
120 return FALSE;
121 }
122
123 static BOOL
124 LoadAndParseAppCompatibilityFlags(LPCOMPATIBILITYPAGE info,
125 LPTSTR szValueName)
126 {
127 LONG e;
128 HKEY hk;
129 DWORD dwType, dwSize;
130 TCHAR szStr[256];
131
132 e = RegOpenKey(HKEY_CURRENT_USER,
133 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"),
134 &hk);
135 if (e == ERROR_SUCCESS)
136 {
137 dwSize = sizeof(szStr);
138
139 e = RegQueryValueEx(hk,
140 szValueName,
141 0,
142 &dwType,
143 (LPBYTE)szStr,
144 &dwSize);
145
146 if (e == ERROR_SUCCESS)
147 {
148 /* FIXME - make sure the string is NULL-terminated! */
149 TCHAR *c;
150 for (c = szStr;
151 *c != TEXT('\0');
152 c++)
153 {
154 /* only the first word represents the compatibility mode */
155 /* FIXME - parse all words! */
156 if (*c == TEXT(' '))
157 {
158 *c = TEXT('\0');
159 break;
160 }
161 }
162
163 info->CSelectedItem = NULL;
164 if (_tcslen(szStr) > 0)
165 {
166 PCITEM item;
167
168 for (item = info->CItems;
169 item != NULL;
170 item = item->next)
171 {
172 if (!_tcsicmp(szStr, item->szKeyName))
173 {
174 info->CSelectedItem = item;
175 break;
176 }
177 }
178 }
179 }
180 RegCloseKey(hk);
181 }
182
183 return FALSE;
184 }
185
186 static BOOL
187 LoadCompatibilityModes(LPCOMPATIBILITYPAGE info)
188 {
189 BOOL Ret;
190 LONG e;
191 HKEY hk, hk2;
192 TCHAR szKey[256];
193
194 ClearCItemList(info);
195
196 e = RegOpenKey(HKEY_CURRENT_USER,
197 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"),
198 &hk);
199
200 if (e == ERROR_SUCCESS)
201 {
202 DWORD i;
203 PCITEM lastitem = NULL;
204
205 for(i = 0;
206 (RegEnumKey(hk, i,szKey, sizeof(szKey) / sizeof(szKey[0])) == ERROR_SUCCESS);
207 i++)
208 {
209 e = RegOpenKey(hk,
210 szKey,
211 &hk2);
212
213 if (e == ERROR_SUCCESS)
214 {
215 DWORD dwType;
216
217 e = RegQueryValueEx(hk2,
218 NULL,
219 0,
220 &dwType,
221 NULL,
222 NULL);
223
224 if (e != ERROR_SUCCESS || (e == ERROR_SUCCESS && dwType == REG_SZ))
225 {
226 PCITEM item;
227
228 item = HeapAlloc(GetProcessHeap(),
229 0,
230 sizeof(CITEM));
231 if (item != NULL)
232 {
233 DWORD cdb = sizeof(item->szName);
234
235 /* description */
236 e = RegQueryValueEx(hk2,
237 NULL,
238 0,
239 NULL,
240 (LPBYTE)item->szName,
241 &cdb);
242
243 /* make sure it is null-terminated */
244 if (cdb > sizeof(item->szName) - sizeof(item->szName[0]))
245 {
246 item->szName[(sizeof(item->szName) / sizeof(item->szName[0])) - 1] = TEXT('\0');
247 }
248
249 if (e != ERROR_SUCCESS ||
250 cdb < sizeof(item->szName[0]))
251 {
252 _tcscpy(item->szName, szKey);
253 e = ERROR_SUCCESS;
254 }
255
256 _tcscpy(item->szKeyName, szKey);
257 info->nItems++;
258
259 ReadDWORDFlag(hk2,
260 TEXT("MajorVersion"),
261 &item->MajorVersion,
262 0);
263 ReadDWORDFlag(hk2,
264 TEXT("MinorVersion"),
265 &item->MinorVersion,
266 0);
267 ReadDWORDFlag(hk2,
268 TEXT("BuildNumber"),
269 &item->BuildNumber,
270 0);
271 ReadDWORDFlag(hk2,
272 TEXT("PlatformId"),
273 &item->PlatformId,
274 0);
275 ReadDWORDFlag(hk2,
276 TEXT("SPMajorVersion"),
277 &item->SPMajorVersion,
278 0);
279 ReadDWORDFlag(hk2,
280 TEXT("SPMinorVersion"),
281 &item->SPMinorVersion,
282 0);
283
284 if (e == ERROR_SUCCESS)
285 {
286 item->next = NULL;
287 if (lastitem != NULL)
288 {
289 lastitem->next = item;
290 }
291 else
292 {
293 info->CItems = item;
294 }
295 lastitem = item;
296 }
297 else
298 {
299 HeapFree(GetProcessHeap(),
300 0,
301 item);
302 }
303 }
304 }
305
306 RegCloseKey(hk2);
307 }
308
309 if (e != ERROR_SUCCESS)
310 {
311 e = ERROR_SUCCESS;
312 }
313 }
314 RegCloseKey(hk);
315 }
316
317 Ret = ((e == ERROR_SUCCESS || e == ERROR_NO_MORE_ITEMS) ? TRUE : FALSE);
318
319 return Ret;
320 }
321
322 static VOID
323 FillComboBoxWithCompatibilityModes(LPCOMPATIBILITYPAGE info,
324 HWND hwndDlg,
325 HWND hCombo,
326 BOOL bSelectItem,
327 BOOL bDisableControlsIfEmpty)
328 {
329 PCITEM item;
330 int i = 0;
331 BOOL sel = FALSE;
332
333 SendMessage(hCombo,
334 CB_RESETCONTENT,
335 0,
336 0);
337
338 for (item = info->CItems;
339 item != NULL;
340 item = item->next)
341 {
342 int iIndex = (int)SendMessage(hCombo,
343 CB_ADDSTRING,
344 0,
345 (LPARAM)item->szName);
346
347 if (item == info->CSelectedItem && bSelectItem)
348 {
349 SendMessage(hCombo,
350 CB_SETCURSEL,
351 (WPARAM)iIndex,
352 0);
353 sel = TRUE;
354 }
355 i++;
356 }
357
358 if (!sel && bSelectItem && i > 0)
359 {
360 /* select the first item */
361 SendMessage(hCombo,
362 CB_SETCURSEL,
363 0,
364 0);
365 }
366
367 if (bDisableControlsIfEmpty)
368 {
369 BOOL enable = (i > 0);
370
371 EnableWindow(GetDlgItem(hwndDlg,
372 IDC_COMPATGROUP),
373 enable);
374
375 EnableWindow(hCombo,
376 (enable && sel));
377
378 EnableWindow(GetDlgItem(hwndDlg,
379 IDC_CHKRUNCOMPATIBILITY),
380 enable);
381
382 CheckDlgButton(hwndDlg,
383 IDC_CHKRUNCOMPATIBILITY,
384 ((enable && sel) ? BST_CHECKED : BST_UNCHECKED));
385 }
386 }
387
388 static VOID
389 FillEditListBoxWithCompatibilityModes(LPCOMPATIBILITYPAGE info,
390 HWND hwndDlg,
391 HWND hListBox,
392 BOOL bDisableControlsIfEmpty)
393 {
394 PCITEM item;
395 int i;
396
397 SendMessage(hListBox,
398 LB_RESETCONTENT,
399 0,
400 0);
401
402 for (item = info->CItems, i = 0;
403 item != NULL;
404 item = item->next, i++)
405 {
406 SendMessage(hListBox,
407 LB_ADDSTRING,
408 0,
409 (LPARAM)item->szName);
410 }
411
412 if (bDisableControlsIfEmpty)
413 {
414 }
415 }
416
417 static INT_PTR CALLBACK
418 EditCompatibilityModesProc(HWND hwndDlg,
419 UINT uMsg,
420 WPARAM wParam,
421 LPARAM lParam)
422 {
423 LPCOMPATIBILITYPAGE this;
424
425 switch (uMsg)
426 {
427 case WM_COMMAND:
428 {
429 switch(LOWORD(wParam))
430 {
431 case IDOK:
432 EndDialog(hwndDlg,
433 IDOK);
434 break;
435
436 case IDCANCEL:
437 EndDialog(hwndDlg,
438 IDCANCEL);
439 break;
440 }
441 break;
442 }
443
444 case WM_CLOSE:
445 {
446 EndDialog(hwndDlg,
447 IDCANCEL);
448 break;
449 }
450
451 case WM_INITDIALOG:
452 {
453 HWND hList = GetDlgItem(hwndDlg,
454 IDC_COMPATIBILITYMODE);
455
456 this = (LPCOMPATIBILITYPAGE)lParam;
457 SetWindowLongPtr(hwndDlg,
458 GWLP_USERDATA,
459 (LONG_PTR)this);
460
461 FillEditListBoxWithCompatibilityModes(this,
462 hwndDlg,
463 hList,
464 FALSE);
465 break;
466 }
467 }
468
469 return FALSE;
470 }
471
472 static VOID
473 InitializePage(LPCOMPATIBILITYPAGE this,
474 HWND hwndDlg)
475 {
476 HWND hList;
477
478 LoadCompatibilityModes(this);
479
480 /* initialize the controls */
481 hList = GetDlgItem(hwndDlg,
482 IDC_COMPATIBILITYMODE);
483
484 LoadAndParseAppCompatibilityFlags(this,
485 this->szFile);
486 FillComboBoxWithCompatibilityModes(this,
487 hwndDlg,
488 hList,
489 TRUE,
490 TRUE);
491 }
492
493 static VOID
494 ReportPropertyChange(LPCOMPATIBILITYPAGE this,
495 HWND hwndDlg)
496 {
497 this->Changed = TRUE;
498
499 SendMessage(GetParent(hwndDlg),
500 PSM_CHANGED,
501 (WPARAM)hwndDlg,
502 0);
503 }
504
505 static BOOL
506 ComposeFlags(LPCOMPATIBILITYPAGE this,
507 LPTSTR szFlags)
508 {
509 if (this->CSelectedItem != NULL)
510 {
511 _tcscpy(szFlags,
512 this->CSelectedItem->szKeyName);
513 return TRUE;
514 }
515
516 return FALSE;
517 }
518
519 static BOOL
520 ApplySettings(LPCOMPATIBILITYPAGE this,
521 HWND hwndDlg)
522 {
523 HKEY hk;
524 LONG e;
525 TCHAR szFlags[256];
526 BOOL enabled = IsDlgButtonChecked(hwndDlg,
527 IDC_CHKRUNCOMPATIBILITY) == BST_CHECKED;
528
529 if (enabled)
530 {
531 HWND hCombo = GetDlgItem(hwndDlg,
532 IDC_COMPATIBILITYMODE);
533 int index = (int)SendMessage(hCombo,
534 CB_GETCURSEL,
535 0,
536 0);
537 if (index >= 0)
538 {
539 int i;
540 PCITEM sel = this->CItems;
541
542 /* map the index to a CITEM structure */
543 for(i = index;
544 i > 0 && sel != NULL;
545 i--)
546 {
547 sel = sel->next;
548 }
549
550 /* update the CSelectedItem member */
551 this->CSelectedItem = sel;
552 }
553 else
554 enabled = FALSE;
555 }
556
557 e = RegOpenKey(HKEY_CURRENT_USER,
558 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"),
559 &hk);
560 if (e == ERROR_SUCCESS)
561 {
562 if (!enabled)
563 {
564 /* FIXME - only delete if nothing else is selected! */
565 e = RegDeleteValue(hk,
566 this->szFile);
567 }
568 else
569 {
570 if (ComposeFlags(this,
571 szFlags))
572 {
573 e = RegSetValueEx(hk,
574 this->szFile,
575 0,
576 REG_SZ,
577 (LPBYTE)szFlags,
578 (_tcslen(szFlags) + 1) * sizeof(TCHAR));
579 }
580 else
581 {
582 e = RegDeleteValue(hk,
583 this->szFile);
584 }
585 }
586
587 RegCloseKey(hk);
588 }
589
590 this->Changed = FALSE;
591 return (e == ERROR_SUCCESS);
592 }
593
594 static INT_PTR CALLBACK
595 CompatibilityPageProc(HWND hwndDlg,
596 UINT uMsg,
597 WPARAM wParam,
598 LPARAM lParam)
599 {
600 LPCOMPATIBILITYPAGE this = (LPCOMPATIBILITYPAGE)GetWindowLongPtr(hwndDlg,
601 GWLP_USERDATA);
602
603 switch (uMsg)
604 {
605 case WM_COMMAND:
606 {
607 if (HIWORD(wParam) == CBN_SELCHANGE && LOWORD(wParam) == IDC_COMPATIBILITYMODE)
608 {
609 ReportPropertyChange(this,
610 hwndDlg);
611 }
612 else
613 {
614 switch (LOWORD(wParam))
615 {
616 case IDC_CHKRUNCOMPATIBILITY:
617 {
618 HWND hList = GetDlgItem(hwndDlg,
619 IDC_COMPATIBILITYMODE);
620
621 if (hList != NULL)
622 {
623 EnableWindow(hList,
624 IsDlgButtonChecked(hwndDlg,
625 IDC_CHKRUNCOMPATIBILITY) == BST_CHECKED);
626 }
627 /* fall through */
628 }
629
630 case IDC_CHKRUNIN256COLORS:
631 case IDC_CHKRUNIN640480RES:
632 case IDC_CHKDISABLEVISUALTHEMES:
633 ReportPropertyChange(this,
634 hwndDlg);
635 break;
636
637 case IDC_EDITCOMPATIBILITYMODES:
638 {
639 if (DialogBoxParam(hInstance,
640 MAKEINTRESOURCE(IDD_EDITCOMPATIBILITYMODES),
641 hwndDlg,
642 EditCompatibilityModesProc,
643 (LPARAM)this) == IDOK)
644 {
645 InitializePage(this,
646 hwndDlg);
647 }
648 break;
649 }
650 }
651 }
652 break;
653 }
654
655 case WM_NOTIFY:
656 {
657 NMHDR *hdr = (NMHDR*)lParam;
658 switch (hdr->code)
659 {
660 case PSN_APPLY:
661 if (this->Changed)
662 {
663 return ApplySettings(this,
664 hwndDlg);
665 }
666 break;
667 }
668 break;
669 }
670
671 case WM_INITDIALOG:
672 {
673 LPPROPSHEETPAGE psp = (LPPROPSHEETPAGE)lParam;
674 this = (LPCOMPATIBILITYPAGE)psp->lParam;
675 SetWindowLongPtr(hwndDlg,
676 GWLP_USERDATA,
677 (LONG_PTR)this);
678
679 InitializePage(this,
680 hwndDlg);
681 break;
682 }
683 }
684
685 return FALSE;
686 }
687
688 static UINT CALLBACK
689 CompatibilityPageCallback(HWND hwnd,
690 UINT uMsg,
691 LPPROPSHEETPAGE ppsp)
692 {
693 LPCOMPATIBILITYPAGE this = (LPCOMPATIBILITYPAGE)ppsp->lParam;
694
695 switch (uMsg)
696 {
697 case PSPCB_CREATE:
698 return TRUE;
699
700 case PSPCB_RELEASE:
701 ICompatibilityPage_fnRelease(this);
702 return FALSE;
703
704 default:
705 return FALSE;
706 }
707 }
708
709 static LPCOMPATIBILITYPAGE
710 ICompatibilityPage_fnConstructor(VOID)
711 {
712 LPCOMPATIBILITYPAGE cp;
713
714 cp = HeapAlloc(GetProcessHeap(),
715 HEAP_ZERO_MEMORY,
716 sizeof(COMPATIBILITYPAGE));
717 if (cp != NULL)
718 {
719 cp->lpVtbl = &efvt;
720 cp->lpVtbl->fn.IShellPropSheetExt = efvtIShellPropSheetExt;
721 cp->ref = 1;
722 InterlockedIncrement(&dllrefs);
723 }
724
725 return cp;
726 }
727
728 HRESULT STDMETHODCALLTYPE
729 ICompatibilityPage_fnQueryInterface(LPCOMPATIBILITYPAGE this,
730 REFIID iid,
731 PVOID *pvObject)
732 {
733 if (IsEqualIID(iid,
734 &IID_IShellPropSheetExt))
735 {
736 this->lpVtbl->fn.IShellPropSheetExt = efvtIShellPropSheetExt;
737 ICompatibilityPage_fnAddRef(this);
738 *pvObject = this;
739 return S_OK;
740 }
741 else if (IsEqualIID(iid,
742 &IID_IShellExtInit))
743 {
744 this->lpVtbl->fn.IShellExtInit = efvtIShellExtInit;
745 ICompatibilityPage_fnAddRef(this);
746 *pvObject = this;
747 return S_OK;
748 }
749 else if (IsEqualIID(iid,
750 &IID_IClassFactory))
751 {
752 this->lpVtbl->fn.IClassFactory = efvtIClassFactory;
753 ICompatibilityPage_fnAddRef(this);
754 *pvObject = this;
755 return S_OK;
756 }
757 else if (IsEqualIID(iid,
758 &IID_IUnknown))
759 {
760 ICompatibilityPage_fnAddRef(this);
761 *pvObject = this;
762 return S_OK;
763 }
764
765 *pvObject = NULL;
766 return E_NOINTERFACE;
767 }
768
769 ULONG STDMETHODCALLTYPE
770 ICompatibilityPage_fnAddRef(LPCOMPATIBILITYPAGE this)
771 {
772 return (ULONG)InterlockedIncrement(&this->ref);
773 }
774
775 ULONG STDMETHODCALLTYPE
776 ICompatibilityPage_fnRelease(LPCOMPATIBILITYPAGE this)
777 {
778 ULONG rfc;
779
780 rfc = (ULONG)InterlockedDecrement(&this->ref);
781 if (rfc == 0)
782 {
783 HeapFree(GetProcessHeap(),
784 0,
785 this);
786 InterlockedDecrement(&dllrefs);
787 }
788 return rfc;
789 }
790
791 HRESULT STDMETHODCALLTYPE
792 ICompatibilityPage_fnAddPages(LPCOMPATIBILITYPAGE this,
793 LPFNADDPROPSHEETPAGE lpfnAddPage,
794 LPARAM lParam)
795 {
796 PROPSHEETPAGE psp = {0};
797 HPROPSHEETPAGE hPage;
798
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;
806
807 hPage = CreatePropertySheetPage(&psp);
808
809 if (hPage != NULL)
810 {
811 if (!lpfnAddPage(hPage,
812 lParam))
813 {
814 DestroyPropertySheetPage(hPage);
815 return E_OUTOFMEMORY;
816 }
817
818 ICompatibilityPage_fnAddRef(this);
819 return S_OK;
820 }
821
822 return E_FAIL;
823 }
824
825 HRESULT STDMETHODCALLTYPE
826 ICompatibilityPage_fnReplacePage(LPCOMPATIBILITYPAGE this,
827 UINT uPageID,
828 LPFNADDPROPSHEETPAGE lpfnReplacePage,
829 LPARAM lParam)
830 {
831 return E_NOTIMPL;
832 }
833
834 HRESULT STDMETHODCALLTYPE
835 ICompatibilityPage_fnInitialize(LPCOMPATIBILITYPAGE this,
836 LPCITEMIDLIST pidlFolder,
837 IDataObject *pdtobj,
838 HKEY hkeyProgID)
839 {
840 FORMATETC fetc;
841 STGMEDIUM smdm;
842
843 if (pdtobj == NULL)
844 {
845 return E_INVALIDARG;
846 }
847
848 fetc.cfFormat = CF_HDROP;
849 fetc.ptd = NULL;
850 fetc.dwAspect = DVASPECT_CONTENT;
851 fetc.lindex = -1;
852 fetc.tymed = TYMED_HGLOBAL;
853
854 if (SUCCEEDED(pdtobj->lpVtbl->GetData(pdtobj,
855 &fetc,
856 &smdm)))
857 {
858 UINT nFiles = DragQueryFile(smdm.hGlobal,
859 0xFFFFFFFF,
860 this->szFile,
861 sizeof(this->szFile) / sizeof(this->szFile[0]));
862 if (nFiles == 1)
863 {
864 /* FIXME - support editing of multiple files later */
865 DragQueryFile(smdm.hGlobal,
866 0, this->szFile,
867 sizeof(this->szFile) / sizeof(this->szFile[0]));
868 ReleaseStgMedium(&smdm);
869
870 return S_OK;
871 }
872 }
873
874 return E_FAIL;
875 }
876
877 HRESULT STDMETHODCALLTYPE
878 ICompatibilityPage_fnCreateInstance(LPCOMPATIBILITYPAGE this,
879 LPUNKNOWN pUnkOuter,
880 REFIID riid,
881 PVOID *ppvObject)
882 {
883 LPCOMPATIBILITYPAGE cp;
884
885 if (pUnkOuter != NULL &&
886 !IsEqualIID(riid,
887 &IID_IUnknown))
888 {
889 return CLASS_E_NOAGGREGATION;
890 }
891
892 cp = ICompatibilityPage_fnConstructor();
893 if (cp != NULL)
894 {
895 HRESULT ret = ICompatibilityPage_fnQueryInterface(cp,
896 riid,
897 ppvObject);
898 ICompatibilityPage_fnRelease(cp);
899 return ret;
900 }
901
902 return E_OUTOFMEMORY;
903 }
904
905 HRESULT STDMETHODCALLTYPE
906 ICompatibilityPage_fnLockServer(LPCOMPATIBILITYPAGE this,
907 BOOL fLock)
908 {
909 if (fLock)
910 {
911 InterlockedIncrement(&dllrefs);
912 }
913 else
914 {
915 InterlockedDecrement(&dllrefs);
916 }
917
918 return S_OK;
919 }
920
921 /******************************************************************************
922 Exported
923 ******************************************************************************/
924
925 HRESULT WINAPI
926 DllGetClassObject(REFCLSID rclsid,
927 REFIID iid,
928 LPVOID *ppv)
929 {
930 if (ppv == NULL)
931 {
932 return E_INVALIDARG;
933 }
934
935 if (IsEqualCLSID(&CLSID_ICompatibilityPage,
936 rclsid))
937 {
938 LPCOMPATIBILITYPAGE iface = ICompatibilityPage_fnConstructor();
939 if (iface != NULL)
940 {
941 HRESULT ret = ICompatibilityPage_fnQueryInterface(iface,
942 iid,
943 ppv);
944 ICompatibilityPage_fnRelease(iface);
945 return ret;
946 }
947 return E_OUTOFMEMORY;
948 }
949
950 return CLASS_E_CLASSNOTAVAILABLE;
951 }
952
953 HRESULT WINAPI
954 DllCanUnloadNow(VOID)
955 {
956 return ((dllrefs == 0) ? S_OK : S_FALSE);
957 }
958
959 static int
960 UnregisterPropSheetHandler(LPTSTR szType)
961 {
962 TCHAR szKey[255];
963
964 _stprintf(szKey,
965 TEXT("%s\\shellex\\PropertySheetHandlers\\Compatibility Property Page"),
966 szType);
967
968 return RegDeleteKey(HKEY_CLASSES_ROOT,
969 szKey);
970 }
971
972 HRESULT WINAPI
973 DllUnregisterServer(VOID)
974 {
975 LONG e;
976 HKEY hk;
977 WCHAR szGuid[40];
978
979 StringFromGUID2(&CLSID_ICompatibilityPage,
980 szGuid,
981 sizeof(szGuid) / sizeof(szGuid[0]));
982
983 e = RegOpenKey(HKEY_LOCAL_MACHINE,
984 TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"),
985 &hk);
986 if (e == ERROR_SUCCESS)
987 {
988 e = RegDeleteValueW(hk,
989 szGuid);
990 RegCloseKey(hk);
991 }
992
993 if (e == ERROR_SUCCESS)
994 {
995 e = UnregisterPropSheetHandler(TEXT("exefile"));
996 }
997
998 if (e == ERROR_SUCCESS)
999 {
1000 e = RegOpenKey(HKEY_CLASSES_ROOT,
1001 TEXT("CLSID"),
1002 &hk);
1003 if (e == ERROR_SUCCESS)
1004 {
1005 TCHAR szInprocKey[255];
1006
1007 _stprintf(szInprocKey,
1008 TEXT("%ws\\InprocServer32"),
1009 szGuid);
1010
1011 e = RegDeleteKey(hk,
1012 szInprocKey);
1013 if (e == ERROR_SUCCESS)
1014 {
1015 e = RegDeleteKeyW(hk,
1016 szGuid);
1017 }
1018 RegCloseKey(hk);
1019 }
1020 }
1021
1022 return ((e == ERROR_SUCCESS) ? S_OK : E_ACCESSDENIED);
1023 }
1024
1025 static int
1026 RegisterPropSheetHandler(LPTSTR szType,
1027 LPWSTR szGuid)
1028 {
1029 TCHAR szKey[255];
1030 HKEY hk;
1031 int e;
1032
1033 _stprintf(szKey,
1034 TEXT("%s\\shellex\\PropertySheetHandlers\\Compatibility Property Page"),
1035 szType);
1036
1037 e = RegCreateKey(HKEY_CLASSES_ROOT,
1038 szKey,
1039 &hk);
1040 if (e == ERROR_SUCCESS)
1041 {
1042 e = RegSetValueExW(hk,
1043 NULL,
1044 0,
1045 REG_SZ,
1046 (BYTE*)szGuid,
1047 (wcslen(szGuid) + 1) * sizeof(WCHAR));
1048 RegCloseKey(hk);
1049 }
1050
1051 return e;
1052 }
1053
1054 HRESULT WINAPI
1055 DllRegisterServer(VOID)
1056 {
1057 LONG e = E_ACCESSDENIED;
1058 HKEY hk;
1059 WCHAR szGuid[40];
1060 WCHAR szDescription[255];
1061 TCHAR szModule[MAX_PATH + 1];
1062 int lnszDescription;
1063
1064 if (!GetModuleFileName(hInstance,
1065 szModule,
1066 sizeof(szModule) / sizeof(szModule[0])))
1067 {
1068 return E_ACCESSDENIED;
1069 }
1070
1071 /* unregister first */
1072 DllUnregisterServer();
1073
1074 lnszDescription = LoadStringW(hInstance,
1075 IDS_DESCRIPTION,
1076 szDescription, sizeof(szDescription) / sizeof(szDescription[0]));
1077 if (lnszDescription > 0)
1078 {
1079 StringFromGUID2(&CLSID_ICompatibilityPage,
1080 szGuid,
1081 sizeof(szGuid) / sizeof(szGuid[0]));
1082
1083 e = RegOpenKey(HKEY_LOCAL_MACHINE,
1084 TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"),
1085 &hk);
1086 if (e == ERROR_SUCCESS)
1087 {
1088 e = RegSetValueExW(hk,
1089 szGuid,
1090 0,
1091 REG_SZ,
1092 (BYTE*)szDescription,
1093 (lnszDescription + 1) * sizeof(WCHAR));
1094 RegCloseKey(hk);
1095 }
1096
1097 if (e == ERROR_SUCCESS)
1098 {
1099 TCHAR szInprocKey[255];
1100
1101 _stprintf(szInprocKey,
1102 TEXT("CLSID\\%ws\\InprocServer32"),
1103 szGuid);
1104
1105 e = RegCreateKey(HKEY_CLASSES_ROOT,
1106 szInprocKey,
1107 &hk);
1108 if (e == ERROR_SUCCESS)
1109 {
1110 e = RegSetValueEx(hk,
1111 NULL,
1112 0,
1113 REG_SZ,
1114 (BYTE*)szModule,
1115 (_tcslen(szModule) + 1) * sizeof(TCHAR));
1116 if (e == ERROR_SUCCESS)
1117 {
1118 const TCHAR szApartment[] = TEXT("Apartment");
1119
1120 e = RegSetValueEx(hk,
1121 TEXT("ThreadingModel"),
1122 0,
1123 REG_SZ,
1124 (BYTE*)szApartment,
1125 (_tcslen(szApartment) + 1) * sizeof(TCHAR));
1126 }
1127
1128 RegCloseKey(hk);
1129 }
1130 }
1131
1132 if (e == ERROR_SUCCESS)
1133 {
1134 e = RegisterPropSheetHandler(TEXT("exefile"),
1135 szGuid);
1136 }
1137 }
1138
1139 return ((e == ERROR_SUCCESS) ? S_OK : E_ACCESSDENIED);
1140 }
1141
1142 BOOL WINAPI
1143 DllMain(HINSTANCE hinstDLL,
1144 DWORD dwReason,
1145 LPVOID lpvReserved)
1146 {
1147 switch (dwReason)
1148 {
1149 case DLL_PROCESS_ATTACH:
1150 hInstance = hinstDLL;
1151 DisableThreadLibraryCalls(hInstance);
1152 break;
1153 }
1154
1155 return TRUE;
1156 }
1157