Beispiel #1
1
HRESULT WinCE_DoDragDrop(LPDATAOBJECT pDataObj, LPDROPSOURCE pDropSource, DWORD dwOKEffects, LPDWORD pdwEffect)
{
    MSG msg;
    POINT dest = {0,0};
    POINT lastDraw = {-1,-1};
    DWORD effect = DROPEFFECT_NONE;
    DWORD lastEffect = -1;
    IDropTarget * currentTarget = NULL;
    IWebViewPrivate * webView = NULL;
    IDataObject * dataObject = pDataObj;
    IDropSource * dropSource = pDropSource;
    HRESULT feedbackHR = DRAGDROP_S_USEDEFAULTCURSORS;
    HCURSOR startCursor = ::GetCursor();
    HCURSOR noCursor = LoadCursor(NULL, IDC_NO);

    // If there is a change in the keyboard or mouse button state, DoDragDrop calls
    // IDropSource::QueryContinueDrag and determines whether to continue the drag, to
    // drop the data, or to cancel the operation based on the return value.
    BOOL escapePressed = FALSE;
    DWORD keyState = MK_LBUTTON;
    if (GetKeyState(VK_CONTROL) & HIGH_BIT_MASK_SHORT)
        keyState |= MK_CONTROL;
    if (GetKeyState(VK_SHIFT) & HIGH_BIT_MASK_SHORT)
        keyState |= MK_SHIFT;

    HRESULT result = dropSource->QueryContinueDrag(escapePressed, keyState);
    bool dragActive = (result == S_OK);
    POINTL screenPoint;

    while (dragActive && GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);

        // Filter all mouse and key events during the drag and drop:
        if (msg.message == WM_LBUTTONUP ||
            msg.message == WM_LBUTTONDOWN ||
            msg.message == WM_RBUTTONUP ||
            msg.message == WM_RBUTTONDOWN ||
            msg.message == WM_MOUSEMOVE ||
            msg.message == WM_KEYDOWN ||
            msg.message == WM_KEYUP ||
            msg.message == WM_CHAR ||
            msg.message == WM_SYSKEYDOWN ||
            msg.message == WM_SYSKEYUP ||
            msg.message == WM_SYSCHAR)
        {
            if (msg.message == WM_MOUSEMOVE) {
                PERFORMANCE_START(WTF::PerformanceTrace::InputEvent,"DragDropManager: Mouse Move");
            }
            else if (msg.message == WM_LBUTTONUP) {
                PERFORMANCE_START(WTF::PerformanceTrace::InputEvent,"DragDropManager: Mouse Up");
            }
            else {
                PERFORMANCE_START(WTF::PerformanceTrace::InputEvent,"DragDropManager: Other Input");
            }
            bool stateChanged = false;
            if (msg.message == WM_MOUSEMOVE ||
                msg.message == WM_LBUTTONUP) {

                POINT pt = {GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)};
                ::ClientToScreen(msg.hwnd, &pt);
                screenPoint.x = pt.x;
                screenPoint.y = pt.y;

                dest.x = pt.x - currentDragImage.ptOffset.x;
                dest.y = pt.y - currentDragImage.ptOffset.y;

                if (msg.message == WM_MOUSEMOVE) {

                    // Which window is my mouse over?
                    HWND mouseWnd = WindowFromPoint(dest);

                    IDropTarget * newTarget = NULL;
                    if (mouseWnd != NULL && dragMap) {
                        DragWindowMap::iterator it = dragMap->find(mouseWnd);
                        if (it != dragMap->end())
                            newTarget = it->second;
                    }
                    if (currentTarget && currentTarget != newTarget) {
                        currentTarget->DragLeave();
                        feedbackHR = dropSource->GiveFeedback(DROPEFFECT_NONE);
                    }
                    if (newTarget) {
                        effect = DROPEFFECT_NONE; //is this the correct way to set effect?
                        if (pdwEffect)
                            effect = *pdwEffect;
                        if (currentTarget != newTarget) {
                            newTarget->DragEnter(dataObject, keyState, screenPoint, &effect);
                            feedbackHR = dropSource->GiveFeedback(effect);
                            // Find out if the target is a webview now.
                            if (webView)
                                webView->Release();
                            newTarget->QueryInterface(IID_IWebViewPrivate, (void**) &webView);
                        }
                        else if (currentTarget) {
                            currentTarget->DragOver(keyState, screenPoint, &effect);
                            feedbackHR = dropSource->GiveFeedback(effect);
                        }
                    }
                    if (webView) {
                        dragImageVisible = true;
                        dragAreaInvalid = true;
                    }
                    if (feedbackHR == DRAGDROP_S_USEDEFAULTCURSORS && effect != lastEffect) {
                        switch (effect) {
                            case DROPEFFECT_NONE:
                                ::SetCursor(noCursor);
                                break;
                            /* MS doesn't give us these cursors!!!
                            case DROPEFFECT_COPY:
                                break;
                            case DROPEFFECT_MOVE:
                                break;
                            case DROPEFFECT_LINK:
                                break;
                                */
                            default:
                                ::SetCursor(startCursor);
                                break;
                        }
                        lastEffect = effect;
                    }
                    currentTarget = newTarget;
                }
                else if (msg.message == WM_LBUTTONUP) {
                    keyState = 0;
                    stateChanged = true;
                }
            }
            else if (msg.message == WM_KEYDOWN) {
                if (msg.wParam == VK_ESCAPE) {
                    escapePressed = TRUE;
                    stateChanged = true;
                }
            }
            else if (msg.message == WM_KEYUP) {
                if (msg.wParam == VK_ESCAPE) {
                    escapePressed = FALSE;
                    stateChanged = true;
                }
            }

            if (stateChanged) {
                result = dropSource->QueryContinueDrag(escapePressed, keyState);
                if (result != S_OK) {
                    dragImageVisible = false;
                    dragAreaInvalid = true;
                    if (currentTarget && effect && result == DRAGDROP_S_DROP) {
                        effect = DROPEFFECT_NONE; //FIXME: should we reset effect or not?
                        result = currentTarget->Drop(dataObject, keyState, screenPoint, &effect);
                        if (SUCCEEDED(result)) {
                            result = DRAGDROP_S_DROP;
                            if (pdwEffect)
                                *pdwEffect = effect;
                        }
                    }
                    else {
                        result = DRAGDROP_S_CANCEL;
                    }
                    dragActive = false;
                }
            }
            PERFORMANCE_END(WTF::PerformanceTrace::InputEvent);
        }
        else {
            DispatchMessage(&msg);
        }
        if (dragAreaInvalid && webView && dragImageCairo) {
            PERFORMANCE_START(WTF::PerformanceTrace::Paint, "DragDropManager::Paint");
            HDC screenDC = ::GetDC(NULL);
            cairo_surface_t * screenSurface = cairo_win32_surface_create(screenDC);
            cairo_t *crScreen = cairo_create(screenSurface);
            HWND wnd;
            webView->viewWindow((OLE_HANDLE*) &wnd);
            RECT dirty;
            if (invalidDragRect.left != -1) {
                dirty = invalidDragRect;
            }
            else {
                POINT p = {0, 0};
                ::ClientToScreen(wnd, &p);
                ::GetClientRect(wnd, &dirty);
                dirty.left += p.x;
                dirty.top += p.y;
                dirty.right += p.x;
                dirty.bottom += p.y;
            }
            if (dragImageVisible) {
                POINT * prevDraw = NULL;
                if (lastDraw.x != -1 && (lastDraw.x != dest.x || lastDraw.y != dest.y))
                    prevDraw = &lastDraw;
                drawDragImage(crScreen, dest, prevDraw, webView, wnd, true, &dirty);
                lastDraw = dest;
                invalidDragRect.left = -1;
            }
            else {
                // erase the drag image wherever we last put it:
                drawDragImage(crScreen, lastDraw, NULL, webView, wnd, false, &dirty);
            }
            cairo_destroy(crScreen);
            cairo_surface_destroy(screenSurface);
            ::ReleaseDC(NULL, screenDC);
            dragAreaInvalid = false;
            PERFORMANCE_END(WTF::PerformanceTrace::Paint);
        }
    }

    if (currentTarget && result != DRAGDROP_S_DROP) {
        currentTarget->DragLeave();
    }
    ::SetCursor(startCursor);

    if (webView)
        webView->Release();
    if (dragImageCairo) {
        cairo_surface_destroy(dragImageCairo);
        dragImageCairo = NULL;
    }
    return result;
}
void _ecore_win32_dnd_drop_source_free(void *drop_source)
{
   if (!drop_source)
     return;

   IDropSource *object = (IDropSource *)drop_source;
   object->Release();
}
// @pymethod |PyIDropSource|GiveFeedback|Description of GiveFeedback.
PyObject *PyIDropSource::GiveFeedback(PyObject *self, PyObject *args)
{
	IDropSource *pIDS = GetI(self);
	if ( pIDS == NULL )
		return NULL;
	// @pyparm int|dwEffect||Description for dwEffect
	DWORD dwEffect;
	if ( !PyArg_ParseTuple(args, "l:GiveFeedback", &dwEffect) )
		return NULL;
	HRESULT hr;
	PY_INTERFACE_PRECALL;
	hr = pIDS->GiveFeedback( dwEffect );

	PY_INTERFACE_POSTCALL;

	if ( FAILED(hr) )
		return PyCom_BuildPyException(hr, pIDS, IID_IDropSource );
	Py_INCREF(Py_None);
	return Py_None;

}
// @pymethod |PyIDropSource|QueryContinueDrag|Description of QueryContinueDrag.
PyObject *PyIDropSource::QueryContinueDrag(PyObject *self, PyObject *args)
{
	IDropSource *pIDS = GetI(self);
	if ( pIDS == NULL )
		return NULL;
	// @pyparm int|fEscapePressed||Description for fEscapePressed
	// @pyparm int|grfKeyState||Description for grfKeyState
	BOOL fEscapePressed;
	DWORD grfKeyState;
	if ( !PyArg_ParseTuple(args, "il:QueryContinueDrag", &fEscapePressed, &grfKeyState) )
		return NULL;
	HRESULT hr;
	PY_INTERFACE_PRECALL;
	hr = pIDS->QueryContinueDrag( fEscapePressed, grfKeyState );

	PY_INTERFACE_POSTCALL;

	if ( FAILED(hr) )
		return PyCom_BuildPyException(hr, pIDS, IID_IDropSource );
	Py_INCREF(Py_None);
	return Py_None;

}
void Explorerplusplus::OnAddressBarBeginDrag(void)
{
	IDragSourceHelper *pDragSourceHelper = NULL;
	IDropSource *pDropSource = NULL;
	HRESULT hr;

	hr = CoCreateInstance(CLSID_DragDropHelper,NULL,CLSCTX_ALL,
		IID_IDragSourceHelper,(LPVOID *)&pDragSourceHelper);

	if(SUCCEEDED(hr))
	{
		hr = CreateDropSource(&pDropSource,DRAG_TYPE_LEFTCLICK);

		if(SUCCEEDED(hr))
		{
			LPITEMIDLIST pidlDirectory = m_pActiveShellBrowser->QueryCurrentDirectoryIdl();

			FORMATETC ftc[2];
			STGMEDIUM stg[2];

			SetFORMATETC(&ftc[0],(CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR),
				NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL);

			HGLOBAL hglb = GlobalAlloc(GMEM_MOVEABLE,1000);

			FILEGROUPDESCRIPTOR *pfgd = static_cast<FILEGROUPDESCRIPTOR *>(GlobalLock(hglb));

			pfgd->cItems = 1;

			FILEDESCRIPTOR *pfd = (FILEDESCRIPTOR *)((LPBYTE)pfgd + sizeof(UINT));

			/* File information (name, size, date created, etc). */
			pfd[0].dwFlags			= FD_ATTRIBUTES|FD_FILESIZE;
			pfd[0].dwFileAttributes	= FILE_ATTRIBUTE_NORMAL;
			pfd[0].nFileSizeLow		= 16384;
			pfd[0].nFileSizeHigh	= 0;

			/* The name of the file will be the folder name, followed by .lnk. */
			TCHAR szDisplayName[MAX_PATH];
			GetDisplayName(pidlDirectory,szDisplayName,SHGDN_INFOLDER);
			StringCchCat(szDisplayName,SIZEOF_ARRAY(szDisplayName),_T(".lnk"));
			StringCchCopy(pfd[0].cFileName,SIZEOF_ARRAY(pfd[0].cFileName),szDisplayName);

			GlobalUnlock(hglb);

			stg[0].pUnkForRelease	= 0;
			stg[0].hGlobal			= hglb;
			stg[0].tymed			= TYMED_HGLOBAL;

			/* File contents. */
			SetFORMATETC(&ftc[1],(CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILECONTENTS),
				NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL);

			hglb = GlobalAlloc(GMEM_MOVEABLE,16384);

			IShellLink *pShellLink = NULL;
			IPersistStream *pPersistStream = NULL;
			HRESULT hr;

			hr = CoCreateInstance(CLSID_ShellLink,NULL,CLSCTX_INPROC_SERVER,
				IID_IShellLink,(LPVOID*)&pShellLink);

			if(SUCCEEDED(hr))
			{
				TCHAR szPath[MAX_PATH];

				GetDisplayName(pidlDirectory,szPath,SHGDN_FORPARSING);

				pShellLink->SetPath(szPath);

				hr = pShellLink->QueryInterface(IID_IPersistStream,(LPVOID*)&pPersistStream);

				if(SUCCEEDED(hr))
				{
					IStream *pStream = NULL;

					CreateStreamOnHGlobal(hglb,FALSE,&pStream);

					hr = pPersistStream->Save(pStream,TRUE);
				}
			}

			GlobalUnlock(hglb);

			stg[1].pUnkForRelease	= 0;
			stg[1].hGlobal			= hglb;
			stg[1].tymed			= TYMED_HGLOBAL;

			IDataObject *pDataObject = NULL;
			POINT pt = {0,0};

			hr = CreateDataObject(ftc,stg,&pDataObject,2);

			pDragSourceHelper->InitializeFromWindow(m_hAddressBar,&pt,pDataObject);

			DWORD dwEffect;

			DoDragDrop(pDataObject,pDropSource,DROPEFFECT_LINK,&dwEffect);

			CoTaskMemFree(pidlDirectory);

			pDataObject->Release();
			pDropSource->Release();
		}

		pDragSourceHelper->Release();
	}
}
// The user started to move a link in the trace ctl
int POTraceCtl::OnLinkDragBegin(const String& strUrl)
{
	int nDragResult = dragNone;

	///////////////////////////////////////////////////////////
	// Allocate resource for the data to share between PngOptimizer and the target application
	// Here it will be some bytes to store a file path
	HGLOBAL  hgDrop = CreateDropFilesW(strUrl);
	/////////////////////////////////////////////////////////

	FORMATETC etc;
	etc.cfFormat = CF_HDROP;	// CLIPFORMAT
	etc.ptd = NULL;				// DVTARGETDEVICE*
	etc.dwAspect = DVASPECT_CONTENT;	// DWORD
	etc.lindex = -1;			// LONG
	etc.tymed = TYMED_HGLOBAL;	// DWORD

	STGMEDIUM med;
	med.tymed = TYMED_HGLOBAL;
	med.hGlobal = hgDrop;
	med.pUnkForRelease = NULL;

	IDataObject* pDataObject = new PlopDataObject;
	if( pDataObject )
	{
		pDataObject->SetData(&etc, &med, TRUE);
		
		IDropSource* pDropSource = new PlopDropSource; 
		if( pDropSource )
		{
			// Forbid drag-and-drop on ourself
			::DragAcceptFiles( ::GetParent(m_handle), FALSE);

			// DoDragDrop will manage the rest of the action and will return when a drag-and-drop action is done
			DWORD nEffect = 0;
			HRESULT hr = ::DoDragDrop(pDataObject, pDropSource, DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK, &nEffect);
		
			// Unless an optimization is in progress, enable again drag-and-drop on ourself
			if( !m_pApp->IsJobRunning() )
			{
				::DragAcceptFiles( ::GetParent(m_handle), TRUE);
			}

			if( hr == DRAGDROP_S_DROP )
			{
				// Testing proved that we cannot rely on the return code given by Windows to know the exact 
				// operation that occurred during DoDragDrop. It depends on the target application, 
				// it depends on the Windows version and maybe the position of the stars in the sky

				// So we check ourselves if DoDragDrop performed a copy or a move by testing if our file is still here

				if( !File::Exists(strUrl) )
				{
					// The source file does not exist anymore, then it was a move operation
					nDragResult = dragMove;
				}
				else
				{
					nDragResult = dragCopy;
				}
			}
			pDropSource->Release();
		}
		pDataObject->Release();
	}

	GlobalFree(hgDrop);

	return nDragResult;
}