WindowsXP-SP1/shell/ext/cdfview/chanmenu.cpp
2020-09-30 16:53:49 +02:00

791 lines
21 KiB
C++

//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// Chanmenu.cpp
//
// IConextMenu for folder items.
//
// History:
//
// 6/12/97 edwardp Created.
//
////////////////////////////////////////////////////////////////////////////////
//
// Includes
//
#include "stdinc.h"
#include "cdfidl.h"
#include "xmlutil.h"
#include "chanmenu.h"
#include "dll.h"
#include "persist.h"
#include "resource.h"
#include "chanapi.h"
#include "chanmgrp.h"
#include "chanmgri.h"
#define _SHDOCVW_
#include <shdocvw.h>
#include <mluisupp.h>
#ifdef UNIX
EXTERN_C char *MwGetXDisplayString( void );
#ifdef UNICODE
#define unixInvokeEditor unixInvokeEditorW
#else
#define unixInvokeEditor unixInvokeEditorA
#endif /* UNICODE */
static void unixInvokeEditorA(LPCSTR lpszPath)
{
HKEY hkeyUnix;
CHAR szCommand [2*MAX_PATH];
CHAR szCmdTempl[MAX_PATH+1];
CHAR szName [MAX_PATH+1];
CHAR hKeyName [MAX_PATH+1];
STARTUPINFOA st;
PROCESS_INFORMATION pi;
BOOL bIsKnownEdit = FALSE;
char displayString [2*MAX_PATH];
DWORD editors = 0;
DWORD type = REG_SZ;
DWORD dwLength = sizeof(szCmdTempl);
if( MwGetXDisplayString() )
sprintf( displayString, "-display %s", MwGetXDisplayString() );
else
sprintf( displayString, " ");
// Get user preferred editor.
if( getenv("EDITOR" ) )
strcpy(szName, getenv("EDITOR") );
else
strcpy(szName, "vi");
// Check editor against the list of known editors in
// registry.
sprintf( hKeyName,
"Software\\Microsoft\\Internet Explorer\\Unix\\Editors\\%s",
szName );
LONG lResult = RegOpenKeyExA(
HKEY_CURRENT_USER,
hKeyName,
0,
KEY_QUERY_VALUE,
&hkeyUnix);
// Create proper command and append dissplay string to make the
// editor appear on the same XServer as the Iexplorer.
if( !bIsKnownEdit )
{
// Default use vi
sprintf( szCommand, "xterm %s -e vi %s ", displayString, lpszPath );
}
else
{
// Use template command from registry to create actual command.
sprintf( szCommand, szCmdTempl, displayString, lpszPath );
}
// Initialize startup info struct.
st.cb = sizeof(STARTUPINFO);
st.lpReserved = NULL;
st.lpDesktop = NULL;
st.lpTitle = NULL;
st.dwFlags = 0;
st.wShowWindow= SW_SHOWNORMAL;
st.cbReserved2= 0;
st.lpReserved2= NULL;
// Launch the command
if ( CreateProcessA( NULL, szCommand, NULL, NULL, TRUE,
CREATE_NEW_CONSOLE, NULL, NULL, &st, &pi ))
{
return;
}
return;
}
static void unixInvokeEditorW(LPCWSTR lpwszPath)
{
char szFileName[MAX_PATH+2]; /* same as in ViewSource */
SHUnicodeToAnsi(lpwszPath,szFileName, ARRAYSIZE(szFileName));
unixInvokeEditorA(szFileName);
return;
}
#endif /* UNIX */
//
// Constructor and destructor.
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CContextMenu::CContextMenu ***
//
// Constructor for IContextMenu.
//
////////////////////////////////////////////////////////////////////////////////
CChannelMenu::CChannelMenu (
void
)
: m_cRef(1)
{
TraceMsg(TF_OBJECTS, "+ IContextMenu (root)");
DllAddRef();
ASSERT(NULL == m_pSubscriptionMgr);
ASSERT(NULL == m_bstrURL);
ASSERT(NULL == m_bstrName);
return;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CContextMenu::~CContextMenu ***
//
// Destructor.
//
////////////////////////////////////////////////////////////////////////////////
CChannelMenu::~CChannelMenu (
void
)
{
ASSERT(0 == m_cRef);
if (NULL != m_bstrURL)
SysFreeString(m_bstrURL);
if (NULL != m_bstrName)
SysFreeString(m_bstrName);
if (NULL != m_pSubscriptionMgr)
m_pSubscriptionMgr->Release();
//
// Matching Release for the constructor Addref.
//
TraceMsg(TF_OBJECTS, "- IContextMenu (root)");
DllRelease();
return;
}
//
// IUnknown methods.
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CContextMenu::CContextMenu ***
//
// CExtractIcon QI.
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CChannelMenu::QueryInterface (
REFIID riid,
void **ppv
)
{
ASSERT(ppv);
HRESULT hr;
*ppv = NULL;
if (IID_IUnknown == riid || IID_IContextMenu == riid)
{
*ppv = (IContextMenu*)this;
}
else if (IID_IShellExtInit == riid)
{
*ppv = (IShellExtInit*)this;
}
if (*ppv)
{
((IUnknown*)*ppv)->AddRef();
hr = S_OK;
}
else
{
hr = E_NOINTERFACE;
}
ASSERT((SUCCEEDED(hr) && *ppv) || (FAILED(hr) && NULL == *ppv));
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CContextMenu::AddRef ***
//
// CContextMenu AddRef.
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG)
CChannelMenu::AddRef (
void
)
{
ASSERT(m_cRef != 0);
ASSERT(m_cRef < (ULONG)-1);
return ++m_cRef;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CContextMenu::Release ***
//
// CContextMenu Release.
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG)
CChannelMenu::Release (
void
)
{
ASSERT (m_cRef != 0);
ULONG cRef = --m_cRef;
if (0 == cRef)
delete this;
return cRef;
}
//
// IContextMenu methods.
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CContextMenu::QueryContextMenu ***
//
//
// Description:
// Adds menu items to the given item's context menu.
//
// Parameters:
// [In Out] hmenu - A handle to the menu. New items are inserted into
// this menu
// [In] indexMenu - Zero-based position at which to insert the first
// menu item.
// [In] idCmdFirst - Minimum value that can be used for a new menu item
// identifier.
// [In] idCmdLast - Maximum value the can be used for a menu item id.
// [In] uFlags - CMF_DEFAULTONLY, CMF_EXPLORE, CMF_NORMAL or
// CMF_VERBSONLY.
//
// Return:
// On success the scode contains the the menu identifier offset of the last
// menu item added plus one.
//
// Comments:
// CMF_DEFAULTONLY flag indicates the user double-clicked on the item. In
// this case no menu is displayed. The shell is simply querying for the ID
// of the default action.
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CChannelMenu::QueryContextMenu(
HMENU hmenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags
)
{
HRESULT hr = S_OK;
BOOL fSubscribed;
HMENU hChannelMenu, hChannelSubMenu;
ASSERT(hmenu);
ASSERT(idCmdFirst < idCmdLast);
if (!(CMF_DEFAULTONLY & uFlags))
{
if (NULL != m_pSubscriptionMgr)
{
ASSERT(idCmdFirst + IDM_SUBSCRIBE < idCmdLast);
#ifndef UNIX
if (CanSubscribe(m_bstrURL))
{
m_pSubscriptionMgr->IsSubscribed(m_bstrURL, &fSubscribed);
if (fSubscribed)
{
hChannelMenu = LoadMenu(MLGetHinst(),
MAKEINTRESOURCE(IDM_SUBSCRIBEDMENU));
if (SHRestricted2W(REST_NoRemovingSubscriptions, m_bstrURL, 0))
{
EnableMenuItem(hChannelMenu, IDM_SUBSCRIBE,
MF_BYCOMMAND | MF_GRAYED);
}
if (SHRestricted2W(REST_NoManualUpdates, m_bstrURL, 0))
{
EnableMenuItem(hChannelMenu, IDM_UPDATESUBSCRIPTION,
MF_BYCOMMAND | MF_GRAYED);
}
}
else
{
int idMenu = !SHRestricted2W(REST_NoAddingSubscriptions,
m_bstrURL, 0)
? IDM_UNSUBSCRIBEDMENU : IDM_NOSUBSCRIBEMENU;
hChannelMenu = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(idMenu));
}
}
else
#endif /* !UNIX */
{
hChannelMenu = LoadMenu(MLGetHinst(),
MAKEINTRESOURCE(IDM_NOSUBSCRIBEMENU));
}
if (NULL != hChannelMenu)
{
hChannelSubMenu = GetSubMenu(hChannelMenu, 0);
if (NULL != hChannelSubMenu)
{
hr = Shell_MergeMenus(hmenu, hChannelSubMenu, indexMenu,
idCmdFirst, idCmdLast, MM_ADDSEPARATOR)
- idCmdFirst;
}
else
{
hr = E_FAIL;
}
DestroyMenu(hChannelMenu);
}
else
{
hr = E_FAIL;
}
}
RemoveMenuItems(hmenu);
}
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CContextMenu::InvokeCommand ***
//
//
// Description:
// Carries out the command for the given menu item id.
//
// Parameters:
// [In] lpici - Structure containing the verb, hwnd, menu id, etc.
//
// Return:
// S_OK if the command was successful.
// E_FAIL otherwise.
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CChannelMenu::InvokeCommand(
LPCMINVOKECOMMANDINFO lpici
)
{
HRESULT hr = S_OK;
ASSERT(lpici);
if (HIWORD(lpici->lpVerb) == 0)
{
switch (LOWORD(lpici->lpVerb))
{
case IDM_UPDATESUBSCRIPTION:
ASSERT(NULL != m_pSubscriptionMgr);
m_pSubscriptionMgr->UpdateSubscription(m_bstrURL);
break;
case IDM_SUBSCRIBE:
ASSERT(NULL != m_pSubscriptionMgr);
ASSERT( sizeof(SUBSCRIPTIONINFO) == m_si.cbSize);
hr = Subscribe(lpici->hwnd);
break;
case IDM_UNSUBSCRIBE:
ASSERT(NULL != m_pSubscriptionMgr);
m_pSubscriptionMgr->DeleteSubscription(m_bstrURL, lpici->hwnd);
break;
case IDM_EDITSUBSCRIPTION:
ASSERT(NULL != m_pSubscriptionMgr);
m_pSubscriptionMgr->ShowSubscriptionProperties(m_bstrURL,
lpici->hwnd);
break;
case IDM_REFRESHCHANNEL:
Refresh(lpici->hwnd);
break;
case IDM_VIEWSOURCE:
ViewSource(lpici->hwnd);
break;
}
}
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CContextMenu::GetCommandString ***
//
//
// Description:
//
//
// Parameters:
//
//
// Return:
//
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CChannelMenu::GetCommandString(
UINT_PTR idCommand,
UINT uFLags,
UINT *pwReserved,
LPSTR pszName,
UINT cchMax
)
{
return E_NOTIMPL;
}
//
//
//
STDMETHODIMP
CChannelMenu::Initialize(
LPCITEMIDLIST pidl,
LPDATAOBJECT pdobj,
HKEY hkey
)
{
HRESULT hr;
STGMEDIUM stgmed;
FORMATETC fmtetc = {CF_HDROP, NULL, DVASPECT_CONTENT, -1,
TYMED_HGLOBAL};
ASSERT(pdobj);
hr = pdobj->GetData(&fmtetc, &stgmed);
if (SUCCEEDED(hr))
{
if (DragQueryFile((HDROP)stgmed.hGlobal, 0, m_szPath,
ARRAYSIZE(m_szPath)))
{
m_tt.cbTriggerSize = sizeof(TASK_TRIGGER);
m_si.cbSize = sizeof(SUBSCRIPTIONINFO);
m_si.fUpdateFlags |= SUBSINFO_SCHEDULE;
m_si.schedule = SUBSSCHED_AUTO;
m_si.pTrigger = &m_tt;
hr = GetNameAndURLAndSubscriptionInfo(m_szPath, &m_bstrName, &m_bstrURL,
&m_si);
ASSERT((SUCCEEDED(hr) && m_bstrName && m_bstrURL) || FAILED(hr));
}
else
{
hr = E_FAIL;
}
ReleaseStgMedium(&stgmed);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL,
CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr,
(void**)&m_pSubscriptionMgr);
}
}
// Return S_OK even if things didn't go as planned so that
// RemoveMenus will get called.
return S_OK;
}
//
// Helper functions
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** Name ***
//
//
// Description:
//
//
// Parameters:
//
//
// Return:
//
//
// Comments:
//
//
////////////////////////////////////////////////////////////////////////////////
void
CChannelMenu::RemoveMenuItems(
HMENU hmenu
)
{
TCHAR aszRemove[4][62] = {{0}, {0}, {0}, {0}};
MLLoadString(IDS_SHARING, aszRemove[0], ARRAYSIZE(aszRemove[0]));
MLLoadString(IDS_RENAME, aszRemove[1], ARRAYSIZE(aszRemove[1]));
MLLoadString(IDS_SENDTO, aszRemove[2], ARRAYSIZE(aszRemove[2]));
if (SHRestricted2W(REST_NoEditingChannels, NULL, 0))
MLLoadString(IDS_PROPERTIES, aszRemove[3], ARRAYSIZE(aszRemove[3]));
TCHAR szBuffer[62];
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_TYPE;
for (int i = GetMenuItemCount(hmenu) - 1; i >= 0; i--)
{
mii.dwTypeData = szBuffer;
mii.cch = ARRAYSIZE(szBuffer);
if (GetMenuItemInfo(hmenu, i, TRUE, &mii) && mii.cch)
{
for (int j = 0; j < ARRAYSIZE(aszRemove); j++)
{
if (StrEql(aszRemove[j], mii.dwTypeData))
{
DeleteMenu(hmenu, i, MF_BYPOSITION);
break;
}
}
}
}
return;
}
void CChannelMenu::Refresh(HWND hwnd)
{
IXMLDocument* pIXMLDocument;
DLL_ForcePreloadDlls(PRELOAD_MSXML);
HRESULT hr = CoCreateInstance(CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER,
IID_IXMLDocument, (void**)&pIXMLDocument);
if (SUCCEEDED(hr))
{
ASSERT(pIXMLDocument);
if (DownloadCdfUI(hwnd, m_bstrURL, pIXMLDocument))
{
UpdateImage(m_szPath);
SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSH,
(void*)m_szPath, NULL);
}
pIXMLDocument->Release();
}
}
static TCHAR c_szFileProtocol[] = TEXT("file:");
static TCHAR c_szCDFExtension[] = TEXT(".cdf");
static TCHAR c_szShellEdit[] = TEXT("\\shell\\edit\\command");
static TCHAR c_szEditVerb[] = TEXT("edit");
static TCHAR c_szChannelFile[] = TEXT("ChannelFile");
static TCHAR c_szChannelFileEdit[] = TEXT("ChannelFile\\shell\\edit\\command");
static TCHAR c_szNotepad[] = TEXT("notepad.exe");
void CChannelMenu::ViewSource(HWND hwnd)
{
TCHAR szProgId[64] = TEXT("");
TCHAR szBuf[INTERNET_MAX_URL_LENGTH];
TCHAR szFile[MAX_PATH + 2]; // Leave room for quotes
DWORD cch, dwType;
SHELLEXECUTEINFO sei;
BOOL fFoundProg = FALSE;
HRESULT hr = S_OK;
TraceMsg(TF_OBJECTS, "+ IContextMenu ViewSource %ls", m_bstrURL);
if (SHUnicodeToTChar(m_bstrURL, szBuf, ARRAYSIZE(szBuf)))
{
if (SUCCEEDED(URLGetLocalFileName(szBuf, szFile, ARRAYSIZE(szFile),
NULL)))
{
if (StrCmpNI(szFile, c_szFileProtocol, 5) == 0)
{
ASSERT(ARRAYSIZE(szFile) < ARRAYSIZE(szBuf));
StrCpy(szBuf, szFile);
cch = ARRAYSIZE(szFile) - 2;
hr = PathCreateFromUrl(szBuf, szFile, &cch, 0);
}
if (SUCCEEDED(hr))
{
PathQuoteSpaces(szFile);
//
// We don't just call ShellExec with edit verb since
// who knows what the file extension will be.
//
cch = ARRAYSIZE(szProgId);
if (ERROR_SUCCESS == SHGetValue(HKEY_CLASSES_ROOT,
c_szCDFExtension,
NULL, &dwType,
szProgId, &cch)
)
{
ASSERT(ARRAYSIZE(szProgId) < ARRAYSIZE(szBuf));
StrCpy(szBuf, szProgId);
ASSERT(ARRAYSIZE(szProgId) + ARRAYSIZE(c_szShellEdit) <
ARRAYSIZE(szBuf));
StrCat(szBuf, c_szShellEdit);
cch = ARRAYSIZE(szBuf);
if (ERROR_SUCCESS == SHGetValue(HKEY_CLASSES_ROOT, szBuf,
NULL, &dwType, szBuf, &cch)
)
{
//
// Getting here means they have an edit verb for CDF files
//
fFoundProg = TRUE;
}
}
//
// If we haven't found a class key yet and the CDF ProgID
// isn't ours, then fall back to our edit verb.
//
if (!fFoundProg && StrCmpI(szProgId, c_szChannelFile))
{
cch = ARRAYSIZE(szBuf);
if (ERROR_SUCCESS == SHGetValue(HKEY_CLASSES_ROOT,
c_szChannelFileEdit,
NULL, &dwType,
szBuf, &cch)
)
{
fFoundProg = TRUE;
ASSERT(ARRAYSIZE(c_szChannelFile) < ARRAYSIZE(szProgId));
StrCpy(szProgId, c_szChannelFile);
}
}
memset(&sei, 0, sizeof(sei));
sei.cbSize = sizeof(sei);
sei.hwnd = hwnd;
sei.nShow = SW_SHOW;
if (fFoundProg)
{
sei.fMask = SEE_MASK_CLASSNAME;
sei.lpVerb = c_szEditVerb;
sei.lpFile = szFile;
sei.lpClass = szProgId;
TraceMsg(TF_OBJECTS, "IContextMenu ViewSource progid=%s file=%s", szProgId, szFile);
}
else
{
sei.lpFile = c_szNotepad;
sei.lpParameters = szFile;
TraceMsg(TF_OBJECTS, "IContextMenu ViewSource Notepad file=%s", szFile);
}
#ifndef UNIX
ShellExecuteEx(&sei);
#else
unixInvokeEditor(szFile);
#endif /* UNIX */
}
}
else
{
CDFMessageBox(hwnd, IDS_ERROR_NO_CACHE_ENTRY, IDS_ERROR_DLG_TITLE,
MB_OK | MB_ICONEXCLAMATION, szBuf);
}
}
else
{
TraceMsg(TF_OBJECTS, "IContextMenu ViewSource couldn't convert to TSTR");
}
TraceMsg(TF_OBJECTS, "- IContextMenu ViewSource");
}
HRESULT CChannelMenu::Subscribe(HWND hwnd)
{
HRESULT hr = S_OK;
CChannelMgr *pChannelMgr = new CChannelMgr;
if (pChannelMgr)
{
hr = pChannelMgr->AddAndSubscribeEx2(hwnd, m_bstrURL, m_pSubscriptionMgr, TRUE);
pChannelMgr->Release();
if (SUCCEEDED(hr) && (NULL != m_pSubscriptionMgr))
{
hr = m_pSubscriptionMgr->UpdateSubscription(m_bstrURL);
}
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}