syswin32.pp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1993-98 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. unit syswin32;
  14. interface
  15. {$ifdef i386}
  16. {$define Set_i386_Exception_handler}
  17. {$endif i386}
  18. { include system-independent routine headers }
  19. {$I systemh.inc}
  20. { include heap support headers }
  21. {$I heaph.inc}
  22. const
  23. { Default filehandles }
  24. UnusedHandle : longint = -1;
  25. StdInputHandle : longint = 0;
  26. StdOutputHandle : longint = 0;
  27. StdErrorHandle : longint = 0;
  28. FileNameCaseSensitive : boolean = true;
  29. type
  30. TStartupInfo=packed record
  31. cb : longint;
  32. lpReserved : Pointer;
  33. lpDesktop : Pointer;
  34. lpTitle : Pointer;
  35. dwX : longint;
  36. dwY : longint;
  37. dwXSize : longint;
  38. dwYSize : longint;
  39. dwXCountChars : longint;
  40. dwYCountChars : longint;
  41. dwFillAttribute : longint;
  42. dwFlags : longint;
  43. wShowWindow : Word;
  44. cbReserved2 : Word;
  45. lpReserved2 : Pointer;
  46. hStdInput : longint;
  47. hStdOutput : longint;
  48. hStdError : longint;
  49. end;
  50. var
  51. { C compatible arguments }
  52. argc : longint;
  53. argv : ppchar;
  54. { Win32 Info }
  55. startupinfo : tstartupinfo;
  56. hprevinst,
  57. HInstance,
  58. MainInstance,
  59. cmdshow : longint;
  60. IsLibrary,IsMultiThreaded,IsConsole : boolean;
  61. DLLreason,DLLparam:longint;
  62. Win32StackTop : Dword;
  63. { Thread count for DLL }
  64. const
  65. Thread_count : longint = 0;
  66. type
  67. TDLL_Process_Entry_Hook = function (dllparam : longint) : longbool;
  68. TDLL_Entry_Hook = procedure (dllparam : longint);
  69. const
  70. Dll_Process_Attach_Hook : TDLL_Process_Entry_Hook = nil;
  71. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  72. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  73. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  74. implementation
  75. { include system independent routines }
  76. {$I system.inc}
  77. { some declarations for Win32 API calls }
  78. {$I win32.inc}
  79. CONST
  80. { These constants are used for conversion of error codes }
  81. { from win32 i/o errors to tp i/o errors }
  82. { errors 1 to 18 are the same as in Turbo Pascal }
  83. { DO NOT MODIFY UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING! }
  84. { The media is write protected. }
  85. ERROR_WRITE_PROTECT = 19;
  86. { The system cannot find the device specified. }
  87. ERROR_BAD_UNIT = 20;
  88. { The device is not ready. }
  89. ERROR_NOT_READY = 21;
  90. { The device does not recognize the command. }
  91. ERROR_BAD_COMMAND = 22;
  92. { Data error (cyclic redundancy check) }
  93. ERROR_CRC = 23;
  94. { The program issued a command but the }
  95. { command length is incorrect. }
  96. ERROR_BAD_LENGTH = 24;
  97. { The drive cannot locate a specific }
  98. { area or track on the disk. }
  99. ERROR_SEEK = 25;
  100. { The specified disk or diskette cannot be accessed. }
  101. ERROR_NOT_DOS_DISK = 26;
  102. { The drive cannot find the sector requested. }
  103. ERROR_SECTOR_NOT_FOUND = 27;
  104. { The printer is out of paper. }
  105. ERROR_OUT_OF_PAPER = 28;
  106. { The system cannot write to the specified device. }
  107. ERROR_WRITE_FAULT = 29;
  108. { The system cannot read from the specified device. }
  109. ERROR_READ_FAULT = 30;
  110. { A device attached to the system is not functioning.}
  111. ERROR_GEN_FAILURE = 31;
  112. { The process cannot access the file because }
  113. { it is being used by another process. }
  114. ERROR_SHARING_VIOLATION = 32;
  115. var
  116. errno : longint;
  117. {$ASMMODE ATT}
  118. { misc. functions }
  119. function GetLastError : DWORD;
  120. external 'kernel32' name 'GetLastError';
  121. { time and date functions }
  122. function GetTickCount : longint;
  123. external 'kernel32' name 'GetTickCount';
  124. { process functions }
  125. procedure ExitProcess(uExitCode : UINT);
  126. external 'kernel32' name 'ExitProcess';
  127. Procedure Errno2InOutRes;
  128. Begin
  129. { DO NOT MODIFY UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING }
  130. if (errno >= ERROR_WRITE_PROTECT) and (errno <= ERROR_GEN_FAILURE) THEN
  131. BEGIN
  132. { This is the offset to the Win32 to add to directly map }
  133. { to the DOS/TP compatible error codes when in this range }
  134. InOutRes := word(errno)+131;
  135. END
  136. else
  137. { This case is special }
  138. if errno=ERROR_SHARING_VIOLATION THEN
  139. BEGIN
  140. InOutRes :=5;
  141. END
  142. else
  143. { other error codes can directly be mapped }
  144. InOutRes := Word(errno);
  145. errno:=0;
  146. end;
  147. {$ifdef dummy}
  148. procedure int_stackcheck(stack_size:longint);[public,alias: 'STACKCHECK'];
  149. {
  150. called when trying to get local stack if the compiler directive $S
  151. is set this function must preserve esi !!!! because esi is set by
  152. the calling proc for methods it must preserve all registers !!
  153. With a 2048 byte safe area used to write to StdIo without crossing
  154. the stack boundary
  155. }
  156. begin
  157. asm
  158. pushl %eax
  159. pushl %ebx
  160. movl stack_size,%ebx
  161. addl $2048,%ebx
  162. movl %esp,%eax
  163. subl %ebx,%eax
  164. movl stacklimit,%ebx
  165. cmpl %eax,%ebx
  166. jae .L__short_on_stack
  167. popl %ebx
  168. popl %eax
  169. leave
  170. ret $4
  171. .L__short_on_stack:
  172. { can be usefull for error recovery !! }
  173. popl %ebx
  174. popl %eax
  175. end['EAX','EBX'];
  176. HandleError(202);
  177. end;
  178. {$endif dummy}
  179. procedure halt(errnum : byte);
  180. begin
  181. do_exit;
  182. ExitProcess(errnum);
  183. end;
  184. function paramcount : longint;
  185. begin
  186. paramcount := argc - 1;
  187. end;
  188. { module functions }
  189. function GetModuleFileName(l1:longint;p:pointer;l2:longint):longint;
  190. external 'kernel32' name 'GetModuleFileNameA';
  191. function GetModuleHandle(p : pointer) : longint;
  192. external 'kernel32' name 'GetModuleHandleA';
  193. function GetCommandFile:pchar;forward;
  194. function paramstr(l : longint) : string;
  195. begin
  196. if (l>=0) and (l<argc) then
  197. paramstr:=strpas(argv[l])
  198. else
  199. paramstr:='';
  200. end;
  201. procedure randomize;
  202. begin
  203. randseed:=GetTickCount;
  204. end;
  205. {*****************************************************************************
  206. Heap Management
  207. *****************************************************************************}
  208. { memory functions }
  209. function GlobalAlloc(mode,size:longint):longint;
  210. external 'kernel32' name 'GlobalAlloc';
  211. function GlobalLock(handle:longint):pointer;
  212. external 'kernel32' name 'GlobalLock';
  213. {$ifdef SYSTEMDEBUG}
  214. function GlobalSize(h:longint):longint;
  215. external 'kernel32' name 'GlobalSize';
  216. {$endif}
  217. var
  218. heap : longint;external name 'HEAP';
  219. intern_heapsize : longint;external name 'HEAPSIZE';
  220. function getheapstart:pointer;assembler;
  221. asm
  222. leal HEAP,%eax
  223. end ['EAX'];
  224. function getheapsize:longint;assembler;
  225. asm
  226. movl intern_HEAPSIZE,%eax
  227. end ['EAX'];
  228. function Sbrk(size : longint):longint;
  229. var
  230. h,l : longint;
  231. begin
  232. h:=GlobalAlloc(258,size);
  233. l:=longint(GlobalLock(h));
  234. if l=0 then
  235. l:=-1;
  236. {$ifdef SYSTEMDEBUG}
  237. Writeln('new heap part at $',hexstr(l,8), ' size = ',GlobalSize(h));
  238. {$endif}
  239. sbrk:=l;
  240. end;
  241. { include standard heap management }
  242. {$I heap.inc}
  243. {*****************************************************************************
  244. Low Level File Routines
  245. *****************************************************************************}
  246. function WriteFile(fh:longint;buf:pointer;len:longint;var loaded:longint;
  247. overlap:pointer):longint;
  248. external 'kernel32' name 'WriteFile';
  249. function ReadFile(fh:longint;buf:pointer;len:longint;var loaded:longint;
  250. overlap:pointer):longint;
  251. external 'kernel32' name 'ReadFile';
  252. function CloseHandle(h : longint) : longint;
  253. external 'kernel32' name 'CloseHandle';
  254. function DeleteFile(p : pchar) : longint;
  255. external 'kernel32' name 'DeleteFileA';
  256. function MoveFile(old,_new : pchar) : longint;
  257. external 'kernel32' name 'MoveFileA';
  258. function SetFilePointer(l1,l2 : longint;l3 : pointer;l4 : longint) : longint;
  259. external 'kernel32' name 'SetFilePointer';
  260. function GetFileSize(h:longint;p:pointer) : longint;
  261. external 'kernel32' name 'GetFileSize';
  262. function CreateFile(name : pointer;access,sharing : longint;
  263. security : pointer;how,attr,template : longint) : longint;
  264. external 'kernel32' name 'CreateFileA';
  265. function SetEndOfFile(h : longint) : longbool;
  266. external 'kernel32' name 'SetEndOfFile';
  267. function GetFileType(Handle:DWORD):DWord;
  268. external 'kernel32' name 'GetFileType';
  269. procedure AllowSlash(p:pchar);
  270. var
  271. i : longint;
  272. begin
  273. { allow slash as backslash }
  274. for i:=0 to strlen(p) do
  275. if p[i]='/' then p[i]:='\';
  276. end;
  277. procedure do_close(h : longint);
  278. begin
  279. closehandle(h);
  280. end;
  281. procedure do_erase(p : pchar);
  282. begin
  283. AllowSlash(p);
  284. if DeleteFile(p)=0 then
  285. Begin
  286. errno:=GetLastError;
  287. Errno2InoutRes;
  288. end;
  289. end;
  290. procedure do_rename(p1,p2 : pchar);
  291. begin
  292. AllowSlash(p1);
  293. AllowSlash(p2);
  294. if MoveFile(p1,p2)=0 then
  295. Begin
  296. errno:=GetLastError;
  297. Errno2InoutRes;
  298. end;
  299. end;
  300. function do_write(h,addr,len : longint) : longint;
  301. var
  302. size:longint;
  303. begin
  304. if writefile(h,pointer(addr),len,size,nil)=0 then
  305. Begin
  306. errno:=GetLastError;
  307. Errno2InoutRes;
  308. end;
  309. do_write:=size;
  310. end;
  311. function do_read(h,addr,len : longint) : longint;
  312. var
  313. _result:longint;
  314. begin
  315. if readfile(h,pointer(addr),len,_result,nil)=0 then
  316. Begin
  317. errno:=GetLastError;
  318. Errno2InoutRes;
  319. end;
  320. do_read:=_result;
  321. end;
  322. function do_filepos(handle : longint) : longint;
  323. var
  324. l:longint;
  325. begin
  326. l:=SetFilePointer(handle,0,nil,FILE_CURRENT);
  327. if l=-1 then
  328. begin
  329. l:=0;
  330. errno:=GetLastError;
  331. Errno2InoutRes;
  332. end;
  333. do_filepos:=l;
  334. end;
  335. procedure do_seek(handle,pos : longint);
  336. begin
  337. if SetFilePointer(handle,pos,nil,FILE_BEGIN)=-1 then
  338. Begin
  339. errno:=GetLastError;
  340. Errno2InoutRes;
  341. end;
  342. end;
  343. function do_seekend(handle:longint):longint;
  344. begin
  345. do_seekend:=SetFilePointer(handle,0,nil,FILE_END);
  346. if do_seekend=-1 then
  347. begin
  348. errno:=GetLastError;
  349. Errno2InoutRes;
  350. end;
  351. end;
  352. function do_filesize(handle : longint) : longint;
  353. var
  354. aktfilepos : longint;
  355. begin
  356. aktfilepos:=do_filepos(handle);
  357. do_filesize:=do_seekend(handle);
  358. do_seek(handle,aktfilepos);
  359. end;
  360. procedure do_truncate (handle,pos:longint);
  361. begin
  362. do_seek(handle,pos);
  363. if not(SetEndOfFile(handle)) then
  364. begin
  365. errno:=GetLastError;
  366. Errno2InoutRes;
  367. end;
  368. end;
  369. procedure do_open(var f;p : pchar;flags:longint);
  370. {
  371. filerec and textrec have both handle and mode as the first items so
  372. they could use the same routine for opening/creating.
  373. when (flags and $100) the file will be append
  374. when (flags and $1000) the file will be truncate/rewritten
  375. when (flags and $10000) there is no check for close (needed for textfiles)
  376. }
  377. Const
  378. file_Share_Read = $00000001;
  379. file_Share_Write = $00000002;
  380. fmShareCompat = $00000000;
  381. fmShareExclusive = $10;
  382. fmShareDenyWrite = $20;
  383. fmShareDenyRead = $30;
  384. fmShareDenyNone = $40;
  385. Var
  386. shflags,
  387. oflags,cd : longint;
  388. begin
  389. AllowSlash(p);
  390. { close first if opened }
  391. if ((flags and $10000)=0) then
  392. begin
  393. case filerec(f).mode of
  394. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  395. fmclosed : ;
  396. else
  397. begin
  398. {not assigned}
  399. inoutres:=102;
  400. exit;
  401. end;
  402. end;
  403. end;
  404. { reset file handle }
  405. filerec(f).handle:=UnusedHandle;
  406. { convert filesharing }
  407. shflags:=0;
  408. if ((filemode and fmshareExclusive) = fmshareExclusive) then
  409. { no sharing }
  410. else
  411. if (filemode = fmShareCompat) or ((filemode and fmshareDenyWrite) = fmshareDenyWrite) then
  412. shflags := file_Share_Read
  413. else
  414. if ((filemode and fmshareDenyRead) = fmshareDenyRead) then
  415. shflags := file_Share_Write
  416. else
  417. if ((filemode and fmshareDenyNone) = fmshareDenyNone) then
  418. shflags := file_Share_Read + file_Share_Write;
  419. { convert filemode to filerec modes }
  420. case (flags and 3) of
  421. 0 : begin
  422. filerec(f).mode:=fminput;
  423. oflags:=GENERIC_READ;
  424. end;
  425. 1 : begin
  426. filerec(f).mode:=fmoutput;
  427. oflags:=GENERIC_WRITE;
  428. end;
  429. 2 : begin
  430. filerec(f).mode:=fminout;
  431. oflags:=GENERIC_WRITE or GENERIC_READ;
  432. end;
  433. end;
  434. { standard is opening and existing file }
  435. cd:=OPEN_EXISTING;
  436. { create it ? }
  437. if (flags and $1000)<>0 then
  438. cd:=CREATE_ALWAYS
  439. { or append ? }
  440. else
  441. if (flags and $100)<>0 then
  442. cd:=OPEN_ALWAYS;
  443. { empty name is special }
  444. if p[0]=#0 then
  445. begin
  446. case filerec(f).mode of
  447. fminput : filerec(f).handle:=StdInputHandle;
  448. fmappend,
  449. fmoutput : begin
  450. filerec(f).handle:=StdOutputHandle;
  451. filerec(f).mode:=fmoutput; {fool fmappend}
  452. end;
  453. end;
  454. exit;
  455. end;
  456. filerec(f).handle:=CreateFile(p,oflags,shflags,nil,cd,FILE_ATTRIBUTE_NORMAL,0);
  457. { append mode }
  458. if (flags and $100)<>0 then
  459. begin
  460. do_seekend(filerec(f).handle);
  461. filerec(f).mode:=fmoutput; {fool fmappend}
  462. end;
  463. { get errors }
  464. { handle -1 is returned sometimes !! (PM) }
  465. if (filerec(f).handle=0) or (filerec(f).handle=-1) then
  466. begin
  467. errno:=GetLastError;
  468. Errno2InoutRes;
  469. end;
  470. end;
  471. function do_isdevice(handle:longint):boolean;
  472. begin
  473. do_isdevice:=(getfiletype(handle)=2);
  474. end;
  475. {*****************************************************************************
  476. UnTyped File Handling
  477. *****************************************************************************}
  478. {$i file.inc}
  479. {*****************************************************************************
  480. Typed File Handling
  481. *****************************************************************************}
  482. {$i typefile.inc}
  483. {*****************************************************************************
  484. Text File Handling
  485. *****************************************************************************}
  486. {$DEFINE EOF_CTRLZ}
  487. {$i text.inc}
  488. {*****************************************************************************
  489. Directory Handling
  490. *****************************************************************************}
  491. function CreateDirectory(name : pointer;sec : pointer) : longint;
  492. external 'kernel32' name 'CreateDirectoryA';
  493. function RemoveDirectory(name:pointer):longint;
  494. external 'kernel32' name 'RemoveDirectoryA';
  495. function SetCurrentDirectory(name : pointer) : longint;
  496. external 'kernel32' name 'SetCurrentDirectoryA';
  497. function GetCurrentDirectory(bufsize : longint;name : pchar) : longint;
  498. external 'kernel32' name 'GetCurrentDirectoryA';
  499. type
  500. TDirFnType=function(name:pointer):word;
  501. procedure dirfn(afunc : TDirFnType;const s:string);
  502. var
  503. buffer : array[0..255] of char;
  504. begin
  505. move(s[1],buffer,length(s));
  506. buffer[length(s)]:=#0;
  507. AllowSlash(pchar(@buffer));
  508. if aFunc(@buffer)=0 then
  509. begin
  510. errno:=GetLastError;
  511. Errno2InoutRes;
  512. end;
  513. end;
  514. function CreateDirectoryTrunc(name:pointer):word;
  515. begin
  516. CreateDirectoryTrunc:=CreateDirectory(name,nil);
  517. end;
  518. procedure mkdir(const s:string);[IOCHECK];
  519. begin
  520. If InOutRes <> 0 then exit;
  521. dirfn(TDirFnType(@CreateDirectoryTrunc),s);
  522. end;
  523. procedure rmdir(const s:string);[IOCHECK];
  524. begin
  525. If InOutRes <> 0 then exit;
  526. dirfn(TDirFnType(@RemoveDirectory),s);
  527. end;
  528. procedure chdir(const s:string);[IOCHECK];
  529. begin
  530. If InOutRes <> 0 then exit;
  531. dirfn(TDirFnType(@SetCurrentDirectory),s);
  532. end;
  533. procedure getdir(drivenr:byte;var dir:shortstring);
  534. const
  535. Drive:array[0..3]of char=(#0,':',#0,#0);
  536. var
  537. defaultdrive:boolean;
  538. DirBuf,SaveBuf:array[0..259] of Char;
  539. begin
  540. defaultdrive:=drivenr=0;
  541. if not defaultdrive then
  542. begin
  543. byte(Drive[0]):=Drivenr+64;
  544. GetCurrentDirectory(SizeOf(SaveBuf),SaveBuf);
  545. SetCurrentDirectory(@Drive);
  546. end;
  547. GetCurrentDirectory(SizeOf(DirBuf),DirBuf);
  548. if not defaultdrive then
  549. SetCurrentDirectory(@SaveBuf);
  550. dir:=strpas(DirBuf);
  551. if not FileNameCaseSensitive then
  552. dir:=upcase(dir);
  553. end;
  554. {*****************************************************************************
  555. SystemUnit Initialization
  556. *****************************************************************************}
  557. { Startup }
  558. procedure GetStartupInfo(p : pointer);
  559. external 'kernel32' name 'GetStartupInfoA';
  560. function GetStdHandle(nStdHandle:DWORD):THANDLE;
  561. external 'kernel32' name 'GetStdHandle';
  562. { command line/enviroment functions }
  563. function GetCommandLine : pchar;
  564. external 'kernel32' name 'GetCommandLineA';
  565. var
  566. ModuleName : array[0..255] of char;
  567. function GetCommandFile:pchar;
  568. begin
  569. GetModuleFileName(0,@ModuleName,255);
  570. GetCommandFile:=@ModuleName;
  571. end;
  572. procedure setup_arguments;
  573. var
  574. arglen,
  575. count : longint;
  576. argstart,
  577. pc : pchar;
  578. quote : set of char;
  579. argsbuf : array[0..127] of pchar;
  580. begin
  581. { create commandline, it starts with the executed filename which is argv[0] }
  582. { Win32 passes the command NOT via the args, but via getmodulefilename}
  583. count:=0;
  584. pc:=getcommandfile;
  585. Arglen:=0;
  586. repeat
  587. Inc(Arglen);
  588. until (pc[Arglen]=#0);
  589. getmem(argsbuf[count],arglen+1);
  590. move(pc^,argsbuf[count]^,arglen);
  591. { Now skip the first one }
  592. pc:=GetCommandLine;
  593. repeat
  594. { skip leading spaces }
  595. while pc^ in [' ',#9,#13] do
  596. inc(pc);
  597. case pc^ of
  598. #0 : break;
  599. '"' : begin
  600. quote:=['"'];
  601. inc(pc);
  602. end;
  603. '''' : begin
  604. quote:=[''''];
  605. inc(pc);
  606. end;
  607. else
  608. quote:=[' ',#9,#13];
  609. end;
  610. { scan until the end of the argument }
  611. argstart:=pc;
  612. while (pc^<>#0) and not(pc^ in quote) do
  613. inc(pc);
  614. { Don't copy the first one, it is already there.}
  615. If Count<>0 then
  616. begin
  617. { reserve some memory }
  618. arglen:=pc-argstart;
  619. getmem(argsbuf[count],arglen+1);
  620. move(argstart^,argsbuf[count]^,arglen);
  621. argsbuf[count][arglen]:=#0;
  622. end;
  623. { skip quote }
  624. if pc^ in quote then
  625. inc(pc);
  626. inc(count);
  627. until false;
  628. { create argc }
  629. argc:=count;
  630. { create an nil entry }
  631. argsbuf[count]:=nil;
  632. inc(count);
  633. { create the argv }
  634. getmem(argv,count shl 2);
  635. move(argsbuf,argv^,count shl 2);
  636. { Setup cmdline variable }
  637. cmdline:=GetCommandLine;
  638. end;
  639. {*****************************************************************************
  640. System Dependent Exit code
  641. *****************************************************************************}
  642. Procedure system_exit;
  643. begin
  644. if not IsConsole then
  645. begin
  646. Close(stderr);
  647. Close(stdout);
  648. { what about Input and Output ?? PM }
  649. end;
  650. end;
  651. {$ifdef dummy}
  652. Function SetUpStack : longint;
  653. { This routine does the following : }
  654. { returns the value of the initial SP - __stklen }
  655. begin
  656. asm
  657. pushl %ebx
  658. pushl %eax
  659. movl __stklen,%ebx
  660. movl %esp,%eax
  661. subl %ebx,%eax
  662. movl %eax,__RESULT
  663. popl %eax
  664. popl %ebx
  665. end;
  666. end;
  667. {$endif}
  668. procedure install_exception_handlers;forward;
  669. procedure PascalMain;external name 'PASCALMAIN';
  670. procedure fpc_do_exit;external name 'FPC_DO_EXIT';
  671. var
  672. { value of the stack segment
  673. to check if the call stack can be written on exceptions }
  674. _SS : longint;
  675. procedure Exe_entry;[public, alias : '_FPC_EXE_Entry'];
  676. begin
  677. IsLibrary:=false;
  678. { install the handlers for exe only ?
  679. or should we install them for DLL also ? (PM) }
  680. install_exception_handlers;
  681. { This strange construction is needed to solve the _SS problem
  682. with a smartlinked syswin32 (PFV) }
  683. asm
  684. pushl %ebp
  685. xorl %ebp,%ebp
  686. movl %esp,%eax
  687. movl %eax,Win32StackTop
  688. movw %ss,%bp
  689. movl %ebp,_SS
  690. xorl %ebp,%ebp
  691. call PASCALMAIN
  692. popl %ebp
  693. end;
  694. { if we pass here there was no error ! }
  695. ExitProcess(0);
  696. end;
  697. Const
  698. { DllEntryPoint }
  699. DLL_PROCESS_ATTACH = 1;
  700. DLL_THREAD_ATTACH = 2;
  701. DLL_PROCESS_DETACH = 0;
  702. DLL_THREAD_DETACH = 3;
  703. function Dll_entry : longbool;[public, alias : '_FPC_DLL_Entry'];
  704. var
  705. res : longbool;
  706. begin
  707. IsLibrary:=true;
  708. case DLLreason of
  709. DLL_PROCESS_ATTACH :
  710. begin
  711. asm
  712. movl %esp,%eax
  713. movl %eax,Win32StackTop
  714. xorl %edi,%edi
  715. movw %ss,%di
  716. movl %edi,_SS
  717. end;
  718. if assigned(Dll_Process_Attach_Hook) then
  719. begin
  720. res:=Dll_Process_Attach_Hook(DllParam);
  721. if not res then
  722. begin
  723. Dll_entry:=false;
  724. exit;
  725. end;
  726. end;
  727. PASCALMAIN;
  728. Dll_entry:=true;
  729. end;
  730. DLL_THREAD_ATTACH :
  731. begin
  732. inc(Thread_count);
  733. if assigned(Dll_Thread_Attach_Hook) then
  734. Dll_Thread_Attach_Hook(DllParam);
  735. Dll_entry:=true; { return value is ignored }
  736. end;
  737. DLL_THREAD_DETACH :
  738. begin
  739. dec(Thread_count);
  740. if assigned(Dll_Thread_Detach_Hook) then
  741. Dll_Thread_Detach_Hook(DllParam);
  742. Dll_entry:=true; { return value is ignored }
  743. end;
  744. DLL_PROCESS_DETACH :
  745. begin
  746. inc(Thread_count);
  747. Dll_entry:=true; { return value is ignored }
  748. FPC_DO_EXIT;
  749. if assigned(Dll_Process_Detach_Hook) then
  750. Dll_Process_Detach_Hook(DllParam);
  751. end;
  752. end;
  753. end;
  754. {$ifdef Set_i386_Exception_handler}
  755. const
  756. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  757. EXCEPTION_ACCESS_VIOLATION = $c0000005;
  758. EXCEPTION_BREAKPOINT = $80000003;
  759. EXCEPTION_DATATYPE_MISALIGNMENT = $80000002;
  760. EXCEPTION_SINGLE_STEP = $80000004;
  761. EXCEPTION_ARRAY_BOUNDS_EXCEEDED = $c000008c;
  762. EXCEPTION_FLT_DENORMAL_OPERAND = $c000008d;
  763. EXCEPTION_FLT_DIVIDE_BY_ZERO = $c000008e;
  764. EXCEPTION_FLT_INEXACT_RESULT = $c000008f;
  765. EXCEPTION_FLT_INVALID_OPERATION = $c0000090;
  766. EXCEPTION_FLT_OVERFLOW = $c0000091;
  767. EXCEPTION_FLT_STACK_CHECK = $c0000092;
  768. EXCEPTION_FLT_UNDERFLOW = $c0000093;
  769. EXCEPTION_INT_DIVIDE_BY_ZERO = $c0000094;
  770. EXCEPTION_INT_OVERFLOW = $c0000095;
  771. EXCEPTION_INVALID_HANDLE = $c0000008;
  772. EXCEPTION_PRIV_INSTRUCTION = $c0000096;
  773. EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025;
  774. EXCEPTION_NONCONTINUABLE = $1;
  775. EXCEPTION_STACK_OVERFLOW = $c00000fd;
  776. EXCEPTION_INVALID_DISPOSITION = $c0000026;
  777. ExceptionContinueExecution = 0;
  778. ExceptionContinueSearch = 1;
  779. type
  780. FLOATING_SAVE_AREA = record
  781. ControlWord : DWORD;
  782. StatusWord : DWORD;
  783. TagWord : DWORD;
  784. ErrorOffset : DWORD;
  785. ErrorSelector : DWORD;
  786. DataOffset : DWORD;
  787. DataSelector : DWORD;
  788. RegisterArea : array[0..79] of BYTE;
  789. Cr0NpxState : DWORD;
  790. end;
  791. _FLOATING_SAVE_AREA = FLOATING_SAVE_AREA;
  792. TFLOATINGSAVEAREA = FLOATING_SAVE_AREA;
  793. PFLOATINGSAVEAREA = ^FLOATING_SAVE_AREA;
  794. CONTEXT = record
  795. ContextFlags : DWORD;
  796. Dr0 : DWORD;
  797. Dr1 : DWORD;
  798. Dr2 : DWORD;
  799. Dr3 : DWORD;
  800. Dr6 : DWORD;
  801. Dr7 : DWORD;
  802. FloatSave : FLOATING_SAVE_AREA;
  803. SegGs : DWORD;
  804. SegFs : DWORD;
  805. SegEs : DWORD;
  806. SegDs : DWORD;
  807. Edi : DWORD;
  808. Esi : DWORD;
  809. Ebx : DWORD;
  810. Edx : DWORD;
  811. Ecx : DWORD;
  812. Eax : DWORD;
  813. Ebp : DWORD;
  814. Eip : DWORD;
  815. SegCs : DWORD;
  816. EFlags : DWORD;
  817. Esp : DWORD;
  818. SegSs : DWORD;
  819. end;
  820. LPCONTEXT = ^CONTEXT;
  821. _CONTEXT = CONTEXT;
  822. TCONTEXT = CONTEXT;
  823. PCONTEXT = ^CONTEXT;
  824. type pexception_record = ^exception_record;
  825. EXCEPTION_RECORD = record
  826. ExceptionCode : longint;
  827. ExceptionFlags : longint;
  828. ExceptionRecord : pexception_record;
  829. ExceptionAddress : pointer;
  830. NumberParameters : longint;
  831. ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of pointer;
  832. end;
  833. PEXCEPTION_POINTERS = ^EXCEPTION_POINTERS;
  834. EXCEPTION_POINTERS = record
  835. ExceptionRecord : PEXCEPTION_RECORD ;
  836. ContextRecord : PCONTEXT ;
  837. end;
  838. { type of functions that should be used for exception handling }
  839. LPTOP_LEVEL_EXCEPTION_FILTER = function(excep :PEXCEPTION_POINTERS) : longint;
  840. function SetUnhandledExceptionFilter(lpTopLevelExceptionFilter : LPTOP_LEVEL_EXCEPTION_FILTER)
  841. : LPTOP_LEVEL_EXCEPTION_FILTER;
  842. external 'kernel32' name 'SetUnhandledExceptionFilter';
  843. function syswin32_i386_exception_handler(excep :PEXCEPTION_POINTERS) : longint;
  844. var frame : longint;
  845. begin
  846. { default : unhandled !}
  847. if excep^.ContextRecord^.SegSs=_SS then
  848. frame:=excep^.ContextRecord^.Ebp
  849. else
  850. frame:=0;
  851. syswin32_i386_exception_handler:=ExceptionContinueSearch;
  852. case excep^.ExceptionRecord^.ExceptionCode of
  853. EXCEPTION_ACCESS_VIOLATION :
  854. HandleErrorFrame(216,frame);
  855. { EXCEPTION_BREAKPOINT = $80000003;
  856. EXCEPTION_DATATYPE_MISALIGNMENT = $80000002;
  857. EXCEPTION_SINGLE_STEP = $80000004; }
  858. EXCEPTION_ARRAY_BOUNDS_EXCEEDED :
  859. HandleErrorFrame(201,frame);
  860. { EXCEPTION_FLT_DENORMAL_OPERAND = $c000008d; }
  861. EXCEPTION_FLT_DIVIDE_BY_ZERO :
  862. HandleErrorFrame(200,frame);
  863. {EXCEPTION_FLT_INEXACT_RESULT = $c000008f;
  864. EXCEPTION_FLT_INVALID_OPERATION = $c0000090;}
  865. EXCEPTION_FLT_OVERFLOW :
  866. HandleErrorFrame(205,frame);
  867. EXCEPTION_FLT_STACK_CHECK :
  868. HandleErrorFrame(207,frame);
  869. { EXCEPTION_FLT_UNDERFLOW :
  870. HandleErrorFrame(206,frame); should be accepted as zero !! }
  871. EXCEPTION_INT_DIVIDE_BY_ZERO :
  872. HandleErrorFrame(200,frame);
  873. EXCEPTION_INT_OVERFLOW :
  874. HandleErrorFrame(215,frame);
  875. {EXCEPTION_INVALID_HANDLE = $c0000008;
  876. EXCEPTION_PRIV_INSTRUCTION = $c0000096;
  877. EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025;
  878. EXCEPTION_NONCONTINUABLE = $1;}
  879. EXCEPTION_STACK_OVERFLOW :
  880. HandleErrorFrame(202,frame);
  881. {EXCEPTION_INVALID_DISPOSITION = $c0000026;}
  882. end;
  883. end;
  884. procedure install_exception_handlers;
  885. begin
  886. SetUnhandledExceptionFilter(@syswin32_i386_exception_handler);
  887. end;
  888. {$else not i386 (Processor specific !!)}
  889. procedure install_exception_handlers;
  890. begin
  891. end;
  892. {$endif Set_i386_Exception_handler}
  893. {****************************************************************************
  894. Error Message writing using messageboxes
  895. ****************************************************************************}
  896. function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
  897. external 'user32' name 'MessageBoxA';
  898. const
  899. ErrorBufferLength = 1024;
  900. var
  901. ErrorBuf : array[0..ErrorBufferLength] of char;
  902. ErrorLen : longint;
  903. Function ErrorWrite(Var F: TextRec): Integer;
  904. {
  905. An error message should always end with #13#10#13#10
  906. }
  907. var
  908. p : pchar;
  909. i : longint;
  910. Begin
  911. if F.BufPos>0 then
  912. begin
  913. if F.BufPos+ErrorLen>ErrorBufferLength then
  914. i:=ErrorBufferLength-ErrorLen
  915. else
  916. i:=F.BufPos;
  917. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  918. inc(ErrorLen,i);
  919. ErrorBuf[ErrorLen]:=#0;
  920. end;
  921. if ErrorLen>3 then
  922. begin
  923. p:=@ErrorBuf[ErrorLen];
  924. for i:=1 to 4 do
  925. begin
  926. dec(p);
  927. if not(p^ in [#10,#13]) then
  928. break;
  929. end;
  930. end;
  931. if ErrorLen=ErrorBufferLength then
  932. i:=4;
  933. if (i=4) then
  934. begin
  935. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  936. ErrorLen:=0;
  937. end;
  938. F.BufPos:=0;
  939. ErrorWrite:=0;
  940. End;
  941. Function ErrorClose(Var F: TextRec): Integer;
  942. begin
  943. if ErrorLen>0 then
  944. begin
  945. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  946. ErrorLen:=0;
  947. end;
  948. ErrorLen:=0;
  949. ErrorClose:=0;
  950. end;
  951. Function ErrorOpen(Var F: TextRec): Integer;
  952. Begin
  953. TextRec(F).InOutFunc:=@ErrorWrite;
  954. TextRec(F).FlushFunc:=@ErrorWrite;
  955. TextRec(F).CloseFunc:=@ErrorClose;
  956. ErrorOpen:=0;
  957. End;
  958. procedure AssignError(Var T: Text);
  959. begin
  960. Assign(T,'');
  961. TextRec(T).OpenFunc:=@ErrorOpen;
  962. Rewrite(T);
  963. end;
  964. const
  965. Exe_entry_code : pointer = @Exe_entry;
  966. Dll_entry_code : pointer = @Dll_entry;
  967. begin
  968. { get some helpful informations }
  969. GetStartupInfo(@startupinfo);
  970. { some misc Win32 stuff }
  971. hprevinst:=0;
  972. if not IsLibrary then
  973. HInstance:=getmodulehandle(GetCommandFile);
  974. MainInstance:=HInstance;
  975. { No idea how to know this issue !! }
  976. IsMultithreaded:=false;
  977. cmdshow:=startupinfo.wshowwindow;
  978. { to test stack depth }
  979. loweststack:=maxlongint;
  980. { real test stack depth }
  981. { stacklimit := setupstack; }
  982. { Setup heap }
  983. InitHeap;
  984. InitExceptions;
  985. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  986. displayed in and messagebox }
  987. StdInputHandle:=longint(GetStdHandle(STD_INPUT_HANDLE));
  988. StdOutputHandle:=longint(GetStdHandle(STD_OUTPUT_HANDLE));
  989. StdErrorHandle:=longint(GetStdHandle(STD_ERROR_HANDLE));
  990. if not IsConsole then
  991. begin
  992. AssignError(stderr);
  993. AssignError(stdout);
  994. Assign(Output,'');
  995. Assign(Input,'');
  996. end
  997. else
  998. begin
  999. OpenStdIO(Input,fmInput,StdInputHandle);
  1000. OpenStdIO(Output,fmOutput,StdOutputHandle);
  1001. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  1002. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  1003. end;
  1004. { Arguments }
  1005. setup_arguments;
  1006. { Reset IO Error }
  1007. InOutRes:=0;
  1008. { Reset internal error variable }
  1009. errno:=0;
  1010. end.
  1011. {
  1012. $Log$
  1013. Revision 1.51 1999-12-01 22:57:31 peter
  1014. * cmdline support
  1015. Revision 1.50 1999/11/20 00:16:44 pierre
  1016. + DLL Hooks for the four callings added
  1017. Revision 1.49 1999/11/18 22:19:57 pierre
  1018. * bug fix for web bug703 and 704
  1019. Revision 1.48 1999/11/09 22:34:00 pierre
  1020. * Check ErrorBuf at exit
  1021. + Win32StackTop
  1022. Revision 1.47 1999/10/26 12:25:51 peter
  1023. * report stderr,stdout to message box for errors
  1024. * close input,output when GUI app is made
  1025. Revision 1.46 1999/10/22 14:47:19 peter
  1026. * allocate an extra byte for argv[0]
  1027. Revision 1.45 1999/10/03 19:39:05 peter
  1028. * fixed argv[0] length
  1029. Revision 1.44 1999/09/10 15:40:35 peter
  1030. * fixed do_open flags to be > $100, becuase filemode can be upto 255
  1031. Revision 1.43 1999/07/07 10:04:43 michael
  1032. + Small edit in paramstr
  1033. Revision 1.42 1999/07/07 09:43:16 michael
  1034. Better construction of commandline argv
  1035. Revision 1.41 1999/07/05 20:04:30 peter
  1036. * removed temp defines
  1037. Revision 1.40 1999/06/11 16:26:40 michael
  1038. + Fixed paramstr(0)
  1039. Revision 1.39 1999/05/17 21:52:47 florian
  1040. * most of the Object Pascal stuff moved to the system unit
  1041. Revision 1.38 1999/04/28 11:42:53 peter
  1042. + FileNameCaseSensetive boolean
  1043. Revision 1.37 1999/04/08 12:23:11 peter
  1044. * removed os.inc
  1045. Revision 1.36 1999/03/24 23:25:59 peter
  1046. * fixed file sharing
  1047. Revision 1.35 1999/03/12 00:07:48 pierre
  1048. + code for coff writer
  1049. Revision 1.34 1999/03/10 22:15:31 florian
  1050. + system.cmdline variable for go32v2 and win32 added
  1051. Revision 1.33 1999/01/18 10:05:57 pierre
  1052. + system_exit procedure added
  1053. Revision 1.32 1998/12/28 23:30:11 peter
  1054. * fixes for smartlinking
  1055. Revision 1.31 1998/12/28 15:50:51 peter
  1056. + stdout, which is needed when you write something in the system unit
  1057. to the screen. Like the runtime error
  1058. Revision 1.30 1998/12/21 14:28:23 pierre
  1059. * HandleError -> HandleErrorFrame to avoid problem in
  1060. assembler code in i386.inc
  1061. (call to overloaded function in assembler block !)
  1062. Revision 1.29 1998/12/15 22:43:14 peter
  1063. * removed temp symbols
  1064. Revision 1.28 1998/12/09 17:57:33 pierre
  1065. + exception handling by default
  1066. Revision 1.27 1998/12/01 14:00:08 pierre
  1067. + added conversion from exceptions into run time error
  1068. (only if syswin32 compiled with -ddebug for now !)
  1069. * added HandleErrorFrame(errno,frame)
  1070. where you specify the frame
  1071. needed for win32 exception handling
  1072. Revision 1.26 1998/11/30 13:13:41 pierre
  1073. * needs asw to link correctly wprt0 or wdllprt0 file
  1074. Revision 1.25 1998/11/30 09:16:58 pierre
  1075. + added the changes from Pavel Ozerski after several modifications
  1076. to be able to create DLLs
  1077. Revision 1.24 1998/11/16 15:48:54 peter
  1078. * fixed longbool returns for api calls
  1079. Revision 1.23 1998/11/16 14:14:58 pierre
  1080. * changed getdir(byte,string) to getdir(byte,shortstring)
  1081. Revision 1.22 1998/10/27 15:07:16 florian
  1082. + Is* flags added
  1083. + IsLibrary works also
  1084. Revision 1.21 1998/10/15 16:26:19 peter
  1085. + fpuinit
  1086. + end of backtrace indicator
  1087. Revision 1.20 1998/09/14 10:48:33 peter
  1088. * FPC_ names
  1089. * Heap manager is now system independent
  1090. Revision 1.19 1998/09/02 09:03:46 pierre
  1091. * do_open sometimes returns -1 as handle on fail
  1092. was not checked correctly
  1093. Revision 1.16 1998/08/24 14:45:22 pierre
  1094. * sbrk was wrong
  1095. heap growing now works for win32
  1096. Revision 1.15 1998/08/21 10:10:16 peter
  1097. * winheap turned off by default
  1098. Revision 1.14 1998/07/30 13:27:19 michael
  1099. + Added support for errorproc. Changed runerror to HandleError
  1100. Revision 1.13 1998/07/13 21:19:15 florian
  1101. * some problems with ansi string support fixed
  1102. Revision 1.12 1998/07/07 12:37:28 carl
  1103. * correct mapping of error codes for TP compatibility
  1104. + implemented stack checking in ifdef dummy
  1105. Revision 1.11 1998/07/02 12:33:18 carl
  1106. * IOCheck/InOutRes check for mkdir,rmdir and chdir like in TP
  1107. Revision 1.10 1998/07/01 15:30:02 peter
  1108. * better readln/writeln
  1109. Revision 1.9 1998/06/10 10:39:17 peter
  1110. * working w32 rtl
  1111. Revision 1.8 1998/06/08 23:07:47 peter
  1112. * dos interface is now 100% compatible
  1113. * fixed call PASCALMAIN which must be direct asm
  1114. Revision 1.7 1998/05/06 12:36:51 michael
  1115. + Removed log from before restored version.
  1116. Revision 1.6 1998/04/27 18:29:09 florian
  1117. + do_open implemented, the file-I/O should be now complete
  1118. Revision 1.5 1998/04/27 13:58:21 florian
  1119. + paramstr/paramcount implemented
  1120. Revision 1.4 1998/04/26 22:37:22 florian
  1121. * some small extensions
  1122. Revision 1.3 1998/04/26 21:49:57 florian
  1123. + more stuff added (??dir procedures etc.)
  1124. }