0e1f6ff7dfe98534e5a992e3026157791bbfc0f5
[reactos.git] / reactos / subsys / system / explorer / utility / shellclasses.h
1 /*
2 * Copyright 2003, 2004, 2005 Martin Fuchs
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19
20 //
21 // Explorer clone
22 //
23 // shellclasses.h
24 //
25 // C++ wrapper classes for COM interfaces and shell objects
26 //
27 // Martin Fuchs, 20.07.2003
28 //
29
30
31 // windows shell headers
32 #include <shellapi.h>
33 #include <shlobj.h>
34
35 /*@@
36 #if _MSC_VER>=1300 // VS.Net
37 #include <comdefsp.h>
38 using namespace _com_util;
39 #endif
40 */
41
42 #ifndef _INC_COMUTIL // is comutil.h of MS headers not available?
43 #ifndef _NO_COMUTIL
44 #define _NO_COMUTIL
45 #endif
46 #endif
47
48 // work around GCC's wide string constant bug when compiling inline functions
49 #ifdef __GNUC__
50 extern const LPCTSTR sCFSTR_SHELLIDLIST;
51 #undef CFSTR_SHELLIDLIST
52 #define CFSTR_SHELLIDLIST sCFSTR_SHELLIDLIST
53 #endif
54
55
56 // Exception Handling
57
58 #ifndef _NO_COMUTIL
59
60 #define COMExceptionBase _com_error
61
62 #else
63
64 /// COM ExceptionBase class as replacement for _com_error
65 struct COMExceptionBase
66 {
67 COMExceptionBase(HRESULT hr)
68 : _hr(hr)
69 {
70 }
71
72 HRESULT Error() const
73 {
74 return _hr;
75 }
76
77 LPCTSTR ErrorMessage() const
78 {
79 if (_msg.empty()) {
80 LPTSTR pBuf;
81
82 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
83 0, _hr, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (LPTSTR)&pBuf, 0, NULL)) {
84 _msg = pBuf;
85 LocalFree(pBuf);
86 } else {
87 TCHAR buffer[128];
88 _stprintf(buffer, TEXT("unknown Exception: 0x%08lX"), _hr);
89 _msg = buffer;
90 }
91 }
92
93 return _msg;
94 }
95
96 protected:
97 HRESULT _hr;
98 mutable String _msg;
99 };
100
101 #endif
102
103
104 /// Exception with context information
105
106 struct COMException : public COMExceptionBase
107 {
108 typedef COMExceptionBase super;
109
110 COMException(HRESULT hr)
111 : super(hr),
112 _context(CURRENT_CONTEXT),
113 _file(NULL), _line(0)
114 {
115 LOG(toString());
116 LOG(CURRENT_CONTEXT.getStackTrace());
117 }
118
119 COMException(HRESULT hr, const char* file, int line)
120 : super(hr),
121 _context(CURRENT_CONTEXT),
122 _file(file), _line(line)
123 {
124 LOG(toString());
125 LOG(CURRENT_CONTEXT.getStackTrace());
126 }
127
128 COMException(HRESULT hr, const String& obj)
129 : super(hr),
130 _context(CURRENT_CONTEXT),
131 _file(NULL), _line(0)
132 {
133 LOG(toString());
134 LOG(CURRENT_CONTEXT.getStackTrace());
135 }
136
137 COMException(HRESULT hr, const String& obj, const char* file, int line)
138 : super(hr),
139 _context(CURRENT_CONTEXT),
140 _file(file), _line(line)
141 {
142 LOG(toString());
143 LOG(CURRENT_CONTEXT.getStackTrace());
144 }
145
146 String toString() const;
147
148 Context _context;
149
150 const char* _file;
151 int _line;
152 };
153
154 #define THROW_EXCEPTION(hr) throw COMException(hr, __FILE__, __LINE__)
155 #define CHECKERROR(hr) ((void)(FAILED(hr)? THROW_EXCEPTION(hr): 0))
156
157
158 #ifdef _NO_COMUTIL
159
160 inline void CheckError(HRESULT hr)
161 {
162 if (FAILED(hr))
163 throw COMException(hr);
164 }
165
166 #endif
167
168
169 /// COM Initialisation
170
171 struct ComInit
172 {
173 ComInit()
174 {
175 CHECKERROR(CoInitialize(0));
176 }
177
178 #if (_WIN32_WINNT>=0x0400) || defined(_WIN32_DCOM)
179 ComInit(DWORD flag)
180 {
181 CHECKERROR(CoInitializeEx(0, flag));
182 }
183 #endif
184
185 ~ComInit()
186 {
187 CoUninitialize();
188 }
189 };
190
191
192 /// OLE initialisation for drag drop support
193
194 struct OleInit
195 {
196 OleInit()
197 {
198 CHECKERROR(OleInitialize(0));
199 }
200
201 ~OleInit()
202 {
203 OleUninitialize();
204 }
205 };
206
207
208 /// Exception Handler for COM exceptions
209
210 extern void HandleException(COMException& e, HWND hwnd);
211
212
213 /// We use a common IMalloc object for all shell memory allocations.
214
215 struct CommonShellMalloc
216 {
217 CommonShellMalloc()
218 {
219 _p = NULL;
220 }
221
222 void init()
223 {
224 if (!_p)
225 CHECKERROR(SHGetMalloc(&_p));
226 }
227
228 ~CommonShellMalloc()
229 {
230 if (_p)
231 _p->Release();
232 }
233
234 operator IMalloc*()
235 {
236 return _p;
237 }
238
239 IMalloc* _p;
240 };
241
242
243 /// wrapper class for IMalloc with usage of common allocator
244
245 struct ShellMalloc
246 {
247 ShellMalloc()
248 {
249 // initialize s_cmn_shell_malloc
250 s_cmn_shell_malloc.init();
251 }
252
253 IMalloc* operator->()
254 {
255 return s_cmn_shell_malloc;
256 }
257
258 static CommonShellMalloc s_cmn_shell_malloc;
259 };
260
261
262 /// wrapper template class for pointers to shell objects managed by IMalloc
263
264 template<typename T> struct SShellPtr
265 {
266 ~SShellPtr()
267 {
268 _malloc->Free(_p);
269 }
270
271 T* operator->()
272 {
273 return _p;
274 }
275
276 T const* operator->() const
277 {
278 return _p;
279 }
280
281 operator T const *() const
282 {
283 return _p;
284 }
285
286 const T& operator*() const
287 {
288 return *_p;
289 }
290
291 T& operator*()
292 {
293 return *_p;
294 }
295
296 protected:
297 SShellPtr()
298 : _p(0)
299 {
300 }
301
302 SShellPtr(T* p)
303 : _p(p)
304 {
305 }
306
307 void Free()
308 {
309 _malloc->Free(_p);
310 _p = NULL;
311 }
312
313 T* _p;
314 mutable ShellMalloc _malloc; // IMalloc memory management object
315
316 private:
317 // disallow copying of SShellPtr objects
318 SShellPtr(const SShellPtr&) {}
319 void operator=(SShellPtr const&) {}
320 };
321
322
323 /// wrapper class for COM interface pointers
324
325 template<typename T> struct SIfacePtr
326 {
327 SIfacePtr()
328 : _p(0)
329 {
330 }
331
332 SIfacePtr(T* p)
333 : _p(p)
334 {
335 if (p)
336 p->AddRef();
337 }
338
339 SIfacePtr(IUnknown* unknown, REFIID riid)
340 {
341 CHECKERROR(unknown->QueryInterface(riid, (LPVOID*)&_p));
342 }
343
344 ~SIfacePtr()
345 {
346 Free();
347 }
348
349 T* operator->()
350 {
351 return _p;
352 }
353
354 const T* operator->() const
355 {
356 return _p;
357 }
358
359 /* not GCC compatible
360 operator const T*() const
361 {
362 return _p;
363 } */
364
365 operator T*()
366 {
367 return _p;
368 }
369
370 T** operator&()
371 {
372 return &_p;
373 }
374
375 bool empty() const //NOTE: GCC seems not to work correctly when defining operator bool() AND operator T*() at one time
376 {
377 return !_p;
378 }
379
380 SIfacePtr& operator=(T* p)
381 {
382 Free();
383
384 if (p) {
385 p->AddRef();
386 _p = p;
387 }
388
389 return *this;
390 }
391
392 void operator=(SIfacePtr const& o)
393 {
394 T* h = _p;
395
396 if (o._p)
397 o._p->AddRef();
398
399 _p = o._p;
400
401 if (h)
402 h->Release();
403 }
404
405 HRESULT CreateInstance(REFIID clsid, REFIID riid)
406 {
407 return CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, riid, (LPVOID*)&_p);
408 }
409
410 template<typename I> HRESULT QueryInterface(REFIID riid, I* p)
411 {
412 return _p->QueryInterface(riid, (LPVOID*)p);
413 }
414
415 T* get()
416 {
417 return _p;
418 }
419
420 void Free()
421 {
422 T* h = _p;
423 _p = NULL;
424
425 if (h)
426 h->Release();
427 }
428
429 protected:
430 SIfacePtr(const SIfacePtr& o)
431 : _p(o._p)
432 {
433 if (_p)
434 _p->AddRef();
435 }
436
437 T* _p;
438 };
439
440
441
442 struct ShellFolder;
443
444
445 /// caching of desktop ShellFolder object
446
447 struct CommonDesktop
448 {
449 CommonDesktop()
450 {
451 _desktop = 0;
452 }
453
454 ~CommonDesktop();
455
456 void init();
457
458 operator ShellFolder&()
459 {
460 return *_desktop;
461 }
462
463 protected:
464 ShellFolder* _desktop;
465 };
466
467
468 #ifndef _NO_COMUTIL // _com_ptr available?
469
470 /// IShellFolder smart pointer
471 struct ShellFolder : public IShellFolderPtr // IShellFolderPtr uses intrinsic extensions of the VC++ compiler.
472 {
473 typedef IShellFolderPtr super;
474
475 ShellFolder(); // desktop folder
476 ShellFolder(IShellFolder* p);
477 ShellFolder(IShellFolder* parent, LPCITEMIDLIST pidl);
478 ShellFolder(LPCITEMIDLIST pidl);
479
480 void attach(IShellFolder* parent, LPCITEMIDLIST pidl);
481 String get_name(LPCITEMIDLIST pidl=NULL, SHGDNF flags=SHGDN_NORMAL) const;
482
483 bool empty() const {return !operator bool();} //NOTE: see SIfacePtr::empty()
484 };
485
486 #ifdef UNICODE
487 #define IShellLinkPtr IShellLinkWPtr
488 #else
489 #define IShellLinkPtr IShellLinkAPtr
490 #endif
491
492 /// IShellLink smart pointer
493 struct ShellLinkPtr : public IShellLinkPtr
494 {
495 typedef IShellLinkPtr super;
496
497 ShellLinkPtr(IShellLink* p)
498 : super(p)
499 {
500 p->AddRef();
501 }
502
503 bool empty() const {return !operator bool();} //NOTE: see SIfacePtr::empty()
504 };
505
506 #else // _com_ptr not available -> use SIfacePtr
507
508 /// IShellFolder smart pointer
509 struct ShellFolder : public SIfacePtr<IShellFolder>
510 {
511 typedef SIfacePtr<IShellFolder> super;
512
513 ShellFolder();
514 ShellFolder(IShellFolder* p);
515 ShellFolder(IShellFolder* parent, LPCITEMIDLIST pidl);
516 ShellFolder(LPCITEMIDLIST pidl);
517
518 void attach(IShellFolder* parent, LPCITEMIDLIST pidl);
519 String get_name(LPCITEMIDLIST pidl, SHGDNF flags=SHGDN_NORMAL) const;
520 };
521
522 /// IShellLink smart pointer
523 struct ShellLinkPtr : public SIfacePtr<IShellLink>
524 {
525 typedef SIfacePtr<IShellLink> super;
526
527 ShellLinkPtr(IShellLink* p)
528 : super(p)
529 {
530 _p->AddRef();
531 }
532
533 };
534
535 #endif
536
537
538 extern ShellFolder& GetDesktopFolder();
539
540
541 #ifdef UNICODE
542 #define path_from_pidl path_from_pidlW
543 #else
544 #define path_from_pidl path_from_pidlA
545 #endif
546
547 extern HRESULT path_from_pidlA(IShellFolder* folder, LPCITEMIDLIST pidl, LPSTR buffer, int len);
548 extern HRESULT path_from_pidlW(IShellFolder* folder, LPCITEMIDLIST pidl, LPWSTR buffer, int len);
549 extern HRESULT name_from_pidl(IShellFolder* folder, LPCITEMIDLIST pidl, LPTSTR buffer, int len, SHGDNF flags);
550
551
552 #ifdef __MINGW32__ // ILGetSize() is currently missing in MinGW.
553 extern "C" UINT STDCALL ILGetSize(LPCITEMIDLIST pidl);
554
555 #ifdef UNICODE // CFSTR_FILENAME is defined wrong in MinGW.
556 #define CFSTR_FILENAMEW TEXT("FileNameW")
557 #undef CFSTR_FILENAME
558 #define CFSTR_FILENAME CFSTR_FILENAMEW
559 #endif
560
561 #endif
562
563
564 /// wrapper class for item ID lists
565
566 struct ShellPath : public SShellPtr<ITEMIDLIST>
567 {
568 typedef SShellPtr<ITEMIDLIST> super;
569
570 ShellPath()
571 {
572 }
573
574 ShellPath(IShellFolder* folder, LPCWSTR path)
575 {
576 CONTEXT("ShellPath::ShellPath(IShellFolder*, LPCWSTR)");
577
578 if (path)
579 CHECKERROR(folder->ParseDisplayName(0, NULL, (LPOLESTR)path, NULL, &_p, NULL));
580 else
581 _p = NULL;
582 }
583
584 ShellPath(LPCWSTR path)
585 {
586 OBJ_CONTEXT("ShellPath::ShellPath(LPCWSTR)", path);
587
588 if (path)
589 CHECKERROR(GetDesktopFolder()->ParseDisplayName(0, NULL, (LPOLESTR)path, NULL, &_p, NULL));
590 else
591 _p = NULL;
592 }
593
594 ShellPath(IShellFolder* folder, LPCSTR path)
595 {
596 CONTEXT("ShellPath::ShellPath(IShellFolder*, LPCSTR)");
597
598 WCHAR b[MAX_PATH];
599
600 if (path) {
601 MultiByteToWideChar(CP_ACP, 0, path, -1, b, MAX_PATH);
602 CHECKERROR(folder->ParseDisplayName(0, NULL, b, NULL, &_p, NULL));
603 } else
604 _p = NULL;
605 }
606
607 ShellPath(LPCSTR path)
608 {
609 CONTEXT("ShellPath::ShellPath(LPCSTR)");
610
611 WCHAR b[MAX_PATH];
612
613 if (path) {
614 MultiByteToWideChar(CP_ACP, 0, path, -1, b, MAX_PATH);
615 CHECKERROR(GetDesktopFolder()->ParseDisplayName(0, NULL, b, NULL, &_p, NULL));
616 } else
617 _p = NULL;
618 }
619
620 ShellPath(const ShellPath& o)
621 : super(NULL)
622 {
623 //CONTEXT("ShellPath::ShellPath(const ShellPath&)");
624
625 if (o._p) {
626 int l = ILGetSize(o._p);
627 _p = (ITEMIDLIST*) _malloc->Alloc(l);
628 if (_p) memcpy(_p, o._p, l);
629 }
630 }
631
632 explicit ShellPath(LPITEMIDLIST p)
633 : super(p)
634 {
635 }
636
637 ShellPath(LPCITEMIDLIST p)
638 {
639 //CONTEXT("ShellPath::ShellPath(LPCITEMIDLIST)");
640
641 if (p) {
642 int l = ILGetSize(p);
643 _p = (ITEMIDLIST*) _malloc->Alloc(l);
644 if (_p) memcpy(_p, p, l);
645 }
646 }
647
648 void operator=(const ShellPath& o)
649 {
650 //CONTEXT("ShellPath::operator=(const ShellPath&)");
651
652 ITEMIDLIST* h = _p;
653
654 if (o._p) {
655 int l = ILGetSize(o._p);
656
657 _p = (ITEMIDLIST*) _malloc->Alloc(l);
658 if (_p) memcpy(_p, o._p, l);
659 }
660 else
661 _p = NULL;
662
663 _malloc->Free(h);
664 }
665
666 void operator=(ITEMIDLIST* p)
667 {
668 //CONTEXT("ShellPath::operator=(ITEMIDLIST*)");
669
670 ITEMIDLIST* h = _p;
671
672 if (p) {
673 int l = ILGetSize(p);
674 _p = (ITEMIDLIST*) _malloc->Alloc(l);
675 if (_p) memcpy(_p, p, l);
676 }
677 else
678 _p = NULL;
679
680 _malloc->Free(h);
681 }
682
683 void operator=(const SHITEMID& o)
684 {
685 ITEMIDLIST* h = _p;
686
687 LPBYTE p = (LPBYTE)_malloc->Alloc(o.cb+2);
688 if (p) *(PWORD)((LPBYTE)memcpy(p, &o, o.cb)+o.cb) = 0;
689 _p = (ITEMIDLIST*)p;
690
691 _malloc->Free(h);
692 }
693
694 void operator+=(const SHITEMID& o)
695 {
696 int l0 = ILGetSize(_p);
697 LPBYTE p = (LPBYTE)_malloc->Alloc(l0+o.cb);
698 int l = l0 - 2;
699
700 if (p) {
701 memcpy(p, _p, l);
702 *(PWORD)((LPBYTE)memcpy(p+l, &o, o.cb)+o.cb) = 0;
703 }
704
705 _malloc->Free(_p);
706 _p = (ITEMIDLIST*)p;
707 }
708
709 void assign(LPCITEMIDLIST pidl, size_t size)
710 {
711 //CONTEXT("ShellPath::assign(LPCITEMIDLIST, size_t)");
712
713 ITEMIDLIST* h = _p;
714
715 _p = (ITEMIDLIST*) _malloc->Alloc(size+sizeof(USHORT/*SHITEMID::cb*/));
716
717 if (_p) {
718 memcpy(_p, pidl, size);
719 ((ITEMIDLIST*)((LPBYTE)_p+size))->mkid.cb = 0; // terminator
720 }
721
722 _malloc->Free(h);
723 }
724
725 void assign(LPCITEMIDLIST pidl)
726 {
727 //CONTEXT("ShellPath::assign(LPCITEMIDLIST)");
728
729 ITEMIDLIST* h = _p;
730
731 if (pidl) {
732 int l = ILGetSize(pidl);
733 _p = (ITEMIDLIST*) _malloc->Alloc(l);
734 if (_p) memcpy(_p, pidl, l);
735 } else
736 _p = NULL;
737
738 _malloc->Free(h);
739 }
740
741 void split(ShellPath& parent, ShellPath& obj) const;
742
743 void GetUIObjectOf(REFIID riid, LPVOID* ppvOut, HWND hWnd=0, ShellFolder& sf=GetDesktopFolder());
744
745 ShellFolder get_folder()
746 {
747 return ShellFolder(_p);
748 }
749
750 ShellFolder get_folder(IShellFolder* parent)
751 {
752 CONTEXT("ShellPath::get_folder()");
753 return ShellFolder(parent, _p);
754 }
755
756 // convert an item id list from relative to absolute (=relative to the desktop) format
757 ShellPath create_absolute_pidl(LPCITEMIDLIST parent_pidl) const;
758 };
759
760
761 #ifdef __WINE__ // Wine doesn't know of unnamed union members and uses some macros instead.
762 #define UNION_MEMBER(x) DUMMYUNIONNAME.##x
763 #else
764 #define UNION_MEMBER(x) x
765 #endif
766
767
768 // encapsulation of STRRET structure for easy string retrieval with conversion
769
770 #ifdef UNICODE
771 #define StrRet StrRetW
772 #define tcscpyn wcscpyn
773 #else
774 #define StrRet StrRetA
775 #define tcscpyn strcpyn
776 #endif
777
778 extern LPSTR strcpyn(LPSTR dest, LPCSTR source, size_t count);
779 extern LPWSTR wcscpyn(LPWSTR dest, LPCWSTR source, size_t count);
780
781 /// easy retrieval of multi byte strings out of STRRET structures
782 struct StrRetA : public STRRET
783 {
784 ~StrRetA()
785 {
786 if (uType == STRRET_WSTR)
787 ShellMalloc()->Free(pOleStr);
788 }
789
790 void GetString(const SHITEMID& shiid, LPSTR b, int l)
791 {
792 switch(uType) {
793 case STRRET_WSTR:
794 WideCharToMultiByte(CP_ACP, 0, UNION_MEMBER(pOleStr), -1, b, l, NULL, NULL);
795 break;
796
797 case STRRET_OFFSET:
798 strcpyn(b, (LPCSTR)&shiid+UNION_MEMBER(uOffset), l);
799 break;
800
801 case STRRET_CSTR:
802 strcpyn(b, UNION_MEMBER(cStr), l);
803 }
804 }
805 };
806
807 /// easy retrieval of wide char strings out of STRRET structures
808 struct StrRetW : public STRRET
809 {
810 ~StrRetW()
811 {
812 if (uType == STRRET_WSTR)
813 ShellMalloc()->Free(pOleStr);
814 }
815
816 void GetString(const SHITEMID& shiid, LPWSTR b, int l)
817 {
818 switch(uType) {
819 case STRRET_WSTR:
820 wcscpyn(b, UNION_MEMBER(pOleStr), l);
821 break;
822
823 case STRRET_OFFSET:
824 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)&shiid+UNION_MEMBER(uOffset), -1, b, l);
825 break;
826
827 case STRRET_CSTR:
828 MultiByteToWideChar(CP_ACP, 0, UNION_MEMBER(cStr), -1, b, l);
829 }
830 }
831 };
832
833
834 /// Retrieval of file system paths of ShellPath objects
835 class FileSysShellPath : public ShellPath
836 {
837 TCHAR _fullpath[MAX_PATH];
838
839 protected:
840 FileSysShellPath() {_fullpath[0] = '\0';}
841
842 public:
843 FileSysShellPath(const ShellPath& o) : ShellPath(o) {_fullpath[0] = '\0';}
844
845 operator LPCTSTR() {if (!SHGetPathFromIDList(_p, _fullpath)) return NULL; return _fullpath;}
846 };
847
848
849 /// Browse dialog operating on shell namespace
850 struct FolderBrowser : public FileSysShellPath
851 {
852 FolderBrowser(HWND owner, UINT flags, LPCTSTR title, LPCITEMIDLIST root=0)
853 {
854 _displayname[0] = '\0';
855 _browseinfo.hwndOwner = owner;
856 _browseinfo.pidlRoot = root;
857 _browseinfo.pszDisplayName = _displayname;
858 _browseinfo.lpszTitle = title;
859 _browseinfo.ulFlags = flags;
860 _browseinfo.lpfn = 0;
861 _browseinfo.lParam = 0;
862 _browseinfo.iImage = 0;
863
864 _p = SHBrowseForFolder(&_browseinfo);
865 }
866
867 LPCTSTR GetDisplayName()
868 {
869 return _displayname;
870 }
871
872 bool IsOK()
873 {
874 return _p != 0;
875 }
876
877 private:
878 BROWSEINFO _browseinfo;
879 TCHAR _displayname[MAX_PATH];
880 };
881
882
883 /// Retrieval of special shell folder paths
884 struct SpecialFolderPath : public ShellPath
885 {
886 SpecialFolderPath(int folder, HWND hwnd)
887 {
888 HRESULT hr = SHGetSpecialFolderLocation(hwnd, folder, &_p);
889 CHECKERROR(hr);
890 }
891 };
892
893 /// Shell folder path of the desktop
894 struct DesktopFolderPath : public SpecialFolderPath
895 {
896 DesktopFolderPath()
897 : SpecialFolderPath(CSIDL_DESKTOP, 0)
898 {
899 }
900 };
901
902 /// Retrieval of special shell folder
903 struct SpecialFolder : public ShellFolder
904 {
905 SpecialFolder(int folder, HWND hwnd)
906 : ShellFolder(GetDesktopFolder(), SpecialFolderPath(folder, hwnd))
907 {
908 }
909 };
910
911 /// Shell folder of the desktop
912 struct DesktopFolder : public ShellFolder
913 {
914 };
915
916
917 /// file system path of special folder
918 struct SpecialFolderFSPath
919 {
920 SpecialFolderFSPath(int folder/*e.g. CSIDL_DESKTOP*/, HWND hwnd);
921
922 operator LPCTSTR()
923 {
924 return _fullpath;
925 }
926
927 protected:
928 TCHAR _fullpath[MAX_PATH];
929 };
930
931 /*
932 /// file system path of special folder
933 struct SpecialFolderFSPath : public FileSysShellPath
934 {
935 SpecialFolderFSPath(int folder, HWND hwnd)
936 {
937 CONTEXT("SpecialFolderFSPath::SpecialFolderFSPath()");
938
939 HRESULT hr = SHGetSpecialFolderLocation(hwnd, folder, &_p);
940 CHECKERROR(hr);
941 }
942 };
943 */
944
945
946 /// wrapper class for enumerating shell namespace objects
947
948 struct ShellItemEnumerator : public SIfacePtr<IEnumIDList>
949 {
950 ShellItemEnumerator(IShellFolder* folder, DWORD flags=SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN)
951 {
952 CONTEXT("ShellItemEnumerator::ShellItemEnumerator()");
953
954 CHECKERROR(folder->EnumObjects(0, flags, &_p));
955 }
956 };
957
958
959 /// list of PIDLs
960 struct PIDList
961 {
962 PIDList()
963 {
964 memset(&_stgm, 0, sizeof(STGMEDIUM));
965 }
966
967 ~PIDList()
968 {
969 if (_stgm.hGlobal) {
970 GlobalUnlock(_stgm.hGlobal);
971 ReleaseStgMedium(&_stgm);
972 }
973 }
974
975 HRESULT GetData(IDataObject* selection)
976 {
977 static UINT CF_IDLIST = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
978
979 FORMATETC fetc;
980 fetc.cfFormat = CF_IDLIST;
981 fetc.ptd = NULL;
982 fetc.dwAspect = DVASPECT_CONTENT;
983 fetc.lindex = -1;
984 fetc.tymed = TYMED_HGLOBAL;
985
986 HRESULT hr = selection->QueryGetData(&fetc);
987 if (FAILED(hr))
988 return hr;
989
990 hr = selection->GetData(&fetc, &_stgm);
991 if (FAILED(hr))
992 return hr;
993
994 _pIDList = (LPIDA)GlobalLock(_stgm.hGlobal);
995
996 return hr;
997 }
998
999 operator LPIDA() {return _pIDList;}
1000
1001 protected:
1002 STGMEDIUM _stgm;
1003 LPIDA _pIDList;
1004 };
1005
1006
1007 struct CtxMenuInterfaces
1008 {
1009 CtxMenuInterfaces()
1010 {
1011 reset();
1012 }
1013
1014 void reset();
1015 bool HandleMenuMsg(UINT nmsg, WPARAM wparam, LPARAM lparam);
1016 IContextMenu* query_interfaces(IContextMenu* pcm1);
1017
1018 IContextMenu2* _pctxmenu2;
1019
1020 #ifndef __MINGW32__ // IContextMenu3 missing in MinGW (as of 6.2.2005)
1021 IContextMenu3* _pctxmenu3;
1022 #endif
1023 };
1024
1025 template<typename BASE> struct ExtContextMenuHandlerT
1026 : public BASE
1027 {
1028 typedef BASE super;
1029
1030 ExtContextMenuHandlerT(HWND hwnd)
1031 : super(hwnd)
1032 {
1033 }
1034
1035 template<typename PARA> ExtContextMenuHandlerT(HWND hwnd, const PARA& info)
1036 : super(hwnd, info)
1037 {
1038 }
1039
1040 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
1041 {
1042 switch(nmsg) {
1043 case WM_DRAWITEM:
1044 case WM_MEASUREITEM:
1045 if (!wparam) // Is the message menu-related?
1046 if (_cm_ifs.HandleMenuMsg(nmsg, wparam, lparam))
1047 return TRUE;
1048
1049 break;
1050
1051 case WM_INITMENUPOPUP:
1052 if (_cm_ifs.HandleMenuMsg(nmsg, wparam, lparam))
1053 return 0;
1054
1055 break;
1056
1057 #ifndef __MINGW32__ // IContextMenu3 missing in MinGW (as of 6.2.2005)
1058 case WM_MENUCHAR: // only supported by IContextMenu3
1059 if (_cm_ifs._pctxmenu3) {
1060 LRESULT lResult = 0;
1061
1062 _cm_ifs._pctxmenu3->HandleMenuMsg2(nmsg, wparam, lparam, &lResult);
1063
1064 return lResult;
1065 }
1066
1067 return 0;
1068 #endif
1069 }
1070
1071 return super::WndProc(nmsg, wparam, lparam);
1072 }
1073
1074 protected:
1075 CtxMenuInterfaces _cm_ifs;
1076 };
1077
1078 extern HRESULT ShellFolderContextMenu(IShellFolder* shell_folder, HWND hwndParent, int cidl,
1079 LPCITEMIDLIST* ppidl, int x, int y, CtxMenuInterfaces& cm_ifs);