2

I'm intercepting and suppressing the WM_PASTE message for a TDBEdit by assigning its WindowProc property, as described in this answer.

After pressing Ctrl+V, despite the WM_PASTE is intercepted, the dataset's state changes from dsBrowse to dsEdit.

Why is this happening and how could I avoid that?

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, DBCtrls, StdCtrls, Mask, DB, DBClient;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    FPrevWindowProc : TWndMethod;
    procedure   MyWindowProc(var AMessage: TMessage);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  Dst : TClientDataSet;
  Dsc : TDataSource;
  Fld : TField;
  Nav : TDBNavigator;
  Edt : TDBEdit;
begin
  //dataset
  Dst := TClientDataSet.Create(Self);
  Dst.FieldDefs.Add('TEST', ftString, 20);
  Dst.CreateDataSet();
  Dst.Active := True;
  Fld := Dst.Fields[0];
  Dst.Append();
  Fld.AsString := 'test';
  Dst.Post();

  //datasource
  Dsc := TDataSource.Create(Self);
  Dsc.DataSet := Dst;

  //navigator
  Nav := TDBNavigator.Create(Self);
  Nav.DataSource := Dsc;
  Nav.Top := 3;  
  Nav.Left := 3;
  Nav.Parent := Self;

  //editor
  Edt := TDBEdit.Create(Self);
  Edt.DataSource := Dsc;
  Edt.DataField := Fld.FieldName;
  Edt.Top := 31;
  Edt.Left := 3;
  Edt.Parent := Self;
  FPrevWindowProc := Edt.WindowProc;
  Edt.WindowProc := MyWindowProc;
end;

procedure   TForm1.MyWindowProc(var AMessage: TMessage);
begin
  if(AMessage.Msg = WM_PASTE) then
  begin
    ShowMessage('WM_PASTE, exit!');
    Exit;
  end;

  FPrevWindowProc(AMessage);
end;

end.
Fabrizio
  • 7,603
  • 6
  • 44
  • 104
  • You haven't followed the example you gave correctly. The WM_PASTE message is intercepted here, but it is also passed on to the other controls, like the Edt. To really fix this, you need to subclass the Edt so that you can prevent the WM_PASTE message from having an affect on that specific control. – Freddie Bell Aug 28 '19 at 14:29
  • Off-topic: Why does this q display almost whited-out in the browse list of qs, in Firefox at any rate? – MartynA Aug 28 '19 at 18:27
  • @MartynA I have no idea what you are trying to say. It appears fine in my FireFox. – Remy Lebeau Aug 28 '19 at 18:28
  • 1
    @Martyn - You probably have one of the tags in your ignore list. watched/ignored tags list is on the right of the browse list. – Sertac Akyuz Aug 28 '19 at 18:32
  • I meant, in my FF this q unlike all the others, displays with the text much lighter that the other messages, verging on the point of invisibility. I have noticed this with particular qs every few days. – MartynA Aug 28 '19 at 18:32
  • @SertacAkyuz: Thanks. Having checked, it turns out that I do indeed have D2007 in my ignore list. – MartynA Aug 28 '19 at 18:36

1 Answers1

1

Using the interposer class solution in Remy's answer to your linked question, if you create a BeforeEdit handler for your DataSet and put a breakpoint in it, you will find that the breakpoint trips before the interposer's WMPaste() method is entered.

If you then trace out of the BeforeEdit handler, you will eventually arrive in TDBEdit.KeyPress() which (in D7) contains the code below:

procedure TDBEdit.KeyPress(var Key: Char);
begin
  inherited KeyPress(Key);
  if (Key in [#32..#255]) and (FDataLink.Field <> nil) and
    not FDataLink.Field.IsValidChar(Key) then
  begin
    MessageBeep(0);
    Key := #0;
  end;
  case Key of
    ^H, ^V, ^X, #32..#255:
      FDataLink.Edit;
    #27:
      begin
        FDataLink.Reset;
        SelectAll;
        Key := #0;
      end;
  end;
end;

So, the DataSet is put into dsEdit state by the call to FDataLink.Edit() as a result of KeyPress() seeing the ^V character.

You could achieve the behavior you want by also overriding KeyPress() in the interposer class. The following will prevent pressing ^V from having any effect:

type  // This can be in your Form's unit but must go before your Form's type declaration
  TDBEdit = class(DBCtrls.TDBEdit)
    procedure WMPaste(var Message: TMessage); message WM_PASTE;
    procedure KeyPress(var Key: Char); override;
  end;
[...]

procedure TDBEdit.WMPaste(var Message: TMessage);
begin
  if not (Message.Msg = WM_PASTE) then
    inherited;
end;

procedure TDBEdit.KeyPress(var Key: Char);
begin
  case Key of
    ^V : Key := #0;
  end;  { case }
  inherited;
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
MartynA
  • 30,454
  • 4
  • 32
  • 73
  • 2
    The check for `Message.Msg` in `WMPaste()` is not necessary since the `message` dispatcher guarantees that `WMPaste()` will only be called for `WM_PASTE` messages. So simply don't call `inherited` in `WMPaste()` at all: `procedure TDBEdit.WMPaste(var Message: TMessage); begin end;` Also, there is no need to call `inherited` in `KeyPress()` when `^V` is detected: `procedure TDBEdit.KeyPress(var Key: Char); begin if Key = ^V then begin Key := #0; Exit; end; inherited; end;` – Remy Lebeau Aug 28 '19 at 18:20
  • @Remy: Thanks but the WMPaste handler was in your code which the OP said he's used so I left it there. – MartynA Aug 28 '19 at 18:24
  • 2
    I guess what I'd do is to preserve the original window procedure replacement but replace wm_paste handler with one of wm_char. `if(AMessage.Msg = WM_CHAR) and (TWmChar(AMessage).CharCode = Ord(^V)) then Exit;` Then no wm_paste will be generated. – Sertac Akyuz Aug 28 '19 at 18:24
  • @MartynA "*the WMPaste handler was in your code*" - yes, but it didn't check the `Message.Msg`, because it didn't need to. "*which the OP said he's used*" - no, the OP used my `WindowProc` example, not my interposer example. And in a `WindowProc`, the `Message.Msg` does need to be checked. In both examples, the `SomeCondition` does not mean "check the `Message.Msg`" – Remy Lebeau Aug 28 '19 at 18:26
  • 1
    I tired and the wm_paste handler is still necessary, the vcl acts on a keypress but the OS also has a context menu!.. – Sertac Akyuz Aug 28 '19 at 19:47
  • Thanks! Where could I learn something about `^V` used for `Ctrl+V` key? – Fabrizio Aug 29 '19 at 06:45
  • There is an [SO q about it](https://stackoverflow.com/questions/13062882/why-can-the-circumflex-sign-be-used-for-control-chars-in-delphi-and-is-it-a-good); it's one of those things that's been around since TurboPascal days (and earlier). – MartynA Aug 29 '19 at 07:23