Entwickler-Ecke
Windows API - Zwischenablage (Bitmap) in anderes Programm (Paint)einfügen?
Tony-S - Mo 19.07.10 16:31
Titel: Zwischenablage (Bitmap) in anderes Programm (Paint)einfügen?
Hallo Forum, ich möchte aus meiner Zwischenablage eine Bitmap in ein anderes Programm (Paint oder Word) einfügen.
Als erstes suche ich nach dem "Paint" Fenster, was auch anscheinend eintritt, da Window > 0 ist. Dann simuliere ich Strg + V, also einfügen.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
| procedure SendBMPtoPaint(BMP: TBitmap); var Window: HWND; begin Window := FindWindowEx(FindWindow('Paint', nil), 0, 0, nil); if Window > 0 then begin PostMessage(Window, wm_KeyDown, vk_Control,0); PostMessage(Window, wm_KeyDown, Ord('V'),0); PostMessage(Window, wm_Keyup, vk_Control,0); PostMessage(Window, wm_Keyup, Ord('V'),0); end; end;
Diese Prozedur rufe ich dann auf:
procedure TForm1.btnPaintExportClick(Sender: TObject); begin Clipboard.Assign(imgBMP.Picture.Bitmap); Try ShellExecute(Application.Handle,'open', pchar('mspaint.exe'),nil, Nil, SW_Show); Finally SendBMPtoPaint(imgBMP.Picture.Bitmap); end; end; |
Was mach ich da falsch, oder was kann ich da anders machen? Bin für jede Hilfe dankbar.
Moderiert von
Narses: Überflüssige Zeilenumbrüche/Leerzeilen entfernt.
Moderiert von
Narses: Topic aus Delphi Language (Object-Pascal) / CLX verschoben am Mo 19.07.2010 um 16:33
Tastaro - Mo 19.07.10 17:32
Probier mal
Delphi-Quelltext
1: 2: 3: 4:
| PostMessage(Window, wm_KeyDown, vk_Control,0); PostMessage(Window, wm_KeyDown, Ord('V'),0); PostMessage(Window, wm_Keyup, Ord('V'),0); PostMessage(Window, wm_Keyup, vk_Control,0); |
Beste Grüße
glotzer - Mo 19.07.10 17:37
eventuell auch ein sleep(1000) einfügen befor der tastendruck simuliert wird, ich vermute mal paint ist noch nicht ganz gestartet...
MaPsTaR - Mo 19.07.10 18:30
Hast du schonmal geprüft, was dir
FindWindow('Paint', nil) zurück gibt?
Ich wette mit dir, da sollte 0 herauskommen.
Wer weiß welches Fenster du mit deinem Code ansprichst...
Wenn du dir die Parameter von FindWindow ansiehst wirst du auch merken warum:
HWND FindWindow(
LPCTSTR lpClassName, // pointer to class name --> PChar('MSPaintAPP')
LPCTSTR lpWindowName // pointer to window name --> klappt mit nil
);
Versuch mal das:
Delphi-Quelltext
1:
| FindWindow(PChar('MSPaintAPP'), nil); |
damit solltest du das richtige Handle von dem Fenster bekommen.
Tony-S - Mo 19.07.10 20:21
Vielen Dank schon mal, man muss also die Tasten in der entgegen gesetzten Richtung "loslassen".
Sleep sowie der Tipp von Mapstar haben leider nicht so ganz geklappt - Window.
Ergänzt hab ich noch:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39:
| procedure TForm1.FormCreate(Sender: TObject); begin BMP:= TBitmap.Create; BMP.Width := imgBMP.Width; BMP.Height := imgBMP.Height; BMP := imgBMP.Picture.Bitmap; end;
procedure TForm1.btnPaintExportClick(Sender: TObject); begin Clipboard.Assign(imgBMP.Picture.Bitmap); Try ShellExecute(Application.Handle,'open', pchar('mspaint.exe'),nil, Nil, SW_Show); Finally SendBMPtoPaint(BMP); end; end;
procedure SendBMPtoPaint(BMP: TBitmap); var Window: HWND; begin Window := FindWindow(PChar('MSPaintAPP'), nil); <--
if Window > 0 then begin sleep(2000); PostMessage(Window, wm_KeyDown, vk_Control,0); PostMessage(Window, wm_KeyDown, Ord('V'),0); PostMessage(Window, wm_Keyup, Ord('V'),0); PostMessage(Window, wm_Keyup, vk_Control,0); end; end; |
Ich hab btw Win7, aber das wird wohl nix ausmachen.
MaPsTaR - Mo 19.07.10 21:21
Lad dir mal
dieses Programm [
http://mh-nexus.de/de/downloads.php?product=PropEdit] runter, damit kannst die Fenster einer Anwendung auswerten, dort erhältst du z.B. auch den Klassennamen von dem Fenster.
MSPaintApp ist der KlassenName für das Fenster von Paint unter XP, vielleicht liegt es daran.
Unter XP kommst du so zu der Zeichenfläche, hab das mit dem oben genannten Programm getestet, ob die Handle stimmen.
Delphi-Quelltext
1: 2: 3:
| Window1 := FindWindow(PChar('MSPaintAPP'), nil); Window2 := FindWindowEx(Window1, 0, PChar('AfxFrameOrView42u'), PChar('')); Window3 := FindWindowEx(Window2, 0, PChar('Afx:1000000:8'), PChar('')); |
Deinen Code habe ich mal ausprobiert. Im Paint funktioniert das bei mir auch nicht, dafür aber in Edit-Feldern, wenn ich es so mache:
Delphi-Quelltext
1: 2: 3: 4: 5:
| PostMessage(Window, WM_KEYDOWN, vk_Control, 0); PostMessage(Window, WM_KEYDOWN, Ord('V'), 0); PostMessage(Window, WM_CHAR, 22, 0); PostMessage(Window, WM_KEYUP, Ord('V'), LongInt($C0000001)); PostMessage(Window, WM_KEYUP, vk_Control, LongInt($C0000001)); |
Vielleicht will Paint noch eine spezielle Message, um Strg+V zu verwerten??
Tony-S - Mo 19.07.10 23:36
Danke für das Programm, hatte auch mal sowas ähnliches. Also an 7 liegt es nicht, hier heißt es auch MSPaintApp.
Das Programm gibt mir ja auch ein Handle als Hexwert(?) zurück und zwar 1061A, was Dezimal 67098. Wenn ich mein Programm jetzt starte und nachschaue welchen Wert das Handle des Paint-Fensters hat, so wird mir da 263568 als Wert zurückgegeben :/
Das mit Edit-Feldern funktioniert heißt ja nur, das Paint anscheinend wirklich noch was zusätzliches braucht, nur was?! Davon mal abgesehen, gibt es nicht noch eine andere (unkomplizierte) Lösung für mein Problem? Wobei ich ja schon der Meinung bin es so richtig zu lösen wäre :D.
Ist ja auch für das forum interessant wenn wir eine Lösung finden, aber vorallem für mich.
MaPsTaR - Di 20.07.10 00:22
Wieso das mit dem Handle nicht klappt kann ich nicht sagen, evtl. deinen aktuellen Code nochmal posten?
Wenn du das Bild nur in Paint öffnen willst, könntest du das Bild über dein Programm speichern und dann mit Paint öffnen lassen...
Tony-S - Di 20.07.10 00:49
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33:
| procedure TForm1.FormCreate(Sender: TObject); begin BMP:= TBitmap.Create; BMP.Width := imgBMP.Width; BMP.Height := imgBMP.Height; BMP := imgBMP.Picture.Bitmap; end;
procedure SendBMPtoPaint(BMP: TBitmap); var Window: HWND; begin Window := FindWindow(PChar('MSPaintApp'), nil);
if Window > 0 then begin sleep(2000); PostMessage(Window, wm_KeyDown, vk_Control,0); PostMessage(Window, wm_KeyDown, Ord('V'),0); PostMessage(Window, wm_Keyup, Ord('V'),0); PostMessage(Window, wm_Keyup, vk_Control,0); end; end;
procedure TForm1.btnPaintExportClick(Sender: TObject); begin Clipboard.Assign(imgBMP.Picture.Bitmap); Try ShellExecute(Application.Handle,'open', pchar('mspaint.exe'),nil, Nil, SW_Show); Finally SendBMPtoPaint(BMP); end; end; |
Nee das mit dem erst speichern macht sich in dem Programm in dem ich das brauche nicht wirklich gut.
´Vielleicht is ja auch das, was ich in der Prozedur mache Blödsinn, also das die eine bmp erwartet hmmm.
Sinspin - Di 20.07.10 09:22
Bist du dir sicher das es einfach reicht das Bitmap zur Zwischenablage zu "Assignen"? Ich habe bisher noch nie was brauchbares gefunden um Bilder in die Zwischenablage einzufügen, aber soweit ich weis muss das Bild im Metafile Format sein.
Wenn du dazu Informationen gefunden hast wäre ich für die Quelle dankbar.
Flamefire - Di 20.07.10 10:58
kontrolliere mal, was in der Zwischenablage steht. Ich vermute dass es nur der pointer (also das objekt) auf die bitmap ist
ALF - Di 20.07.10 11:52
hi, ich weiss nicht ob Du es schon gemacht hast. Aber soviel ich weiss must Du dafür ein Handle erstellen wenn Du die Zwischenablage global verwenden willst.
Alles ander was man inerhalb von Delphi macht, bleibt auch in Delphi selbst.
Musste ich bei mir auch machen, allerdings ging es bei mir um dragdrop von Files aus meinem Programm herraus. Also strg+c dann strg+v z.B.
Bei Dir währe es BitMap was Du ja einfügen tust. Ist aber vom Prinzip her das gleiche, lediglich der Aufruf würde sich ändern!
Delphi-Quelltext
1:
| Clipboard.SetAsHandle(CF_HDROP, hGlobal); |
für CF_HDROP gibt es CF_BITMAP glaube ich!
Hoffentlich habe ich es richtig erklärt!
Gruss Alf
Tony-S - Di 20.07.10 12:10
@Sinspin, klappen tut das aufjeden Fall, denn wenn ich das mal so ausprobiere,
Paint öffne und dann (selbser) Strg + V drücke wird das Bild eingefügt, sprich es war auch in der Zwischenablage.
Auf der Suche nach einer Quelle hab ich noch das hier gefunden:
http://www.swissdelphicenter.ch/de/showcode.php?id=1981
Da gibt es die Prozedur "PasteBitmap32FromClipboard" als Ziel erwartet die auch ne Bitmap..
@Flamefire hm wie überprüft man das :D? Ich mein es scheint ja "da" zu sein.
Ist wohl doch alles komplizierter als ich dachte ;D.
Hidden - Di 20.07.10 12:26
Hi :)
Wenn es jetzt nicht um den allgemeinen Fall, sondern konkret um Paint geht: Kannst du die Datei nicht von deinem Programm abspeichern(TBitmap.SaveToFile/Stream), und dann per Parameter mit Paint öffnen?
lg,
Tony-S - Di 20.07.10 12:27
@ ALF
Hm nein das habe ich nicht.
Ich hab zumindestens verstanden wormu es geht :D,
der erste Paramater ist der Dateityp das dürfte auch CF_Bitmap sein,
der zweite ist dann wie darauf zugegriffen werden soll?
Sprich das sieht dann so aus:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure TimgBMP.btnPaintExportClick(Sender: TObject); begin Clipboard.SetAsHandle(CF_BITMAP, hGlobal);
Clipboard.Assign(imgBMP.Picture.Bitmap); Try ShellExecute(Application.Handle,'open', pchar('mspaint.exe'),nil, Nil, SW_Show); Finally SendBMPtoPaint(imgBMP.Picture.Bitmap); end; end; |
Siehe Zeile mit Pfeil
ALF - Di 20.07.10 12:47
hglobel ist der Handler dafür!
Delphi-Quelltext
1: 2: 3: 4:
| var hGlobal: THandle; begin hGlobal := GlobalAlloc(GMEM_SHARE or GMEM_MOVEABLE or GMEM_ZEROINIT, |
der allerdings dannn Deiner Bitmap noch zugewiessen werden muss.
Ich weiss zwar nicht ob der Umweg nötig is,t da Du ja selber sagst, mit STRG+V kannst Du die Bitmap ja schon in MSPAINT einfügen.
Ansonsten empfehle ich es so wie
Hidden es vorgeschlagen hat.Speichern musst Du sie sicherlich irgendwan!
Denn, entweder Du hängst die Datei beim Aufruf von MSPAINT mit ran, oder Du must sowieso mit STRG+V das BitMap in MSPAINT einfügen!!! Und dies funktioniert ja schon, wie Du sagst. Ich glaube nicht das es da noch andere Möglichkeiten gibt!
Gruss Alf
MaPsTaR - Di 20.07.10 12:49
Hallo, ich glaube, das Problem liegt nicht bei der Zuweisung zur Zwischenablage, sondern bei der Übergabe der Tastenkombination an Paint.
Probier mal das:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| procedure TForm1.SendBMPtoPaint; var Window: HWND; begin Application.ProcessMessages; Sleep(500); Window := FindWindow(PChar('MSPaintAPP'), nil); if Window > 0 then begin Sleep(500); SetForegroundWindow(Window); Sleep(500); keybd_event(vk_Control, MapVirtualKey(vk_Control, 0), 0, 0); keybd_event(vkKeyScan('V'), MapVirtualKey(vkKeyScan('V'), 0), 0, 0); keybd_event(vkKeyScan('V'), MapVirtualKey(vkKeyScan('V'), 0), KEYEVENTF_KEYUP, 0); keybd_event(vk_Control, MapVirtualKey(vk_Control, 0), KEYEVENTF_KEYUP, 0); end; end; |
Bei mir läuft es so, eventuell musst du die sleep's noch etwas anpassen.
Gruß MaPsTaR
ALF - Di 20.07.10 12:57
MaPsTaR hat folgendes geschrieben : |
Hallo, ich glaube, das Problem liegt nicht bei der Zuweisung zur Zwischenablage, sondern bei der Übergabe der Tastenkombination an Paint. |
Das vermute ich auch!
Wobei ich mich frage was das Sleep soll!
Die Procedure muss sowie so komplet durchlaufen werden bevor irgend etwas passiert!
Wenn dann müssten es zwei Aufrufe sein!
Der erste öffnet Paint!
Der zweite übergibt an das Handle von Paint die Tasten!!
Gruss ALf
MaPsTaR - Di 20.07.10 12:59
Das würde natürlich auch gehen, aber so wie Tony-S es angefangen hat habe ich es ohne Sleep probiert und da ist gar nichts passiert.
EDIT:
Die Werte für Sleep lassen sich bestimmt auch noch runtersetzen, das sollte von dem jeweiligen System abhängen, wie lange Paint braucht, um die Eingabe empfangen zu können.
Hatte jetzt bloß keine Lust das auch noch auszuprobieren. :-)
Tony-S - Di 20.07.10 13:08
Danke Mapstar das läuft!
Aber da ich nicht kopieren will, naja gut mach ich jetzt eh ^^, wäre es noch nett wenn du mir bissl was erklärst:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| procedure TForm1.SendBMPtoPaint; var Window: HWND; begin Application.ProcessMessages; Sleep(500); Window := FindWindow(PChar('MSPaintAPP'), nil); if Window > 0 then begin Sleep(500); SetForegroundWindow(Window); Sleep(500); wo ist der Unterschied mit MapVirtualKey? keybd_event(vk_Control, MapVirtualKey(vk_Control, 0), 0, 0); keybd_event(vkKeyScan('V'), MapVirtualKey(vkKeyScan('V'), 0), 0, 0); keybd_event(vkKeyScan('V'), MapVirtualKey(vkKeyScan('V'), 0), KEYEVENTF_KEYUP, 0); keybd_event(vk_Control, MapVirtualKey(vk_Control, 0), KEYEVENTF_KEYUP, 0); end; end; |
Ansonsten Vielen Dank an alle hier die dazu beigetragen haben, das Problem zu lösen.
Schönen Tag noch.
ALF - Di 20.07.10 13:11
Mit Sleep würde ich das nicht empfehlen! Vom Systhem abhängig! langsamer rechner langsamer aufbau von Paint
Wenn, dann warten bis das Handle von Paint da ist oder, komm auf den Begriff nicht, bis Paint onshow ist.
Dann erst die Tasten Übergabe machen! Würde ich so vorschlagen!
Gruss Alf
MaPsTaR - Di 20.07.10 13:14
Zitat: |
Mit der Methode ProcessMessages können Sie die Ausführung einer Anwendung unterbrechen, sodass die Botschaftswarteschlange verarbeitet werden kann. |
Das kannst du hier wahrscheinlich auch weglassen, ist eher in Schleifen wichtig, wenn während des Schleifendurchlaufs etwas abgearbeitet werden muss.
Zitat: |
SetForegroundWindow(Window); |
setzt Window als oberstes Fenster, damit es die Tastaturbotschaften empfängt, da man mit keybd_event kein Handle ansprechen kann.
Zitat: |
The MapVirtualKey function translates (maps) a virtual-key code into a scan code or character value, or translates a scan code into a virtual-key code. |
gibt den ScanCode einer Taste zurück, das wird für keybd_event benötigt, genauer kann ich das jetzt auch nicht erklären.
EDIT:
@ALF
Delphi-Quelltext
1: 2: 3: 4: 5:
| Window := 0; repeat Window := FindWindow(PChar('MSPaintAPP'), nil); Application.ProcessMessages; until Window <> 0; |
Mit dieser Änderung können alle Sleep's rausgenommen werden.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!