system.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2009 by Sven Barth
  4. FPC Pascal system unit for the WinNT API.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit System;
  12. interface
  13. {$ifdef SYSTEMDEBUG}
  14. {$define SYSTEMEXCEPTIONDEBUG}
  15. {$endif SYSTEMDEBUG}
  16. {$ifdef cpui386}
  17. {$define Set_i386_Exception_handler}
  18. {$endif cpui386}
  19. {$define DISABLE_NO_THREAD_MANAGER}
  20. {$ifdef KMODE}
  21. // in KernelMode we need use a memory manager that just wraps the routines
  22. // provided by the NT Executive and allows to select whether we want to use
  23. // paged or non-paged (use sparely!) memory
  24. {$define HAS_MEMORYMANAGER}
  25. {$endif KMODE}
  26. { include system-independent routine headers }
  27. {$I systemh.inc}
  28. var
  29. CurrentPeb: Pointer;
  30. IsDeviceDriver: Boolean = False;
  31. const
  32. LineEnding = #13#10;
  33. LFNSupport = true;
  34. DirectorySeparator = '\';
  35. DriveSeparator = '\';
  36. ExtensionSeparator = '.';
  37. PathSeparator = ';';
  38. AllowDirectorySeparators : set of char = ['\'];
  39. AllowDriveSeparators : set of char = [];
  40. { FileNameCaseSensitive is defined separately below!!! }
  41. maxExitCode = High(ErrorCode);
  42. MaxPathLen = High(Word);
  43. AllFilesMask = '*';
  44. type
  45. PEXCEPTION_FRAME = ^TEXCEPTION_FRAME;
  46. TEXCEPTION_FRAME = record
  47. next : PEXCEPTION_FRAME;
  48. handler : pointer;
  49. end;
  50. var
  51. { C compatible arguments }
  52. argc: LongWord;
  53. argvw: PPWideChar;
  54. argv: PPChar;
  55. const
  56. { Default filehandles }
  57. UnusedHandle : THandle = 0;
  58. StdInputHandle : THandle = 0;
  59. StdOutputHandle : THandle = 0;
  60. StdErrorHandle : THandle = 0;
  61. {$ifndef kmode}
  62. type
  63. TDLL_Entry_Hook = procedure (dllparam : longint);
  64. const
  65. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  66. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  67. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  68. {$endif}
  69. const
  70. // NT is case sensitive
  71. FileNameCaseSensitive : boolean = true;
  72. // todo: check whether this is really the case on NT
  73. CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
  74. sLineBreak = LineEnding;
  75. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  76. System_exception_frame : PEXCEPTION_FRAME =nil;
  77. implementation
  78. { include system independent routines }
  79. {$I system.inc}
  80. function fpc_pwidechar_length(p: PWideChar): SizeInt; external name 'FPC_PWIDECHAR_LENGTH';
  81. { based on setup_arguments from Win32 RTL }
  82. procedure setup_arguments;
  83. var
  84. i,len,
  85. arglen,
  86. count : longint;
  87. argstart,
  88. pc,arg : pwidechar;
  89. pc2 : pchar;
  90. quote : Boolean;
  91. argvlen : longint;
  92. params : PRTLUserProcessParameters;
  93. procedure allocarg(idx,len:longint);
  94. var
  95. oldargvlen : longint;
  96. begin
  97. if idx>=argvlen then
  98. begin
  99. oldargvlen:=argvlen;
  100. argvlen:=(idx+8) and (not 7);
  101. sysreallocmem(argvw,argvlen*sizeof(pointer));
  102. fillchar(argvw[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);
  103. end;
  104. { use realloc to reuse already existing memory }
  105. { always allocate, even if length is zero, since }
  106. { the arg. is still present! }
  107. sysreallocmem(argvw[idx],len*sizeof(widechar)+2);
  108. end;
  109. begin
  110. { create commandline, it starts with the executed filename which is argvw[0] }
  111. { NativeNT passes inside the PEB which is passed on startup }
  112. argvw:=nil;
  113. argv:=nil;
  114. argvlen:=0;
  115. params:=PSimplePEB(CurrentPEB)^.ProcessParameters;
  116. ArgLen:=params^.ImagePathName.Length + 1;
  117. allocarg(0,arglen);
  118. move(params^.ImagePathName.Buffer^,argvw[0]^,arglen*sizeof(widechar)+1);
  119. { Setup cmdline variable }
  120. { cmdline is a PChar, but NT uses PWideChar... don't set cmdline for now }
  121. {$message warning 'cmdline is not set'}
  122. // cmdline:=GetCommandLine;
  123. { the first argument isn't the image file name, so start at 1 }
  124. count:=1;
  125. { process arguments }
  126. pc:=params^.CommandLine.Buffer;
  127. while pc^<>#0 do
  128. begin
  129. { skip leading spaces }
  130. while (Ord(pc^) >= 1) and (Ord(pc^) <= 32) {pc^ in [#1..#32]} do
  131. inc(pc);
  132. if pc^=#0 then
  133. break;
  134. { calc argument length }
  135. quote:=False;
  136. argstart:=pc;
  137. arglen:=0;
  138. while pc^<>#0 do
  139. begin
  140. case pc^ of
  141. #1..#32 :
  142. begin
  143. if quote then
  144. inc(arglen)
  145. else
  146. break;
  147. end;
  148. '"' :
  149. if pc[1]<>'"' then
  150. quote := not quote
  151. else
  152. inc(pc);
  153. else
  154. inc(arglen);
  155. end;
  156. inc(pc);
  157. end;
  158. { copy argument }
  159. { Don't copy the first one, it is already there.}
  160. If Count<>0 then
  161. begin
  162. allocarg(count,arglen);
  163. quote:=False;
  164. pc:=argstart;
  165. arg:=argvw[count];
  166. while (pc^<>#0) do
  167. begin
  168. case pc^ of
  169. #1..#32 :
  170. begin
  171. if quote then
  172. begin
  173. arg^:=pc^;
  174. inc(arg);
  175. end
  176. else
  177. break;
  178. end;
  179. '"' :
  180. if pc[1]<>'"' then
  181. quote := not quote
  182. else
  183. inc(pc);
  184. else
  185. begin
  186. arg^:=pc^;
  187. inc(arg);
  188. end;
  189. end;
  190. inc(pc);
  191. end;
  192. arg^:=#0;
  193. end;
  194. inc(count);
  195. end;
  196. { get argc }
  197. argc:=count;
  198. { free unused memory, leaving a nil entry at the end }
  199. sysreallocmem(argvw,(count+1)*sizeof(pointer));
  200. argvw[count] := nil;
  201. { now we need to fill argv with UTF8 encoded arguments }
  202. sysreallocmem(argv,(count+1)*sizeof(pointer));
  203. fillchar(argv^,(count+1)*sizeof(pointer),0);
  204. for i := 0 to count - 1 do begin
  205. len := fpc_pwidechar_length(argvw[i]);
  206. pc := argvw[i];
  207. argv[i]:=nil;
  208. sysreallocmem(argv[i],len+1);
  209. pc2 := argv[i];
  210. {$message warning 'Use UnicodeToUTF8 for argument conversion'}
  211. while Ord(pc^) > 0 do begin
  212. if word(pc^) < 127 then
  213. pc2^ := Char(word(pc^))
  214. else
  215. pc2^ := '?';
  216. Inc(pc);
  217. Inc(pc2);
  218. end;
  219. pc2^ := #0;
  220. end;
  221. end;
  222. function paramcount : longint;
  223. begin
  224. paramcount := argc - 1;
  225. end;
  226. function paramstr(l : longint) : string;
  227. begin
  228. if (l>=0) and (l<argc) then
  229. paramstr:=strpas(argv[l])
  230. else
  231. paramstr:='';
  232. end;
  233. procedure KeQueryTickCount(TickCount: PLargeInteger); stdcall; external ntdll name 'KeQueryTickCount';
  234. procedure randomize;
  235. var
  236. tc: PLargeInteger;
  237. begin
  238. FillChar(tc, SizeOf(TLargeInteger), 0);
  239. KeQueryTickCount(@tc);
  240. // the lower part should differ most on system startup
  241. randseed := tc^.LowPart;
  242. end;
  243. {*****************************************************************************
  244. System Dependent Exit code
  245. *****************************************************************************}
  246. procedure PascalMain;stdcall;external name 'PASCALMAIN';
  247. {$ifndef KMODE}
  248. function NtTerminateProcess(aProcess: THandle; aStatus: LongInt): LongInt; stdcall; external ntdll name 'NtTerminateProcess';
  249. {$endif KMODE}
  250. Procedure system_exit;
  251. begin
  252. if IsLibrary or IsDeviceDriver then
  253. Exit;
  254. {$ifndef KMODE}
  255. NtTerminateProcess(THandle(-1), ExitCode);
  256. {$endif KMODE}
  257. end;
  258. {$ifdef kmode}
  259. function FPCDriverStartup(aDriverObject: Pointer; aRegistryPath: Pointer): LongInt; [public, alias: 'FPC_DriverStartup'];
  260. begin
  261. IsDeviceDriver := True;
  262. IsConsole := True;
  263. IsLibrary := True;
  264. SysDriverObject := aDriverObject;
  265. SysRegistryPath := aRegistryPath;
  266. PASCALMAIN;
  267. SysDriverObject := Nil;
  268. SysRegistryPath := Nil;
  269. Result := ExitCode;
  270. end;
  271. {$else}
  272. const
  273. DLL_PROCESS_ATTACH = 1;
  274. DLL_THREAD_ATTACH = 2;
  275. DLL_PROCESS_DETACH = 0;
  276. DLL_THREAD_DETACH = 3;
  277. function FPCDLLEntry(aHInstance: Pointer; aDLLReason: LongInt; aDLLParam: LongInt): LongBool; [public, alias: 'FPC_DLLEntry'];
  278. begin
  279. IsLibrary := True;
  280. FPCDLLEntry := True;
  281. case aDLLReason of
  282. DLL_PROCESS_ATTACH: begin
  283. PascalMain;
  284. FPCDLLEntry := ExitCode = 0;
  285. end;
  286. DLL_THREAD_ATTACH: begin
  287. if Dll_Thread_Attach_Hook <> Nil then
  288. Dll_Thread_Attach_Hook(aDllParam);
  289. end;
  290. DLL_THREAD_DETACH: begin
  291. if Dll_Thread_Detach_Hook <> Nil then
  292. Dll_Thread_Detach_Hook(aDllParam);
  293. end;
  294. DLL_PROCESS_DETACH: begin
  295. if Dll_Process_Detach_Hook <> Nil then
  296. Dll_Process_Detach_Hook(aDllParam);
  297. // finalize units
  298. do_exit;
  299. end;
  300. end;
  301. end;
  302. procedure FPCProcessStartup(aArgument: Pointer);[public, alias: 'FPC_ProcessStartup'];
  303. begin
  304. IsConsole := True;
  305. IsLibrary := False;
  306. CurrentPeb := aArgument;
  307. PASCALMAIN;
  308. system_exit;
  309. end;
  310. {$endif}
  311. {$ifdef kmode}
  312. // Kernel Mode Entry Point
  313. function NtDriverEntry( aDriverObject: Pointer; aRegistryPath: Pointer ): LongInt; stdcall; [public, alias: '_NtDriverEntry'];
  314. begin
  315. NtDriverEntry := FPCDriverStartup(aDriverObject, aRegistryPath);
  316. end;
  317. {$else}
  318. // User Mode Entry Points
  319. procedure NtProcessStartup( aArgument: Pointer ); stdcall; [public, alias: '_NtProcessStartup'];
  320. begin
  321. FPCProcessStartup(aArgument);
  322. end;
  323. function DLLMainStartup( aHInstance: Pointer; aDLLReason, aDLLParam: LongInt ): LongBool; stdcall; [public, alias: '_DLLMainStartup'];
  324. begin
  325. DLLMainStartup := FPCDLLEntry(aHInstance, aDLLReason, aDLLParam);
  326. end;
  327. {$endif}
  328. {$ifndef kmode}
  329. // other user mode only stuff
  330. procedure SysInitStdIO;
  331. begin
  332. with PSimplePEB(CurrentPEB)^.ProcessParameters^ do begin
  333. StdInputHandle := StandardInput;
  334. StdOutputHandle := StandardOutput;
  335. StdErrorHandle := StandardError;
  336. end;
  337. if StdInputHandle <> 0 then
  338. OpenStdIO(Input, fmInput, StdInputHandle)
  339. else
  340. Assign(Input, '');
  341. if StdOutputHandle <> 0 then begin
  342. OpenStdIO(Output, fmOutput, StdOutputHandle);
  343. OpenStdIO(StdOut, fmOutput, StdOutputHandle);
  344. end else begin
  345. Assign(Output, '');
  346. Assign(StdOut, '');
  347. end;
  348. if StdErrorHandle <> 0 then begin
  349. OpenStdIO(ErrOutput, fmOutput, StdErrorHandle);
  350. OpenStdIO(StdErr, fmOutput, StdErrorHandle);
  351. end else begin
  352. Assign(ErrOutput, '');
  353. Assign(StdErr, '');
  354. end;
  355. end;
  356. {$else}
  357. // other kernel mode only stuff
  358. {$endif}
  359. function GetProcessID: SizeUInt;
  360. begin
  361. {$ifdef kmode}
  362. // it might be that we can detect the user process that called us,
  363. // but that needs to be checked... so for now just return 0
  364. Result := 0;
  365. {$else}
  366. Result := NtCurrentTEB^.ClientID.UniqueProcess;
  367. {$endif}
  368. end;
  369. begin
  370. {$if not defined(KMODE) and not defined(HAS_MEMORYMANAGER)}
  371. { Setup heap }
  372. InitHeap;
  373. {$endif ndef KMODE and ndef HAS_MEMORYMANAGER}
  374. SysInitExceptions;
  375. initvariantmanager;
  376. {$ifndef KMODE}
  377. SysInitStdIO;
  378. { Arguments }
  379. setup_arguments;
  380. {$endif}
  381. InOutRes := 0;
  382. InitSystemThreads;
  383. errno := 0;
  384. { we do not use winlike widestrings and also the RTL can't be compiled with
  385. 2.2, so we can savely use the UnicodeString manager only. }
  386. initunicodestringmanager;
  387. end.