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