2
0

system.pp 11 KB

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