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 |