Autor Beitrag
neverX
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Sa 07.08.04 15:16 
hallo!

ich hab folgendes problem: ein formular mit winapi erstellen ist ja alles kein problem, aber komischer weise sobald ich versuche den code in eine klasse zu packen, was das ganze etwas "freundlicher" gestalten würde, funktioniert es nicht mehr...

hab debugged, alles was ich rausfinden konnte ist, dass die methode CreateWindowEx 0 zurückgibt. GetLastError() hingegen sagt mir 1400 was soviel heißt wie "Fensterhandle nicht vorhanden". nur hab ich keine idee warum und wieso das nicht hinhaut...

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
unit UApiForm;

interface

uses
  Windows, Messages;

type
  TApiForm = class(TObject)
  private
    fClassName      : String;
    fWClass         : TWndClass;
    fFormHandle     : HWND;
    fCaption        : String;
    fTop            : Integer;
    fLeft           : Integer;
    fWidth          : Integer;
    fHeight         : Integer;

    function WndProc(hWnd: HWND; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;

  protected

  public
    constructor Create(className: String; appInstance: HWND);
    procedure Show();

  published
    property Handle: HWND read fFormHandle;
    
  end;

implementation

function TApiForm.WndProc(hWnd: HWND; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
begin
  result := DefWindowProc(hWnd, Msg, wParam, lParam);
end;

constructor TApiForm.Create(className: String; appInstance: HWND);
begin
  fTop := 100;    fLeft := 100;
  fHeight := 80;  fWidth := 200;

  fCaption := 'test';
  fClassName := className;
  fWClass.hInstance := appInstance;
  with fWClass do
  begin
    style := 0;
    hIcon := LoadIcon(fWClass.hInstance, 'MAINICON');
    lpfnWndProc := @TApiForm.WndProc;
    hbrBackground := COLOR_BTNFACE + 1;
    lpszClassName := PChar(fClassName);
    hCursor := LoadCursor(0,IDC_ARROW);

    cbClsExtra := 0;
    cbWndExtra := 0;
    lpszMenuName := '';
  end;

  RegisterClass(fWClass);

  fFormHandle := CreateWindowEx(
    WS_EX_NOACTIVATE or WS_EX_TOPMOST,
    PChar(fClassName),
    PChar(fCaption),
    WS_POPUP,
    fLeft,
    fTop,
    fWidth,
    fHeight,
    0,
    0,
    appInstance,
    nil
    );
end;

procedure TApiForm.Show;
begin
  ShowWindow(fFormHandle, SW_SHOWNORMAL);
end;


wäre dankbar wenn mir da jemand aushelfen könnte, hab stundenlang gesucht, aber nichts gefunden das mir weiterhelfen würde...

mfg,
never

_________________
// better be green.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 07.08.04 15:33 
Das dürfte so nicht Funktionieren. Die Fenster-Prozedur ist laut Microsoft so deklariert:
ausblenden Delphi-Quelltext
1:
function WndProc(hWnd: HWND; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;					

Da Methoden einer Klasse immer den unsichtbaren Self-Parameter mit schleppen sieht das dan bei dir so aus:
[pre]
function WndProc(Self: TObject; hWnd: HWND; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
[/pre]
Und somit passen die Aufrufe nicht mehr zusammen.
Aber warum die Mühe? Nimm doch die VCL, da hast du doch alles in Klassen. Oder wenn dir das zu doick aufträgt, dann kuck dir mal die Suche bei Google KOL an.
neverX Threadstarter
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Sa 07.08.04 15:46 
interessant, ich wusste nicht das delphi "Self" als versteckten parameter oder so übergibt, und das obwohl ich schon "ewig" damit arbeite (ähm, hobby).

die mühe mach ich mir nur aus prinzip. wenn ich eine anwendung haben will, die gerade mal ein wenig text ausgeben will (notify popup) dann will ich nicht das ne vcl-anwendung unnötig speicher gebraucht.

mag ja in der heutigen zeit sinnlos klingen, aber würde nur die hälfte der programmierer auf die ressourcen besser acht geben, wären die anwendungen etc wahrscheinlich doppelt so schnell bzw würden fast überall laufen.

gibt es nicht irgendeine möglichkeit, die api-funktionen trotz diesem problem in ne klasse zu packen?

// edit: letzteres rein aus interesse, dieses problem dürfte man dann ja jedesmal haben, wenn man objekte mit win-api ausstatten will

_________________
// better be green.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 07.08.04 16:48 
Also wenn du nur mal so eine kleine anwendung haben willst, dann würde ich mir nicht die Mühe machen es extra eine Klasse zu packen und die API direkt benutzen.
Zitat:

gibt es nicht irgendeine möglichkeit, die api-funktionen trotz diesem problem in ne klasse zu packen?

Hat man auch, deswegen dürfen zum Beispiel Callback-Funktionen keine Methode einer Klasse sein.
neverX Threadstarter
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Sa 07.08.04 17:04 
wäre nur deshalb gewesen, weil ich mehrere fenster benötige, die dynamisch erstellt werden. deshalb wäre es in einer netten klasse sauber und schön zu verwenden gewesen. auch für "kleinigkeiten" ordentliche konzepte zu wählen kann ich nur empfehlen, zumindest wenn man die kleinigkeit öfter verwenden will.

dann bleibt mir wohl nichts anderes übrig, als das ganze auf die herkömmliche strukturierte art und weise zu lösen, schade doch.

hat sich damit wohl erledigt, vielen dank für die prompte hilfe!
never

_________________
// better be green.
obbschtkuche
Gast
Erhaltene Danke: 1



BeitragVerfasst: Sa 07.08.04 17:13 
Klar bleibt Dir was anderes übrig. Beispielsweise kannst du dem Fenster per SetWindowLong dem Index GWL_USERDATA dword(self) übergeben und das dann später wieder zurückcasten. So oder so ähnlich dürfte das in der VCL auch gelöst sein.

z.B:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
function WndProc(hWnd: HWND; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
begin
 with TMeineKlasse(GetWindowLong(hwnd, GWL_USERDATA)) do
 begin
  ...
 end;
end;

constructor TMeineKlasse.Create(...);
begin
 handle := CreateWindowEx(...);
 SetWindowLong(handle, GWL_USERDATA, dword(self);
end;
neverX Threadstarter
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Sa 07.08.04 17:26 
im WndProc muss ich nicht auf die klasse zugreifen, dass problem war nur, dass CreateWindowEx fehlgeschlagen ist, weil @TApiForm.WndProc nicht funktioniert. ist aber auch gut zu wissen, wie ich das später schaffen kann :)

wie ich bei dir gerade sehe, fällt mir was selbstverständliches auf... WndProc kann ja für alle meine notify-fenster dieselbe methode sein, also muss sie nicht ind er klasse dabei sein. ich werd das gleich mal versuchen, wär nur zu besänftigt wenn das so funktioniert :)

// edit:
yess, es geht endlich! danke nochmal für eure hilfe! jetzt wird ne schöne kleine mini-klasse gebaut, mit der man dann etwas schneller ans ziel kommt wenn man api-forms benötigt, und dann bin ich glücklich :D

_________________
// better be green.