dosbox_wrapper.pas 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. {$MODE objfpc}{$H+}
  2. uses
  3. SysUtils, StrUtils, Process;
  4. function GenerateTempDir: string;
  5. var
  6. FileName: string;
  7. TempDir: string;
  8. Done: Boolean = False;
  9. begin
  10. TempDir := GetTempDir(False);
  11. repeat
  12. try
  13. FileName := TempDir + 'dosboxwrappertmp_' + IntToStr(Random(100000));
  14. MkDir(FileName);
  15. Done := True;
  16. except
  17. on E: EInOutError do
  18. begin
  19. { 5 = Access Denied, returned when a file is duplicated }
  20. if E.ErrorCode <> 5 then
  21. raise;
  22. end;
  23. end;
  24. until Done;
  25. Result := FileName + DirectorySeparator;
  26. end;
  27. procedure GenerateDosBoxConf(const ADosBoxDir: string);
  28. var
  29. SourceConfFileName, TargetConfFileName: string;
  30. SourceFile, TargetFile: TextFile;
  31. S: string;
  32. begin
  33. SourceConfFileName := ExtractFilePath(ParamStr(0)) + 'dosbox.conf';
  34. TargetConfFileName := ADosBoxDir + 'dosbox.conf';
  35. AssignFile(SourceFile, SourceConfFileName);
  36. AssignFile(TargetFile, TargetConfFileName);
  37. Reset(SourceFile);
  38. try
  39. Rewrite(TargetFile);
  40. try
  41. while not EoF(SourceFile) do
  42. begin
  43. Readln(SourceFile, S);
  44. S := AnsiReplaceStr(S, '$DosBoxDir', ADosBoxDir);
  45. Writeln(TargetFile, S);
  46. end;
  47. finally
  48. CloseFile(TargetFile);
  49. end;
  50. finally
  51. CloseFile(SourceFile);
  52. end;
  53. end;
  54. procedure CopyFile(ASrcFileName, ADestFileName: string);
  55. var
  56. SrcF, DestF: File;
  57. OldFileMode: Integer;
  58. Buf: array [0..4095] of Byte;
  59. BytesRead: Integer;
  60. begin
  61. Writeln('CopyFile ', ASrcFileName, '->', ADestFileName);
  62. if not AnsiEndsText('.exe', ASrcFileName) then
  63. ASrcFileName := ASrcFileName + '.exe';
  64. OldFileMode := FileMode;
  65. try
  66. AssignFile(SrcF, ASrcFileName);
  67. AssignFile(DestF, ADestFileName);
  68. FileMode := fmOpenRead;
  69. Reset(SrcF, 1);
  70. try
  71. FileMode := fmOpenWrite;
  72. try
  73. Rewrite(DestF, 1);
  74. repeat
  75. BlockRead(SrcF, Buf, SizeOf(Buf), BytesRead);
  76. BlockWrite(DestF, Buf, BytesRead);
  77. until BytesRead < SizeOf(Buf);
  78. finally
  79. CloseFile(DestF);
  80. end;
  81. finally
  82. CloseFile(SrcF);
  83. end;
  84. finally
  85. FileMode := OldFileMode;
  86. end;
  87. end;
  88. function ReadExitCode(const ADosBoxDir: string): Integer;
  89. var
  90. F: TextFile;
  91. begin
  92. AssignFile(F, ADosBoxDir + 'EXITCODE.TXT');
  93. Reset(F);
  94. try
  95. Readln(F, Result);
  96. finally
  97. CloseFile(F);
  98. end;
  99. end;
  100. procedure ExecuteDosBox(const ADosBoxBinaryPath, ADosBoxDir: string);
  101. const
  102. Timeout = 10*15; { 15 seconds }
  103. var
  104. Process: TProcess;
  105. Time: Integer = 0;
  106. begin
  107. Process := TProcess.Create(nil);
  108. try
  109. Process.Executable := ADosBoxBinaryPath;
  110. Process.Parameters.Add('-conf');
  111. Process.Parameters.Add(ADosBoxDir + 'dosbox.conf');
  112. {$ifdef MSWINDOWS}
  113. Process.ShowWindow := swoHIDE;
  114. {$endif MSWINDOWS}
  115. Process.Execute;
  116. repeat
  117. Inc(Time);
  118. if Time > Timeout then
  119. break;
  120. Sleep(100);
  121. until not Process.Running;
  122. if Process.Running then
  123. Process.Terminate(254);
  124. finally
  125. Process.Free;
  126. end;
  127. end;
  128. procedure Cleanup(const ADosBoxDir: string);
  129. procedure DeleteIfExists(const AFileName: string);
  130. begin
  131. if FileExists(AFileName) then
  132. DeleteFile(AFileName);
  133. end;
  134. begin
  135. DeleteIfExists(ADosBoxDir + 'dosbox.conf');
  136. DeleteIfExists(ADosBoxDir + 'EXITCODE.TXT');
  137. DeleteIfExists(ADosBoxDir + 'EXITCODE.EXE');
  138. DeleteIfExists(ADosBoxDir + 'TEST.EXE');
  139. RmDir(ADosBoxDir);
  140. end;
  141. var
  142. DosBoxDir: string;
  143. ExitCode: Integer = 255;
  144. DosBoxBinaryPath: string;
  145. begin
  146. Randomize;
  147. if ParamCount = 0 then
  148. begin
  149. Writeln('Usage: ' + ParamStr(0) + ' <executable>');
  150. halt(1);
  151. end;
  152. DosBoxBinaryPath := GetEnvironmentVariable('DOSBOX');
  153. if DosBoxBinaryPath = '' then
  154. begin
  155. Writeln('Please set the DOSBOX environment variable to the dosbox executable');
  156. halt(1);
  157. end;
  158. DosBoxDir := GenerateTempDir;
  159. try
  160. GenerateDosBoxConf(DosBoxDir);
  161. CopyFile(ExtractFilePath(ParamStr(0)) + 'exitcode.exe', DosBoxDir + 'EXITCODE.EXE');
  162. CopyFile(ParamStr(1), DosBoxDir + 'TEST.EXE');
  163. ExecuteDosBox(DosBoxBinaryPath, DosBoxDir);
  164. ExitCode := ReadExitCode(DosBoxDir);
  165. finally
  166. Cleanup(DosBoxDir);
  167. end;
  168. halt(ExitCode);
  169. end.