Drag Drop Win API 32

Я пытаюсь перетащить элемент ListView из моей программы в другую (например, перетаскивая путь к чему-то лежащему VLC, и он воспроизводит видеофайл). Я использую формат буфера обмена CF_HDROP. CopySelection — это то, что устанавливает переменную hglobal STGMEDIUM в структуру DROPFILES.

void CopySelection(HWND hwndList, STGMEDIUM &stgmed)
{
HGLOBAL hMem;
DROPFILES  *ptr;
DROPFILES dfiles;
POINT p;

// get the selection inside the list control
int iPos = SendMessage(hwndList, LVM_GETNEXTITEM, (WPARAM)-1,(LPARAM)LVNI_SELECTED);
cout << "iPos: " << iPos << endl;
LVITEM item;
char buffer[256];
string fileDir = "";
item.iItem = iPos;
item.iSubItem = 1;
item.cchTextMax = 256;
item.pszText = buffer;
item.mask = LVIF_TEXT;

ListView_GetItem(hwndList, &item);
fileDir += string(item.pszText);
fileDir += "\\";
item.iItem = iPos;
item.iSubItem = 0;

ListView_GetItem(hwndList, &item);
fileDir += string(item.pszText);
item.iItem = iPos;
item.iSubItem = 2;

ListView_GetItem(hwndList, &item);
fileDir += string(item.pszText);

cout << "fileDir: " << fileDir << endl;

hMem = GlobalAlloc(GHND, sizeof(DROPFILES));
ptr  = (DROPFILES *)GlobalLock(hMem);

dfiles.fNC = TRUE;
dfiles.fWide = FALSE;
memcpy((void*)&dfiles.pFiles, (fileDir.c_str()+'\0'), fileDir.size()+1);

GetCursorPos(&p);
dfiles.pt=p;

// copy the selected text and nul-terminate
memcpy(ptr, (void*)&dfiles, sizeof(DROPFILES));

GlobalUnlock(hMem);

stgmed.hGlobal = hMem;

//return hMem;
}

Но это, кажется, вызывает segfault. Вот код сообщения списка MouseMove, который вызывает его:

case WM_MOUSEMOVE:
{
// stop drag-drop from happening when the mouse is released.
if(fMouseDown)
{
IDataObject *pDataObject;
IDropSource *pDropSource;
DWORD        dwEffect;
DWORD        dwResult;

FORMATETC fmtetc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgmed = { TYMED_HGLOBAL   , { 0 }, 0 };

// transfer the current selection into the IDataObject
CopySelection(hwnd, stgmed);
cout << "DO WE?" << endl;

// 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);
dwResult = DoDragDrop(pDataObject, pDropSource, DROPEFFECT_COPY, &dwEffect);

// success!
if(dwResult == DRAGDROP_S_DROP)
{
if(dwEffect & DROPEFFECT_MOVE)
{
// remove selection from list control
}
else if(dwEffect & DROPEFFECT_LINK)
{
}
}
// cancelled
else if(dwResult == DRAGDROP_S_CANCEL)
{
}

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

ReleaseCapture();
fMouseDown = FALSE;
fDidDragDrop = TRUE;
}

Код правильно отформатирован (я проверял), но не уверен, почему это не работает. Я даже использую правильный формат буфера обмена OLE, чтобы это произошло? Я не уверен, что использовать, и документация, которую я нашел, не велика.

Ура,
обкрадывать

Постскриптум Я попытался адаптировать этот пример:
http://www.catch22.net/tuts/drop-source

Разница в том, что он просто перемещает текст, в то время как я пытаюсь переместить список файлов (например, выбирая значки в окнах и перетаскивая их на VID-плеер).

3

Решение

Вы не выделяете достаточно памяти для HGLOBAL блок. Вы выделяете только достаточно памяти для хранения DROPFILES само по себе, но нет памяти для хранения имени файла, которое идет с ним. Но даже если вы правильно распределяете память, вы не используете DROPFILES::pFiles поле правильно. Необходимо указать смещение от начала DROPFILES struct, где начинается список имен файлов, но вместо этого вы рассматриваете его как адрес памяти.

Попробуйте это вместо этого:

HGLOBAL CopySelection(HWND hwndList)
{
// get the selection inside the list control

int iPos = SendMessage(hwndList, LVM_GETNEXTITEM, (WPARAM)-1,(LPARAM)LVNI_SELECTED);
if (iPos == -1)
return NULL;

cout << "iPos: " << iPos << endl;

LVITEM item = {0};
char buffer[256];
string fileDir;

item.cchTextMax = 256;
item.pszText = buffer;
item.mask = LVIF_TEXT;

item.iItem = iPos;
item.iSubItem = 1;
ListView_GetItem(hwndList, &item);
fileDir = item.pszText;
fileDir += "\\";

item.iItem = iPos;
item.iSubItem = 0;
ListView_GetItem(hwndList, &item);
fileDir += item.pszText;

item.iItem = iPos;
item.iSubItem = 2;
ListView_GetItem(hwndList, &item);
fileDir += item.pszText;

cout << "fileDir: " << fileDir << endl;

// +2 = the filename's null terminator and the file list's null terminator
HGLOBAL hMem = GlobalAlloc(GHND, sizeof(DROPFILES) + fileDir.length() + 2);
if (!hMem)
return NULL;

DROPFILES *dfiles = (DROPFILES*) GlobalLock(hMem);
if (!dfiles)
{
GlobalFree(hMem);
return NULL;
}

dfiles->pFiles = sizeof(DROPFILES);
GetCursorPos(&(dfiles->pt));
dfiles->fNC = TRUE;
dfiles->fWide = FALSE;
memcpy(&dfiles[1], fileDir.c_str(), fileDir.length());

GlobalUnlock(hMem);
return hMem;
}

.

case WM_MOUSEMOVE:
{
// stop drag-drop from happening when the mouse is released.
if (fMouseDown)
{
IDataObject *pDataObject;
IDropSource *pDropSource;
DWORD        dwEffect;
DWORD        dwResult;

FORMATETC fmtetc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgmed = { TYMED_HGLOBAL   , { 0 }, 0 };

// transfer the current selection into the IDataObject
stgmed.hGlobal = CopySelection(hwnd);
if (stgmed.hGlobal)
{
cout << "DO WE?" << endl;

// 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);
dwResult = DoDragDrop(pDataObject, pDropSource, DROPEFFECT_COPY, &dwEffect);

// success!
if(dwResult == DRAGDROP_S_DROP)
{
if(dwEffect & DROPEFFECT_MOVE)
{
// remove selection from list control
}
else if(dwEffect & DROPEFFECT_LINK)
{
}
}
// cancelled
else if(dwResult == DRAGDROP_S_CANCEL)
{
}

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

ReleaseCapture();
fMouseDown = FALSE;
fDidDragDrop = TRUE;
}
}

Если вы хотите перетаскивать несколько выбранных файлов одновременно, попробуйте это:

HGLOBAL CopySelection(HWND hwndList)
{
vector<string> files;
UINT len = 0;

// get the selection inside the list control

int iPos = -1;
do
{
int iPos = SendMessage(hwndList, LVM_GETNEXTITEM, iPos, LVNI_SELECTED);
if (iPos == -1)
break;

LVITEM item = {0};
char buffer[256];
string fileDir;

item.cchTextMax = 256;
item.pszText = buffer;
item.mask = LVIF_TEXT;

item.iItem = iPos;
item.iSubItem = 1;
ListView_GetItem(hwndList, &item);
fileDir = item.pszText;
fileDir += "\\";

item.iItem = iPos;
item.iSubItem = 0;
ListView_GetItem(hwndList, &item);
fileDir += item.pszText;

item.iItem = iPos;
item.iSubItem = 2;
ListView_GetItem(hwndList, &item);
fileDir += item.pszText;

files.push_back(fileDir);

// +1 = the filename's null terminator
len += (fileDir.length() + 1);

cout << "iPos: " << iPos << ", fileDir: " << fileDir << endl;
}
while (true);

if (files.empty())
return NULL;

// +1 = the file list's null terminator
HGLOBAL hMem = GlobalAlloc(GHND, sizeof(DROPFILES) + len + 1);
if (!hMem)
return NULL;

DROPFILES *dfiles = (DROPFILES*) GlobalLock(hMem);
if (!dfiles)
{
GlobalFree(hMem);
return NULL;
}

dfiles->pFiles = sizeof(DROPFILES);
GetCursorPos(&(dfiles->pt));
dfiles->fNC = TRUE;
dfiles->fWide = FALSE;

char *pFile = (char*) &dfiles[1];
for (vector<string>::size_type i = 0; i < files.size(); ++i)
{
string &fileDir = files[i];

// +1 = the filename's null terminator
len = (fileDir.length() + 1);

memcpy(pFile, fileDir.c_str(), len);
pFile += len;
}

GlobalUnlock(hMem);
return hMem;
}
7

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]