306 lines
8.6 KiB
C++
306 lines
8.6 KiB
C++
//
|
|
// Copy Hook Handler for CDFView shell extension
|
|
//
|
|
// Description:
|
|
// This object installs an ICopyHook handler that traps all
|
|
// copies/movies/renames in the shell so that we can special
|
|
// case links to channel objects and unsubscribe them when
|
|
// the link is deleted. The implementation is in shdocvw for
|
|
// speed.
|
|
//
|
|
// julianj 6/16/97
|
|
//
|
|
|
|
#include "priv.h"
|
|
#include "sccls.h"
|
|
#include "chanmgr.h"
|
|
#include "channel.h"
|
|
#include "../resource.h"
|
|
|
|
#include <mluisupp.h>
|
|
|
|
class CCDFCopyHook
|
|
: public ICopyHookA
|
|
, public ICopyHookW
|
|
{
|
|
public:
|
|
|
|
// *** IUnknown ***
|
|
STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
|
|
STDMETHODIMP_(ULONG) AddRef(void);
|
|
STDMETHODIMP_(ULONG) Release(void);
|
|
|
|
// *** ICopyHookA method ***
|
|
STDMETHODIMP_(UINT) CopyCallback(HWND hwnd,
|
|
UINT wFunc, UINT wFlags, LPCSTR pszSrcFile, DWORD dwSrcAttribs, LPCSTR pszDestFile, DWORD dwDestAttribs);
|
|
|
|
// *** ICopyHookW method ***
|
|
STDMETHODIMP_(UINT) CopyCallback(HWND hwnd,
|
|
UINT wFunc, UINT wFlags, LPCWSTR pwzSrcFile, DWORD dwSrcAttribs, LPCWSTR pwzDestFile, DWORD dwDestAttribs);
|
|
|
|
private:
|
|
CCDFCopyHook( HRESULT * pHr);
|
|
~CCDFCopyHook();
|
|
|
|
BOOL IsSubscriptionFolder(LPCTSTR pszPath);
|
|
|
|
LONG m_cRef;
|
|
|
|
friend HRESULT CCDFCopyHook_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi); // for ctor
|
|
};
|
|
|
|
//The copyhook handler uses this function
|
|
|
|
HRESULT Channel_GetFolder(LPTSTR pszPath, int cchPath)
|
|
{
|
|
TCHAR szChannel[MAX_PATH];
|
|
TCHAR szFav[MAX_PATH];
|
|
ULONG cbChannel = sizeof(szChannel);
|
|
|
|
if (SHGetSpecialFolderPath(NULL, szFav, CSIDL_FAVORITES, TRUE))
|
|
{
|
|
//
|
|
// Get the potentially localized name of the Channel folder from the
|
|
// registry if it is there. Otherwise just read it from the resource.
|
|
// Then tack this on the favorites path.
|
|
//
|
|
|
|
if (ERROR_SUCCESS != SHRegGetUSValue(L"Software\\Microsoft\\Windows\\CurrentVersion",
|
|
L"ChannelFolderName", NULL, (void*)szChannel,
|
|
&cbChannel, TRUE, NULL, 0))
|
|
{
|
|
MLLoadString(IDS_CHANNEL, szChannel, ARRAYSIZE(szChannel));
|
|
}
|
|
|
|
PathCombine(pszPath, szFav, szChannel);
|
|
|
|
//
|
|
// For IE5+ use the channels dir if it exists - else use favorites
|
|
//
|
|
if (!PathFileExists(pszPath))
|
|
StrCpyN(pszPath, szFav, cchPath);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
//
|
|
// Basic CreateInstance for this object
|
|
//
|
|
HRESULT CCDFCopyHook_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
|
|
{
|
|
if ( pUnkOuter )
|
|
return CLASS_E_NOAGGREGATION;
|
|
|
|
HRESULT hr = NOERROR;
|
|
CCDFCopyHook * pCDFCopyHook = new CCDFCopyHook( & hr );
|
|
if ( !pCDFCopyHook )
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
if ( FAILED( hr ))
|
|
{
|
|
delete pCDFCopyHook;
|
|
return hr;
|
|
}
|
|
|
|
*ppunk = SAFECAST(pCDFCopyHook, ICopyHookA *);
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CCDFCopyHook::QueryInterface( REFIID riid, LPVOID * ppvObj )
|
|
{
|
|
if (IsEqualIID(riid, IID_IUnknown) ||
|
|
IsEqualIID(riid, IID_IShellCopyHookA))
|
|
{
|
|
*ppvObj = SAFECAST(this, ICopyHookA *);
|
|
}
|
|
else if (IsEqualIID(riid, IID_IShellCopyHookW))
|
|
{
|
|
*ppvObj = SAFECAST(this, ICopyHookW *);
|
|
}
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP_ (ULONG) CCDFCopyHook::AddRef()
|
|
{
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
STDMETHODIMP_ (ULONG) CCDFCopyHook::Release()
|
|
{
|
|
if (InterlockedDecrement(&m_cRef))
|
|
return m_cRef;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
CCDFCopyHook::CCDFCopyHook( HRESULT * pHr) : m_cRef(1)
|
|
{
|
|
*pHr = S_OK;
|
|
DllAddRef();
|
|
}
|
|
|
|
CCDFCopyHook::~CCDFCopyHook()
|
|
{
|
|
DllRelease();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ICopyHookA::CopyCallback
|
|
//
|
|
// Either allows the shell to move, copy, delete, or rename a folder or printer
|
|
// object, or disallows the shell from carrying out the operation. The shell
|
|
// calls each copy hook handler registered for a folder or printer object until
|
|
// either all the handlers have been called or one of them returns IDCANCEL.
|
|
//
|
|
// RETURNS:
|
|
//
|
|
// IDYES - Allows the operation.
|
|
// IDNO - Prevents the operation on this file, but continues with any other
|
|
// operations (for example, a batch copy operation).
|
|
// IDCANCEL - Prevents the current operation and cancels any pending operations
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
UINT CCDFCopyHook::CopyCallback(
|
|
HWND hwnd, // Handle of the parent window for displaying UI objects
|
|
UINT wFunc, // Operation to perform.
|
|
UINT wFlags, // Flags that control the operation
|
|
LPCSTR pszSrcFile, // Pointer to the source file
|
|
DWORD dwSrcAttribs, // Source file attributes
|
|
LPCSTR pszDestFile, // Pointer to the destination file
|
|
DWORD dwDestAttribs // Destination file attributes
|
|
)
|
|
{
|
|
WCHAR szSrcFile[MAX_PATH];
|
|
WCHAR szDestFile[MAX_PATH];
|
|
|
|
AnsiToUnicode(pszSrcFile, szSrcFile, ARRAYSIZE(szSrcFile));
|
|
|
|
if (pszDestFile) // shell32.dll can call with NULL for pszDestFile
|
|
AnsiToUnicode(pszDestFile, szDestFile, ARRAYSIZE(szDestFile));
|
|
else
|
|
szDestFile[0] = L'\0';
|
|
|
|
return CopyCallback(hwnd, wFunc, wFlags, szSrcFile, dwSrcAttribs, szSrcFile, dwDestAttribs);
|
|
}
|
|
|
|
|
|
CCDFCopyHook::IsSubscriptionFolder(LPCTSTR pszPath)
|
|
{
|
|
TCHAR szSubsPath[MAX_PATH] = {0};
|
|
DWORD dwSize = SIZEOF(szSubsPath);
|
|
|
|
if (SHGetValueGoodBoot(HKEY_LOCAL_MACHINE, REGSTR_PATH_SUBSCRIPTION,
|
|
REGSTR_VAL_DIRECTORY, NULL, (LPBYTE)szSubsPath, &dwSize) != ERROR_SUCCESS)
|
|
{
|
|
TCHAR szWindows[MAX_PATH];
|
|
|
|
GetWindowsDirectory(szWindows, ARRAYSIZE(szWindows));
|
|
PathCombine(szSubsPath, szWindows, TEXT("Offline Web Pages"));
|
|
}
|
|
|
|
return 0 == StrCmpI(pszPath, szSubsPath);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ICopyHookW::CopyCallback
|
|
//
|
|
// Currently we just thunk to the ansi version.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
UINT CCDFCopyHook::CopyCallback(
|
|
HWND hwnd, // Handle of the parent window for displaying UI objects
|
|
UINT wFunc, // Operation to perform.
|
|
UINT wFlags, // Flags that control the operation
|
|
LPCWSTR pszSrcFile, // Pointer to the source file
|
|
DWORD dwSrcAttribs, // Source file attributes
|
|
LPCWSTR pszDestFile, // Pointer to the destination file
|
|
DWORD dwDestAttribs // Destination file attributes
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
ICopyHookA * pCDFViewCopyHookA;
|
|
TCHAR szPath[MAX_PATH];
|
|
|
|
//
|
|
// Return immediately if this isn't a system folder or if isn't a delete or
|
|
// rename operation
|
|
//
|
|
if (!(wFunc == FO_DELETE || wFunc == FO_RENAME))
|
|
{
|
|
return IDYES;
|
|
}
|
|
|
|
// no rename of channels folder allowed.
|
|
if ((wFunc == FO_RENAME)
|
|
&& (Channel_GetFolder(szPath, ARRAYSIZE(szPath)) == S_OK)
|
|
&& (StrCmpI(szPath, pszSrcFile) == 0))
|
|
{
|
|
MessageBeep(MB_OK);
|
|
return IDNO;
|
|
}
|
|
|
|
if (SHRestricted2W(REST_NoRemovingSubscriptions, NULL, 0) &&
|
|
IsSubscriptionFolder(pszSrcFile))
|
|
{
|
|
MessageBeep(MB_OK);
|
|
return IDNO;
|
|
}
|
|
|
|
if (!(dwSrcAttribs & FILE_ATTRIBUTE_SYSTEM))
|
|
return IDYES;
|
|
//
|
|
// REVIEW could check for guid in desktop.ini matching CDFVIEW but its
|
|
// cleaner to have the ChannelMgr know about that
|
|
//
|
|
|
|
//
|
|
// Create the channel manager object and ask it for the copy hook iface
|
|
//
|
|
hr = CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IShellCopyHookA, (void**)&pCDFViewCopyHookA);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Delegate to the Copy hook handler in the channel mgr
|
|
//
|
|
CHAR szSrcFile[MAX_PATH];
|
|
CHAR szDestFile[MAX_PATH] = {'\0'};
|
|
|
|
SHUnicodeToAnsi(pszSrcFile, szSrcFile, ARRAYSIZE(szSrcFile));
|
|
|
|
if (pszDestFile)
|
|
SHUnicodeToAnsi(pszDestFile, szDestFile, ARRAYSIZE(szDestFile));
|
|
|
|
UINT retValue = pCDFViewCopyHookA->CopyCallback(
|
|
hwnd, wFunc, wFlags, szSrcFile,
|
|
dwSrcAttribs, szDestFile, dwDestAttribs);
|
|
|
|
pCDFViewCopyHookA->Release();
|
|
|
|
return retValue;
|
|
}
|
|
else
|
|
{
|
|
// Couldn't create ChannelMgr object for some reason
|
|
TraceMsg(TF_ERROR, "Could not CoCreateInstance CLSID_ChannelMgr");
|
|
return IDYES;
|
|
}
|
|
}
|
|
|
|
|