Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi wndproc geht nicht (https://www.delphipraxis.net/210835-wndproc-geht-nicht.html)

milurt 19. Jun 2022 13:05

wndproc geht nicht
 
i habe ein program, aber die vierecke reagieren nicht auf
tastatur und maus:

Delphi-Quellcode:
program bspforum01;

  uses
  wintypes,
  Winprocs;

  Var
    Cls:WNDCLASSEX;
    dk,db,dm:ShortInt;

Function wndproc(hwnd:HWND;m,w:word;l:longint):LongInt;
  Begin
    case m of
      $100:dk:=-1*dk;
      $201:db:=-1*db;
      $200:dm:=-1*dm;
      $204:db:=2;
    end;
  End;

  Function regwin:Integer;
  Begin
    cls.cbSize:=sizeof(cls);
    cls.style:=CS_HREDRAW Or CS_VREDRAW;
    cls.lpfnWndProc:=Addr(wndproc);
    cls.cbClsExtra:=0;
    cls.cbWndExtra:=0;
    cls.hInstance:=GetModuleHandle(nil);; {IH}
    cls.hIcon:=winprocs.LoadIcon(0, IDI_APPLICATION);
    cls.hCursor:=0;
    cls.hCursor:=0;
    cls.hbrBackground:=(14 + 1);
    cls.lpszMenuName:=NiL;
    cls.lpszClassName:='Win here'#0;
    cls.hIconSm:=LoadIcon(cls.hInstance, IDI_APPLICATION);

    regwin:=winprocs.RegisterClassEx(cls);
  End;

  Function creWin:word;
    Var
      s2,s1:pchar;
      wndparent:hwnd;
      menu:hmenu;
      instance:thandle;
      param:pointer;
  Begin
    S2:='STATIC'#0;
    S1:='Win here'#0;
    wndparent:=0;
    menu:=0;
    instance:=0;
    param:=NiL;
    creWin:=winprocs.createwindow(s2,s1,ws_popup,20,40,300,200,
      wndparent,menu,instance,param);
  End;

  Var hwnd:Word;

  procedure draw4(hwnd,x,y,wid,hei:word;r,g,b:byte);
    Var
      DC,bp:HDC;
      xx,yy,Pos:LongInt;
      PaintStrc:wintypes.TPAINTSTRUCT;
  Begin
    DC:=winprocs.getdc(hwnd); {device context of window}
    PaintStrc.hdc:=DC;
    PaintStrc.ferase:=false;
    PaintStrc.rcpaint.left:=0;
    PaintStrc.rcpaint.top:=0;
    PaintStrc.rcpaint.right:=X+wid;
    PaintStrc.rcpaint.bottom:=Y+hei;
    bp:=winprocs.BeginPaint(hwnd,PaintStrc);
    for yy:=1 To hei Do
      For xx:=1 To wid Do
      Begin
        winprocs.SetPixel(dc,x+xx,y+yy,(((r*256)+g)*256)+b);
      End;
    winprocs.EndPaint(hwnd,PaintStrc);
    releasedc(hwnd,dc);
  end;

Begin
  dk:=-1;db:=-1;dm:=-1;
  regwin;
  hwnd:=crewin;
  showwindow(hwnd,sw_show);
  updatewindow(hwnd);
  Repeat
    if dk=-1 Then draw4(hwnd,02,02,20,20,$C0,$00,$00)
      else draw4(hwnd,02,02,20,20,$40,$40,$00);
    if db=-1 Then draw4(hwnd,24,02,20,20,$00,$C0,$00)
      else draw4(hwnd,24,02,20,20,$00,$40,$40);
    if dm=-1 Then draw4(hwnd,46,02,20,20,$00,$00,$C0)
      else draw4(hwnd,46,02,20,20,$40,$00,$40);
    showwindow(hwnd,sw_show);
    updatewindow(hwnd);
  Until db=2;
end.

Daniel 19. Jun 2022 13:29

AW: wndproc geht nicht
 
Moin,

Du hast - allem Anschein nach - von irgendwoher einen sehr alten Programmcode (die Units WinProcs und WinTypes sind hier ein Indikator) und möchtest nun was genau erreichen?
Alles selbst machen zu wollen, ist am Anfang vielleicht etwas ambitioniert.

Lasse Delphi das Fenster selbst erstellen und dann nimm vielleicht zunächst irgendwas Fertiges wie z.B. einen Button oder ein Panel. Und dann mache Dich damit vertraut, wie man auf Tastatur-Eingaben reagiert (OnKeyPress z.B.) - sobald Du da Erkenntnisse gewonnen hast, baut sich das Mosaik nach und nach zusammen und Du könntest Objekte auf dem Canvas herumschubsen.

Als offenes Wort: Wenn Dir nicht klar ist, warum Dein Code nicht auf Tastatur-Eingaben reagiert, hast Du noch ein paar Lern-Schritte dort Dir. Das ist nicht schlimm, wir alle haben mal angefangen - es ist nur wichtig, dies zu realisieren.

himitsu 19. Jun 2022 14:28

AW: wndproc geht nicht
 
Noch schlimmer. Es könnte eventuell sogar ein Code für Delphi 1 sein, also für ein 16 Bit Windows. (Windows 1.0 bis 3.11)
Hat dieser Code jemals funktioniert, dann wohl eher nur in uralten Windowsen. (vor allem die fehlende Messagebehandlung und die echt winzige Darstellung, schon bei FullHD)

Und es gibt unmassen Fehler:

* Rückgabewerte nicht zugewiesen -> WindowProc
* Aufrufconvention (stdcall) vergessen -> WindowProc
* Handle (HWND) sind seit laaangem eigentlich 32 Bit, aber hier Word (auch wenn es zufällig noch funktionieren könnte, aber nicht muß)

* es wird eine Fensterklasse "Win here" registriert (RegisterClass), aber Diese garnicht verwendet, da bei CreateWindow ein anderer Name "STATIC" angegeben wurde, während "Win here" dort als Caption genutzt wurde
** also die WindowProc wurde niemals verwendet (weil in anderer Klasse)

* UND, weil es keine MessageBehandlung gab, werden Mausereignisse auch niemals ausgeführt (das Fenster kann garnicht reagieren)


Tipp:
* es kann nie schaden die "richtigen" Typen-Bezeichner zu nutzen
* die Variablen/Funktionen verständlich zu benennen, verhindert vermindert bestimmt Verwechslungen
* und anstatt irgendwlecher unverständlicher Werte/Zahlen sind Konstanten zu bevorzugen

Delphi-Quellcode:
program Project21;

{$R *.res}

uses
  Types, SysUtils, Windows, Messages; // or System.Types, System.SysUtils Winapi.Windows, Winapi.Messages;

var
  Cls: WNDCLASSEX;
  DK, DB, DM, DE: Boolean;

function WindowProc(Wnd: HWND; Msg: LongInt; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall; // die CallingConvention fehlte !!!!!!!!
begin
  Result := 0; // der Rückgabewert fehlte !!!!!!!!!
  case Msg of
    WM_KEYDOWN:    DK := not DK;
    WM_LBUTTONDOWN: DB := not DB;
    WM_MOUSEMOVE:  DM := not DM;
    WM_RBUTTONDOWN: DE := True;
    else Result := DefWindowProc(Wnd, Msg, WParam, LParam); // als auch die Standardbehandlung für alle Messages, welche DU nicht behandelst
  end;
end;


function RegisterWindowClass: ATOM;
begin
  Cls.cbSize       := SizeOf(Cls);
  Cls.style        := CS_HREDRAW or CS_VREDRAW;
  Cls.lpfnWndProc  := @WindowProc;
  Cls.cbClsExtra   := 0;
  Cls.cbWndExtra   := 0;
  Cls.hInstance    := GetModuleHandle(nil);
  Cls.hIcon        := LoadIcon(0, IDI_APPLICATION);
  Cls.hCursor      := 0;
  Cls.hCursor      := 0;
  Cls.hbrBackground := COLOR_BTNFACE; // 14 + 1;
  Cls.lpszMenuName := niL;
  Cls.lpszClassName := 'MyClassName';
  Cls.hIconSm      := LoadIcon(Cls.hInstance, IDI_APPLICATION);

  Result := RegisterClassEx(Cls);
end;

function CreateMainWindow: HWND;
var
  ClassName, Caption: PChar;
  wndparent: HWND;
  menu:     HMENU;
  instance: THandle;
  param:    Pointer;
begin
  ClassName := 'MyClassName';
  Caption  := 'Text';
  wndparent := 0;
  menu     := 0;
  instance := 0;
  param    := niL;

  Result := CreateWindow(ClassName, Caption, WS_POPUP, 20, 40, 300, 200,
    wndparent, menu, instance, param);
end;

procedure Draw4(Window: HWND; X, Y, Width, Height: Integer; R, G, B: Byte);
var
  DC, BP: HDC;
  XX, YY, Pos: LongInt;
  PaintStrc: TPaintStruct;
begin
  DC               := GetDC(Window);
  PaintStrc.hdc    := DC;
  PaintStrc.fErase := False;
  PaintStrc.rcPaint := Rect(0, 0, X + Width, Y + Height);

  BP := BeginPaint(Window, PaintStrc);
  for YY := 1 to Height do
    for XX := 1 to Width do begin
      //SetPixel(DC, X + XX, Y + YY, (((Integer(R) * 256) + G) * 256) + B);
      SetPixel(DC, X + XX, Y + YY, RGB(R, G, B));
    end;
  EndPaint(Window, PaintStrc);

  ReleaseDC(Window, DC);
end;

var
  Wnd: HWND;
  Msg: TMsg;

begin
  DK := False; DB := False; DM := False; DE := False;
  RegisterWindowClass;
  Wnd := CreateMainWindow;
  ShowWindow(Wnd, SW_SHOW);
  //UpdateWindow(Wnd);
  repeat
    if DK then
      Draw4(Wnd, 02, 02, 20, 20, $C0, $00, $00)
    else
      Draw4(Wnd, 02, 02, 20, 20, $40, $40, $00);
    if DB then
      Draw4(Wnd, 24, 02, 20, 20, $00, $C0, $00)
    else
      Draw4(Wnd, 24, 02, 20, 20, $00, $40, $40);
    if DM then
      Draw4(Wnd, 46, 02, 20, 20, $00, $00, $C0)
    else
      Draw4(Wnd, 46, 02, 20, 20, $40, $00, $40);
    //ShowWindow(Wnd, SW_SHOW);
    //UpdateWindow(Wnd);
    if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then begin
      if Msg.Message = WM_QUIT then
        Break;
      TranslateMessage(Msg);
      DispatchMessage(Msg);
    end;
  until DE;
end.

milurt 19. Jun 2022 18:03

AW: wndproc geht nicht
 
tut mir leid himitsu,
bei deinem program reagieren die vierecke
auch nicht auf tastatur und maus.
und das ist wohl ein fehler, denn microsoft
sagt classname muss der 2te parameter sein,
zudem s1 nicht deklariert wurde:
ClassName := 'MyClassName';
Caption := 'Text';
Result := CreateWindow(S1, Caption, WS_POPUP, 20, 40, 300, 200,
wndparent, menu, instance, param);
ausserdem habe ich es jetzt so und es geht auch nicht:
Function wndproc(hwnd1:HWND;m,w:word;l:longint):LongInt;std call;
Begin
case m of
$100:dk:=-1*dk;
$201:db:=-1*db;
$200:dm:=-1*dm;
$204:db:=2;
end;
wndproc:=DefWindowProc(hwnd1,m,w,l);
End;

himitsu 19. Jun 2022 18:40

AW: wndproc geht nicht
 
Zitat:

Zitat von milurt (Beitrag 1507505)
bei deinem program reagieren die vierecke
auch nicht auf tastatur und maus.

ja, weil das fenster noch nicht richtig initialisiert war.

Es fehlten noch sehr viele Messages, welche nicht behandelt wurden.
Unter Anderem war daher auch das Fenster selber unsichtbar, bis auf diese paar gemalten Rechtecke.

Aber das mit dem DefWindowProc hattest du schon bemerkt.
Oben hatte ich es auch schon nachgetragen, mit dem Unterschied des ELSE, aber ist erstmal egal, da das Fenster auf diese Messages eh keine Behandlung hat und es praktisch keine Konflikte gibt.
Delphi-Quellcode:
else Result := DefWindowProc(Wnd, Msg, WParam, LParam);

Zitat:

Zitat von milurt (Beitrag 1507505)
und das ist wohl ein fehler, denn microsoft
sagt classname muss der 2te parameter sein,

Nein, das sagt Microsoft nicht.
1: ClassName = die Klasse ... Eine der vordefinierten System-Klassen, oder etwas aus RegisterClass/RegisterClassEx
2: WindowName = die Caption

Tipp: Bei Quellcode bitte [CODE]...[/CODE] drumrum. bzw. [DELPHI]...[/DELPHI] für Delphi-Code, damit man es besser lesen kann.

milurt 19. Jun 2022 20:36

AW: wndproc geht nicht
 
ich hatte bei createwindowex nachgesehen, aber S1 ist wirklich nicht definiert.
ist bei deinem program denn das fenster richtig initialisiert gewesen? warum
hast Du Dir den soviel mühe gemacht?
wie liest man also von der tastatur und maus?

hoika 20. Jun 2022 07:36

AW: wndproc geht nicht
 
Hallo,

Tastatus: GetAsyncKeyState
https://docs.microsoft.com/en-us/win...tasynckeystate

Maus: WM_MOUSE_X abfangen

milurt 20. Jun 2022 11:03

AW: wndproc geht nicht
 
jetzt habe ich das und es funktioniert immer noch nicht:

Code:
program bspforum01chg2;

  uses
  wintypes,
  Winprocs;

  Var
    Cls:WNDCLASSEX;
    dk,db,dm:ShortInt;

  Function wndproc(hwnd1:HWND;m,w:word;l:longint):LongInt;stdcall;
  Begin
    wndproc:=DefWindowProc(hwnd1,m,w,l);
  End;

  Function regwin:Integer;
  Begin
    cls.cbSize:=sizeof(cls);
    cls.style:=CS_HREDRAW Or CS_VREDRAW;
    cls.lpfnWndProc:=Addr(wndproc);
    cls.cbClsExtra:=0;
    cls.cbWndExtra:=0;
    cls.hInstance:=GetModuleHandle(nil);; {IH}
    cls.hIcon:=winprocs.LoadIcon(0, IDI_APPLICATION);
    cls.hCursor:=0;
    cls.hCursor:=0;
    cls.hbrBackground:=(14 + 1);
    cls.lpszMenuName:=NiL;
    cls.lpszClassName:='Win here'#0;
    cls.hIconSm:=LoadIcon(cls.hInstance, IDI_APPLICATION);

    regwin:=winprocs.RegisterClassEx(cls);
  End;

  Function creWin:word;
    Var
      s2,s1:pchar;
      wndparent:hwnd;
      menu:hmenu;
      instance:thandle;
      param:pointer;
  Begin
    S1:='STATIC'#0;
    S2:='Win here'#0;
    wndparent:=0;
    menu:=0;
    instance:=0;
    param:=NiL;
    creWin:=winprocs.createwindow(s2,s1,ws_popup,60,40,300,200,
      wndparent,menu,instance,param);
  End;

  Var hwnd1:hwnd;

  procedure draw4(hwnd1:hwnd;x,y,wid,hei:word;r,g,b:byte);
    Var
      DC,bp:HDC;
      xx,yy:LongInt;
      PaintStrc:wintypes.TPAINTSTRUCT;
  Begin
    DC:=winprocs.getdc(hwnd1); {device context of window}
    PaintStrc.hdc:=DC;
    PaintStrc.ferase:=false;
    PaintStrc.rcpaint.left:=0;
    PaintStrc.rcpaint.top:=0;
    PaintStrc.rcpaint.right:=X+wid;
    PaintStrc.rcpaint.bottom:=Y+hei;
    bp:=winprocs.BeginPaint(hwnd1,PaintStrc);
    for yy:=1 To hei Do
      For xx:=1 To wid Do
      Begin
        winprocs.SetPixel(dc,x+xx,y+yy,(((r*256)+g)*256)+b);
      End;
    winprocs.EndPaint(hwnd1,PaintStrc);
    releasedc(hwnd1,dc);
  end;

  var msgptr:tagmsg;
  hAccelTable:Haccel;

  procedure readkm;
  begin
    while GetMessage(msgptr, hwnd1, 0, 0) do
    begin
      if (TranslateAccelerator(msgptr.hwnd, hAccelTable,msgptr))<>0 then begin
        TranslateMessage(msgptr);
        DispatchMessage(msgptr);
      end;
    end;
    case msgptr.message of
      $100:dk:=+1;
      $101:dk:=-1;
      $201:db:=+1;
      $202:db:=-1;
      $200:dm:=-1*dm;
      $204:db:=2;
//      $015:Begin showwindow(hwnd1,sw_show);
//        updatewindow(hwnd1);End;
    end;
  end;

Begin
  dk:=-1;db:=-1;dm:=-1;
  regwin;
  hwnd1:=crewin;
  msgptr.hwnd:=hwnd1;
  showwindow(hwnd1,sw_show);
  updatewindow(hwnd1);
  draw4(hwnd1,00,00,70,30,$40,$40,$40);
  Repeat
    readkm;
    if dk=-1 Then draw4(hwnd1,02,02,20,20,$C0,$00,$00)
      else draw4(hwnd1,02,02,20,20,$80,$80,$00);
    if db=-1 Then draw4(hwnd1,24,02,20,20,$00,$C0,$00)
      else draw4(hwnd1,24,02,20,20,$00,$80,$80);
    if dm=-1 Then draw4(hwnd1,46,02,20,20,$00,$00,$C0)
      else draw4(hwnd1,46,02,20,20,$80,$00,$80);
  Until db=2;
end.

TurboMagic 21. Jun 2022 15:09

AW: wndproc geht nicht
 
Vielleicht ist es einfacher wenn du uns sagst mit welcher Delphi Version du was erreichen willst? Evtl. ist dann ein ganz anderer Ansatz der richtige..?

himitsu 21. Jun 2022 15:54

AW: wndproc geht nicht
 
Zitat:

Vielleicht ist es einfacher wenn du uns sagst mit welcher Delphi Version du was erreichen willst? Evtl. ist dann ein ganz anderer Ansatz der richtige..?
joar

Zitat:

wie
Auf die Messages reagieren
oder GetAsyncKeyState
oder GetKeyState (innerhalb irgendeiner Message)
oder anderes Zeugs, z.B. aus DirectX und Co.


So wie in #3 (mit Message-Loop und der richtigen registrieren Klasse) funktioniert es, in halbwegs aktuellen Windowsen und in allen Delphis der letzten 15 Jahre und vermutlich auch mehr.



Was macht im readkm das CASE außerhalb der Schleife?


zum Code aus #8:
Wenn jemand (DU) den Debugger benutzten würde,
dann viele vielleicht auf, dass das Programm im CreateWindow in creWin hängen bleibt
und nachfolgend natürlich die externe Messagebeandlung & Tastenprüfung demnach auch garnichts machen kann.

Und ab Delphi 11 bekommt man auch noch wunderschön einen RuntimError 201 um die Ohren gehauen,
da dort die Bereichsprüfung (RangeCheck) nun im Debug-Profil standardmäßig aktiv ist.




Und wer ein eigentliches "HauptFenster" als Popup (WS_POPUP) deklariert, der braucht sich nicht wundern, wenn es etwas "anders" auf Tastatur/Maus/Fokusteuerung reagiert.




PeekMessage ohne Pausen, lässt die CPU nur ein bissl unnötig viel arbeiten.

PeekMessage+MsgWaitForMultipleObjects (siehe DelayDelay) oder GetMessage sind da sparsamer. (aber funktionell ist es erstmal egal)







Lesetipps:

https://www.delphi-treff.de/tutorial...ierung/nonvcl/

und auch mal da durchstöbern

https://www.michael-puff.de/ (das menü unten funktioniert nicht mehr, daher siehe nachfolgenden Link)
http://web.archive.org/web/201804300...chael-puff.de/



PS: Wenn wndprocnur noch DefWindowProc macht, dann kann man das auch gleich ganz weglassen.

milurt 21. Jun 2022 23:09

AW: wndproc geht nicht
 
ja, ich habe die case in readkm kurz nach dem forum
in die schleife getan und es hat auch nicht funktioniert.
wm_popup: ich wollte nicht so mit zwei fenstern
arbeiten sondern ein fenster das ich (border,...)
gestalten kann.
derzeit habe ich community10.4 und möchte win 64bit
programme schreiben auch wenn es akzeptabel ist wenn
sie vor win10 noch laufen (32bit,16bit).
ich möchte erzählen dass ich später nicht nur keydown
haben will, sondern auch den letter von der tastatur,
aber wenn nicht mal das ging sollte ich das warum
machen?
himitsu, was ist #3 und #8 bei dir da?
mein debugger überspringt in readkm $100 zu $101
und von dort zu getmessage.
wenn ich call readkm weglasse werden die drei vierecke
gezeichnet, ansonsten nur das grosse graue.
deine webseiten haben nichts gebracht.

himitsu 22. Jun 2022 09:57

AW: wndproc geht nicht
 
Zitat:

Zitat von milurt (Beitrag 1507611)
himitsu, was ist #3 und #8 bei dir da?

Schau mal im Forum bei den einzelnen Posts oben rechts in die Ecke. :zwinker:

Wenn neues Delphi, dann schmeiß die uralten Units raus und verwende die Aktuellen,
denn wintypes und winproc gibt es schon seit Jahrzehnten nicht mehr. (du kannst froh sein, dass standardmäßig in Projektoptionen > Delphi-Compiler > Unit-Aliase etwas drin steht)

Zitat:

Zitat von milurt (Beitrag 1507611)
ja, ich habe die case in readkm kurz nach dem forum
in die schleife getan und es hat auch nicht funktioniert.

Ja, theoretisch würde es dann gehn, wenn ... dein Programm nicht vorher hängen bleiben würde (siehe meine letzte Antwort).
Oder wenn es durch GetMessage nicht in der Schleife hinge und deine Rechtecke aus draw4 nicht öfters gelöscht/üermalt würden, als du sie neu zeichnen lässt.

WM_POPUP hat nichts hat nichts direkt mit der Fenstergestaltung zu tun. Dafür gibr es andere Attribute.
Es steuert wird das Fenster reagiert ... eben wie ein POPUP, also was selbstgebautes ähnlich einem PopupMenü, MainMenü oder dem DropDown einer ComboBox.

Zitat:

Zitat von milurt (Beitrag 1507611)
nicht nur keydown haben will, sondern auch den letter von der tastatur

Wenn man statt nichtssagender Nummern die passenden Konstanten verwenden würde, dann könnte man auch in der Hilfe danach suchen
und fände raus, dass dort die Taste ebenfalls in der Message drin steckt und wie man da dran kommt.

MSDN-Library durchsuchenWM_KEYDOWN/WM_KEYUP ala TForm.OnKeyDown/OnKeyUp liefert den ScanCode (Code der Taste, noch ohne Übersetuung des KeyboardLayouts) und die ModifierKeys (Strg/Alt/Shift)
MSDN-Library durchsuchenWM_CHAR als TForm.OnKeyPress



Zitat:

Zitat von milurt (Beitrag 1507611)
mein debugger überspringt in readkm $100 zu $101
und von dort zu getmessage.
wenn ich call readkm weglasse werden die drei vierecke
gezeichnet, ansonsten nur das grosse graue.

Nja, mit GetMessage hat du ein großes Problem ... das Programm wartet dort, bis zur nächsten Message.

Mit PostMessage rannte es immer in der schleife und dadurch wurden auch die Rechtecke "immer wieder" neu gemalt.
Fällt nicht kaum auf, wenn Windows das Fenster neu malt und damit deine Rechtecke übermalt. (sie dann ganz kurz weg sind, bis zum nächsten Malen der Rechtecke)

Eigentlich gehört das Malen der Rechtecke besser ins WM_PAINT (ala OnPaint bei TForm oder TPaintBox)
und beim Ändern des Status, durch Taste/Maus, löst man ein Repaint aus.

In aktuellen Windowsen hast du noch Grlück, dass der WindowsDesktoManager mehr zwischenspeichert ... bei älteren Windows hättest du noch mehr Probleme, weil dort noch öfters das Fenster neu gemalt würde (es deine Rechtecke übermalt).


Zitat:

deine webseiten haben nichts gebracht.
Wenn man direkt mit der WinAPI (GDI) arbeiten will, dann sollte man da bissl Grundlagen kennen und wissen wo die Dokumentation zu finden ist (MSDN bzw. Win32-SDK).
Für eine Suche bezüglich Delphi, da nennen wir sowas gern mal NonVCL (also "ohne die VCL" und somit ohne so Zeugs wie TForm und TPaintBox/TImage oder TShape und OnKeyDown/OnKeyPress/OnMouseMove, was man hierfür verwenden könnte)

milurt 22. Jun 2022 13:39

AW: wndproc geht nicht
 
sind wintypes,winprocs jetzt 16bit obwohl ich
nur 1x C:\windows habe, das 64bit ist?
öfter übermalt: ich errinnere mich, das ich die
reaktion früher anders gemacht habe und nur
auf keydn ohne keyup zeichnete.
wenn getmessage auf eingabe wartet, soll ich
also doch wieder wndproc benutzen?
wenn man wm_popup macht, heisst das also
das ich wndproc keydn nicht mehr nutzen kann?
ich habe schon verstanden, dass nach keydn
man wparam braucht, wollte aber es nicht
programmieren. denn da war so viel von
shiftstate-read die rede und die taste liest man
doch von wndproc, die nicht window-style heisst.
"Wenn man mit der WinAPI (GDI) arbeiten will":
willst du sagen ich kann setpixel nicht gebrauchen?
mein problem sind doch keyboard und mouse.

KodeZwerg 22. Jun 2022 16:41

AW: wndproc geht nicht
 
Zitat:

Zitat von milurt (Beitrag 1507644)
willst du sagen ich kann setpixel nicht gebrauchen?

Er wollte wohl eher vermitteln das man unter Non-VCL sich alle Informationen via Microsoft besorgen kann, wie das erwähnte SetPixel.

himitsu 22. Jun 2022 17:45

AW: wndproc geht nicht
 
Genau, das sind die Anfänge/Grundlagen, wenn man sich mit sowas beschäftigen will. (bzw. was man für die Suche im Forum, beim G oder sonstwo nutzen kann)




Nja, entweder man nutzt die passendere API (WM_CHAR vs. WM_KEYUP/DOWN)
oder man nutzt APIs zum Umrechnen der Werte
oder man verwendet direkt die gegebenen Werte.

ScanCode (der Tastencode von der Tastatur) -> Virtual Key Code (der Key Code in den KEY-Events) -> Character (im Char-Event)
https://stackoverflow.com/questions/...current-keyboa





Klar darf man SetPixel verwenden, genauso wie man in der VCL Canvas.Pixels nutzen kann.
Aber sinnlos in Massen ist es nicht empfehlungswert, vorallem da Pixels in der VCL extrem langsam ist.
Man kann ein Rechteck aber auch direkt zeichnen. Rechtangle bzw. FillRect (was "zufällig" jeweils in der WinAPI/GDI und im TCanvas gleich heißt)

Wichtiger ist aber, wo/wann man zeichnet und nicht womit. (siehe nachfolgend)





Klar, damals bei Delphi 2006 gab es eine schöne Demo, welche zeigte, dass man selbst extrem uralten Code, aus Zeiten von TurboPascal, immernoch kompiliert und ausgeführt bekommt.

Aber gerade wenn man etwas neu scheibt, sollte man dringend die Finger von uralten Schnittstellen lassen und stattdessen gleich das Aktuelle benutzen.
Für ein paar uralte Units gibt es zwar Aliase, damit man solche alte Units/Programme noch kompilieren könnte,
aber diese sind mehr für alten "vorhandenen" Code als Fallback gedacht und nicht damit man sie jetzt "neu" verwendet.




Malen auf ein Canvas/DeviceContext (HDC) tut man am Besten nur im Paint-Ereignis (WM_PAINT bzw. OnPaint).
Selbst wenn man wo anders malt, sollte man immer eine "Wiederherstellung" im Paint-Ereignis haben, damit das nach dem Übermalen direkt neu gezeichnet wird.

z.B. in einem Button-Click etwas malen, dann die Form minimieren oder die Form teilweise kurz aus dem Bildschirm rausschieben und weg ist alles,
wenn man es im OnPaint nicht erneut malt.
Früher reichte es sogar schon, ein anderes Fenster/Menü vor das eigene Fenster zu schieben und weg war es. (das geht heute nur zufällig, weil der DWM sich alle sichtbaren Fenster merkt, wegen der Berechnung von Transparenzen, den Vorschaubildern und Dergleichen)

Delphi-Quellcode:
type
  // OnMouseDown, OnMouseUp und OnMouseMove
  TForm5 = class(TForm)
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  private
    FDoPaint: Boolean;
  end;

var
  Form5: TForm5;

implementation

{$R *.dfm}

procedure TForm5.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbLeft then
    FDoPaint := True;
end;

procedure TForm5.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  if FDoPaint then
    Canvas.Pixels[X, Y] := clMaroon;
end;

procedure TForm5.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  FDoPaint := False;
end;
Tipp: rate mal, was dieser Code macht und was du demnach mit dieser Form und deiner Maus machen kannst. :angle:

TurboMagic 23. Jun 2022 08:09

AW: wndproc geht nicht
 
Hallo,

also ich würde erstmal eine ganz einfache VCL Anwendung mit einer einzelnen Form erstellen.
Auf dieses würde ich eine TPaintBox platzieren. Anchors passend setzen, damit diese beim
Ändern der Fenstergröße mit angepasst wird.

In der Paintbox (z. B. Paintbox1 oder ein besserer Name) kann man dann nach belieben
Line, Rectangle, Arc etc. zeichnen. Jeweils vorher Paintbox1.Brush.Color auf die gewünschte
Farbe setzen wenn es um ausgefüllte Dinge geht und Paintbox1.Pen.Color für Linien/Ränder.

Wenn du mit diesen Zeichenmethoden (Line hat übrigens nur 2 Koordinaten, die anderen beiden
kommen durch MoveTo oder wie das heißt um den virtuellen Cursor zu platzieren zustande) mal ein
paar Minuten rumgespielt hat, kannst du dich um das Maushandlink kümmern, die Paintbox hat dafür
bestimmt events.

Zum Thema Tastaturhandling: keine Ahnung ob die Paintbox ein Event dafür hat, die Form hat aber
m.W. ein OnKeyPressed Event.

Grüße
TurboMagic

milurt 24. Jun 2022 13:40

AW: wndproc geht nicht
 
ich habe es geschafft, danke.

TurboMagic 25. Jun 2022 10:21

AW: wndproc geht nicht
 
Zitat:

Zitat von milurt (Beitrag 1507784)
ich habe es geschafft, danke.

Som du hast es also geschafft. Aber mit welchem Ansatz?
Magst du verhindern, dass wir diesbezüglich dumm sterben? ;-)

venice2 25. Jun 2022 11:08

AW: wndproc geht nicht
 
Zitat:

Magst du verhindern, dass wir diesbezüglich dumm sterben?
Wird er wohl nicht können.
Denn bekanntlich sterben wir alle dumm andernfalls würden wir ewig leben.

milurt 25. Jun 2022 13:52

AW: wndproc geht nicht
 
so ging es, vielleicht haben himitsu und ich bei weiteren gesprächen peekmessage vergessen.
wndproc braucht man schon weil regwin sie pointet.

Code:
program bspforum01chg2me2;

  uses
  wintypes,
  Winprocs;

  Var
    Cls:WNDCLASSEX;
    dk,db,dm:ShortInt;

  Function wndproc(hwnd1:HWND;m,w:word;l:longint):LongInt;stdcall;
  Begin
    wndproc:=DefWindowProc(hwnd1,m,w,l);
  End;

  Function regwin:Integer;
  Begin
    cls.cbSize:=sizeof(cls);
    cls.style:=CS_HREDRAW Or CS_VREDRAW;
    cls.lpfnWndProc:=Addr(wndproc);
    cls.cbClsExtra:=0;
    cls.cbWndExtra:=0;
    cls.hInstance:=GetModuleHandle(nil);; {IH}
    cls.hIcon:=winprocs.LoadIcon(0, IDI_APPLICATION);
    cls.hCursor:=0;
    cls.hCursor:=0;
    cls.hbrBackground:=(14 + 1);
    cls.lpszMenuName:=NiL;
    cls.lpszClassName:='Win here'#0;
    cls.hIconSm:=LoadIcon(cls.hInstance, IDI_APPLICATION);

    regwin:=winprocs.RegisterClassEx(cls);
  End;

  Function creWin:word;
    Var
      s2,s1:pchar;
      wndparent:hwnd;
      menu:hmenu;
      instance:thandle;
      param:pointer;
  Begin
    S1:='STATIC'#0;
    S2:='Win here'#0;
    wndparent:=0;
    menu:=0;
    instance:=0;
    param:=NiL;
    creWin:=winprocs.createwindow(s2,s1,ws_popup,60,40,300,200,
      wndparent,menu,instance,param);
  End;

  Var hwnd1:hwnd;

  procedure draw4(hwnd1:hwnd;x,y,wid,hei:word;r,g,b:byte);
    Var
      DC,bp:HDC;
      xx,yy:LongInt;
      PaintStrc:wintypes.TPAINTSTRUCT;
  Begin
    DC:=winprocs.getdc(hwnd1); {device context of window}
    PaintStrc.hdc:=DC;
    PaintStrc.ferase:=false;
    PaintStrc.rcpaint.left:=0;
    PaintStrc.rcpaint.top:=0;
    PaintStrc.rcpaint.right:=X+wid;
    PaintStrc.rcpaint.bottom:=Y+hei;
    bp:=winprocs.BeginPaint(hwnd1,PaintStrc);
    for yy:=1 To hei Do
      For xx:=1 To wid Do
      Begin
        winprocs.SetPixel(dc,x+xx,y+yy,(((r*256)+g)*256)+b);
      End;
    winprocs.EndPaint(hwnd1,PaintStrc);
    releasedc(hwnd1,dc);
  end;

  var msg:tagmsg;

  procedure readkm;
  begin
    while PeekMessage(msg, hwnd1, 0, 0, PM_REMOVE) do begin
      if msg.message=$100 then dk:=+1;
      if msg.message=$101 then dk:=-1;
      if msg.message=$201 then db:=+1;
      if msg.message=$200 then db:=-1;
      if msg.message=$200 then dm:=-1*dm;
      if msg.message=$204 then db:=2;
    end;
  end;

Begin
  dk:=-1;db:=-1;dm:=-1;
  regwin;
  hwnd1:=crewin;
  msg.hwnd:=hwnd1;
  showwindow(hwnd1,sw_show);
  updatewindow(hwnd1);
  draw4(hwnd1,00,00,70,30,$40,$40,$40);
  Repeat
    readkm;
    if dk=-1 Then draw4(hwnd1,02,02,20,20,$C0,$00,$00)
      else draw4(hwnd1,02,02,20,20,$80,$80,$00);
    if db=-1 Then draw4(hwnd1,24,02,20,20,$00,$C0,$00)
      else draw4(hwnd1,24,02,20,20,$00,$80,$80);
    if dm=-1 Then draw4(hwnd1,46,02,20,20,$00,$00,$C0)
      else draw4(hwnd1,46,02,20,20,$80,$00,$80);
  Until db=2;
end.

milurt 29. Jun 2022 20:52

AW: wndproc geht nicht
 
ich habe das problem, dass bei peekmessage niemals ein wm_char kommt, wenn ich eine taste drücke.

himitsu 29. Jun 2022 22:49

AW: wndproc geht nicht
 
Ich seh kein PeekMessage im Code. (#20)

Außerdem ist da schonwieder lpClassName und lpWindowsName im CreateWindow vertauscht, bzw. es wird eine Klasse registriert, die nie verwendet wird.




Und nicht alle Messages kommen aus PeekMessage/GetMessage raus.
z.B. Alles, was SendMessage betrifft, wird direkt innerhalb von PeekMessage/GetMessage verarbeitet und garnicht zurückgegben.

Ebenso liegen z.B. WM_TIMER garnicht in der MessageQueue, sondern werden direkt im PeekMessage/GetMessage generiert und rausgegeben.

milurt 30. Jun 2022 10:19

AW: wndproc geht nicht
 
bei meinem #20 letzten beitrag ist in readkm ein peekmessage.
wie liest man also von der tastatur zeichen?
wozu brauche ich wm_timer dabei?

milurt 30. Jun 2022 10:21

AW: wndproc geht nicht
 
wenn bei createwindow zuerst S2 und dann S1 steht ist das wirklich falsch?
das ist nicht createwindowex

KodeZwerg 30. Jun 2022 12:03

AW: wndproc geht nicht
 
Bitte lese Dir ein paar Non-VCL Dokumentationen durch, Michael Puff war ein begeisterter und talentierter Non-VCL Programmierer, seine Resourcen sind immer noch abrufbar.
Die Art und Weise wie Du es versuchst ist .... schräg.

Mein Rat, ich würde die Tastatur-Abfrage in einen Timer schubsen, kleines mini Beispiel:
Delphi-Quellcode:
// global
var
  HID: Integer;
  Msg: TMsg;

// hier eine timer methode für tasten
procedure HotkeyTimer(TimerID, Msg: Uint; dwUser, dw1, dw2: DWord); pascal;
BEGIN
 if (GetKeyState(VK_P) and (1 shl 31)) <> 0) // wurde taste "P" gedrückt
 then
   // mach was wenn P gedrückt wurde.... nur als beispiel
 ;
END;


// hier folgt der hauptaufruf um die klasse und deren objekte zu erschaffen

// nachdem du deine klasse mal ordentlich initialisiert hast und auch nutzt, diese zeile aktiviert einen windows timer der alle 10ms abgerufen wird
HID := TimeSetEvent(10, 0, @HotkeyTimer, 0, TIME_PERIODIC);

// nach diesem Aufruf folgt die Message behandlung, regulär so:
 while(GetMessage(Msg, Handle, 0, 0)) do
  begin
    TranslateMessage(Msg);
    DispatchMessage(Msg);
  end;

// damit wenn der loop beendet ist du die klasse und alle anderen objekte auch wieder freigeben kannst
  TimeKillEvent(HID);
// edit
das obige versetzt die tastatur-abfrage systemweit, also von jedem window aus werden die tasten geprüft und ausgewertet!

himitsu 30. Jun 2022 15:39

AW: wndproc geht nicht
 
Timer ist unnötig.

Entwerder es wird in der MessageLoop (nach GetMessage/PeekMessage) gemacht, indem man auf die gewünschten Tastatur-Messages reagiert,
oder in einer WindowProc. (via GWL_WNDPROC an eine bestehenden Klasse/Instanz angehängt, oder mit RegisterClass über eine eigene WindowClass)

KodeZwerg 30. Jun 2022 16:30

AW: wndproc geht nicht
 
Zitat:

Zitat von himitsu (Beitrag 1508211)
Timer ist unnötig.

Entwerder es wird in der MessageLoop (nach GetMessage/PeekMessage) gemacht, indem man auf die gewünschten Tastatur-Messages reagiert,
oder in einer WindowProc. (via GWL_WNDPROC an eine bestehenden Klasse/Instanz angehängt, oder mit RegisterClass über eine eigene WindowClass)

Ich bin mir da nicht so ganz sicher ob er überhaupt ein Control hat das fokussiert werden kann und Tasten akzeptiert, sein API Quelltext ist sehr schwer zu entziffern.

himitsu 30. Jun 2022 16:41

AW: wndproc geht nicht
 
Mindestens die Form hat hat den Fokus, selbst wenn nichts drauf ist (so wie hier).

Und in der Schleife kommt auch erstmal Alles vorbei. (und Msg.hWnd kann man hier ja ignorieren)


GetKeyState/GetAsyncKeyState haben auch nur den Tastenstatus von innerhalb der aktuell/letzten abgerufenen Message.

Problem beim Timer ist auch, wenn man GetKeyState falsch auswertet, dann gehen da womöglich gedrückte Tasten verloren, wenn die Taste nicht gerade beim GetKeyState gedrückt wird, sondern zwischen den beiden letzten GetKeyState gedrückt wurde.
Und was beim GetKeyState immer verloren geht, wenn eine Taste mehrmals zwischen den GetKeyState gedrückt wurde.

milurt 30. Jun 2022 17:27

AW: wndproc geht nicht
 
ich denke ich werde es so machen:
Code:
if GetKeyState(65) And $80 Then {taste a}

KodeZwerg 30. Jun 2022 21:13

AW: wndproc geht nicht
 
Zitat:

Zitat von milurt (Beitrag 1508217)
ich denke ich werde es so machen:
Code:
if GetKeyState(65) And $80 Then {taste a}

Warum nutzt Du nicht vorgegebene Konstanten?

himitsu 1. Jul 2022 00:26

AW: wndproc geht nicht
 
Weil schon seit Anfang an jegliche Konstanten abgelehnt werden. :zwinker:


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:35 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