Subversion Repositories aysalia

Rev

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