Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

506 lines
17 KiB

#include "shellprv.h"
#pragma hdrstop
#include "copy.h"
int PathCopyHookCallback(HWND hwnd, UINT wFunc, LPCTSTR pszSrc, LPCTSTR pszDest);
void _CopyHookTerminate(HDSA *phdsaCopyHooks, BOOL fProcessDetach);
typedef struct _CALLABLECOPYHOOK {
LPCOPYHOOK pcphk; // Either LPCOPYHOOKA or LPCOPYHOOK
BOOL fAnsiCrossOver; // TRUE for LPCOPYHOOKA on UNICODE build
} CALLABLECOPYHOOK, *LPCALLABLECOPYHOOK;
//========================================================================
// CCopyHook Class definition
//========================================================================
typedef struct _CCopyHook // dxi
{
ICopyHook cphk;
#ifdef UNICODE
ICopyHookA cphkA;
#endif
UINT cRef;
} CShellCopyHook, FAR* LPSHELLCOPYHOOK;
//========================================================================
// CShellCopyHook Member function prototypes
//========================================================================
STDMETHODIMP CShellCopyHook_QueryInterface(LPCOPYHOOK pcphk, REFIID riid, LPVOID FAR* ppvObj);
STDMETHODIMP_(ULONG) CShellCopyHook_AddRef(LPCOPYHOOK pcphk);
STDMETHODIMP_(ULONG) CShellCopyHook_Release(LPCOPYHOOK pcphk);
STDMETHODIMP_(UINT) CShellCopyHook_CopyCallback(LPCOPYHOOK pcphk, HWND hwnd, UINT wFunc, UINT wFlags, LPCTSTR pszSrcFile, DWORD dwSrcAttribs,
LPCTSTR pszDestFile, DWORD dwDestAttribs);
//========================================================================
// CShellCopyHook Vtable
//========================================================================
ICopyHookVtbl c_CShellCopyHookVtbl = {
CShellCopyHook_QueryInterface,
CShellCopyHook_AddRef,
CShellCopyHook_Release,
CShellCopyHook_CopyCallback,
};
#ifdef UNICODE
//========================================================================
// CShellCopyHook Member function prototypes
//========================================================================
STDMETHODIMP CShellCopyHookA_QueryInterface(LPCOPYHOOKA pcphk, REFIID riid, LPVOID FAR* ppvObj);
STDMETHODIMP_(ULONG) CShellCopyHookA_AddRef(LPCOPYHOOKA pcphk);
STDMETHODIMP_(ULONG) CShellCopyHookA_Release(LPCOPYHOOKA pcphk);
STDMETHODIMP_(UINT) CShellCopyHookA_CopyCallback(LPCOPYHOOKA pcphk,
HWND hwnd, UINT wFunc, UINT wFlags,
LPCSTR pszSrcFile, DWORD dwSrcAttribs,
LPCSTR pszDestFile, DWORD dwDestAttribs);
//========================================================================
// CShellCopyHook Vtable
//========================================================================
ICopyHookAVtbl c_CShellCopyHookAVtbl = {
CShellCopyHookA_QueryInterface,
CShellCopyHookA_AddRef,
CShellCopyHookA_Release,
CShellCopyHookA_CopyCallback,
};
#endif
//========================================================================
// CShellCopyHook constructor
//========================================================================
STDAPI SHCreateShellCopyHook(LPCOPYHOOK FAR* pcphkOut, REFIID riid)
{
HRESULT hres = ResultFromScode(E_OUTOFMEMORY); // assume error;
LPSHELLCOPYHOOK pcphk;
pcphk = (void*)LocalAlloc(LPTR, SIZEOF(CShellCopyHook));
if (pcphk)
{
pcphk->cphk.lpVtbl = &c_CShellCopyHookVtbl;
#ifdef UNICODE
pcphk->cphkA.lpVtbl = &c_CShellCopyHookAVtbl;
#endif
pcphk->cRef = 1;
hres = CShellCopyHook_QueryInterface(&pcphk->cphk, riid, pcphkOut);
CShellCopyHook_Release(&pcphk->cphk);
}
return hres;
}
HRESULT CALLBACK CShellCopyHook_CreateInstance(LPUNKNOWN punkOuter, REFIID riid, LPVOID * ppvOut)
{
Assert(punkOuter == NULL);
return(SHCreateShellCopyHook((LPCOPYHOOK *)ppvOut, riid));
}
//========================================================================
// CShellCopyHook members
//========================================================================
STDMETHODIMP CShellCopyHook_QueryInterface(LPCOPYHOOK pcphk, REFIID riid,
LPVOID FAR* ppvObj)
{
LPSHELLCOPYHOOK this = IToClass(CShellCopyHook, cphk, pcphk);
if (IsEqualIID(riid, &IID_IShellCopyHook)
|| IsEqualIID(riid, &IID_IUnknown))
{
*ppvObj = pcphk;
this->cRef++;
return NOERROR;
}
#ifdef UNICODE
else if (IsEqualIID(riid, &IID_IShellCopyHookA))
{
*ppvObj = &this->cphkA;
this->cRef++;
return NOERROR;
}
#endif
*ppvObj = NULL;
return(ResultFromScode(E_NOINTERFACE));
}
STDMETHODIMP_(ULONG) CShellCopyHook_AddRef(LPCOPYHOOK pcphk)
{
LPSHELLCOPYHOOK this = IToClass(CShellCopyHook, cphk, pcphk);
this->cRef++;
return this->cRef;
}
STDMETHODIMP_(ULONG) CShellCopyHook_Release(LPCOPYHOOK pcphk)
{
LPSHELLCOPYHOOK this = IToClass(CShellCopyHook, cphk, pcphk);
this->cRef--;
if (this->cRef > 0)
{
return this->cRef;
}
LocalFree((HLOCAL)this);
return 0;
}
STDMETHODIMP_(UINT) CShellCopyHook_CopyCallback(LPCOPYHOOK pcphk, HWND hwnd,
UINT wFunc, UINT wFlags,
LPCTSTR pszSrcFile,
DWORD dwSrcAttribs,
LPCTSTR pszDestFile,
DWORD dwDestAttribs)
{
extern UINT DefView_CopyHook(const COPYHOOKINFO *pchi);
UINT idRet;
COPYHOOKINFO chi = { hwnd, wFunc, wFlags,
pszSrcFile, dwSrcAttribs,
pszDestFile, dwDestAttribs };
DebugMsg(DM_TRACE, TEXT("Event = %d, File = %s , %s"), wFunc, pszSrcFile,
pszDestFile ? pszDestFile : 0);
// First try see source path is in the list...
if (wFunc != FO_COPY && !(wFlags & FOF_NOCONFIRMATION))
{
TCHAR szShortName[MAX_PATH];
BOOL fInReg;
BOOL fInBitBucket;
UINT iLength;
fInReg = (RLIsPathInList(pszSrcFile) != -1);
fInBitBucket = IsFileInBitBucket(pszSrcFile);
iLength = GetShortPathName(pszSrcFile, szShortName, ARRAYSIZE(szShortName));
// Don't double search for names that are the same (or already found)
if (iLength != 0 && lstrcmpi(pszSrcFile, szShortName) != 0)
{
if (!fInReg)
fInReg = (RLIsPathInList(szShortName) != -1);
if (!fInBitBucket)
fInBitBucket = IsFileInBitBucket(szShortName);
}
if (fInReg && !fInBitBucket)
{
// Move to resource
return ShellMessageBox(HINST_THISDLL, hwnd,
MAKEINTRESOURCE(IDS_RENAMEFILESINREG),
pszSrcFile, MB_YESNO | MB_ICONEXCLAMATION);
}
}
idRet = DefView_CopyHook(&chi);
if (idRet!=IDYES) {
return idRet;
}
// REVIEW: this should be moved to the network dll.
return PathCopyHookCallback(hwnd, wFunc, pszSrcFile, pszDestFile);
}
#ifdef UNICODE
//========================================================================
// CShellCopyHookA members
//========================================================================
STDMETHODIMP CShellCopyHookA_QueryInterface(LPCOPYHOOKA pcphkA, REFIID riid,
LPVOID FAR* ppvObj)
{
LPSHELLCOPYHOOK this = IToClass(CShellCopyHook, cphkA, pcphkA);
return CShellCopyHook_QueryInterface(&this->cphk,riid,ppvObj);
}
STDMETHODIMP_(ULONG) CShellCopyHookA_AddRef(LPCOPYHOOKA pcphkA)
{
LPSHELLCOPYHOOK this = IToClass(CShellCopyHook, cphkA, pcphkA);
return CShellCopyHook_AddRef(&this->cphk);
}
STDMETHODIMP_(ULONG) CShellCopyHookA_Release(LPCOPYHOOKA pcphkA)
{
LPSHELLCOPYHOOK this = IToClass(CShellCopyHook, cphkA, pcphkA);
return CShellCopyHook_Release(&this->cphk);
}
STDMETHODIMP_(UINT) CShellCopyHookA_CopyCallback(LPCOPYHOOKA pcphkA, HWND hwnd,
UINT wFunc, UINT wFlags,
LPCSTR pszSrcFile,
DWORD dwSrcAttribs,
LPCSTR pszDestFile,
DWORD dwDestAttribs)
{
WCHAR szSrcFileW[MAX_PATH];
WCHAR szDestFileW[MAX_PATH];
LPWSTR pszSrcFileW = NULL;
LPWSTR pszDestFileW = NULL;
LPSHELLCOPYHOOK this = IToClass(CShellCopyHook, cphkA, pcphkA);
if (pszSrcFile)
{
MultiByteToWideChar(CP_ACP, 0,
pszSrcFile, -1,
szSrcFileW, ARRAYSIZE(szSrcFileW));
pszSrcFileW = szSrcFileW;
}
if (pszDestFile)
{
MultiByteToWideChar(CP_ACP, 0,
pszDestFile, -1,
szDestFileW, ARRAYSIZE(szDestFileW));
pszDestFileW = szDestFileW;
}
return CShellCopyHook_CopyCallback(&this->cphk, hwnd, wFunc, wFlags,
pszSrcFileW, dwSrcAttribs,
pszDestFileW, dwDestAttribs);
}
#endif
///// here we actually use the hook...
BOOL CopyHookInitialize(HDSA *phdsaCopyHooks, LPCTSTR lpszSubKey)
{
HKEY hk;
TCHAR szKey[128];
TCHAR szValue[128];
int i;
LONG cb;
BOOL bRet = TRUE;
HDSA hdsaCopyHooks;
// Note that we check *phdsaCopyHooks again in case we were in the middle
// of initializing it when we checked it before entering this function
if (*phdsaCopyHooks)
{
goto Exit;
}
hdsaCopyHooks = DSA_Create(SIZEOF(CALLABLECOPYHOOK), 4);
if (!hdsaCopyHooks)
{
bRet = FALSE;
goto Exit;
}
if (RegOpenKey(HKEY_CLASSES_ROOT, lpszSubKey, &hk) == ERROR_SUCCESS) {
HRESULT hres;
CALLABLECOPYHOOK cc;
IUnknown *punk;
// iterate through the subkeys
for (i = 0; RegEnumKey(hk, i, szKey, ARRAYSIZE(szKey)) == ERROR_SUCCESS; ++i) {
cb = SIZEOF(szValue);
// for each subkey, get the class id and do a cocreateinstance
if (RegQueryValue(hk, (LPTSTR)szKey, szValue, &cb) == ERROR_SUCCESS) {
hres =SHCoCreateInstance(szValue, NULL, NULL, &IID_IUnknown, &punk);
if (SUCCEEDED(hres)) {
cc.pcphk = NULL;
cc.fAnsiCrossOver = FALSE;
hres = punk->lpVtbl->QueryInterface(punk,&IID_IShellCopyHook,&cc.pcphk);
if (SUCCEEDED(hres))
{
DSA_InsertItem(hdsaCopyHooks, 0x7FFF, &cc);
}
#ifdef UNICODE
else
{
hres = punk->lpVtbl->QueryInterface(punk,&IID_IShellCopyHookA,&cc.pcphk);
if (SUCCEEDED(hres))
{
cc.fAnsiCrossOver = TRUE;
DSA_InsertItem(hdsaCopyHooks, 0x7FFF, &cc);
}
}
#endif
punk->lpVtbl->Release(punk);
}
}
}
}
// Note that we do not fill in *phdsaCopyHooks until we have finished
// initializing it, so if any other thread sees it as non-NULL, it will
// be guaranteed to be initialized and we will not need to enter the
// critical section. If another thread sees it as NULL, we check it
// again inside the critical section to let other threads finish.
if (*phdsaCopyHooks == NULL)
{
ENTERCRITICAL;
if (*phdsaCopyHooks == NULL)
{
*phdsaCopyHooks = hdsaCopyHooks;
hdsaCopyHooks = NULL; // Indicate that we used it.
}
LEAVECRITICAL;
}
//
// If we did not use this hdsa (because it is already initialized
// by another thread), destroy it.
//
if (hdsaCopyHooks)
{
_CopyHookTerminate(&hdsaCopyHooks, FALSE);
}
Exit:
return bRet;
}
int CallCopyHooks(HDSA *phdsaCopyHooks, LPCTSTR lpszSubKey,
HWND hwnd, UINT wFunc, FILEOP_FLAGS fFlags,
LPCTSTR pszSrcFile, DWORD dwSrcAttribs,
LPCTSTR pszDestFile, DWORD dwDestAttribs)
{
LPCALLABLECOPYHOOK pcc;
int i;
int iReturn;
HDSA hdsaCopyHooks;
if (!*phdsaCopyHooks && !CopyHookInitialize(phdsaCopyHooks, lpszSubKey))
return IDYES;
hdsaCopyHooks = *phdsaCopyHooks;
for (i = DSA_GetItemCount(hdsaCopyHooks) - 1; i >= 0; i--) {
pcc = (LPCALLABLECOPYHOOK)DSA_GetItemPtr(hdsaCopyHooks, i);
#ifdef UNICODE
if (!pcc->fAnsiCrossOver)
{
#endif
iReturn = pcc->pcphk->lpVtbl->CopyCallback(pcc->pcphk,
hwnd, wFunc, fFlags,
pszSrcFile, dwSrcAttribs,
pszDestFile, dwDestAttribs);
#ifdef UNICODE
}
else
{
CHAR szSrcFileA[MAX_PATH];
CHAR szDestFileA[MAX_PATH];
LPSTR pszSrcFileA = NULL;
LPSTR pszDestFileA = NULL;
LPCOPYHOOKA pcphkA = (LPCOPYHOOKA)pcc->pcphk;
if (pszSrcFile)
{
WideCharToMultiByte(CP_ACP, 0,
pszSrcFile, -1,
szSrcFileA, ARRAYSIZE(szSrcFileA),
NULL, NULL);
pszSrcFileA = szSrcFileA;
}
if (pszDestFile)
{
WideCharToMultiByte(CP_ACP, 0,
pszDestFile, -1,
szDestFileA, ARRAYSIZE(szDestFileA),
NULL, NULL);
pszDestFileA = szDestFileA;
}
iReturn = pcphkA->lpVtbl->CopyCallback(pcphkA,
hwnd, wFunc, fFlags,
pszSrcFileA, dwSrcAttribs,
pszDestFileA, dwDestAttribs);
}
#endif
if (iReturn != IDYES) {
return iReturn;
}
}
return IDYES;
}
// These need to be per-instance since we are storing interfaces pointers
#pragma data_seg(DATASEG_PERINSTANCE)
HDSA g_hdsaFileCopyHooks = NULL;
HDSA g_hdsaPrinterCopyHooks = NULL;
#pragma data_seg()
const TCHAR c_szSTRREG_SHEX_COPYHOOK[] = STRREG_SHEX_COPYHOOK;
const TCHAR c_szSTRREG_SHEX_PRNCOPYHOOK[] = STRREG_SHEX_PRNCOPYHOOK;
int CallFileCopyHooks(HWND hwnd, UINT wFunc, FILEOP_FLAGS fFlags,
LPCTSTR pszSrcFile, DWORD dwSrcAttribs,
LPCTSTR pszDestFile, DWORD dwDestAttribs)
{
return(CallCopyHooks(&g_hdsaFileCopyHooks, c_szSTRREG_SHEX_COPYHOOK,
hwnd, wFunc, fFlags,
pszSrcFile, dwSrcAttribs, pszDestFile,
dwDestAttribs));
}
int CallPrinterCopyHooks(HWND hwnd, UINT wFunc, PRINTEROP_FLAGS fFlags,
LPCTSTR pszSrcPrinter, DWORD dwSrcAttribs,
LPCTSTR pszDestPrinter, DWORD dwDestAttribs)
{
DebugMsg(DM_TRACE,TEXT("sh TR - CallPrinterCopyHook(%x)"), wFunc);
return(CallCopyHooks(&g_hdsaPrinterCopyHooks, c_szSTRREG_SHEX_PRNCOPYHOOK,
hwnd, wFunc, fFlags,
pszSrcPrinter, dwSrcAttribs, pszDestPrinter,
dwDestAttribs));
}
//
// We will only call this on process detach, and these are per-process
// globals, so we do not need a critical section here
//
// This function is also called from CopyHookInitialize when the second
// thread is cleaning up its local hdsaCopyHoos, which does not require
// a critical section either.
//
void _CopyHookTerminate(HDSA *phdsaCopyHooks, BOOL fProcessDetach)
{
LPCALLABLECOPYHOOK pcc;
int i;
HDSA hdsaCopyHooks = *phdsaCopyHooks;
*phdsaCopyHooks = NULL;
if (!hdsaCopyHooks)
{
return;
}
//
// Note that we must no call any of virtual functions when we are
// processing PROCESS_DETACH signal, because the DLL might have been
// already unloaded before shell32. We just hope that they don't
// allocate any global thing to be cleaned. USER does the same thing
// with undestroyed window. It does not send call its window procedure
// when it is destroying an undestroyed window within its PROCESS_DETACH
// code. (SatoNa/DavidDS)
//
if (!fProcessDetach)
{
for (i = DSA_GetItemCount(hdsaCopyHooks) - 1; i >= 0; i--) {
pcc = (LPCALLABLECOPYHOOK)DSA_GetItemPtr(hdsaCopyHooks, i);
pcc->pcphk->lpVtbl->Release(pcc->pcphk);
}
}
DSA_Destroy(hdsaCopyHooks);
}
void CopyHooksTerminate(void)
{
if (g_hdsaFileCopyHooks)
_CopyHookTerminate(&g_hdsaFileCopyHooks, TRUE);
if (g_hdsaPrinterCopyHooks)
_CopyHookTerminate(&g_hdsaPrinterCopyHooks, TRUE);
}