CONTMENU.CPP

/************************************************************************** 
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Copyright 1997 Microsoft Corporation. All Rights Reserved.
**************************************************************************/

/**************************************************************************

File: ContMenu.cpp

Description: CContextMenu implementation.

**************************************************************************/

/**************************************************************************
#include statements
**************************************************************************/

#include "ContMenu.h"

/**************************************************************************
global variables
**************************************************************************/

/**************************************************************************

CContextMenu::CContextMenu()

**************************************************************************/

CContextMenu::CContextMenu(CShellFolder *pSFParent, LPCITEMIDLIST *aPidls, UINT uItemCount)
{
m_pSFParent = pSFParent;
if(m_pSFParent)
m_pSFParent->AddRef();

m_ObjRefCount = 1;
g_DllRefCount++;

m_aPidls = NULL;
SHGetMalloc(&m_pMalloc);
if(!m_pMalloc)
{
delete this;
return;
}

m_pPidlMgr = new CPidlMgr();

AllocPidlTable(uItemCount);
if(m_aPidls)
{
FillPidlTable(aPidls, uItemCount);
}

m_fAllValues = 1;
UINT u;
for(u = 0; u < uItemCount; u++)
{
m_fAllValues &= (m_pPidlMgr->IsValue(aPidls[u]) ? 1 : 0);
}
}

/**************************************************************************

CContextMenu::~CContextMenu()

**************************************************************************/

CContextMenu::~CContextMenu()
{
if(m_pSFParent)
m_pSFParent->Release();

g_DllRefCount--;

//make sure the pidl is freed
if(m_aPidls && m_pMalloc)
{
FreePidlTable();
}

if(m_pPidlMgr)
delete m_pPidlMgr;

if(m_pMalloc)
m_pMalloc->Release();
}

///////////////////////////////////////////////////////////////////////////
//
// IUnknown Implementation
//

/**************************************************************************

CContextMenu::QueryInterface

**************************************************************************/

STDMETHODIMP CContextMenu::QueryInterface( REFIID riid,
LPVOID FAR * ppReturn)
{
if(IsEqualIID(riid, IID_IUnknown))
{
*ppReturn = (LPUNKNOWN)(LPCONTEXTMENU)this;
m_ObjRefCount++;
return ResultFromScode(S_OK);
}

if(IsEqualIID(riid, IID_IContextMenu))
{
*ppReturn = (LPCONTEXTMENU)this;
m_ObjRefCount++;
return ResultFromScode(S_OK);
}

if(IsEqualIID(riid, IID_IShellExtInit))
{
*ppReturn = (LPSHELLEXTINIT)this;
m_ObjRefCount++;
return ResultFromScode(S_OK);
}

*ppReturn = NULL;
return ResultFromScode(E_NOINTERFACE);
}

/**************************************************************************

CContextMenu::AddRef

**************************************************************************/

STDMETHODIMP_(DWORD) CContextMenu::AddRef()
{
return ++m_ObjRefCount;
}


/**************************************************************************

CContextMenu::Release

**************************************************************************/

STDMETHODIMP_(DWORD) CContextMenu::Release()
{
if(--m_ObjRefCount == 0)
delete this;

return m_ObjRefCount;
}

///////////////////////////////////////////////////////////////////////////
//
// IContextMenu Implementation
//

/**************************************************************************

CContextMenu::QueryContextMenu()

**************************************************************************/

STDMETHODIMP CContextMenu::QueryContextMenu( HMENU hMenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags)
{
if(!(CMF_DEFAULTONLY & uFlags))
{
MENUITEMINFO mii;

if(!m_fAllValues)
{
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
mii.wID = idCmdFirst + IDM_EXPLORE;
mii.fType = MFT_STRING;
mii.dwTypeData = TEXT("&Explore");
mii.fState = MFS_ENABLED | MFS_DEFAULT;
InsertMenuItem( hMenu,
indexMenu++,
TRUE,
&mii);

ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
mii.wID = idCmdFirst + IDM_OPEN;
mii.fType = MFT_STRING;
mii.dwTypeData = TEXT("&Open");
mii.fState = MFS_ENABLED;
InsertMenuItem( hMenu,
indexMenu++,
TRUE,
&mii);
}
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(IDM_LAST + 1));
}

return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0));
}

/**************************************************************************

CContextMenu::InvokeCommand()

**************************************************************************/

STDMETHODIMP CContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
{
if(HIWORD(lpcmi->lpVerb))
{
//the command is being sent via a verb
return NOERROR;
}

if(LOWORD(lpcmi->lpVerb) > IDM_LAST)
return ResultFromScode(E_INVALIDARG);

switch(LOWORD(lpcmi->lpVerb))
{
case IDM_EXPLORE:
case IDM_OPEN:
{
LPITEMIDLIST pidlFQ;
SHELLEXECUTEINFO sei;

/*
Find the first item in the list that is not a value. These commands
should never be invoked if there isn't at least one key item in the list.
*/
int i;
for(i = 0; m_aPidls[i]; i++)
{
if(!m_pPidlMgr->IsValue(m_aPidls[i]))
break;
}

pidlFQ = m_pPidlMgr->Concatenate(m_pSFParent->m_pidlFQ, m_aPidls[i]);

ZeroMemory(&sei, sizeof(sei));
sei.cbSize = sizeof(sei);
sei.fMask = SEE_MASK_IDLIST | SEE_MASK_CLASSNAME;
sei.lpIDList = pidlFQ;
sei.lpClass = TEXT("folder");
sei.hwnd = lpcmi->hwnd;

if(LOWORD(lpcmi->lpVerb) == IDM_EXPLORE)
sei.lpVerb = TEXT("explore");
else
sei.lpVerb = TEXT("open");

ShellExecuteEx(&sei);

m_pPidlMgr->Delete(pidlFQ);
}
break;

}

return NOERROR;
}

/**************************************************************************

CContextMenu::GetCommandString()

**************************************************************************/

STDMETHODIMP CContextMenu::GetCommandString( UINT idCommand,
UINT uFlags,
LPUINT lpReserved,
LPSTR lpszName,
UINT uMaxNameLen)
{
HRESULT hr = E_INVALIDARG;

switch(uFlags)
{
case GCS_HELPTEXT:
switch(idCommand)
{
case 0:
lstrcpy(lpszName, "Display the file name.");
hr = NOERROR;
break;
}
break;

case GCS_VERB:
switch(idCommand)
{
case 0:
lstrcpy(lpszName, "display");
hr = NOERROR;
break;
}
break;

case GCS_VALIDATE:
hr = NOERROR;
break;
}

return hr;
}

/**************************************************************************

CContextMenu::AllocPidlTable()

**************************************************************************/

BOOL CContextMenu::AllocPidlTable(DWORD dwEntries)
{
//add one for NULL terminator
dwEntries++;

m_aPidls = (LPITEMIDLIST*)m_pMalloc->Alloc(dwEntries * sizeof(LPITEMIDLIST));

if(m_aPidls)
{
//set all of the entries to NULL
ZeroMemory(m_aPidls, dwEntries * sizeof(LPITEMIDLIST));
}

return (m_aPidls != NULL);
}

/**************************************************************************

CContextMenu::FreePidlTable()

**************************************************************************/

void CContextMenu::FreePidlTable(void)
{
if(m_aPidls && m_pPidlMgr)
{
int i;
for(i = 0; m_aPidls[i]; i++)
m_pPidlMgr->Delete(m_aPidls[i]);

m_pMalloc->Free(m_aPidls);

m_aPidls = NULL;
}
}

/**************************************************************************

CContextMenu::FillPidlTable()

**************************************************************************/

BOOL CContextMenu::FillPidlTable(LPCITEMIDLIST *aPidls, UINT uItemCount)
{
if(m_aPidls)
{
if(m_pPidlMgr)
{
UINT i;
for(i = 0; i < uItemCount; i++)
{
m_aPidls[i] = m_pPidlMgr->Copy(aPidls[i]);
}
return TRUE;
}
}

return FALSE;
}