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