dosbox_wrapper.pas 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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. Process.Execute;
  113. repeat
  114. Inc(Time);
  115. if Time > Timeout then
  116. break;
  117. Sleep(100);
  118. until not Process.Running;
  119. if Process.Running then
  120. Process.Terminate(254);
  121. finally
  122. Process.Free;
  123. end;
  124. end;
  125. procedure Cleanup(const ADosBoxDir: string);
  126. procedure DeleteIfExists(const AFileName: string);
  127. begin
  128. if FileExists(AFileName) then
  129. DeleteFile(AFileName);
  130. end;
  131. begin
  132. DeleteIfExists(ADosBoxDir + 'dosbox.conf');
  133. DeleteIfExists(ADosBoxDir + 'EXITCODE.TXT');
  134. DeleteIfExists(ADosBoxDir + 'EXITCODE.EXE');
  135. DeleteIfExists(ADosBoxDir + 'TEST.EXE');
  136. RmDir(ADosBoxDir);
  137. end;
  138. var
  139. DosBoxDir: string;
  140. ExitCode: Integer = 255;
  141. DosBoxBinaryPath: string;
  142. begin
  143. Randomize;
  144. if ParamCount = 0 then
  145. begin
  146. Writeln('Usage: ' + ParamStr(0) + ' <executable>');
  147. halt(1);
  148. end;
  149. DosBoxBinaryPath := GetEnvironmentVariable('DOSBOX');
  150. if DosBoxBinaryPath = '' then
  151. begin
  152. Writeln('Please set the DOSBOX environment variable to the dosbox executable');
  153. halt(1);
  154. end;
  155. DosBoxDir := GenerateTempDir;
  156. try
  157. GenerateDosBoxConf(DosBoxDir);
  158. CopyFile(ExtractFilePath(ParamStr(0)) + 'exitcode.exe', DosBoxDir + 'EXITCODE.EXE');
  159. CopyFile(ParamStr(1), DosBoxDir + 'TEST.EXE');
  160. ExecuteDosBox(DosBoxBinaryPath, DosBoxDir);
  161. ExitCode := ReadExitCode(DosBoxDir);
  162. finally
  163. Cleanup(DosBoxDir);
  164. end;
  165. halt(ExitCode);
  166. end.