Subversion Repositories aysalia

Rev

Rev 16 | Rev 20 | 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
4
// Revision 2018-12-06
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';
20
 
21
var
22
  hPsApiDll: cardinal;
23
 
24
(*
25
function GetModuleFileNameEx(inProcess: THandle; inModule: THandle;
26
      Filename: PChar; size: DWord): DWord; stdcall;
27
      external 'psapi.dll' name 'GetModuleFileNameExA';
28
*)
29
{$IFDEF UNICODE}
19 daniel-mar 30
function GetModuleFileNameEx(inProcess: THandle; inModule: THandle; Filename: PWideChar; size: DWord): Integer;
16 daniel-mar 31
type
32
  TGetModuleFileNameExFunc = function (inProcess: THandle; inModule: THandle; Filename: PWideChar; size: DWord): DWord; stdcall;
33
var
34
  funcGetModuleFileNameEx: TGetModuleFileNameExFunc;
35
begin
36
  if psAPIHandle <> 0 then
37
  begin
19 daniel-mar 38
    @funcGetModuleFileNameEx := GetProcAddress(psAPIHandle, 'GetModuleFileNameExW');
39
    if Assigned(funcGetModuleFileNameEx) then
16 daniel-mar 40
      result := funcGetModuleFileNameEx(inProcess, inModule, Filename, size)
41
    else
19 daniel-mar 42
      result := -1;
16 daniel-mar 43
  end
19 daniel-mar 44
  else result := -2;
16 daniel-mar 45
end;
46
{$ELSE}
19 daniel-mar 47
function GetModuleFileNameEx(inProcess: THandle; inModule: THandle; Filename: PAnsiChar; size: DWord): Integer;
16 daniel-mar 48
type
49
  TGetModuleFileNameExFunc = function (inProcess: THandle; inModule: THandle; Filename: PAnsiChar; size: DWord): DWord; stdcall;
50
var
19 daniel-mar 51
  funcGetModuleFileNameEx: TGetModuleFileNameExFunc;
16 daniel-mar 52
begin
53
  if hPsApiDll <> 0 then
54
  begin
19 daniel-mar 55
    @funcGetModuleFileNameEx := GetProcAddress(hPsApiDll, 'GetModuleFileNameExA');
56
    if Assigned(funcGetModuleFileNameEx) then
16 daniel-mar 57
      result := funcGetModuleFileNameEx(inProcess, inModule, Filename, size)
58
    else
19 daniel-mar 59
      result := -1;
16 daniel-mar 60
  end
19 daniel-mar 61
  else result := -2;
16 daniel-mar 62
end;
63
{$ENDIF}
64
 
65
var
66
  hIcon: THandle = 0;
67
  bCeneredOnce: boolean = false;
68
 
69
procedure ChangeTitleAndIcon(hWnd: Thandle);
70
var
71
  Title: array[0..255] of Char;
72
const
73
  TargetWinWidth = 640;
74
  TargetWinHeight = 480;
75
begin
76
  ZeroMemory(@Title, sizeof(Title));
77
  GetWindowText(hWnd, @Title, sizeof(Title)-1);
78
 
79
  // Center window (once)
80
  if (Title = 'DOSBox') and not bCeneredOnce then
81
  begin
82
    MoveWindow(hWnd, GetSystemMetrics(SM_CXSCREEN) div 2 - TargetWinWidth div 2,
83
                     GetSystemMetrics(SM_CYSCREEN) div 2 - TargetWinHeight div 2,
84
                     TargetWinWidth,
85
                     TargetWinHeight,
86
                     true);
87
    bCeneredOnce := true;
88
  end;
89
 
90
  // Change window title
91
  if Pos('AYDOS1', Title) > 0 then
92
    SetWindowText(hWnd, 'Aysalia DOS I')
93
  else if Pos('AYDOS2', Title) > 0 then
94
    SetWindowText(hWnd, 'Aysalia DOS II')
95
  else
96
    SetWindowText(hWnd, 'Aysalia DOS');
97
 
98
  // Change window and taskbar icon
99
  if hIcon > 0 then
100
  begin
101
    // Change both icons to the same icon handle.
102
    SendMessage(hWnd, WM_SETICON, ICON_SMALL, hIcon);
103
    SendMessage(hWnd, WM_SETICON, ICON_BIG, hIcon);
104
 
105
    // This will ensure that the application icon gets changed too.
106
    SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_SMALL, hIcon);
107
    SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_BIG, hIcon);
108
  end;
109
end;
110
 
111
function EnumWindowsProc(Handle: hWnd; dummy: DWORD): BOOL; stdcall;
112
var
113
  Title: array[0..255] of Char;
19 daniel-mar 114
  WinFileName: array[0..MAX_PATH] of Char;
16 daniel-mar 115
var
19 daniel-mar 116
  PID: DWORD;
117
  hProcess: THandle;
118
  Len: Integer;
16 daniel-mar 119
begin
120
  Result := True;
19 daniel-mar 121
  ZeroMemory(@WinFileName, sizeof(WinFileName));
122
  GetWindowThreadProcessId(Handle, @PID);
16 daniel-mar 123
  hProcess := OpenProcess(PROCESS_ALL_ACCESS, False, PID);
19 daniel-mar 124
  Len := GetModuleFileNameEx(hProcess, 0, WinFileName, sizeof(WinFileName)-1);
16 daniel-mar 125
  if Len > 0 then
126
  begin
127
    // GetModuleFileNameEx is available on newer operating systems;
128
    // it ensures that we find the correct window by checking its EXE filename.
129
    if SameText(WinFileName, ExtractFilePath(ParamStr(0)) + DOSBOX_EXE) then
130
    begin
131
      Result := False; // stop enumeration
132
      ChangeTitleAndIcon(Handle);
133
    end;
134
  end
19 daniel-mar 135
  else if Len < 0 then
16 daniel-mar 136
  begin
137
    // At Win9x, there is no psapi.dll, so we try it the old fashioned way,
138
    // finding the window by parts of its title
139
    ZeroMemory(@Title, sizeof(Title));
140
    GetWindowText(Handle, Title, sizeof(Title)-1);
141
    if IsWindowVisible(Handle) then
142
    begin
143
      if (title = 'DOSBox') or ((Pos('DOSBox ',   title) > 0) and
144
                                (Pos('Cpu speed', title) > 0)) then
145
      begin
146
        Result := False; // stop enumeration
147
        ChangeTitleAndIcon(Handle);
148
      end;
149
    end;
150
  end;
151
end;
152
 
9 daniel-mar 153
function ShellExecuteWait(hWnd: HWND; Operation, FileName, Parameters,
154
  Directory: PAnsiChar; ShowCmd: Integer): DWord;
155
var
156
  Info: TShellExecuteInfo;
157
  pInfo: PShellExecuteInfo;
158
begin
159
  pInfo := @Info;
160
  with Info do
161
  begin
16 daniel-mar 162
    cbSize       := SizeOf(Info);
163
    fMask        := SEE_MASK_NOCLOSEPROCESS;
164
    wnd          := hWnd;
165
    lpVerb       := Operation;
19 daniel-mar 166
    lpFile       := FileName;
9 daniel-mar 167
    lpParameters := PChar(Parameters + #0);
16 daniel-mar 168
    lpDirectory  := PChar(Directory);
169
    nShow        := ShowCmd;
170
    hInstApp     := 0;
9 daniel-mar 171
  end;
172
  ShellExecuteEx(pInfo);
173
 
174
  repeat
19 daniel-mar 175
    result := WaitForSingleObject(Info.hProcess, 10);
16 daniel-mar 176
    EnumWindows(@EnumWindowsProc, 0);
19 daniel-mar 177
  until (result <> WAIT_TIMEOUT);
9 daniel-mar 178
end;
179
 
16 daniel-mar 180
function Main: Integer;
9 daniel-mar 181
var
182
  sFile: string;
183
begin
16 daniel-mar 184
  ShellExecuteWait(0, 'open', DOSBOX_EXE, '-noconsole -conf DOSBox.conf',
9 daniel-mar 185
    PChar(ExtractFilePath(ParamStr(0))), SW_NORMAL);
186
 
19 daniel-mar 187
  sFile := IncludeTrailingBackSlash(ExtractFilePath(ParamStr(0))) + 'stdout.txt';
9 daniel-mar 188
  if FileExists(sFile) then DeleteFile(PChar(sFile));
189
 
19 daniel-mar 190
  sFile := IncludeTrailingBackSlash(ExtractFilePath(ParamStr(0))) + 'stderr.txt';
9 daniel-mar 191
  if FileExists(sFile) then DeleteFile(PChar(sFile));
16 daniel-mar 192
 
193
  result := 0;
194
end;
195
 
196
begin
19 daniel-mar 197
  hPsApiDll := LoadLibrary('psapi.dll');
198
  try
199
    hIcon := LoadIcon(hInstance, 'MainIcon');
200
    ExitCode := Main;
201
  finally
202
    FreeLibrary(hPsApiDll);
203
  end;
9 daniel-mar 204
end.