Subversion Repositories aysalia

Rev

Rev 30 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 30 Rev 31
1
program AyDos;
1
program AyDos;
2
 
2
 
3
// Aysalia DOS Launcher
3
// Aysalia DOS Launcher
4
// Revision 2018-12-07
4
// Revision 2018-12-08
5
// (C) 2018 Daniel Marschall, ViaThinkSoft
5
// (C) 2018 Daniel Marschall, ViaThinkSoft
6
 
6
 
7
// This launcher does launch DOSBox with the correct *.conf file,
7
// This launcher does launch DOSBox with the correct *.conf file,
8
// centers the window and changes the window title and icon at runtime.
8
// centers the window and changes the window title and icon at runtime.
9
 
9
 
10
uses
10
uses
11
  SysUtils,
11
  SysUtils,
12
  ShellAPI,
12
  ShellAPI,
13
  Windows,
13
  Windows,
14
  Messages;
14
  Messages;
15
 
15
 
16
{$R *.RES}
16
{$R *.RES}
17
 
17
 
18
const
18
const
19
  DOSBOX_EXE = 'DOSBox.exe';
19
  DOSBOX_EXE = 'DOSBox.exe';
20
  AYDOS_MNU = 'AyDos.mnu';
20
  AYDOS_MNU = 'AyDos.mnu';
21
  AYDOS_COM = 'AyDos.com';
21
  AYDOS_COM = 'AyDos.com';
22
 
22
 
23
var
23
var
24
  hPsApiDll: Cardinal = 0;
24
  hPsApiDll: Cardinal = 0;
25
  hIcon: THandle = 0;
25
  hIcon: THandle = 0;
26
  bCeneredOnce: boolean = false;
26
  bCeneredOnce: boolean = false;
27
 
27
 
28
(*
28
(*
29
function GetModuleFileNameEx(inProcess: THandle; inModule: THandle;
29
function GetModuleFileNameEx(inProcess: THandle; inModule: THandle;
30
      Filename: PChar; size: DWord): DWord; stdcall;
30
      Filename: PChar; size: DWord): DWord; stdcall;
31
      external 'psapi.dll' name 'GetModuleFileNameExA';
31
      external 'psapi.dll' name 'GetModuleFileNameExA';
32
*)
32
*)
33
{$IFDEF UNICODE}
33
{$IFDEF UNICODE}
34
function GetModuleFileNameEx(inProcess: THandle; inModule: THandle; Filename: PWideChar; size: DWord): Integer;
34
function GetModuleFileNameEx(inProcess: THandle; inModule: THandle; Filename: PWideChar; size: DWord): Integer;
35
type
35
type
36
  TGetModuleFileNameExFunc = function (inProcess: THandle; inModule: THandle; Filename: PWideChar; size: DWord): DWord; stdcall;
36
  TGetModuleFileNameExFunc = function (inProcess: THandle; inModule: THandle; Filename: PWideChar; size: DWord): DWord; stdcall;
37
var
37
var
38
  funcGetModuleFileNameEx: TGetModuleFileNameExFunc;
38
  funcGetModuleFileNameEx: TGetModuleFileNameExFunc;
39
begin
39
begin
40
  if hPsApiDll <> 0 then
40
  if hPsApiDll <> 0 then
41
  begin
41
  begin
42
    @funcGetModuleFileNameEx := GetProcAddress(hPsApiDll, 'GetModuleFileNameExW');
42
    @funcGetModuleFileNameEx := GetProcAddress(hPsApiDll, 'GetModuleFileNameExW');
43
    if Assigned(funcGetModuleFileNameEx) then
43
    if Assigned(funcGetModuleFileNameEx) then
44
      result := funcGetModuleFileNameEx(inProcess, inModule, Filename, size)
44
      result := funcGetModuleFileNameEx(inProcess, inModule, Filename, size)
45
    else
45
    else
46
      result := -1;
46
      result := -1;
47
  end
47
  end
48
  else result := -2;
48
  else result := -2;
49
end;
49
end;
50
{$ELSE}
50
{$ELSE}
51
function GetModuleFileNameEx(inProcess: THandle; inModule: THandle; Filename: PAnsiChar; size: DWord): Integer;
51
function GetModuleFileNameEx(inProcess: THandle; inModule: THandle; Filename: PAnsiChar; size: DWord): Integer;
52
type
52
type
53
  TGetModuleFileNameExFunc = function (inProcess: THandle; inModule: THandle; Filename: PAnsiChar; size: DWord): DWord; stdcall;
53
  TGetModuleFileNameExFunc = function (inProcess: THandle; inModule: THandle; Filename: PAnsiChar; size: DWord): DWord; stdcall;
54
var
54
var
55
  funcGetModuleFileNameEx: TGetModuleFileNameExFunc;
55
  funcGetModuleFileNameEx: TGetModuleFileNameExFunc;
56
begin
56
begin
57
  if hPsApiDll <> 0 then
57
  if hPsApiDll <> 0 then
58
  begin
58
  begin
59
    @funcGetModuleFileNameEx := GetProcAddress(hPsApiDll, 'GetModuleFileNameExA');
59
    @funcGetModuleFileNameEx := GetProcAddress(hPsApiDll, 'GetModuleFileNameExA');
60
    if Assigned(funcGetModuleFileNameEx) then
60
    if Assigned(funcGetModuleFileNameEx) then
61
      result := funcGetModuleFileNameEx(inProcess, inModule, Filename, size)
61
      result := funcGetModuleFileNameEx(inProcess, inModule, Filename, size)
62
    else
62
    else
63
      result := -1;
63
      result := -1;
64
  end
64
  end
65
  else result := -2;
65
  else result := -2;
66
end;
66
end;
67
{$ENDIF}
67
{$ENDIF}
68
 
68
 
69
procedure ChangeTitleAndIcon(hWnd: Thandle);
69
procedure ChangeTitleAndIcon(hWnd: Thandle);
70
var
70
var
71
  Title: array[0..255] of Char;
71
  Title: array[0..255] of Char;
72
const
72
const
73
  TargetWinWidth = 640;
73
  TargetWinWidth = 640;
74
  TargetWinHeight = 480;
74
  TargetWinHeight = 480;
75
resourcestring
75
resourcestring
76
  AyDosTitle = 'Aysalia DOS';
76
  AyDosTitle = 'Aysalia DOS';
77
  AyDos1Title = 'Aysalia DOS 1';
77
  AyDos1Title = 'Aysalia DOS 1';
78
  AyDos2Title = 'Aysalia DOS 2';
78
  AyDos2Title = 'Aysalia DOS 2';
79
begin
79
begin
80
  ZeroMemory(@Title, sizeof(Title));
80
  ZeroMemory(@Title, sizeof(Title));
81
  GetWindowText(hWnd, @Title, sizeof(Title)-1);
81
  GetWindowText(hWnd, @Title, sizeof(Title)-1);
82
 
82
 
83
  // Center window (once)
83
  // Center window (once)
84
  if (Title = 'DOSBox') and not bCeneredOnce then
84
  if (Title = 'DOSBox') and not bCeneredOnce then
85
  begin
85
  begin
86
    MoveWindow(hWnd, GetSystemMetrics(SM_CXSCREEN) div 2 - TargetWinWidth div 2,
86
    MoveWindow(hWnd, GetSystemMetrics(SM_CXSCREEN) div 2 - TargetWinWidth div 2,
87
                     GetSystemMetrics(SM_CYSCREEN) div 2 - TargetWinHeight div 2,
87
                     GetSystemMetrics(SM_CYSCREEN) div 2 - TargetWinHeight div 2,
88
                     TargetWinWidth,
88
                     TargetWinWidth,
89
                     TargetWinHeight,
89
                     TargetWinHeight,
90
                     true);
90
                     true);
91
    bCeneredOnce := true;
91
    bCeneredOnce := true;
92
  end;
92
  end;
93
 
93
 
94
  // Change window title
94
  // Change window title
95
  if Pos('AYDOS1', Title) > 0 then
95
  if Pos('AYDOS1', Title) > 0 then
96
    SetWindowText(hWnd, PChar(AyDos1Title))
96
    SetWindowText(hWnd, PChar(AyDos1Title))
97
  else if Pos('AYDOS2', Title) > 0 then
97
  else if Pos('AYDOS2', Title) > 0 then
98
    SetWindowText(hWnd, PChar(AyDos2Title))
98
    SetWindowText(hWnd, PChar(AyDos2Title))
99
  else if Pos('AYDOS', Title) > 0 then
99
  else if Pos('AYDOS', Title) > 0 then
100
    SetWindowText(hWnd, PChar(AyDosTitle));
100
    SetWindowText(hWnd, PChar(AyDosTitle));
101
 
101
 
102
  // Change window and taskbar icon
102
  // Change window and taskbar icon
103
  if hIcon > 0 then
103
  if hIcon > 0 then
104
  begin
104
  begin
105
    // Change both icons to the same icon handle.
105
    // Change both icons to the same icon handle.
106
    SendMessage(hWnd, WM_SETICON, ICON_SMALL, hIcon);
106
    SendMessage(hWnd, WM_SETICON, ICON_SMALL, hIcon);
107
    SendMessage(hWnd, WM_SETICON, ICON_BIG, hIcon);
107
    SendMessage(hWnd, WM_SETICON, ICON_BIG, hIcon);
108
 
108
 
109
    // This will ensure that the application icon gets changed too.
109
    // This will ensure that the application icon gets changed too.
110
    SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_SMALL, hIcon);
110
    SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_SMALL, hIcon);
111
    SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_BIG, hIcon);
111
    SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_BIG, hIcon);
112
  end;
112
  end;
113
end;
113
end;
114
 
114
 
115
function EnumWindowsProc(Handle: hWnd; dummy: DWORD): BOOL; stdcall;
115
function EnumWindowsProc(Handle: hWnd; dummy: DWORD): BOOL; stdcall;
116
var
116
var
117
  Title: array[0..255] of Char;
117
  Title: array[0..255] of Char;
118
  WinFileName: array[0..MAX_PATH] of Char;
118
  WinFileName: array[0..MAX_PATH] of Char;
119
var
119
var
120
  PID: DWORD;
120
  PID: DWORD;
121
  hProcess: THandle;
121
  hProcess: THandle;
122
  Len: Integer;
122
  Len: Integer;
123
begin
123
begin
124
  Result := True;
124
  Result := True;
125
  ZeroMemory(@WinFileName, sizeof(WinFileName));
125
  ZeroMemory(@WinFileName, sizeof(WinFileName));
126
  GetWindowThreadProcessId(Handle, @PID);
126
  GetWindowThreadProcessId(Handle, @PID);
127
  hProcess := OpenProcess(PROCESS_ALL_ACCESS, False, PID);
127
  hProcess := OpenProcess(PROCESS_ALL_ACCESS, False, PID);
128
  Len := GetModuleFileNameEx(hProcess, 0, WinFileName, sizeof(WinFileName)-1);
128
  Len := GetModuleFileNameEx(hProcess, 0, WinFileName, sizeof(WinFileName)-1);
129
  if Len > 0 then
129
  if Len > 0 then
130
  begin
130
  begin
131
    // GetModuleFileNameEx is available on newer operating systems;
131
    // GetModuleFileNameEx is available on newer operating systems;
132
    // it ensures that we find the correct window by checking its EXE filename.
132
    // it ensures that we find the correct window by checking its EXE filename.
133
    if SameText(WinFileName, ExtractFilePath(ParamStr(0)) + DOSBOX_EXE) then
133
    if SameText(WinFileName, ExtractFilePath(ParamStr(0)) + DOSBOX_EXE) then
134
    begin
134
    begin
135
      Result := False; // stop enumeration
135
      Result := False; // stop enumeration
136
      ChangeTitleAndIcon(Handle);
136
      ChangeTitleAndIcon(Handle);
137
    end;
137
    end;
138
  end
138
  end
139
  else if Len < 0 then
139
  else if Len < 0 then
140
  begin
140
  begin
141
    // At Win9x, there is no psapi.dll, so we try it the old fashioned way,
141
    // At Win9x, there is no psapi.dll, so we try it the old fashioned way,
142
    // finding the window by parts of its title
142
    // finding the window by parts of its title
143
    ZeroMemory(@Title, sizeof(Title));
143
    ZeroMemory(@Title, sizeof(Title));
144
    GetWindowText(Handle, Title, sizeof(Title)-1);
144
    GetWindowText(Handle, Title, sizeof(Title)-1);
145
    if IsWindowVisible(Handle) then
145
    if IsWindowVisible(Handle) then
146
    begin
146
    begin
147
      if (title = 'DOSBox') or ((Pos('DOSBox ',   title) > 0) and
147
      if (title = 'DOSBox') or ((Pos('DOSBox ',   title) > 0) and
148
                                (Pos('Cpu speed', title) > 0)) then
148
                                (Pos('Cpu speed', title) > 0)) then
149
      begin
149
      begin
150
        Result := False; // stop enumeration
150
        Result := False; // stop enumeration
151
        ChangeTitleAndIcon(Handle);
151
        ChangeTitleAndIcon(Handle);
152
      end;
152
      end;
153
    end;
153
    end;
154
  end;
154
  end;
155
end;
155
end;
156
 
156
 
157
function ShellExecuteWait(hWnd: HWND; Operation, FileName, Parameters,
157
function ShellExecuteWait(hWnd: HWND; Operation, FileName, Parameters,
158
  Directory: PChar; ShowCmd: Integer): DWord;
158
  Directory: PChar; ShowCmd: Integer; lpEnumFunc: TFNWndEnumProc=nil): DWord;
159
var
159
var
160
  Info: TShellExecuteInfo;
160
  Info: TShellExecuteInfo;
161
  pInfo: PShellExecuteInfo;
161
  pInfo: PShellExecuteInfo;
162
begin
162
begin
163
  pInfo := @Info;
163
  pInfo := @Info;
164
  with Info do
164
  with Info do
165
  begin
165
  begin
166
    cbSize       := SizeOf(Info);
166
    cbSize       := SizeOf(Info);
167
    fMask        := SEE_MASK_NOCLOSEPROCESS;
167
    fMask        := SEE_MASK_NOCLOSEPROCESS;
168
    wnd          := hWnd;
168
    wnd          := hWnd;
169
    lpVerb       := Operation;
169
    lpVerb       := Operation;
170
    lpFile       := FileName;
170
    lpFile       := FileName;
171
    lpParameters := PChar(Parameters + #0);
171
    lpParameters := PChar(Parameters + #0);
172
    lpDirectory  := PChar(Directory);
172
    lpDirectory  := PChar(Directory);
173
    nShow        := ShowCmd;
173
    nShow        := ShowCmd;
174
    hInstApp     := 0;
174
    hInstApp     := 0;
175
  end;
175
  end;
176
  ShellExecuteEx(pInfo);
176
  ShellExecuteEx(pInfo);
177
 
177
 
178
  repeat
178
  repeat
179
    result := WaitForSingleObject(Info.hProcess, 10);
179
    result := WaitForSingleObject(Info.hProcess, 10);
180
    EnumWindows(@EnumWindowsProc, 0);
180
    if Assigned(lpEnumFunc) then EnumWindows(lpEnumFunc, 0);
181
  until (result <> WAIT_TIMEOUT);
181
  until (result <> WAIT_TIMEOUT);
182
end;
182
end;
183
 
183
 
184
function CanRunDosBox: boolean;
184
function CanRunDosBox: boolean;
185
var
185
var
186
  windir: array[0..MAX_PATH] of char;
186
  windir: array[0..MAX_PATH] of char;
187
  osVerInfo: TOSVersionInfo;
187
  osVerInfo: TOSVersionInfo;
188
begin
188
begin
189
  osVerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
189
  osVerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
190
  if GetVersionEx(osVerInfo) then
190
  if GetVersionEx(osVerInfo) then
191
  begin
191
  begin
192
    // DOSBox does not work with Windows 95
192
    // DOSBox does not work with Windows 95
193
    // It works on Windows 98 (but the VC++ Runtime must be installed)
193
    // It works on Windows 98 (but the VC++ Runtime must be installed)
194
    if osVerInfo.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS then
194
    if osVerInfo.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS then
195
    begin
195
    begin
196
      result := (osVerInfo.dwMajorVersion > 4) or
196
      result := (osVerInfo.dwMajorVersion > 4) or
197
               ((osVerInfo.dwMajorVersion = 4) and (osVerInfo.dwMinorVersion >= 10{Win98}));
197
               ((osVerInfo.dwMajorVersion = 4) and (osVerInfo.dwMinorVersion >= 10{Win98}));
198
    end
198
    end
199
    else if osVerInfo.dwPlatformId = VER_PLATFORM_WIN32_NT then
199
    else if osVerInfo.dwPlatformId = VER_PLATFORM_WIN32_NT then
200
    begin
200
    begin
201
      result := true;
201
      result := true;
202
    end
202
    end
203
    else
203
    else
204
    begin
204
    begin
205
      // This should not happen
205
      // This should not happen
206
      result := false;
206
      result := false;
207
    end;
207
    end;
208
  end
208
  end
209
  else
209
  else
210
  begin
210
  begin
211
    if GetWindowsDirectory(windir, sizeof(windir)) > 0 then
211
    if GetWindowsDirectory(windir, sizeof(windir)) > 0 then
212
    begin
212
    begin
213
      // In case GetVersionEx fails, we are trying to see if command.com exists
213
      // In case GetVersionEx fails, we are trying to see if command.com exists
214
      result := FileExists(windir + '\command.com');
214
      result := FileExists(windir + '\command.com');
215
    end
215
    end
216
    else
216
    else
217
    begin
217
    begin
218
      // This should never happen
218
      // This should never happen
219
      result := false;
219
      result := false;
220
    end;
220
    end;
221
  end;
221
  end;
222
end;
222
end;
223
 
223
 
224
function Main: Integer;
224
function Main: Integer;
225
var
225
var
226
  sFile: string;
226
  sFile: string;
227
begin
227
begin
228
  if CanRunDosBox then
228
  if CanRunDosBox then
229
  begin
229
  begin
-
 
230
    hPsApiDll := LoadLibrary('psapi.dll');
-
 
231
    try
-
 
232
      hIcon := LoadIcon(hInstance, 'MainIcon');
-
 
233
      bCeneredOnce := false;
-
 
234
 
230
    ShellExecuteWait(0, 'open', DOSBOX_EXE, '-noconsole -conf DOSBox.conf',
235
      ShellExecuteWait(0, 'open', DOSBOX_EXE, '-noconsole -conf DOSBox.conf',
231
      PChar(ExtractFilePath(ParamStr(0))), SW_NORMAL);
236
        PChar(ExtractFilePath(ParamStr(0))), SW_NORMAL, @EnumWindowsProc);
232
 
237
 
233
    sFile := IncludeTrailingBackslash(ExtractFilePath(ParamStr(0))) + 'stdout.txt';
238
      sFile := IncludeTrailingBackslash(ExtractFilePath(ParamStr(0))) + 'stdout.txt';
234
    if FileExists(sFile) then DeleteFile(PChar(sFile));
239
      if FileExists(sFile) then DeleteFile(PChar(sFile));
235
 
240
 
236
    sFile := IncludeTrailingBackslash(ExtractFilePath(ParamStr(0))) + 'stderr.txt';
241
      sFile := IncludeTrailingBackslash(ExtractFilePath(ParamStr(0))) + 'stderr.txt';
237
    if FileExists(sFile) then DeleteFile(PChar(sFile));
242
      if FileExists(sFile) then DeleteFile(PChar(sFile));
-
 
243
    finally
-
 
244
      FreeLibrary(hPsApiDll);
-
 
245
      hPsApiDll := 0;
-
 
246
    end;
238
  end
247
  end
239
  else
248
  else
240
  begin
249
  begin
241
    // SEE_MASK_CLASSNAME cannot be used with pure MZ files (it does only work for NE/PE files!)
250
    // SEE_MASK_CLASSNAME cannot be used with pure MZ files (it does only work for NE/PE files!)
242
    // So we need to do the dirty rename-hack...
251
    // So we need to do the dirty rename-hack...
243
    RenameFile(AYDOS_MNU, AYDOS_COM);
252
    if FileExists(AYDOS_MNU) and not FileExists(AYDOS_COM) then RenameFile(AYDOS_MNU, AYDOS_COM);
244
    try
253
    try
245
      ShellExecuteWait(0, 'open', PChar(AYDOS_COM), '', PChar(ExtractFilePath(ParamStr(0))), SW_NORMAL);
254
      ShellExecuteWait(0, 'open', PChar(AYDOS_COM), '',
-
 
255
        PChar(ExtractFilePath(ParamStr(0))), SW_NORMAL, nil);
246
    finally
256
    finally
247
      RenameFile(AYDOS_COM, AYDOS_MNU);
257
      if FileExists(AYDOS_COM) and not FileExists(AYDOS_MNU) then RenameFile(AYDOS_COM, AYDOS_MNU);
248
    end;
258
    end;
249
  end;
259
  end;
250
 
260
 
251
  result := 0;
261
  result := 0;
252
end;
262
end;
253
 
263
 
254
begin
264
begin
255
  hPsApiDll := LoadLibrary('psapi.dll');
-
 
256
  try
-
 
257
    hIcon := LoadIcon(hInstance, 'MainIcon');
-
 
258
    ExitCode := Main;
265
  ExitCode := Main;
259
  finally
-
 
260
    FreeLibrary(hPsApiDll);
-
 
261
    hPsApiDll := 0;
-
 
262
  end;
-
 
263
end.
266
end.
264
 
267