Sign in to follow this  
Rattrap

Win32 - Drag And Drop

Recommended Posts

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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this