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