joachim99@77
|
1 /***************************************************************************
|
joachim99@77
|
2 ShellContextMenu.cpp - description
|
joachim99@77
|
3 -------------------
|
joachim99@77
|
4 begin : Sat Mar 4 2006
|
joachim99@77
|
5 copyright : (C) 2005-2007 by Joachim Eibl
|
joachim99@77
|
6 email : joachim dot eibl at gmx dot de
|
joachim99@77
|
7 ***************************************************************************/
|
joachim99@77
|
8
|
joachim99@77
|
9 /***************************************************************************
|
joachim99@77
|
10 * *
|
joachim99@77
|
11 * This program is free software; you can redistribute it and/or modify *
|
joachim99@77
|
12 * it under the terms of the GNU General Public License as published by *
|
joachim99@77
|
13 * the Free Software Foundation; either version 2 of the License, or *
|
joachim99@77
|
14 * (at your option) any later version. *
|
joachim99@77
|
15 * *
|
joachim99@77
|
16 ***************************************************************************/
|
joachim99@69
|
17 // ShellContextMenu.cpp: Implementierung der Klasse CShellContextMenu.
|
joachim99@69
|
18 //
|
joachim99@69
|
19 //////////////////////////////////////////////////////////////////////
|
joachim99@69
|
20 #ifdef _WIN32
|
joachim99@69
|
21 #include <windows.h>
|
joachim99@69
|
22 #include <shlobj.h>
|
joachim99@69
|
23 #include <malloc.h>
|
joachim99@69
|
24 #include <qstring.h>
|
joachim99@69
|
25 #include <qstringlist.h>
|
joachim99@69
|
26 #include <qwidget.h>
|
joachim99@69
|
27 #include <qdir.h>
|
joachim99@70
|
28 #include <QMenu>
|
joachim99@69
|
29 #include "ShellContextMenu.h"
|
joachim99@69
|
30
|
joachim99@69
|
31 #ifdef _DEBUG
|
joachim99@69
|
32 #undef THIS_FILE
|
joachim99@69
|
33 static char THIS_FILE[]=__FILE__;
|
joachim99@69
|
34 #define new DEBUG_NEW
|
joachim99@69
|
35 #endif
|
joachim99@69
|
36
|
joachim99@69
|
37 //////////////////////////////////////////////////////////////////////
|
joachim99@69
|
38 // Konstruktion/Destruktion
|
joachim99@69
|
39 //////////////////////////////////////////////////////////////////////
|
joachim99@69
|
40
|
joachim99@69
|
41 #define MIN_ID 100
|
joachim99@69
|
42 #define MAX_ID 10000
|
joachim99@69
|
43
|
joachim99@69
|
44
|
joachim99@70
|
45 void showShellContextMenu( const QString& itemPath, QPoint pt, QWidget* pParentWidget, QMenu* pMenu )
|
joachim99@69
|
46 {
|
joachim99@69
|
47 CShellContextMenu scm;
|
joachim99@77
|
48 scm.SetObjects(QDir::toNativeSeparators(QDir::cleanPath(itemPath)));
|
joachim99@69
|
49 int id = scm.ShowContextMenu (pParentWidget, pt, pMenu);
|
joachim99@69
|
50 if (id>=1)
|
joachim99@75
|
51 pMenu->actions().value(id-1)->trigger();
|
joachim99@69
|
52 }
|
joachim99@69
|
53
|
joachim99@69
|
54 IContextMenu2 * g_IContext2 = NULL;
|
joachim99@69
|
55 IContextMenu3 * g_IContext3 = NULL;
|
joachim99@69
|
56
|
joachim99@69
|
57 CShellContextMenu::CShellContextMenu()
|
joachim99@69
|
58 {
|
joachim99@69
|
59 m_psfFolder = NULL;
|
joachim99@69
|
60 m_pidlArray = NULL;
|
joachim99@69
|
61 m_hMenu = NULL;
|
joachim99@69
|
62 }
|
joachim99@69
|
63
|
joachim99@69
|
64 CShellContextMenu::~CShellContextMenu()
|
joachim99@69
|
65 {
|
joachim99@69
|
66 // free all allocated datas
|
joachim99@69
|
67 if (m_psfFolder && bDelete)
|
joachim99@69
|
68 m_psfFolder->Release ();
|
joachim99@69
|
69 m_psfFolder = NULL;
|
joachim99@69
|
70 FreePIDLArray (m_pidlArray);
|
joachim99@69
|
71 m_pidlArray = NULL;
|
joachim99@69
|
72
|
joachim99@69
|
73 if (m_hMenu)
|
joachim99@69
|
74 DestroyMenu( m_hMenu );
|
joachim99@69
|
75 }
|
joachim99@69
|
76
|
joachim99@69
|
77
|
joachim99@69
|
78
|
joachim99@69
|
79 // this functions determines which version of IContextMenu is avaibale for those objects (always the highest one)
|
joachim99@69
|
80 // and returns that interface
|
joachim99@69
|
81 BOOL CShellContextMenu::GetContextMenu (void ** ppContextMenu, int & iMenuType)
|
joachim99@69
|
82 {
|
joachim99@69
|
83 *ppContextMenu = NULL;
|
joachim99@69
|
84 LPCONTEXTMENU icm1 = NULL;
|
joachim99@77
|
85
|
joachim99@77
|
86 if ( m_psfFolder==0 )
|
joachim99@77
|
87 return FALSE;
|
joachim99@69
|
88
|
joachim99@69
|
89 // first we retrieve the normal IContextMenu interface (every object should have it)
|
joachim99@69
|
90 m_psfFolder->GetUIObjectOf (NULL, nItems, (LPCITEMIDLIST *) m_pidlArray, IID_IContextMenu, NULL, (void**) &icm1);
|
joachim99@69
|
91
|
joachim99@69
|
92 if (icm1)
|
joachim99@69
|
93 { // since we got an IContextMenu interface we can now obtain the higher version interfaces via that
|
joachim99@69
|
94 if (icm1->QueryInterface (IID_IContextMenu3, ppContextMenu) == NOERROR)
|
joachim99@69
|
95 iMenuType = 3;
|
joachim99@69
|
96 else if (icm1->QueryInterface (IID_IContextMenu2, ppContextMenu) == NOERROR)
|
joachim99@69
|
97 iMenuType = 2;
|
joachim99@69
|
98
|
joachim99@69
|
99 if (*ppContextMenu)
|
joachim99@69
|
100 icm1->Release(); // we can now release version 1 interface, cause we got a higher one
|
joachim99@69
|
101 else
|
joachim99@69
|
102 {
|
joachim99@69
|
103 iMenuType = 1;
|
joachim99@69
|
104 *ppContextMenu = icm1; // since no higher versions were found
|
joachim99@69
|
105 } // redirect ppContextMenu to version 1 interface
|
joachim99@69
|
106 }
|
joachim99@69
|
107 else
|
joachim99@69
|
108 return (FALSE); // something went wrong
|
joachim99@69
|
109
|
joachim99@69
|
110 return (TRUE); // success
|
joachim99@69
|
111 }
|
joachim99@69
|
112
|
joachim99@69
|
113
|
joachim99@69
|
114 LRESULT CALLBACK CShellContextMenu::HookWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
joachim99@69
|
115 {
|
joachim99@69
|
116 switch (message)
|
joachim99@69
|
117 {
|
joachim99@69
|
118 case WM_MENUCHAR: // only supported by IContextMenu3
|
joachim99@69
|
119 if (g_IContext3)
|
joachim99@69
|
120 {
|
joachim99@69
|
121 LRESULT lResult = 0;
|
joachim99@69
|
122 g_IContext3->HandleMenuMsg2 (message, wParam, lParam, &lResult);
|
joachim99@69
|
123 return (lResult);
|
joachim99@69
|
124 }
|
joachim99@69
|
125 break;
|
joachim99@69
|
126
|
joachim99@69
|
127 case WM_DRAWITEM:
|
joachim99@69
|
128 case WM_MEASUREITEM:
|
joachim99@69
|
129 if (wParam)
|
joachim99@69
|
130 break; // if wParam != 0 then the message is not menu-related
|
joachim99@69
|
131
|
joachim99@69
|
132 case WM_INITMENUPOPUP:
|
joachim99@69
|
133 if (g_IContext2)
|
joachim99@69
|
134 g_IContext2->HandleMenuMsg (message, wParam, lParam);
|
joachim99@69
|
135 else // version 3
|
joachim99@69
|
136 g_IContext3->HandleMenuMsg (message, wParam, lParam);
|
joachim99@69
|
137 return (message == WM_INITMENUPOPUP ? 0 : TRUE); // inform caller that we handled WM_INITPOPUPMENU by ourself
|
joachim99@69
|
138 break;
|
joachim99@69
|
139
|
joachim99@69
|
140 default:
|
joachim99@69
|
141 break;
|
joachim99@69
|
142 }
|
joachim99@69
|
143
|
joachim99@69
|
144 // call original WndProc of window to prevent undefined bevhaviour of window
|
joachim99@69
|
145 return ::CallWindowProc ((WNDPROC) GetProp ( hWnd, TEXT ("OldWndProc")), hWnd, message, wParam, lParam);
|
joachim99@69
|
146 }
|
joachim99@69
|
147
|
joachim99@69
|
148
|
joachim99@70
|
149 UINT CShellContextMenu::ShowContextMenu(QWidget * pParentWidget, QPoint pt, QMenu* pMenu )
|
joachim99@69
|
150 {
|
joachim99@69
|
151 HWND hWnd = pParentWidget->winId();
|
joachim99@69
|
152 int iMenuType = 0; // to know which version of IContextMenu is supported
|
joachim99@69
|
153 LPCONTEXTMENU pContextMenu; // common pointer to IContextMenu and higher version interface
|
joachim99@69
|
154
|
joachim99@69
|
155 if (!GetContextMenu ((void**) &pContextMenu, iMenuType))
|
joachim99@69
|
156 return (0); // something went wrong
|
joachim99@69
|
157
|
joachim99@69
|
158 if (!m_hMenu)
|
joachim99@69
|
159 {
|
joachim99@69
|
160 DestroyMenu( m_hMenu );
|
joachim99@69
|
161 m_hMenu = CreatePopupMenu ();
|
joachim99@69
|
162 }
|
joachim99@69
|
163
|
joachim99@75
|
164 int i;
|
joachim99@75
|
165 QList<QAction*> actionList = pMenu->actions();
|
joachim99@75
|
166 for( i=0; i<actionList.count(); ++i )
|
joachim99@69
|
167 {
|
joachim99@75
|
168 QString s = actionList.at(i)->text();
|
joachim99@69
|
169 if (!s.isEmpty())
|
joachim99@75
|
170 AppendMenuW( m_hMenu, MF_STRING, i+1, (LPCWSTR)s.utf16() );
|
joachim99@69
|
171 }
|
joachim99@69
|
172 AppendMenuW( m_hMenu, MF_SEPARATOR, i+1, L"" );
|
joachim99@69
|
173
|
joachim99@69
|
174 // lets fill the our popupmenu
|
joachim99@69
|
175 pContextMenu->QueryContextMenu (m_hMenu, GetMenuItemCount (m_hMenu), MIN_ID, MAX_ID, CMF_NORMAL | CMF_EXPLORE);
|
joachim99@69
|
176
|
joachim99@69
|
177 // subclass window to handle menurelated messages in CShellContextMenu
|
joachim99@69
|
178 WNDPROC OldWndProc;
|
joachim99@69
|
179 if (iMenuType > 1) // only subclass if its version 2 or 3
|
joachim99@69
|
180 {
|
joachim99@69
|
181 OldWndProc = (WNDPROC) SetWindowLong (hWnd, GWL_WNDPROC, (DWORD) HookWndProc);
|
joachim99@69
|
182 if (iMenuType == 2)
|
joachim99@69
|
183 g_IContext2 = (LPCONTEXTMENU2) pContextMenu;
|
joachim99@69
|
184 else // version 3
|
joachim99@69
|
185 g_IContext3 = (LPCONTEXTMENU3) pContextMenu;
|
joachim99@69
|
186 }
|
joachim99@69
|
187 else
|
joachim99@69
|
188 OldWndProc = NULL;
|
joachim99@69
|
189
|
joachim99@69
|
190 UINT idCommand = TrackPopupMenu (m_hMenu,TPM_RETURNCMD | TPM_LEFTALIGN, pt.x(), pt.y(), 0, pParentWidget->winId(), 0);
|
joachim99@69
|
191
|
joachim99@69
|
192 if (OldWndProc) // unsubclass
|
joachim99@69
|
193 SetWindowLong (hWnd, GWL_WNDPROC, (DWORD) OldWndProc);
|
joachim99@69
|
194
|
joachim99@69
|
195 if (idCommand >= MIN_ID && idCommand <= MAX_ID) // see if returned idCommand belongs to shell menu entries
|
joachim99@69
|
196 {
|
joachim99@69
|
197 InvokeCommand (pContextMenu, idCommand - MIN_ID); // execute related command
|
joachim99@69
|
198 idCommand = 0;
|
joachim99@69
|
199 }
|
joachim99@69
|
200
|
joachim99@69
|
201 pContextMenu->Release();
|
joachim99@69
|
202 g_IContext2 = NULL;
|
joachim99@69
|
203 g_IContext3 = NULL;
|
joachim99@69
|
204
|
joachim99@69
|
205 return (idCommand);
|
joachim99@69
|
206 }
|
joachim99@69
|
207
|
joachim99@69
|
208
|
joachim99@69
|
209 void CShellContextMenu::InvokeCommand (LPCONTEXTMENU pContextMenu, UINT idCommand)
|
joachim99@69
|
210 {
|
joachim99@69
|
211 CMINVOKECOMMANDINFO cmi = {0};
|
joachim99@69
|
212 cmi.cbSize = sizeof (CMINVOKECOMMANDINFO);
|
joachim99@69
|
213 cmi.lpVerb = (LPSTR) MAKEINTRESOURCE (idCommand);
|
joachim99@69
|
214 cmi.nShow = SW_SHOWNORMAL;
|
joachim99@69
|
215
|
joachim99@69
|
216 pContextMenu->InvokeCommand (&cmi);
|
joachim99@69
|
217 }
|
joachim99@69
|
218
|
joachim99@69
|
219
|
joachim99@69
|
220 void CShellContextMenu::SetObjects(const QString& strObject)
|
joachim99@69
|
221 {
|
joachim99@69
|
222 // only one object is passed
|
joachim99@69
|
223 QStringList strArray;
|
joachim99@69
|
224 strArray << strObject; // create a CStringArray with one element
|
joachim99@69
|
225
|
joachim99@69
|
226 SetObjects (strArray); // and pass it to SetObjects (CStringArray &strArray)
|
joachim99@69
|
227 // for further processing
|
joachim99@69
|
228 }
|
joachim99@69
|
229
|
joachim99@69
|
230
|
joachim99@69
|
231 void CShellContextMenu::SetObjects(const QStringList &strList)
|
joachim99@69
|
232 {
|
joachim99@69
|
233 // free all allocated datas
|
joachim99@69
|
234 if (m_psfFolder && bDelete)
|
joachim99@69
|
235 m_psfFolder->Release ();
|
joachim99@69
|
236 m_psfFolder = NULL;
|
joachim99@69
|
237 FreePIDLArray (m_pidlArray);
|
joachim99@69
|
238 m_pidlArray = NULL;
|
joachim99@69
|
239
|
joachim99@69
|
240 // get IShellFolder interface of Desktop (root of shell namespace)
|
joachim99@69
|
241 IShellFolder * psfDesktop = NULL;
|
joachim99@69
|
242 SHGetDesktopFolder (&psfDesktop); // needed to obtain full qualified pidl
|
joachim99@69
|
243
|
joachim99@69
|
244 // ParseDisplayName creates a PIDL from a file system path relative to the IShellFolder interface
|
joachim99@69
|
245 // but since we use the Desktop as our interface and the Desktop is the namespace root
|
joachim99@69
|
246 // that means that it's a fully qualified PIDL, which is what we need
|
joachim99@69
|
247 LPITEMIDLIST pidl = NULL;
|
joachim99@69
|
248
|
joachim99@75
|
249 psfDesktop->ParseDisplayName (NULL, 0, (LPOLESTR)strList[0].utf16(), NULL, &pidl, NULL);
|
joachim99@69
|
250
|
joachim99@69
|
251 // now we need the parent IShellFolder interface of pidl, and the relative PIDL to that interface
|
joachim99@69
|
252 LPITEMIDLIST pidlItem = NULL; // relative pidl
|
joachim99@69
|
253 SHBindToParentEx (pidl, IID_IShellFolder, (void **) &m_psfFolder, NULL);
|
joachim99@69
|
254 free (pidlItem);
|
joachim99@69
|
255 // get interface to IMalloc (need to free the PIDLs allocated by the shell functions)
|
joachim99@69
|
256 LPMALLOC lpMalloc = NULL;
|
joachim99@69
|
257 SHGetMalloc (&lpMalloc);
|
joachim99@69
|
258 lpMalloc->Free (pidl);
|
joachim99@69
|
259
|
joachim99@69
|
260 // now we have the IShellFolder interface to the parent folder specified in the first element in strArray
|
joachim99@69
|
261 // since we assume that all objects are in the same folder (as it's stated in the MSDN)
|
joachim99@69
|
262 // we now have the IShellFolder interface to every objects parent folder
|
joachim99@69
|
263
|
joachim99@69
|
264 IShellFolder * psfFolder = NULL;
|
joachim99@69
|
265 nItems = strList.size ();
|
joachim99@69
|
266 for (int i = 0; i < nItems; i++)
|
joachim99@69
|
267 {
|
joachim99@69
|
268 pidl=0;
|
joachim99@75
|
269 psfDesktop->ParseDisplayName (NULL, 0, (LPOLESTR)strList[i].utf16(), NULL, &pidl, NULL);
|
joachim99@69
|
270 if (pidl)
|
joachim99@69
|
271 {
|
joachim99@69
|
272 m_pidlArray = (LPITEMIDLIST *) realloc (m_pidlArray, (i + 1) * sizeof (LPITEMIDLIST));
|
joachim99@69
|
273 // get relative pidl via SHBindToParent
|
joachim99@69
|
274 SHBindToParentEx (pidl, IID_IShellFolder, (void **) &psfFolder, (LPCITEMIDLIST *) &pidlItem);
|
joachim99@69
|
275 m_pidlArray[i] = CopyPIDL (pidlItem); // copy relative pidl to pidlArray
|
joachim99@69
|
276 free (pidlItem);
|
joachim99@69
|
277 lpMalloc->Free (pidl); // free pidl allocated by ParseDisplayName
|
joachim99@69
|
278 psfFolder->Release ();
|
joachim99@69
|
279 }
|
joachim99@69
|
280 }
|
joachim99@69
|
281 lpMalloc->Release ();
|
joachim99@69
|
282 psfDesktop->Release ();
|
joachim99@69
|
283
|
joachim99@69
|
284 bDelete = TRUE; // indicates that m_psfFolder should be deleted by CShellContextMenu
|
joachim99@69
|
285 }
|
joachim99@69
|
286
|
joachim99@69
|
287
|
joachim99@69
|
288 // only one full qualified PIDL has been passed
|
joachim99@69
|
289 void CShellContextMenu::SetObjects(LPITEMIDLIST /*pidl*/)
|
joachim99@69
|
290 {
|
joachim99@69
|
291 /*
|
joachim99@69
|
292 // free all allocated datas
|
joachim99@69
|
293 if (m_psfFolder && bDelete)
|
joachim99@69
|
294 m_psfFolder->Release ();
|
joachim99@69
|
295 m_psfFolder = NULL;
|
joachim99@69
|
296 FreePIDLArray (m_pidlArray);
|
joachim99@69
|
297 m_pidlArray = NULL;
|
joachim99@69
|
298
|
joachim99@69
|
299 // full qualified PIDL is passed so we need
|
joachim99@69
|
300 // its parent IShellFolder interface and its relative PIDL to that
|
joachim99@69
|
301 LPITEMIDLIST pidlItem = NULL;
|
joachim99@69
|
302 SHBindToParent ((LPCITEMIDLIST) pidl, IID_IShellFolder, (void **) &m_psfFolder, (LPCITEMIDLIST *) &pidlItem);
|
joachim99@69
|
303
|
joachim99@69
|
304 m_pidlArray = (LPITEMIDLIST *) malloc (sizeof (LPITEMIDLIST)); // allocate ony for one elemnt
|
joachim99@69
|
305 m_pidlArray[0] = CopyPIDL (pidlItem);
|
joachim99@69
|
306
|
joachim99@69
|
307
|
joachim99@69
|
308 // now free pidlItem via IMalloc interface (but not m_psfFolder, that we need later
|
joachim99@69
|
309 LPMALLOC lpMalloc = NULL;
|
joachim99@69
|
310 SHGetMalloc (&lpMalloc);
|
joachim99@69
|
311 lpMalloc->Free (pidlItem);
|
joachim99@69
|
312 lpMalloc->Release();
|
joachim99@69
|
313
|
joachim99@69
|
314 nItems = 1;
|
joachim99@69
|
315 bDelete = TRUE; // indicates that m_psfFolder should be deleted by CShellContextMenu
|
joachim99@69
|
316 */
|
joachim99@69
|
317 }
|
joachim99@69
|
318
|
joachim99@69
|
319
|
joachim99@69
|
320 // IShellFolder interface with a relative pidl has been passed
|
joachim99@69
|
321 void CShellContextMenu::SetObjects(IShellFolder *psfFolder, LPITEMIDLIST pidlItem)
|
joachim99@69
|
322 {
|
joachim99@69
|
323 // free all allocated datas
|
joachim99@69
|
324 if (m_psfFolder && bDelete)
|
joachim99@69
|
325 m_psfFolder->Release ();
|
joachim99@69
|
326 m_psfFolder = NULL;
|
joachim99@69
|
327 FreePIDLArray (m_pidlArray);
|
joachim99@69
|
328 m_pidlArray = NULL;
|
joachim99@69
|
329
|
joachim99@69
|
330 m_psfFolder = psfFolder;
|
joachim99@69
|
331
|
joachim99@69
|
332 m_pidlArray = (LPITEMIDLIST *) malloc (sizeof (LPITEMIDLIST));
|
joachim99@69
|
333 m_pidlArray[0] = CopyPIDL (pidlItem);
|
joachim99@69
|
334
|
joachim99@69
|
335 nItems = 1;
|
joachim99@69
|
336 bDelete = FALSE; // indicates wheter m_psfFolder should be deleted by CShellContextMenu
|
joachim99@69
|
337 }
|
joachim99@69
|
338
|
joachim99@69
|
339 void CShellContextMenu::SetObjects(IShellFolder * psfFolder, LPITEMIDLIST *pidlArray, int nItemCount)
|
joachim99@69
|
340 {
|
joachim99@69
|
341 // free all allocated datas
|
joachim99@69
|
342 if (m_psfFolder && bDelete)
|
joachim99@69
|
343 m_psfFolder->Release ();
|
joachim99@69
|
344 m_psfFolder = NULL;
|
joachim99@69
|
345 FreePIDLArray (m_pidlArray);
|
joachim99@69
|
346 m_pidlArray = NULL;
|
joachim99@69
|
347
|
joachim99@69
|
348 m_psfFolder = psfFolder;
|
joachim99@69
|
349
|
joachim99@69
|
350 m_pidlArray = (LPITEMIDLIST *) malloc (nItemCount * sizeof (LPITEMIDLIST));
|
joachim99@69
|
351
|
joachim99@69
|
352 for (int i = 0; i < nItemCount; i++)
|
joachim99@69
|
353 m_pidlArray[i] = CopyPIDL (pidlArray[i]);
|
joachim99@69
|
354
|
joachim99@69
|
355 nItems = nItemCount;
|
joachim99@69
|
356 bDelete = FALSE; // indicates wheter m_psfFolder should be deleted by CShellContextMenu
|
joachim99@69
|
357 }
|
joachim99@69
|
358
|
joachim99@69
|
359
|
joachim99@69
|
360 void CShellContextMenu::FreePIDLArray(LPITEMIDLIST *pidlArray)
|
joachim99@69
|
361 {
|
joachim99@69
|
362 if (!pidlArray)
|
joachim99@69
|
363 return;
|
joachim99@69
|
364
|
joachim99@69
|
365 int iSize = _msize (pidlArray) / sizeof (LPITEMIDLIST);
|
joachim99@69
|
366
|
joachim99@69
|
367 for (int i = 0; i < iSize; i++)
|
joachim99@69
|
368 free (pidlArray[i]);
|
joachim99@69
|
369 free (pidlArray);
|
joachim99@69
|
370 }
|
joachim99@69
|
371
|
joachim99@69
|
372
|
joachim99@69
|
373 LPITEMIDLIST CShellContextMenu::CopyPIDL (LPCITEMIDLIST pidl, int cb)
|
joachim99@69
|
374 {
|
joachim99@69
|
375 if (cb == -1)
|
joachim99@69
|
376 cb = GetPIDLSize (pidl); // Calculate size of list.
|
joachim99@69
|
377
|
joachim99@69
|
378 LPITEMIDLIST pidlRet = (LPITEMIDLIST) calloc (cb + sizeof (USHORT), sizeof (BYTE));
|
joachim99@69
|
379 if (pidlRet)
|
joachim99@69
|
380 CopyMemory(pidlRet, pidl, cb);
|
joachim99@69
|
381
|
joachim99@69
|
382 return (pidlRet);
|
joachim99@69
|
383 }
|
joachim99@69
|
384
|
joachim99@69
|
385
|
joachim99@69
|
386 UINT CShellContextMenu::GetPIDLSize (LPCITEMIDLIST pidl)
|
joachim99@69
|
387 {
|
joachim99@69
|
388 if (!pidl)
|
joachim99@69
|
389 return 0;
|
joachim99@69
|
390 int nSize = 0;
|
joachim99@69
|
391 LPITEMIDLIST pidlTemp = (LPITEMIDLIST) pidl;
|
joachim99@69
|
392 while (pidlTemp->mkid.cb)
|
joachim99@69
|
393 {
|
joachim99@69
|
394 nSize += pidlTemp->mkid.cb;
|
joachim99@69
|
395 pidlTemp = (LPITEMIDLIST) (((LPBYTE) pidlTemp) + pidlTemp->mkid.cb);
|
joachim99@69
|
396 }
|
joachim99@69
|
397 return nSize;
|
joachim99@69
|
398 }
|
joachim99@69
|
399
|
joachim99@69
|
400 HMENU CShellContextMenu::GetMenu()
|
joachim99@69
|
401 {
|
joachim99@69
|
402 if (!m_hMenu)
|
joachim99@69
|
403 {
|
joachim99@69
|
404 m_hMenu = CreatePopupMenu(); // create the popupmenu (its empty)
|
joachim99@69
|
405 }
|
joachim99@69
|
406 return (m_hMenu);
|
joachim99@69
|
407 }
|
joachim99@69
|
408
|
joachim99@69
|
409
|
joachim99@69
|
410 // this is workaround function for the Shell API Function SHBindToParent
|
joachim99@69
|
411 // SHBindToParent is not available under Win95/98
|
joachim99@69
|
412 HRESULT CShellContextMenu::SHBindToParentEx (LPCITEMIDLIST pidl, REFIID riid, VOID **ppv, LPCITEMIDLIST *ppidlLast)
|
joachim99@69
|
413 {
|
joachim99@69
|
414 HRESULT hr = 0;
|
joachim99@69
|
415 if (!pidl || !ppv)
|
joachim99@69
|
416 return E_POINTER;
|
joachim99@69
|
417
|
joachim99@69
|
418 int nCount = GetPIDLCount (pidl);
|
joachim99@69
|
419 if (nCount == 0) // desktop pidl of invalid pidl
|
joachim99@69
|
420 return E_POINTER;
|
joachim99@69
|
421
|
joachim99@69
|
422 IShellFolder * psfDesktop = NULL;
|
joachim99@69
|
423 SHGetDesktopFolder (&psfDesktop);
|
joachim99@69
|
424 if (nCount == 1) // desktop pidl
|
joachim99@69
|
425 {
|
joachim99@69
|
426 if ((hr = psfDesktop->QueryInterface(riid, ppv)) == S_OK)
|
joachim99@69
|
427 {
|
joachim99@69
|
428 if (ppidlLast)
|
joachim99@69
|
429 *ppidlLast = CopyPIDL (pidl);
|
joachim99@69
|
430 }
|
joachim99@69
|
431 psfDesktop->Release ();
|
joachim99@69
|
432 return hr;
|
joachim99@69
|
433 }
|
joachim99@69
|
434
|
joachim99@69
|
435 LPBYTE pRel = GetPIDLPos (pidl, nCount - 1);
|
joachim99@69
|
436 LPITEMIDLIST pidlParent = NULL;
|
joachim99@69
|
437 pidlParent = CopyPIDL (pidl, pRel - (LPBYTE) pidl);
|
joachim99@69
|
438 IShellFolder * psfFolder = NULL;
|
joachim99@69
|
439
|
joachim99@69
|
440 if ((hr = psfDesktop->BindToObject (pidlParent, NULL, IID_IShellFolder, (void **) &psfFolder)) != S_OK)
|
joachim99@69
|
441 {
|
joachim99@69
|
442 free (pidlParent);
|
joachim99@69
|
443 psfDesktop->Release ();
|
joachim99@69
|
444 return hr;
|
joachim99@69
|
445 }
|
joachim99@69
|
446 if ((hr = psfFolder->QueryInterface (riid, ppv)) == S_OK)
|
joachim99@69
|
447 {
|
joachim99@69
|
448 if (ppidlLast)
|
joachim99@69
|
449 *ppidlLast = CopyPIDL ((LPCITEMIDLIST) pRel);
|
joachim99@69
|
450 }
|
joachim99@69
|
451 free (pidlParent);
|
joachim99@69
|
452 psfFolder->Release ();
|
joachim99@69
|
453 psfDesktop->Release ();
|
joachim99@69
|
454 return hr;
|
joachim99@69
|
455 }
|
joachim99@69
|
456
|
joachim99@69
|
457
|
joachim99@69
|
458 LPBYTE CShellContextMenu::GetPIDLPos (LPCITEMIDLIST pidl, int nPos)
|
joachim99@69
|
459 {
|
joachim99@69
|
460 if (!pidl)
|
joachim99@69
|
461 return 0;
|
joachim99@69
|
462 int nCount = 0;
|
joachim99@69
|
463
|
joachim99@69
|
464 BYTE * pCur = (BYTE *) pidl;
|
joachim99@69
|
465 while (((LPCITEMIDLIST) pCur)->mkid.cb)
|
joachim99@69
|
466 {
|
joachim99@69
|
467 if (nCount == nPos)
|
joachim99@69
|
468 return pCur;
|
joachim99@69
|
469 nCount++;
|
joachim99@69
|
470 pCur += ((LPCITEMIDLIST) pCur)->mkid.cb; // + sizeof(pidl->mkid.cb);
|
joachim99@69
|
471 }
|
joachim99@69
|
472 if (nCount == nPos)
|
joachim99@69
|
473 return pCur;
|
joachim99@69
|
474 return NULL;
|
joachim99@69
|
475 }
|
joachim99@69
|
476
|
joachim99@69
|
477
|
joachim99@69
|
478 int CShellContextMenu::GetPIDLCount (LPCITEMIDLIST pidl)
|
joachim99@69
|
479 {
|
joachim99@69
|
480 if (!pidl)
|
joachim99@69
|
481 return 0;
|
joachim99@69
|
482
|
joachim99@69
|
483 int nCount = 0;
|
joachim99@69
|
484 BYTE* pCur = (BYTE *) pidl;
|
joachim99@69
|
485 while (((LPCITEMIDLIST) pCur)->mkid.cb)
|
joachim99@69
|
486 {
|
joachim99@69
|
487 nCount++;
|
joachim99@69
|
488 pCur += ((LPCITEMIDLIST) pCur)->mkid.cb;
|
joachim99@69
|
489 }
|
joachim99@69
|
490 return nCount;
|
joachim99@69
|
491 }
|
joachim99@69
|
492
|
joachim99@69
|
493 #endif
|
joachim99@69
|
494
|