SetClipboard() mit COleDataSource und CF_HDROP funktioniert nur einmal
-
Hallo,
ich habe folgendes Problem:
Ich möchte aus meiner Dokumentenverwaltung Files kopieren und dann z. B. in Windows Explorer oder wo auch immer einfügen.
Also baue ich mir einen String mit den selektierten Files (g_pcstrClipboardFiles)und möchte diesen der Zwischenablage mittels oleDataSource->SetClipboard() übergeben.
Beim ersten Mal klappt das auch wunderbar, wenn ich aber zum wiederholten Mal die 'kopieren'-Funktion aufrufe, erhalte ich eben bei SetClipboard() eine Unhandled Access Violation. Außerdem kann ich, wenn die 'kopieren'-Funktion einmal ausgeführt wurde, die 'copy'- und 'cut'-Funktionen in keiner anderen Applikation mehr benutzen, solange meine Applikation noch läuft.Der Code dazu sieht folgendermaßen aus:
COleDataSource* oleDataSource = new COleDataSource(); STGMEDIUM* medium = new tagSTGMEDIUM; DROPFILES files = { 20, { 0, 0 }, 0, 1 }; ::OleSetClipboard(NULL); int nLen = g_pcstrClipboardFiles->GetLength(); // benötigte Größe des Speichers für den String mit den Files + DROPFILES-Struktur ermitteln int nGblLen = sizeof(files) + nLen*2 + 5;// es wird mit Multibyte-Characters und abschließenden \0 gearbeitet // globalen Speicher für die Struktur reservieren HGLOBAL hGbl = GlobalAlloc(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_DDESHARE, nGblLen); // globalen Speicher für andere Prozesse sperren, um einen Speicherpointer zu erhalten char* sData = (char*)::GlobalLock(hGbl); // die ersten 20 Bytes von sData mit der DROPFILES-Struktur füllen memcpy( sData, &files, 20 ); // der String, in dem die tatsächlichen Pfade stehen char* sWStr = sData+20; for( int ii = 0; ii < nLen*2; ii += 2 ) { CString cstrTmp, cstrBuffer = "\0"; cstrTmp = g_pcstrClipboardFiles->GetAt(ii/2); // ii/2 wegen Multibyte-Characters if (cstrTmp == "|") // den Separator mit dem \0-character ersetzen { sWStr[ii] = cstrBuffer.GetAt(1); } else // ansonsten den jeweiligen Character einfügen { sWStr[ii] = g_pcstrClipboardFiles->GetAt(ii/2); } } ::GlobalUnlock(hGbl); medium->tymed = TYMED_HGLOBAL; medium->hGlobal = hGbl; oleDataSource->CacheData(CF_HDROP, medium); oleDataSource->SetClipboard();
Ich versuche jetzt schon den halben Tag, eine Lösung zu finden und komme auf keinen grünen Zweig. Für Hilfe wäre ich sehr dankbar.
Wer hatte schon mal ein solches Problem und was könnte ich da machen, bzw. welchen Fehler mache ich?Grüße und vielen Dank
PeterPS: gerade sehe ich, dass ich es bei meinen Drag&Drop-Operationen mit den Files genau so handhabe, nur dass dann eben an Schluss anstatt SetClipboard() die Funktion DoDragDrop() aufgerufen wird. Da funktioniert's dann problemlos.
-
Hi,
schlussendlich habe ich die Lösung doch noch selbst gefunden:
das STGMEDIUM war unvollständig initialisiert.
Wenn man die Variable pUnkForRelease folgendermaßen initialisiert:
mediumFiles.pUnkForRelease = NULL;dann klappt's!
pUnkForRelease soll auf eine Funktion zeigen, die festlegt, was mit dem Speicher geschieht, wenn er neu belegt wird. Ohne initialisierung zeigt er natürlich ins Nirwana und wenn man das Clipboard neu belegen möchte, weiß Windows nicht mehr weiter.
Wird mit NULL initialisiert, werden Windows-Standardfunktionen verwendet.Grüßle
Peter