//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // // 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 #include #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; }