none
Drag & Drop einer Datei aus einem CListCtrl Element - Debug Error RRS feed

  • 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:

    Drag&Drop Between Programs

    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

    Dienstag, 26. Mai 2020 09:47

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ß,
    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.

    Mittwoch, 27. Mai 2020 09:35
    Administrator
  • 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

    Dienstag, 2. Juni 2020 09:15
  • 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.

    Mittwoch, 3. Juni 2020 07:36
    Administrator
  • 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.

    Donnerstag, 2. Juli 2020 07:51
    Administrator