Skip to content
Snippets Groups Projects
Commit 778005a3 authored by callum's avatar callum
Browse files

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

parent 3dd79ad2
No related branches found
No related tags found
No related merge requests found
...@@ -34,216 +34,183 @@ ...@@ -34,216 +34,183 @@
#include "linden_common.h" #include "linden_common.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "llwindowwin32.h" #include "llwindowwin32.h"
#include "llkeyboardwin32.h" #include "llkeyboardwin32.h"
#include "lldragdropwin32.h"
#include "llwindowcallbacks.h" #include "llwindowcallbacks.h"
#include "lldragdropwin32.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" )
class LLDragDropWin32Target: class LLDragDropWin32Target:
public IDropTarget public IDropTarget
{ {
public: public:
////////////////////////////////////////////////////////////////////////////////
//
LLDragDropWin32Target( HWND hWnd ) : LLDragDropWin32Target( HWND hWnd ) :
mWindowHandle( hWnd ), mRefCount( 1 ),
mRefCount( 0 ) 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; delete this;
return 0; 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 ) if ( iid == IID_IUnknown || iid == IID_IDropTarget )
{ {
*ppvObject = this;
AddRef(); AddRef();
*ppvObject = this;
return S_OK; return S_OK;
}; }
else
*ppvObject = NULL; {
*ppvObject = 0;
return E_NOINTERFACE; return E_NOINTERFACE;
}; };
};
/* IDropTarget methods */ ////////////////////////////////////////////////////////////////////////////////
STDMETHOD (DragEnter)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) //
HRESULT __stdcall DragEnter( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect )
{ {
HRESULT hr = E_INVALIDARG; FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
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))) // support CF_TEXT using a HGLOBAL?
if ( S_OK == pDataObject->QueryGetData( &fmtetc ) )
{ {
// We can Handle Only one File At a time !!! mAllowDrop = true;
if (1 == DragQueryFile ((HDROP)medium.hGlobal,0xFFFFFFFF,NULL,0 ))
{
// Get the File Name
if (DragQueryFileA((HDROP)medium.hGlobal, 0, szFileDropped,MAX_PATH))
{
if (!PathIsDirectoryA(szFileDropped))
{
char szTempFile[MAX_PATH];
_splitpath(szFileDropped,NULL,NULL,NULL,szTempFile);
// 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; *pdwEffect = DROPEFFECT_COPY;
//We Want to Create a Copy
bDropTargetValid = true;
hr = S_OK;
// }
}
}
}
if (medium.pUnkForRelease) SetFocus( mAppWindowHandle );
medium.pUnkForRelease->Release ();
else
GlobalFree (medium.hGlobal);
} }
else else
{ {
fmte.cfFormat = CF_TEXT; mAllowDrop = false;
fmte.ptd = NULL; *pdwEffect = DROPEFFECT_NONE;
fmte.dwAspect = DVASPECT_CONTENT; };
fmte.lindex = -1;
fmte.tymed = TYMED_HGLOBAL;
// Does the drag source provide CF_TEXT ?
if (NOERROR == pDataObj->QueryGetData(&fmte))
{
bDropTargetValid = true;
bTextDropped = true;
*pdwEffect=DROPEFFECT_COPY;
hr = S_OK;
}
}
return hr;
return S_OK;
}; };
STDMETHOD (DragOver)(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) ////////////////////////////////////////////////////////////////////////////////
//
HRESULT __stdcall DragOver( DWORD grfKeyState, POINTL pt, DWORD* pdwEffect )
{
if ( mAllowDrop )
{ {
HRESULT hr = S_OK;
if (bDropTargetValid)
*pdwEffect = DROPEFFECT_COPY; *pdwEffect = DROPEFFECT_COPY;
}
else
{
*pdwEffect = DROPEFFECT_NONE;
};
return hr; return S_OK;
}; };
STDMETHOD (DragLeave)(void) ////////////////////////////////////////////////////////////////////////////////
//
HRESULT __stdcall DragLeave( void )
{ {
HRESULT hr = S_OK; return S_OK;
strcpy(szFileDropped,"");
return hr;
}; };
STDMETHOD (Drop)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) ////////////////////////////////////////////////////////////////////////////////
//
HRESULT __stdcall Drop( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect )
{ {
HRESULT hr = S_OK; if ( mAllowDrop )
if (bDropTargetValid)
{ {
*pdwEffect=DROPEFFECT_COPY; // construct a FORMATETC object
FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
FORMATETC fmte; // do we have text?
STGMEDIUM medium; if( S_OK == pDataObject->QueryGetData( &fmtetc ) )
if (bTextDropped)
{ {
fmte.cfFormat = CF_TEXT; STGMEDIUM stgmed;
fmte.ptd = NULL; if( S_OK == pDataObject->GetData( &fmtetc, &stgmed ) )
fmte.dwAspect = DVASPECT_CONTENT; {
fmte.lindex = -1; // note: data is in an HGLOBAL - not 'regular' memory
fmte.tymed = TYMED_HGLOBAL; PVOID data = GlobalLock( stgmed.hGlobal );
hr = pDataObj->GetData(&fmte, &medium);
HGLOBAL hText = medium.hGlobal;
LPSTR lpszText = (LPSTR)GlobalLock(hText);
LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mWindowHandle, GWL_USERDATA); // window impl stored in Window data (neat!)
LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong( mAppWindowHandle, GWL_USERDATA );
if ( NULL != window_imp ) if ( NULL != window_imp )
{ {
LLCoordGL gl_coord( 0, 0 ); LLCoordGL gl_coord( 0, 0 );
POINT pt2; POINT pt_client;
pt2.x = pt.x; pt_client.x = pt.x;
pt2.y = pt.y; pt_client.y = pt.y;
ScreenToClient( mWindowHandle, &pt2 ); ScreenToClient( mAppWindowHandle, &pt_client );
LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); LLCoordWindow cursor_coord_window( pt_client.x, pt_client.y );
window_imp->convertCoords(cursor_coord_window, &gl_coord); window_imp->convertCoords(cursor_coord_window, &gl_coord);
llinfos << "### (Drop) URL is: " << lpszText << llendl; llinfos << "### (Drop) URL is: " << data << llendl;
llinfos << "### raw coords are: " << pt.x << " x " << pt.y << llendl; llinfos << "### raw coords are: " << pt.x << " x " << pt.y << llendl;
llinfos << "### window coords are: " << pt2.x << " x " << pt2.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 << "### GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << llendl;
llinfos << llendl; llinfos << llendl;
// no keyboard modifier option yet but we could one day
MASK mask = gKeyboard->currentMask( TRUE ); MASK mask = gKeyboard->currentMask( TRUE );
window_imp->completeDropRequest( gl_coord, mask, std::string( lpszText ) );
// actually do the drop
window_imp->completeDropRequest( gl_coord, mask, std::string( (char*)data ) );
}; };
GlobalUnlock(hText); GlobalUnlock( stgmed.hGlobal );
ReleaseStgMedium(&medium);
} ReleaseStgMedium( &stgmed );
};
};
*pdwEffect = DROPEFFECT_COPY;
} }
return hr; else
{
*pdwEffect = DROPEFFECT_NONE;
};
return S_OK;
}; };
////////////////////////////////////////////////////////////////////////////////
//
private: private:
ULONG mRefCount; LONG mRefCount;
HWND mWindowHandle; HWND mAppWindowHandle;
char szFileDropped[1024]; bool mAllowDrop;
bool bDropTargetValid;
bool bTextDropped;
friend class LLWindowWin32; friend class LLWindowWin32;
}; };
////////////////////////////////////////////////////////////////////////////////
//
LLDragDropWin32::LLDragDropWin32() : LLDragDropWin32::LLDragDropWin32() :
mDropTarget( NULL ), mDropTarget( NULL ),
mDropWindowHandle( NULL ) mDropWindowHandle( NULL )
...@@ -251,10 +218,14 @@ LLDragDropWin32::LLDragDropWin32() : ...@@ -251,10 +218,14 @@ LLDragDropWin32::LLDragDropWin32() :
{ {
} }
////////////////////////////////////////////////////////////////////////////////
//
LLDragDropWin32::~LLDragDropWin32() LLDragDropWin32::~LLDragDropWin32()
{ {
} }
////////////////////////////////////////////////////////////////////////////////
//
bool LLDragDropWin32::init( HWND hWnd ) bool LLDragDropWin32::init( HWND hWnd )
{ {
if ( NOERROR != OleInitialize( NULL ) ) if ( NOERROR != OleInitialize( NULL ) )
...@@ -263,7 +234,7 @@ bool LLDragDropWin32::init( HWND hWnd ) ...@@ -263,7 +234,7 @@ bool LLDragDropWin32::init( HWND hWnd )
mDropTarget = new LLDragDropWin32Target( hWnd ); mDropTarget = new LLDragDropWin32Target( hWnd );
if ( mDropTarget ) if ( mDropTarget )
{ {
HRESULT result = CoLockObjectExternal( mDropTarget, TRUE, TRUE ); HRESULT result = CoLockObjectExternal( mDropTarget, TRUE, FALSE );
if ( S_OK == result ) if ( S_OK == result )
{ {
result = RegisterDragDrop( hWnd, mDropTarget ); result = RegisterDragDrop( hWnd, mDropTarget );
...@@ -287,12 +258,14 @@ bool LLDragDropWin32::init( HWND hWnd ) ...@@ -287,12 +258,14 @@ bool LLDragDropWin32::init( HWND hWnd )
return true; return true;
} }
////////////////////////////////////////////////////////////////////////////////
//
void LLDragDropWin32::reset() void LLDragDropWin32::reset()
{ {
if ( mDropTarget ) if ( mDropTarget )
{ {
CoLockObjectExternal( mDropTarget, FALSE, TRUE );
RevokeDragDrop( mDropWindowHandle ); RevokeDragDrop( mDropWindowHandle );
CoLockObjectExternal( mDropTarget, FALSE, TRUE );
mDropTarget->Release(); mDropTarget->Release();
}; };
......
...@@ -33,10 +33,10 @@ ...@@ -33,10 +33,10 @@
#ifndef LL_LLDRAGDROP32_H #ifndef LL_LLDRAGDROP32_H
#define LL_LLDRAGDROP32_H #define LL_LLDRAGDROP32_H
#if LL_WINDOWS
#include <windows.h> #include <windows.h>
#include <ole2.h> #include <ole2.h>
#include <shlobj.h>
#include <shlwapi.h>
class LLDragDropWin32 class LLDragDropWin32
{ {
...@@ -52,4 +52,6 @@ class LLDragDropWin32 ...@@ -52,4 +52,6 @@ class LLDragDropWin32
HWND mDropWindowHandle; HWND mDropWindowHandle;
}; };
#endif #endif // LL_WINDOWS
#endif // LL_LLDRAGDROP32_H
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment