Avatar billede brian0905 Nybegynder
11. juli 2008 - 11:38 Der er 3 kommentarer og
1 løsning

Window subclass og min egen WinProc fejler

Hejsa,
Jeg eksperimenterer med at subclasse et TMemo i min egen applikation for at kunne filtrere på de messages der bliver sendt til det enkelte vindue. Jeg har følgende kode, meget simpelt:

unit GrapperTest;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    GrapperSourceWindow: TMemo;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
    procedure SubClassWin(hWnd: HWND);
    procedure UnSubClassWin(hWnd: HWND);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  OldWinProc: Integer;

implementation

{$R *.dfm}

procedure SendText(themessage: string);
var
  remoteWindow: HWND;
  cds: COPYDATASTRUCT;
begin
  remoteWindow := FindWindow(nil, 'Grapper');
  if remoteWindow <> 0 then begin
    ZeroMemory(@cds, sizeof(COPYDATASTRUCT));
    cds.dwData := 0;
    cds.cbData := 1 + Length(themessage);
    cds.lpData := PChar(themessage);
    SendMessage(remoteWindow, WM_COPYDATA, WPARAM(remoteWindow), LPARAM(@cds));
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
//  SendText('This is the text sendt');
  SubClassWin(GrapperSourceWindow.Handle);
end;

function NewWinProc(hWnd: HWND; Msg: WORD; wParam: WORD; lParam: LONGINT): LONGINT;
var
messageProcessed: boolean;
begin
  messageProcessed := false;
  if Msg = WM_SETTEXT then begin
    SendText('called set text');
    messagePRocessed := true;
  end;

  if not MessageProcessed then
      Result := CallWindowProc(Pointer(OldWinProc), hWnd,Msg,wParam,lParam)
  else
      Result := 0;

end;


procedure TForm1.SubClassWin(hWnd: HWND);
begin
  OldWinProc := SetWindowLong(hWnd, GWL_WNDPROC, LongInt(@NewWinProc));
end;


procedure TForm1.UnSubClassWin(hWnd: HWND);
begin
  SetWindowLong(hWnd,GWL_WNDPROC,OldWinProc);
end;


procedure TForm1.Button2Click(Sender: TObject);
begin
  GrapperSourceWindow.Text := GrapperSourceWindow.Text+'ABC.';
end;

end.

Problemet opstår når den løber min egen WinProc igennem (NewWinProc) det ser ud til den får lov at løbe et par gange og så går den ned. Jeg klikker på min knap, og hvis jeg flytter musen ind på mit memo kommer den ind i min egen winproc og laver en exception og stiller sig i cpu vinduet.. jeg aner ikke hvad jeg skal gøre... Arbejder normalt med  C# :-)
Avatar billede psycosoft-funware Nybegynder
11. juli 2008 - 20:57 #1
ved første øjekast, kan jeg se at du har valgt at bruge en fordefineret type både som variable navn og type (hWnd og HWND ), Delphi er ikke Case-Sensitive som C++ er (mener også C skarp er men skal ikke gøre mig klog på) :)
Avatar billede hrc Mester
12. juli 2008 - 00:24 #2
Det kan godt være at Psykosoft har fat i noget her. Jeg plæderer altid for at foranstille parametre med et "a" således, at din UnSubClass får parametrene (aHWND: HWND).

Eksempelvis sådan her:

function NewWinProc(aHWND: HWND; aMsg: WORD; aWParam: WORD; aLParam: LONGINT): LONGINT;
begin
  if aMsg = WM_SETTEXT then
  begin
    SendText('called set text');
    Result := 0;
  end
  else
    Result := CallWindowProc(Pointer(OldWinProc), aHWND,aMsg,aWParam,aLParam)
end;

I øvrigt kan du prøve at benytte dig af OutputDebugString til at pumpe debugmeddelelser ud.

På samme måde plejer man i Delphi at sætte et "f" foran de private attributter. En af de her De-facto standarder.

I øvrigt er C# et brain child af Anders Hejlsberg ... som fostrede Compas-/Poly-/Turbo-Pascal og i sidste ende Delphi. Da AH. rejste til MS fik han nok chancen for bygge det  bedste med over. Savner en garbage collector selvom den sikkert er en ydelsesdræber (æv, nu døde Dennis Hopper og Peter Fonda igen).
Avatar billede brian0905 Nybegynder
13. juli 2008 - 19:27 #3
Prøvede det, men uden held. Kan godt se at det ville give problemer, man skal lige vænne sig til at skifte til et nyt miljø :-)

Jeg prøvede at køre igen, men det ser ud til at den stopper i min nye WinProc (NewWinProc) den looper den igennem et par gange og så stopper den på den sidste "end" i min funktion (i stedet for at returnere) så venter den bare i et par sekunder og laver så en fejl om at den ikke kan læse instruktionen i blablabla 0x000000 Det ser ud til at den har kørt rekursivt og laver nu backtracking og har tabt en reference??? nogle gode ideer?
Avatar billede brian0905 Nybegynder
14. juli 2008 - 11:20 #4
Fik det til at virke, ved ikke helt hvorfor ændringen virker bedre... (gå fra function til procedure). Til alle der forsøger i fremtiden, dette virker:

unit GrapperTest;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    GrapperSourceWindow: TMemo;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
    hProc: TFarProc;
    sourceWindow: HWND;
    procedure SubClassWin(aHWND: HWND);
    procedure UnSubClassWin(aHWND: HWND);
  public
    { Public declarations }
    procedure SendText(themessage: string);
    procedure NewWinProc(var aMsg: TMessage);
  end;

var
  Form1: TForm1;
  OldWinProc: Integer;

implementation

{$R *.dfm}

procedure TForm1.SendText(themessage: string);
var
  remoteWindow: HWND;
  cds: COPYDATASTRUCT;
begin
  remoteWindow := FindWindow(nil, 'Grapper');
  if remoteWindow <> 0 then begin
    ZeroMemory(@cds, sizeof(COPYDATASTRUCT));
    cds.dwData := 0;
    cds.cbData := 1 + Length(themessage);
    cds.lpData := PChar(themessage);
    SendMessage(remoteWindow, WM_COPYDATA, WPARAM(remoteWindow), LPARAM(@cds));
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  //SendText('This is the text sendt');
  SubClassWin(GrapperSourceWindow.Handle);
end;

procedure TForm1.SubClassWin(aHWND: HWND);
var
  fproc: TFarProc;
begin
//  OldWinProc := SetWindowLong(hWnd, GWL_WNDPROC, LongInt(@NewWinProc));
  sourceWindow := aHWND;
  hproc:=TFarProc(GetWindowLong(aHWND,GWL_WNDPROC));
  fproc := MakeObjectInstance(NewWinProc);
  OldWinProc := SetWindowLong(aHWND, GWL_WNDPROC, longword(fproc));
end;


procedure TForm1.UnSubClassWin(aHWND: HWND);
begin
  SetWindowLong(aHWND,GWL_WNDPROC,OldWinProc);
end;


procedure TForm1.Button2Click(Sender: TObject);
begin
  GrapperSourceWindow.Text := GrapperSourceWindow.Text+'ABC.';
end;

procedure TForm1.NewWinProc(var aMsg: TMessage);
begin
  case aMsg.msg of
  WM_SIZE:
  begin
    SendText('Resize the memo');
  end;
end;
//all unhandled messages are sent to original procedure. Here,
//hproc is the  handle to the original window procedure.
aMsg.result := CallWindowProc(hproc, sourceWindow, aMsg.msg, aMsg.wparam, aMsg.lparam);

end;

end.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester