Dear Jimmy,
As a first approach I have taken all C++ code out of main.c (previously main.cpp) and created a new file builddrop.cpp
This way we can simply compile the cpp files and use them from Harbour. I am building it from Visual Studio and it properly builds :-)
Next is to properly use it from FWH and Harbour:
main.c
//
//聽 MAIN.CPP
//
//聽 DragSource
//
//聽 Freeware written by J Brown 2004
//
//聽 www.catch22.net
//
#define STRICT
#include <windows.h>
#include "resource.h"
#define APPNAME "IDropSource"
#pragma comment(linker, "/OPT:NOWIN98")
void BuildDrop(HWND, BOOL *, BOOL * );
HWND聽 聽 聽 聽 hwndMain;
HWND聽 聽 聽 聽 hwndEdit;
HINSTANCE聽 聽hInstance;
WNDPROC聽聽 聽 OldEditWndProc;
HRESULT CreateDropSource(IDropSource **ppDropSource);
HRESULT CreateDataObject(FORMATETC *fmtetc, STGMEDIUM *stgmeds, UINT count, IDataObject **ppDataObject);
//
//聽 Is the mouse cursor within the edit control's selected text?
//
//聽 Return TRUE/FALSE
//
BOOL MouseInSelection(HWND hwndEdit, LPARAM MouseMsgParam)
{
聽 聽 DWORD nSelStart;
聽 聽 DWORD nSelEnd;
聽 聽 // get the selection inside the edit control
聽 聽 SendMessage(hwndEdit, EM_GETSEL, (WPARAM)&nSelStart, (LPARAM)&nSelEnd);
聽 聽 if(nSelStart != nSelEnd)
聽 聽 {
聽 聽 聽 聽 DWORD nCurPos;
聽 聽 聽 聽 // Get the cursor position the mouse has clicked on
聽 聽 聽 聽 nCurPos = SendMessage(hwndEdit, EM_CHARFROMPOS, 0, MouseMsgParam);
聽 聽 聽 聽 nCurPos = LOWORD(nCurPos);
聽 聽 聽 聽 // Did the mouse click inside the active selection?
聽 聽 聽 聽 return (nCurPos >= nSelStart && nCurPos < nSelEnd) ? TRUE : FALSE;
聽 聽 }
聽 聽 return FALSE;
}
//
//聽 Remove any selection from the edit control
//
void ClearSelection(HWND hwndEdit)
{
聽 聽 SendMessage(hwndEdit, EM_SETSEL, -1, -1);
}
//
//聽 Copy selected text to a HGLOBAL and return it
//
HGLOBAL CopySelection(HWND hwndEdit)
{
聽 聽 DWORD 聽 nSelStart, nSelEnd;
聽 聽 DWORD 聽 nSelLength, nEditLength;
聽 聽 HGLOBAL hMem;
聽 聽 char 聽 *ptr;
聽 聽 char 聽 *tmp;
聽 聽 SendMessage(hwndEdit, EM_GETSEL, (WPARAM)&nSelStart, (LPARAM)&nSelEnd);
聽 聽 nSelLength = nSelEnd - nSelStart;
聽 聽 // get the entire contents of the control
聽 聽 nEditLength = SendMessage(hwndEdit, EM_GETLIMITTEXT, 0, 0);
聽 聽 tmp 聽= (char *)malloc(nEditLength);
聽 聽 SendMessage(hwndEdit, WM_GETTEXT, nEditLength, (LPARAM)tmp);
聽 聽 hMem = GlobalAlloc(GHND, nSelLength+1);
聽 聽 ptr 聽= (char *)GlobalLock(hMem);
聽 聽 // copy the selected text and nul-terminate
聽 聽 memcpy(ptr, tmp+nSelStart, nSelLength);
聽 聽 ptr[nSelLength] = '\0';
聽 聽 GlobalUnlock(hMem);
聽 聽 free(tmp);
聽 聽 return hMem;
}
//
//聽 Subclass window-procedure for EDIT control
//
LRESULT CALLBACK EditWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
聽 聽 static BOOL 聽fMouseDown 聽 = FALSE;
聽 聽 static BOOL 聽fDidDragDrop = FALSE;
聽 聽 聽 聽 聽 聽
聽 聽 switch(msg)
聽 聽 {
聽 聽 case WM_KEYDOWN:
聽 聽 聽 聽
聽 聽 聽 聽 // when ESCAPE is pressed clear the current selection
聽 聽 聽 聽 if(wParam == VK_ESCAPE)
聽 聽 聽 聽 聽 聽 ClearSelection(hwnd);
聽 聽 聽 聽 break;
聽 聽 case WM_LBUTTONDOWN:
聽 聽 case WM_LBUTTONDBLCLK:
聽 聽 聽 聽 // if the mouse is pressed when it is over a selection,
聽 聽 聽 聽 // then start a drag-drop as soon as the mouse moves next
聽 聽 聽 聽 if(MouseInSelection(hwndEdit, lParam))
聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 fMouseDown = TRUE;
聽 聽 聽 聽 聽 聽 fDidDragDrop = FALSE;
聽 聽 聽 聽 聽 聽 SetCapture(hwnd);
聽 聽 聽 聽 聽 聽 return 0;
聽 聽 聽 聽 }
聽 聽 聽 聽 break;
聽 聽 case WM_SETCURSOR:
聽 聽 聽 聽 // set the mouse cursor to an ARROW when it intersects the
聽 聽 聽 聽 // current selection, or the default IBEAM otherwise
聽 聽 聽 聽 if((HWND)wParam == hwnd)
聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 POINT pt;
聽 聽 聽 聽 聽 聽 GetCursorPos(&pt);
聽 聽 聽 聽 聽 聽 ScreenToClient(hwndEdit, &pt);
聽 聽 聽 聽 聽 聽 if(MouseInSelection(hwndEdit, MAKELPARAM(pt.x, pt.y)))
聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 SetCursor(LoadCursor(0, MAKEINTRESOURCE(IDC_ARROW)));
聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 聽 else
聽 聽 聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 聽 聽 SetCursor(LoadCursor(0, MAKEINTRESOURCE(IDC_IBEAM)));
聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 }
聽 聽 聽 聽 return TRUE;
聽 聽 case WM_MOUSEMOVE:
聽 聽 聽 聽 // if the mouse is held down then start a drag-drop
聽 聽 聽 聽 if(fMouseDown)
聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 BuildDrop( hwndEdit, &fMouseDown, &fDidDragDrop );
聽 聽 聽 聽 }
聽 聽 聽 聽 break;
聽 聽 case WM_LBUTTONUP:
聽 聽 聽 聽
聽 聽 聽 聽 // stop drag-drop from happening when the mouse is released.
聽 聽 聽 聽 if(fMouseDown)
聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 ReleaseCapture();
聽 聽 聽 聽 聽 聽 fMouseDown = FALSE;
聽 聽 聽 聽 聽 聽 if(fDidDragDrop == FALSE)
聽 聽 聽 聽 聽 聽 聽 聽 ClearSelection(hwnd);
聽 聽 聽 聽 }
聽 聽 聽 聽 break;
聽 聽 }
聽 聽 return CallWindowProc(OldEditWndProc, hwnd, msg, wParam, lParam);
}
//
//聽 Main Window message handler
//
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
聽 聽 switch(msg)
聽 聽 {
聽 聽 case WM_CREATE:
聽 聽 聽 聽 // create a child-window EDIT control
聽 聽 聽 聽 hwndEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "",
聽 聽 聽 聽 聽 聽 WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_WANTRETURN|WS_VSCROLL,
聽 聽 聽 聽 聽 聽 0,0,0,0, hwnd, 0, hInstance, 0);
聽 聽 聽 聽 // fixed-width font
聽 聽 聽 聽 SendMessage(hwndEdit, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), 0);
聽 聽 聽 聽 // subclass the edit control so we can add drag+drop support to it
聽 聽 聽 聽 OldEditWndProc = (WNDPROC)SetWindowLong(hwndEdit, GWL_WNDPROC, (LONG)EditWndProc);
聽 聽 聽 聽 SetFocus(hwndEdit);
聽 聽 聽 聽 return TRUE;
聽 聽 case WM_COMMAND:
聽 聽
聽 聽 聽 聽 // react to menu messages
聽 聽 聽 聽 switch(LOWORD(wParam))
聽 聽 聽 聽 {
聽 聽 聽 聽 case IDM_FILE_EXIT:
聽 聽 聽 聽 聽 聽 CloseWindow(hwnd);
聽 聽 聽 聽 聽 聽 return 0;
聽 聽 聽 聽 case IDM_FILE_ABOUT:
聽 聽 聽 聽 聽 聽 MessageBox(hwnd, "IDropSource Test Application\r\n\r\n"
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽"Copyright(c) 2004 by Catch22 Productions\t\r\n"
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽"Written by J Brown.\r\n\r\n"
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽"Homepage at www.catch22.net", APPNAME, MB_ICONINFORMATION);
聽 聽 聽 聽 聽 聽 return 0;
聽 聽 聽 聽 }
聽 聽 聽 聽 break;
聽 聽 case WM_CLOSE:
聽 聽 聽 聽 // shut program down
聽 聽 聽 聽 DestroyWindow(hwnd);
聽 聽 聽 聽 PostQuitMessage(0);
聽 聽 聽 聽 return 0;
聽 聽 case WM_SIZE:
聽 聽 聽 聽
聽 聽 聽 聽 // resize editbox to fit in main window
聽 聽 聽 聽 MoveWindow(hwndEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
聽 聽 聽 聽 return 0;
聽 聽 }
聽 聽 return DefWindowProc(hwnd, msg, wParam, lParam);
}
void InitMainWnd()
{
聽 聽 WNDCLASSEX wc = { sizeof(wc) };
聽 聽 wc.lpfnWndProc 聽 = WndProc;
聽 聽 wc.lpszClassName = APPNAME;
聽 聽 wc.lpszMenuName 聽= MAKEINTRESOURCE(IDR_MENU1);
聽 聽 wc.hInstance 聽 聽 = hInstance;
聽 聽 RegisterClassEx(&wc);
}
void CreateMainWnd()
{
聽 聽 hwndMain = CreateWindowEx(0, APPNAME, APPNAME,
聽 聽 聽 聽 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
聽 聽 聽 聽 CW_USEDEFAULT, CW_USEDEFAULT, 512, 200, 0,0,
聽 聽 聽 聽 hInstance, 0);
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int nShowCmd)
{
聽 聽 MSG msg;
聽 聽 hInstance = hInst;
聽 聽 // This program requires COM
聽 聽 OleInitialize(0);
聽 聽
聽 聽 InitMainWnd();
聽 聽 CreateMainWnd();
聽 聽 // message-pump
聽 聽 while(GetMessage(&msg, 0, 0, 0))
聽 聽 {
聽 聽 聽 聽 TranslateMessage(&msg);
聽 聽 聽 聽 DispatchMessage(&msg);
聽 聽 }
聽 聽 // Shutdown COM
聽 聽 OleUninitialize();
聽 聽 return 0;
}
buildprop.cpp
#include <windows.h>
extern "C" HGLOBAL CopySelection(HWND hwndEdit);
HRESULT CreateDropSource(IDropSource** ppDropSource);
HRESULT CreateDataObject(FORMATETC* fmtetc, STGMEDIUM* stgmeds, UINT count, IDataObject** ppDataObject);
extern "C" void BuildDrop(HWND hwndEdit, BOOL * fMouseDown, BOOL * fDidDragDrop)
{
聽 聽 IDataObject* pDataObject;
聽 聽 IDropSource* pDropSource;
聽 聽 DWORD聽 聽聽 聽 聽dwEffect;
聽 聽 DWORD聽 聽聽 聽 聽dwResult;
聽 聽 FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
聽 聽 STGMEDIUM stgmed = { TYMED_HGLOBAL, { 0 }, 0 };
聽 聽 // transfer the current selection into the IDataObject
聽 聽 stgmed.hGlobal = CopySelection(hwndEdit);
聽 聽 // Create IDataObject and IDropSource COM objects
聽 聽 CreateDropSource(&pDropSource);
聽 聽 CreateDataObject(&fmtetc, &stgmed, 1, &pDataObject);
聽 聽 //
聽 聽 //聽 ** ** ** The drag-drop operation starts here! ** ** **
聽 聽 //
聽 聽 dwResult = DoDragDrop(pDataObject, pDropSource, DROPEFFECT_COPY | DROPEFFECT_MOVE, &dwEffect);
聽 聽 // success!
聽 聽 if (dwResult == DRAGDROP_S_DROP)
聽 聽 {
聽 聽 聽 聽 if (dwEffect & DROPEFFECT_MOVE)
聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 // remove selection from edit control
聽 聽 聽 聽 }
聽 聽 }
聽 聽 // cancelled
聽 聽 else if (dwResult == DRAGDROP_S_CANCEL)
聽 聽 {
聽 聽 }
聽 聽 pDataObject->Release();
聽 聽 pDropSource->Release();
聽 聽 ReleaseCapture();
聽 聽 * fMouseDown = FALSE;
聽 聽 * fDidDragDrop = TRUE;
}
dataobject.cpp
//
//聽 DATAOBJECT.CPP
//
//聽 Implementation of the IDataObject COM interface
//
//聽 By J Brown 2004
//
//聽 www.catch22.net
//
#define STRICT
#include <windows.h>
// defined in enumformat.cpp
HRESULT CreateEnumFormatEtc(UINT nNumFormats, FORMATETC *pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc);
class CDataObject : public IDataObject
{
public:
聽 聽 //
聽 聽 // IUnknown members
聽 聽 //
聽 聽 HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject);
聽 聽 ULONG 聽 __stdcall AddRef (void);
聽 聽 ULONG 聽 __stdcall Release (void);
聽 聽 聽 聽
聽 聽 //
聽 聽 // IDataObject members
聽 聽 //
聽 聽 HRESULT __stdcall GetData聽 聽聽 聽 聽 聽 聽 聽 (FORMATETC *pFormatEtc, 聽STGMEDIUM *pMedium);
聽 聽 HRESULT __stdcall GetDataHere聽 聽聽 聽 聽 聽 (FORMATETC *pFormatEtc, 聽STGMEDIUM *pMedium);
聽 聽 HRESULT __stdcall QueryGetData聽 聽 聽 聽 聽 (FORMATETC *pFormatEtc);
聽 聽 HRESULT __stdcall GetCanonicalFormatEtc (FORMATETC *pFormatEct, 聽FORMATETC *pFormatEtcOut);
聽 聽 HRESULT __stdcall SetData聽 聽聽 聽 聽 聽 聽 聽 (FORMATETC *pFormatEtc, 聽STGMEDIUM *pMedium, 聽BOOL fRelease);
聽 聽 HRESULT __stdcall EnumFormatEtc聽聽 聽 聽 聽 (DWORD 聽 聽 聽dwDirection, IEnumFORMATETC **ppEnumFormatEtc);
聽 聽 HRESULT __stdcall DAdvise聽 聽聽 聽 聽 聽 聽 聽 (FORMATETC *pFormatEtc, 聽DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
聽 聽 HRESULT __stdcall DUnadvise聽聽 聽 聽 聽 聽 聽 (DWORD 聽 聽 聽dwConnection);
聽 聽 HRESULT __stdcall EnumDAdvise聽 聽聽 聽 聽 聽 (IEnumSTATDATA **ppEnumAdvise);
聽 聽
聽 聽 //
聽 聽 // Constructor / Destructor
聽 聽 //
聽 聽 CDataObject(FORMATETC *fmt, STGMEDIUM *stgmed, int count);
聽 聽 ~CDataObject();
聽 聽
private:
聽 聽 int LookupFormatEtc(FORMATETC *pFormatEtc);
聽 聽 //
聽 聽 // any private members and functions
聽 聽 //
聽 聽 LONG聽 聽 聽 聽m_lRefCount;
聽 聽 FORMATETC *m_pFormatEtc;
聽 聽 STGMEDIUM *m_pStgMedium;
聽 聽 LONG聽 聽 聽 聽m_nNumFormats;
};
//
//聽 Constructor
//
CDataObject::CDataObject(FORMATETC *fmtetc, STGMEDIUM *stgmed, int count)
{
聽 聽 m_lRefCount 聽= 1;
聽 聽 m_nNumFormats = count;
聽 聽
聽 聽 m_pFormatEtc 聽= new FORMATETC[count];
聽 聽 m_pStgMedium 聽= new STGMEDIUM[count];
聽 聽 for(int i = 0; i < count; i++)
聽 聽 {
聽 聽 聽 聽 m_pFormatEtc[i] = fmtetc[i];
聽 聽 聽 聽 m_pStgMedium[i] = stgmed[i];
聽 聽 }
}
//
//聽 Destructor
//
CDataObject::~CDataObject()
{
聽 聽 // cleanup
聽 聽 if(m_pFormatEtc) delete[] m_pFormatEtc;
聽 聽 if(m_pStgMedium) delete[] m_pStgMedium;
聽 聽 OutputDebugString("oof\n");
}
//
//聽 IUnknown::AddRef
//
ULONG __stdcall CDataObject::AddRef(void)
{
聽 聽 // increment object reference count
聽 聽 return InterlockedIncrement(&m_lRefCount);
}
//
//聽 IUnknown::Release
//
ULONG __stdcall CDataObject::Release(void)
{
聽 聽 // decrement object reference count
聽 聽 LONG count = InterlockedDecrement(&m_lRefCount);
聽 聽 聽 聽
聽 聽 if(count == 0)
聽 聽 {
聽 聽 聽 聽 delete this;
聽 聽 聽 聽 return 0;
聽 聽 }
聽 聽 else
聽 聽 {
聽 聽 聽 聽 return count;
聽 聽 }
}
//
//聽 IUnknown::QueryInterface
//
HRESULT __stdcall CDataObject::QueryInterface(REFIID iid, void **ppvObject)
{
聽 聽 // check to see what interface has been requested
聽 聽 if(iid == IID_IDataObject || iid == IID_IUnknown)
聽 聽 {
聽 聽 聽 聽 AddRef();
聽 聽 聽 聽 *ppvObject = this;
聽 聽 聽 聽 return S_OK;
聽 聽 }
聽 聽 else
聽 聽 {
聽 聽 聽 聽 *ppvObject = 0;
聽 聽 聽 聽 return E_NOINTERFACE;
聽 聽 }
}
HGLOBAL DupMem(HGLOBAL hMem)
{
聽 聽 // lock the source memory object
聽 聽 DWORD 聽 len 聽 聽= GlobalSize(hMem);
聽 聽 PVOID 聽 source = GlobalLock(hMem);
聽 聽
聽 聽 // create a fixed "global" block - i.e. just
聽 聽 // a regular lump of our process heap
聽 聽 PVOID 聽 dest 聽 = GlobalAlloc(GMEM_FIXED, len);
聽 聽 memcpy(dest, source, len);
聽 聽 GlobalUnlock(hMem);
聽 聽 return dest;
}
int CDataObject::LookupFormatEtc(FORMATETC *pFormatEtc)
{
聽 聽 for(int i = 0; i < m_nNumFormats; i++)
聽 聽 {
聽 聽 聽 聽 if((pFormatEtc->tymed 聽 聽& 聽m_pFormatEtc[i].tymed) 聽 &&
聽 聽 聽 聽 聽 聽 pFormatEtc->cfFormat == m_pFormatEtc[i].cfFormat &&
聽 聽 聽 聽 聽 聽 pFormatEtc->dwAspect == m_pFormatEtc[i].dwAspect)
聽 聽 聽 聽 {
聽 聽 聽 聽 聽 聽 return i;
聽 聽 聽 聽 }
聽 聽 }
聽 聽 return -1;
}
//
//聽 IDataObject::GetData
//
HRESULT __stdcall CDataObject::GetData (FORMATETC *pFormatEtc, STGMEDIUM *pMedium)
{
聽 聽 int idx;
聽 聽 //
聽 聽 // try to match the requested FORMATETC with one of our supported formats
聽 聽 //
聽 聽 if((idx = LookupFormatEtc(pFormatEtc)) == -1)
聽 聽 {
聽 聽 聽 聽 return DV_E_FORMATETC;
聽 聽 }
聽 聽 //
聽 聽 // found a match! transfer the data into the supplied storage-medium
聽 聽 //
聽 聽 pMedium->tymed聽 聽 聽 聽 聽 聽= m_pFormatEtc[idx].tymed;
聽 聽 pMedium->pUnkForRelease 聽= 0;
聽 聽
聽 聽 switch(m_pFormatEtc[idx].tymed)
聽 聽 {
聽 聽 case TYMED_HGLOBAL:
聽 聽 聽 聽 pMedium->hGlobal = DupMem(m_pStgMedium[idx].hGlobal);
聽 聽 聽 聽 //return S_OK;
聽 聽 聽 聽 break;
聽 聽 default:
聽 聽 聽 聽 return DV_E_FORMATETC;
聽 聽 }
聽 聽 return S_OK;
}
//
//聽 IDataObject::GetDataHere
//
HRESULT __stdcall CDataObject::GetDataHere (FORMATETC *pFormatEtc, STGMEDIUM *pMedium)
{
聽 聽 // GetDataHere is only required for IStream and IStorage mediums
聽 聽 // It is an error to call GetDataHere for things like HGLOBAL and other clipboard formats
聽 聽 //
聽 聽 //聽 OleFlushClipboard
聽 聽 //
聽 聽 return DATA_E_FORMATETC;
}
//
//聽 IDataObject::QueryGetData
//
//聽 Called to see if the IDataObject supports the specified format of data
//
HRESULT __stdcall CDataObject::QueryGetData (FORMATETC *pFormatEtc)
{
聽 聽 return (LookupFormatEtc(pFormatEtc) == -1) ? DV_E_FORMATETC : S_OK;
}
//
//聽 IDataObject::GetCanonicalFormatEtc
//
HRESULT __stdcall CDataObject::GetCanonicalFormatEtc (FORMATETC *pFormatEct, FORMATETC *pFormatEtcOut)
{
聽 聽 // Apparently we have to set this field to NULL even though we don't do anything else
聽 聽 pFormatEtcOut->ptd = NULL;
聽 聽 return E_NOTIMPL;
}
//
//聽 IDataObject::SetData
//
HRESULT __stdcall CDataObject::SetData (FORMATETC *pFormatEtc, STGMEDIUM *pMedium, 聽BOOL fRelease)
{
聽 聽 return E_NOTIMPL;
}
//
//聽 IDataObject::EnumFormatEtc
//
HRESULT __stdcall CDataObject::EnumFormatEtc (DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc)
{
聽 聽 if(dwDirection == DATADIR_GET)
聽 聽 {
聽 聽 聽 聽 // for Win2k+ you can use the SHCreateStdEnumFmtEtc API call, however
聽 聽 聽 聽 // to support all Windows platforms we need to implement IEnumFormatEtc ourselves.
聽 聽 聽 聽 return CreateEnumFormatEtc(m_nNumFormats, m_pFormatEtc, ppEnumFormatEtc);
聽 聽 }
聽 聽 else
聽 聽 {
聽 聽 聽 聽 // the direction specified is not support for drag+drop
聽 聽 聽 聽 return E_NOTIMPL;
聽 聽 }
}
//
//聽 IDataObject::DAdvise
//
HRESULT __stdcall CDataObject::DAdvise (FORMATETC *pFormatEtc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
{
聽 聽 return OLE_E_ADVISENOTSUPPORTED;
}
//
//聽 IDataObject::DUnadvise
//
HRESULT __stdcall CDataObject::DUnadvise (DWORD dwConnection)
{
聽 聽 return OLE_E_ADVISENOTSUPPORTED;
}
//
//聽 IDataObject::EnumDAdvise
//
HRESULT __stdcall CDataObject::EnumDAdvise (IEnumSTATDATA **ppEnumAdvise)
{
聽 聽 return OLE_E_ADVISENOTSUPPORTED;
}
//
//聽 Helper function
//
HRESULT CreateDataObject (FORMATETC *fmtetc, STGMEDIUM *stgmeds, UINT count, IDataObject **ppDataObject)
{
聽 聽 if(ppDataObject == 0)
聽 聽 聽 聽 return E_INVALIDARG;
聽 聽 *ppDataObject = new CDataObject(fmtetc, stgmeds, count);
聽 聽 return (*ppDataObject) ? S_OK : E_OUTOFMEMORY;
}
dropsource.cpp
//
//聽 DROPSOURCE.CPP
//
//聽 Implementation of the IDropSource COM interface
//
//聽 By J Brown 2004
//
//聽 www.catch22.net
//
#define STRICT
#include <windows.h>
class CDropSource : public IDropSource
{
public:
聽 聽 //
聽 聽 // IUnknown members
聽 聽 //
聽 聽 HRESULT __stdcall QueryInterface聽 聽 (REFIID iid, void ** ppvObject);
聽 聽 ULONG 聽 __stdcall AddRef聽 聽 聽 聽 聽 聽 (void);
聽 聽 ULONG 聽 __stdcall Release聽 聽聽 聽 聽 聽 (void);
聽 聽 聽 聽
聽 聽 //
聽 聽 // IDropSource members
聽 聽 //
聽 聽 HRESULT __stdcall QueryContinueDrag聽(BOOL fEscapePressed, DWORD grfKeyState);
聽 聽 HRESULT __stdcall GiveFeedback聽 聽 聽 (DWORD dwEffect);
聽 聽
聽 聽 //
聽 聽 // Constructor / Destructor
聽 聽 //
聽 聽 CDropSource();
聽 聽 ~CDropSource();
聽 聽
private:
聽 聽 //
聽 聽 // private members and functions
聽 聽 //
聽 聽 LONG聽 聽 聽 聽m_lRefCount;
};
//
//聽 Constructor
//
CDropSource::CDropSource()
{
聽 聽 m_lRefCount = 1;
}
//
//聽 Destructor
//
CDropSource::~CDropSource()
{
}
//
//聽 IUnknown::AddRef
//
ULONG __stdcall CDropSource::AddRef(void)
{
聽 聽 // increment object reference count
聽 聽 return InterlockedIncrement(&m_lRefCount);
}
//
//聽 IUnknown::Release
//
ULONG __stdcall CDropSource::Release(void)
{
聽 聽 // decrement object reference count
聽 聽 LONG count = InterlockedDecrement(&m_lRefCount);
聽 聽 聽 聽
聽 聽 if(count == 0)
聽 聽 {
聽 聽 聽 聽 delete this;
聽 聽 聽 聽 return 0;
聽 聽 }
聽 聽 else
聽 聽 {
聽 聽 聽 聽 return count;
聽 聽 }
}
//
//聽 IUnknown::QueryInterface
//
HRESULT __stdcall CDropSource::QueryInterface(REFIID iid, void **ppvObject)
{
聽 聽 // check to see what interface has been requested
聽 聽 if(iid == IID_IDropSource || iid == IID_IUnknown)
聽 聽 {
聽 聽 聽 聽 AddRef();
聽 聽 聽 聽 *ppvObject = this;
聽 聽 聽 聽 return S_OK;
聽 聽 }
聽 聽 else
聽 聽 {
聽 聽 聽 聽 *ppvObject = 0;
聽 聽 聽 聽 return E_NOINTERFACE;
聽 聽 }
}
//
//聽 CDropSource::QueryContinueDrag
//
//聽 Called by OLE whenever Escape/Control/Shift/Mouse buttons have changed
//
HRESULT __stdcall CDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
{
聽 聽 // if the <Escape> key has been pressed since the last call, cancel the drop
聽 聽 if(fEscapePressed == TRUE)
聽 聽 聽 聽 return DRAGDROP_S_CANCEL;聽 聽
聽 聽 // if the <LeftMouse> button has been released, then do the drop!
聽 聽 if((grfKeyState & MK_LBUTTON) == 0)
聽 聽 聽 聽 return DRAGDROP_S_DROP;
聽 聽 // continue with the drag-drop
聽 聽 return S_OK;
}
//
//聽 CDropSource::GiveFeedback
//
//聽 Return either S_OK, or DRAGDROP_S_USEDEFAULTCURSORS to instruct OLE to use the
// 聽default mouse cursor images
//
HRESULT __stdcall CDropSource::GiveFeedback(DWORD dwEffect)
{
聽 聽 return DRAGDROP_S_USEDEFAULTCURSORS;
}
//
//聽 Helper routine to create an IDropSource object
//聽
HRESULT CreateDropSource(IDropSource **ppDropSource)
{
聽 聽 if(ppDropSource == 0)
聽 聽 聽 聽 return E_INVALIDARG;
聽 聽 *ppDropSource = new CDropSource();
聽 聽 return (*ppDropSource) ? S_OK : E_OUTOFMEMORY;
}