Fragensteller
Drag & Drop einer Datei aus einem CListCtrl Element - Debug Error

Frage
-
Hallo Forum
Vermutlich bereits eine oft gestellte Frage: Wie ziehe ich eine Datei aus einem CListCtrl Element in den Windows-Explorer?
Ich habe hierzu folgende Info gefunden:
Daraus habe ich mir Folgendes "abgeleitet":
void CftcDlg::OnBegindragList1(NMHDR *pNMHDR, LRESULT *pResult) { //CListCtrl *pL = (CListCtrl*)GetDlgItem(IDC_LIST1); LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR); CStringList lsDraggedFiles; POSITION pos; UINT uBuffSize = 0; HGLOBAL hgDrop; DROPFILES* pDrop; wchar_t *wcsTmpDir = _wgetenv(_T("TEMP")); // For every selected item in the list, // put the filename into lsDraggedFiles. // c_FileList is our dialog's CListCtrl. pos = m_pListCtrl->GetFirstSelectedItemPosition(); while ( NULL != pos ) { int nSelItem = m_pListCtrl->GetNextSelectedItem ( pos ); dirlist_t *elem = (dirlist_t*)m_pListCtrl->GetItemData(nSelItem); // retrieve File to temporary folder and put the filename in sFile if (wcsTmpDir && ((elem->dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == 0)) {// dragging only files wchar_t wcsSrc[MAX_PATH]; wchar_t wcsTmp[MAX_PATH]; _snwprintf_s(wcsSrc,MAX_PATH,_TRUNCATE,_T("%s\\%s"),m_wcsPath,elem->wcsName); _snwprintf_s(wcsTmp,MAX_PATH,_TRUNCATE,_T("%s\\%s"),wcsTmpDir,elem->wcsName); if (CSC_RetrFile(m_comm.WS,m_comm.pBuf,wcsSrc,wcsTmp) == 0) { lsDraggedFiles.AddTail ( wcsTmp ); // Calculate the # of chars required to hold this string. uBuffSize += lstrlen ( wcsTmp ) + 1; } } } // Add 1 extra for the final null char, and the size of the DROPFILES struct. uBuffSize = sizeof(DROPFILES) + sizeof(TCHAR) * (uBuffSize + 1); // Allocate memory from the heap for the DROPFILES struct. hgDrop = GlobalAlloc ( GHND | GMEM_SHARE, uBuffSize ); if ( NULL == hgDrop ) { TRACE("cannot allocate hgDrop\n"); return; } pDrop = (DROPFILES*) GlobalLock ( hgDrop ); if ( NULL == pDrop ) { GlobalFree ( hgDrop ); TRACE("cannot Lock pDrop\n"); return; } // war wohl nix // Fill in the DROPFILES struct. pDrop->pFiles = sizeof(DROPFILES); #ifdef _UNICODE // If we're compiling for Unicode, set the Unicode flag in the struct to indicate it contains Unicode strings. pDrop->fWide = TRUE; #endif TCHAR* pszBuff; // Copy all the filenames into memory after // the end of the DROPFILES struct. pos = lsDraggedFiles.GetHeadPosition(); pszBuff = (TCHAR*) (LPBYTE(pDrop) + sizeof(DROPFILES)); while ( NULL != pos ) { lstrcpy ( pszBuff, (LPCTSTR) lsDraggedFiles.GetNext ( pos ) ); pszBuff = 1 + _tcschr ( pszBuff, '\0' ); } GlobalUnlock ( hgDrop ); COleDataSource datasrc; FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; // Put the data in the data source. datasrc.CacheGlobalData ( CF_HDROP, hgDrop, &etc ); TRACE("DoDragDrop ..."); DROPEFFECT dwEffect; dwEffect = datasrc.DoDragDrop ( DROPEFFECT_COPY | DROPEFFECT_MOVE ); switch ( dwEffect ) { case DROPEFFECT_COPY: { TRACE(" -> COPY\n"); break; } case DROPEFFECT_MOVE: { TRACE(" -> MOVE\n"); // The files were copied or moved. // Note: Don't call GlobalFree() because the data will be freed by the drop target. // ** Omitted code to remove list control items. ** break; } case DROPEFFECT_NONE: { TRACE(" -> NONE\n"); // ** Omitted code for NT/2000 that checks // if the operation actually succeeded. ** // The drag operation wasn't accepted, or was canceled, so we should call GlobalFree() to clean up. GlobalFree ( hgDrop ); break; } } *pResult = 0; }
Ich habe also OnBeginDragList verwendet, um die zu kopierenden Dateien über OLE an den Microsoft-Explorer (Desktop) zu übergeben. Mein Programm muss diese Dateien zunächst (über eine proprietäre Schnittstelle) vom eigentlichen Gerät downloaden und in ein temporäres Verzeichnis stellen, um sie dann dem Explorer zum Kopieren anbieten zu können.
Nun all dies funktioniert auch wunderprächtig mit einer Einschränkung:
Im Debug-Mode bekomme ich nach erfolgreicher Ausführung eines Drag&Drop eine Debug-Assertion im Destruktor von CCmdTarget. Das Problem ist ASSERT(m_dwRef <= 1). (Interessanterweise hängt sich bei dieser Aktion der VisualStudio2010 Debugger sogar auf, offenbar blockiert diese Aktion das System irgendwie)
Was habe ich daher noch falsch gemacht? Ich vermute, dass noch etwas fehlt, aber was?
Bei der Umsetzung des Beispiels aus CodeProject habe ich eine Sache weggelassen, weil sie mir nicht wichtig erschien: Es geht dabei darum, dass man in das Clipboard noch ein zweites Objekt stellt, um erkennen und verhindern zu können, dass man bei einer OLE Aktion nicht seine eigenen Elemente - im Glauben sie kämen von einer anderen Quelle - annimmt. Da ich aber auf diesem Weg keine OLE Element annehme, war mir das nicht wichtig. Könnte das ein Grund sein?
Grüße
FireHeart
Alle Antworten
-
Hallo FireHeart,
Die Lebensdauer dieser Objekte lässt sich mithilfe von CoCreateInstance(), AddRef() und Release() verwalten, wobei die Objektlöschung dem COM überlassen wird. Die Funktion InterlockedDecrement kann Dir dabei behilflich sein, sowie das Aufspüren der Freigabe des letzten Verweises mit OnFinalRelease in der übergeordneten Klasse, wie im Beispiel aus diesem Thread veranschaulicht wurde:
Under what conditions is CCmdTarget::OnFinalRelease called?
Gruß,
DimitarBitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „IT-Pros helfen IT-Pros“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.
- Als Antwort vorgeschlagen Ivan DragovMicrosoft contingent staff, Moderator Montag, 1. Juni 2020 05:37
-
Hallo Dimitar
Da hast Du mich jetzt natürlich an meiner Achillessehne gepackt. Ich habe mein ganzes Leben immer einen großen Bogen um COM und OLE gemacht, daher stehe ich jetzt ziemlich nackt vor diesem Thema.
Kann es sein, dass ich das COleDataSource datasrc Objekt mit CoCreateInstance behandeln muss, ein AddRef machen, und dann im switch(dwEffect) das Release?
Grüße
FireHeart
-
Hallo FireHeart,
Ja, es ist jedenfalls einen Versuch wert, weil es auf die richtige Verwaltung der Verweisanzahl ankommt. Ich vermute zudem, dass insbesondere der Hinweis auf die Freigabe in Verbindung mit CCmdTarget auch in Deinem Fall hilfreich sein würde:
For CCmdTarget the destruction should happen as a result of the final release in the parent class CWnd
Gruß,
Dimitar
Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „IT-Pros helfen IT-Pros“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.
- Bearbeitet Dimitar DenkovMicrosoft contingent staff, Administrator Mittwoch, 3. Juni 2020 13:57 stilistische Korrektur
-
Hallo FireHeart,
Bist Du weitergekommen? Ist der Thread noch aktuell?
Gruß,
Dimitar
Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „IT-Pros helfen IT-Pros“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.