syswin32.pp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253
  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. 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. function paramcount : longint;
  180. begin
  181. paramcount := argc - 1;
  182. end;
  183. { module functions }
  184. function GetModuleFileName(l1:longint;p:pointer;l2:longint):longint;
  185. external 'kernel32' name 'GetModuleFileNameA';
  186. function GetModuleHandle(p : pointer) : longint;
  187. external 'kernel32' name 'GetModuleHandleA';
  188. function GetCommandFile:pchar;forward;
  189. function paramstr(l : longint) : string;
  190. begin
  191. if (l>=0) and (l<argc) then
  192. paramstr:=strpas(argv[l])
  193. else
  194. paramstr:='';
  195. end;
  196. procedure randomize;
  197. begin
  198. randseed:=GetTickCount;
  199. end;
  200. {*****************************************************************************
  201. Heap Management
  202. *****************************************************************************}
  203. { memory functions }
  204. function GlobalAlloc(mode,size:longint):longint;
  205. external 'kernel32' name 'GlobalAlloc';
  206. function GlobalLock(handle:longint):pointer;
  207. external 'kernel32' name 'GlobalLock';
  208. {$ifdef SYSTEMDEBUG}
  209. function GlobalSize(h:longint):longint;
  210. external 'kernel32' name 'GlobalSize';
  211. {$endif}
  212. var
  213. heap : longint;external name 'HEAP';
  214. intern_heapsize : longint;external name 'HEAPSIZE';
  215. function getheapstart:pointer;assembler;
  216. asm
  217. leal HEAP,%eax
  218. end ['EAX'];
  219. function getheapsize:longint;assembler;
  220. asm
  221. movl intern_HEAPSIZE,%eax
  222. end ['EAX'];
  223. function Sbrk(size : longint):longint;
  224. var
  225. h,l : longint;
  226. begin
  227. h:=GlobalAlloc(258,size);
  228. l:=longint(GlobalLock(h));
  229. if l=0 then
  230. l:=-1;
  231. {$ifdef DUMPGROW}
  232. Writeln('new heap part at $',hexstr(l,8), ' size = ',GlobalSize(h));
  233. {$endif}
  234. sbrk:=l;
  235. end;
  236. { include standard heap management }
  237. {$I heap.inc}
  238. {*****************************************************************************
  239. Low Level File Routines
  240. *****************************************************************************}
  241. function WriteFile(fh:longint;buf:pointer;len:longint;var loaded:longint;
  242. overlap:pointer):longint;
  243. external 'kernel32' name 'WriteFile';
  244. function ReadFile(fh:longint;buf:pointer;len:longint;var loaded:longint;
  245. overlap:pointer):longint;
  246. external 'kernel32' name 'ReadFile';
  247. function CloseHandle(h : longint) : longint;
  248. external 'kernel32' name 'CloseHandle';
  249. function DeleteFile(p : pchar) : longint;
  250. external 'kernel32' name 'DeleteFileA';
  251. function MoveFile(old,_new : pchar) : longint;
  252. external 'kernel32' name 'MoveFileA';
  253. function SetFilePointer(l1,l2 : longint;l3 : pointer;l4 : longint) : longint;
  254. external 'kernel32' name 'SetFilePointer';
  255. function GetFileSize(h:longint;p:pointer) : longint;
  256. external 'kernel32' name 'GetFileSize';
  257. function CreateFile(name : pointer;access,sharing : longint;
  258. security : pointer;how,attr,template : longint) : longint;
  259. external 'kernel32' name 'CreateFileA';
  260. function SetEndOfFile(h : longint) : longbool;
  261. external 'kernel32' name 'SetEndOfFile';
  262. function GetFileType(Handle:DWORD):DWord;
  263. external 'kernel32' name 'GetFileType';
  264. procedure AllowSlash(p:pchar);
  265. var
  266. i : longint;
  267. begin
  268. { allow slash as backslash }
  269. for i:=0 to strlen(p) do
  270. if p[i]='/' then p[i]:='\';
  271. end;
  272. function do_isdevice(handle:longint):boolean;
  273. begin
  274. do_isdevice:=(getfiletype(handle)=2);
  275. end;
  276. procedure do_close(h : longint);
  277. begin
  278. if do_isdevice(h) then
  279. exit;
  280. CloseHandle(h);
  281. end;
  282. procedure do_erase(p : pchar);
  283. begin
  284. AllowSlash(p);
  285. if DeleteFile(p)=0 then
  286. Begin
  287. errno:=GetLastError;
  288. Errno2InoutRes;
  289. end;
  290. end;
  291. procedure do_rename(p1,p2 : pchar);
  292. begin
  293. AllowSlash(p1);
  294. AllowSlash(p2);
  295. if MoveFile(p1,p2)=0 then
  296. Begin
  297. errno:=GetLastError;
  298. Errno2InoutRes;
  299. end;
  300. end;
  301. function do_write(h,addr,len : longint) : longint;
  302. var
  303. size:longint;
  304. begin
  305. if writefile(h,pointer(addr),len,size,nil)=0 then
  306. Begin
  307. errno:=GetLastError;
  308. Errno2InoutRes;
  309. end;
  310. do_write:=size;
  311. end;
  312. function do_read(h,addr,len : longint) : longint;
  313. var
  314. _result:longint;
  315. begin
  316. if readfile(h,pointer(addr),len,_result,nil)=0 then
  317. Begin
  318. errno:=GetLastError;
  319. Errno2InoutRes;
  320. end;
  321. do_read:=_result;
  322. end;
  323. function do_filepos(handle : longint) : longint;
  324. var
  325. l:longint;
  326. begin
  327. l:=SetFilePointer(handle,0,nil,FILE_CURRENT);
  328. if l=-1 then
  329. begin
  330. l:=0;
  331. errno:=GetLastError;
  332. Errno2InoutRes;
  333. end;
  334. do_filepos:=l;
  335. end;
  336. procedure do_seek(handle,pos : longint);
  337. begin
  338. if SetFilePointer(handle,pos,nil,FILE_BEGIN)=-1 then
  339. Begin
  340. errno:=GetLastError;
  341. Errno2InoutRes;
  342. end;
  343. end;
  344. function do_seekend(handle:longint):longint;
  345. begin
  346. do_seekend:=SetFilePointer(handle,0,nil,FILE_END);
  347. if do_seekend=-1 then
  348. begin
  349. errno:=GetLastError;
  350. Errno2InoutRes;
  351. end;
  352. end;
  353. function do_filesize(handle : longint) : longint;
  354. var
  355. aktfilepos : longint;
  356. begin
  357. aktfilepos:=do_filepos(handle);
  358. do_filesize:=do_seekend(handle);
  359. do_seek(handle,aktfilepos);
  360. end;
  361. procedure do_truncate (handle,pos:longint);
  362. begin
  363. do_seek(handle,pos);
  364. if not(SetEndOfFile(handle)) then
  365. begin
  366. errno:=GetLastError;
  367. Errno2InoutRes;
  368. end;
  369. end;
  370. procedure do_open(var f;p : pchar;flags:longint);
  371. {
  372. filerec and textrec have both handle and mode as the first items so
  373. they could use the same routine for opening/creating.
  374. when (flags and $100) the file will be append
  375. when (flags and $1000) the file will be truncate/rewritten
  376. when (flags and $10000) there is no check for close (needed for textfiles)
  377. }
  378. Const
  379. file_Share_Read = $00000001;
  380. file_Share_Write = $00000002;
  381. fmShareCompat = $00000000;
  382. fmShareExclusive = $10;
  383. fmShareDenyWrite = $20;
  384. fmShareDenyRead = $30;
  385. fmShareDenyNone = $40;
  386. Var
  387. shflags,
  388. oflags,cd : longint;
  389. begin
  390. AllowSlash(p);
  391. { close first if opened }
  392. if ((flags and $10000)=0) then
  393. begin
  394. case filerec(f).mode of
  395. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  396. fmclosed : ;
  397. else
  398. begin
  399. {not assigned}
  400. inoutres:=102;
  401. exit;
  402. end;
  403. end;
  404. end;
  405. { reset file handle }
  406. filerec(f).handle:=UnusedHandle;
  407. { convert filesharing }
  408. shflags:=0;
  409. if ((filemode and fmshareExclusive) = fmshareExclusive) then
  410. { no sharing }
  411. else
  412. if (filemode = fmShareCompat) or ((filemode and fmshareDenyWrite) = fmshareDenyWrite) then
  413. shflags := file_Share_Read
  414. else
  415. if ((filemode and fmshareDenyRead) = fmshareDenyRead) then
  416. shflags := file_Share_Write
  417. else
  418. if ((filemode and fmshareDenyNone) = fmshareDenyNone) then
  419. shflags := file_Share_Read + file_Share_Write;
  420. { convert filemode to filerec modes }
  421. case (flags and 3) of
  422. 0 : begin
  423. filerec(f).mode:=fminput;
  424. oflags:=GENERIC_READ;
  425. end;
  426. 1 : begin
  427. filerec(f).mode:=fmoutput;
  428. oflags:=GENERIC_WRITE;
  429. end;
  430. 2 : begin
  431. filerec(f).mode:=fminout;
  432. oflags:=GENERIC_WRITE or GENERIC_READ;
  433. end;
  434. end;
  435. { standard is opening and existing file }
  436. cd:=OPEN_EXISTING;
  437. { create it ? }
  438. if (flags and $1000)<>0 then
  439. cd:=CREATE_ALWAYS
  440. { or append ? }
  441. else
  442. if (flags and $100)<>0 then
  443. cd:=OPEN_ALWAYS;
  444. { empty name is special }
  445. if p[0]=#0 then
  446. begin
  447. case FileRec(f).mode of
  448. fminput :
  449. FileRec(f).Handle:=StdInputHandle;
  450. fminout, { this is set by rewrite }
  451. fmoutput :
  452. FileRec(f).Handle:=StdOutputHandle;
  453. fmappend :
  454. begin
  455. FileRec(f).Handle:=StdOutputHandle;
  456. FileRec(f).mode:=fmoutput; {fool fmappend}
  457. end;
  458. end;
  459. exit;
  460. end;
  461. filerec(f).handle:=CreateFile(p,oflags,shflags,nil,cd,FILE_ATTRIBUTE_NORMAL,0);
  462. { append mode }
  463. if (flags and $100)<>0 then
  464. begin
  465. do_seekend(filerec(f).handle);
  466. filerec(f).mode:=fmoutput; {fool fmappend}
  467. end;
  468. { get errors }
  469. { handle -1 is returned sometimes !! (PM) }
  470. if (filerec(f).handle=0) or (filerec(f).handle=-1) then
  471. begin
  472. errno:=GetLastError;
  473. Errno2InoutRes;
  474. end;
  475. end;
  476. {*****************************************************************************
  477. UnTyped File Handling
  478. *****************************************************************************}
  479. {$i file.inc}
  480. {*****************************************************************************
  481. Typed File Handling
  482. *****************************************************************************}
  483. {$i typefile.inc}
  484. {*****************************************************************************
  485. Text File Handling
  486. *****************************************************************************}
  487. {$DEFINE EOF_CTRLZ}
  488. {$i text.inc}
  489. {*****************************************************************************
  490. Directory Handling
  491. *****************************************************************************}
  492. function CreateDirectory(name : pointer;sec : pointer) : longint;
  493. external 'kernel32' name 'CreateDirectoryA';
  494. function RemoveDirectory(name:pointer):longint;
  495. external 'kernel32' name 'RemoveDirectoryA';
  496. function SetCurrentDirectory(name : pointer) : longint;
  497. external 'kernel32' name 'SetCurrentDirectoryA';
  498. function GetCurrentDirectory(bufsize : longint;name : pchar) : longint;
  499. external 'kernel32' name 'GetCurrentDirectoryA';
  500. type
  501. TDirFnType=function(name:pointer):word;
  502. procedure dirfn(afunc : TDirFnType;const s:string);
  503. var
  504. buffer : array[0..255] of char;
  505. begin
  506. move(s[1],buffer,length(s));
  507. buffer[length(s)]:=#0;
  508. AllowSlash(pchar(@buffer));
  509. if aFunc(@buffer)=0 then
  510. begin
  511. errno:=GetLastError;
  512. Errno2InoutRes;
  513. end;
  514. end;
  515. function CreateDirectoryTrunc(name:pointer):word;
  516. begin
  517. CreateDirectoryTrunc:=CreateDirectory(name,nil);
  518. end;
  519. procedure mkdir(const s:string);[IOCHECK];
  520. begin
  521. If InOutRes <> 0 then exit;
  522. dirfn(TDirFnType(@CreateDirectoryTrunc),s);
  523. end;
  524. procedure rmdir(const s:string);[IOCHECK];
  525. begin
  526. If InOutRes <> 0 then exit;
  527. dirfn(TDirFnType(@RemoveDirectory),s);
  528. end;
  529. procedure chdir(const s:string);[IOCHECK];
  530. begin
  531. If InOutRes <> 0 then exit;
  532. dirfn(TDirFnType(@SetCurrentDirectory),s);
  533. end;
  534. procedure getdir(drivenr:byte;var dir:shortstring);
  535. const
  536. Drive:array[0..3]of char=(#0,':',#0,#0);
  537. var
  538. defaultdrive:boolean;
  539. DirBuf,SaveBuf:array[0..259] of Char;
  540. begin
  541. defaultdrive:=drivenr=0;
  542. if not defaultdrive then
  543. begin
  544. byte(Drive[0]):=Drivenr+64;
  545. GetCurrentDirectory(SizeOf(SaveBuf),SaveBuf);
  546. SetCurrentDirectory(@Drive);
  547. end;
  548. GetCurrentDirectory(SizeOf(DirBuf),DirBuf);
  549. if not defaultdrive then
  550. SetCurrentDirectory(@SaveBuf);
  551. dir:=strpas(DirBuf);
  552. if not FileNameCaseSensitive then
  553. dir:=upcase(dir);
  554. end;
  555. {*****************************************************************************
  556. SystemUnit Initialization
  557. *****************************************************************************}
  558. { Startup }
  559. procedure GetStartupInfo(p : pointer);
  560. external 'kernel32' name 'GetStartupInfoA';
  561. function GetStdHandle(nStdHandle:DWORD):THANDLE;
  562. external 'kernel32' name 'GetStdHandle';
  563. { command line/enviroment functions }
  564. function GetCommandLine : pchar;
  565. external 'kernel32' name 'GetCommandLineA';
  566. var
  567. ModuleName : array[0..255] of char;
  568. function GetCommandFile:pchar;
  569. begin
  570. GetModuleFileName(0,@ModuleName,255);
  571. GetCommandFile:=@ModuleName;
  572. end;
  573. procedure setup_arguments;
  574. var
  575. arglen,
  576. count : longint;
  577. argstart,
  578. pc : pchar;
  579. quote : set of char;
  580. argsbuf : array[0..127] of pchar;
  581. begin
  582. { create commandline, it starts with the executed filename which is argv[0] }
  583. { Win32 passes the command NOT via the args, but via getmodulefilename}
  584. count:=0;
  585. pc:=getcommandfile;
  586. Arglen:=0;
  587. repeat
  588. Inc(Arglen);
  589. until (pc[Arglen]=#0);
  590. getmem(argsbuf[count],arglen+1);
  591. move(pc^,argsbuf[count]^,arglen);
  592. { Now skip the first one }
  593. pc:=GetCommandLine;
  594. repeat
  595. { skip leading spaces }
  596. while pc^ in [' ',#9,#13] do
  597. inc(pc);
  598. case pc^ of
  599. #0 : break;
  600. '"' : begin
  601. quote:=['"'];
  602. inc(pc);
  603. end;
  604. '''' : begin
  605. quote:=[''''];
  606. inc(pc);
  607. end;
  608. else
  609. quote:=[' ',#9,#13];
  610. end;
  611. { scan until the end of the argument }
  612. argstart:=pc;
  613. while (pc^<>#0) and not(pc^ in quote) do
  614. inc(pc);
  615. { Don't copy the first one, it is already there.}
  616. If Count<>0 then
  617. begin
  618. { reserve some memory }
  619. arglen:=pc-argstart;
  620. getmem(argsbuf[count],arglen+1);
  621. move(argstart^,argsbuf[count]^,arglen);
  622. argsbuf[count][arglen]:=#0;
  623. end;
  624. { skip quote }
  625. if pc^ in quote then
  626. inc(pc);
  627. inc(count);
  628. until false;
  629. { create argc }
  630. argc:=count;
  631. { create an nil entry }
  632. argsbuf[count]:=nil;
  633. inc(count);
  634. { create the argv }
  635. getmem(argv,count shl 2);
  636. move(argsbuf,argv^,count shl 2);
  637. { Setup cmdline variable }
  638. cmdline:=GetCommandLine;
  639. end;
  640. {*****************************************************************************
  641. System Dependent Exit code
  642. *****************************************************************************}
  643. procedure install_exception_handlers;forward;
  644. procedure remove_exception_handlers;forward;
  645. procedure PascalMain;external name 'PASCALMAIN';
  646. procedure fpc_do_exit;external name 'FPC_DO_EXIT';
  647. Procedure ExitDLL(Exitcode : longint); forward;
  648. Procedure system_exit;
  649. begin
  650. { don't call ExitProcess inside
  651. the DLL exit code !!
  652. This crashes Win95 at least PM }
  653. if IsLibrary then
  654. ExitDLL(ExitCode);
  655. if not IsConsole then
  656. begin
  657. Close(stderr);
  658. Close(stdout);
  659. { what about Input and Output ?? PM }
  660. end;
  661. remove_exception_handlers;
  662. ExitProcess(ExitCode);
  663. end;
  664. {$ifdef dummy}
  665. Function SetUpStack : longint;
  666. { This routine does the following : }
  667. { returns the value of the initial SP - __stklen }
  668. begin
  669. asm
  670. pushl %ebx
  671. pushl %eax
  672. movl __stklen,%ebx
  673. movl %esp,%eax
  674. subl %ebx,%eax
  675. movl %eax,__RESULT
  676. popl %eax
  677. popl %ebx
  678. end;
  679. end;
  680. {$endif}
  681. var
  682. { value of the stack segment
  683. to check if the call stack can be written on exceptions }
  684. _SS : longint;
  685. procedure Exe_entry;[public, alias : '_FPC_EXE_Entry'];
  686. begin
  687. IsLibrary:=false;
  688. { install the handlers for exe only ?
  689. or should we install them for DLL also ? (PM) }
  690. install_exception_handlers;
  691. { This strange construction is needed to solve the _SS problem
  692. with a smartlinked syswin32 (PFV) }
  693. asm
  694. pushl %ebp
  695. xorl %ebp,%ebp
  696. movl %esp,%eax
  697. movl %eax,Win32StackTop
  698. movw %ss,%bp
  699. movl %ebp,_SS
  700. xorl %ebp,%ebp
  701. call PASCALMAIN
  702. popl %ebp
  703. end;
  704. { if we pass here there was no error ! }
  705. system_exit;
  706. end;
  707. Const
  708. { DllEntryPoint }
  709. DLL_PROCESS_ATTACH = 1;
  710. DLL_THREAD_ATTACH = 2;
  711. DLL_PROCESS_DETACH = 0;
  712. DLL_THREAD_DETACH = 3;
  713. Var
  714. DLLBuf : Jmp_buf;
  715. Const
  716. DLLExitOK : boolean = true;
  717. function Dll_entry : longbool;[public, alias : '_FPC_DLL_Entry'];
  718. var
  719. res : longbool;
  720. begin
  721. IsLibrary:=true;
  722. Dll_entry:=false;
  723. case DLLreason of
  724. DLL_PROCESS_ATTACH :
  725. begin
  726. If SetJmp(DLLBuf) = 0 then
  727. begin
  728. if assigned(Dll_Process_Attach_Hook) then
  729. begin
  730. res:=Dll_Process_Attach_Hook(DllParam);
  731. if not res then
  732. exit(false);
  733. end;
  734. PASCALMAIN;
  735. Dll_entry:=true;
  736. end
  737. else
  738. Dll_entry:=DLLExitOK;
  739. end;
  740. DLL_THREAD_ATTACH :
  741. begin
  742. inc(Thread_count);
  743. if assigned(Dll_Thread_Attach_Hook) then
  744. Dll_Thread_Attach_Hook(DllParam);
  745. Dll_entry:=true; { return value is ignored }
  746. end;
  747. DLL_THREAD_DETACH :
  748. begin
  749. dec(Thread_count);
  750. if assigned(Dll_Thread_Detach_Hook) then
  751. Dll_Thread_Detach_Hook(DllParam);
  752. Dll_entry:=true; { return value is ignored }
  753. end;
  754. DLL_PROCESS_DETACH :
  755. begin
  756. Dll_entry:=true; { return value is ignored }
  757. If SetJmp(DLLBuf) = 0 then
  758. begin
  759. FPC_DO_EXIT;
  760. end;
  761. if assigned(Dll_Process_Detach_Hook) then
  762. Dll_Process_Detach_Hook(DllParam);
  763. end;
  764. end;
  765. end;
  766. Procedure ExitDLL(Exitcode : longint);
  767. begin
  768. DLLExitOK:=ExitCode=0;
  769. LongJmp(DLLBuf,1);
  770. end;
  771. {$ifdef Set_i386_Exception_handler}
  772. const
  773. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  774. EXCEPTION_ACCESS_VIOLATION = $c0000005;
  775. EXCEPTION_BREAKPOINT = $80000003;
  776. EXCEPTION_DATATYPE_MISALIGNMENT = $80000002;
  777. EXCEPTION_SINGLE_STEP = $80000004;
  778. EXCEPTION_ARRAY_BOUNDS_EXCEEDED = $c000008c;
  779. EXCEPTION_FLT_DENORMAL_OPERAND = $c000008d;
  780. EXCEPTION_FLT_DIVIDE_BY_ZERO = $c000008e;
  781. EXCEPTION_FLT_INEXACT_RESULT = $c000008f;
  782. EXCEPTION_FLT_INVALID_OPERATION = $c0000090;
  783. EXCEPTION_FLT_OVERFLOW = $c0000091;
  784. EXCEPTION_FLT_STACK_CHECK = $c0000092;
  785. EXCEPTION_FLT_UNDERFLOW = $c0000093;
  786. EXCEPTION_INT_DIVIDE_BY_ZERO = $c0000094;
  787. EXCEPTION_INT_OVERFLOW = $c0000095;
  788. EXCEPTION_INVALID_HANDLE = $c0000008;
  789. EXCEPTION_PRIV_INSTRUCTION = $c0000096;
  790. EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025;
  791. EXCEPTION_NONCONTINUABLE = $1;
  792. EXCEPTION_STACK_OVERFLOW = $c00000fd;
  793. EXCEPTION_INVALID_DISPOSITION = $c0000026;
  794. EXCEPTION_ILLEGAL_INSTRUCTION = $C000001D;
  795. EXCEPTION_IN_PAGE_ERROR = $C0000006;
  796. ExceptionContinueExecution = 0;
  797. ExceptionContinueSearch = 1;
  798. type
  799. FLOATING_SAVE_AREA = record
  800. ControlWord : DWORD;
  801. StatusWord : DWORD;
  802. TagWord : DWORD;
  803. ErrorOffset : DWORD;
  804. ErrorSelector : DWORD;
  805. DataOffset : DWORD;
  806. DataSelector : DWORD;
  807. RegisterArea : array[0..79] of BYTE;
  808. Cr0NpxState : DWORD;
  809. end;
  810. _FLOATING_SAVE_AREA = FLOATING_SAVE_AREA;
  811. TFLOATINGSAVEAREA = FLOATING_SAVE_AREA;
  812. PFLOATINGSAVEAREA = ^FLOATING_SAVE_AREA;
  813. CONTEXT = record
  814. ContextFlags : DWORD;
  815. Dr0 : DWORD;
  816. Dr1 : DWORD;
  817. Dr2 : DWORD;
  818. Dr3 : DWORD;
  819. Dr6 : DWORD;
  820. Dr7 : DWORD;
  821. FloatSave : FLOATING_SAVE_AREA;
  822. SegGs : DWORD;
  823. SegFs : DWORD;
  824. SegEs : DWORD;
  825. SegDs : DWORD;
  826. Edi : DWORD;
  827. Esi : DWORD;
  828. Ebx : DWORD;
  829. Edx : DWORD;
  830. Ecx : DWORD;
  831. Eax : DWORD;
  832. Ebp : DWORD;
  833. Eip : DWORD;
  834. SegCs : DWORD;
  835. EFlags : DWORD;
  836. Esp : DWORD;
  837. SegSs : DWORD;
  838. end;
  839. LPCONTEXT = ^CONTEXT;
  840. _CONTEXT = CONTEXT;
  841. TCONTEXT = CONTEXT;
  842. PCONTEXT = ^CONTEXT;
  843. type pexception_record = ^exception_record;
  844. EXCEPTION_RECORD = record
  845. ExceptionCode : longint;
  846. ExceptionFlags : longint;
  847. ExceptionRecord : pexception_record;
  848. ExceptionAddress : pointer;
  849. NumberParameters : longint;
  850. ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of pointer;
  851. end;
  852. PEXCEPTION_POINTERS = ^EXCEPTION_POINTERS;
  853. EXCEPTION_POINTERS = record
  854. ExceptionRecord : PEXCEPTION_RECORD ;
  855. ContextRecord : PCONTEXT ;
  856. end;
  857. { type of functions that should be used for exception handling }
  858. LPTOP_LEVEL_EXCEPTION_FILTER = function(excep :PEXCEPTION_POINTERS) : longint;
  859. function SetUnhandledExceptionFilter(lpTopLevelExceptionFilter : LPTOP_LEVEL_EXCEPTION_FILTER)
  860. : LPTOP_LEVEL_EXCEPTION_FILTER;
  861. external 'kernel32' name 'SetUnhandledExceptionFilter';
  862. function syswin32_i386_exception_handler(excep :PEXCEPTION_POINTERS) : longint;
  863. var frame : longint;
  864. begin
  865. { default : unhandled !}
  866. if excep^.ContextRecord^.SegSs=_SS then
  867. frame:=excep^.ContextRecord^.Ebp
  868. else
  869. frame:=0;
  870. syswin32_i386_exception_handler:=ExceptionContinueSearch;
  871. case excep^.ExceptionRecord^.ExceptionCode of
  872. EXCEPTION_ACCESS_VIOLATION :
  873. HandleErrorFrame(216,frame);
  874. { EXCEPTION_BREAKPOINT = $80000003;
  875. EXCEPTION_DATATYPE_MISALIGNMENT = $80000002;
  876. EXCEPTION_SINGLE_STEP = $80000004; }
  877. EXCEPTION_ARRAY_BOUNDS_EXCEEDED :
  878. HandleErrorFrame(201,frame);
  879. { EXCEPTION_FLT_DENORMAL_OPERAND = $c000008d; }
  880. EXCEPTION_FLT_DIVIDE_BY_ZERO :
  881. HandleErrorFrame(200,frame);
  882. {EXCEPTION_FLT_INEXACT_RESULT = $c000008f;
  883. EXCEPTION_FLT_INVALID_OPERATION = $c0000090;}
  884. EXCEPTION_FLT_OVERFLOW :
  885. HandleErrorFrame(205,frame);
  886. EXCEPTION_FLT_STACK_CHECK :
  887. HandleErrorFrame(207,frame);
  888. { EXCEPTION_FLT_UNDERFLOW :
  889. HandleErrorFrame(206,frame); should be accepted as zero !! }
  890. EXCEPTION_INT_DIVIDE_BY_ZERO :
  891. HandleErrorFrame(200,frame);
  892. EXCEPTION_INT_OVERFLOW :
  893. HandleErrorFrame(215,frame);
  894. {EXCEPTION_INVALID_HANDLE = $c0000008;
  895. EXCEPTION_PRIV_INSTRUCTION = $c0000096;
  896. EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025;
  897. EXCEPTION_NONCONTINUABLE = $1;}
  898. EXCEPTION_STACK_OVERFLOW :
  899. HandleErrorFrame(202,frame);
  900. {EXCEPTION_INVALID_DISPOSITION = $c0000026;}
  901. EXCEPTION_ILLEGAL_INSTRUCTION,
  902. EXCEPTION_IN_PAGE_ERROR,
  903. EXCEPTION_SINGLE_STEP : HandleErrorFrame(217,frame)
  904. end;
  905. end;
  906. procedure install_exception_handlers;
  907. begin
  908. SetUnhandledExceptionFilter(@syswin32_i386_exception_handler);
  909. end;
  910. procedure remove_exception_handlers;
  911. begin
  912. SetUnhandledExceptionFilter(nil);
  913. end;
  914. {$else not i386 (Processor specific !!)}
  915. procedure install_exception_handlers;
  916. begin
  917. end;
  918. procedure remove_exception_handlers;
  919. begin
  920. end;
  921. {$endif Set_i386_Exception_handler}
  922. {****************************************************************************
  923. Error Message writing using messageboxes
  924. ****************************************************************************}
  925. function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
  926. external 'user32' name 'MessageBoxA';
  927. const
  928. ErrorBufferLength = 1024;
  929. var
  930. ErrorBuf : array[0..ErrorBufferLength] of char;
  931. ErrorLen : longint;
  932. Function ErrorWrite(Var F: TextRec): Integer;
  933. {
  934. An error message should always end with #13#10#13#10
  935. }
  936. var
  937. p : pchar;
  938. i : longint;
  939. Begin
  940. if F.BufPos>0 then
  941. begin
  942. if F.BufPos+ErrorLen>ErrorBufferLength then
  943. i:=ErrorBufferLength-ErrorLen
  944. else
  945. i:=F.BufPos;
  946. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  947. inc(ErrorLen,i);
  948. ErrorBuf[ErrorLen]:=#0;
  949. end;
  950. if ErrorLen>3 then
  951. begin
  952. p:=@ErrorBuf[ErrorLen];
  953. for i:=1 to 4 do
  954. begin
  955. dec(p);
  956. if not(p^ in [#10,#13]) then
  957. break;
  958. end;
  959. end;
  960. if ErrorLen=ErrorBufferLength then
  961. i:=4;
  962. if (i=4) then
  963. begin
  964. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  965. ErrorLen:=0;
  966. end;
  967. F.BufPos:=0;
  968. ErrorWrite:=0;
  969. End;
  970. Function ErrorClose(Var F: TextRec): Integer;
  971. begin
  972. if ErrorLen>0 then
  973. begin
  974. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  975. ErrorLen:=0;
  976. end;
  977. ErrorLen:=0;
  978. ErrorClose:=0;
  979. end;
  980. Function ErrorOpen(Var F: TextRec): Integer;
  981. Begin
  982. TextRec(F).InOutFunc:=@ErrorWrite;
  983. TextRec(F).FlushFunc:=@ErrorWrite;
  984. TextRec(F).CloseFunc:=@ErrorClose;
  985. ErrorOpen:=0;
  986. End;
  987. procedure AssignError(Var T: Text);
  988. begin
  989. Assign(T,'');
  990. TextRec(T).OpenFunc:=@ErrorOpen;
  991. Rewrite(T);
  992. end;
  993. const
  994. Exe_entry_code : pointer = @Exe_entry;
  995. Dll_entry_code : pointer = @Dll_entry;
  996. begin
  997. { get some helpful informations }
  998. GetStartupInfo(@startupinfo);
  999. { some misc Win32 stuff }
  1000. hprevinst:=0;
  1001. if not IsLibrary then
  1002. HInstance:=getmodulehandle(GetCommandFile);
  1003. MainInstance:=HInstance;
  1004. { No idea how to know this issue !! }
  1005. IsMultithreaded:=false;
  1006. cmdshow:=startupinfo.wshowwindow;
  1007. { to test stack depth }
  1008. loweststack:=maxlongint;
  1009. { real test stack depth }
  1010. { stacklimit := setupstack; }
  1011. { Setup heap }
  1012. InitHeap;
  1013. InitExceptions;
  1014. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  1015. displayed in and messagebox }
  1016. StdInputHandle:=longint(GetStdHandle(STD_INPUT_HANDLE));
  1017. StdOutputHandle:=longint(GetStdHandle(STD_OUTPUT_HANDLE));
  1018. StdErrorHandle:=longint(GetStdHandle(STD_ERROR_HANDLE));
  1019. if not IsConsole then
  1020. begin
  1021. AssignError(stderr);
  1022. AssignError(stdout);
  1023. Assign(Output,'');
  1024. Assign(Input,'');
  1025. end
  1026. else
  1027. begin
  1028. OpenStdIO(Input,fmInput,StdInputHandle);
  1029. OpenStdIO(Output,fmOutput,StdOutputHandle);
  1030. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  1031. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  1032. end;
  1033. { Arguments }
  1034. setup_arguments;
  1035. { Reset IO Error }
  1036. InOutRes:=0;
  1037. { Reset internal error variable }
  1038. errno:=0;
  1039. end.
  1040. {
  1041. $Log$
  1042. Revision 1.62 2000-03-16 20:42:26 michael
  1043. + Added more system exception handling afte T. Schatzl remark
  1044. Revision 1.61 2000/03/10 09:21:11 pierre
  1045. * ExitDLL fixed : uses now SetJmp LongJmp
  1046. * System_exit unloads the exception hanlder before leaving
  1047. Revision 1.60 2000/02/09 16:59:34 peter
  1048. * truncated log
  1049. Revision 1.59 2000/02/09 12:24:39 peter
  1050. * halt moved to system.inc
  1051. Revision 1.58 2000/01/20 23:38:02 peter
  1052. * support fm_inout as stdoutput for assign(f,'');rewrite(f,1); becuase
  1053. rewrite opens always with filemode 2
  1054. Revision 1.57 2000/01/18 09:03:04 pierre
  1055. * DLL crash fixed : ExitProcess can not be called in DLL system_exit
  1056. Problem : Halt or RunError code inside DLL will return to caller !!
  1057. * Changed the "if h<4 then" into "if do_isdevice(h) then " in do_close
  1058. to avoid closing of standard files
  1059. Revision 1.56 2000/01/16 23:05:03 peter
  1060. * fixed typo
  1061. Revision 1.55 2000/01/16 22:25:38 peter
  1062. * check handle for file closing
  1063. Revision 1.54 2000/01/07 16:41:52 daniel
  1064. * copyright 2000
  1065. Revision 1.53 2000/01/07 16:32:34 daniel
  1066. * copyright 2000 added
  1067. Revision 1.52 2000/01/06 23:40:36 peter
  1068. * fixed exitprocess call, it's now in system_exit and uses exitcode
  1069. Revision 1.51 1999/12/01 22:57:31 peter
  1070. * cmdline support
  1071. Revision 1.50 1999/11/20 00:16:44 pierre
  1072. + DLL Hooks for the four callings added
  1073. Revision 1.49 1999/11/18 22:19:57 pierre
  1074. * bug fix for web bug703 and 704
  1075. Revision 1.48 1999/11/09 22:34:00 pierre
  1076. * Check ErrorBuf at exit
  1077. + Win32StackTop
  1078. Revision 1.47 1999/10/26 12:25:51 peter
  1079. * report stderr,stdout to message box for errors
  1080. * close input,output when GUI app is made
  1081. Revision 1.46 1999/10/22 14:47:19 peter
  1082. * allocate an extra byte for argv[0]
  1083. Revision 1.45 1999/10/03 19:39:05 peter
  1084. * fixed argv[0] length
  1085. Revision 1.44 1999/09/10 15:40:35 peter
  1086. * fixed do_open flags to be > $100, becuase filemode can be upto 255
  1087. }