Subversion Repositories aysalia

Rev

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

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