Uzyskanie głównego okna z uchwytu kontrolki.

0

Cześc. Jak wiecie, co zawsze powtarzam - staram się sobie radzić samodzielnie. Jednak teraz utknąłem z pozornie prostą rzeczą. Chodzi mi o kod działający również w WinAPI. Chce wiedzieć jak zrobić funkcję, która po podaniu uchwytu jakiejś kontrolki, będzie od niej tak enumerować pozostałe aby uzyskać uchwyt okna rodzica jako dialogu lub formatki. Czyli na przykład pod VCL, kładziemy na formatkę TFrorm1 TPanel, na niego TButton i podajemy do funkcji NaszButton.Handle. W rezultacie mamy dostać uchwyt HWND tejże TForm1. Bez względu na to, na jakich innyh komponentach czy kontrolkach okna dialogowego "leżał" ten Button czy inna kontrolka. Kombinowałem z GetParent, GetWindow i GetWindowLong(PrevHandle, GWL_HWNDPARENT), kombinując z GW_HWNDPREV i GW_HWNDNEXT, ale bez powodzenia. Próbowałem googlować, ale mało skutecznie. Prosił bym o przykładowy kod. Bez sensu jest chyba dośc wolne rozwiązanie, żeby enumerować wszystkie okna w systemie, szukać na nich kontrolki o danym uchwycie, a jeśłi znajdzie, zwracać ten uchwyt. Bo nie mam pewności czy to się sprawdzi, dla okienek dialogowych z szablonów w zsobach, które są pokazanye modalnie. Z góry dziękuję za wszelkie pomysły.

0

Ok, jednak sobie sam poradziłem. Mój kod poniżej. Ważne jest to, aby te trzy zmienne, które są na poczatku były poza ciałem całej funkcji jako globalne. Inaczej będziemy mieli bład AV. Jednak jeśli wrzucimy sobie te funkcje do osobnego modułu i umieścimy je poniżej sekcji implementation, to w nimczym to raczej nie przeszkdza. Wyszukiwanie trwa nawet dla wielu otwartych okien i kontrolki w ostatnim z nich jakieś ułamki sekund. Także chyba przy tym rozwiązaniu pozostane. Ale jeżeli ktoś z Was tutaj zna lepsze rozwiązanie, to proszę napiszcie.

unit get_handle_of_main_window_control;

interface

uses
  WIndows;

function GetHandleOfMainWindowControl(ControlHandle : HWND) : HWND;

implementation

var
  DestH, TempH : HWNd;
  StopEnumNow : boolean;

function GetHandleOfMainWindowControl(ControlHandle : HWND) : HWND;

  function EnumChildWinProc(AHandle : HWND; LParam : LParam) : boolean; stdcall;
  begin
    Result := True;
    if AHandle = DestH then
    begin
      StopEnumNow := True;
      Result := False;
    end;
  end;

  function EnumWindowsProc(AHandle : HWND; ALParam : LParam) : boolean; stdcall
  begin
    Result := True;
    TempH := AHAndle;
    EnumChildWindows(AHandle, @EnumChildWinProc, 0);
    if StopEnumNow then
    begin
      Result := False;
    end;
  end;

begin
  TempH := 0;
  StopEnumNow := False;
  DestH := ControlHandle;
  EnumWindows(@EnumWindowsProc, 0);
  Result := TempH;
end;

end.
0

Ważne jest to, aby te trzy zmienne, które są na poczatku były poza ciałem całej funkcji jako globalne. Inaczej będziemy mieli bład AV.

You must be using Delphi7.
FPC nie pozwala na pobranie adresu procedury w procedurze z tego właśnie powodu, że wtedy dziecko będzie się kreszować przy dostępie do zmiennych lokalnych wyższego poziomu. Twój kod nie powinien być przepuszczany przez kompilator. No ale niektórym po prostu nie da się przemówić do rozsądku ;) , będą używali i bronili kompilatora dopóki się okaże że ma to zalety w stylu 'Program D7 ładuje się o 1ns szybciej' etc. . Co jak co ale moderator chyba powinien pomyśleć o unowocześnieniu swojego warsztatu pracy...

Jednak jeśli wrzucimy sobie te funkcje do osobnego modułu i umieścimy je poniżej sekcji implementation, to w nimczym to raczej nie przeszkdza.

Można napisać klasę jeżeli chce się mieć ładny kod.

0

Po prostu @olesio bardzo lubi WinAPI i nie potrzebuje do tego kombajnów jak Lazarus - wystarczy Delphi 7 ;)

Delphi3 też potrafi generować kod 32bitowy, nagłówki można sobie załatwić (i co najlepsze, jest mniejsze niż D7, dla olesia mus). Tutaj nie chodzi o bycie kombajnem, tutaj chodzi o ogarnięcie kompilatora, może on sobie używać FPC i tworzyć programy bez LCL ale z dobrym środowiskiem Lazarusa. Jaka będzie różnica? Brak kompilatora sprzed 10 lat, mniej bugów, lepszy kod (wspierany przez wiele smaczków dodanych w FPC). Łatwiejsza refaktoryzacja kodu, podpowiadanie składni. Już nie mówiąc że obecnie się każdemu odradza używanie D7 niczym TP7. To jest po prostu marnowanie swojego czasu na zabawy w stylu 'czemu ten kod nie działa?' gdy FPC by od razu wypluł jasny błąd. A sam FPC to mniejszy kombajn niż to wasze 'minimalistyczne' D7.
Wniosek jest bardzo prosty: Olesio się ogranicza. Widać postęp w stylu jakieś przygody z Lazarusem x64, ale to wciąż jest niewiele w porównaniu z tym co wielu użytkowników zrobiło, czyli wywaleniem D7 do śmieci.

0

masz to: protected TWinControl.GetTopParentHandle
oraz: function GetParentForm(Control: TControl): TCustomForm;
oraz: HWND WINAPI GetParent(_In_ HWND hWnd); http://msdn.microsoft.com/en-us/library/windows/desktop/ms633510%28v=vs.85%29.aspx

0

Wolę używać Delphi 7 w większości przypadków. Generuje mniejesze exeki, a obsługa IDE nie sprawia, że się motam jak pod Lazarusem. To czy jestem moderatorem nie ma na to wpływu, Piszę w WinAPI, bo tworzę docelowo dllkę, która ma być jak najmniejsza, ale i tak nie może być packnięta niczym ani korzystać z alternatywnych modułów Windows i System z http://kolmck.net - ponieważ te generują kilka false positives według VirusTotal.

A Pomysł z klasą jest ok, ale musze pokombinować bo nie umiem przekazać funkcją Api kodu będącego zawarotścią klasy. Dla modułów na wygooglowanych na sieci i z kod VCL dla Delphi 7 wiem, że trzeba kombinować z MakeObjectInstance, ale to działa dla funkcji WndProc i Hooków z 4 parametrami, przez króre nic nie jest zwracane. Kobminowanie jak na: http://stackoverflow.com/questions/10460171/get-pointer-of-member-function-delphi nie działa.

Ponieważ nawet jeżeli zmienię kod tej funkcji to nie zwraca mi uchwytów z pierwszego parametru, tylko przyjmuje go jako to co podamy do LParam. Troszkę się pogubiłem w tym. Na szybko łatwiej można zrobić taki moduł jakiego kod pokazałem powyżej. Przynajmniej dla mnie, osoby, które rzadko tworzy własne klasy. Jak to można rozwiązać? Chyba, że egwa (i inne podobne nicki) miał na myśli, że klasa i tak się odwoła do funkcji enumerujących nie będących elementami klasy. Prosił bym o przykład kodu. Przy okazji czegoś nowego dla mnie się nauczę.

@_13th_Dragon: GetParent zwróci Handle na przykład TPanel, jeżeli to na nim będzie umieszczona dana kontrolka, jak na przykład TButton, także dla mnie odpada. A i podsumowując. Lubię pisać w WinAPI, kiedy daję radę. Ale nie jestem żaden Perfect Pan Programista Forum 4p i nigdy takich aspiracji nie miałem i mieć nie będę. Cały czas się staram czegoś uczyć w kwestii poznawania obiektowego pascala.

EDIT: z kodu Forms.pas z Delphi 7, wynika ze jednak można posiłkować się klasą, ale elementy jaka funkcja enumerująca są poza klasą. Czyli tak należy kombinować:

//...
function GetTopMostWindows(Handle: HWND; Info: Pointer): BOOL; stdcall;
begin
  Result := True;
  if GetWindow(Handle, GW_OWNER) = Application.Handle then
    if (GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0) and
      ((Application.MainForm = nil) or PTopMostEnumInfo(Info)^.IncludeMain or
      (Handle <> Application.MainForm.Handle)) then
      Application.FTopMostList.Add(Pointer(Handle))
    else
    begin
      PTopMostEnumInfo(Info)^.TopWindow := Handle;
      Result := False;
    end;
end;

procedure TApplication.DoNormalizeTopMosts(IncludeMain: Boolean);
var
  I: Integer;
  Info: TTopMostEnumInfo;
begin
  if Application.Handle <> 0 then
  begin
    if FTopMostLevel = 0 then
    begin
      Info.TopWindow := Handle;
      Info.IncludeMain := IncludeMain;
      EnumWindows(@GetTopMostWindows, Longint(@Info));
      if FTopMostList.Count <> 0 then
      begin
        Info.TopWindow := GetWindow(Info.TopWindow, GW_HWNDPREV);
        if GetWindowLong(Info.TopWindow, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0 then
          Info.TopWindow := HWND_NOTOPMOST;
        for I := FTopMostList.Count - 1 downto 0 do
          SetWindowPos(HWND(FTopMostList[I]), Info.TopWindow, 0, 0, 0, 0,
            SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOOWNERZORDER);
      end;
    end;
    Inc(FTopMostLevel);
  end;
end;
//...
0
olesio napisał(a):

@_13th_Dragon: GetParent zwróci Handle na przykład TPanel, jeżeli to na nim będzie umieszczona dana kontrolka, jak na przykład TButton, także dla mnie odpada.
Ja myślałem że słyszałeś o while... ;P

0

@_13th_Dragon: słyszałem o while, ale prosił bym przykład jak tego użyć, bo nie mam doświadczenia z GetParent i GetWindow. A za pewne ich użycie będzie jeszcze szybsze niż enumerowanie wszystkich okien. Które wprawdzie trwa niezauważalnie u mnie. Ale na pewno idealne rozwiązanie to nie jest. I jestem tego świadomy :)

3
function FormHandle(Ctrl:THandle):THandle;
begin
  Result:=0;
  while Ctrl<>0 do
  begin
    Result:=Ctrl;
    Ctrl:=GetParent(Ctrl);
  end;
end;
if Form1.Handle=FormHandle(Button1.Handle) then ShowMessage("Ok");
if Form1=GetParentForm(Button1) then ShowMessage("Ok");
0

No proszę. Proste acz geniealne, a ja kombinowałem na około. Dziękuję @_13th_Dragon. Czegoś się nowego nauczyłem, żeby nie komplikować ponadto co potrzebne, wedle zasady KISS. A i poprawiłem w treści posta procedure na function oczywiście.

0

Generuje mniejesze exeki

Powiedz mi ile dokładnie waży najmniejszy exek typu 'helloworld' w D7 (packer dowolny). Ja ci pokażę 'helloworld' z FPC spakowany moim ulubionym packerem, zobaczymy jaka będzie różnica.
Widzę że olesio w dobie dysków 1TB musi mieć najmniejsze exeki, ale nie, nie assembler który by pozwolił na najmniejsze pliki, tylko argument w myśl którego sam wychodzisz co jak co ale na idiotę...
Polecam Delphi 3 albo Nasm.

a obsługa IDE nie sprawia, że się motam jak pod Lazarusem

Kwestia przyzwyczajenia, natomiast to motanie się zaowocuje w przyszłości.

To czy jestem moderatorem nie ma na to wpływu

Moim zdaniem ma, bo to zwiększa twoją wiarygodność. Powinieneś dawać dobry przykład.

Piszę w WinAPI, bo tworzę docelowo dllkę, która ma być jak najmniejsza, ale i tak nie może być packnięta niczym ani korzystać z alternatywnych modułów Windows i System z http://kolmck.net - ponieważ te generują kilka false positives według VirusTotal.

Zakładając że twoim jedynym priorytetem jest rozmiar, użyj Delphi3 albo Nasma.
Poza tym, UPX generuje falsepositivy tylko na genialnych antywirusach.
Przypomina mi się anticheat jednej gry. Koleś nie packował go niczym, nie zabezpieczał, był pisany w C++ (Dzięki czemu sobie IDĄ mogłem podglądać co on takiego robi żeby wykrywać cheaty i napisać sobie niewykrywalnego). Koniec końców jakiś genialny antywirus wykrył ten plik jako wirus, bo uwaga uwaga, użył on biblioteki kryptograficznej. Wobec tego czy można się zabezpieczyć przed antywirusem ciot? Nie.
Już nie mówiąc o tym że zjeboantywirusy lubią generować falsepositivy na plikach które są małe więc olesio, sam się pakujesz w problemy. Twój argument nie ma sensu od żadnej strony.
Każdy miał do czynienia z fałszywymi trafieniami, marzenie o braku powyższych to marzenie ściętej głowy. Zawsze znajdzie się antywirus który wykryje coś.
Wobec tego jeżeli na prawdę potrzebujesz małego rozmiaru, mam gdzieś packer który spakuje twój plik o parę kb lepiej niż każdy inny dostępny packer, tylko że będzie to rozpakowywać przez parę sekund (dla 60Kb pliku). I nie jestem przekonany czy wspiera Dllki, hm... Jeżeli nie to mam taki który generuje sporo lepsze wyniki od UPXa i wielu innych 'niesamowitych' packerów (i jest już raczej niedostępny na internetach). Oczywiście umie on packować też wirusy, wobec czego niektórzy twórcy antywirusów po prostu oznaczają każdy jego plik jako wirus. O idiotyzmie powyższego nie muszę mówić mam nadzieję?
Osobom którym wyskakuje komunikat o wirusie w moim sofcie polecam zmianę antywirusa. Osobiście używam darmowego Avasta, nawet on umie rozpakować mój ulubiony packer i nie ma wątów do niego... Tobie polecam podobne podejście, bo po prostu nie wyeliminujesz każdego false-positiva. Niech się użytkownicy antywirusa ciot martwią (i zgłaszają jako falsepositive), nie ty.

A Pomysł z klasą jest ok, ale musze pokombinować bo nie umiem przekazać funkcją Api kodu będącego zawarotścią klasy. Dla modułów na wygooglowanych na sieci i z kod VCL dla Delphi 7 wiem, że trzeba kombinować z MakeObjectInstance, ale to działa dla funkcji WndProc i Hooków z 4 parametrami, przez króre nic nie jest zwracane.

Przecież można przekazać parametr rozmiaru 32-bity, zrzutuj sobie wskaźnik na klasę na int, potem przekaż i przerób na klasę.

Chyba, że egwa (i inne podobne nicki) miał na myśli, że klasa i tak się odwoła do funkcji enumerujących nie będących elementami klasy. Prosił bym o przykład kodu. Przy okazji czegoś nowego dla mnie się nauczę.

Kompiluje się pod FPC. Wykonania nie sprawdzałem.

unit get_handle_of_main_window_control;

interface

uses
  Windows;

function GetHandleOfMainWindowControl(ControlHandle : HWND) : HWND;

implementation

type
  TEnumClass = class
  private
    DestH, TempH : HWND;
    StopEnumNow : boolean;
    function SearchForControl(ControlHandle : HWND) : HWND;
  end;

function EnumChildWinProc(AHandle : HWND; ALParam : LParam) : LongBool; stdcall;
var
  EC : TEnumClass;
begin
  EC := TEnumClass(ALParam);
  Result := True;
  if AHandle = EC.DestH then
  begin
    EC.StopEnumNow := True;
    Result := False;
  end;
end;

function EnumWindowsProc(AHandle : HWND; ALParam : LParam) : LongBool; stdcall;
var
  EC : TEnumClass;
begin
  EC := TEnumClass(ALParam);
  Result := True;
  EC.TempH := AHAndle;
  EnumChildWindows(AHandle, @EnumChildWinProc, LParam(EC));
  if EC.StopEnumNow then
  begin
    Result := False;
  end;
end;

function TEnumClass.SearchForControl(ControlHandle : HWND) : HWND;
begin
  TempH := 0;
  StopEnumNow := False;
  DestH := ControlHandle;
  EnumWindows(@EnumWindowsProc, LParam(Self));
  Result := TempH;
end;

function GetHandleOfMainWindowControl(ControlHandle : HWND) : HWND;
var
  EC : TEnumClass;
begin
  Result := 0;
  if IsWindow(ControlHandle) then
  begin
    EC := TEnumClass.Create;
    Result := EC.SearchForControl(ControlHandle);
    EC.Free;
  end;
end;

end.
0

Kod @_13th_Dragon jednak nie jest jednak zawsze skuteczny, bo są kontrolki na oknach dialogowych dla których rezultat jest inny. Dzięki za Twój kod @payl - dostosowałem go do tego aby się kompilował też pod znienawidzonym przez Ciebie Delphi. Poniżej kod tego modułu. I podobnie też kombinowałem wcześniej sam. Co do pytania to najmniejszy exek z helloworld pod Delphi 7 spakowany UPX'em z parametrem -9 zajmuje u mnie dokładnie 5120 bajtów. I hamuj się. Ja nie nazywam nikogo idiotą. Tylko dlatego, że śmie używać Delphi 7. Mam inne zdanie niż Ty. Trzeba to uszanować. Delphi 3 nadal mam na dysku, ale jak wiadomo brakuje tam w kodzie wielu klas i definicji funkcji. Nie chce mi się też uczyć Nasma. Z pisaniem TSR'a do dosowej gry na bazie przykładów miałem problemy bo nie działalo i już. To co dopiero pod Windowsem się bedzie dziać. Będę używał Delphi 7 póki co i nic mnie do zmiany nastawienia nie zmieni. Tak jak Ciebie nic nie przekona do narzucania wszystkim FPC i Lazarusa oraz odnoszenia się często chamsko do innych tylko dlatego, że nie podzielają Twoich poglądów. Wiem, że tylko krowa nie zmienia poglądów. Kiedyś jak zaczynałem się bawic w programowanie i nawet ucząc się na policealnym studium jako przyszły technik informatyk uważałem - co jest oczywiśćie głupie - że formatowanie kodu jest zbędne i je usuwałem. Teraz na niesformatowany kod nie mogę nawet spojrzeć. Anyway. Wierz mi lub nie, ale Lazarusa 64 bitowego (napisałem w nim nawet prosty plugin dla 64 bitowego AQQ) i FPC też mam na dysku. Delphi 7 powstało mniej więcej w czasach istnienia na rynku XP, a ten system jeszcze niektórzy muszą z konieczności używać. Mimo jako miłośnik oldskoolu i czasem abandoware i niektórych dosowych gier, zgodzę się jednak, że pisanie w Turbo Pascalu to przesada. Jednak Delphi 7 jest dla mnie do zaakceptowania. Szanuj zdanie innych. Proszę nie dziw się więc później, że Administratorzy Ciebie banują czy, że spotykasz się z niechęcią. Podsumowując ja GURU nie jestem. I nie mam oczywicie takich aspiracji. Jednak nigdy nikogo nie zwyzywam, jeśli czegoś nie wie. Albo używa przestażałego IDE. Zawsze może poszukać czegoś. Ale ludziom się nie chce. To inna sprawa niestety. Nikt jednak kto nie ubliża innym nie zasługuje na to by w sposób chamski i jego atakować. Swój pogląd może jednak kiedyś zmienię i będę używał pr0 IDE Lazarusa na czasie, ale na pewno nie będę tego narzucał innym. Ludzie piszą też nie wiedzieć dlaczego koniecznie z użyciem Indy zamiast Synapse. Jednak każdego wybór. Tylko późnej @kAzek musi z tym pomagać, bo chyba tylko On to do końca ogarnia (tak samo jak ktoś chce używać TWebBrowser do prostej obsługi HTTP).

unit get_handle_of_main_window_control;

interface

uses
  Windows;

function GetHandleOfMainWindowControl(ControlHandle : HWND) : HWND;

type
  TEnumClass = class
  private
    DestH, TempH : HWND;
    StopEnumNow : boolean;
    function SearchForControl(ControlHandle : HWND) : HWND;
  end;

implementation

function EnumChildWinProc(AHandle : HWND; ALParam : LParam) : LongBool; stdcall;
var
  EC : TEnumClass;
begin
  EC := TEnumClass(ALParam);
  Result := True;
  if AHandle = EC.DestH then
  begin
    EC.StopEnumNow := True;
    Result := False;
  end;
end;

function EnumWindowsProc(AHandle : HWND; ALParam : LParam) : LongBool; stdcall;
var
  EC : TEnumClass;
begin
  EC := TEnumClass(ALParam);
  Result := True;
  EC.TempH := AHAndle;
  EnumChildWindows(AHandle, @EnumChildWinProc, LParam(EC));
  if EC.StopEnumNow then
  begin
    Result := False;
  end;
end;

function TEnumClass.SearchForControl(ControlHandle : HWND) : HWND;
begin
  TempH := 0;
  StopEnumNow := False;
  DestH := ControlHandle;
  EnumWindows(@EnumWindowsProc, LParam(Self));
  Result := TempH;
end;

function GetHandleOfMainWindowControl(ControlHandle : HWND) : HWND;
var
  EC : TEnumClass;
begin
  Result := 0;
  if IsWindow(ControlHandle) then
  begin
    EC := TEnumClass.Create;
    Result := EC.SearchForControl(ControlHandle);
    EC.Free;
  end;
end;

end.

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