Subversion Repositories aysalia

Rev

Rev 16 | Rev 20 | 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 psAPIHandle <> 0 then
  37.   begin
  38.     @funcGetModuleFileNameEx := GetProcAddress(psAPIHandle, '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. 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;
  114.   WinFileName: array[0..MAX_PATH] of Char;
  115. var
  116.   PID: DWORD;
  117.   hProcess: THandle;
  118.   Len: Integer;
  119. begin
  120.   Result := True;
  121.   ZeroMemory(@WinFileName, sizeof(WinFileName));
  122.   GetWindowThreadProcessId(Handle, @PID);
  123.   hProcess := OpenProcess(PROCESS_ALL_ACCESS, False, PID);
  124.   Len := GetModuleFileNameEx(hProcess, 0, WinFileName, sizeof(WinFileName)-1);
  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
  135.   else if Len < 0 then
  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.  
  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
  162.     cbSize       := SizeOf(Info);
  163.     fMask        := SEE_MASK_NOCLOSEPROCESS;
  164.     wnd          := hWnd;
  165.     lpVerb       := Operation;
  166.     lpFile       := FileName;
  167.     lpParameters := PChar(Parameters + #0);
  168.     lpDirectory  := PChar(Directory);
  169.     nShow        := ShowCmd;
  170.     hInstApp     := 0;
  171.   end;
  172.   ShellExecuteEx(pInfo);
  173.  
  174.   repeat
  175.     result := WaitForSingleObject(Info.hProcess, 10);
  176.     EnumWindows(@EnumWindowsProc, 0);
  177.   until (result <> WAIT_TIMEOUT);
  178. end;
  179.  
  180. function Main: Integer;
  181. var
  182.   sFile: string;
  183. begin
  184.   ShellExecuteWait(0, 'open', DOSBOX_EXE, '-noconsole -conf DOSBox.conf',
  185.     PChar(ExtractFilePath(ParamStr(0))), SW_NORMAL);
  186.  
  187.   sFile := IncludeTrailingBackSlash(ExtractFilePath(ParamStr(0))) + 'stdout.txt';
  188.   if FileExists(sFile) then DeleteFile(PChar(sFile));
  189.  
  190.   sFile := IncludeTrailingBackSlash(ExtractFilePath(ParamStr(0))) + 'stderr.txt';
  191.   if FileExists(sFile) then DeleteFile(PChar(sFile));
  192.  
  193.   result := 0;
  194. end;
  195.  
  196. begin
  197.   hPsApiDll := LoadLibrary('psapi.dll');
  198.   try
  199.     hIcon := LoadIcon(hInstance, 'MainIcon');
  200.     ExitCode := Main;
  201.   finally
  202.     FreeLibrary(hPsApiDll);
  203.   end;
  204. end.
  205.