RichEdit - WM_PASTE abfangen



  • Ich möchte gerne verhindern (oder besser kontrollieren), wenn mit Paste etwas aus der Zwischenablage in ein RichEdit kopiert wird. Dabei dachte ich, ich könnte WM_PASTE abfangen, gemäss der guten FAQ von WebFritzi.

    Leider tut sich aber nix: Die neue Handlerfunktion wird NIE aufgerufen. Ich habe es auf die in der FAQ von WebFritzi beschriebene erste Art versucht; das heisst, einen Nachfahren von TRichEdit erzeugt, und dann mit

    BEGIN_MESSAGE_MAP
    	MESSAGE_HANDLER(WM_PASTE, TMessage, wmPaste);
      END_MESSAGE_MAP(inherited)
    

    Was ist falsch? - Ich habe auf dem INet Workarounds gefunden, wie etwa Ctrl-V und Ctrl-Ins abfangen. Das ist aber höchst hässlich, und ich möchte es besser lösen. Bitte um Hilfe! - Danke!

    - Adrian



  • Übrignes funktioniert das Abfangen von WM_PASTE auch mit einer neu geschriebenen WndProc nicht. Weshalb nicht?

    Gibt es irgend ne Möglichkeit, zu Debuggen, wo überall die Message WM_PASTE durchgeht? - so dass ich sehe, wo sie schon früher behandelt und abgefangen wird?
    Oder weiss einer die Lösung?

    - Adrian



  • Hmm, habe gleich mal noch in der MSDN bei WM_PASTE gelesen:

    An application sends a WM_PASTE message to an edit control or combo box to copy the current content of the clipboard to the edit control at the current caret position.

    Scheibar funktioniert das wirklich nur bei Edit Controls (habe es ausprobiert mit einem TEdit, dort klapperts auf beide Arten). Wieso aber nicht bei RichEdit? - RichEdit ist ja auch von Edit abgeleitet. (von TCustomEdit, so wie TEdit selbst auch)

    - Adrian



  • Probier mal mit SetWindowLong(RichEdit->Handle,GWL_WNDPROC,NeueWndProc) auf eine neue WndProc zu Verweisen:

    static LONG alteWndProc;
    alteWndProc = SetWindowLong(RichEdit->Handle,GWL_WNDPROC,NeueWndProc);
    /* ... */
    LRESULT CALLBACK NeueWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch(message)
        {
          case WM_PASTE:
            /* bla bla */
            break;
          /* case, default weiter */
        }
    return CallWindowProc((WNDPROC) alteWndProc, hwnd, message, wParam, lParam);
    }
    

    Die RichEdit sitzt in einer DLL und ist daher keine Ableitung eines Edit, beim BCB ist es eine Ableitung der Klasse TEdit um dessen Funktionen zu Erben.



  • msdn::SetWindowLong

    Return Values

    If the function succeeds, the return value is the previous value of the specified 32-bit integer.
    If the function fails, the return value is zero. To get extended error information, call GetLastError.
    If the previous value of the specified 32-bit integer is zero, and the function succeeds, the return value is zero, but the function does not clear the last error information. This makes it difficult to determine success or failure. To deal with this, you should clear the last error information by calling SetLastError(0) before calling SetWindowLong. Then, function failure will be indicated by a return value of zero and a GetLastError result that is nonzero.

    Komisch, ich habe das schon oft gemacht, aber der BCB und Dev meckern egal was ich angebe, ob WNDPROC xxx = SetWindowLong() oder long etc.
    Vieleicht bin ich auch noch zu Müde, teste das später mal 🙂



  • So da ich jetzt Fit bin, weiß ich auch wieder wie es mit dem BCB geht:

    #define STRICT /* WICHTIG */
    #include <vcl.h>
    #pragma hdrstop
    #include <windows.h>
    #include "Unit1.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    WNDPROC alteProc;
    LRESULT CALLBACK neueProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
    {
    alteProc = NULL;
    alteProc = (WNDPROC)SetWindowLong(RichEdit1->Handle, GWL_WNDPROC, (long)neueProc);
    }
    //---------------------------------------------------------------------------
    LRESULT CALLBACK neueProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    
     /* Hier die Message bearbeiten */
    
     return CallWindowProc((WNDPROC) alteProc, hwnd, message, wParam, lParam);
    }
    

    Nur leider steige ich nicht dahinter welcher Code gesendet wird für Paste.
    Habe einige ausprobiert, aber keiner will.



  • Hey, erstmal vielen Dank für Deine Mühe.

    Aber: Auch in die Funktion

    LRESULT CALLBACK neueProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    

    springt er nicht beim Einfügen (Paste, Ctrl+V, Shift+Ins) in das RichEdit. (Habe mal ein Beep in die Funktion reingeschrieben. Zwischendurch biebst es, aber beim Zwischenablage Einfügen nicht -> er geht nicht in die Funktion hinein)

    Seh ich etwas falsch?

    - Adrian



  • Doch macht er, nur Beep ist zu langsam, er sendet 14 Nachrichten
    ab Nummer 10:

    0:70
    1:71
    2:7
    3:45082
    4:133
    5:20
    6:15
    7:15
    8:20
    9:20
    10:48384 <--- KeyDown für Richedit (eigenes)
    11:256
    12:48384
    13:256 WM_KEYDOWN
    14:48386 <-- keyDown für Char
    15:258 WM_CHAR
    16:15 WM_PAINT
    17:133 WM_NCPAINT
    18:20 WM_ERASEBKGND
    19:20 WM_ERASEBKGND
    20:48385 <-- KeyUp RichEdit
    21:257 WM_KEYUP
    22:48385
    23:257

    daher meine Alternative:

    #define STRICT /* WICHTIG */
    #include <vcl.h>
    #pragma hdrstop
    #include <windows.h>
    #include "Unit1.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    WNDPROC alteProc;
    bool Keys[255];
    LRESULT CALLBACK neueProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
    {
    alteProc = NULL;
    alteProc = (WNDPROC)SetWindowLong(RichEdit1->Handle, GWL_WNDPROC, (long)neueProc);
    }
    //---------------------------------------------------------------------------
    LRESULT CALLBACK neueProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        if (message == WM_KEYDOWN) Keys[wParam] = true;
        if (message == WM_KEYUP) Keys[wParam] = false;
    
        if (Keys[VK_CONTROL] && Keys['V']) {
           /* Hier Code Ausführen */
    
        }
    
     return CallWindowProc((WNDPROC) alteProc, hwnd, message, wParam, lParam);
    }
    


  • Danke für die Infos. Aber das ist jetzt genau den Murks mit Ctrl+V und Shift+Ins abfangen. Ist doch nicht schön, oder?

    Wenn manns so machen würde, ginge es auch einfacher: mit zwei Actions: Eine normal Einfügen mit Ctrl+V und eine Versteckte für Shift+Ins..

    Aber das MUSS doch noch sauberer gehen, oder???

    - Adrian



  • Ich könnte mir gut Vorstellen das RichEdit1->Handle nicht das Handle der Eigentlichen RichEdit20A ist sondern ein anderes Objekt (Ole) in der die RichEdit als Child sitzt, man müßte mit FindWindow das mal ermitteln.



  • Guter Punkt. Nehme mal Spy++ zur Hilfe.

    - Adrian



  • So, ich habe mal mit Spy++ das ganze untersucht.
    Das Handle stimmt überein. Eine WM_PASTE oder WM_PASTESPECIAL Message sehe ich nie vorbei flitzen. Sonst viel Zeugs, z.B: natürlich das Drücken von Ctrl und V... aber dann auch noch "unknown" Messages. Was ist mit denen? von wo kommen die?

    Huch, habe ich mir nicht ganz so schwierig vorgestellt. Hat mir noch einer nen Tip?
    - Adrian



  • Die Unbekannten sind wohl die eigenen von der RichEdit, schau mal in der richedit.h



  • Hmm, dort sind ganz viele definiert. Aber lauter solche, die man auch in der Hilfe findet.
    Ich bin aber noch auf etwas interessantes gestossen: Auf EM_CANPASTE

    The EM_CANPASTE message determines whether a rich edit control can paste a specified clipboard format.

    Nun, was muss man wohl für das Format angeben, damit er nur plain text frisst? - Ist das überhaupt ein möglicher Ansatz?

    Ist es nicht komisch, dass kein WM_PASTE auftritt?

    Bis Morgen,
    - Adrian



  • Ne, ich gebe noch nicht auf. Hat keiner mehr nen Tip für mich parat?

    - Adrian



  • Ich habe gar nicht mehr an das thema gedacht, zu viel zu tun 😞

    So wie ich das letztens in erfahrung bringen konnte, behndelt die Richedit alles manuel, nur wenn über WM_CANPASTE Plain gesetzt ist (also ohne Textformatierung), dann kann/wird ein WM_PASTE gesendet.
    Ich habe aber mal vor langer zeit ein OnbevorChange() ereignis für die Richie geschrieben, ich muß das mal suchen morgen, das könnte dann weiter helfen, so aus dem Kopf wüßte ich es jetzt auch nicht.



  • nur wenn über WM_CANPASTE Plain gesetzt ist

    Wie setzt man das?

    Ja, wenn Du mir OnBeforChange mal zeigen könntest, wäre ich Dir natürlich sehr dankbar 👍 👍

    - Adrian


Log in to reply