Subversion Repositories aysalia

Rev

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