FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour opposite of HB_FUNC( REGISTERDRAGDROP ) ?
Posts: 1772
Joined: Thu Sep 05, 2019 05:32 AM
opposite of HB_FUNC( REGISTERDRAGDROP ) ?
Posted: Wed Dec 13, 2023 09:25 AM
hi,

Fivewin can use REGISTERDRAGDROP() to use App "as Target" where i can drop to
i麓m searching how to use App "as Source" to drag Data to "external" App, how :?:
greeting,

Jimmy
Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: opposite of HB_FUNC( REGISTERDRAGDROP ) ?
Posted: Wed Dec 13, 2023 09:49 AM
Dear Jimmy,

Is this what you are looking for ?
Code (fw): Select all Collapse
#include <windows.h>
#include <ole2.h>
#include <shlobj.h>

// Definir una estructura para almacenar los datos del destino de arrastre
typedef struct {
聽 IDropTargetVtbl *lpVtbl; // Puntero a la tabla de funciones virtuales
聽 DWORD refCount; // Contador de referencias
聽 HWND hwnd; // Control de ventana asociado al destino de arrastre
聽 BOOL isOver; // Indica si el cursor est谩 sobre el destino de arrastre
聽 BOOL allowDrop; // Indica si se permite soltar el objeto
聽 IDataObject *dataObject; // Puntero al objeto de datos arrastrado
} DropTarget;

// Definir las funciones de la interfaz IDropTarget
HRESULT STDMETHODCALLTYPE QueryInterface (IDropTarget *, REFIID, void **);
ULONG STDMETHODCALLTYPE AddRef (IDropTarget *);
ULONG STDMETHODCALLTYPE Release (IDropTarget *);
HRESULT STDMETHODCALLTYPE DragEnter (IDropTarget *, IDataObject *, DWORD, POINTL, DWORD *);
HRESULT STDMETHODCALLTYPE DragOver (IDropTarget *, DWORD, POINTL, DWORD *);
HRESULT STDMETHODCALLTYPE DragLeave (IDropTarget *);
HRESULT STDMETHODCALLTYPE Drop (IDropTarget *, IDataObject *, DWORD, POINTL, DWORD *);

// Crear la tabla de funciones virtuales
static IDropTargetVtbl dropTargetVtbl = {
聽 QueryInterface,
聽 AddRef,
聽 Release,
聽 DragEnter,
聽 DragOver,
聽 DragLeave,
聽 Drop
};

// Crear una instancia de la interfaz IDropTarget
DropTarget *CreateDropTarget (HWND hwnd) {
聽 DropTarget *dropTarget = (DropTarget *) GlobalAlloc (GMEM_FIXED, sizeof (DropTarget));
聽 dropTarget->lpVtbl = &dropTargetVtbl;
聽 dropTarget->refCount = 1;
聽 dropTarget->hwnd = hwnd;
聽 dropTarget->isOver = FALSE;
聽 dropTarget->allowDrop = FALSE;
聽 dropTarget->dataObject = NULL;
聽 return dropTarget;
}

// Implementar la funci贸n QueryInterface
HRESULT STDMETHODCALLTYPE QueryInterface (IDropTarget *this, REFIID riid, void **ppvObject) {
聽 if (IsEqualIID (riid, &IID_IUnknown) || IsEqualIID (riid, &IID_IDropTarget)) {
聽 聽 this->lpVtbl->AddRef (this);
聽 聽 *ppvObject = this;
聽 聽 return S_OK;
聽 }
聽 else {
聽 聽 *ppvObject = NULL;
聽 聽 return E_NOINTERFACE;
聽 }
}

// Implementar la funci贸n AddRef
ULONG STDMETHODCALLTYPE AddRef (IDropTarget *this) {
聽 return InterlockedIncrement (&(((DropTarget *) this)->refCount));
}

// Implementar la funci贸n Release
ULONG STDMETHODCALLTYPE Release (IDropTarget *this) {
聽 ULONG refCount = InterlockedDecrement (&(((DropTarget *) this)->refCount));
聽 if (refCount == 0) {
聽 聽 GlobalFree (this);
聽 聽 return 0;
聽 }
聽 else {
聽 聽 return refCount;
聽 }
}

// Implementar la funci贸n DragEnter
HRESULT STDMETHODCALLTYPE DragEnter (IDropTarget *this, IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) {
聽 // Comprobar si el objeto de datos contiene archivos
聽 FORMATETC formatEtc;
聽 formatEtc.cfFormat = CF_HDROP;
聽 formatEtc.ptd = NULL;
聽 formatEtc.dwAspect = DVASPECT_CONTENT;
聽 formatEtc.lindex = -1;
聽 formatEtc.tymed = TYMED_HGLOBAL;
聽 HRESULT hr = pDataObject->lpVtbl->QueryGetData (pDataObject, &formatEtc);
聽 if (hr == S_OK) {
聽 聽 // Guardar una referencia al objeto de datos
聽 聽 ((DropTarget *) this)->dataObject = pDataObject;
聽 聽 pDataObject->lpVtbl->AddRef (pDataObject);
聽 聽 // Indicar que el cursor est谩 sobre el destino de arrastre
聽 聽 ((DropTarget *) this)->isOver = TRUE;
聽 聽 // Indicar que se permite soltar el objeto
聽 聽 ((DropTarget *) this)->allowDrop = TRUE;
聽 聽 // Establecer el efecto de la operaci贸n
聽 聽 *pdwEffect = DROPEFFECT_COPY;
聽 }
聽 else {
聽 聽 // Indicar que no se permite soltar el objeto
聽 聽 ((DropTarget *) this)->allowDrop = FALSE;
聽 聽 // Establecer el efecto de la operaci贸n
聽 聽 *pdwEffect = DROPEFFECT_NONE;
聽 }
聽 return S_OK;
}

// Implementar la funci贸n DragOver
HRESULT STDMETHODCALLTYPE DragOver (IDropTarget *this, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) {
聽 if (((DropTarget *) this)->isOver) {
聽 聽 if (((DropTarget *) this)->allowDrop) {
聽 聽 聽 // Establecer el efecto de la operaci贸n
聽 聽 聽 *pdwEffect = DROPEFFECT_COPY;
聽 聽 }
聽 聽 else {
聽 聽 聽 // Establecer el efecto de la operaci贸n
聽 聽 聽 *pdwEffect = DROPEFFECT_NONE;
聽 聽 }
聽 }
聽 return S_OK;
}

// Implementar la funci贸n DragLeave
HRESULT STDMETHODCALLTYPE DragLeave (IDropTarget *this) {
聽 if (((DropTarget *) this)->isOver) {
聽 聽 // Liberar la referencia al objeto de datos
聽 聽 ((DropTarget *) this)->dataObject->lpVtbl->Release (((DropTarget *) this)->dataObject);
聽 聽 // Indicar que el cursor ha salido del destino de arrastre
聽 聽 ((DropTarget *) this)->isOver = FALSE;
聽 }
聽 return S_OK;
}

// Implementar la funci贸n Drop
HRESULT STDMETHODCALLTYPE Drop (IDropTarget *this, IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) {
聽 if (((DropTarget *) this)->isOver) {
聽 聽 if (((DropTarget *) this)->allowDrop) {
聽 聽 聽 // Obtener los nombres de los archivos arrastrados
聽 聽 聽 FORMATETC formatEtc;
聽 聽 聽 formatEtc.cfFormat = CF_HDROP;
聽 聽 聽 formatEtc.ptd = NULL;
聽 聽 聽 formatEtc.dwAspect = DVASPECT_CONTENT;
聽 聽 聽 formatEtc.lindex = -1;
聽 聽 聽 formatEtc.tymed = TYMED_HGLOBAL;
聽 聽 聽 STGMEDIUM storageMedium;
聽 聽 聽 HRESULT hr = pDataObject->lpVtbl->GetData (pDataObject, &formatEtc, &storageMedium);
聽 聽 聽 if (SUCCEEDED (hr)) {
聽 聽 聽 聽 HDROP hDrop = (HDROP) GlobalLock (storageMedium.hGlobal);
聽 聽 聽 聽 if (hDrop != NULL) {
聽 聽 聽 聽 聽 UINT fileCount = DragQueryFile (hDrop, 0xFFFFFFFF, NULL, 0);
聽 聽 聽 聽 聽 for (UINT i = 0; i < fileCount; i++) {
聽 聽 聽 聽 聽 聽 TCHAR fileName[MAX_PATH];
聽 聽 聽 聽 聽 聽 if (DragQueryFile (hDrop, i, fileName, MAX_PATH) > 0) {
聽 聽 聽 聽 聽 聽 聽 // Hacer algo con el nombre del archivo
聽 聽 聽 聽 聽 聽 聽 MessageBox (((DropTarget *) this)->hwnd, fileName, TEXT ("Archivo arrastrado"), MB_OK);
聽 聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 }
聽 聽 聽 聽 聽 GlobalUnlock (storageMedium.hGlobal);
聽 聽 聽 聽 聽 DragFinish (hDrop);
聽 聽 聽 聽 }
聽 聽 聽 聽 ReleaseStgMedium (&storageMedium);
聽 聽 聽 }
聽 聽 聽 // Establecer el efecto de la operaci贸n
聽 聽 聽 *pdwEffect = DROPEFFECT_COPY;
聽 聽 }
聽 聽 else {
聽 聽 聽 // Establecer el efecto de la operaci贸n
聽 聽 聽 *pdwEffect = DROPEFFECT_NONE;
聽 聽 }
聽 聽 // Liberar la referencia al objeto de datos
聽 聽 ((DropTarget *) this)->dataObject->lpVtbl->Release (((DropTarget *) this)->dataObject);
聽 聽 // Indicar que el cursor ha salido del destino de arrastre
聽 聽 (
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 1772
Joined: Thu Sep 05, 2019 05:32 AM
Re: opposite of HB_FUNC( REGISTERDRAGDROP ) ?
Posted: Wed Dec 13, 2023 10:35 AM
hi Antonio,

thx for Answer

it seems me that Sample is to react on
DragEnter
DragOver
DragLeave
Drop
to receive in "my App" when use "as Target"

but i like to Dragdrop Data from "my App" and send to external App e.g. Picture to Outlook Email

---

i have read at https://www.catch22.net/tuts/ole/ about OLE Dragdrop and play with samples\imgdrop.prg
it use source\winapi\dropfile.c where i found HB_FUNC( REGISTERDRAGDROP )

now i want to register "my App" for Dragdrop "as Source", how :?:
greeting,

Jimmy
Posts: 1772
Joined: Thu Sep 05, 2019 05:32 AM
Re: opposite of HB_FUNC( REGISTERDRAGDROP ) ?
Posted: Mon Dec 18, 2023 02:43 AM
hi

how can i use this https://www.catch22.net/assets/tuts/zips/dropsource.zip *.CPP CODE with harbour :?:
greeting,

Jimmy
Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: opposite of HB_FUNC( REGISTERDRAGDROP ) ?
Posted: Wed Dec 20, 2023 10:55 AM
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
Code (fw): Select all Collapse
//
//聽 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
Code (fw): Select all Collapse
#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
Code (fw): Select all Collapse
//
//聽 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
Code (fw): Select all Collapse
//
//聽 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;

}
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 1772
Joined: Thu Sep 05, 2019 05:32 AM
Re: opposite of HB_FUNC( REGISTERDRAGDROP ) ?
Posted: Wed Dec 20, 2023 09:20 PM
hi Antonio,
Antonio Linares wrote: Next is to properly use it from FWH and Harbour:
GREAT
it would be nice when include in next FWH Version
greeting,

Jimmy

Continue the discussion