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.
 
 
 
 
 
 

734 lines
18 KiB

/*
* drop.cpp - IDropTarget implementation for MSMosaic.
*/
/* Headers
**********/
#include "project.hpp"
#pragma hdrstop
#include "dataobjm.h"
#include "drag.h"
#include "drop.h"
/* Types
********/
/* clipboard formats supported by dropped data object */
typedef enum drop_cf_flags
{
DROP_CF_FL_HDROP = 0x0001,
DROP_CF_FL_URL = 0x0002,
ALL_DROP_CF_FLAGS = (DROP_CF_FL_HDROP |
DROP_CF_FL_URL)
}
DROP_CF_FLAGS;
/* Classes
**********/
class MosaicDropTarget : private RefCount,
public IDropTarget
{
private:
HWND m_hwnd;
PIDataObject m_pido;
DWORD m_dwLastKeyState;
DWORD m_dwLastEffect;
public:
MosaicDropTarget(HWND hwnd);
~MosaicDropTarget(void);
// IDropTarget methods
HRESULT STDMETHODCALLTYPE DragEnter(PIDataObject pido, DWORD dwKeyState, POINTL pt, PDWORD pdwEffect);
HRESULT STDMETHODCALLTYPE DragOver(DWORD dwKeyState, POINTL pt, PDWORD pdwEffect);
HRESULT STDMETHODCALLTYPE DragLeave(void);
HRESULT STDMETHODCALLTYPE Drop(PIDataObject pido, DWORD dwKeyState, POINTL pt, PDWORD pdwEffect);
// IUnknown methods
ULONG STDMETHODCALLTYPE AddRef(void);
ULONG STDMETHODCALLTYPE Release(void);
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *ppvObj);
// other methods
void STDMETHODCALLTYPE ClearDropMembers(void);
// friends
#ifdef DEBUG
friend BOOL IsValidPCMosaicDropTarget(const MosaicDropTarget *pcmdt);
#endif
};
DECLARE_STANDARD_TYPES(MosaicDropTarget);
/***************************** Private Functions *****************************/
PRIVATE_CODE DWORD DetermineDefaultDropEffect(DWORD dwDropEffect)
{
DWORD dwDefDropEffect;
ASSERT(FLAGS_ARE_VALID(dwDropEffect, ALL_DROPEFFECT_FLAGS));
if (IS_FLAG_SET(dwDropEffect, DROPEFFECT_COPY))
dwDefDropEffect = DROPEFFECT_COPY;
else if (IS_FLAG_SET(dwDropEffect, DROPEFFECT_LINK))
dwDefDropEffect = DROPEFFECT_LINK;
else
dwDefDropEffect = DROPEFFECT_NONE;
ASSERT(FLAGS_ARE_VALID(dwDefDropEffect, ALL_DROPEFFECT_FLAGS));
TRACE_OUT(("DetermineDefaultDropEffect()=0x%lx",dwDefDropEffect));
return(dwDefDropEffect);
}
PRIVATE_CODE HRESULT DetermineDropEffect(HWND hwnd, PIDataObject pido,
DWORD dwKeyState, POINTL pt,
PDWORD pdwEffect,
PDWORD pdwDropCFFlags)
{
HRESULT hr;
DWORD dwEffect = DROPEFFECT_NONE;
ASSERT(IS_VALID_INTERFACE_PTR(pido, IDataObject));
ASSERT(FLAGS_ARE_VALID(dwKeyState, ALL_KEYSTATE_FLAGS));
ASSERT(IS_VALID_STRUCT_PTR(&pt, CPOINTL));
ASSERT(IS_VALID_WRITE_PTR(pdwEffect, DWORD));
ASSERT(IS_VALID_WRITE_PTR(pdwDropCFFlags, DWORD));
*pdwDropCFFlags = 0;
if (TW_SafeWindow(GetPrivateData(hwnd)))
{
FORMATETC fmtetc = { g_cfURL, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
// Check for UniformResourceLocator or CF_HDROP.
if (pido->QueryGetData(&fmtetc) == S_OK)
{
SET_FLAG(*pdwDropCFFlags, DROP_CF_FL_URL);
TRACE_OUT(("DetermineDropEffect(): Object supports clipboard format %s.",
GetClipboardFormatNameString(fmtetc.cfFormat)));
}
fmtetc.cfFormat = CF_HDROP;
if (pido->QueryGetData(&fmtetc) == S_OK)
{
SET_FLAG(*pdwDropCFFlags, DROP_CF_FL_HDROP);
TRACE_OUT(("DetermineDropEffect(): Object supports clipboard format %s.",
GetClipboardFormatNameString(fmtetc.cfFormat)));
}
if (*pdwDropCFFlags)
dwEffect = DetermineDefaultDropEffect(*pdwEffect);
}
*pdwEffect = dwEffect;
hr = S_OK;
TRACE_OUT(("DetermineDropEffect(): Returning drop effect %#lx.",
*pdwEffect));
ASSERT(FLAGS_ARE_VALID(*pdwEffect, ALL_DROPEFFECT_FLAGS));
ASSERT(FLAGS_ARE_VALID(*pdwDropCFFlags, ALL_DROP_CF_FLAGS));
return(hr);
}
PRIVATE_CODE HRESULT SetCurrentURL(HWND hwnd, PCSTR pcszURL)
{
PMWIN tw;
ASSERT(IS_VALID_HANDLE(hwnd, WND));
ASSERT(IS_VALID_STRING_PTR(pcszURL, CSTR));
tw = GetPrivateData(hwnd);
SetWindowText(tw->hWndURLComboBox, pcszURL);
TW_LoadDocument(tw, pcszURL, TW_LD_FL_RECORD, NULL, EMPTY_STRING);
TRACE_OUT(("SetCurrentURL(): Set current URL to %s.",
pcszURL));
return(S_OK);
}
PRIVATE_CODE HRESULT DropHDrop(HWND hwnd, PIDataObject pido, DWORD dwKeyState,
POINTL pt, PDWORD pdwEffect)
{
HRESULT hr;
FORMATETC fmtetc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgmed;
ASSERT(IS_VALID_HANDLE(hwnd, WND));
ASSERT(IS_VALID_INTERFACE_PTR(pido, IDataObject));
ASSERT(FLAGS_ARE_VALID(dwKeyState, ALL_KEYSTATE_FLAGS));
ASSERT(IS_VALID_STRUCT_PTR(&pt, CPOINTL));
ASSERT(IS_VALID_WRITE_PTR(pdwEffect, DWORD));
TRACE_OUT(("DropHDrop()"));
hr = pido->GetData(&fmtetc, &stgmed);
if (hr == S_OK)
{
HDROP hdrop = (HDROP)GlobalLock(stgmed.hGlobal);
if (EVAL(hdrop))
{
UINT ucFiles = DragQueryFile(hdrop, (UINT)-1, NULL, 0);
if (ucFiles > 0)
{
char szFileURL[MAX_URL_STRING + 1];
UINT ucProtocolLen;
PSTR pszFile;
UINT ucFileLen;
// Just use first file in HDROP.
lstrcpy(szFileURL, "file:");
ucProtocolLen = lstrlen(szFileURL);
pszFile = szFileURL + ucProtocolLen;
ucFileLen = sizeof(szFileURL) - ucProtocolLen;
if (DragQueryFile(hdrop, 0, pszFile, ucFileLen))
{
hr = SetCurrentURL(hwnd, szFileURL);
if (ucFiles > 1)
WARNING_OUT(("DropHDrop(): Called on HDROP with %u files. Using only first file.",
ucFiles,
pszFile));
TRACE_OUT(("DropHDrop(): Called on HDROP with \"%s\" file.",
pszFile));
}
else
hr = E_UNEXPECTED;
}
else
{
// Allow 0 files.
ASSERT(hr == S_OK);
WARNING_OUT(("DropHDrop(): Called on HDROP with 0 files."));
}
}
else
{
WARNING_OUT(("DropHDrop(): failed E_UNEXPECTED"));
hr = E_UNEXPECTED;
}
EVAL(MyReleaseStgMedium(&stgmed) == S_OK);
}
if (hr == S_OK)
*pdwEffect = DetermineDefaultDropEffect(*pdwEffect);
else
*pdwEffect = DROPEFFECT_NONE;
ASSERT(FLAGS_ARE_VALID(*pdwEffect, ALL_DROPEFFECT_FLAGS));
ASSERT(FAILED(hr) ||
EVAL(*pdwEffect != 0));
return(hr);
}
PRIVATE_CODE HRESULT DropURL(HWND hwnd, PIDataObject pido, DWORD dwKeyState,
POINTL pt, PDWORD pdwEffect)
{
HRESULT hr;
FORMATETC fmtetc = { g_cfURL, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgmed;
ASSERT(IS_VALID_HANDLE(hwnd, WND));
ASSERT(IS_VALID_INTERFACE_PTR(pido, IDataObject));
ASSERT(FLAGS_ARE_VALID(dwKeyState, ALL_KEYSTATE_FLAGS));
ASSERT(IS_VALID_STRUCT_PTR(&pt, CPOINTL));
ASSERT(IS_VALID_WRITE_PTR(pdwEffect, DWORD));
TRACE_OUT(("DropURL()"));
hr = pido->GetData(&fmtetc, &stgmed);
if (hr == S_OK)
{
PCSTR pcszURL = (PCSTR)GlobalLock(stgmed.hGlobal);
if (EVAL(pcszURL))
{
hr = SetCurrentURL(hwnd, pcszURL);
EVAL(MyReleaseStgMedium(&stgmed) == S_OK);
}
else
hr = E_UNEXPECTED;
}
if (hr == S_OK)
*pdwEffect = DetermineDefaultDropEffect(*pdwEffect);
else
*pdwEffect = DROPEFFECT_NONE;
ASSERT(FLAGS_ARE_VALID(*pdwEffect, ALL_DROPEFFECT_FLAGS));
ASSERT(FAILED(hr) ||
EVAL(*pdwEffect != 0));
return(hr);
}
PRIVATE_CODE HRESULT MyDrop(HWND hwnd, PIDataObject pido, DWORD dwKeyState,
POINTL pt, PDWORD pdwEffect)
{
HRESULT hr;
DWORD dwDropCFFlags;
ASSERT(IS_VALID_HANDLE(hwnd, WND));
ASSERT(IS_VALID_INTERFACE_PTR(pido, IDataObject));
ASSERT(FLAGS_ARE_VALID(dwKeyState, ALL_KEYSTATE_FLAGS));
ASSERT(IS_VALID_STRUCT_PTR(&pt, CPOINTL));
ASSERT(IS_VALID_WRITE_PTR(pdwEffect, DWORD));
TRACE_OUT(("MyDrop()"));
// Check for UniformResourceLocator or CF_HDROP.
hr = DetermineDropEffect(hwnd, pido, dwKeyState, pt, pdwEffect, &dwDropCFFlags);
if (hr == S_OK)
{
if (IS_FLAG_SET(dwDropCFFlags, DROP_CF_FL_URL))
hr = DropURL(hwnd, pido, dwKeyState, pt, pdwEffect);
else if (IS_FLAG_SET(dwDropCFFlags, DROP_CF_FL_HDROP))
hr = DropHDrop(hwnd, pido, dwKeyState, pt, pdwEffect);
}
ASSERT(FLAGS_ARE_VALID(*pdwEffect, ALL_DROPEFFECT_FLAGS));
// THIS ASSERT is not true now as just before drop window could go unsafe
// (EG Security Dialog pops up)
// ASSERT(FAILED(hr) ||
// EVAL(*pdwEffect != 0));
return(hr);
}
#ifdef DEBUG
PRIVATE_CODE BOOL IsValidPCMosaicDropTarget(PCMosaicDropTarget pcmdt)
{
BOOL retval;
// DebugEntry(MosaicDropTarget::IsValidPCMosaicDropTarget);
retval=(IS_VALID_READ_PTR(pcmdt, CMosaicDropTarget) &&
(! pcmdt->m_hwnd ||
IS_VALID_HANDLE(pcmdt->m_hwnd, WND)) &&
(! pcmdt->m_pido ||
IS_VALID_INTERFACE_PTR(pcmdt->m_pido, IDataObject)) &&
FLAGS_ARE_VALID(pcmdt->m_dwLastKeyState, ALL_KEYSTATE_FLAGS) &&
FLAGS_ARE_VALID(pcmdt->m_dwLastEffect, ALL_DROPEFFECT_FLAGS) &&
IS_VALID_STRUCT_PTR((PCRefCount)pcmdt, CRefCount) &&
IS_VALID_INTERFACE_PTR((PCIDropTarget)pcmdt, IDropTarget));
// DebugExitBOOL(MosaicDropTarget::IsValidPCMosaicDropTarget,retval);
return retval;
}
#endif
/****************************** Public Functions *****************************/
PUBLIC_CODE HRESULT RegisterDropTarget(HWND hwnd)
{
HRESULT hr;
PMosaicDropTarget pmdt;
TRACE_OUT(("RegisterDropTarget(): Window %#lx requested as drop target.",
hwnd));
ASSERT(IS_VALID_HANDLE(hwnd, WND));
pmdt = new(MosaicDropTarget(hwnd));
#ifndef WINNT
if (pmdt)
{
hr = SHRegisterDragDrop(hwnd, pmdt);
pmdt->Release();
}
else
hr = E_OUTOFMEMORY;
#else
if (pmdt)
{
/*
* This little fix solves the problem of missing Drag
* capability. There is a bug in the SUR shell32 that
* keeps us from loading OLE properly if we call
* SHRegisterDragDrop(), so instead we implicitely load
* OLE by linking it in, and then we Init it here.
* This would be considered a heinous crime under W95,
* but the shell loads up OLE on startup, so the memory
* and load time penalties are minimal.
*/
hr = OleInitialize(NULL);
if (hr == S_OK || hr == S_FALSE)
hr = RegisterDragDrop(hwnd, pmdt);
else
WARNING_OUT(("OleInitialze(): Failed %#lx .", hr));
if(hr == S_OK || hr == S_FALSE)
pmdt->Release();
}
else
hr = E_OUTOFMEMORY;
#endif
if (hr == S_OK)
TRACE_OUT(("RegisterDropTarget(): Window %#lx registered as drop target.",
hwnd));
else
WARNING_OUT(("RegisterDropTarget(): Failed to register window %#lx as drop target.",
hwnd));
return(hr);
}
PUBLIC_CODE HRESULT RevokeDropTarget(HWND hwnd)
{
HRESULT hr;
ASSERT(IS_VALID_HANDLE(hwnd, WND));
#ifdef WINNT
hr = RevokeDragDrop(hwnd);
OleUninitialize();
#else
hr = SHRevokeDragDrop(hwnd);
#endif
if (hr == S_OK)
TRACE_OUT(("RevokeDropTarget(): Window %#lx drop target revoked.",
hwnd));
else
WARNING_OUT(("RevokeDropTarget(): Failed to revoke window %#lx drop target. ERR=0x%lx",
hwnd, hr));
return(hr);
}
/********************************** Methods **********************************/
MosaicDropTarget::MosaicDropTarget(HWND hwnd) : RefCount(NULL)
{
DebugEntry(MosaicDropTarget::MosaicDropTarget);
// Don't validate this until after initialization.
ASSERT(IS_VALID_HANDLE(hwnd, WND));
m_hwnd = hwnd;
m_pido = NULL;
m_dwLastKeyState = 0;
m_dwLastEffect = 0;
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
DebugExitVOID(MosaicDropTarget::MosaicDropTarget);
return;
}
MosaicDropTarget::~MosaicDropTarget(void)
{
DebugEntry(MosaicDropTarget::~MosaicDropTarget);
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
m_hwnd = NULL;
ClearDropMembers();
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
DebugExitVOID(MosaicDropTarget::~MosaicDropTarget);
return;
}
ULONG STDMETHODCALLTYPE MosaicDropTarget::AddRef(void)
{
ULONG ulcRef;
DebugEntry(MosaicDropTarget::AddRef);
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
ulcRef = RefCount::AddRef();
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
DebugExitULONG(MosaicDropTarget::AddRef, ulcRef);
return(ulcRef);
}
ULONG STDMETHODCALLTYPE MosaicDropTarget::Release(void)
{
ULONG ulcRef;
DebugEntry(MosaicDropTarget::Release);
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
ulcRef = RefCount::Release();
DebugExitULONG(MosaicDropTarget::Release, ulcRef);
return(ulcRef);
}
HRESULT STDMETHODCALLTYPE MosaicDropTarget::QueryInterface(REFIID riid,
PVOID *ppvObject)
{
HRESULT hr = S_OK;
DebugEntry(MosaicDropTarget::QueryInterface);
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
ASSERT(IsValidREFIID(riid));
ASSERT(IS_VALID_WRITE_PTR(ppvObject, PVOID));
if (riid == IID_IDropTarget)
{
*ppvObject = (PIDropTarget)this;
ASSERT(IS_VALID_INTERFACE_PTR((PIDropTarget)*ppvObject, IDropTarget));
TRACE_OUT(("MosaicDropTarget::QueryInterface(): Returning IDropTarget."));
}
else if (riid == IID_IUnknown)
{
*ppvObject = (PIUnknown)this;
ASSERT(IS_VALID_INTERFACE_PTR((PIUnknown)*ppvObject, IUnknown));
TRACE_OUT(("MosaicDropTarget::QueryInterface(): Returning IUnknown."));
}
else
{
*ppvObject = NULL;
hr = E_NOINTERFACE;
TRACE_OUT(("MosaicDropTarget::QueryInterface(): Called on unknown interface."));
}
if (hr == S_OK)
AddRef();
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
ASSERT(FAILED(hr) ||
IS_VALID_STRUCT_PTR(*ppvObject, CINTERFACE));
DebugExitHRESULT(MosaicDropTarget::QueryInterface, hr);
return(hr);
}
HRESULT STDMETHODCALLTYPE MosaicDropTarget::DragEnter(PIDataObject pido,
DWORD dwKeyState,
POINTL pt,
PDWORD pdwEffect)
{
HRESULT hr;
DWORD dwDropCFFlags;
HWND hwndDropSourceFrame;
DebugEntry(MosaicDropTarget::DragEnter);
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
ASSERT(IS_VALID_INTERFACE_PTR(pido, IDataObject));
ASSERT(FLAGS_ARE_VALID(dwKeyState, ALL_KEYSTATE_FLAGS));
ASSERT(IS_VALID_STRUCT_PTR(&pt, CPOINTL));
ASSERT(IS_VALID_WRITE_PTR(pdwEffect, DWORD));
ASSERT(! m_pido);
m_pido = pido;
m_pido->AddRef();
if (! GetLocalDragSourceFrameWindow(&hwndDropSourceFrame) ||
hwndDropSourceFrame != m_hwnd)
hr = DetermineDropEffect(m_hwnd, m_pido, dwKeyState, pt, pdwEffect,
&dwDropCFFlags);
else
{
*pdwEffect &= DROPEFFECT_NONE;
hr = S_OK;
TRACE_OUT(("MosaicDropTarget::DragEnter(): Disabling drop on drag source."));
}
// Remember drop characteristics.
if (hr == S_OK)
{
m_dwLastKeyState = dwKeyState;
m_dwLastEffect = *pdwEffect;
}
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
ASSERT(FLAGS_ARE_VALID(*pdwEffect, ALL_DROPEFFECT_FLAGS));
DebugExitHRESULT(MosaicDropTarget::DragEnter, hr);
return(hr);
}
HRESULT STDMETHODCALLTYPE MosaicDropTarget::DragOver(DWORD dwKeyState,
POINTL pt,
PDWORD pdwEffect)
{
HRESULT hr;
DebugEntry(MosaicDropTarget::DragOver);
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
ASSERT(FLAGS_ARE_VALID(dwKeyState, ALL_KEYSTATE_FLAGS));
ASSERT(IS_VALID_STRUCT_PTR(&pt, CPOINTL));
ASSERT(IS_VALID_WRITE_PTR(pdwEffect, DWORD));
ASSERT(IS_VALID_INTERFACE_PTR(m_pido, IDataObject));
if (TW_SafeWindow(GetPrivateData(m_hwnd)) &&
dwKeyState == m_dwLastKeyState)
{
*pdwEffect = m_dwLastEffect;
hr = S_OK;
}
else
{
DWORD dwDropCFFlags;
hr = DetermineDropEffect(m_hwnd, m_pido, dwKeyState, pt, pdwEffect,
&dwDropCFFlags);
// Remember drop characteristics.
if (hr == S_OK)
{
m_dwLastKeyState = dwKeyState;
m_dwLastEffect = *pdwEffect;
}
}
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
ASSERT(FLAGS_ARE_VALID(*pdwEffect, ALL_DROPEFFECT_FLAGS));
DebugExitHRESULT(MosaicDropTarget::DragOver, hr);
return(hr);
}
HRESULT STDMETHODCALLTYPE MosaicDropTarget::DragLeave(void)
{
HRESULT hr;
DebugEntry(MosaicDropTarget::DragLeave);
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
ClearDropMembers();
hr = S_OK;
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
DebugExitHRESULT(MosaicDropTarget::DragLeave, hr);
return(hr);
}
HRESULT STDMETHODCALLTYPE MosaicDropTarget::Drop(PIDataObject pido,
DWORD dwKeyState, POINTL pt,
PDWORD pdwEffect)
{
HRESULT hr;
DebugEntry(MosaicDropTarget::Drop);
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
ASSERT(IS_VALID_INTERFACE_PTR(pido, IDataObject));
ASSERT(FLAGS_ARE_VALID(dwKeyState, ALL_KEYSTATE_FLAGS));
ASSERT(IS_VALID_STRUCT_PTR(&pt, CPOINTL));
ASSERT(IS_VALID_WRITE_PTR(pdwEffect, DWORD));
ASSERT(IS_VALID_HANDLE(m_hwnd, WND));
hr = MyDrop(m_hwnd, pido, dwKeyState, pt, pdwEffect);
ClearDropMembers();
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
ASSERT(FLAGS_ARE_VALID(*pdwEffect, ALL_DROPEFFECT_FLAGS));
DebugExitHRESULT(MosaicDropTarget::Drop, hr);
return(hr);
}
void STDMETHODCALLTYPE MosaicDropTarget::ClearDropMembers(void)
{
DebugEntry(MosaicDropTarget::ClearDropMembers);
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
// Clear m_pido, m_dwLastKeyState, and m_dwLastEffect. Do not clear m_hwnd.
if (m_pido)
{
m_pido->Release();
m_pido = NULL;
}
m_dwLastKeyState = 0;
m_dwLastEffect = 0;
ASSERT(IS_VALID_STRUCT_PTR(this, CMosaicDropTarget));
DebugExitVOID(MosaicDropTarget::ClearDropMembers);
return;
}