Subversion Repositories aysalia

Rev

Rev 10 | Rev 19 | 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): DWord;
  31. type
  32.   TGetModuleFileNameExFunc = function (inProcess: THandle; inModule: THandle; Filename: PWideChar; size: DWord): DWord; stdcall;
  33. var
  34.   dllHandle: Cardinal;
  35.   funcGetModuleFileNameEx: TGetModuleFileNameExFunc;
  36. begin
  37.   if psAPIHandle <> 0 then
  38.   begin
  39.     @funcGetModuleFileNameEx := GetProcAddress(psAPIHandle, 'GetModuleFileNameExW') ;
  40.     if Assigned (funcGetModuleFileNameEx) then
  41.       result := funcGetModuleFileNameEx(inProcess, inModule, Filename, size)
  42.     else
  43.       result := 0;
  44.   end
  45.   else result := 0;
  46. end;
  47. {$ELSE}
  48. function GetModuleFileNameEx(inProcess: THandle; inModule: THandle; Filename: PAnsiChar; size: DWord): DWord;
  49. type
  50.   TGetModuleFileNameExFunc = function (inProcess: THandle; inModule: THandle; Filename: PAnsiChar; size: DWord): DWord; stdcall;
  51. var
  52.   funcGetModuleFileNameEx : TGetModuleFileNameExFunc;
  53. begin
  54.   if hPsApiDll <> 0 then
  55.   begin
  56.     @funcGetModuleFileNameEx := GetProcAddress(hPsApiDll, 'GetModuleFileNameExA') ;
  57.     if Assigned (funcGetModuleFileNameEx) then
  58.       result := funcGetModuleFileNameEx(inProcess, inModule, Filename, size)
  59.     else
  60.       result := 0;
  61.   end
  62.   else result := 0;
  63. end;
  64. {$ENDIF}
  65.  
  66. var
  67.   hIcon: THandle = 0;
  68.   bCeneredOnce: boolean = false;
  69.  
  70. procedure ChangeTitleAndIcon(hWnd: Thandle);
  71. var
  72.   Title: array[0..255] of Char;
  73. const
  74.   TargetWinWidth = 640;
  75.   TargetWinHeight = 480;
  76. begin
  77.   ZeroMemory(@Title, sizeof(Title));
  78.   GetWindowText(hWnd, @Title, sizeof(Title)-1);
  79.  
  80.   // Center window (once)
  81.   if (Title = 'DOSBox') and not bCeneredOnce then
  82.   begin
  83.     MoveWindow(hWnd, GetSystemMetrics(SM_CXSCREEN) div 2 - TargetWinWidth div 2,
  84.                      GetSystemMetrics(SM_CYSCREEN) div 2 - TargetWinHeight div 2,
  85.                      TargetWinWidth,
  86.                      TargetWinHeight,
  87.                      true);
  88.     bCeneredOnce := true;
  89.   end;
  90.  
  91.   // Change window title
  92.   if Pos('AYDOS1', Title) > 0 then
  93.     SetWindowText(hWnd, 'Aysalia DOS I')
  94.   else if Pos('AYDOS2', Title) > 0 then
  95.     SetWindowText(hWnd, 'Aysalia DOS II')
  96.   else
  97.     SetWindowText(hWnd, 'Aysalia DOS');
  98.  
  99.   // Change window and taskbar icon
  100.   if hIcon > 0 then
  101.   begin
  102.     // Change both icons to the same icon handle.
  103.     SendMessage(hWnd, WM_SETICON, ICON_SMALL, hIcon);
  104.     SendMessage(hWnd, WM_SETICON, ICON_BIG, hIcon);
  105.  
  106.     // This will ensure that the application icon gets changed too.
  107.     SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_SMALL, hIcon);
  108.     SendMessage(GetWindow(hWnd, GW_OWNER), WM_SETICON, ICON_BIG, hIcon);
  109.   end;
  110. end;
  111.  
  112. function EnumWindowsProc(Handle: hWnd; dummy: DWORD): BOOL; stdcall;
  113. var
  114.   Title: array[0..255] of Char;
  115. const
  116.   C_FileNameLength = 256;
  117. var
  118.   WinFileName: string;
  119.   PID, hProcess: DWORD;
  120.   Len: Byte;
  121. begin
  122.   Result := True;
  123.   SetLength(WinFileName, C_FileNameLength);
  124.   GetWindowThreadProcessId(Handle, PID);
  125.   hProcess := OpenProcess(PROCESS_ALL_ACCESS, False, PID);
  126.   Len := GetModuleFileNameEx(hProcess, 0, PChar(WinFileName), C_FileNameLength);
  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.     SetLength(WinFileName, Len);
  132.     if SameText(WinFileName, ExtractFilePath(ParamStr(0)) + DOSBOX_EXE) then
  133.     begin
  134.       Result := False; // stop enumeration
  135.       ChangeTitleAndIcon(Handle);
  136.     end;
  137.   end
  138.   else
  139.   begin
  140.     // At Win9x, there is no psapi.dll, so we try it the old fashioned way,
  141.     // finding the window by parts of its title
  142.     ZeroMemory(@Title, sizeof(Title));
  143.     GetWindowText(Handle, Title, sizeof(Title)-1);
  144.     if IsWindowVisible(Handle) then
  145.     begin
  146.       if (title = 'DOSBox') or ((Pos('DOSBox ',   title) > 0) and
  147.                                 (Pos('Cpu speed', title) > 0)) then
  148.       begin
  149.         Result := False; // stop enumeration
  150.         ChangeTitleAndIcon(Handle);
  151.       end;
  152.     end;
  153.   end;
  154. end;
  155.  
  156. function ShellExecuteWait(hWnd: HWND; Operation, FileName, Parameters,
  157.   Directory: PAnsiChar; ShowCmd: Integer): DWord;
  158. var
  159.   Info: TShellExecuteInfo;
  160.   pInfo: PShellExecuteInfo;
  161.   exitCode: DWord;
  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.     exitCode := WaitForSingleObject(Info.hProcess, 10);
  180.     EnumWindows(@EnumWindowsProc, 0);
  181.   until (exitCode <> WAIT_TIMEOUT);
  182.  
  183.   result := exitCode;
  184. end;
  185.  
  186. function Main: Integer;
  187. var
  188.   sFile: string;
  189. begin
  190.   ShellExecuteWait(0, 'open', DOSBOX_EXE, '-noconsole -conf DOSBox.conf',
  191.     PChar(ExtractFilePath(ParamStr(0))), SW_NORMAL);
  192.  
  193.   sFile := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + 'stdout.txt';
  194.   if FileExists(sFile) then DeleteFile(PChar(sFile));
  195.  
  196.   sFile := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + 'stderr.txt';
  197.   if FileExists(sFile) then DeleteFile(PChar(sFile));
  198.  
  199.   result := 0;
  200. end;
  201.  
  202. begin
  203.   hPsApiDll := LoadLibrary('psapi.dll') ;
  204.   hIcon := LoadIcon(hInstance, 'MainIcon');
  205.   ExitCode := Main;
  206.   FreeLibrary(hPsApiDll);
  207. end.
  208.