|
|
|
/***************************************************************************
|
|
|
|
ShellContextMenu.cpp - description
|
|
|
|
-------------------
|
|
|
|
begin : Sat Mar 4 2006
|
|
|
|
copyright : (C) 2005-2007 by Joachim Eibl
|
|
|
|
email : joachim dot eibl at gmx dot de
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
// ShellContextMenu.cpp: Implementierung der Klasse CShellContextMenu.
|
|
|
|
//
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include <windows.h>
|
|
|
|
#include <shlobj.h>
|
|
|
|
#include <malloc.h>
|
|
|
|
#include <tqstring.h>
|
|
|
|
#include <tqstringlist.h>
|
|
|
|
#include <tqwidget.h>
|
|
|
|
#include <tqdir.h>
|
|
|
|
#include <tqpopupmenu.h>
|
|
|
|
#include "ShellContextMenu.h"
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
#undef THIS_FILE
|
|
|
|
static char THIS_FILE[]=__FILE__;
|
|
|
|
#define new DEBUG_NEW
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Konstruktion/Destruktion
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#define MIN_ID 100
|
|
|
|
#define MAX_ID 10000
|
|
|
|
|
|
|
|
|
|
|
|
void showShellContextMenu( const TQString& itemPath, TQPoint pt, TQWidget* pParentWidget, TQPopupMenu* pMenu )
|
|
|
|
{
|
|
|
|
CShellContextMenu scm;
|
|
|
|
scm.SetObjects(TQDir::convertSeparators(itemPath));
|
|
|
|
int id = scm.ShowContextMenu (pParentWidget, pt, pMenu);
|
|
|
|
if (id>=1)
|
|
|
|
pMenu->activateItemAt(id-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
IContextMenu2 * g_IContext2 = NULL;
|
|
|
|
IContextMenu3 * g_IContext3 = NULL;
|
|
|
|
|
|
|
|
CShellContextMenu::CShellContextMenu()
|
|
|
|
{
|
|
|
|
m_psfFolder = NULL;
|
|
|
|
m_pidlArray = NULL;
|
|
|
|
m_hMenu = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
CShellContextMenu::~CShellContextMenu()
|
|
|
|
{
|
|
|
|
// free all allocated datas
|
|
|
|
if (m_psfFolder && bDelete)
|
|
|
|
m_psfFolder->Release ();
|
|
|
|
m_psfFolder = NULL;
|
|
|
|
FreePIDLArray (m_pidlArray);
|
|
|
|
m_pidlArray = NULL;
|
|
|
|
|
|
|
|
if (m_hMenu)
|
|
|
|
DestroyMenu( m_hMenu );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// this functions determines which version of IContextMenu is avaibale for those objects (always the highest one)
|
|
|
|
// and returns that interface
|
|
|
|
BOOL CShellContextMenu::GetContextMenu (void ** ppContextMenu, int & iMenuType)
|
|
|
|
{
|
|
|
|
*ppContextMenu = NULL;
|
|
|
|
LPCONTEXTMENU icm1 = NULL;
|
|
|
|
|
|
|
|
if ( m_psfFolder==0 )
|
|
|
|
return FALSE;
|
|
|
|
// first we retrieve the normal IContextMenu interface (every object should have it)
|
|
|
|
m_psfFolder->GetUIObjectOf (NULL, nItems, (LPCITEMIDLIST *) m_pidlArray, IID_IContextMenu, NULL, (void**) &icm1);
|
|
|
|
|
|
|
|
if (icm1)
|
|
|
|
{ // since we got an IContextMenu interface we can now obtain the higher version interfaces via that
|
|
|
|
if (icm1->QueryInterface (IID_IContextMenu3, ppContextMenu) == NOERROR)
|
|
|
|
iMenuType = 3;
|
|
|
|
else if (icm1->QueryInterface (IID_IContextMenu2, ppContextMenu) == NOERROR)
|
|
|
|
iMenuType = 2;
|
|
|
|
|
|
|
|
if (*ppContextMenu)
|
|
|
|
icm1->Release(); // we can now release version 1 interface, cause we got a higher one
|
|
|
|
else
|
|
|
|
{
|
|
|
|
iMenuType = 1;
|
|
|
|
*ppContextMenu = icm1; // since no higher versions were found
|
|
|
|
} // redirect ppContextMenu to version 1 interface
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return (FALSE); // something went wrong
|
|
|
|
|
|
|
|
return (TRUE); // success
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LRESULT CALLBACK CShellContextMenu::HookWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
switch (message)
|
|
|
|
{
|
|
|
|
case WM_MENUCHAR: // only supported by IContextMenu3
|
|
|
|
if (g_IContext3)
|
|
|
|
{
|
|
|
|
LRESULT lResult = 0;
|
|
|
|
g_IContext3->HandleMenuMsg2 (message, wParam, lParam, &lResult);
|
|
|
|
return (lResult);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_DRAWITEM:
|
|
|
|
case WM_MEASUREITEM:
|
|
|
|
if (wParam)
|
|
|
|
break; // if wParam != 0 then the message is not menu-related
|
|
|
|
|
|
|
|
case WM_INITMENUPOPUP:
|
|
|
|
if (g_IContext2)
|
|
|
|
g_IContext2->HandleMenuMsg (message, wParam, lParam);
|
|
|
|
else // version 3
|
|
|
|
g_IContext3->HandleMenuMsg (message, wParam, lParam);
|
|
|
|
return (message == WM_INITMENUPOPUP ? 0 : TRUE); // inform caller that we handled WM_INITPOPUPMENU by ourself
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// call original WndProc of window to prevent undefined bevhaviour of window
|
|
|
|
return ::CallWindowProc ((WNDPROC) GetProp ( hWnd, TEXT ("OldWndProc")), hWnd, message, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UINT CShellContextMenu::ShowContextMenu(TQWidget * pParentWidget, TQPoint pt, TQPopupMenu* pMenu )
|
|
|
|
{
|
|
|
|
HWND hWnd = pParentWidget->winId();
|
|
|
|
int iMenuType = 0; // to know which version of IContextMenu is supported
|
|
|
|
LPCONTEXTMENU pContextMenu; // common pointer to IContextMenu and higher version interface
|
|
|
|
|
|
|
|
if (!GetContextMenu ((void**) &pContextMenu, iMenuType))
|
|
|
|
return (0); // something went wrong
|
|
|
|
|
|
|
|
if (!m_hMenu)
|
|
|
|
{
|
|
|
|
DestroyMenu( m_hMenu );
|
|
|
|
m_hMenu = CreatePopupMenu ();
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT_PTR i;
|
|
|
|
for( i=0; i<pMenu->count(); ++i )
|
|
|
|
{
|
|
|
|
TQString s = pMenu->text(pMenu->idAt(i));
|
|
|
|
if (!s.isEmpty())
|
|
|
|
AppendMenuW( m_hMenu, MF_STRING, i+1, (LPCWSTR)s.ucs2() );
|
|
|
|
}
|
|
|
|
AppendMenuW( m_hMenu, MF_SEPARATOR, i+1, L"" );
|
|
|
|
|
|
|
|
// lets fill the our popupmenu
|
|
|
|
pContextMenu->QueryContextMenu (m_hMenu, GetMenuItemCount (m_hMenu), MIN_ID, MAX_ID, CMF_NORMAL | CMF_EXPLORE);
|
|
|
|
|
|
|
|
// subclass window to handle menurelated messages in CShellContextMenu
|
|
|
|
WNDPROC OldWndProc;
|
|
|
|
if (iMenuType > 1) // only subclass if its version 2 or 3
|
|
|
|
{
|
|
|
|
OldWndProc = (WNDPROC) SetWindowLong (hWnd, GWL_WNDPROC, (DWORD) HookWndProc);
|
|
|
|
if (iMenuType == 2)
|
|
|
|
g_IContext2 = (LPCONTEXTMENU2) pContextMenu;
|
|
|
|
else // version 3
|
|
|
|
g_IContext3 = (LPCONTEXTMENU3) pContextMenu;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
OldWndProc = NULL;
|
|
|
|
|
|
|
|
UINT idCommand = TrackPopupMenu (m_hMenu,TPM_RETURNCMD | TPM_LEFTALIGN, pt.x(), pt.y(), 0, pParentWidget->winId(), 0);
|
|
|
|
|
|
|
|
if (OldWndProc) // unsubclass
|
|
|
|
SetWindowLong (hWnd, GWL_WNDPROC, (DWORD) OldWndProc);
|
|
|
|
|
|
|
|
if (idCommand >= MIN_ID && idCommand <= MAX_ID) // see if returned idCommand belongs to shell menu entries
|
|
|
|
{
|
|
|
|
InvokeCommand (pContextMenu, idCommand - MIN_ID); // execute related command
|
|
|
|
idCommand = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
pContextMenu->Release();
|
|
|
|
g_IContext2 = NULL;
|
|
|
|
g_IContext3 = NULL;
|
|
|
|
|
|
|
|
return (idCommand);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CShellContextMenu::InvokeCommand (LPCONTEXTMENU pContextMenu, UINT idCommand)
|
|
|
|
{
|
|
|
|
CMINVOKECOMMANDINFO cmi = {0};
|
|
|
|
cmi.cbSize = sizeof (CMINVOKECOMMANDINFO);
|
|
|
|
cmi.lpVerb = (LPSTR) MAKEINTRESOURCE (idCommand);
|
|
|
|
cmi.nShow = SW_SHOWNORMAL;
|
|
|
|
|
|
|
|
pContextMenu->InvokeCommand (&cmi);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CShellContextMenu::SetObjects(const TQString& strObject)
|
|
|
|
{
|
|
|
|
// only one object is passed
|
|
|
|
TQStringList strArray;
|
|
|
|
strArray << strObject; // create a CStringArray with one element
|
|
|
|
|
|
|
|
SetObjects (strArray); // and pass it to SetObjects (CStringArray &strArray)
|
|
|
|
// for further processing
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CShellContextMenu::SetObjects(const TQStringList &strList)
|
|
|
|
{
|
|
|
|
// free all allocated datas
|
|
|
|
if (m_psfFolder && bDelete)
|
|
|
|
m_psfFolder->Release ();
|
|
|
|
m_psfFolder = NULL;
|
|
|
|
FreePIDLArray (m_pidlArray);
|
|
|
|
m_pidlArray = NULL;
|
|
|
|
|
|
|
|
// get IShellFolder interface of Desktop (root of shell namespace)
|
|
|
|
IShellFolder * psfDesktop = NULL;
|
|
|
|
SHGetDesktopFolder (&psfDesktop); // needed to obtain full qualified pidl
|
|
|
|
|
|
|
|
// ParseDisplayName creates a PIDL from a file system path relative to the IShellFolder interface
|
|
|
|
// but since we use the Desktop as our interface and the Desktop is the namespace root
|
|
|
|
// that means that it's a fully qualified PIDL, which is what we need
|
|
|
|
LPITEMIDLIST pidl = NULL;
|
|
|
|
|
|
|
|
psfDesktop->ParseDisplayName (NULL, 0, (LPOLESTR)strList[0].ucs2(), NULL, &pidl, NULL);
|
|
|
|
|
|
|
|
// now we need the tqparent IShellFolder interface of pidl, and the relative PIDL to that interface
|
|
|
|
LPITEMIDLIST pidlItem = NULL; // relative pidl
|
|
|
|
SHBindToParentEx (pidl, IID_IShellFolder, (void **) &m_psfFolder, NULL);
|
|
|
|
free (pidlItem);
|
|
|
|
// get interface to IMalloc (need to free the PIDLs allocated by the shell functions)
|
|
|
|
LPMALLOC lpMalloc = NULL;
|
|
|
|
SHGetMalloc (&lpMalloc);
|
|
|
|
lpMalloc->Free (pidl);
|
|
|
|
|
|
|
|
// now we have the IShellFolder interface to the tqparent folder specified in the first element in strArray
|
|
|
|
// since we assume that all objects are in the same folder (as it's stated in the MSDN)
|
|
|
|
// we now have the IShellFolder interface to every objects tqparent folder
|
|
|
|
|
|
|
|
IShellFolder * psfFolder = NULL;
|
|
|
|
nItems = strList.size ();
|
|
|
|
for (int i = 0; i < nItems; i++)
|
|
|
|
{
|
|
|
|
pidl=0;
|
|
|
|
psfDesktop->ParseDisplayName (NULL, 0, (LPOLESTR)strList[i].ucs2(), NULL, &pidl, NULL);
|
|
|
|
if (pidl)
|
|
|
|
{
|
|
|
|
m_pidlArray = (LPITEMIDLIST *) realloc (m_pidlArray, (i + 1) * sizeof (LPITEMIDLIST));
|
|
|
|
// get relative pidl via SHBindToParent
|
|
|
|
SHBindToParentEx (pidl, IID_IShellFolder, (void **) &psfFolder, (LPCITEMIDLIST *) &pidlItem);
|
|
|
|
m_pidlArray[i] = CopyPIDL (pidlItem); // copy relative pidl to pidlArray
|
|
|
|
free (pidlItem);
|
|
|
|
lpMalloc->Free (pidl); // free pidl allocated by ParseDisplayName
|
|
|
|
psfFolder->Release ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lpMalloc->Release ();
|
|
|
|
psfDesktop->Release ();
|
|
|
|
|
|
|
|
bDelete = TRUE; // indicates that m_psfFolder should be deleted by CShellContextMenu
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// only one full qualified PIDL has been passed
|
|
|
|
void CShellContextMenu::SetObjects(LPITEMIDLIST /*pidl*/)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
// free all allocated datas
|
|
|
|
if (m_psfFolder && bDelete)
|
|
|
|
m_psfFolder->Release ();
|
|
|
|
m_psfFolder = NULL;
|
|
|
|
FreePIDLArray (m_pidlArray);
|
|
|
|
m_pidlArray = NULL;
|
|
|
|
|
|
|
|
// full qualified PIDL is passed so we need
|
|
|
|
// its tqparent IShellFolder interface and its relative PIDL to that
|
|
|
|
LPITEMIDLIST pidlItem = NULL;
|
|
|
|
SHBindToParent ((LPCITEMIDLIST) pidl, IID_IShellFolder, (void **) &m_psfFolder, (LPCITEMIDLIST *) &pidlItem);
|
|
|
|
|
|
|
|
m_pidlArray = (LPITEMIDLIST *) malloc (sizeof (LPITEMIDLIST)); // allocate ony for one elemnt
|
|
|
|
m_pidlArray[0] = CopyPIDL (pidlItem);
|
|
|
|
|
|
|
|
|
|
|
|
// now free pidlItem via IMalloc interface (but not m_psfFolder, that we need later
|
|
|
|
LPMALLOC lpMalloc = NULL;
|
|
|
|
SHGetMalloc (&lpMalloc);
|
|
|
|
lpMalloc->Free (pidlItem);
|
|
|
|
lpMalloc->Release();
|
|
|
|
|
|
|
|
nItems = 1;
|
|
|
|
bDelete = TRUE; // indicates that m_psfFolder should be deleted by CShellContextMenu
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// IShellFolder interface with a relative pidl has been passed
|
|
|
|
void CShellContextMenu::SetObjects(IShellFolder *psfFolder, LPITEMIDLIST pidlItem)
|
|
|
|
{
|
|
|
|
// free all allocated datas
|
|
|
|
if (m_psfFolder && bDelete)
|
|
|
|
m_psfFolder->Release ();
|
|
|
|
m_psfFolder = NULL;
|
|
|
|
FreePIDLArray (m_pidlArray);
|
|
|
|
m_pidlArray = NULL;
|
|
|
|
|
|
|
|
m_psfFolder = psfFolder;
|
|
|
|
|
|
|
|
m_pidlArray = (LPITEMIDLIST *) malloc (sizeof (LPITEMIDLIST));
|
|
|
|
m_pidlArray[0] = CopyPIDL (pidlItem);
|
|
|
|
|
|
|
|
nItems = 1;
|
|
|
|
bDelete = FALSE; // indicates wheter m_psfFolder should be deleted by CShellContextMenu
|
|
|
|
}
|
|
|
|
|
|
|
|
void CShellContextMenu::SetObjects(IShellFolder * psfFolder, LPITEMIDLIST *pidlArray, int nItemCount)
|
|
|
|
{
|
|
|
|
// free all allocated datas
|
|
|
|
if (m_psfFolder && bDelete)
|
|
|
|
m_psfFolder->Release ();
|
|
|
|
m_psfFolder = NULL;
|
|
|
|
FreePIDLArray (m_pidlArray);
|
|
|
|
m_pidlArray = NULL;
|
|
|
|
|
|
|
|
m_psfFolder = psfFolder;
|
|
|
|
|
|
|
|
m_pidlArray = (LPITEMIDLIST *) malloc (nItemCount * sizeof (LPITEMIDLIST));
|
|
|
|
|
|
|
|
for (int i = 0; i < nItemCount; i++)
|
|
|
|
m_pidlArray[i] = CopyPIDL (pidlArray[i]);
|
|
|
|
|
|
|
|
nItems = nItemCount;
|
|
|
|
bDelete = FALSE; // indicates wheter m_psfFolder should be deleted by CShellContextMenu
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CShellContextMenu::FreePIDLArray(LPITEMIDLIST *pidlArray)
|
|
|
|
{
|
|
|
|
if (!pidlArray)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int iSize = _msize (pidlArray) / sizeof (LPITEMIDLIST);
|
|
|
|
|
|
|
|
for (int i = 0; i < iSize; i++)
|
|
|
|
free (pidlArray[i]);
|
|
|
|
free (pidlArray);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LPITEMIDLIST CShellContextMenu::CopyPIDL (LPCITEMIDLIST pidl, int cb)
|
|
|
|
{
|
|
|
|
if (cb == -1)
|
|
|
|
cb = GetPIDLSize (pidl); // Calculate size of list.
|
|
|
|
|
|
|
|
LPITEMIDLIST pidlRet = (LPITEMIDLIST) calloc (cb + sizeof (USHORT), sizeof (BYTE));
|
|
|
|
if (pidlRet)
|
|
|
|
CopyMemory(pidlRet, pidl, cb);
|
|
|
|
|
|
|
|
return (pidlRet);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UINT CShellContextMenu::GetPIDLSize (LPCITEMIDLIST pidl)
|
|
|
|
{
|
|
|
|
if (!pidl)
|
|
|
|
return 0;
|
|
|
|
int nSize = 0;
|
|
|
|
LPITEMIDLIST pidlTemp = (LPITEMIDLIST) pidl;
|
|
|
|
while (pidlTemp->mkid.cb)
|
|
|
|
{
|
|
|
|
nSize += pidlTemp->mkid.cb;
|
|
|
|
pidlTemp = (LPITEMIDLIST) (((LPBYTE) pidlTemp) + pidlTemp->mkid.cb);
|
|
|
|
}
|
|
|
|
return nSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
HMENU CShellContextMenu::GetMenu()
|
|
|
|
{
|
|
|
|
if (!m_hMenu)
|
|
|
|
{
|
|
|
|
m_hMenu = CreatePopupMenu(); // create the popupmenu (its empty)
|
|
|
|
}
|
|
|
|
return (m_hMenu);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// this is workaround function for the Shell API Function SHBindToParent
|
|
|
|
// SHBindToParent is not available under Win95/98
|
|
|
|
HRESULT CShellContextMenu::SHBindToParentEx (LPCITEMIDLIST pidl, REFIID riid, VOID **ppv, LPCITEMIDLIST *ppidlLast)
|
|
|
|
{
|
|
|
|
HRESULT hr = 0;
|
|
|
|
if (!pidl || !ppv)
|
|
|
|
return E_POINTER;
|
|
|
|
|
|
|
|
int nCount = GetPIDLCount (pidl);
|
|
|
|
if (nCount == 0) // desktop pidl of invalid pidl
|
|
|
|
return E_POINTER;
|
|
|
|
|
|
|
|
IShellFolder * psfDesktop = NULL;
|
|
|
|
SHGetDesktopFolder (&psfDesktop);
|
|
|
|
if (nCount == 1) // desktop pidl
|
|
|
|
{
|
|
|
|
if ((hr = psfDesktop->QueryInterface(riid, ppv)) == S_OK)
|
|
|
|
{
|
|
|
|
if (ppidlLast)
|
|
|
|
*ppidlLast = CopyPIDL (pidl);
|
|
|
|
}
|
|
|
|
psfDesktop->Release ();
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
LPBYTE pRel = GetPIDLPos (pidl, nCount - 1);
|
|
|
|
LPITEMIDLIST pidlParent = NULL;
|
|
|
|
pidlParent = CopyPIDL (pidl, pRel - (LPBYTE) pidl);
|
|
|
|
IShellFolder * psfFolder = NULL;
|
|
|
|
|
|
|
|
if ((hr = psfDesktop->BindToObject (pidlParent, NULL, IID_IShellFolder, (void **) &psfFolder)) != S_OK)
|
|
|
|
{
|
|
|
|
free (pidlParent);
|
|
|
|
psfDesktop->Release ();
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
if ((hr = psfFolder->QueryInterface (riid, ppv)) == S_OK)
|
|
|
|
{
|
|
|
|
if (ppidlLast)
|
|
|
|
*ppidlLast = CopyPIDL ((LPCITEMIDLIST) pRel);
|
|
|
|
}
|
|
|
|
free (pidlParent);
|
|
|
|
psfFolder->Release ();
|
|
|
|
psfDesktop->Release ();
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LPBYTE CShellContextMenu::GetPIDLPos (LPCITEMIDLIST pidl, int nPos)
|
|
|
|
{
|
|
|
|
if (!pidl)
|
|
|
|
return 0;
|
|
|
|
int nCount = 0;
|
|
|
|
|
|
|
|
BYTE * pCur = (BYTE *) pidl;
|
|
|
|
while (((LPCITEMIDLIST) pCur)->mkid.cb)
|
|
|
|
{
|
|
|
|
if (nCount == nPos)
|
|
|
|
return pCur;
|
|
|
|
nCount++;
|
|
|
|
pCur += ((LPCITEMIDLIST) pCur)->mkid.cb; // + sizeof(pidl->mkid.cb);
|
|
|
|
}
|
|
|
|
if (nCount == nPos)
|
|
|
|
return pCur;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CShellContextMenu::GetPIDLCount (LPCITEMIDLIST pidl)
|
|
|
|
{
|
|
|
|
if (!pidl)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
int nCount = 0;
|
|
|
|
BYTE* pCur = (BYTE *) pidl;
|
|
|
|
while (((LPCITEMIDLIST) pCur)->mkid.cb)
|
|
|
|
{
|
|
|
|
nCount++;
|
|
|
|
pCur += ((LPCITEMIDLIST) pCur)->mkid.cb;
|
|
|
|
}
|
|
|
|
return nCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|