Subversion Repositories aysalia

Rev

Rev 26 | Rev 28 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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