[Delphi] 2de start app, 1ste on-top

Pagina: 1
Acties:

  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Topicstarter
Ik wil niet dat de gebruiker twee keer mijn applicatie kan starten. Probeert hij dit wel, dan moet de eerste versie van mijn applicatie on-top worden gebracht.

Nou had ik hier een mooie oplossing voor:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var
  hMutex: THandle;

begin
  hMutex := CreateMutex(nil, False, 'AppNaam');
  try
    if WaitForSingleObject(hMutex, 0) <> WAIT_TIMEOUT then begin
    Application.Initialize;
    Application.Title := 'AppNaam';
    Application.CreateForm(TMainForm, MainForm);
    //eventueel meedere forms hier
    Application.Run;
    end else begin
    SetForegroundWindow(FindWindow('TMainForm', nil));
    CloseHandle(hMutex);
    end;
  finally
    ReleaseMutex(hMutex);
  end;
end.

Het probleem is echter dat als de gebruiker een totaal andere applicatie met dezelfde form naam (in dit geval TMainForm) heeft dan wordt deze (soms) on-top gehaald. Is hier een betere oplossing voor?

"The shell stopped unexpectedly and Explorer.exe was restarted."


  • Mr_Blobby
  • Registratie: Mei 2000
  • Laatst online: 13-09 12:53
Misschien met een FindWindow() functie?
code:
1
2
3
4
5
var
    hTestWindow : THandle;
...
    hTestWindow:=Findwindow( 'TestWindowClassName',nil )
    SetForeGroundWindow(hTestWindow);

Met als TestWindowClassName de classname van het window dat je zoek.
of
code:
1
2
3
4
5
var
    hTestWindow : THandle;
...
    hTestWindow:=Findwindow(nil, 'TestWindowCaption');
    SetForeGroundWindow(hTestWindow);

Met als TestWindowCaption de string in de titelbalk van het window dat je zoekt.

en zij zagen niet hoe spot in mij worstelde met verdriet


  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Topicstarter
Dat heb ik toch: :?
code:
1
2
    SetForegroundWindow(FindWindow('TMainForm', nil));
    CloseHandle(hMutex);

"The shell stopped unexpectedly and Explorer.exe was restarted."


  • Mr_Blobby
  • Registratie: Mei 2000
  • Laatst online: 13-09 12:53
Inderderdaad, stom |:(
Maar is het dan niet mogelijk om op zowel de classname als de windowtitel te checken. Het moet wel een hele rare applicatie zijn als die samen niet uniek zijn ...

en zij zagen niet hoe spot in mij worstelde met verdriet


Verwijderd

Misschien kun je 1 of andere message naar de form sturen en als je daar bv 100 op terugkrijgt is het hetzelfde programma..

Maar ik snap niet precies wat je met die mutex doet, bedoeling is toch dat die zolang het programma runt, bestaat?

[Oeps: niet goed gelezen :)]

  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Topicstarter
Op maandag 10 december 2001 14:59 schreef DiFool het volgende:
Maar ik snap niet precies wat je met die mutex doet, bedoeling is toch dat die zolang het programma runt, bestaat?
Ik heb die code met Google gevonden. Volgens mij maakt hij een Mutex aan met dezelfde naam, lukt dit niet (er is al 1 met die naam) dan moet die on-top worden gehaald, anders programma gewoon starten. Volgens mij is dat de functie van die mutex.


Verder had ik idd ook het idee een message naar mijn programma te sturen dat ie on-top moet komen. Maar daar heb ik geen ervaring mee. Is dit een oplossing? Zo ja, hoe moet dit dan?

"The shell stopped unexpectedly and Explorer.exe was restarted."


Verwijderd

Probeer dit eens:
code:
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
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    FCheckMsg: LongWord;
  protected
    procedure WndProc(var Message: TMessage); override;
    function OtherExists: Boolean;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
  OtherHandle: HWnd;
begin
  if FCheckMsg = 0 then
    FCheckMsg := RegisterWindowMessage('CheckApp');
  if OtherExists then
    ShowMessage('Ander actief');
end;

procedure TForm1.WndProc(var Message: TMessage);
begin
  if (FCheckMsg <> 0) and (Message.Msg = FCheckMsg) then
    Message.Result := 100
  else
    inherited;
end;

function EnumCallBack(Handle: HWnd; info: Pointer): BOOL; stdcall;
var
  Buffer: array[0..100] of Char;
  H: HWnd;
begin
  Result := True;
  if (GetClassName(Handle, @Buffer, SizeOf(Buffer)) > 0)
    and (StrComp(Buffer, 'TForm1') = 0)
    and (GetWindow(Handle, GW_OWNER) <> Application.Handle) then

    TList(info).Add(Pointer(Handle));
end;

function TForm1.OtherExists: Boolean;
var
  HandleList: TList;
  I: Integer;
begin
  Result := False;
  HandleList := TList.Create;
  try
    EnumWindows(@EnumCallBack, Longint(HandleList));
    for I := 0 to HandleList.Count - 1 do
    Result := Result
      or (SendMessage(HWnd(HandleList[I]), FCheckMsg, 0, 0) = 100);
  finally
    HandleList.Free;
  end;
end;

end.

  • jelmervos
  • Registratie: Oktober 2000
  • Niet online

jelmervos

Simple user

Topicstarter
Lekker lap code, kun je misschien beetje uitleggen wat het precies doet?

"The shell stopped unexpectedly and Explorer.exe was restarted."


Verwijderd

in HandleList zet hij alle handles van forms van het type TFORM1
( EnumWindows(@EnumCallBack, Longint(HandleList));)

daarna stuurt hij er een bericht naar, en kijkt of die 100 terug krijgt.
(
for I := 0 to HandleList.Count - 1 do
Result := Result
or (SendMessage(HWnd(HandleList[I]), FCheckMsg, 0, 0) = 100);
)

Verwijderd

Op maandag 10 december 2001 15:48 schreef DiFool het volgende:
Probeer dit eens:
Nette oplossing, en niet eens zo ingewikkeld.
Al zou ik voor de netheid (en een wat universelere inzetbaarheid) 'TForm1' vervangen door Application.MainForm.ClassName.

Verwijderd

Via RegisterWindowMessage krijg je een unieke message id, die gekoppeld wordt aan de string 'CheckApp' [CheckApp is willekeurig gekozen]; andere programma's zullen dus hier niet op reageren en alle programma's die RegisterWindowMessage('CheckApp') aanroepen, krijgen dezelfde message id terug.

In de WndProc reageer je op deze message door Result op 100 te zetten. [100 is willekeurig]

In de functie OtherExists roep je EnumWindows aan, die voor elke window EnumCallBack zal aanroepen met als parameters de handle van de window en het getal dat je meegeeft aan EnumWindows [hier een pointer naar de TList HandleList]

In EnumCallBack vraag je de classname op van die window en als die gelijk is aan 'TForm1' en het niet het huidige programma is dan voeg je die toe aan HandleList.

Als EnumWindows is afgelopen is HandleList gevuld met alle potentiële kandidaten; hier stuur je een message heen en als hier 100 op terug komt, bestaat er nog een andere instance.

Ik heb dat geintje met EnumWindows gedaan omdat ik dacht dat het niet met FindWindow zou gaan omdat je dan een message naar de eigen window zou kunnen sturen; maar nu ik jouw code weer lees zie ik dat je dat doet voordat je de mainform creëert. 2x verkeerd lezen |:( Maar het kan natuurlijk voorkomen dat er een window is die toevallig hetzelfde heet en nog een window die een app instance is. Dan gaat deze code wellicht goed...

En wat Afterlife zei is natuurlijk waar :)

Verwijderd

Op maandag 10 december 2001 22:39 schreef DiFool het volgende:
Ik heb dat geintje met EnumWindows gedaan omdat ik dacht dat het niet met FindWindow zou gaan omdat je dan een message naar de eigen window zou kunnen sturen; maar nu ik jouw code weer lees zie ik dat je dat doet voordat je de mainform creëert.
FindWindow geeft maar 1 handle terug (de eerste die 'ie vindt), dus EnumWindows is in dit geval veiliger.
Pagina: 1