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. |