- Update address of Free Software Foundation.
[reactos.git] / reactos / base / shell / 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 friend bool operator<(const ShellPath& a, const ShellPath& b)
795 {
796 int la = ILGetSize(a._p);
797 int lb = ILGetSize(b._p);
798
799 int r = memcmp(a._p, b._p, min(la, lb));
800 if (r)
801 return r < 0;
802 else
803 return la < lb;
804 }
805
806 void assign(LPCITEMIDLIST pidl, size_t size)
807 {
808 //CONTEXT("ShellPath::assign(LPCITEMIDLIST, size_t)");
809
810 ITEMIDLIST* h = _p;
811
812 _p = (ITEMIDLIST*) _malloc->Alloc(size+sizeof(USHORT/*SHITEMID::cb*/));
813
814 if (_p) {
815 memcpy(_p, pidl, size);
816 ((ITEMIDLIST*)((LPBYTE)_p+size))->mkid.cb = 0; // terminator
817 }
818
819 _malloc->Free(h);
820 }
821
822 void assign(LPCITEMIDLIST pidl)
823 {
824 //CONTEXT("ShellPath::assign(LPCITEMIDLIST)");
825
826 ITEMIDLIST* h = _p;
827
828 if (pidl) {
829 int l = ILGetSize(pidl);
830 _p = (ITEMIDLIST*) _malloc->Alloc(l);
831 if (_p) memcpy(_p, pidl, l);
832 } else
833 _p = NULL;
834
835 _malloc->Free(h);
836 }
837
838 void split(ShellPath& parent, ShellPath& obj) const;
839
840 void GetUIObjectOf(REFIID riid, LPVOID* ppvOut, HWND hWnd=0, ShellFolder& sf=GetDesktopFolder());
841
842 ShellFolder get_folder()
843 {
844 return ShellFolder(_p);
845 }
846
847 ShellFolder get_folder(IShellFolder* parent)
848 {
849 CONTEXT("ShellPath::get_folder()");
850 return ShellFolder(parent, _p);
851 }
852
853 // convert an item id list from relative to absolute (=relative to the desktop) format
854 ShellPath create_absolute_pidl(LPCITEMIDLIST parent_pidl) const;
855 };
856
857
858 #if defined(__WINE__) && defined(NONAMELESSUNION) // Wine doesn't know of unnamed union members and uses some macros instead.
859 #define UNION_MEMBER(x) DUMMYUNIONNAME.##x
860 #else
861 #define UNION_MEMBER(x) x
862 #endif
863
864
865 // encapsulation of STRRET structure for easy string retrieval with conversion
866
867 #ifdef UNICODE
868 #define StrRet StrRetW
869 //#define tcscpyn wcscpyn
870 #else
871 #define StrRet StrRetA
872 //#define tcscpyn strcpyn
873 #endif
874
875 //extern LPSTR strcpyn(LPSTR dest, LPCSTR source, size_t count);
876 //extern LPWSTR wcscpyn(LPWSTR dest, LPCWSTR source, size_t count);
877
878 /// easy retrieval of multi byte strings out of STRRET structures
879 struct StrRetA : public STRRET
880 {
881 ~StrRetA()
882 {
883 if (uType == STRRET_WSTR)
884 ShellMalloc()->Free(pOleStr);
885 }
886
887 void GetString(const SHITEMID& shiid, LPSTR b, int l)
888 {
889 switch(uType) {
890 case STRRET_WSTR:
891 WideCharToMultiByte(CP_ACP, 0, UNION_MEMBER(pOleStr), -1, b, l, NULL, NULL);
892 break;
893
894 case STRRET_OFFSET:
895 lstrcpynA(b, (LPCSTR)&shiid+UNION_MEMBER(uOffset), l);
896 break;
897
898 case STRRET_CSTR:
899 lstrcpynA(b, UNION_MEMBER(cStr), l);
900 }
901 }
902 };
903
904 /// easy retrieval of wide char strings out of STRRET structures
905 struct StrRetW : public STRRET
906 {
907 ~StrRetW()
908 {
909 if (uType == STRRET_WSTR)
910 ShellMalloc()->Free(pOleStr);
911 }
912
913 void GetString(const SHITEMID& shiid, LPWSTR b, int l)
914 {
915 switch(uType) {
916 case STRRET_WSTR:
917 lstrcpynW(b, UNION_MEMBER(pOleStr), l);
918 break;
919
920 case STRRET_OFFSET:
921 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)&shiid+UNION_MEMBER(uOffset), -1, b, l);
922 break;
923
924 case STRRET_CSTR:
925 MultiByteToWideChar(CP_ACP, 0, UNION_MEMBER(cStr), -1, b, l);
926 }
927 }
928 };
929
930
931 /// Retrieval of file system paths of ShellPath objects
932 class FileSysShellPath : public ShellPath
933 {
934 TCHAR _fullpath[MAX_PATH];
935
936 protected:
937 FileSysShellPath() {_fullpath[0] = '\0';}
938
939 public:
940 FileSysShellPath(const ShellPath& o) : ShellPath(o) {_fullpath[0] = '\0';}
941
942 operator LPCTSTR() {if (!SHGetPathFromIDList(_p, _fullpath)) return NULL; return _fullpath;}
943 };
944
945
946 /// Browse dialog operating on shell namespace
947 struct FolderBrowser : public FileSysShellPath
948 {
949 FolderBrowser(HWND owner, UINT flags, LPCTSTR title, LPCITEMIDLIST root=0)
950 {
951 _displayname[0] = '\0';
952 _browseinfo.hwndOwner = owner;
953 _browseinfo.pidlRoot = root;
954 _browseinfo.pszDisplayName = _displayname;
955 _browseinfo.lpszTitle = title;
956 _browseinfo.ulFlags = flags;
957 _browseinfo.lpfn = 0;
958 _browseinfo.lParam = 0;
959 _browseinfo.iImage = 0;
960
961 _p = SHBrowseForFolder(&_browseinfo);
962 }
963
964 LPCTSTR GetDisplayName()
965 {
966 return _displayname;
967 }
968
969 bool IsOK()
970 {
971 return _p != 0;
972 }
973
974 private:
975 BROWSEINFO _browseinfo;
976 TCHAR _displayname[MAX_PATH];
977 };
978
979
980 /// Retrieval of special shell folder paths
981 struct SpecialFolderPath : public ShellPath
982 {
983 SpecialFolderPath(int folder, HWND hwnd)
984 {
985 HRESULT hr = SHGetSpecialFolderLocation(hwnd, folder, &_p);
986 CHECKERROR(hr);
987 }
988 };
989
990 /// Shell folder path of the desktop
991 struct DesktopFolderPath : public SpecialFolderPath
992 {
993 DesktopFolderPath()
994 : SpecialFolderPath(CSIDL_DESKTOP, 0)
995 {
996 }
997 };
998
999 /// Retrieval of special shell folder
1000 struct SpecialFolder : public ShellFolder
1001 {
1002 SpecialFolder(int folder, HWND hwnd)
1003 : ShellFolder(GetDesktopFolder(), SpecialFolderPath(folder, hwnd))
1004 {
1005 }
1006 };
1007
1008 /// Shell folder of the desktop
1009 struct DesktopFolder : public ShellFolder
1010 {
1011 };
1012
1013
1014 /// file system path of special folder
1015 struct SpecialFolderFSPath
1016 {
1017 SpecialFolderFSPath(int folder/*e.g. CSIDL_DESKTOP*/, HWND hwnd);
1018
1019 operator LPCTSTR()
1020 {
1021 return _fullpath;
1022 }
1023
1024 protected:
1025 TCHAR _fullpath[MAX_PATH];
1026 };
1027
1028 /*
1029 /// file system path of special folder
1030 struct SpecialFolderFSPath : public FileSysShellPath
1031 {
1032 SpecialFolderFSPath(int folder, HWND hwnd)
1033 {
1034 CONTEXT("SpecialFolderFSPath::SpecialFolderFSPath()");
1035
1036 HRESULT hr = SHGetSpecialFolderLocation(hwnd, folder, &_p);
1037 CHECKERROR(hr);
1038 }
1039 };
1040 */
1041
1042
1043 /// wrapper class for enumerating shell namespace objects
1044
1045 struct ShellItemEnumerator : public SIfacePtr<IEnumIDList>
1046 {
1047 ShellItemEnumerator(IShellFolder* folder, DWORD flags=SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN)
1048 {
1049 CONTEXT("ShellItemEnumerator::ShellItemEnumerator()");
1050
1051 CHECKERROR(folder->EnumObjects(0, flags, &_p));
1052 }
1053 };
1054
1055
1056 /// list of PIDLs
1057 struct PIDList
1058 {
1059 PIDList()
1060 {
1061 memset(&_stgm, 0, sizeof(STGMEDIUM));
1062 }
1063
1064 ~PIDList()
1065 {
1066 if (_stgm.hGlobal) {
1067 GlobalUnlock(_stgm.hGlobal);
1068 ReleaseStgMedium(&_stgm);
1069 }
1070 }
1071
1072 HRESULT GetData(IDataObject* selection)
1073 {
1074 static UINT CF_IDLIST = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
1075
1076 FORMATETC fetc;
1077 fetc.cfFormat = CF_IDLIST;
1078 fetc.ptd = NULL;
1079 fetc.dwAspect = DVASPECT_CONTENT;
1080 fetc.lindex = -1;
1081 fetc.tymed = TYMED_HGLOBAL;
1082
1083 HRESULT hr = selection->QueryGetData(&fetc);
1084 if (FAILED(hr))
1085 return hr;
1086
1087 hr = selection->GetData(&fetc, &_stgm);
1088 if (FAILED(hr))
1089 return hr;
1090
1091 _pIDList = (LPIDA)GlobalLock(_stgm.hGlobal);
1092
1093 return hr;
1094 }
1095
1096 operator LPIDA() {return _pIDList;}
1097
1098 protected:
1099 STGMEDIUM _stgm;
1100 LPIDA _pIDList;
1101 };
1102
1103
1104 struct CtxMenuInterfaces
1105 {
1106 CtxMenuInterfaces()
1107 {
1108 reset();
1109 }
1110
1111 void reset();
1112 bool HandleMenuMsg(UINT nmsg, WPARAM wparam, LPARAM lparam);
1113 IContextMenu* query_interfaces(IContextMenu* pcm1);
1114
1115 IContextMenu2* _pctxmenu2;
1116
1117 #ifndef __MINGW32__ // IContextMenu3 missing in MinGW (as of 6.2.2005)
1118 IContextMenu3* _pctxmenu3;
1119 #endif
1120 };
1121
1122 template<typename BASE> struct ExtContextMenuHandlerT
1123 : public BASE
1124 {
1125 typedef BASE super;
1126
1127 ExtContextMenuHandlerT(HWND hwnd)
1128 : super(hwnd)
1129 {
1130 }
1131
1132 template<typename PARA> ExtContextMenuHandlerT(HWND hwnd, const PARA& info)
1133 : super(hwnd, info)
1134 {
1135 }
1136
1137 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
1138 {
1139 switch(nmsg) {
1140 case WM_DRAWITEM:
1141 case WM_MEASUREITEM:
1142 if (!wparam) // Is the message menu-related?
1143 if (_cm_ifs.HandleMenuMsg(nmsg, wparam, lparam))
1144 return TRUE;
1145
1146 break;
1147
1148 case WM_INITMENUPOPUP:
1149 if (_cm_ifs.HandleMenuMsg(nmsg, wparam, lparam))
1150 return 0;
1151
1152 break;
1153
1154 #ifndef __MINGW32__ // IContextMenu3 missing in MinGW (as of 6.2.2005)
1155 case WM_MENUCHAR: // only supported by IContextMenu3
1156 if (_cm_ifs._pctxmenu3) {
1157 LRESULT lResult = 0;
1158
1159 _cm_ifs._pctxmenu3->HandleMenuMsg2(nmsg, wparam, lparam, &lResult);
1160
1161 return lResult;
1162 }
1163
1164 return 0;
1165 #endif
1166 }
1167
1168 return super::WndProc(nmsg, wparam, lparam);
1169 }
1170
1171 protected:
1172 CtxMenuInterfaces _cm_ifs;
1173 };
1174
1175
1176 extern HRESULT ShellFolderContextMenu(IShellFolder* shell_folder, HWND hwndParent, int cidl,
1177 LPCITEMIDLIST* ppidl, int x, int y, CtxMenuInterfaces& cm_ifs);