Reworked IDropTarget COM interface impl - now much cleaner and doesn't crash!

meow-7.2.2
callum 2009-11-13 17:43:55 -08:00
parent 3dd79ad226
commit 778005a350
2 changed files with 142 additions and 167 deletions

View File

@ -34,216 +34,183 @@
#include "linden_common.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "llwindowwin32.h"
#include "llkeyboardwin32.h"
#include "lldragdropwin32.h"
#include "llwindowcallbacks.h"
#include <windows.h>
#include <ole2.h>
#include <shlobj.h>
#include <shellapi.h>
#include <shlwapi.h>
// FIXME: this should be done in CMake
#pragma comment( lib, "shlwapi.lib" )
#include "lldragdropwin32.h"
class LLDragDropWin32Target:
public IDropTarget
{
public:
////////////////////////////////////////////////////////////////////////////////
//
LLDragDropWin32Target( HWND hWnd ) :
mWindowHandle( hWnd ),
mRefCount( 0 )
mRefCount( 1 ),
mAppWindowHandle( hWnd ),
mAllowDrop( false)
{
strcpy(szFileDropped,"");
bDropTargetValid = false;
bTextDropped = false;
};
/* IUnknown methods */
STDMETHOD_( ULONG, AddRef )( void )
////////////////////////////////////////////////////////////////////////////////
//
ULONG __stdcall AddRef( void )
{
return ++mRefCount;
return InterlockedIncrement( &mRefCount );
};
STDMETHOD_( ULONG, Release )( void )
////////////////////////////////////////////////////////////////////////////////
//
ULONG __stdcall Release( void )
{
if ( --mRefCount == 0 )
LONG count = InterlockedDecrement( &mRefCount );
if ( count == 0 )
{
delete this;
return 0;
}
return mRefCount;
else
{
return count;
};
};
STDMETHOD ( QueryInterface )( REFIID iid, void ** ppvObject )
////////////////////////////////////////////////////////////////////////////////
//
HRESULT __stdcall QueryInterface( REFIID iid, void** ppvObject )
{
if ( iid == IID_IUnknown || iid == IID_IDropTarget )
{
*ppvObject = this;
AddRef();
*ppvObject = this;
return S_OK;
}
else
{
*ppvObject = 0;
return E_NOINTERFACE;
};
};
////////////////////////////////////////////////////////////////////////////////
//
HRESULT __stdcall DragEnter( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect )
{
FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
// support CF_TEXT using a HGLOBAL?
if ( S_OK == pDataObject->QueryGetData( &fmtetc ) )
{
mAllowDrop = true;
*pdwEffect = DROPEFFECT_COPY;
SetFocus( mAppWindowHandle );
}
else
{
mAllowDrop = false;
*pdwEffect = DROPEFFECT_NONE;
};
*ppvObject = NULL;
return E_NOINTERFACE;
return S_OK;
};
/* IDropTarget methods */
STDMETHOD (DragEnter)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
////////////////////////////////////////////////////////////////////////////////
//
HRESULT __stdcall DragOver( DWORD grfKeyState, POINTL pt, DWORD* pdwEffect )
{
HRESULT hr = E_INVALIDARG;
bDropTargetValid = false;
bTextDropped = false;
*pdwEffect=DROPEFFECT_NONE;
FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
STGMEDIUM medium;
if (pDataObj && SUCCEEDED (pDataObj->GetData (&fmte, &medium)))
if ( mAllowDrop )
{
// We can Handle Only one File At a time !!!
if (1 == DragQueryFile ((HDROP)medium.hGlobal,0xFFFFFFFF,NULL,0 ))
*pdwEffect = DROPEFFECT_COPY;
}
else
{
*pdwEffect = DROPEFFECT_NONE;
};
return S_OK;
};
////////////////////////////////////////////////////////////////////////////////
//
HRESULT __stdcall DragLeave( void )
{
return S_OK;
};
////////////////////////////////////////////////////////////////////////////////
//
HRESULT __stdcall Drop( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect )
{
if ( mAllowDrop )
{
// construct a FORMATETC object
FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
// do we have text?
if( S_OK == pDataObject->QueryGetData( &fmtetc ) )
{
// Get the File Name
if (DragQueryFileA((HDROP)medium.hGlobal, 0, szFileDropped,MAX_PATH))
STGMEDIUM stgmed;
if( S_OK == pDataObject->GetData( &fmtetc, &stgmed ) )
{
if (!PathIsDirectoryA(szFileDropped))
// note: data is in an HGLOBAL - not 'regular' memory
PVOID data = GlobalLock( stgmed.hGlobal );
// window impl stored in Window data (neat!)
LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong( mAppWindowHandle, GWL_USERDATA );
if ( NULL != window_imp )
{
char szTempFile[MAX_PATH];
_splitpath(szFileDropped,NULL,NULL,NULL,szTempFile);
LLCoordGL gl_coord( 0, 0 );
// if (!stricmp(szTempFile,".lnk"))
// {
// if (ResolveLink(szFileDropped,szTempFile))
// {
// strcpy(szFileDropped,szTempFile);
// *pdwEffect=DROPEFFECT_COPY;
// We Want to Create a Copy
// bDropTargetValid = true;
// hr = S_OK;
// }
// }
// else
// {
*pdwEffect=DROPEFFECT_COPY;
//We Want to Create a Copy
bDropTargetValid = true;
hr = S_OK;
// }
}
}
}
POINT pt_client;
pt_client.x = pt.x;
pt_client.y = pt.y;
ScreenToClient( mAppWindowHandle, &pt_client );
if (medium.pUnkForRelease)
medium.pUnkForRelease->Release ();
else
GlobalFree (medium.hGlobal);
}
else
{
fmte.cfFormat = CF_TEXT;
fmte.ptd = NULL;
fmte.dwAspect = DVASPECT_CONTENT;
fmte.lindex = -1;
fmte.tymed = TYMED_HGLOBAL;
LLCoordWindow cursor_coord_window( pt_client.x, pt_client.y );
window_imp->convertCoords(cursor_coord_window, &gl_coord);
llinfos << "### (Drop) URL is: " << data << llendl;
llinfos << "### raw coords are: " << pt.x << " x " << pt.y << llendl;
llinfos << "### client coords are: " << pt_client.x << " x " << pt_client.y << llendl;
llinfos << "### GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << llendl;
llinfos << llendl;
// Does the drag source provide CF_TEXT ?
if (NOERROR == pDataObj->QueryGetData(&fmte))
{
bDropTargetValid = true;
bTextDropped = true;
*pdwEffect=DROPEFFECT_COPY;
hr = S_OK;
}
}
return hr;
// no keyboard modifier option yet but we could one day
MASK mask = gKeyboard->currentMask( TRUE );
// actually do the drop
window_imp->completeDropRequest( gl_coord, mask, std::string( (char*)data ) );
};
GlobalUnlock( stgmed.hGlobal );
};
STDMETHOD (DragOver)(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
{
HRESULT hr = S_OK;
if (bDropTargetValid)
*pdwEffect=DROPEFFECT_COPY;
return hr;
};
STDMETHOD (DragLeave)(void)
{
HRESULT hr = S_OK;
strcpy(szFileDropped,"");
return hr;
};
STDMETHOD (Drop)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
{
HRESULT hr = S_OK;
if (bDropTargetValid)
{
*pdwEffect=DROPEFFECT_COPY;
FORMATETC fmte;
STGMEDIUM medium;
if (bTextDropped)
{
fmte.cfFormat = CF_TEXT;
fmte.ptd = NULL;
fmte.dwAspect = DVASPECT_CONTENT;
fmte.lindex = -1;
fmte.tymed = TYMED_HGLOBAL;
hr = pDataObj->GetData(&fmte, &medium);
HGLOBAL hText = medium.hGlobal;
LPSTR lpszText = (LPSTR)GlobalLock(hText);
LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mWindowHandle, GWL_USERDATA);
if (NULL != window_imp)
{
LLCoordGL gl_coord( 0, 0 );
POINT pt2;
pt2.x = pt.x;
pt2.y = pt.y;
ScreenToClient( mWindowHandle, &pt2 );
LLCoordWindow cursor_coord_window( pt2.x, pt2.y );
window_imp->convertCoords(cursor_coord_window, &gl_coord);
llinfos << "### (Drop) URL is: " << lpszText << llendl;
llinfos << "### raw coords are: " << pt.x << " x " << pt.y << llendl;
llinfos << "### window coords are: " << pt2.x << " x " << pt2.y << llendl;
llinfos << "### GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << llendl;
llinfos << llendl;
MASK mask = gKeyboard->currentMask(TRUE);
window_imp->completeDropRequest( gl_coord, mask, std::string( lpszText ) );
ReleaseStgMedium( &stgmed );
};
};
GlobalUnlock(hText);
ReleaseStgMedium(&medium);
}
*pdwEffect = DROPEFFECT_COPY;
}
return hr;
else
{
*pdwEffect = DROPEFFECT_NONE;
};
return S_OK;
};
////////////////////////////////////////////////////////////////////////////////
//
private:
ULONG mRefCount;
HWND mWindowHandle;
char szFileDropped[1024];
bool bDropTargetValid;
bool bTextDropped;
LONG mRefCount;
HWND mAppWindowHandle;
bool mAllowDrop;
friend class LLWindowWin32;
};
////////////////////////////////////////////////////////////////////////////////
//
LLDragDropWin32::LLDragDropWin32() :
mDropTarget( NULL ),
mDropWindowHandle( NULL )
@ -251,19 +218,23 @@ LLDragDropWin32::LLDragDropWin32() :
{
}
////////////////////////////////////////////////////////////////////////////////
//
LLDragDropWin32::~LLDragDropWin32()
{
}
////////////////////////////////////////////////////////////////////////////////
//
bool LLDragDropWin32::init( HWND hWnd )
{
if (NOERROR != OleInitialize(NULL))
if ( NOERROR != OleInitialize( NULL ) )
return FALSE;
mDropTarget = new LLDragDropWin32Target( hWnd );
if ( mDropTarget )
{
HRESULT result = CoLockObjectExternal( mDropTarget, TRUE, TRUE );
HRESULT result = CoLockObjectExternal( mDropTarget, TRUE, FALSE );
if ( S_OK == result )
{
result = RegisterDragDrop( hWnd, mDropTarget );
@ -287,12 +258,14 @@ bool LLDragDropWin32::init( HWND hWnd )
return true;
}
////////////////////////////////////////////////////////////////////////////////
//
void LLDragDropWin32::reset()
{
if ( mDropTarget )
{
CoLockObjectExternal( mDropTarget, FALSE, TRUE );
RevokeDragDrop( mDropWindowHandle );
CoLockObjectExternal( mDropTarget, FALSE, TRUE );
mDropTarget->Release();
};

View File

@ -33,10 +33,10 @@
#ifndef LL_LLDRAGDROP32_H
#define LL_LLDRAGDROP32_H
#if LL_WINDOWS
#include <windows.h>
#include <ole2.h>
#include <shlobj.h>
#include <shlwapi.h>
class LLDragDropWin32
{
@ -52,4 +52,6 @@ class LLDragDropWin32
HWND mDropWindowHandle;
};
#endif
#endif // LL_WINDOWS
#endif // LL_LLDRAGDROP32_H