system.pp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Florian Klaempfl and Pavel Ozerski
  5. member of the Free Pascal development team.
  6. FPC Pascal system unit for the Win32 API.
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. {$ifndef VER1_0}
  14. { $define MT}
  15. {$endif VER1_0}
  16. unit {$ifdef VER1_0}SysWin32{$else}System{$endif};
  17. interface
  18. {$ifdef SYSTEMDEBUG}
  19. {$define SYSTEMEXCEPTIONDEBUG}
  20. {$endif SYSTEMDEBUG}
  21. {$ifdef cpui386}
  22. {$define Set_i386_Exception_handler}
  23. {$endif cpui386}
  24. { Ctrl-Z means EOF }
  25. {$DEFINE EOF_CTRLZ}
  26. { include system-independent routine headers }
  27. {$I systemh.inc}
  28. const
  29. LineEnding = #13#10;
  30. LFNSupport = true;
  31. DirectorySeparator = '\';
  32. DriveSeparator = ':';
  33. PathSeparator = ';';
  34. { FileNameCaseSensitive is defined separately below!!! }
  35. maxExitCode = 65535;
  36. type
  37. PEXCEPTION_FRAME = ^TEXCEPTION_FRAME;
  38. TEXCEPTION_FRAME = record
  39. next : PEXCEPTION_FRAME;
  40. handler : pointer;
  41. end;
  42. const
  43. { Default filehandles }
  44. UnusedHandle : THandle = -1;
  45. StdInputHandle : THandle = 0;
  46. StdOutputHandle : THandle = 0;
  47. StdErrorHandle : THandle = 0;
  48. FileNameCaseSensitive : boolean = true;
  49. sLineBreak = LineEnding;
  50. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  51. { Thread count for DLL }
  52. Thread_count : longint = 0;
  53. System_exception_frame : PEXCEPTION_FRAME =nil;
  54. type
  55. TStartupInfo=packed record
  56. cb : longint;
  57. lpReserved : Pointer;
  58. lpDesktop : Pointer;
  59. lpTitle : Pointer;
  60. dwX : longint;
  61. dwY : longint;
  62. dwXSize : longint;
  63. dwYSize : longint;
  64. dwXCountChars : longint;
  65. dwYCountChars : longint;
  66. dwFillAttribute : longint;
  67. dwFlags : longint;
  68. wShowWindow : Word;
  69. cbReserved2 : Word;
  70. lpReserved2 : Pointer;
  71. hStdInput : longint;
  72. hStdOutput : longint;
  73. hStdError : longint;
  74. end;
  75. var
  76. { C compatible arguments }
  77. argc : longint;
  78. argv : ppchar;
  79. { Win32 Info }
  80. startupinfo : tstartupinfo;
  81. hprevinst,
  82. HInstance,
  83. MainInstance,
  84. cmdshow : longint;
  85. DLLreason,DLLparam:longint;
  86. Win32StackTop : Dword;
  87. type
  88. TDLL_Process_Entry_Hook = function (dllparam : longint) : longbool;
  89. TDLL_Entry_Hook = procedure (dllparam : longint);
  90. const
  91. Dll_Process_Attach_Hook : TDLL_Process_Entry_Hook = nil;
  92. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  93. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  94. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  95. type
  96. HMODULE = THandle;
  97. implementation
  98. { include system independent routines }
  99. {$I system.inc}
  100. {*****************************************************************************
  101. Parameter Handling
  102. *****************************************************************************}
  103. var
  104. ModuleName : array[0..255] of char;
  105. function GetCommandFile:pchar;
  106. begin
  107. GetModuleFileName(0,@ModuleName,255);
  108. GetCommandFile:=@ModuleName;
  109. end;
  110. procedure setup_arguments;
  111. var
  112. arglen,
  113. count : longint;
  114. argstart,
  115. pc,arg : pchar;
  116. quote : char;
  117. argvlen : longint;
  118. procedure allocarg(idx,len:longint);
  119. var
  120. oldargvlen : longint;
  121. begin
  122. if idx>=argvlen then
  123. begin
  124. oldargvlen:=argvlen;
  125. argvlen:=(idx+8) and (not 7);
  126. sysreallocmem(argv,argvlen*sizeof(pointer));
  127. fillchar(argv[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);
  128. end;
  129. { use realloc to reuse already existing memory }
  130. { always allocate, even if length is zero, since }
  131. { the arg. is still present! }
  132. sysreallocmem(argv[idx],len+1);
  133. end;
  134. begin
  135. { create commandline, it starts with the executed filename which is argv[0] }
  136. { Win32 passes the command NOT via the args, but via getmodulefilename}
  137. count:=0;
  138. argv:=nil;
  139. argvlen:=0;
  140. pc:=getcommandfile;
  141. Arglen:=0;
  142. repeat
  143. Inc(Arglen);
  144. until (pc[Arglen]=#0);
  145. allocarg(count,arglen);
  146. move(pc^,argv[count]^,arglen);
  147. { Setup cmdline variable }
  148. cmdline:=GetCommandLine;
  149. { process arguments }
  150. pc:=cmdline;
  151. {$IfDef SYSTEM_DEBUG_STARTUP}
  152. Writeln(stderr,'Win32 GetCommandLine is #',pc,'#');
  153. {$EndIf }
  154. while pc^<>#0 do
  155. begin
  156. { skip leading spaces }
  157. while pc^ in [#1..#32] do
  158. inc(pc);
  159. if pc^=#0 then
  160. break;
  161. { calc argument length }
  162. quote:=' ';
  163. argstart:=pc;
  164. arglen:=0;
  165. while (pc^<>#0) do
  166. begin
  167. case pc^ of
  168. #1..#32 :
  169. begin
  170. if quote<>' ' then
  171. inc(arglen)
  172. else
  173. break;
  174. end;
  175. '"' :
  176. begin
  177. if quote<>'''' then
  178. begin
  179. if pchar(pc+1)^<>'"' then
  180. begin
  181. if quote='"' then
  182. quote:=' '
  183. else
  184. quote:='"';
  185. end
  186. else
  187. inc(pc);
  188. end
  189. else
  190. inc(arglen);
  191. end;
  192. '''' :
  193. begin
  194. if quote<>'"' then
  195. begin
  196. if pchar(pc+1)^<>'''' then
  197. begin
  198. if quote='''' then
  199. quote:=' '
  200. else
  201. quote:='''';
  202. end
  203. else
  204. inc(pc);
  205. end
  206. else
  207. inc(arglen);
  208. end;
  209. else
  210. inc(arglen);
  211. end;
  212. inc(pc);
  213. end;
  214. { copy argument }
  215. { Don't copy the first one, it is already there.}
  216. If Count<>0 then
  217. begin
  218. allocarg(count,arglen);
  219. quote:=' ';
  220. pc:=argstart;
  221. arg:=argv[count];
  222. while (pc^<>#0) do
  223. begin
  224. case pc^ of
  225. #1..#32 :
  226. begin
  227. if quote<>' ' then
  228. begin
  229. arg^:=pc^;
  230. inc(arg);
  231. end
  232. else
  233. break;
  234. end;
  235. '"' :
  236. begin
  237. if quote<>'''' then
  238. begin
  239. if pchar(pc+1)^<>'"' then
  240. begin
  241. if quote='"' then
  242. quote:=' '
  243. else
  244. quote:='"';
  245. end
  246. else
  247. inc(pc);
  248. end
  249. else
  250. begin
  251. arg^:=pc^;
  252. inc(arg);
  253. end;
  254. end;
  255. '''' :
  256. begin
  257. if quote<>'"' then
  258. begin
  259. if pchar(pc+1)^<>'''' then
  260. begin
  261. if quote='''' then
  262. quote:=' '
  263. else
  264. quote:='''';
  265. end
  266. else
  267. inc(pc);
  268. end
  269. else
  270. begin
  271. arg^:=pc^;
  272. inc(arg);
  273. end;
  274. end;
  275. else
  276. begin
  277. arg^:=pc^;
  278. inc(arg);
  279. end;
  280. end;
  281. inc(pc);
  282. end;
  283. arg^:=#0;
  284. end;
  285. {$IfDef SYSTEM_DEBUG_STARTUP}
  286. Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
  287. {$EndIf SYSTEM_DEBUG_STARTUP}
  288. inc(count);
  289. end;
  290. { get argc and create an nil entry }
  291. argc:=count;
  292. allocarg(argc,0);
  293. { free unused memory }
  294. sysreallocmem(argv,(argc+1)*sizeof(pointer));
  295. end;
  296. function paramcount : longint;
  297. begin
  298. paramcount := argc - 1;
  299. end;
  300. function paramstr(l : longint) : string;
  301. begin
  302. if (l>=0) and (l<argc) then
  303. paramstr:=strpas(argv[l])
  304. else
  305. paramstr:='';
  306. end;
  307. procedure randomize;
  308. begin
  309. randseed:=GetTickCount;
  310. end;
  311. {*****************************************************************************
  312. System Dependent Exit code
  313. *****************************************************************************}
  314. procedure install_exception_handlers;forward;
  315. procedure remove_exception_handlers;forward;
  316. procedure PascalMain;stdcall;external name 'PASCALMAIN';
  317. procedure fpc_do_exit;stdcall;external name 'FPC_DO_EXIT';
  318. Procedure ExitDLL(Exitcode : longint); forward;
  319. procedure asm_exit(Exitcode : longint);external name 'asm_exit';
  320. Procedure system_exit;
  321. begin
  322. { don't call ExitProcess inside
  323. the DLL exit code !!
  324. This crashes Win95 at least PM }
  325. if IsLibrary then
  326. ExitDLL(ExitCode);
  327. if not IsConsole then
  328. begin
  329. Close(stderr);
  330. Close(stdout);
  331. { what about Input and Output ?? PM }
  332. end;
  333. remove_exception_handlers;
  334. { call exitprocess, with cleanup as required }
  335. asm_exit(exitcode);
  336. end;
  337. var
  338. { value of the stack segment
  339. to check if the call stack can be written on exceptions }
  340. _SS : Cardinal;
  341. procedure Exe_entry;[public, alias : '_FPC_EXE_Entry'];
  342. begin
  343. IsLibrary:=false;
  344. { install the handlers for exe only ?
  345. or should we install them for DLL also ? (PM) }
  346. install_exception_handlers;
  347. { This strange construction is needed to solve the _SS problem
  348. with a smartlinked syswin32 (PFV) }
  349. asm
  350. { allocate space for an exception frame }
  351. pushl $0
  352. pushl %fs:(0)
  353. { movl %esp,%fs:(0)
  354. but don't insert it as it doesn't
  355. point to anything yet
  356. this will be used in signals unit }
  357. movl %esp,%eax
  358. movl %eax,System_exception_frame
  359. pushl %ebp
  360. xorl %ebp,%ebp
  361. movl %esp,%eax
  362. movl %eax,Win32StackTop
  363. movw %ss,%bp
  364. movl %ebp,_SS
  365. call SysResetFPU
  366. xorl %ebp,%ebp
  367. call PASCALMAIN
  368. popl %ebp
  369. end;
  370. { if we pass here there was no error ! }
  371. system_exit;
  372. end;
  373. Const
  374. { DllEntryPoint }
  375. DLL_PROCESS_ATTACH = 1;
  376. DLL_THREAD_ATTACH = 2;
  377. DLL_PROCESS_DETACH = 0;
  378. DLL_THREAD_DETACH = 3;
  379. Var
  380. DLLBuf : Jmp_buf;
  381. Const
  382. DLLExitOK : boolean = true;
  383. function Dll_entry : longbool;[public, alias : '_FPC_DLL_Entry'];
  384. var
  385. res : longbool;
  386. begin
  387. IsLibrary:=true;
  388. Dll_entry:=false;
  389. case DLLreason of
  390. DLL_PROCESS_ATTACH :
  391. begin
  392. If SetJmp(DLLBuf) = 0 then
  393. begin
  394. if assigned(Dll_Process_Attach_Hook) then
  395. begin
  396. res:=Dll_Process_Attach_Hook(DllParam);
  397. if not res then
  398. exit(false);
  399. end;
  400. PASCALMAIN;
  401. Dll_entry:=true;
  402. end
  403. else
  404. Dll_entry:=DLLExitOK;
  405. end;
  406. DLL_THREAD_ATTACH :
  407. begin
  408. inc(Thread_count);
  409. {$warning Allocate Threadvars !}
  410. if assigned(Dll_Thread_Attach_Hook) then
  411. Dll_Thread_Attach_Hook(DllParam);
  412. Dll_entry:=true; { return value is ignored }
  413. end;
  414. DLL_THREAD_DETACH :
  415. begin
  416. dec(Thread_count);
  417. if assigned(Dll_Thread_Detach_Hook) then
  418. Dll_Thread_Detach_Hook(DllParam);
  419. {$warning Release Threadvars !}
  420. Dll_entry:=true; { return value is ignored }
  421. end;
  422. DLL_PROCESS_DETACH :
  423. begin
  424. Dll_entry:=true; { return value is ignored }
  425. If SetJmp(DLLBuf) = 0 then
  426. begin
  427. FPC_DO_EXIT;
  428. end;
  429. if assigned(Dll_Process_Detach_Hook) then
  430. Dll_Process_Detach_Hook(DllParam);
  431. end;
  432. end;
  433. end;
  434. Procedure ExitDLL(Exitcode : longint);
  435. begin
  436. DLLExitOK:=ExitCode=0;
  437. LongJmp(DLLBuf,1);
  438. end;
  439. function GetCurrentProcess : dword;
  440. stdcall;external 'kernel32' name 'GetCurrentProcess';
  441. function ReadProcessMemory(process : dword;address : pointer;dest : pointer;size : dword;bytesread : pdword) : longbool;
  442. stdcall;external 'kernel32' name 'ReadProcessMemory';
  443. function is_prefetch(p : pointer) : boolean;
  444. var
  445. a : array[0..15] of byte;
  446. doagain : boolean;
  447. instrlo,instrhi,opcode : byte;
  448. i : longint;
  449. begin
  450. result:=false;
  451. { read memory savely without causing another exeception }
  452. if not(ReadProcessMemory(GetCurrentProcess,p,@a,sizeof(a),nil)) then
  453. exit;
  454. i:=0;
  455. doagain:=true;
  456. while doagain and (i<15) do
  457. begin
  458. opcode:=a[i];
  459. instrlo:=opcode and $f;
  460. instrhi:=opcode and $f0;
  461. case instrhi of
  462. { prefix? }
  463. $20,$30:
  464. doagain:=(instrlo and 7)=6;
  465. $60:
  466. doagain:=(instrlo and $c)=4;
  467. $f0:
  468. doagain:=instrlo in [0,2,3];
  469. $0:
  470. begin
  471. result:=(instrlo=$f) and (a[i+1] in [$d,$18]);
  472. exit;
  473. end;
  474. else
  475. doagain:=false;
  476. end;
  477. inc(i);
  478. end;
  479. end;
  480. //
  481. // Hardware exception handling
  482. //
  483. {$ifdef Set_i386_Exception_handler}
  484. {
  485. Error code definitions for the Win32 API functions
  486. Values are 32 bit values layed out as follows:
  487. 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  488. 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
  489. +---+-+-+-----------------------+-------------------------------+
  490. |Sev|C|R| Facility | Code |
  491. +---+-+-+-----------------------+-------------------------------+
  492. where
  493. Sev - is the severity code
  494. 00 - Success
  495. 01 - Informational
  496. 10 - Warning
  497. 11 - Error
  498. C - is the Customer code flag
  499. R - is a reserved bit
  500. Facility - is the facility code
  501. Code - is the facility's status code
  502. }
  503. const
  504. SEVERITY_SUCCESS = $00000000;
  505. SEVERITY_INFORMATIONAL = $40000000;
  506. SEVERITY_WARNING = $80000000;
  507. SEVERITY_ERROR = $C0000000;
  508. const
  509. STATUS_SEGMENT_NOTIFICATION = $40000005;
  510. DBG_TERMINATE_THREAD = $40010003;
  511. DBG_TERMINATE_PROCESS = $40010004;
  512. DBG_CONTROL_C = $40010005;
  513. DBG_CONTROL_BREAK = $40010008;
  514. STATUS_GUARD_PAGE_VIOLATION = $80000001;
  515. STATUS_DATATYPE_MISALIGNMENT = $80000002;
  516. STATUS_BREAKPOINT = $80000003;
  517. STATUS_SINGLE_STEP = $80000004;
  518. DBG_EXCEPTION_NOT_HANDLED = $80010001;
  519. STATUS_ACCESS_VIOLATION = $C0000005;
  520. STATUS_IN_PAGE_ERROR = $C0000006;
  521. STATUS_INVALID_HANDLE = $C0000008;
  522. STATUS_NO_MEMORY = $C0000017;
  523. STATUS_ILLEGAL_INSTRUCTION = $C000001D;
  524. STATUS_NONCONTINUABLE_EXCEPTION = $C0000025;
  525. STATUS_INVALID_DISPOSITION = $C0000026;
  526. STATUS_ARRAY_BOUNDS_EXCEEDED = $C000008C;
  527. STATUS_FLOAT_DENORMAL_OPERAND = $C000008D;
  528. STATUS_FLOAT_DIVIDE_BY_ZERO = $C000008E;
  529. STATUS_FLOAT_INEXACT_RESULT = $C000008F;
  530. STATUS_FLOAT_INVALID_OPERATION = $C0000090;
  531. STATUS_FLOAT_OVERFLOW = $C0000091;
  532. STATUS_FLOAT_STACK_CHECK = $C0000092;
  533. STATUS_FLOAT_UNDERFLOW = $C0000093;
  534. STATUS_INTEGER_DIVIDE_BY_ZERO = $C0000094;
  535. STATUS_INTEGER_OVERFLOW = $C0000095;
  536. STATUS_PRIVILEGED_INSTRUCTION = $C0000096;
  537. STATUS_STACK_OVERFLOW = $C00000FD;
  538. STATUS_CONTROL_C_EXIT = $C000013A;
  539. STATUS_FLOAT_MULTIPLE_FAULTS = $C00002B4;
  540. STATUS_FLOAT_MULTIPLE_TRAPS = $C00002B5;
  541. STATUS_REG_NAT_CONSUMPTION = $C00002C9;
  542. EXCEPTION_EXECUTE_HANDLER = 1;
  543. EXCEPTION_CONTINUE_EXECUTION = -1;
  544. EXCEPTION_CONTINUE_SEARCH = 0;
  545. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  546. CONTEXT_X86 = $00010000;
  547. CONTEXT_CONTROL = CONTEXT_X86 or $00000001;
  548. CONTEXT_INTEGER = CONTEXT_X86 or $00000002;
  549. CONTEXT_SEGMENTS = CONTEXT_X86 or $00000004;
  550. CONTEXT_FLOATING_POINT = CONTEXT_X86 or $00000008;
  551. CONTEXT_DEBUG_REGISTERS = CONTEXT_X86 or $00000010;
  552. CONTEXT_EXTENDED_REGISTERS = CONTEXT_X86 or $00000020;
  553. CONTEXT_FULL = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
  554. MAXIMUM_SUPPORTED_EXTENSION = 512;
  555. type
  556. PFloatingSaveArea = ^TFloatingSaveArea;
  557. TFloatingSaveArea = packed record
  558. ControlWord : Cardinal;
  559. StatusWord : Cardinal;
  560. TagWord : Cardinal;
  561. ErrorOffset : Cardinal;
  562. ErrorSelector : Cardinal;
  563. DataOffset : Cardinal;
  564. DataSelector : Cardinal;
  565. RegisterArea : array[0..79] of Byte;
  566. Cr0NpxState : Cardinal;
  567. end;
  568. PContext = ^TContext;
  569. TContext = packed record
  570. //
  571. // The flags values within this flag control the contents of
  572. // a CONTEXT record.
  573. //
  574. ContextFlags : Cardinal;
  575. //
  576. // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
  577. // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
  578. // included in CONTEXT_FULL.
  579. //
  580. Dr0, Dr1, Dr2,
  581. Dr3, Dr6, Dr7 : Cardinal;
  582. //
  583. // This section is specified/returned if the
  584. // ContextFlags word contains the flag CONTEXT_FLOATING_POINT.
  585. //
  586. FloatSave : TFloatingSaveArea;
  587. //
  588. // This section is specified/returned if the
  589. // ContextFlags word contains the flag CONTEXT_SEGMENTS.
  590. //
  591. SegGs, SegFs,
  592. SegEs, SegDs : Cardinal;
  593. //
  594. // This section is specified/returned if the
  595. // ContextFlags word contains the flag CONTEXT_INTEGER.
  596. //
  597. Edi, Esi, Ebx,
  598. Edx, Ecx, Eax : Cardinal;
  599. //
  600. // This section is specified/returned if the
  601. // ContextFlags word contains the flag CONTEXT_CONTROL.
  602. //
  603. Ebp : Cardinal;
  604. Eip : Cardinal;
  605. SegCs : Cardinal;
  606. EFlags, Esp, SegSs : Cardinal;
  607. //
  608. // This section is specified/returned if the ContextFlags word
  609. // contains the flag CONTEXT_EXTENDED_REGISTERS.
  610. // The format and contexts are processor specific
  611. //
  612. ExtendedRegisters : array[0..MAXIMUM_SUPPORTED_EXTENSION-1] of Byte;
  613. end;
  614. type
  615. PExceptionRecord = ^TExceptionRecord;
  616. TExceptionRecord = packed record
  617. ExceptionCode : Longint;
  618. ExceptionFlags : Longint;
  619. ExceptionRecord : PExceptionRecord;
  620. ExceptionAddress : Pointer;
  621. NumberParameters : Longint;
  622. ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of Pointer;
  623. end;
  624. PExceptionPointers = ^TExceptionPointers;
  625. TExceptionPointers = packed record
  626. ExceptionRecord : PExceptionRecord;
  627. ContextRecord : PContext;
  628. end;
  629. { type of functions that should be used for exception handling }
  630. TTopLevelExceptionFilter = function (excep : PExceptionPointers) : Longint;stdcall;
  631. function SetUnhandledExceptionFilter(lpTopLevelExceptionFilter : TTopLevelExceptionFilter) : TTopLevelExceptionFilter;
  632. stdcall;external 'kernel32' name 'SetUnhandledExceptionFilter';
  633. const
  634. MaxExceptionLevel = 16;
  635. exceptLevel : Byte = 0;
  636. var
  637. exceptEip : array[0..MaxExceptionLevel-1] of Longint;
  638. exceptError : array[0..MaxExceptionLevel-1] of Byte;
  639. resetFPU : array[0..MaxExceptionLevel-1] of Boolean;
  640. {$ifdef SYSTEMEXCEPTIONDEBUG}
  641. procedure DebugHandleErrorAddrFrame(error, addr, frame : longint);
  642. begin
  643. if IsConsole then
  644. begin
  645. write(stderr,'HandleErrorAddrFrame(error=',error);
  646. write(stderr,',addr=',hexstr(addr,8));
  647. writeln(stderr,',frame=',hexstr(frame,8),')');
  648. end;
  649. HandleErrorAddrFrame(error,addr,frame);
  650. end;
  651. {$endif SYSTEMEXCEPTIONDEBUG}
  652. procedure JumpToHandleErrorFrame;
  653. var
  654. eip, ebp, error : Longint;
  655. begin
  656. // save ebp
  657. asm
  658. movl (%ebp),%eax
  659. movl %eax,ebp
  660. end;
  661. if (exceptLevel > 0) then
  662. dec(exceptLevel);
  663. eip:=exceptEip[exceptLevel];
  664. error:=exceptError[exceptLevel];
  665. {$ifdef SYSTEMEXCEPTIONDEBUG}
  666. if IsConsole then
  667. writeln(stderr,'In JumpToHandleErrorFrame error=',error);
  668. {$endif SYSTEMEXCEPTIONDEBUG}
  669. if resetFPU[exceptLevel] then asm
  670. fninit
  671. fldcw fpucw
  672. end;
  673. { build a fake stack }
  674. asm
  675. {$ifdef REGCALL}
  676. movl ebp,%ecx
  677. movl eip,%edx
  678. movl error,%eax
  679. pushl eip
  680. movl ebp,%ebp // Change frame pointer
  681. {$else}
  682. movl ebp,%eax
  683. pushl %eax
  684. movl eip,%eax
  685. pushl %eax
  686. movl error,%eax
  687. pushl %eax
  688. movl eip,%eax
  689. pushl %eax
  690. movl ebp,%ebp // Change frame pointer
  691. {$endif}
  692. {$ifdef SYSTEMEXCEPTIONDEBUG}
  693. jmpl DebugHandleErrorAddrFrame
  694. {$else not SYSTEMEXCEPTIONDEBUG}
  695. jmpl HandleErrorAddrFrame
  696. {$endif SYSTEMEXCEPTIONDEBUG}
  697. end;
  698. end;
  699. function syswin32_i386_exception_handler(excep : PExceptionPointers) : Longint;stdcall;
  700. var
  701. frame,
  702. res : longint;
  703. function SysHandleErrorFrame(error, frame : Longint; must_reset_fpu : Boolean) : Longint;
  704. begin
  705. if (frame = 0) then
  706. SysHandleErrorFrame:=EXCEPTION_CONTINUE_SEARCH
  707. else begin
  708. if (exceptLevel >= MaxExceptionLevel) then exit;
  709. exceptEip[exceptLevel] := excep^.ContextRecord^.Eip;
  710. exceptError[exceptLevel] := error;
  711. resetFPU[exceptLevel] := must_reset_fpu;
  712. inc(exceptLevel);
  713. excep^.ContextRecord^.Eip := Longint(@JumpToHandleErrorFrame);
  714. excep^.ExceptionRecord^.ExceptionCode := 0;
  715. SysHandleErrorFrame := EXCEPTION_CONTINUE_EXECUTION;
  716. {$ifdef SYSTEMEXCEPTIONDEBUG}
  717. if IsConsole then begin
  718. writeln(stderr,'Exception Continue Exception set at ',
  719. hexstr(exceptEip[exceptLevel],8));
  720. writeln(stderr,'Eip changed to ',
  721. hexstr(longint(@JumpToHandleErrorFrame),8), ' error=', error);
  722. end;
  723. {$endif SYSTEMEXCEPTIONDEBUG}
  724. end;
  725. end;
  726. begin
  727. if excep^.ContextRecord^.SegSs=_SS then
  728. frame := excep^.ContextRecord^.Ebp
  729. else
  730. frame := 0;
  731. res := EXCEPTION_CONTINUE_SEARCH;
  732. {$ifdef SYSTEMEXCEPTIONDEBUG}
  733. if IsConsole then Writeln(stderr,'Exception ',
  734. hexstr(excep^.ExceptionRecord^.ExceptionCode, 8));
  735. {$endif SYSTEMEXCEPTIONDEBUG}
  736. case cardinal(excep^.ExceptionRecord^.ExceptionCode) of
  737. STATUS_INTEGER_DIVIDE_BY_ZERO,
  738. STATUS_FLOAT_DIVIDE_BY_ZERO :
  739. res := SysHandleErrorFrame(200, frame, true);
  740. STATUS_ARRAY_BOUNDS_EXCEEDED :
  741. res := SysHandleErrorFrame(201, frame, false);
  742. STATUS_STACK_OVERFLOW :
  743. res := SysHandleErrorFrame(202, frame, false);
  744. STATUS_FLOAT_OVERFLOW :
  745. res := SysHandleErrorFrame(205, frame, true);
  746. STATUS_FLOAT_DENORMAL_OPERAND,
  747. STATUS_FLOAT_UNDERFLOW :
  748. res := SysHandleErrorFrame(206, frame, true);
  749. {excep^.ContextRecord^.FloatSave.StatusWord := excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
  750. STATUS_FLOAT_INEXACT_RESULT,
  751. STATUS_FLOAT_INVALID_OPERATION,
  752. STATUS_FLOAT_STACK_CHECK :
  753. res := SysHandleErrorFrame(207, frame, true);
  754. STATUS_INTEGER_OVERFLOW :
  755. res := SysHandleErrorFrame(215, frame, false);
  756. STATUS_ILLEGAL_INSTRUCTION:
  757. res := SysHandleErrorFrame(216, frame, true);
  758. STATUS_ACCESS_VIOLATION:
  759. { Athlon prefetch bug? }
  760. if is_prefetch(pointer(excep^.ContextRecord^.Eip)) then
  761. begin
  762. { if yes, then retry }
  763. excep^.ExceptionRecord^.ExceptionCode := 0;
  764. res:=EXCEPTION_CONTINUE_EXECUTION;
  765. end
  766. else
  767. res := SysHandleErrorFrame(216, frame, true);
  768. STATUS_CONTROL_C_EXIT:
  769. res := SysHandleErrorFrame(217, frame, true);
  770. STATUS_PRIVILEGED_INSTRUCTION:
  771. res := SysHandleErrorFrame(218, frame, false);
  772. else
  773. begin
  774. if ((excep^.ExceptionRecord^.ExceptionCode and SEVERITY_ERROR) = SEVERITY_ERROR) then
  775. res := SysHandleErrorFrame(217, frame, true)
  776. else
  777. res := SysHandleErrorFrame(255, frame, true);
  778. end;
  779. end;
  780. syswin32_i386_exception_handler := res;
  781. end;
  782. procedure install_exception_handlers;
  783. {$ifdef SYSTEMEXCEPTIONDEBUG}
  784. var
  785. oldexceptaddr,
  786. newexceptaddr : Longint;
  787. {$endif SYSTEMEXCEPTIONDEBUG}
  788. begin
  789. {$ifdef SYSTEMEXCEPTIONDEBUG}
  790. asm
  791. movl $0,%eax
  792. movl %fs:(%eax),%eax
  793. movl %eax,oldexceptaddr
  794. end;
  795. {$endif SYSTEMEXCEPTIONDEBUG}
  796. SetUnhandledExceptionFilter(@syswin32_i386_exception_handler);
  797. {$ifdef SYSTEMEXCEPTIONDEBUG}
  798. asm
  799. movl $0,%eax
  800. movl %fs:(%eax),%eax
  801. movl %eax,newexceptaddr
  802. end;
  803. if IsConsole then
  804. writeln(stderr,'Old exception ',hexstr(oldexceptaddr,8),
  805. ' new exception ',hexstr(newexceptaddr,8));
  806. {$endif SYSTEMEXCEPTIONDEBUG}
  807. end;
  808. procedure remove_exception_handlers;
  809. begin
  810. SetUnhandledExceptionFilter(nil);
  811. end;
  812. {$else not cpui386 (Processor specific !!)}
  813. procedure install_exception_handlers;
  814. begin
  815. end;
  816. procedure remove_exception_handlers;
  817. begin
  818. end;
  819. {$endif Set_i386_Exception_handler}
  820. {$ifdef HASWIDESTRING}
  821. {****************************************************************************
  822. OS dependend widestrings
  823. ****************************************************************************}
  824. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD; stdcall; external 'user32' name 'CharUpperBuffW';
  825. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD; stdcall; external 'user32' name 'CharLowerBuffW';
  826. function Win32WideUpper(const s : WideString) : WideString;
  827. begin
  828. result:=s;
  829. UniqueString(result);
  830. if length(result)>0 then
  831. CharUpperBuff(LPWSTR(result),length(result));
  832. end;
  833. function Win32WideLower(const s : WideString) : WideString;
  834. begin
  835. result:=s;
  836. UniqueString(result);
  837. if length(result)>0 then
  838. CharLowerBuff(LPWSTR(result),length(result));
  839. end;
  840. { there is a similiar procedure in sysutils which inits the fields which
  841. are only relevant for the sysutils units }
  842. procedure InitWin32Widestrings;
  843. begin
  844. widestringmanager.UpperWideStringProc:=@Win32WideUpper;
  845. widestringmanager.LowerWideStringProc:=@Win32WideLower;
  846. end;
  847. {$endif HASWIDESTRING}
  848. {****************************************************************************
  849. Error Message writing using messageboxes
  850. ****************************************************************************}
  851. function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
  852. stdcall;external 'user32' name 'MessageBoxA';
  853. const
  854. ErrorBufferLength = 1024;
  855. var
  856. ErrorBuf : array[0..ErrorBufferLength] of char;
  857. ErrorLen : longint;
  858. Function ErrorWrite(Var F: TextRec): Integer;
  859. {
  860. An error message should always end with #13#10#13#10
  861. }
  862. var
  863. p : pchar;
  864. i : longint;
  865. Begin
  866. if F.BufPos>0 then
  867. begin
  868. if F.BufPos+ErrorLen>ErrorBufferLength then
  869. i:=ErrorBufferLength-ErrorLen
  870. else
  871. i:=F.BufPos;
  872. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  873. inc(ErrorLen,i);
  874. ErrorBuf[ErrorLen]:=#0;
  875. end;
  876. if ErrorLen>3 then
  877. begin
  878. p:=@ErrorBuf[ErrorLen];
  879. for i:=1 to 4 do
  880. begin
  881. dec(p);
  882. if not(p^ in [#10,#13]) then
  883. break;
  884. end;
  885. end;
  886. if ErrorLen=ErrorBufferLength then
  887. i:=4;
  888. if (i=4) then
  889. begin
  890. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  891. ErrorLen:=0;
  892. end;
  893. F.BufPos:=0;
  894. ErrorWrite:=0;
  895. End;
  896. Function ErrorClose(Var F: TextRec): Integer;
  897. begin
  898. if ErrorLen>0 then
  899. begin
  900. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  901. ErrorLen:=0;
  902. end;
  903. ErrorLen:=0;
  904. ErrorClose:=0;
  905. end;
  906. Function ErrorOpen(Var F: TextRec): Integer;
  907. Begin
  908. TextRec(F).InOutFunc:=@ErrorWrite;
  909. TextRec(F).FlushFunc:=@ErrorWrite;
  910. TextRec(F).CloseFunc:=@ErrorClose;
  911. ErrorOpen:=0;
  912. End;
  913. procedure AssignError(Var T: Text);
  914. begin
  915. Assign(T,'');
  916. TextRec(T).OpenFunc:=@ErrorOpen;
  917. Rewrite(T);
  918. end;
  919. procedure SysInitStdIO;
  920. begin
  921. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  922. displayed in and messagebox }
  923. StdInputHandle:=longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  924. StdOutputHandle:=longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  925. StdErrorHandle:=longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  926. if not IsConsole then
  927. begin
  928. AssignError(stderr);
  929. AssignError(stdout);
  930. Assign(Output,'');
  931. Assign(Input,'');
  932. Assign(ErrOutput,'');
  933. end
  934. else
  935. begin
  936. OpenStdIO(Input,fmInput,StdInputHandle);
  937. OpenStdIO(Output,fmOutput,StdOutputHandle);
  938. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  939. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  940. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  941. end;
  942. end;
  943. (* ProcessID cached to avoid repeated calls to GetCurrentProcess. *)
  944. var
  945. ProcessID: SizeUInt;
  946. function GetProcessID: SizeUInt;
  947. begin
  948. GetProcessID := ProcessID;
  949. end;
  950. const
  951. Exe_entry_code : pointer = @Exe_entry;
  952. Dll_entry_code : pointer = @Dll_entry;
  953. begin
  954. StackLength := InitialStkLen;
  955. StackBottom := Sptr - StackLength;
  956. { get some helpful informations }
  957. GetStartupInfo(@startupinfo);
  958. { some misc Win32 stuff }
  959. hprevinst:=0;
  960. if not IsLibrary then
  961. HInstance:=getmodulehandle(GetCommandFile);
  962. MainInstance:=HInstance;
  963. cmdshow:=startupinfo.wshowwindow;
  964. { Setup heap }
  965. InitHeap;
  966. SysInitExceptions;
  967. SysInitStdIO;
  968. { Arguments }
  969. setup_arguments;
  970. { Reset IO Error }
  971. InOutRes:=0;
  972. ProcessID := GetCurrentProcessID;
  973. { threading }
  974. InitSystemThreads;
  975. { Reset internal error variable }
  976. errno:=0;
  977. {$ifdef HASVARIANT}
  978. initvariantmanager;
  979. {$endif HASVARIANT}
  980. {$ifdef HASWIDESTRING}
  981. initwidestringmanager;
  982. InitWin32Widestrings
  983. {$endif HASWIDESTRING}
  984. end.
  985. {
  986. $Log$
  987. Revision 1.72 2005-03-21 16:31:33 peter
  988. * fix crash under win32 with previous reallocmem fix
  989. Revision 1.71 2005/03/02 19:18:42 florian
  990. * fixed compilation with 1.0.10
  991. Revision 1.70 2005/02/26 20:43:52 florian
  992. + WideCompareString and WideCompareText for win32 implemented
  993. Revision 1.69 2005/02/26 10:21:17 florian
  994. + implemented WideFormat
  995. + some Widestring stuff implemented
  996. * some Widestring stuff fixed
  997. Revision 1.68 2005/02/14 17:13:32 peter
  998. * truncate log
  999. Revision 1.67 2005/02/06 13:06:20 peter
  1000. * moved file and dir functions to sysfile/sysdir
  1001. * win32 thread in systemunit
  1002. Revision 1.66 2005/02/01 20:22:50 florian
  1003. * improved widestring infrastructure manager
  1004. }