//____________________________________________________________________________ // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1995 - 1996. // // File: menu.hxx // // Contents: Declaration of CJobsCM, implementing IContextMenu // // Classes: // // Functions: // // History: 1/4/1996 RaviR Created // //____________________________________________________________________________ #include "..\pch\headers.hxx" #pragma hdrstop #include "dbg.h" #include "macros.h" #include // ARRAY_LEN #include "policy.hxx" #include "resource.h" #include "jobidl.hxx" #include "util.hxx" #include "dll.hxx" #include "..\schedui\schedui.hxx" #include "..\schedui\dlg.hxx" #include "..\wizard\wizpage.hxx" #include "..\wizard\taskwiz.hxx" // // extern // extern HINSTANCE g_hInstance; HRESULT JFGetDataObject( LPCTSTR pszFolderPath, LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST * apidl, BOOL fCut, LPVOID * ppvObj); HRESULT JFOpenPropSheet( LPDATAOBJECT pdtobj, LPTSTR pszCaption); HRESULT GetSchSvcState( DWORD &dwCurrState); HRESULT StartScheduler(void); HRESULT PauseScheduler( BOOL fPause); BOOL UserCanChangeService( LPCTSTR ptszServer); HRESULT PromptForServiceStart( HWND hwnd); //____________________________________________________________________________ // // Class: CJobsCM // // Purpose: Provide IContextMenu interface to Job Folder objects. // // History: 1/24/1996 RaviR Created //____________________________________________________________________________ class CJobsCM : public IContextMenu { public: CJobsCM( HWND hwnd, ITaskScheduler *pScheduler, LPCTSTR ptszMachine); HRESULT InitInstance( LPCTSTR pszFolderPath, LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST* apidl); ~CJobsCM(); // IUnknown methods DECLARE_STANDARD_IUNKNOWN; // IContextMenu methods STDMETHOD(QueryContextMenu)(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO lpici); STDMETHOD(GetCommandString)(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax); private: HRESULT _RunJob(CJobID & jid); HRESULT _AbortJob(CJobID & jid); HRESULT _DeleteJobs(void); HRESULT _DisplayJobProperties(HWND hwnd, CJobID & jid); LPCTSTR m_pszFolderPath; LPITEMIDLIST m_pidlFolder; UINT m_cidl; LPITEMIDLIST * m_apidl; HWND m_hwnd; ITaskScheduler * m_pScheduler; LPCTSTR m_ptszMachine; }; inline CJobsCM::CJobsCM( HWND hwnd, ITaskScheduler *pScheduler, LPCTSTR ptszMachine): m_ulRefs(1), m_hwnd(hwnd), m_cidl(0), m_apidl(NULL), m_pScheduler(pScheduler), m_ptszMachine(ptszMachine), m_pidlFolder(NULL), m_pszFolderPath(NULL) { TRACE(CJobsCM, CJobsCM); } //____________________________________________________________________________ // // Member: CJobsCM::~CJobsCM, Destructor // // History: 1/8/1996 RaviR Created //____________________________________________________________________________ CJobsCM::~CJobsCM() { TRACE(CJobsCM, ~CJobsCM); ILA_Free(m_cidl, m_apidl); ILFree(m_pidlFolder); m_cidl = 0; m_apidl = NULL; // Don't do a release on pScheduler, since this object never // increased its ref count. } //____________________________________________________________________________ // // Member: IUnknown methods //____________________________________________________________________________ IMPLEMENT_STANDARD_IUNKNOWN(CJobsCM); STDMETHODIMP CJobsCM::QueryInterface(REFIID riid, LPVOID* ppvObj) { if (IsEqualIID(IID_IUnknown, riid) || IsEqualIID(IID_IContextMenu, riid)) { *ppvObj = (IUnknown*)(IContextMenu*) this; this->AddRef(); return S_OK; } *ppvObj = NULL; return E_NOINTERFACE; } //____________________________________________________________________________ // // Member: CJobsCM::InitInstance // // Synopsis: S // // Arguments: [cidl] -- IN // [apidl] -- IN // // Returns: HRESULT. // // History: 1/8/1996 RaviR Created // //____________________________________________________________________________ HRESULT CJobsCM::InitInstance( LPCTSTR pszFolderPath, LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST* apidl) { TRACE(CJobsCM, InitInstance); HRESULT hr = S_OK; m_pszFolderPath = pszFolderPath; m_cidl = cidl; m_apidl = ILA_Clone(cidl, apidl); if (!m_apidl) { hr = E_OUTOFMEMORY; CHECK_HRESULT(hr); return hr; } m_pidlFolder = ILClone(pidlFolder); if (!m_pidlFolder) { ILA_Free(m_cidl, m_apidl); m_cidl = 0; m_apidl = NULL; hr = E_OUTOFMEMORY; CHECK_HRESULT(hr); return hr; } return S_OK; } //____________________________________________________________________________ // // Member: CJobsCM::QueryContextMenu // // Synopsis: Same as IContextMenu::QueryContextMenu // // Arguments: [hmenu] -- IN // [indexMenu] -- IN // [idCmdFirst] -- IN // [idCmdLast] -- IN // [uFlags] -- IN // // Returns: STDMETHODIMP // // History: 1/8/1996 RaviR Created // //____________________________________________________________________________ STDMETHODIMP CJobsCM::QueryContextMenu( HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) { TRACE(CJobsCM, QueryContextMenu); DEBUG_OUT((DEB_TRACE, "QueryContextMenu\n", uFlags)); QCMINFO qcm = {hmenu, indexMenu, idCmdFirst, idCmdLast}; BOOL fRunning = FALSE; // selected objects include running object BOOL fTemplate = FALSE; // selected objects include template object UINT i; for (i=0; i < m_cidl; i++) { PJOBID pjid = (PJOBID)m_apidl[i]; if (pjid->IsTemplate()) { fTemplate = TRUE; } if (pjid->IsRunning()) { fRunning = TRUE; } } if (fTemplate) { UtMergeMenu(g_hInstance, POPUP_JOB_TEMPLATE, 0, (LPQCMINFO)&qcm); SetMenuDefaultItem(hmenu, idCmdFirst + CMIDM_OPEN, FALSE); } else { UtMergeMenu(g_hInstance, (uFlags & CMF_DVFILE) ? POPUP_JOB_VERBS_ONLY : POPUP_JOB, 0, (LPQCMINFO)&qcm); UINT uEnable = (m_cidl > 1) ? (MF_GRAYED | MF_BYCOMMAND) : (MF_ENABLED | MF_BYCOMMAND); EnableMenuItem(hmenu, idCmdFirst + CMIDM_PROPERTIES, uEnable); uEnable = (fRunning == TRUE) ? (MF_ENABLED | MF_BYCOMMAND) : (MF_GRAYED | MF_BYCOMMAND); EnableMenuItem(hmenu, idCmdFirst + CMIDM_ABORT, uEnable); // // We are trying to prevent the "RUN" command // from being available if the job is already running // -- okay b/c we only permit one running instance at a time // // Note, that as in the above (abort enable) we have about // a second's worth of delay between when we fire off the // run command and when the service actually updates the // state of the job object itself, permitting us to make the // right choice. We've always had this with "End Task" and // it has so far been okay. // uEnable = (fRunning == FALSE) ? (MF_ENABLED | MF_BYCOMMAND) : (MF_GRAYED | MF_BYCOMMAND); EnableMenuItem(hmenu, idCmdFirst + CMIDM_RUN, uEnable); // // Policy - user can control the ui // if (RegReadPolicyKey(TS_KEYPOLICY_DENY_DELETE)) { // Do not permit the removal of tasks EnableMenuItem(hmenu, idCmdFirst + CMIDM_DELETE, (MF_GRAYED | MF_BYCOMMAND)); EnableMenuItem(hmenu, idCmdFirst + CMIDM_CUT, (MF_GRAYED | MF_BYCOMMAND)); EnableMenuItem(hmenu, idCmdFirst + CMIDM_RENAME, (MF_GRAYED | MF_BYCOMMAND)); } if (RegReadPolicyKey(TS_KEYPOLICY_DENY_CREATE_TASK)) { // Do not allow tasks to be created (new name) EnableMenuItem(hmenu, idCmdFirst + CMIDM_RENAME, (MF_GRAYED | MF_BYCOMMAND)); } if (RegReadPolicyKey(TS_KEYPOLICY_DENY_DRAGDROP)) { // Prevent any drag-drop type operations/clipboard stuff EnableMenuItem(hmenu, idCmdFirst + CMIDM_CUT, (MF_GRAYED | MF_BYCOMMAND)); EnableMenuItem(hmenu, idCmdFirst + CMIDM_COPY, (MF_GRAYED | MF_BYCOMMAND)); EnableMenuItem(hmenu, idCmdFirst + CMIDM_RENAME, (MF_GRAYED | MF_BYCOMMAND)); } if (RegReadPolicyKey(TS_KEYPOLICY_DENY_PROPERTIES)) { // Do not allow access to property pages EnableMenuItem(hmenu, idCmdFirst + CMIDM_PROPERTIES, (MF_GRAYED | MF_BYCOMMAND)); } if (RegReadPolicyKey(TS_KEYPOLICY_DENY_EXECUTION)) { // Do not allow users to run or stop a job EnableMenuItem(hmenu, idCmdFirst + CMIDM_RUN, (MF_GRAYED | MF_BYCOMMAND)); EnableMenuItem(hmenu, idCmdFirst + CMIDM_ABORT, (MF_GRAYED | MF_BYCOMMAND)); } SetMenuDefaultItem(hmenu, idCmdFirst + CMIDM_PROPERTIES, FALSE); } return ResultFromShort(qcm.idCmdFirst - idCmdFirst); } //____________________________________________________________________________ // // Member: CJobsCM::InvokeCommand // // Synopsis: Same as IContextMenu::InvokeCommand // // Arguments: [lpici] -- IN // // Returns: STDMETHODIMP // // History: 1/8/1996 RaviR Created // //____________________________________________________________________________ STDMETHODIMP CJobsCM::InvokeCommand( LPCMINVOKECOMMANDINFO lpici) { TRACE(CJobsCM, InvokeCommand); HRESULT hr = S_OK; UINT i; UINT idCmd; if (HIWORD(lpici->lpVerb)) { // Deal with string commands PSTR pszCmd = (PSTR)lpici->lpVerb; if (0 == lstrcmpA(pszCmd, "delete")) { idCmd = CMIDM_DELETE; } else if (0 == lstrcmpA(pszCmd, "properties")) { idCmd = CMIDM_PROPERTIES; } else if (0 == lstrcmpA(pszCmd, "cut")) { idCmd = CMIDM_CUT; } else if (0 == lstrcmpA(pszCmd, "copy")) { idCmd = CMIDM_COPY; } else if (0 == lstrcmpA(pszCmd, "rename")) { idCmd = CMIDM_RENAME; } else { DEBUG_OUT((DEB_ERROR, "Unprocessed InvokeCommand<%s>\n", pszCmd)); return E_INVALIDARG; } } else { idCmd = LOWORD(lpici->lpVerb); } switch(idCmd) { case CMIDM_DELETE: { hr = _DeleteJobs(); break; } case CMIDM_PROPERTIES: Win4Assert(m_cidl == 1); hr = _DisplayJobProperties(m_hwnd, *((PJOBID)m_apidl[0])); break; case CMIDM_CUT: case CMIDM_COPY: { LPDATAOBJECT pdobj = NULL; hr = JFGetDataObject(m_pszFolderPath, m_pidlFolder, m_cidl, (LPCITEMIDLIST *)m_apidl, (idCmd == CMIDM_CUT), (void **)&pdobj); if (SUCCEEDED(hr)) { hr = OleSetClipboard(pdobj); CHECK_HRESULT(hr); } pdobj->Release(); if (idCmd == CMIDM_CUT) { ShellFolderView_SetClipboard(m_hwnd, DFM_CMD_MOVE); } break; } case CMIDM_RUN: { if (UserCanChangeService(m_ptszMachine)) { hr = PromptForServiceStart(m_hwnd); } if (hr != S_OK) { break; } for (i=0; i < m_cidl; i++) { hr = _RunJob(*((PJOBID)m_apidl[i])); } break; } case CMIDM_ABORT: { for (i=0; i < m_cidl; i++) { PJOBID pjid = (PJOBID)m_apidl[i]; if (pjid->IsRunning() == TRUE) { hr = _AbortJob(*((PJOBID)m_apidl[i])); } } break; } case CMIDM_OPEN: (void) CTaskWizard::Launch(m_pszFolderPath, m_pidlFolder); break; default: return E_FAIL; } return hr; } //____________________________________________________________________________ // // Member: CJobsCM::GetCommandString // // Synopsis: Same as IContextMenu::GetCommandString // // Arguments: [idCmd] -- IN // [uType] -- IN // [pwReserved] -- IN // [pszName] -- IN // [cchMax] -- IN // // Returns: STDMETHODIMP // // History: 1/8/1996 RaviR Created // //____________________________________________________________________________ STDMETHODIMP CJobsCM::GetCommandString( UINT_PTR idCmd, UINT uType, UINT * pwReserved, LPSTR pszName, UINT cchMax) { TRACE(CJobsCM, GetCommandString); #if DBG==1 char * aType[] = {"GCS_VERBA", "GCS_HELPTEXTA", "GCS_VALIDATEA", "Unused", "GCS_VERBW", "GCS_HELPTEXTW", "GCS_VALIDATEW", "UNICODE"}; DEBUG_OUT((DEB_TRACE, "GetCommandString = <%d, %d, %s>\n", idCmd, uType, aType[uType])); #endif // DBG==1 *((LPTSTR)pszName) = TEXT('\0'); if (uType == GCS_HELPTEXT) { LoadString(g_hInstance, (UINT)idCmd + IDS_MH_FSIDM_FIRST, (LPTSTR)pszName, cchMax); return S_OK; } if (uType == GCS_VERB && idCmd == CMIDM_RENAME) { // "rename" is language independent lstrcpy((LPTSTR)pszName, TEXT("rename")); return S_OK; } return E_FAIL; } //____________________________________________________________________________ // // Member: CJobsCM::_RunJob // // Arguments: [hwnd] -- IN // [jid] -- IN // // Returns: HRESULT. // // History: 1/12/1996 RaviR Created // //____________________________________________________________________________ HRESULT CJobsCM::_RunJob( CJobID & jid) { TRACE(CJobsCM, _RunJob); ITask * pJob = NULL; TCHAR tcJob[MAX_PATH]; lstrcpy(tcJob, jid.GetPath()); lstrcat(tcJob, TSZ_DOTJOB); HRESULT hr = ::JFCreateAndLoadTask(m_pszFolderPath, tcJob, &pJob); if (SUCCEEDED(hr)) { hr = pJob->Run(); CHECK_HRESULT(hr); pJob->Release(); } return hr; } //____________________________________________________________________________ // // Member: CJobsCM::_AbortJob // // Arguments: [hwnd] -- IN // [jid] -- IN // // Returns: HRESULT. // // History: 1/12/1996 RaviR Created // //____________________________________________________________________________ HRESULT CJobsCM::_AbortJob( CJobID & jid) { TRACE(CJobsCM, _AbortJob); ITask * pJob = NULL; TCHAR tcJob[MAX_PATH]; lstrcpy(tcJob, jid.GetPath()); lstrcat(tcJob, TSZ_DOTJOB); HRESULT hr = ::JFCreateAndLoadTask(m_pszFolderPath, tcJob, &pJob); if (SUCCEEDED(hr)) { hr = pJob->Terminate(); CHECK_HRESULT(hr); pJob->Release(); } return hr; } //____________________________________________________________________________ // // Member: CJobsCM::_DeleteJobs // // Arguments: [hwnd] -- IN // [pwszJob] -- IN // // Returns: HRESULT. // // History: 1/11/1996 RaviR Created // //____________________________________________________________________________ HRESULT CJobsCM::_DeleteJobs(void) { TRACE(CJobsCM, _DeleteJobs); PJOBID pjid = NULL; UINT cchReqd = 0; // // Policy - if DELETE flag set, cannot remove jobs // if (RegReadPolicyKey(TS_KEYPOLICY_DENY_DELETE)) { return E_FAIL; } // // First compute buffer size for pFrom. // // Each file full path is composed as: // FolderPath + \ + job path rel to fldr + extn + null // // Only differs for each. (Assuming extension // length is always 4 <.job, .que>) for (UINT i=0; i < m_cidl; i++) { pjid = (PJOBID)m_apidl[i]; cchReqd += lstrlen(pjid->GetPath()); } cchReqd += (lstrlen(m_pszFolderPath) + 1 + ARRAY_LEN(TSZ_DOTJOB)) * m_cidl; // one for the extra null at the end ++cchReqd; LPTSTR pFrom = new TCHAR[cchReqd]; if (pFrom == NULL) { CHECK_HRESULT(E_OUTOFMEMORY); return E_OUTOFMEMORY; } UINT ufldrPathLen = lstrlen(m_pszFolderPath); LPTSTR pCur = pFrom; for (i=0; i < m_cidl; i++) { pjid = (PJOBID)m_apidl[i]; lstrcpy(pCur, m_pszFolderPath); pCur += ufldrPathLen; *pCur++ = TEXT('\\'); lstrcpy(pCur, pjid->GetPath()); lstrcat(pCur, pjid->GetExtension()); pCur += lstrlen(pCur) + 1; } // Make sure we have double trailing NULL! *pCur = TEXT('\0'); SHFILEOPSTRUCT fo; fo.hwnd = m_hwnd; fo.wFunc = FO_DELETE; fo.pFrom = pFrom; fo.pTo = NULL; fo.fFlags = FOF_ALLOWUNDO; fo.fAnyOperationsAborted = FALSE; fo.hNameMappings = NULL; fo.lpszProgressTitle = NULL; HRESULT hr = S_OK; if ((SHFileOperation(&fo) !=0) || fo.fAnyOperationsAborted == TRUE) { hr = E_FAIL; CHECK_HRESULT(hr); } delete pFrom; return hr; } ///////////////////////////////////////////////////////////////////////////// // // Display properties // // from ..\ps\jobpages.cxx HRESULT DisplayJobProperties( LPDATAOBJECT pdtobj); DWORD __stdcall JFPropertiesThread( LPVOID pvData) { LPDATAOBJECT pdtobj = (LPDATAOBJECT)pvData; HRESULT hrOle = OleInitialize(NULL); __try { if (SUCCEEDED(hrOle)) { ::DisplayJobProperties(pdtobj); } } __finally { pdtobj->Release(); if (SUCCEEDED(hrOle)) { OleUninitialize(); } ExitThread(0); } return 0; } //____________________________________________________________________________ // // Member: CJobsCM::_DisplayJobProperties // // Arguments: [hwnd] -- IN // [pwszJob] -- IN // // Returns: HRESULT. // // History: 1/11/1996 RaviR Created // //____________________________________________________________________________ HRESULT CJobsCM::_DisplayJobProperties( HWND hwnd, CJobID & jid) { TRACE(CJobsCM, _DisplayJobProperties); Win4Assert(m_cidl == 1); HRESULT hr = S_OK; LPDATAOBJECT pdtobj = NULL; do { hr = JFGetDataObject(m_pszFolderPath, m_pidlFolder, m_cidl, (LPCITEMIDLIST *)m_apidl, FALSE, (LPVOID *)&pdtobj); CHECK_HRESULT(hr); BREAK_ON_FAIL(hr); HANDLE hThread; DWORD idThread; hThread = CreateThread(NULL, 0, JFPropertiesThread, pdtobj, 0, &idThread); if (hThread) { CloseHandle(hThread); } else { pdtobj->Release(); } } while (0); return hr; } //____________________________________________________________________________ // // Function: JFGetItemContextMenu // // Synopsis: S // // Arguments: [hwnd] -- IN // [pScheduler] -- IN // [cidl] -- IN // [apidl] -- IN // [ppvOut] -- OUT // // Returns: HRESULT // // History: 1/25/1996 RaviR Created //____________________________________________________________________________ HRESULT JFGetItemContextMenu( HWND hwnd, ITaskScheduler * pScheduler, LPCTSTR ptszMachine, LPCTSTR pszFolderPath, LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST* apidl, LPVOID * ppvOut) { CJobsCM* pObj = new CJobsCM(hwnd, pScheduler, ptszMachine); if (NULL == pObj) { return E_OUTOFMEMORY; } HRESULT hr = pObj->InitInstance(pszFolderPath, pidlFolder, cidl, apidl); if (SUCCEEDED(hr)) { hr = pObj->QueryInterface(IID_IContextMenu, ppvOut); } pObj->Release(); return hr; }