Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Text in ein DBRichEdit einfügen per SendMessage() (https://www.delphipraxis.net/206802-text-ein-dbrichedit-einfuegen-per-sendmessage.html)

juergen 30. Jan 2021 23:30


Text in ein DBRichEdit einfügen per SendMessage()
 
Hallo zusammen,

ich versuche nun schon länger einen Text per SendMessage() in ein DBRichEdit einzufügen.
Das Handle habe ich und es ist auch korrekt. Es passiert aber nichts. Der DB-Navigator zeigt keinerlei Änderung und demzufolge steht im DBRichEdit auch nicht mein Text.
Versucht habe ich einiges.
U.a. das hier:
Delphi-Quellcode:
  s := 'Test, Test, Test';
  FOR i := 1 TO Length( s ) DO
    SendMessage( my_HWnd, WM_CHAR, Word( s[i] ), 0 );
  // Simulate Return Key.
  PostMessage( my_HWnd, WM_KEYDOWN, VK_RETURN, 0 );
  // Simulate Space.
  PostMessage( my_HWnd, WM_KEYDOWN, VK_SPACE, 0 );
Mit Notepad z.B. funktioniert es.

Hat jemand eine wertvollen Tipp für mich?

Vielen Dank schon mal vorab!

hoika 31. Jan 2021 00:02

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
Hallo,
ist das DataSet im EditMode?

juergen 31. Jan 2021 00:13

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
Ja.
Ich weiß nicht ob es wichtig ist: es ist eine Fremdanwendung.

jziersch 31. Jan 2021 10:58

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
Eine Möglichkeit wäre noch
WM_PASTE

venice2 31. Jan 2021 11:51

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
WM_COPYDATA
Aber keine gewähr ob die andere Anwendung diese Message behandelt.

juergen 31. Jan 2021 20:13

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
Es liegt an der Fremdanwendung. Bei anderen Anwendungen funktioniert es. Da kann man wohl nichts machen.

hoika 1. Feb 2021 06:35

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
Hallo,
Zitat:

DBRichEdit und Fremdanwendung.
Woher weisst Du., dass es ein DBRichEdit ist?

Zitat:

Mit Notepad z.B. funktioniert es.
Dein Code trägt in Notepad was ein?

Klappt es denn über die Windows-Zwischenablage?
Dann wäre das obige WM_PASTE eine Überlegung wert.
Du kopierst deine Daten in die Zwischenablage und schickst dem Fenster ein WM_PASTE.

juergen 1. Feb 2021 07:41

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
Gute Morgen,
über WinSpy kann ich sehen welches Control es ist. Allerdings ist es kein Standardcontrol von Delphi, sondern ein abgeleitetes Control von DBRichEdit. (die Fremdanwendung ist auch in Delphi geschrieben)
Die Zwischenablage wollte ich nicht zerstören, da das Ganze recht häufig angewendet werden soll. Im Prinzip sollte es ein Ersatz für PhraseExpress werden. Also pro globalem Hotkey einen bestimmten Textbaustein am Mauscursor einfügen.

himitsu 1. Feb 2021 08:02

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
Notepad ist ein Memo. (Wordpad ist das RichEdit)

WM_KEYDOWN alleine: Wenn man eine Taste drückt, dann muß man sie auch wieder loslassen!!!

WM_CHAR alleine reicht nicht immer aus.
Eine Tastendruck besteht aus einem/mehreren WM_KEYDOWN, einem WM_CHAR und einem/mehreren WM_KEYUP.
Rate mal, warum es mehrere Versuche von SndKey/SendKey/... gibt.



Tipp: EM_REPLACESEL (TCustomComboBox.SetSelText)

HolgerX 1. Feb 2021 16:49

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
Hmm...

Zitat:

Zitat von juergen (Beitrag 1481900)
Gute Morgen,
über WinSpy kann ich sehen welches Control es ist. Allerdings ist es kein Standardcontrol von Delphi, sondern ein abgeleitetes Control von DBRichEdit. (die Fremdanwendung ist auch in Delphi geschrieben)
Die Zwischenablage wollte ich nicht zerstören, da das Ganze recht häufig angewendet werden soll. Im Prinzip sollte es ein Ersatz für PhraseExpress werden. Also pro globalem Hotkey einen bestimmten Textbaustein am Mauscursor einfügen.



wie in diesem Tread aus 2018:

https://www.delphipraxis.net/1419689-post33.html

Das Testtool macht etwas ähnliches..

Es wartet auf einen (Hot-) Key und schickt einen Text als KeyEvent.

Musst jetzt nur eigenen Keys definieren und statt des Memos von Dir vorgegebene Texte schicken.

juergen 1. Feb 2021 18:40

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Holger,
vielen Dank, lieb gemeint. U. a. hatte ich es auch so probiert wie in deinem Source. Aber es funktioniert einfach nicht.
Es muss an der Fremd-Anwendung liegen.
Ich habe zig Varianten durch probiert und es klappt einfach nicht. Mit anderen Anwendungen hatte ich kein Problem. Das Handle ist auch immer korrekt, das DBRichEdit ist im Editmodus, es wird aber kein Text übernommen.
WinSpy zeigt mir auch an, dass es wohl eine Midi-Anwendung ist. Ob es damit was zu tun haben könnte? Ich bin da echt ratlos.
Lt. Debugger wird alles korrekt ausgeführt.

@himitsu,
leider war mein Code-Ausschnitt unvollständig. Ich hatte das alles ausprobiert, auch mit WM_KEYUP. In Zukunft muss ich da etwas genauer den Code-Ausschnitt aufbereiten.

Was meintest du mit
Zitat:

Rate mal, warum es mehrere Versuche von SndKey/SendKey/... gibt.

himitsu 1. Feb 2021 19:12

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
Wie gesagt, siehe Bei Google suchenDelphi SendKeys / Hier im Forum suchenSendKeys
oder eben MSDN-Library durchsuchenEM_REPLACESEL ala
Delphi-Quellcode:
RichEdit.SelText := '...';
.


Hat das Programm, bzw. das RichEdit den Eingabefocus?

juergen 1. Feb 2021 20:55

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
@himitsu,
dank dir für deine Mühe!
Ich habe deine Tipps auch probiert, aber selbes Ergebnis: Die Showmessage wird aufgerufen und zeigt das richtige Handle an, aber im DBRichEdit der Fremdanwendung passiert absolut nichts.
Das DBRichEdit im Fremdprogramm hat immer den Fokus (Cursor blinkt im DBRichEdit), jeweils einmal im Editiermodus getestet und einmal ohne.

Wie kann ich denn in einem Fremdprogramm
Zitat:

RichEdit.SelText :=
setzen?


Hier mal einer meiner Tests:

Delphi-Quellcode:
PROCEDURE Tfrm_Main.WMHotKey( VAR Msg: TWMHotKey );
VAR
  s: STRING;
  copyDataStruct: TCopyDataStruct;
BEGIN
  gc_my_DBRichEdit_Handle := Handle_DBRichEdit_ermitteln { Return Handle-ID };
  TRY
    IF ( Msg.HotKey = Hotkey_id ) AND ( gc_my_DBRichEdit_Handle > 0 ) THEN
    BEGIN
      s := 'Das ist ein Test';
      copyDataStruct.cbData := 1 + ( Length( s ) * SizeOf( Char ) ); // !!!
      copyDataStruct.lpData := PChar( s );

      Keybd_Event( VK_RETURN, 0, 0, 0 ); // Taste drücken
      Keybd_Event( VK_RETURN, 0, KEYEVENTF_KEYUP, 0 ); // Taste loslassen

      SendMessage( gc_my_DBRichEdit_Handle, EM_REPLACESEL, 0, LPARAM( @copyDataStruct ) );
      Sleep( 2000 );

      ShowMessage( s + ' Handle-ID=' + IntToStr( gc_my_DBRichEdit_Handle ) );
    END;
  FINALLY
    // gc_my_DBRichEdit_Handle := 0; { TODO 2 -oJS -cnoch zu erledigen : Nach den Tests ist das zu aktivieren, damit die Variable nach jedem Aufruf auch initialisiert ist }
  END;
END;

himitsu 1. Feb 2021 21:21

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
Ein CopyDataStruct für was Anderes verwenden zu wollen, als für WM_COPYDATA ... naja :zwinker:

Hier bissl Was zum Abgucken und Ideenholen:
Delphi-Quellcode:
procedure TCustomEdit.SetSelTextBuf(Buffer: PChar);
begin
  SendMessage(Handle, EM_REPLACESEL, 0, LPARAM(Buffer));
end;

// oder besser
procedure TCustomEdit.DoSetTextHint(const Value: string);
begin
  ...
  SendTextMessage(Handle, EM_SETCUEBANNER, 0, Value);
end;
Und natürlich auch beim Hersteller nachzulesen.
MSDN-Library durchsuchenEM_REPLACESEL : https://docs.microsoft.com/en-us/win.../em-replacesel


PS, auch wenn es hier keine Lösung werden wird:
Selbst wenn es so funktioniert hätte, dann wäre aber die Größe dennoch falsch geworden.
Zitat:

Delphi-Quellcode:
1 + ( Length( s ) * SizeOf( Char ) )

Die abschließende #0 hätte natürlich auch 2 Byte groß sein wollen.
Erst (Length+1) und dann das *.

juergen 1. Feb 2021 21:55

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
@himitsu,

danke für die Hinweise. Es hilft alles nichts, noch nie hat das DBRichEdit aus der Fremdanwendung überhaupt mal reagiert. Es scheint keine Messages von "außen" anzunehmen. Da bin ich mir ziemlich sicher. Da kann man wohl nichts machen.
Was als Q&D ginge, wäre den Text über Clipboard einzufügen, das funktioniert. Aber das will ich nicht. Ich mach da jetzt nichts mehr.

Gute N8! :dp:

juergen 5. Feb 2021 21:48

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
Hallo zusammen,
also, ich weiß inzwischen, dass es nicht so einfach ist einen Text an ein RichEdit zu senden.
Ich taste mich nun so langsam ran, erst mal mit dem RichEdit von WordPad.
Das Handle zu ermitteln wenn Wordpad im Vordergrund ist, ist kein Problem.
Ich habe folgenden Source der prinzipiell einen Text an ein RichEdit innerhalb meiner eigenen Anwendung sendet:

Delphi-Quellcode:
// Source von Dr. Peter Below
TYPE
  TMyRichEdit = TRichEdit;

TYPE
  TEditStreamCallBack = FUNCTION( dwCookie: Longint; pbBuff: PByte;
    cb: Longint; VAR pcb: Longint ): DWORD; STDCALL;

  TEditStream = RECORD
    dwCookie: Longint;
    dwError: Longint;
    pfnCallback: TEditStreamCallBack;
  END;


FUNCTION EditStreamInCallback( dwCookie: Longint; pbBuff: PByte;
  cb: Longint; VAR pcb: Longint ): DWORD; STDCALL;
VAR
  theStream: TStream;
  dataAvail: LongInt;
BEGIN
  theStream := TStream( dwCookie );
  WITH theStream DO
  BEGIN
    dataAvail := Size - Position;
    Result := 0; { assume everything is ok }
    IF dataAvail <= cb THEN
    BEGIN
      pcb := READ( pbBuff^, dataAvail );
      IF pcb <> dataAvail THEN // couldn't read req. amount of bytes
          result := 0; // E_FAIL;
    END
    ELSE BEGIN
      pcb := READ( pbBuff^, cb );
      IF pcb <> cb THEN
          result := 0; // E_FAIL;
    END;
  END;
END;

FUNCTION EditStreamOutCallback( dwCookie: Longint; pbBuff: PByte;
  cb: Longint; VAR pcb: Longint ): DWORD; STDCALL;
VAR
  theStream: TStream;
BEGIN
  theStream := TStream( dwCookie );

  WITH theStream DO
  BEGIN
    IF cb > 0 THEN
        pcb := WRITE( pbBuff^, cb );
    Result := 0;
  END;
END;

PROCEDURE GetRTFSelection( aRichEdit: TRichEdit; intoStream: TStream );
VAR
  editstream: TEditStream;
BEGIN
  WITH editstream DO
  BEGIN
    dwCookie := Longint( intoStream );
    dwError := 0;
    pfnCallback := EditStreamOutCallBack;
  END;
  aRichedit.Perform( EM_STREAMOUT, SF_RTF OR SFF_SELECTION, longint( @editstream ) );
END;

PROCEDURE PutRTFSelection( aRichEdit: TRichEdit; sourceStream: TStream );
VAR
  editstream: TEditStream;
BEGIN
  WITH editstream DO
  BEGIN
    dwCookie := Longint( sourceStream );
    dwError := 0;
    pfnCallback := EditStreamInCallBack;
  END;
  aRichedit.Perform( EM_STREAMIN, SF_RTF OR SFF_SELECTION, longint( @editstream ) );
END;
Ich weiß nun nicht, wie ich es hinbekomme, dass ich einen Text an ein RichEdit einer Fremd-Anwendung (Wordpad) gesendet bekomme. :oops:
Die Frage ist, wie ich das Control in der Fremd-Anwendung ansprechen kann. Das was ich habe ist das Handle dieses Controls. Die Procedure PutRTFSelection erwartet ein RichEdit.

Delphi-Quellcode:
PROCEDURE Tfrm_Main.WMHotKey( VAR Msg: TWMHotKey );
VAR
  SS: TStringStream;

  FUNCTION WORDPAD_finden_TEST: THandle;
  VAR
    Len: LongInt;
    Title: STRING;
    Main_Wnd, wndChild: THandle;
  BEGIN
    Result := 0;
    Main_Wnd := GetForegroundWindow;
    IF Main_Wnd <> 0 THEN
    BEGIN
      Len := GetWindowTextLength( Main_Wnd ) + 1;
      SetLength( Title, Len );
      GetWindowText( Main_Wnd, PChar( Title ), Len );
      IF ( Pos( 'wordpad', LowerCase( Title ) ) > 0 ) THEN
      BEGIN
        IF Main_Wnd <> 0 THEN
        BEGIN
          wndChild := FindWindowEx( Main_Wnd, 0, 'RICHEDIT50W', NIL );
          IF wndChild <> 0 THEN
          BEGIN
            Result := wndChild;
          END;
        END;
      END;
    END;
  END;

BEGIN
  TRY
    gc_my_DBRichEdit_Handle := WORDPAD_finden_TEST;
    IF ( Msg.HotKey = Hotkey_id ) AND ( gc_my_DBRichEdit_Handle > 0 ) THEN
    BEGIN
      SS := TStringStream.Create
        ( '{\rtf1\ansi\ansicpg1252\deff0\deflang2055{\fonttbl{\f0\fswiss\fprq2\fcharset0 Arial;}{\f1\fnil MS Sans Serif;}}\viewkind4\uc1\pard\ul\b\f0\fs24 Test\ulnone\b0\f1\fs16\par}' );
      TRY
        PutRTFSelection( RICHEDIT1, SS ); // <==== wie komme ich hier das Control von Wordpad angesprochen (RICHEDIT50W), anstelle meinem RichEdit1
      FINALLY
        SS.Free;
      END;

      ShowMessage( 'Handle-ID=' + IntToStr( gc_my_DBRichEdit_Handle ) );
    END;
  FINALLY
    //
  END;
END;

Vielen Dank für Hinweise!

himitsu 6. Feb 2021 04:16

AW: Text in ein DBRichEdit einfügen per SendMessage()
 
Ich bin mir fast sicher, dass du EM_STREAMIN nur innerhalb deiner Anwendung nutzen darfst.

Um es an einen anderen Prozeess schicken zu können,
müsstest du deinen Code von EditStreamInCallback/EditStreamOutCallback erst in diesen Prozess injizieren,
denn was will das andere Programm mit einem Pointer für deinen Speicher, wenn es seinen eigenen Speicher hat und an jener Stelle nichts oder sonstwas liegen wird.


Zitat:

Delphi-Quellcode:
 dwCookie := Longint( intoStream );

Wen sollen wir dafür steinigen?

UIntPtr oder NativeUInt
bzw.
IntPtr oder NativeInt

Aber auch TEditStream, TEditStreamCallBack, EditStreamInCallback und EditStreamOutCallback sind falsch deklariert.
DWORD_PTR -> https://docs.microsoft.com/en-us/win...streamcallback


Es gibt nur eine Message, welche "irgendeinen" Speicher selbstständig in den Zielprozess kopiert. (WM_COPYDATA)
Zusätzlich machen das auch noch die bekannten Text-Messages ala WM_SETTEXT.

Selbst wenn EM_STREAMIN/EM_STREAMOUT den Speicher von EDITSTREAM/TEditStream rüberkopiert, dann bleibt dennoch deine Funktion, und das von ihr Verwendete, bei dir.
Hast mal geschaut, ob es eine Variante mit IStream gibt? (z.B. beim Clippboard gibt es Schnittstellen, welche damit auch prozesssübergreifend funktionieren)

https://www.quickmacros.com/forum/sh...t=em_streamout
Zitat:

To get RTF from other process, would need to create dll file, for example in C language, and inject it into that process, for example with a hook.
k.A. ob das mit dem FileHandle hier funktioniert, aber vermutlich wird EM_STREAMIN/EM_STREAMOUT kein DuplicateHandle benutzen, womit "dein" Handle drüben ungültig wäre.
https://www.codeproject.com/Question...icateHandle-fu


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:43 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz