You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1847 lines
46 KiB
1847 lines
46 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1995.
|
|
//
|
|
// File: jobfldr.cxx
|
|
//
|
|
// Contents: Implementation of COM object CJobFolder
|
|
//
|
|
// Classes: CJobFolder
|
|
//
|
|
// History: 1/4/1996 RaviR Created
|
|
// 1-23-1997 DavidMun Add m_hwndNotify
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "..\pch\headers.hxx"
|
|
#pragma hdrstop
|
|
|
|
#include "dbg.h"
|
|
#include "macros.h"
|
|
#include "..\inc\resource.h"
|
|
#include "resource.h"
|
|
|
|
#include "sch_cls.hxx" // sched\inc
|
|
#include "job_cls.hxx" // sched\inc
|
|
#include "misc.hxx" // sched\inc
|
|
#include "policy.hxx" // sched\inc
|
|
|
|
#include "jobidl.hxx"
|
|
#include "jobfldr.hxx"
|
|
#include "common.hxx"
|
|
#include "guids.h"
|
|
#include "util.hxx"
|
|
|
|
//#undef DEB_TRACE
|
|
//#define DEB_TRACE DEB_USER1
|
|
|
|
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
|
|
|
|
BOOL
|
|
UserCanChangeService(
|
|
LPCTSTR ptszServer);
|
|
|
|
HRESULT
|
|
PromptForServiceStart(
|
|
HWND hwnd);
|
|
|
|
BOOL
|
|
IsMsNetwork( LPTSTR ptszMachine );
|
|
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Member: CJobFolder::~CJobFolder, Destructor
|
|
//____________________________________________________________________________
|
|
|
|
CJobFolder::~CJobFolder()
|
|
{
|
|
TRACE(CJobFolder, ~CJobFolder);
|
|
|
|
if (m_uRegister)
|
|
{
|
|
DEBUG_OUT((DEB_ERROR,
|
|
"CJobFolder::~CJobFolder: m_uRegister = %uL but should be 0\n",
|
|
m_uRegister));
|
|
SHChangeNotifyDeregister(m_uRegister);
|
|
m_uRegister = 0;
|
|
CDll::LockServer(FALSE);
|
|
}
|
|
|
|
if (m_hwndNotify)
|
|
{
|
|
DEBUG_OUT((DEB_ERROR,
|
|
"CJobFolder::~CJobFolder: m_hwndNotify = 0x%x but should be NULL\n",
|
|
m_hwndNotify));
|
|
|
|
BOOL fOk = DestroyWindow(m_hwndNotify);
|
|
|
|
if (!fOk)
|
|
{
|
|
DEBUG_OUT_LASTERROR;
|
|
}
|
|
}
|
|
|
|
delete m_pszMachine;
|
|
|
|
if (m_pUpdateDirData)
|
|
{
|
|
GlobalFree(m_pUpdateDirData);
|
|
}
|
|
|
|
if (m_pidlFldr)
|
|
{
|
|
ILFree(m_pidlFldr);
|
|
}
|
|
|
|
// No need to Release m_pShellView since we never addrefed it.
|
|
// See CreateViewObject in sfolder.cxx for more info.
|
|
|
|
if (m_pScheduler != NULL)
|
|
{
|
|
DEBUG_OUT((DEB_USER1, "m_pScheduler->Release\n"));
|
|
m_pScheduler->Release();
|
|
}
|
|
|
|
OleUninitialize();
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
CJobFolder::_AddObject(
|
|
PJOBID pjid,
|
|
LPITEMIDLIST *ppidl)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
INT_PTR iRet = -1;
|
|
|
|
LPITEMIDLIST pidl = ILClone((LPCITEMIDLIST)pjid);
|
|
|
|
if (pidl == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
CHECK_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
#if (DBG == 1)
|
|
((PJOBID) pidl)->Validate();
|
|
#endif // (DBG == 1)
|
|
|
|
iRet = ShellFolderView_AddObject(m_hwndOwner, pidl);
|
|
|
|
if (iRet < 0)
|
|
{
|
|
ILFree(pidl);
|
|
pidl = NULL;
|
|
|
|
hr = E_FAIL;
|
|
CHECK_HRESULT(hr);
|
|
}
|
|
|
|
if (ppidl)
|
|
{
|
|
*ppidl = pidl;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CJobFolder::_UpdateObject
|
|
//
|
|
// Synopsis: Notify the shell defview that the object with pidl [pjidOld]
|
|
// has been updated and now should look like pidl [pjidNew].
|
|
//
|
|
// Arguments: [pjidOld] - pidl of object as it appears in defview
|
|
// [pjidNew] - pidl of object as it should now appear
|
|
// [ppidl] - filled with pidl of updated object
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Modifies: *[ppidl]
|
|
//
|
|
// History: 7-07-1999 davidmun Commented
|
|
//
|
|
// Notes: Do not free returned pidl in *[ppidl].
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CJobFolder::_UpdateObject(
|
|
PJOBID pjidOld,
|
|
PJOBID pjidNew,
|
|
LPITEMIDLIST *ppidl)
|
|
{
|
|
TRACE(CJobFolder, _UpdateObject);
|
|
|
|
HRESULT hr = S_OK;
|
|
INT_PTR iRet = -1;
|
|
|
|
#if (DBG == 1)
|
|
DEBUG_OUT((DEB_TRACE,
|
|
"CJobFolder::_UpdateObject Validating pjidNew %x\n",
|
|
pjidNew));
|
|
pjidNew->Validate();
|
|
#endif // (DBG == 1)
|
|
|
|
LPITEMIDLIST pidlCopyOfNew = ILClone((LPCITEMIDLIST)pjidNew);
|
|
|
|
if (pidlCopyOfNew == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
CHECK_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
#if (DBG == 1)
|
|
DEBUG_OUT((DEB_TRACE,
|
|
"CJobFolder::_UpdateObject Validating pidlCopyOfNew %x\n",
|
|
pidlCopyOfNew));
|
|
((PJOBID) pidlCopyOfNew)->Validate();
|
|
|
|
DEBUG_OUT((DEB_TRACE,
|
|
"CJobFolder::_UpdateObject Validating pjidOld %x\n",
|
|
pjidOld));
|
|
pjidOld->Validate();
|
|
#endif // (DBG == 1)
|
|
|
|
LPITEMIDLIST apidl[2] = {(LPITEMIDLIST)pjidOld, pidlCopyOfNew};
|
|
|
|
iRet = ShellFolderView_UpdateObject(m_hwndOwner, apidl);
|
|
|
|
if (iRet < 0)
|
|
{
|
|
//
|
|
// The object to update couldn't be found, so the shell won't
|
|
// take ownership of the new object, and we have to free it now.
|
|
//
|
|
|
|
ILFree(pidlCopyOfNew);
|
|
pidlCopyOfNew = NULL;
|
|
}
|
|
|
|
if (ppidl)
|
|
{
|
|
*ppidl = (LPITEMIDLIST)ShellFolderView_GetObject(m_hwndOwner, iRet);
|
|
#if (DBG == 1)
|
|
if (*ppidl)
|
|
{
|
|
DEBUG_OUT((DEB_TRACE,
|
|
"CJobFolder::_UpdateObject Validating *ppidl %x\n",
|
|
*ppidl));
|
|
((PJOBID) *ppidl)->Validate();
|
|
}
|
|
else
|
|
{
|
|
DEBUG_OUT((DEB_TRACE, "CJobFolder::_UpdateObject *ppidl is NULL\n"));
|
|
}
|
|
#endif // (DBG == 1)
|
|
}
|
|
|
|
DEBUG_OUT((DEB_TRACE, "<CJobFolder::_UpdateObject\n"));
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Function: JFGetJobFolder
|
|
//
|
|
// Synopsis: Create an instance of CJobFolder and return the requested
|
|
// interface.
|
|
//
|
|
// Arguments: [riid] -- IN interface needed.
|
|
// [ppvObj] -- OUT place to store the interface.
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// History: 1/24/1996 RaviR Created
|
|
//____________________________________________________________________________
|
|
|
|
HRESULT
|
|
JFGetJobFolder(
|
|
REFIID riid,
|
|
LPVOID* ppvObj)
|
|
{
|
|
CJobFolder * pJobFolder = NULL;
|
|
|
|
HRESULT hr = CJobFolder::Create(&pJobFolder);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pJobFolder->QueryInterface(riid, ppvObj);
|
|
|
|
pJobFolder->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Member: CJobFolder::Create
|
|
//
|
|
// History: 1/31/1996 RaviR Created
|
|
//____________________________________________________________________________
|
|
|
|
HRESULT
|
|
CJobFolder::Create(
|
|
CJobFolder ** ppJobFolder)
|
|
{
|
|
TRACE_FUNCTION(CJobFolder::Create);
|
|
|
|
HRESULT hr = OleInitialize(NULL);
|
|
|
|
CHECK_HRESULT(hr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CJobFolder *pJobFolder;
|
|
|
|
pJobFolder = new CJobFolder();
|
|
|
|
if (pJobFolder != NULL)
|
|
{
|
|
*ppJobFolder = pJobFolder;
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
CHECK_HRESULT(hr);
|
|
|
|
OleUninitialize();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Member: CJobFolder::IUnknown methods
|
|
//
|
|
// History: 1/31/1996 RaviR Created
|
|
//____________________________________________________________________________
|
|
|
|
|
|
IMPLEMENT_STANDARD_IUNKNOWN(CJobFolder);
|
|
|
|
|
|
STDMETHODIMP
|
|
CJobFolder::QueryInterface(REFIID riid, LPVOID* ppvObj)
|
|
{
|
|
LPUNKNOWN punk = NULL;
|
|
|
|
if (IsEqualIID(IID_IUnknown, riid) ||
|
|
IsEqualIID(IID_IShellFolder, riid))
|
|
{
|
|
punk = (IUnknown*) (IShellFolder*) this;
|
|
}
|
|
else if (IsEqualIID(IID_IShellFolder2, riid))
|
|
{
|
|
punk = (IUnknown*)(IShellFolder2*) this;
|
|
}
|
|
else if (IsEqualIID(IID_IPersistFolder, riid))
|
|
{
|
|
punk = (IUnknown*) (IPersistFolder*) this;
|
|
}
|
|
#if (_WIN32_IE >= 0x0400)
|
|
else if (IsEqualIID(IID_IPersistFolder2, riid))
|
|
{
|
|
punk = (IUnknown*) (IPersistFolder2*) this;
|
|
}
|
|
#endif (_WIN32_IE >= 0x0400)
|
|
else if (IsEqualIID(IID_IDropTarget, riid))
|
|
{
|
|
punk = (IUnknown*) (IDropTarget*) this;
|
|
}
|
|
else if (IsEqualIID(IID_IRemoteComputer, riid))
|
|
{
|
|
punk = (IUnknown*) (IRemoteComputer*) this;
|
|
}
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
*ppvObj = punk;
|
|
punk->AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Member: CJobFolder::IRemoteComputer::Initialize
|
|
//
|
|
// Synopsis: This method is called when the explorer is initializing or
|
|
// enumerating the name space extension. If failure is returned
|
|
// during enumeration, the extension won't appear for this
|
|
// computer. Otherwise, the extension will appear, and should
|
|
// target the given machine.
|
|
//
|
|
// Arguments: [pwszMachine] -- IN Specifies the name of the machine to target.
|
|
// [bEnumerating] -- IN
|
|
//
|
|
// Returns: HRESULT.
|
|
//
|
|
// History: 2/21/1996 RaviR Created
|
|
//
|
|
//____________________________________________________________________________
|
|
|
|
STDMETHODIMP
|
|
CJobFolder::Initialize(
|
|
LPCWSTR pwszMachine,
|
|
BOOL bEnumerating)
|
|
{
|
|
DEBUG_OUT((DEB_USER12,
|
|
"CJobFolder::IRemoteComputer::Initialize<%ws>\n",
|
|
pwszMachine));
|
|
|
|
HRESULT hr = S_OK;
|
|
LPTSTR ptszMachine = NULL;
|
|
|
|
do
|
|
{
|
|
if (!pwszMachine)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
CHECK_HRESULT(hr);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make a copy of the machine name.
|
|
//
|
|
ptszMachine = NewDupString(pwszMachine);
|
|
if (!ptszMachine)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
CHECK_HRESULT(hr);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// The first thing about showing a remote folder is it must be
|
|
// a MS network or else the RegConnectregistry time out will
|
|
// take at least 20 seconds and there won't even be a MSTask
|
|
// on the machine.
|
|
|
|
if( !IsMsNetwork( ptszMachine ) )
|
|
{
|
|
hr = E_FAIL;
|
|
CHECK_HRESULT(hr);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We only want to show the remote jobs folder if the user has
|
|
// administrative access to that machine, and the task scheduler
|
|
// is installed there.
|
|
//
|
|
// Test both at once by trying to get a full access handle to
|
|
// the remote machine's task scheduler reg key.
|
|
//
|
|
|
|
if (bEnumerating)
|
|
{
|
|
//
|
|
// Check if the schedule service is registered on pwszMachine.
|
|
//
|
|
|
|
long lr = ERROR_SUCCESS;
|
|
HKEY hRemoteKey = NULL;
|
|
HKEY hSchedKey = NULL;
|
|
|
|
lr = RegConnectRegistry(ptszMachine,
|
|
HKEY_LOCAL_MACHINE,
|
|
&hRemoteKey);
|
|
CHECK_LASTERROR(lr);
|
|
|
|
if (lr == ERROR_SUCCESS)
|
|
{
|
|
lr = RegOpenKeyEx(hRemoteKey,
|
|
SCH_AGENT_KEY,
|
|
0,
|
|
KEY_READ,
|
|
&hSchedKey);
|
|
CHECK_LASTERROR(lr);
|
|
|
|
if (hRemoteKey != NULL)
|
|
{
|
|
RegCloseKey(hRemoteKey);
|
|
}
|
|
|
|
if (lr == ERROR_SUCCESS)
|
|
{
|
|
if (hSchedKey != NULL)
|
|
{
|
|
RegCloseKey(hSchedKey);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(lr);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(lr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Success; remember the machine name.
|
|
//
|
|
|
|
m_pszMachine = ptszMachine;
|
|
} while (0);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
delete [] ptszMachine;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
//
|
|
// Support function: MsNetwork
|
|
//
|
|
// Synopsis: Resolves whether or not we're attempting to connect to
|
|
// a MS network
|
|
//
|
|
// History: 11/12/00 DGrube Created
|
|
//
|
|
//
|
|
//____________________________________________________________________________
|
|
|
|
BOOL IsMsNetwork( LPTSTR ptszMachine )
|
|
{
|
|
DWORD dwError;
|
|
NETRESOURCE nr;
|
|
NETRESOURCE nrOut;
|
|
LPTSTR pszSystem = NULL; // pointer to variable-length strings
|
|
NETRESOURCE* lpBuffer = &nrOut; // buffer
|
|
DWORD cbResult = sizeof(nrOut); // buffer size
|
|
BOOL bReturn = TRUE;
|
|
|
|
//
|
|
// Fill a block of memory with zeroes; then
|
|
// initialize the NETRESOURCE structure.
|
|
//
|
|
SecureZeroMemory(&nr, sizeof(nr));
|
|
|
|
nr.dwScope = RESOURCE_GLOBALNET;
|
|
nr.dwType = RESOURCETYPE_ANY;
|
|
nr.lpRemoteName = ptszMachine;
|
|
|
|
//
|
|
// First call the WNetGetResourceInformation function with
|
|
// memory allocated to hold only a NETRESOURCE structure. This
|
|
// method can succeed if all the NETRESOURCE pointers are NULL.
|
|
//
|
|
dwError = WNetGetResourceInformation(&nr, lpBuffer, &cbResult, &pszSystem);
|
|
|
|
//
|
|
// If the call fails because the buffer is too small,
|
|
// call the LocalAlloc function to allocate a larger buffer.
|
|
//
|
|
if (dwError == ERROR_MORE_DATA)
|
|
{
|
|
lpBuffer = (NETRESOURCE*) LocalAlloc(LMEM_FIXED, cbResult);
|
|
|
|
if (lpBuffer == NULL)
|
|
{
|
|
CHECK_LASTERROR(GetLastError());
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Call WNetGetResourceInformation again
|
|
// with the larger buffer.
|
|
//
|
|
|
|
dwError = WNetGetResourceInformation(&nr, lpBuffer, &cbResult, &pszSystem);
|
|
|
|
if (dwError == NO_ERROR)
|
|
{
|
|
// If the call succeeds, process the contents of the
|
|
// returned NETRESOURCE structure and the variable-length
|
|
// strings in lpBuffer. Then free the memory.
|
|
//
|
|
if ( NULL != lpBuffer->lpProvider )
|
|
{
|
|
NETINFOSTRUCT NetInfo;
|
|
|
|
NetInfo.cbStructure = sizeof( NetInfo );
|
|
DWORD dwReturn = WNetGetNetworkInformation( lpBuffer->lpProvider, &NetInfo );
|
|
|
|
//
|
|
// Need to shift 16 bits for masks below because their a DWORD starting at the
|
|
// 16th bit and wNetType is a word starting at 0
|
|
//
|
|
if ( !( ( NetInfo.wNetType == ( WNNC_NET_MSNET >> 16)) ||
|
|
( NetInfo.wNetType == ( WNNC_NET_LANMAN >>16) ) ) )
|
|
{
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CHECK_LASTERROR(GetLastError());
|
|
bReturn = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CHECK_LASTERROR(GetLastError());
|
|
bReturn = FALSE;
|
|
}
|
|
|
|
if ((NULL != lpBuffer ) &&
|
|
(&nrOut != lpBuffer)) // let's not free a stack variable, eh?
|
|
{
|
|
LocalFree( lpBuffer );
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Member: CJobFolder::IPersistFolder::Initialize
|
|
//
|
|
// Synopsis: same as IPersistFolder::Initialize
|
|
//
|
|
// History: 1/31/1996 RaviR Created
|
|
//____________________________________________________________________________
|
|
|
|
STDMETHODIMP
|
|
CJobFolder::Initialize(
|
|
LPCITEMIDLIST pidl)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
TRACE(CJobFolder, IPersistFolder::Initialize);
|
|
|
|
m_pidlFldr = ILClone(pidl);
|
|
|
|
if (NULL == m_pidlFldr)
|
|
{
|
|
CHECK_HRESULT(E_OUTOFMEMORY);
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// determine whether we're local or remote
|
|
// for a remote case, the path is always prepended with
|
|
// "\\machinename"
|
|
WCHAR folderPath[MAX_PATH +1];
|
|
|
|
// if IRemoteComputer::Initialize hasn't been called yet, we'll init now
|
|
// we might have \\machinename\c:\windows\tasks
|
|
// or we might have \\machinename::{ugly guid looking thingie}
|
|
if ((m_pszMachine == NULL) && SHGetPathFromIDList(pidl, folderPath) && (0 == wcsncmp(L"\\\\", folderPath,2)))
|
|
{
|
|
WCHAR* p = NULL;
|
|
if (p = wcspbrk(&folderPath[2], L"\\:"))
|
|
{
|
|
*p = L'\0';
|
|
hr = Initialize(folderPath, TRUE);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Member: CJobFolder::GetClassID
|
|
//
|
|
// Synopsis: same as IPersistFolder::GetClassID
|
|
//
|
|
// History: 1/31/1996 RaviR Created
|
|
//____________________________________________________________________________
|
|
|
|
STDMETHODIMP
|
|
CJobFolder::GetClassID(
|
|
LPCLSID lpClassID)
|
|
{
|
|
TRACE(CJobFolder, GetClassID);
|
|
|
|
*lpClassID = CLSID_CJobFolder;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CJobFolder::IPersistFolder2::GetCurFolder
|
|
//
|
|
// Synopsis: Return a copy of the item id list for the current folder.
|
|
//
|
|
// Arguments: [ppidl] - filled with copy of pidl, or NULL on error.
|
|
//
|
|
// Returns: S_OK or E_OUTOFMEMORY
|
|
//
|
|
// Modifies: *[ppidl]
|
|
//
|
|
// History: 12-04-1997 DavidMun Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CJobFolder::GetCurFolder(
|
|
LPITEMIDLIST *ppidl)
|
|
{
|
|
TRACE(CJobFolder, GetCurFolder);
|
|
|
|
*ppidl = ILClone(m_pidlFldr);
|
|
|
|
if (NULL == *ppidl)
|
|
{
|
|
CHECK_HRESULT(E_OUTOFMEMORY);
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// NOTE: if this is being invoked remotely, we assume that IRemoteComputer
|
|
// is invoked *before* IPersistFolder2.
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//____________________________________________________________________________
|
|
//____________________________________________________________________________
|
|
//________________ ___________________________________
|
|
//________________ Interface IDropTarget ___________________________________
|
|
//________________ ___________________________________
|
|
//____________________________________________________________________________
|
|
//____________________________________________________________________________
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Member: CJobFolder::DragEnter
|
|
//
|
|
// Synopsis: same as IDropTarget::DragEnter
|
|
//
|
|
// History: 1/31/1996 RaviR Created
|
|
//____________________________________________________________________________
|
|
|
|
HRESULT
|
|
CJobFolder::DragEnter(
|
|
LPDATAOBJECT pdtobj,
|
|
DWORD grfKeyState,
|
|
POINTL pt,
|
|
DWORD *pdwEffect)
|
|
{
|
|
DEBUG_OUT((DEB_TRACE, "CJobFolder::DragEnter<%x, dwEffect=%x>\n",
|
|
this, *pdwEffect));
|
|
m_grfKeyStateLast = grfKeyState;
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
//
|
|
// Policy - if key TS_KEYPOLICY_DENY_DRAGDROP or DENY_CREATE_TASK
|
|
// then we won't allow this
|
|
//
|
|
|
|
if (RegReadPolicyKey(TS_KEYPOLICY_DENY_DRAGDROP) ||
|
|
RegReadPolicyKey(TS_KEYPOLICY_DENY_CREATE_TASK))
|
|
{
|
|
DEBUG_OUT((DEB_ITRACE, "Policy CREATE_TASK or DRAGDROP active - no copy operations\n"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
if (pdtobj != NULL)
|
|
{
|
|
LPENUMFORMATETC penum;
|
|
HRESULT hr;
|
|
|
|
pdtobj->AddRef();
|
|
|
|
hr = pdtobj->EnumFormatEtc(DATADIR_GET, &penum);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
FORMATETC fmte;
|
|
ULONG celt;
|
|
|
|
while (penum->Next(1, &fmte, &celt) == S_OK)
|
|
{
|
|
if (fmte.cfFormat == CF_HDROP && (fmte.tymed & TYMED_HGLOBAL))
|
|
{
|
|
// The default action is to MOVE the object. If the user
|
|
// has the CONTROL key pressed, then the operation
|
|
// becomes a copy
|
|
|
|
*pdwEffect = DROPEFFECT_MOVE;
|
|
|
|
if (grfKeyState & MK_CONTROL)
|
|
{
|
|
*pdwEffect = DROPEFFECT_COPY;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
penum->Release();
|
|
}
|
|
|
|
pdtobj->Release();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Member: CJobFolder::DragOver
|
|
//
|
|
// Synopsis: same as IDropTarget::DragOver
|
|
//
|
|
// History: 1/31/1996 RaviR Created
|
|
//____________________________________________________________________________
|
|
|
|
HRESULT
|
|
CJobFolder::DragOver(
|
|
DWORD grfKeyState,
|
|
POINTL pt,
|
|
DWORD *pdwEffect)
|
|
{
|
|
DEBUG_OUT((DEB_TRACE, "CJobFolder::DragOver<%x, dwEffect=%d>\n",
|
|
this, *pdwEffect));
|
|
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
//
|
|
// Policy - if we cannot create a task, or have no drag-drop, deny
|
|
// the request
|
|
//
|
|
|
|
if (RegReadPolicyKey(TS_KEYPOLICY_DENY_DRAGDROP) ||
|
|
RegReadPolicyKey(TS_KEYPOLICY_DENY_CREATE_TASK))
|
|
{
|
|
DEBUG_OUT((DEB_ITRACE, "Policy CREATE_TASK or DRAGDROP active - no copy operations\n"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
*pdwEffect = DROPEFFECT_MOVE;
|
|
|
|
if (grfKeyState & MK_CONTROL)
|
|
{
|
|
*pdwEffect = DROPEFFECT_COPY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Member: CJobFolder::DragLeave
|
|
//
|
|
// Synopsis: same as IDropTarget::DragLeave
|
|
//
|
|
// History: 1/31/1996 RaviR Created
|
|
//____________________________________________________________________________
|
|
|
|
HRESULT
|
|
CJobFolder::DragLeave(void)
|
|
{
|
|
TRACE(CJobFolder, DragLeave);
|
|
|
|
return S_OK; // Don't need to do anything here...
|
|
}
|
|
|
|
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Member: CJobFolder::CopyToFolder
|
|
//
|
|
// Synopsis: Performs copy of a job obect passed in to this folder
|
|
//
|
|
// Notes: If policy prevents a copy into this folder, this will
|
|
// return E_FAIL. Callers should check this if necessary.
|
|
//
|
|
// History: 1/31/1996 RaviR Created
|
|
// 4/23/1998 CameronE Modified for policy
|
|
//____________________________________________________________________________
|
|
|
|
HRESULT
|
|
CJobFolder::CopyToFolder(
|
|
LPDATAOBJECT pdtobj,
|
|
BOOL fMove,
|
|
BOOL fDragDrop, // TRUE if called as a result of a dd op.
|
|
POINTL * pPtl) // Valid for a dd op.
|
|
{
|
|
DEBUG_OUT((DEB_USER12, "CJobFolder::CopyToFolder <<----\n"));
|
|
|
|
//
|
|
// Policy - no copying into the folder if DENY_CREATE_TASK is on
|
|
// - no copying via dragdrop, either, if DENY_DRAGDROP is on
|
|
//
|
|
|
|
if (RegReadPolicyKey(TS_KEYPOLICY_DENY_CREATE_TASK) ||
|
|
(fDragDrop && RegReadPolicyKey(TS_KEYPOLICY_DENY_DRAGDROP)))
|
|
{
|
|
DEBUG_OUT((DEB_ITRACE, "Policy CREATE_TASK or DRAGDROP active - no copy operations\n"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
BOOL fIsDropOnSrc = ShellFolderView_IsDropOnSource(m_hwndOwner,
|
|
(IDropTarget*)this);
|
|
|
|
STGMEDIUM medium;
|
|
FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
|
|
HRESULT hr = pdtobj->GetData(&fmte, &medium);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
HDROP hdrop = (HDROP)medium.hGlobal;
|
|
UINT cFiles = DragQueryFile(hdrop, (UINT)-1, NULL, 0);
|
|
BYTE * rglen = NULL;
|
|
LPTSTR pFrom = NULL;
|
|
UINT i;
|
|
BOOL fCreatedJob = FALSE;
|
|
|
|
do
|
|
{
|
|
TCHAR szFileFrom[MAX_PATH+1];
|
|
UINT cchFileFrom = ARRAYSIZE(szFileFrom);
|
|
BOOL fHasASchedObj = fIsDropOnSrc;
|
|
|
|
if (fHasASchedObj == FALSE)
|
|
{
|
|
for (i = 0; i < cFiles; i++)
|
|
{
|
|
DragQueryFile(hdrop, i, szFileFrom, cchFileFrom);
|
|
|
|
if (IsAScheduleObject(szFileFrom) == TRUE)
|
|
{
|
|
fHasASchedObj = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((fDragDrop == TRUE) &&
|
|
(m_grfKeyStateLast & MK_RBUTTON) &&
|
|
(fHasASchedObj == TRUE))
|
|
{
|
|
if (_PopupRBMoveCtx(pPtl->x, pPtl->y, &fMove) == FALSE)
|
|
{
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((fIsDropOnSrc == TRUE) && (fMove == TRUE))
|
|
{
|
|
// We don't handle positioning in the jobs folder.
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Prepare to copy jobs.
|
|
//
|
|
|
|
if (fHasASchedObj == TRUE)
|
|
{
|
|
rglen = new BYTE[cFiles];
|
|
|
|
if (rglen == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
CHECK_HRESULT(hr);
|
|
break;
|
|
}
|
|
|
|
SecureZeroMemory(rglen, cFiles * sizeof(BYTE));
|
|
}
|
|
|
|
UINT cchReqd = 1; // for an extra null char
|
|
|
|
for (i = 0; i < cFiles; i++)
|
|
{
|
|
DragQueryFile(hdrop, i, szFileFrom, cchFileFrom);
|
|
|
|
if ((fIsDropOnSrc == FALSE) &&
|
|
(IsAScheduleObject(szFileFrom) == FALSE))
|
|
{
|
|
hr = CreateAJobForApp(szFileFrom);
|
|
CHECK_HRESULT(hr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
fCreatedJob = TRUE;
|
|
}
|
|
|
|
// continue even if an error occurs
|
|
continue;
|
|
}
|
|
|
|
if (fHasASchedObj == TRUE)
|
|
{
|
|
rglen[i] = lstrlen(szFileFrom) + 1;
|
|
cchReqd += rglen[i];
|
|
}
|
|
}
|
|
|
|
hr = S_OK; // reset CreateAJobForApp might have failed
|
|
|
|
if (fHasASchedObj == FALSE)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pFrom = new TCHAR[cchReqd];
|
|
|
|
if (pFrom == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
CHECK_HRESULT(hr);
|
|
break;
|
|
}
|
|
|
|
LPTSTR pszTemp = pFrom;
|
|
|
|
for (i = 0; i < cFiles; i++)
|
|
{
|
|
if (rglen[i])
|
|
{
|
|
DragQueryFile(hdrop, i, szFileFrom, cchFileFrom);
|
|
|
|
CopyMemory(pszTemp, szFileFrom, rglen[i] * sizeof(TCHAR));
|
|
|
|
pszTemp += rglen[i];
|
|
}
|
|
}
|
|
|
|
// add extra null char
|
|
*pszTemp = TEXT('\0');
|
|
|
|
SHFILEOPSTRUCT fo = {m_hwndOwner, (fMove ? FO_MOVE : FO_COPY),
|
|
pFrom, m_pszFolderPath,
|
|
FOF_ALLOWUNDO | (fIsDropOnSrc ? FOF_RENAMEONCOLLISION : 0),
|
|
FALSE, NULL, NULL};
|
|
|
|
if (SHFileOperation(&fo) || fo.fAnyOperationsAborted)
|
|
{
|
|
hr = E_FAIL;
|
|
CHECK_HRESULT(hr);
|
|
BREAK_ON_FAIL(hr);
|
|
}
|
|
|
|
fCreatedJob = TRUE;
|
|
|
|
//
|
|
// If the drop was on the job folder shortcut, there is nothing
|
|
// else to do here.
|
|
//
|
|
|
|
if (m_hwndOwner == NULL || m_pShellView == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If fIsDropOnSource then this was a copy operation from the source
|
|
// (if it was a move operation we would've already returned), the
|
|
// SHFileOperation has done the rename work for us and will
|
|
// create the files.
|
|
//
|
|
// That will produce a SHCNE_CREATE message for each dropped renamed &
|
|
// copied file. CJobFolder::HandleFsNotify will then do an _AddObject
|
|
// to put them in the UI.
|
|
//
|
|
// So in this case we need to leave before adding a bogus copy
|
|
// ourselves.
|
|
//
|
|
|
|
if (fIsDropOnSrc == TRUE)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Add these items to the foldr & select them.
|
|
//
|
|
|
|
LPITEMIDLIST pidl;
|
|
CJobID jid;
|
|
|
|
// First deselect any selected items
|
|
|
|
LPITEMIDLIST * ppidl;
|
|
|
|
hr = (HRESULT)ShellFolderView_GetSelectedObjects(m_hwndOwner, &ppidl);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
i = ShortFromResult(hr);
|
|
|
|
while (i--)
|
|
{
|
|
m_pShellView->SelectItem(ppidl[i], SVSI_DESELECT);
|
|
}
|
|
|
|
LocalFree(ppidl);
|
|
}
|
|
|
|
|
|
for (i = 0; i < cFiles; i++)
|
|
{
|
|
if (rglen[i])
|
|
{
|
|
DragQueryFile(hdrop, i, szFileFrom, cchFileFrom);
|
|
|
|
LPTSTR pszName = PathFindFileName(szFileFrom);
|
|
|
|
//
|
|
// If a move or copy operation includes objects which collide
|
|
// with objects already in the folder, we need to avoid
|
|
// creating a bogus duplicate in the UI for those objects.
|
|
//
|
|
|
|
if (_ObjectAlreadyPresent(pszName))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
hr = jid.Load(m_pszFolderPath, pszName);
|
|
|
|
BREAK_ON_FAIL(hr);
|
|
|
|
hr = _AddObject(&jid, &pidl);
|
|
|
|
BREAK_ON_FAIL(hr);
|
|
|
|
m_pShellView->SelectItem(pidl, SVSI_SELECT);
|
|
}
|
|
}
|
|
|
|
BREAK_ON_FAIL(hr);
|
|
|
|
} while (0);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
MessageBeep(MB_ICONHAND);
|
|
}
|
|
else if (fCreatedJob)
|
|
{
|
|
//
|
|
// If the drag/drop operation resulted in a new task being added
|
|
// to the tasks folder, prompt the user to start the service
|
|
// if it isn't already running.
|
|
//
|
|
|
|
if (UserCanChangeService(m_pszMachine))
|
|
{
|
|
PromptForServiceStart(m_hwndOwner);
|
|
}
|
|
}
|
|
|
|
// clean up
|
|
delete pFrom;
|
|
delete rglen;
|
|
ReleaseStgMedium(&medium);
|
|
|
|
return S_OK; // Don't need to do anything here...
|
|
}
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Member: CJobFolder::Drop
|
|
//
|
|
// Synopsis: same as IDropTarget::Drop
|
|
//
|
|
// History: 1/31/1996 RaviR Created
|
|
//____________________________________________________________________________
|
|
|
|
HRESULT
|
|
CJobFolder::Drop(
|
|
LPDATAOBJECT pdtobj,
|
|
DWORD grfKeyState,
|
|
POINTL ptl,
|
|
DWORD *pdwEffect)
|
|
{
|
|
DEBUG_OUT((DEB_USER1, "CJobFolder::Drop <<----\n"));
|
|
|
|
*pdwEffect = DROPEFFECT_NONE;
|
|
|
|
//
|
|
// Policy - we should never get here, since we disabled
|
|
// it in DragEnter and DragOver, but just in case
|
|
//
|
|
|
|
if (RegReadPolicyKey(TS_KEYPOLICY_DENY_CREATE_TASK) ||
|
|
RegReadPolicyKey(TS_KEYPOLICY_DENY_DRAGDROP))
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
BOOL fMove = !(grfKeyState & MK_CONTROL);
|
|
|
|
DEBUG_OUT((DEB_USER12, "CJobFolder::Drop <%s>\n", fMove ? "Move" : "Copy"));
|
|
|
|
return CopyToFolder(pdtobj, fMove, TRUE, &ptl);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CJobFolder::_PopupRBMoveCtx(
|
|
LONG x,
|
|
LONG y,
|
|
BOOL * pfMove)
|
|
{
|
|
DEBUG_OUT((DEB_USER1, "CJobFolder::_PopupRBMoveCtx\n"));
|
|
|
|
const TCHAR c_szStatic[] = TEXT("Static");
|
|
int iRet = FALSE;
|
|
|
|
HWND hwndDummy = CreateWindow(c_szStatic, NULL, 0, x, y, 1, 1,
|
|
m_hwndOwner, // HWND_DESKTOP,
|
|
NULL, g_hInstance, NULL);
|
|
if (hwndDummy)
|
|
{
|
|
HWND hwndPrev = GetForegroundWindow(); // to restore
|
|
UINT uFlags = TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN;
|
|
|
|
HMENU popup;
|
|
HMENU subpopup;
|
|
|
|
if (popup = LoadMenu(g_hInstance, MAKEINTRESOURCE(POPUP_RBUTTON_MOVE)))
|
|
{
|
|
subpopup = GetSubMenu(popup, 0);
|
|
|
|
SetForegroundWindow(hwndDummy);
|
|
SetFocus(hwndDummy);
|
|
iRet = TrackPopupMenu(subpopup, uFlags, x, y, 0, hwndDummy, NULL);
|
|
|
|
DestroyMenu(popup);
|
|
}
|
|
else
|
|
return FALSE;
|
|
|
|
if (iRet)
|
|
{
|
|
// non-cancel item is selected. Make the hwndOwner foreground.
|
|
SetForegroundWindow(m_hwndOwner);
|
|
SetFocus(m_hwndOwner);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The user canceled the menu. Restore the previous foreground
|
|
// window (before destroying hwndDummy).
|
|
//
|
|
|
|
if (hwndPrev)
|
|
{
|
|
SetForegroundWindow(hwndPrev);
|
|
}
|
|
}
|
|
|
|
DestroyWindow(hwndDummy);
|
|
}
|
|
|
|
switch (iRet)
|
|
{
|
|
case DDIDM_MOVE:
|
|
*pfMove = TRUE;
|
|
return TRUE;
|
|
|
|
case DDIDM_COPY:
|
|
*pfMove = FALSE;
|
|
return TRUE;
|
|
|
|
case 0:
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Member: CJobFolder::CreateAJobForApp
|
|
//
|
|
// Synopsis: Creates a job for the given app.
|
|
// If (pszApp != 0) job name <- app name with ext changed to job
|
|
// Else job name <- "New Job.job", with rename.
|
|
//
|
|
// Arguments: [pszApp] -- IN
|
|
//
|
|
// Returns: HRESULT
|
|
// --- E_FAIL if policy is on preventing creation. Callers
|
|
// should check this if are contingent on a job being made.
|
|
//
|
|
// History: 4/4/1996 RaviR Created
|
|
//
|
|
//____________________________________________________________________________
|
|
|
|
HRESULT
|
|
CJobFolder::CreateAJobForApp(
|
|
LPCTSTR pszApp)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Policy - if we have the regkey DENY_CREATE_TASK active
|
|
// we cannot permit new jobs to be created via the ui
|
|
//
|
|
|
|
if (RegReadPolicyKey(TS_KEYPOLICY_DENY_CREATE_TASK))
|
|
{
|
|
DEBUG_OUT((DEB_ITRACE, "Policy CREATE_TASK active - no drag-drop or copy/cut/paste\n"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
CJob * pCJob = CJob::Create();
|
|
|
|
if (pCJob == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
CHECK_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
do
|
|
{
|
|
DWORD dwAddFlags = TASK_FLAG_DONT_START_IF_ON_BATTERIES |
|
|
TASK_FLAG_KILL_IF_GOING_ON_BATTERIES;
|
|
|
|
hr = pCJob->SetFlags(dwAddFlags);
|
|
|
|
CHECK_HRESULT(hr);
|
|
BREAK_ON_FAIL(hr);
|
|
|
|
//
|
|
// Create and set a default trigger for ever day at 9:00 AM, with
|
|
// no repetition.
|
|
//
|
|
|
|
TASK_TRIGGER jt;
|
|
SYSTEMTIME stNow;
|
|
|
|
GetSystemTime(&stNow);
|
|
|
|
SecureZeroMemory(&jt, sizeof(jt));
|
|
|
|
jt.cbTriggerSize = sizeof(jt);
|
|
jt.wBeginYear = stNow.wYear;
|
|
jt.wBeginMonth = stNow.wMonth;
|
|
jt.wBeginDay = stNow.wDay;
|
|
jt.TriggerType = TASK_TIME_TRIGGER_DAILY;
|
|
jt.Type.Daily.DaysInterval = 1;
|
|
jt.wStartHour = 9;
|
|
jt.wStartMinute = 0;
|
|
jt.rgFlags = 0;
|
|
|
|
ITaskTrigger * pTrigger = NULL;
|
|
WORD iTrigger = (WORD)-1;
|
|
|
|
hr = pCJob->CreateTrigger(&iTrigger, &pTrigger);
|
|
|
|
CHECK_HRESULT(hr);
|
|
BREAK_ON_FAIL(hr);
|
|
|
|
hr = pTrigger->SetTrigger((const PTASK_TRIGGER)&jt);
|
|
|
|
pTrigger->Release();
|
|
|
|
CHECK_HRESULT(hr);
|
|
BREAK_ON_FAIL(hr);
|
|
|
|
|
|
TCHAR szJob[MAX_PATH+12];
|
|
|
|
StringCchCopy(szJob, MAX_PATH+12, m_pszFolderPath);
|
|
StringCchCat(szJob, MAX_PATH+12, TEXT("\\"));
|
|
|
|
if (pszApp != NULL)
|
|
{
|
|
// set the app name
|
|
|
|
hr = pCJob->SetApplicationName(pszApp);
|
|
|
|
CHECK_HRESULT(hr);
|
|
BREAK_ON_FAIL(hr);
|
|
|
|
// the job name ...
|
|
|
|
StringCchCat(szJob, MAX_PATH+12, PathFindFileName(pszApp));
|
|
|
|
LPTSTR pszExt = PathFindExtension(szJob);
|
|
StringCchCopy(pszExt, MAX_PATH+12 - (pszExt - szJob), TSZ_DOTJOB);
|
|
}
|
|
else
|
|
{
|
|
UINT len = lstrlen(szJob);
|
|
|
|
static int s_nLengthOK = -1;
|
|
|
|
if (s_nLengthOK == -1)
|
|
{
|
|
UINT uiTemp = (UINT)LoadString(g_hInstance, IDS_NEW_JOB,
|
|
&szJob[len], (MAX_PATH + 12 - len));
|
|
|
|
uiTemp += len;
|
|
|
|
if (uiTemp <= MAX_PATH)
|
|
{
|
|
s_nLengthOK = 1;
|
|
}
|
|
else
|
|
{
|
|
s_nLengthOK = 0;
|
|
}
|
|
}
|
|
|
|
if (s_nLengthOK == 0)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
|
CHECK_HRESULT(hr);
|
|
break;
|
|
}
|
|
|
|
LoadString(g_hInstance, IDS_NEW_JOB,
|
|
&szJob[len], (MAX_PATH - len));
|
|
|
|
EnsureUniquenessOfFileName(szJob, MAX_PATH+12);
|
|
|
|
if (lstrlen(szJob) > MAX_PATH)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
|
CHECK_HRESULT(hr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
hr = pCJob->Save(szJob, FALSE);
|
|
|
|
CHECK_HRESULT(hr);
|
|
BREAK_ON_FAIL(hr);
|
|
|
|
//
|
|
// If the drop was on the job folder shortcut, there is nothing
|
|
// else to do here.
|
|
//
|
|
|
|
if (m_hwndOwner == NULL || m_pShellView == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Add the job to the job folder
|
|
//
|
|
|
|
CJobID jid;
|
|
|
|
LPTSTR pszJobName = &szJob[lstrlen(m_pszFolderPath)+1];
|
|
|
|
//*(pszJobName - 1) = TEXT('\0');
|
|
|
|
hr = jid.Load(m_pszFolderPath, pszJobName);
|
|
BREAK_ON_FAIL(hr);
|
|
|
|
hr = _AddObject(&jid);
|
|
BREAK_ON_FAIL(hr);
|
|
|
|
//
|
|
// If this is a new task prompt the user for rename
|
|
//
|
|
|
|
if (pszApp == NULL)
|
|
{
|
|
//
|
|
// Prompt the user to rename the new job.
|
|
//
|
|
|
|
if (m_pShellView != NULL)
|
|
{
|
|
hr = m_pShellView->SelectItem(((LPCITEMIDLIST)&jid), SVSI_EDIT);
|
|
|
|
CHECK_HRESULT(hr);
|
|
}
|
|
}
|
|
|
|
//BREAK_ON_FAIL(hr);
|
|
|
|
} while (0);
|
|
|
|
if (pCJob != NULL)
|
|
{
|
|
pCJob->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
int
|
|
CJobFolder::_GetJobIDForTask(
|
|
PJOBID *ppjid,
|
|
int count,
|
|
LPTSTR pszTask)
|
|
{
|
|
LPTSTR pszExt = PathFindExtension(pszTask);
|
|
TCHAR tcSave;
|
|
|
|
if (pszExt)
|
|
{
|
|
tcSave = *pszExt;
|
|
*pszExt = TEXT('\0');
|
|
}
|
|
|
|
//
|
|
// If the folder is empty, count is 0, so initialize iCmp to -1
|
|
// to force the return statement to indicate there was no match.
|
|
//
|
|
|
|
int iCmp = -1;
|
|
|
|
for (int i=0; i < count; i++)
|
|
{
|
|
#if (DBG == 1)
|
|
ppjid[i]->Validate();
|
|
#endif // (DBG == 1)
|
|
|
|
//
|
|
// Don't compare template (virtual) objects against real files.
|
|
//
|
|
|
|
if (ppjid[i]->IsTemplate())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
iCmp = lstrcmpi(ppjid[i]->GetName(), pszTask);
|
|
|
|
if (iCmp >= 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pszExt)
|
|
{
|
|
*pszExt = tcSave;
|
|
}
|
|
|
|
return (iCmp == 0) ? i : -1;
|
|
}
|
|
|
|
|
|
void hsort(PJOBID *ppjid, UINT cObjs);
|
|
|
|
void I_Sort(PJOBID * ppjid, UINT cObjs)
|
|
{
|
|
UINT i;
|
|
|
|
#if (DBG == 1)
|
|
for (i=0; i < cObjs; i++)
|
|
{
|
|
ppjid[i]->Validate();
|
|
}
|
|
#endif // (DBG == 1)
|
|
|
|
if (cObjs < 10)
|
|
{
|
|
UINT k = 0;
|
|
PJOBID pjid;
|
|
|
|
for (i=1; i < cObjs; i++)
|
|
{
|
|
for (k=i;
|
|
k && (lstrcmpi(ppjid[k]->GetName(), ppjid[k-1]->GetName()) < 0);
|
|
--k)
|
|
{
|
|
pjid = ppjid[k];
|
|
ppjid[k] = ppjid[k-1];
|
|
ppjid[k-1] = pjid;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Heap sort
|
|
hsort(ppjid, cObjs);
|
|
}
|
|
|
|
#if (DBG == 1)
|
|
for (i=0; i < cObjs; i++)
|
|
{
|
|
ppjid[i]->Validate();
|
|
}
|
|
#endif // (DBG == 1)
|
|
}
|
|
|
|
|
|
//____________________________________________________________________________
|
|
//
|
|
// Member: CJobFolder::OnUpdateDir
|
|
//
|
|
// Synopsis: S
|
|
//
|
|
// Returns: void
|
|
//
|
|
// History: 2/20/1996 RaviR Created
|
|
//
|
|
//____________________________________________________________________________
|
|
|
|
void
|
|
CJobFolder::OnUpdateDir(void)
|
|
{
|
|
DEBUG_OUT((DEB_USER1, "CJobFolder::OnUpdateDir <<--\n"));
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// First collect all the itemids from the LPSHELLVIEW
|
|
//
|
|
|
|
int cObjs = (int) ShellFolderView_GetObjectCount(m_hwndOwner);
|
|
|
|
if (m_cObjsAlloced < cObjs)
|
|
{
|
|
// 40 so that it is DWORD aligned
|
|
|
|
m_cObjsAlloced = ((cObjs / 40) + 1) * 40;
|
|
|
|
//
|
|
// Allocate an extra byte per jobid to use with pbPresent flag
|
|
// array. (See below.)
|
|
//
|
|
|
|
DWORD dwBytes = m_cObjsAlloced * (sizeof(PJOBID) + 1);
|
|
|
|
if (m_pUpdateDirData == NULL)
|
|
{
|
|
m_pUpdateDirData = (BYTE *)GlobalAlloc(GPTR, dwBytes);
|
|
}
|
|
else
|
|
{
|
|
|
|
BYTE * pbTemp = (BYTE *)GlobalReAlloc(m_pUpdateDirData,
|
|
dwBytes, GHND);
|
|
|
|
if (pbTemp)
|
|
{
|
|
m_pUpdateDirData = pbTemp;
|
|
}
|
|
else
|
|
{
|
|
GlobalFree(m_pUpdateDirData);
|
|
m_pUpdateDirData = NULL;
|
|
}
|
|
}
|
|
|
|
if (m_pUpdateDirData == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
CHECK_HRESULT(hr);
|
|
|
|
m_cObjsAlloced = 0;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
PPJOBID ppjid = (PPJOBID)m_pUpdateDirData;
|
|
PBYTE pbPresent = m_pUpdateDirData + m_cObjsAlloced * sizeof(PJOBID);
|
|
|
|
SecureZeroMemory(pbPresent, m_cObjsAlloced * sizeof(BYTE));
|
|
|
|
for (int i=0; i < cObjs; i++)
|
|
{
|
|
ppjid[i] = (PJOBID)ShellFolderView_GetObject(m_hwndOwner, i);
|
|
#if (DBG == 1)
|
|
ppjid[i]->Validate();
|
|
#endif
|
|
}
|
|
|
|
I_Sort(ppjid, cObjs);
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
TCHAR szSearchPath[MAX_PATH +1] = TEXT("");
|
|
|
|
StringCchCopy(szSearchPath, MAX_PATH +1, m_pszFolderPath);
|
|
StringCchCat(szSearchPath, MAX_PATH +1, TEXT("\\*") TSZ_DOTJOB);
|
|
|
|
WIN32_FIND_DATA fd;
|
|
HANDLE hFind = FindFirstFile(szSearchPath, &fd);
|
|
|
|
int index;
|
|
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
CJobID jid;
|
|
|
|
while (1)
|
|
{
|
|
index = _GetJobIDForTask(ppjid, cObjs, fd.cFileName);
|
|
|
|
if (index < 0)
|
|
{
|
|
// Add item
|
|
|
|
hr = jid.Load(m_pszFolderPath, fd.cFileName);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
hr = _AddObject(&jid);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FILETIME ftCreate = ppjid[index]->_ftCreation;
|
|
FILETIME ftLastWrite = ppjid[index]->_ftLastWrite;
|
|
if (CompareFileTime(&fd.ftCreationTime,
|
|
&ftCreate) ||
|
|
CompareFileTime(&fd.ftLastWriteTime,
|
|
&ftLastWrite))
|
|
{
|
|
// update job
|
|
DEBUG_OUT((DEB_USER12, "OnUpdateDir::UPDATE_ITEM<%ws>\n",
|
|
fd.cFileName));
|
|
|
|
hr = jid.Load(m_pszFolderPath, fd.cFileName);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
|
|
hr = _UpdateObject(&jid, &jid, &pidl);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ppjid[index] = (PJOBID)pidl;
|
|
}
|
|
|
|
// mark as present
|
|
pbPresent[index] = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// mark as present
|
|
pbPresent[index] = 1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Let us continue even on failure unless it is a memory error
|
|
//
|
|
|
|
if (hr == E_OUTOFMEMORY)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get the next file.
|
|
//
|
|
|
|
if (FindNextFile(hFind, &fd) == FALSE)
|
|
{
|
|
if (GetLastError() != ERROR_NO_MORE_FILES)
|
|
{
|
|
CHECK_LASTERROR(GetLastError());
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
FindClose(hFind);
|
|
|
|
//
|
|
// Let us continue even on failure unless it is a memory error
|
|
//
|
|
|
|
if (hr != E_OUTOFMEMORY)
|
|
{
|
|
//
|
|
// Now delete any old items that are no longer valid, making
|
|
// sure to ignore the template object.
|
|
//
|
|
|
|
for (i=0; i < cObjs; i++)
|
|
{
|
|
if (!pbPresent[i] && !ppjid[i]->IsTemplate())
|
|
{
|
|
// Delete object
|
|
_RemoveObject(ppjid[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GetLastError() != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
CHECK_LASTERROR(GetLastError());
|
|
}
|
|
else if (GetLastError() != ERROR_NO_MORE_FILES)
|
|
{
|
|
// delete everything but template objects
|
|
|
|
for (i=0; i < cObjs; i++)
|
|
{
|
|
if (!ppjid[i]->IsTemplate())
|
|
{
|
|
_RemoveObject(ppjid[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hr == E_OUTOFMEMORY)
|
|
{
|
|
// Display error message
|
|
}
|
|
|
|
DEBUG_OUT((DEB_USER1, "CJobFolder::OnUpdateDir -->>\n"));
|
|
|
|
return;
|
|
}
|