Check-in [9584fe1b9f]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:* If the program is already running, don't launch a second instance but activate the first; * If Shift is pressed during shutdown, no line '(closed)' is added.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 9584fe1b9f17b1a2f81ad10d32d6627617a6d3e0
User & Date: MCO 2011-05-05 08:59:15
Context
2011-05-05
08:59
* If the program is already running, don't launch a second instance but activate the first; * If Shift is pressed during shutdown, no line '(closed)' is added. check-in: c982850919 user: MCO tags: trunk
08:59
* If the program is already running, don't launch a second instance but activate the first; * If Shift is pressed during shutdown, no line '(closed)' is added. check-in: 9584fe1b9f user: MCO tags: trunk
2011-05-04
13:07
Added icon, keyboard shortcuts check-in: 25b06ad3a6 user: MCO tags: trunk
Changes

Added src/lib/CheckPrevious.pas.

















































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
unit CheckPrevious;
{
********************************************
Zarko Gajic
About.com Guide to Delphi Programming
http://delphi.about.com
email: delphi.guide@about.com
free newsletter: http://delphi.about.com/library/blnewsletter.htm
forum: http://forums.about.com/ab-delphi/start/
********************************************
}
interface
uses Windows, SysUtils;

function RestoreIfRunning(
                const AppHandle : THandle;
                MaxInstances : integer = 1) : boolean;

implementation
{$IFDEF USEVERSIONINFO}
uses
  L_VersionInfoW;
{$ENDIF}

type
  PInstanceInfo = ^TInstanceInfo;
  TInstanceInfo = packed record
    PreviousHandle : THandle;
    RunCounter : integer;
  end;

var
  MappingHandle: THandle;
  InstanceInfo: PInstanceInfo;
  MappingName : string;

  RemoveMe : boolean = True;

{ ------------------------------------------------------------------------------------------------ }
function RestoreIfRunning(
             const AppHandle : THandle;
             MaxInstances : integer = 1) : boolean;
var
  FWI: FLASHWINFO;
{$IFDEF USEVERSIONINFO}
  FVI: TFileVersionInfo;
{$ENDIF}
begin
  Result := True;

{$IFDEF USEVERSIONINFO}
  FVI := TFileVersionInfo.Create(ParamStr(0));
  try
    if FVI.HasVersionInfo then begin
      MappingName := Format('%s_%s_%s_V%d.%d',
                            [FVI.CompanyName, FVI.ProductName, FVI.Internalname,
                             FVI.MajorVersion, FVI.MinorVersion]);
    end else begin
{$ENDIF}
      MappingName := StringReplace(ParamStr(0),
                                   '\','',
                                   [rfReplaceAll, rfIgnoreCase]);
{$IFDEF USEVERSIONINFO}
    end;
  finally
    FVI.Free;
  end;
{$ENDIF}

  MappingHandle := CreateFileMapping($FFFFFFFF,
                                     nil,
                                     PAGE_READWRITE,
                                     0,
                                     SizeOf(TInstanceInfo),
                                     PChar(MappingName));

  if MappingHandle = 0 then
    RaiseLastOSError
  else
  begin
    if GetLastError <> ERROR_ALREADY_EXISTS then
    begin
      InstanceInfo := MapViewOfFile(MappingHandle,
                                    FILE_MAP_ALL_ACCESS,
                                    0,
                                    0,
                                    SizeOf(TInstanceInfo));

      InstanceInfo^.PreviousHandle := AppHandle;
      InstanceInfo^.RunCounter := 1;

      Result := False;
    end
    else //already runing
    begin
      MappingHandle := OpenFileMapping(
                                FILE_MAP_ALL_ACCESS, 
                                False, 
                                PChar(MappingName));
      if MappingHandle <> 0 then
      begin
        InstanceInfo := MapViewOfFile(MappingHandle,
                                      FILE_MAP_ALL_ACCESS,
                                      0,
                                      0,
                                      SizeOf(TInstanceInfo));

        if InstanceInfo^.RunCounter >= MaxInstances then
        begin
          RemoveMe := False;

          if IsIconic(InstanceInfo^.PreviousHandle) then
            ShowWindow(InstanceInfo^.PreviousHandle, SW_RESTORE);
          if not SetForegroundWindow(InstanceInfo^.PreviousHandle) then begin
            FWI.cbSize := sizeof(FWI);
            FWI.hwnd := InstanceInfo^.PreviousHandle;
            FWI.dwFlags := FLASHW_ALL;
            FWI.uCount := 5;
            FWI.dwTimeout := 125;
            FlashWindowEx(FWI);
          end;
        end
        else
        begin
          InstanceInfo^.PreviousHandle := AppHandle;
          InstanceInfo^.RunCounter := 1 + InstanceInfo^.RunCounter;

          Result := False;
        end
      end;
    end;
  end;
end; (*RestoreIfRunning*)

initialization
//nothing special here
//we need this section because we have the
//finalization section

finalization
  //remove this instance
  if RemoveMe then
  begin
    MappingHandle := OpenFileMapping(
                        FILE_MAP_ALL_ACCESS, 
                        False, 
                        PChar(MappingName));
    if MappingHandle <> 0 then
    begin
      InstanceInfo := MapViewOfFile(MappingHandle,
                                  FILE_MAP_ALL_ACCESS,
                                  0,
                                  0,
                                  SizeOf(TInstanceInfo));

      InstanceInfo^.RunCounter := -1 + InstanceInfo^.RunCounter;
    end
    else
      RaiseLastOSError;
  end;

  if Assigned(InstanceInfo) then UnmapViewOfFile(InstanceInfo);
  if MappingHandle <> 0 then CloseHandle(MappingHandle);

end(*unit CheckPrevious*).