syswin32.pp 33 KB

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