Znów problem z funkcją zwrotną zn. się w klasie

0

Witam

Jeśli ktoś się po nazwie tematu jeszcze nie połapał o co mi chodzi to niech zajrzy:
Wywołanie funkcji zwrotnych z klasy

No więc. Mam takie uno picolo problemo:
WM_GETMINMAXINFO dostaję przed WM_CREATE i WM_NCCREATE, a potrzebuję się w tym komunikacie odwołać do zmiennej z klasy. Co powinienem zrobić? Póki co dostaję "Runtime error 216".

0

mozesz jasniej ?

moze wklej jakis mini kawalek kodu w ktorym jest problem.

0

Wiedziałem, że to właśnie Ty mi odpiszesz :-)

Kod:

function TLinksWnd.WndProc(uMsg: UINT; wPar: WPARAM; lPar: LPARAM): LRESULT; stdcall;
var
  hWindow: HWND;
  iRet: Integer;
begin
  Result := 0;
  hWindow := Integer(Self);
  iRet := GetWindowLong(hWindow, GWL_USERDATA);
  if (iRet <> 0) then Self := TLinksWnd(iRet)
  else Self := TLinksWnd(PCREATESTRUCT(lPar)^.lpCreateParams);
  case uMsg of
    WM_CREATE:
    begin
      SetWindowLong(hWindow, GWL_USERDATA, Integer(PCREATESTRUCT(lPar)^.lpCreateParams));
    end;
    WM_GETMINMAXINFO:
    begin
      PMinMaxInfo(lPar)^.ptMinTrackSize.X := Self.FMinWndWidth; //Tutaj błąd
    end;
    WM_CLOSE:
    begin
      ShowWindow(hWindow, SW_HIDE);
    end;
    else
     Result := DefWindowProc(hWindow, uMsg, wPar, lPar);
  end;
end;

Tworzenie okna:

FHandle := CreateWindowEx(WS_EX_TOOLWINDOW, PChar(FWndClassName), PChar(FWndTitle), WS_CHILD or WS_CAPTION or WS_SYSMENU or WS_SIZEBOX or WS_MAXIMIZEBOX, iLeft, iTop, iWidth, iHeight, hParentWnd, HMENU(iID), hInstance, Self);

FWndClassName i FWndTitle są typu String.

PS. Tak na marginesie - nie lepiej zmienić WM_CREATE na WM_NCCREATE ?
PS. 2: Jaki jest pierwszy komunikat jaki leci do okna? Z tych co tu mam wygrywa WM_GETMINMAXINFO.
Jest jeszcze jakiś wysyłany wcześniej?

Aha, byłbym zapomniał - to okno, które tu widzisz, nie jest głównym oknem aplikacji. To okno dodatkowe, wyświetlane po wciśnięciu przycisku. Myślę, że tu jest pies pogrzebany i dlatego dostaję najpierw WM_GETMINMAXINFO.

0

Teoretycznie NCCREATE powinno byc przed CREATE (jak NCDESTROY po DESTROY).

Jak przychodzi przed CREATE teoretycznie wtedy jeszcze nie ma uchwytu do okna (bo wtedy moze sie wycofac i handle = 0), wiec rozwiazaniem bylo by ustawienie w tym miejscu struktury wypelnionej zerami jak to robi mfc (http://msdn.microsoft.com/en-us/magazine/cc302145.aspx).

0
reichel napisał(a)

wiec rozwiazaniem bylo by ustawienie w tym miejscu struktury wypelnionej zerami

W którym miejscu? I jakiej struktury? MINMAXINFO?

reichel napisał(a)

jak to robi mfc

W, którym miejscu na tej stronie? Ja tam nie widze nic co mógłbyś mieć na myśli.

reichel napisał(a)

Teoretycznie NCCREATE powinno byc przed CREATE (jak NCDESTROY po DESTROY).

Tak, wiem o tym, dlatego wydaje mi się, że lepiej zmienić na NCCREATE.

EDIT:
Na razie rozwiązałem to tak:

    WM_GETMINMAXINFO:
    begin
      if (GetProp(hWindow, 'bFirstGMMI') = 1) then
        PMinMaxInfo(lPar)^.ptMinTrackSize.X := Self.FMinWndWidth
      else SetProp(hWindow, 'bFirstGMMI', 1);
    end;

Ale nadal chcę, wiedzieć, jakie rozwiązanie miałeś na myśli.

0

To i tak jest do bani z punktu widzenia klasy

Reset napisał(a)
    WM_GETMINMAXINFO:
    begin
      if (GetProp(hWindow, 'bFirstGMMI') = 1) then
        PMinMaxInfo(lPar)^.ptMinTrackSize.X := Self.FMinWndWidth
      else SetProp(hWindow, 'bFirstGMMI', 1);
    end;

... bo i tak nie ma hWindow (jak to uzyskujesz, ze dopoki nie wroci sie z create (bo tam mozna zadecydowac o tym czy istnieje czy tez nie). Jednym slowem sprawdzic czy ret z getwindowlong = 0 i czy cos innego niz wm_create/nccreate gdzie jest info o tym jak nie to self = nil i wtedy jak nil to przypisac co kolwiek do struktury (np 0) albo od razu return.

0
reichel napisał(a)

To i tak jest do bani z punktu widzenia klasy

reset napisał(a)
    WM_GETMINMAXINFO:
    begin
      if (GetProp(hWindow, 'bFirstGMMI') = 1) then
        PMinMaxInfo(lPar)^.ptMinTrackSize.X := Self.FMinWndWidth
      else SetProp(hWindow, 'bFirstGMMI', 1);
    end;

Wiem :-) Dlatego byłem ciekaw jakie Ty znalazłeś rozwiązanie.

reichel napisał(a)

Jednym slowem sprawdzic czy ret z getwindowlong = 0

Działa. Aż wstyd, że sam na to nie wpadłem :-O

Dzięki za pomoc.

0

Żeby nie zakładać nowego tematu (bo problem jest podobny) kontynuuję ten.
Tym razem chcę z wątku znajdującego się w tejże klasie odwołać do zmiennej z klasy.
Problem jest dziwny, bo nie ważne co przekażę w czwartym parametrze funkcji CreateThread to w funkcji wątku dostaję zawsze liczbę 3 (po zrzutowaniu pointera na int-a).
To przez to, że wątek jest w klasie?
Po drugie - udało mi się zdobyć Self-a, ale nie rozumiem jak to możliwe, że się udało :D
Przecież wg. tej konstrukcji powinno pobrać GWL_USERDATA z dowolnego okna w systemie, lub funkcja zwróciłaby 0.
Tak w ogóle to Selfa bym chciał przekazać przez lpVoid, ale nic z tego.

function TLinksWnd.MyThread(lpVoid: Pointer): DWORD; stdcall;
var
  hWindow: HWND;
  iRet: Integer;
begin
  hWindow := Integer(Self); //Tutaj selfa nie ma, więc hWindow jest fałszywe
  iRet := GetWindowLong(hWindow, GWL_USERDATA); //Tu już nie powinno pobrac z mojego okna
  if (iRet <> 0) then Self := TLinksWnd(iRet)
  else ExitThread(0);
end;

Wątek tworzony w jednym z komunikatów w WndProc:

FMyThread := CreateThread(nil, 0, @TLinksWnd.MyThread, nil, 0, PDWORD(nil)^);

PS. Jak widzisz zmieniłem nick :)

0

Popatrz na przypadek funkcji z okna (np przeczytaj w tym tekscie co rzucilem) a potem popatrz i wykorzystaj analogie do funkcji z watkiem (parametry !!!!!!!!!).

A moze domyslnie parametr zwraca uchwyt pasujacy do jakiegos okna ? SPrawdziles czy na pewno to jest twoje okno?

BTW. lepiej chyba zalozyc nowy temat bo przypadkiem tu zajrzalem ...

0
reichel napisał(a)

Popatrz na przypadek funkcji z okna (np przeczytaj w tym tekscie co rzucilem) a potem popatrz i wykorzystaj analogie do funkcji z watkiem (parametry !!!!!!!!!).

Na razie działa, to co zrobiłem. Jedyne co chciałbym zmienić to przekazywać do funkcji wątku Self, poprzez lpVoid, niestety to mi nie działa. Ale głównie chodzi mi o to, jakbyś mi wytłumaczył paradoks, że:

  1. Skoro hWindow = uchwytowi mojego okna, to znaczy, że Self wskazuje na to co powinien.
  2. Skoro Self wskazuje na to co powinien, to powinienem móc się odwołać do zmiennej z klasy bez wydobywania Self na nowo - niestety nie da się.
    No i powiedz mi, czemu nie mogę przekazać niczego do funkcji wątku poprzez parametr lpVoid?
reichel napisał(a)

A moze domyslnie parametr zwraca uchwyt pasujacy do jakiegos okna ? SPrawdziles czy na pewno to jest twoje okno?

Tak, to moje okno.

reichel napisał(a)

BTW. lepiej chyba zalozyc nowy temat bo przypadkiem tu zajrzalem ...

Chyba nie, skoro już zajrzałeś :)

0

normalnie powinno byc

function WndProc(hWindow:integer; uMsg: UINT; wPar: WPARAM; lPar: LPARAM): LRESULT; stdcall;

a jest

function TLinksWnd.WndProc(uMsg: UINT; wPar: WPARAM; lPar: LPARAM): LRESULT; stdcall;

lpVoid tez ma 4 bajty jak self ... wniosek ...

nie masz selfa, bo jako self laduje jakis paramer z lpVoid (mozesz znow dac wiecej kodu, bo tak nie chce mi sie odtwarzac).

0

Zostawiając to co najważniejsze:

type
  TLinksWnd = class
  private
    FWndClassName: String;
    FWndTitle: String;
    FHandle: HWND;

    FLinksEdit: HWND;
    FStatic: HWND;
    FDirEdit: HWND;
    FChangeBtn: HWND;
    FCancelBtn: HWND;
    FAddBtn: HWND;

    FThread_CheckLinks: DWORD;

    function WndProc(uMsg: UINT; wPar: WPARAM; lPar: LPARAM): LRESULT; stdcall;
    function Thread_CheckLinks(lpVoid: Pointer): DWORD; stdcall;
end;

function TLinksWnd.Thread_CheckLinks(lpVoid: Pointer): DWORD; stdcall;
var
  hWindow: HWND;
  iRet: Integer;

  iLinksCount: Integer;
begin
  hWindow := Integer(Self);
  MessageBox(0, PChar(IntToStr(Integer(lpVoid))), 'lpVoid', 0); //Pokazuje zawsze liczbę 3
  //if hWindow = LinksWnd.Handle then MessageBox(0, '', '', 0);
  iRet := GetWindowLong(hWindow, GWL_USERDATA);
  if (iRet <> 0) then Self := TLinksWnd(iRet)
  else ExitThread(0);

  iLinksCount := SendMessage(Self.FLinksEdit, EM_GETLINECOUNT, 0, 0);
  ShowInt(iLinksCount); //MessageBox
end;

function TLinksWnd.WndProc(uMsg: UINT; wPar: WPARAM; lPar: LPARAM): LRESULT; stdcall;
var
  hWindow: HWND;
  iRet: Integer;
begin
  Result := 0;
  hWindow := Integer(Self);
  iRet := GetWindowLong(hWindow, GWL_USERDATA);
  if (iRet <> 0) then Self := TLinksWnd(iRet)
  else Self := TLinksWnd(PCREATESTRUCT(lPar)^.lpCreateParams);
  case uMsg of
    WM_NCCREATE:
    begin
      SetWindowLong(hWindow, GWL_USERDATA, Integer(PCREATESTRUCT(lPar)^.lpCreateParams));
      Result := 1;
    end;
    WM_COMMAND:
    begin
      case (LoWord(wPar)) of
        ID_BUTTON_ADD:
        begin
          EnableWindow(FLinksEdit, False);
          EnableWindow(FStatic, False);
          EnableWindow(FDirEdit, False);
          EnableWindow(FChangeBtn, False);
          EnableWindow(FCancelBtn, False);
          EnableWindow(FAddBtn, False);
          MessageBox(0, PChar(IntToStr(Integer(Self))), 'Self', 0);
          FThread_CheckLinks := CreateThread(nil, 0, @TLinksWnd.Thread_CheckLinks, Self, 0, PDWORD(nil)^);
        end;
      end;
    end;
    WM_CLOSE:
    begin
      ShowWindow(hWindow, SW_HIDE);
    end;
    else
     Result := DefWindowProc(hWindow, uMsg, wPar, lPar);
  end;
end;

Tak w ogóle to czym jest Self? Bo pasuje do Pointera i TLinksWnd, tak jakby był Variantem.
Przekazywać go powinno się jako:
Self
czy
@self
Czy jeszcze jakoś inaczej? (Np. deklarując nad klasą PLinksWnd = ^TLinksWnd i wykorzystując to)

Widzę, że nie da się niczego przekazać poprzez lpVoid, nawet zwykłego wskaźnika na rekord.
Zawsze jest 3, a 3 to chyba nil (bo jak dam nil to też MessageBox pokaże 3).

0

w ten desen (jak pisalem kilka razy w tym watku)

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    FThread_CheckLinks: DWORD;
    function Thread_CheckLinks(): DWORD; stdcall;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
function TForm1.Thread_CheckLinks(): DWORD; stdcall;
var
  hWindow: HWND;
  iRet: Integer;

  iLinksCount: Integer;
begin
  hWindow := Integer(Self);
  MessageBox(0, PChar(IntToStr(Integer(hWindow))), 'lpVoid', 0); //Pokazuje zawsze liczbę 3

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  caption := IntToStr(Integer(self));
  FThread_CheckLinks := CreateThread(nil, 0, @TForm1.Thread_CheckLinks, Self, 0, PDWORD(nil)^);


  //100 ---------------
  FThread_CheckLinks := CreateThread(nil, 0, @TForm1.Thread_CheckLinks, pchar(100), 0, PDWORD(nil)^);
end;

end.

0

No wreszcie skumałem. Wielkie dzięki reichel.

0

Na twoim miejscu przyinteresowal bym sie jak wyglada obiekt (bardziej w pamieci), struktury, funkcje, rodzeje wywolan, etc ...

to pozniej ulatwi Ci zycie (che che ktos moglby powiedziec co to za zycie).

0

O widzę, że mam double posta. No cóż edit :D ! Może i się zainteresuje, ale jak będę miał czas, bo na razie prawie nie mam czasu na pisanie programu. Jeszcze raz wielkie dzięki.

1 użytkowników online, w tym zalogowanych: 0, gości: 1