Win32 - Drag And Drop

Started by
4 comments, last by Rattrap 14 years, 1 month ago
I've been trying to implement some Drag and Drop (using the OLE method) functionality into my Win32 program, and have been hitting a roadblock. I've been trying to follow this tutorial I found. From what I understand, I needed to create a class that inherits from IDropTarget Below is the extremelty stubbed out class. DropTarget.hpp

#ifndef	DEFINE_KS_GUI_WIN32_DROPTARGET_HPP
#define	DEFINE_KS_GUI_WIN32_DROPTARGET_HPP

#include <OleIdl.h>

class DropTarget : public IDropTarget
{
public:
	DropTarget();
	~DropTarget();

	/*	IUnknown functions	*/
	HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
	ULONG STDMETHODCALLTYPE AddRef();
	ULONG STDMETHODCALLTYPE Release();

	/*	IDropTarget functions	*/
	HRESULT STDMETHODCALLTYPE DragEnter(IDataObject* in_DataObject, DWORD in_KeyState, POINTL in_Point, DWORD* inout_Effect);
	HRESULT STDMETHODCALLTYPE DragOver(DWORD in_KeyState, POINTL in_Point, DWORD* inout_Effect);
	HRESULT STDMETHODCALLTYPE DragLeave();
	HRESULT STDMETHODCALLTYPE Drop(IDataObject* in_DataObject, DWORD in_KeyState, POINTL in_Point, DWORD* inout_Effect);

private:
	ULONG	m_RefCount;
};
#endif	//	DEFINE_KS_GUI_WIN32_DROPTARGET_HPP


DropTarget.cpp

#include "DropTarget.hpp"

#include <iostream>

DropTarget::DropTarget() : 
	m_RefCount(1)
{
}

DropTarget::~DropTarget()
{
}

HRESULT STDMETHODCALLTYPE DropTarget::QueryInterface(REFIID riid, void** ppvObject)
{
	if(ppvObject == 0)
	{
		return E_POINTER;
	}

	return S_OK;
}

ULONG STDMETHODCALLTYPE DropTarget::AddRef()
{
	return ++m_RefCount;
}

ULONG STDMETHODCALLTYPE DropTarget::Release()
{
	if((--m_RefCount) == 0)
	{
		/*	Release resources	*/
	}

	return m_RefCount;
}

HRESULT STDMETHODCALLTYPE DropTarget::DragEnter(IDataObject* in_DataObject, DWORD in_KeyState, POINTL in_Point, DWORD* inout_Effect)
{
	return S_OK;
}

HRESULT STDMETHODCALLTYPE DropTarget::DragOver(DWORD in_KeyState, POINTL in_Point, DWORD* inout_Effect)
{
	return S_OK;
}

HRESULT STDMETHODCALLTYPE DropTarget::DragLeave()
{
	return S_OK;
}

HRESULT STDMETHODCALLTYPE DropTarget::Drop(IDataObject* in_DataObject, DWORD in_KeyState, POINTL in_Point, DWORD* inout_Effect)
{
	return S_OK;
}


Below is a simple program a rigged up to try and get it to work, when it wouldn't inside my bigger project. I create an instance of DropTarget and register it to the window. When a file is dragged onto the window, the DropTarget::DragEnter should be called, followed by DropTarget::DragOver until the mouse is released and DropTarget::Drop is called, or the mouse leaves the window and DropTarget::DragLeave is called. The DropTarget functions never seem to be called, when a file icon is dragged over the window. I set break points on all of the returns in the DropTarget functions, and none of them are ever tripped (Debugging using MSVC2005).

#include <windows.h>
#include <iostream>
#include <exception>

#include "DropTarget.hpp"

LRESULT CALLBACK WindowProcedure(HWND in_WindowHandle, UINT in_Message, WPARAM in_wParam, LPARAM in_lParam)
{
	switch(in_Message)
	{
	case WM_DESTROY:
		{
			PostQuitMessage(0);
		}

	default:
		{
			return DefWindowProc(in_WindowHandle, in_Message, in_wParam, in_lParam);
		}
	}
}

int WINAPI WinMain(HINSTANCE Instance, HINSTANCE PreviousInstance, PSTR CmdLine, int ShowCommand)
{
	try
	{
		OleInitialize(0);

		WNDCLASSEX	_WindowClass;
		ZeroMemory(&_WindowClass, sizeof(_WindowClass));

		const HINSTANCE _InstanceHandle(GetModuleHandle(0));

		_WindowClass.cbClsExtra = 0;
		_WindowClass.cbSize = sizeof(_WindowClass);
		_WindowClass.cbWndExtra = 0;
		_WindowClass.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_APPWORKSPACE + 1);
		_WindowClass.hCursor = LoadCursor(0, IDC_ARROW);
		_WindowClass.hIcon = LoadIcon(0, IDI_APPLICATION);
		_WindowClass.hIconSm = LoadIcon(0, IDI_APPLICATION);
		_WindowClass.hInstance = _InstanceHandle;
		_WindowClass.lpfnWndProc = WindowProcedure;
		_WindowClass.lpszClassName = TEXT("MyForm");;
		_WindowClass.lpszMenuName = 0;
		_WindowClass.style = CS_HREDRAW | CS_VREDRAW;

		ATOM _Atom(RegisterClassEx(&_WindowClass));
		if(_Atom == 0)
		{
			const DWORD _Error(GetLastError());
			throw std::exception("Error");
		}

		const LPTSTR _ClassName(MAKEINTATOM(_Atom));

		/*	Create the window	*/
		HWND _WindowHandle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW | WS_EX_CONTROLPARENT, _ClassName, TEXT(""), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, Instance, 0);
		if(_WindowHandle == 0)
		{
			const DWORD _Error(GetLastError());
			throw std::exception("Error");
		}

		ShowWindow(_WindowHandle, SW_SHOW);

		/*	Create the OLE Target	*/
		DropTarget _DropTarget;
		/*	Register it with the window	*/
		if(RegisterDragDrop(_WindowHandle, &_DropTarget) != S_OK)
		{
			throw std::exception("Error");
		}

		MSG _Message;
		do
		{
			GetMessage(&_Message, 0, 0, 0);
			TranslateMessage(&_Message);
			DispatchMessage(&_Message);
		}
		while(_Message.message != WM_QUIT);

		OleUninitialize();
	}
	catch(std::exception&)
	{
		return -1;
	}

	return 0;
}


I tried compiling the tutorial example, but it actually seems to be more geared torwards using the clipboard and a textbox instead of dragging an actual file into the window. Does anyone know if I'm missing something in the code?

"I can't believe I'm defending logic to a turing machine." - Kent Woolworth [Other Space]

Advertisement
It is much easier to do this with the DragAcceptFiles Function, which will send WM_DROPFILES messages to your WndProc. Is there any reason you need to use the other method?
If it comes to that point, I'll fallback to WM_DROPFILES, but I was hoping to get this version working.

"I can't believe I'm defending logic to a turing machine." - Kent Woolworth [Other Space]

Your QueryInterface seems wrong, ppvObject is an out parameter. You probably need to do AddRef and *ppvObject = this in QueryInterface.

Also, I would use something like InterlockedIncrement and InterlockedDecrement to change the reference count thread-safely.
I tried putting a breakpoint into QueryInterface, and it doesn't look like it is ever envoked, which I don't know if that is a/the problem or not.

As far as the thread safety, like I said, it's just a stubbed version. The full version uses boost threads, I just didn't want the example to have the dependancy.

[edit]
I think you are on the right track, the demo he had seems to envoke QueryInterface.

"I can't believe I'm defending logic to a turing machine." - Kent Woolworth [Other Space]

I just discovered what is wrong, the problem wasn't the code, but the fact that I often use Remote Desktop to access my PC. Aparently the OLE functionality doesn't work through Remote Desktop. When I tried the code on a local machine, it fired correctly.

"I can't believe I'm defending logic to a turing machine." - Kent Woolworth [Other Space]

This topic is closed to new replies.

Advertisement