syswin.inc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2008 by Florian Klaempfl and Pavel Ozerski
  4. member of the Free Pascal development team.
  5. FPC Pascal system unit part shared by win32/win64.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {
  13. Error code definitions for the Win32 API functions
  14. Values are 32 bit values layed out as follows:
  15. 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  16. 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
  17. +---+-+-+-----------------------+-------------------------------+
  18. |Sev|C|R| Facility | Code |
  19. +---+-+-+-----------------------+-------------------------------+
  20. where
  21. Sev - is the severity code
  22. 00 - Success
  23. 01 - Informational
  24. 10 - Warning
  25. 11 - Error
  26. C - is the Customer code flag
  27. R - is a reserved bit
  28. Facility - is the facility code
  29. Code - is the facility's status code
  30. }
  31. const
  32. SEVERITY_SUCCESS = $00000000;
  33. SEVERITY_INFORMATIONAL = $40000000;
  34. SEVERITY_WARNING = $80000000;
  35. SEVERITY_ERROR = $C0000000;
  36. const
  37. STATUS_SEGMENT_NOTIFICATION = $40000005;
  38. DBG_TERMINATE_THREAD = $40010003;
  39. DBG_TERMINATE_PROCESS = $40010004;
  40. DBG_CONTROL_C = $40010005;
  41. DBG_CONTROL_BREAK = $40010008;
  42. STATUS_GUARD_PAGE_VIOLATION = $80000001;
  43. STATUS_DATATYPE_MISALIGNMENT = $80000002;
  44. STATUS_BREAKPOINT = $80000003;
  45. STATUS_SINGLE_STEP = $80000004;
  46. DBG_EXCEPTION_NOT_HANDLED = $80010001;
  47. STATUS_ACCESS_VIOLATION = $C0000005;
  48. STATUS_IN_PAGE_ERROR = $C0000006;
  49. STATUS_INVALID_HANDLE = $C0000008;
  50. STATUS_NO_MEMORY = $C0000017;
  51. STATUS_ILLEGAL_INSTRUCTION = $C000001D;
  52. STATUS_NONCONTINUABLE_EXCEPTION = $C0000025;
  53. STATUS_INVALID_DISPOSITION = $C0000026;
  54. STATUS_ARRAY_BOUNDS_EXCEEDED = $C000008C;
  55. STATUS_FLOAT_DENORMAL_OPERAND = $C000008D;
  56. STATUS_FLOAT_DIVIDE_BY_ZERO = $C000008E;
  57. STATUS_FLOAT_INEXACT_RESULT = $C000008F;
  58. STATUS_FLOAT_INVALID_OPERATION = $C0000090;
  59. STATUS_FLOAT_OVERFLOW = $C0000091;
  60. STATUS_FLOAT_STACK_CHECK = $C0000092;
  61. STATUS_FLOAT_UNDERFLOW = $C0000093;
  62. STATUS_INTEGER_DIVIDE_BY_ZERO = $C0000094;
  63. STATUS_INTEGER_OVERFLOW = $C0000095;
  64. STATUS_PRIVILEGED_INSTRUCTION = $C0000096;
  65. STATUS_STACK_OVERFLOW = $C00000FD;
  66. STATUS_CONTROL_C_EXIT = $C000013A;
  67. STATUS_FLOAT_MULTIPLE_FAULTS = $C00002B4;
  68. STATUS_FLOAT_MULTIPLE_TRAPS = $C00002B5;
  69. STATUS_REG_NAT_CONSUMPTION = $C00002C9;
  70. { Exceptions raised by RTL use this code }
  71. FPC_EXCEPTION_CODE = $E0465043;
  72. EXCEPTION_EXECUTE_HANDLER = 1;
  73. EXCEPTION_CONTINUE_EXECUTION = -1;
  74. EXCEPTION_CONTINUE_SEARCH = 0;
  75. { exception flags (not everything applies to Win32!) }
  76. EXCEPTION_NONCONTINUABLE = $01;
  77. EXCEPTION_UNWINDING = $02;
  78. EXCEPTION_EXIT_UNWIND = $04;
  79. EXCEPTION_STACK_INVALID = $08;
  80. EXCEPTION_NESTED_CALL = $10;
  81. EXCEPTION_TARGET_UNWIND = $20;
  82. EXCEPTION_COLLIDED_UNWIND = $40;
  83. CONTEXT_X86 = $00010000;
  84. CONTEXT_CONTROL = CONTEXT_X86 or $00000001;
  85. CONTEXT_INTEGER = CONTEXT_X86 or $00000002;
  86. CONTEXT_SEGMENTS = CONTEXT_X86 or $00000004;
  87. CONTEXT_FLOATING_POINT = CONTEXT_X86 or $00000008;
  88. CONTEXT_DEBUG_REGISTERS = CONTEXT_X86 or $00000010;
  89. CONTEXT_EXTENDED_REGISTERS = CONTEXT_X86 or $00000020;
  90. CONTEXT_FULL = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
  91. MAXIMUM_SUPPORTED_EXTENSION = 512;
  92. type
  93. EXCEPTION_DISPOSITION=(
  94. ExceptionContinueExecution,
  95. ExceptionContinueSearch,
  96. ExceptionNestedException,
  97. ExceptionCollidedUnwind
  98. );
  99. TUnwindProc=procedure(frame: PtrUInt);
  100. PFilterRec=^TFilterRec;
  101. TFilterRec=record
  102. RvaClass: DWord;
  103. RvaHandler: DWord;
  104. end;
  105. TExceptObjProc=function(code: Longint; const rec: TExceptionRecord): Pointer; { Exception }
  106. TExceptClsProc=function(code: Longint): Pointer; { ExceptClass }
  107. procedure RaiseException(
  108. dwExceptionCode: DWORD;
  109. dwExceptionFlags: DWORD;
  110. dwArgCount: DWORD;
  111. lpArguments: Pointer); // msdn: *ULONG_PTR
  112. stdcall; external 'kernel32.dll' name 'RaiseException';
  113. function RunErrorCode(const rec: TExceptionRecord): longint;
  114. begin
  115. { negative result means 'FPU reset required' }
  116. case rec.ExceptionCode of
  117. STATUS_INTEGER_DIVIDE_BY_ZERO: result := 200; { reDivByZero }
  118. STATUS_FLOAT_DIVIDE_BY_ZERO: result := -208; { !!reZeroDivide }
  119. STATUS_ARRAY_BOUNDS_EXCEEDED: result := 201; { reRangeError }
  120. STATUS_STACK_OVERFLOW: result := 202; { reStackOverflow }
  121. STATUS_FLOAT_OVERFLOW: result := -205; { reOverflow }
  122. STATUS_FLOAT_DENORMAL_OPERAND,
  123. STATUS_FLOAT_UNDERFLOW: result := -206; { reUnderflow }
  124. STATUS_FLOAT_INEXACT_RESULT,
  125. STATUS_FLOAT_INVALID_OPERATION,
  126. STATUS_FLOAT_STACK_CHECK: result := -207; { reInvalidOp }
  127. STATUS_INTEGER_OVERFLOW: result := 215; { reIntOverflow }
  128. STATUS_ILLEGAL_INSTRUCTION: result := -216;
  129. STATUS_ACCESS_VIOLATION: result := 216; { reAccessViolation }
  130. STATUS_CONTROL_C_EXIT: result := 217; { reControlBreak }
  131. STATUS_PRIVILEGED_INSTRUCTION: result := 218; { rePrivilegedInstruction }
  132. STATUS_FLOAT_MULTIPLE_TRAPS,
  133. STATUS_FLOAT_MULTIPLE_FAULTS: result := -255; { indicate FPU reset }
  134. else
  135. result := 255; { reExternalException }
  136. end;
  137. end;
  138. procedure TranslateMxcsr(mxcsr: longword; var code: longint);
  139. begin
  140. case (mxcsr and $3f) of
  141. 1,32: code:=-207; { InvalidOp, Precision }
  142. 2,16: code:=-206; { Denormal, Underflow }
  143. 4: code:=-208; { !!reZeroDivide }
  144. 8: code:=-205; { reOverflow }
  145. end;
  146. end;
  147. function FilterException(var rec:TExceptionRecord; imagebase: PtrUInt; filterRva: DWord; errcode: Longint): Pointer;
  148. var
  149. ExClass: TClass;
  150. i: Longint;
  151. Filter: Pointer;
  152. curFilt: PFilterRec;
  153. begin
  154. result:=nil;
  155. if rec.ExceptionCode=FPC_EXCEPTION_CODE then
  156. ExClass:=TObject(rec.ExceptionInformation[1]).ClassType
  157. else if Assigned(ExceptClsProc) then
  158. ExClass:=TClass(TExceptClsProc(ExceptClsProc)(errcode))
  159. else
  160. Exit; { if we cannot determine type of exception, don't handle it }
  161. Filter:=Pointer(imagebase+filterRva);
  162. for i:=0 to PLongint(Filter)^-1 do
  163. begin
  164. CurFilt:=@PFilterRec(Filter+sizeof(Longint))[i];
  165. if (CurFilt^.RvaClass=$FFFFFFFF) or
  166. { TODO: exception might be coming from another module, need more advanced comparing }
  167. (ExClass.InheritsFrom(TClass(imagebase+CurFilt^.RvaClass))) then
  168. begin
  169. result:=Pointer(imagebase+CurFilt^.RvaHandler);
  170. exit;
  171. end;
  172. end;
  173. end;
  174. {*****************************************************************************
  175. Parameter Handling
  176. *****************************************************************************}
  177. procedure setup_arguments;
  178. var
  179. arglen,
  180. count : longint;
  181. argstart,
  182. pc,arg : pchar;
  183. quote : Boolean;
  184. argvlen : longint;
  185. buf: array[0..259] of char; // need MAX_PATH bytes, not 256!
  186. procedure allocarg(idx,len:longint);
  187. var
  188. oldargvlen : longint;
  189. begin
  190. if idx>=argvlen then
  191. begin
  192. oldargvlen:=argvlen;
  193. argvlen:=(idx+8) and (not 7);
  194. sysreallocmem(argv,argvlen*sizeof(pointer));
  195. fillchar(argv[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);
  196. end;
  197. { use realloc to reuse already existing memory }
  198. { always allocate, even if length is zero, since }
  199. { the arg. is still present! }
  200. sysreallocmem(argv[idx],len+1);
  201. end;
  202. begin
  203. { create commandline, it starts with the executed filename which is argv[0] }
  204. { Win32 passes the command NOT via the args, but via getmodulefilename}
  205. count:=0;
  206. argv:=nil;
  207. argvlen:=0;
  208. ArgLen := GetModuleFileName(0, @buf[0], sizeof(buf));
  209. buf[ArgLen] := #0; // be safe
  210. allocarg(0,arglen);
  211. move(buf,argv[0]^,arglen+1);
  212. { Setup cmdline variable }
  213. cmdline:=GetCommandLine;
  214. { process arguments }
  215. pc:=cmdline;
  216. {$IfDef SYSTEM_DEBUG_STARTUP}
  217. Writeln(stderr,'Win32 GetCommandLine is #',pc,'#');
  218. {$EndIf }
  219. while pc^<>#0 do
  220. begin
  221. { skip leading spaces }
  222. while pc^ in [#1..#32] do
  223. inc(pc);
  224. if pc^=#0 then
  225. break;
  226. { calc argument length }
  227. quote:=False;
  228. argstart:=pc;
  229. arglen:=0;
  230. while (pc^<>#0) do
  231. begin
  232. case pc^ of
  233. #1..#32 :
  234. begin
  235. if quote then
  236. inc(arglen)
  237. else
  238. break;
  239. end;
  240. '"' :
  241. if pc[1]<>'"' then
  242. quote := not quote
  243. else
  244. inc(pc);
  245. else
  246. inc(arglen);
  247. end;
  248. inc(pc);
  249. end;
  250. { copy argument }
  251. { Don't copy the first one, it is already there.}
  252. If Count<>0 then
  253. begin
  254. allocarg(count,arglen);
  255. quote:=False;
  256. pc:=argstart;
  257. arg:=argv[count];
  258. while (pc^<>#0) do
  259. begin
  260. case pc^ of
  261. #1..#32 :
  262. begin
  263. if quote then
  264. begin
  265. arg^:=pc^;
  266. inc(arg);
  267. end
  268. else
  269. break;
  270. end;
  271. '"' :
  272. if pc[1]<>'"' then
  273. quote := not quote
  274. else
  275. inc(pc);
  276. else
  277. begin
  278. arg^:=pc^;
  279. inc(arg);
  280. end;
  281. end;
  282. inc(pc);
  283. end;
  284. arg^:=#0;
  285. end;
  286. {$IfDef SYSTEM_DEBUG_STARTUP}
  287. Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
  288. {$EndIf SYSTEM_DEBUG_STARTUP}
  289. inc(count);
  290. end;
  291. { get argc }
  292. argc:=count;
  293. { free unused memory, leaving a nil entry at the end }
  294. sysreallocmem(argv,(count+1)*sizeof(pointer));
  295. argv[count] := nil;
  296. end;
  297. function paramcount : longint;
  298. begin
  299. paramcount := argc - 1;
  300. end;
  301. function paramstr(l : longint) : string;
  302. begin
  303. if (l>=0) and (l<argc) then
  304. paramstr:=strpas(argv[l])
  305. else
  306. paramstr:='';
  307. end;
  308. procedure randomize;
  309. begin
  310. randseed:=GetTickCount;
  311. end;
  312. Var
  313. DLLInitState : Longint = -1;
  314. DLLBuf : Jmp_buf;
  315. function Dll_entry{$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}(constref info : TEntryInformation){$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION} : longbool; [public,alias:'_FPC_DLL_Entry'];
  316. begin
  317. {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  318. SetupEntryInformation(info);
  319. {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  320. IsLibrary:=true;
  321. DllInitState:=DLLreason;
  322. Dll_entry:=false; { return value is ignored, except when DLLreason=DLL_PROCESS_ATTACH }
  323. case DLLreason of
  324. DLL_PROCESS_ATTACH :
  325. begin
  326. MainThreadIdWin32 := Win32GetCurrentThreadId;
  327. If SetJmp(DLLBuf) = 0 then
  328. begin
  329. {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  330. EntryInformation.PascalMain();
  331. {$else FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  332. PascalMain;
  333. {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  334. Dll_entry:=true;
  335. end
  336. else
  337. Dll_entry:=(ExitCode=0);
  338. end;
  339. DLL_THREAD_ATTACH :
  340. begin
  341. { SysInitMultithreading must not be called here,
  342. see comments in exec_tls_callback below }
  343. { Allocate Threadvars }
  344. SysAllocateThreadVars;
  345. { NS : no idea what is correct to pass here - pass dummy value for now }
  346. { passing a dummy is ok, the correct value is read from the coff header of SysInstance (FK) }
  347. InitThread($1000000); { Assume everything is idempotent there, as the thread could have been created with BeginThread... }
  348. if assigned(Dll_Thread_Attach_Hook) then
  349. Dll_Thread_Attach_Hook(DllParam);
  350. end;
  351. DLL_THREAD_DETACH :
  352. begin
  353. if assigned(Dll_Thread_Detach_Hook) then
  354. Dll_Thread_Detach_Hook(DllParam);
  355. { Release Threadvars }
  356. if TlsGetValue(TLSKey^)<>nil then
  357. DoneThread; { Assume everything is idempotent there }
  358. end;
  359. DLL_PROCESS_DETACH :
  360. begin
  361. if MainThreadIDWin32=0 then // already been here.
  362. exit;
  363. If SetJmp(DLLBuf) = 0 then
  364. begin
  365. if assigned(Dll_Process_Detach_Hook) then
  366. Dll_Process_Detach_Hook(DllParam);
  367. InternalExit;
  368. end;
  369. SysReleaseThreadVars;
  370. { Free TLS resources used by ThreadVars }
  371. SysFiniMultiThreading;
  372. MainThreadIDWin32:=0;
  373. end;
  374. end;
  375. DllInitState:=-1;
  376. end;
  377. {****************************************************************************
  378. Error Message writing using messageboxes
  379. ****************************************************************************}
  380. function MessageBox(w1:THandle;l1,l2:pointer;w2:longint):longint;
  381. stdcall;external 'user32' name 'MessageBoxA';
  382. const
  383. ErrorBufferLength = 1024;
  384. var
  385. ErrorBuf : array[0..ErrorBufferLength] of char;
  386. ErrorLen : SizeInt;
  387. procedure ErrorWrite(Var F: TextRec);
  388. {
  389. An error message should always end with #13#10#13#10
  390. }
  391. var
  392. i : SizeInt;
  393. Begin
  394. while F.BufPos>0 do
  395. begin
  396. begin
  397. if F.BufPos+ErrorLen>ErrorBufferLength then
  398. i:=ErrorBufferLength-ErrorLen
  399. else
  400. i:=F.BufPos;
  401. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  402. inc(ErrorLen,i);
  403. ErrorBuf[ErrorLen]:=#0;
  404. end;
  405. if ErrorLen=ErrorBufferLength then
  406. begin
  407. if not NoErrMsg then
  408. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  409. ErrorLen:=0;
  410. end;
  411. Dec(F.BufPos,i);
  412. end;
  413. End;
  414. procedure ErrorClose(Var F: TextRec);
  415. begin
  416. if ErrorLen>0 then
  417. begin
  418. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  419. ErrorLen:=0;
  420. end;
  421. ErrorLen:=0;
  422. end;
  423. procedure ErrorOpen(Var F: TextRec);
  424. Begin
  425. TextRec(F).InOutFunc:=@ErrorWrite;
  426. TextRec(F).FlushFunc:=@ErrorWrite;
  427. TextRec(F).CloseFunc:=@ErrorClose;
  428. ErrorLen:=0;
  429. End;
  430. procedure AssignError(Var T: Text);
  431. begin
  432. Assign(T,'');
  433. TextRec(T).OpenFunc:=@ErrorOpen;
  434. Rewrite(T);
  435. end;
  436. procedure SysInitStdIO;
  437. begin
  438. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  439. displayed in a messagebox }
  440. { WARNING: this should be done only once at startup,
  441. not for DLL entry code, as the standard handles might
  442. have been redirected }
  443. if StdInputHandle=0 then
  444. StdInputHandle:=THandle(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  445. if StdOutputHandle=0 then
  446. StdOutputHandle:=THandle(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  447. if StdErrorHandle=0 then
  448. StdErrorHandle:=THandle(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  449. if not IsConsole then
  450. begin
  451. AssignError(stderr);
  452. AssignError(StdOut);
  453. Assign(Output,'');
  454. Assign(Input,'');
  455. Assign(ErrOutput,'');
  456. end
  457. else
  458. begin
  459. OpenStdIO(Input,fmInput,StdInputHandle);
  460. OpenStdIO(Output,fmOutput,StdOutputHandle);
  461. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  462. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  463. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  464. end;
  465. end;
  466. { ProcessID cached to avoid repeated calls to GetCurrentProcess. }
  467. var
  468. ProcessID: SizeUInt;
  469. function GetProcessID: SizeUInt;
  470. begin
  471. GetProcessID := ProcessID;
  472. end;
  473. {******************************************************************************
  474. Unicode
  475. ******************************************************************************}
  476. const
  477. { MultiByteToWideChar }
  478. MB_PRECOMPOSED = 1;
  479. WC_NO_BEST_FIT_CHARS = $400;
  480. function MultiByteToWideChar(CodePage:UINT; dwFlags:DWORD; lpMultiByteStr:PChar; cchMultiByte:longint; lpWideCharStr:PWideChar;cchWideChar:longint):longint;
  481. stdcall; external 'kernel32' name 'MultiByteToWideChar';
  482. function WideCharToMultiByte(CodePage:UINT; dwFlags:DWORD; lpWideCharStr:PWideChar; cchWideChar:longint; lpMultiByteStr:PChar;cchMultiByte:longint; lpDefaultChar:PChar; lpUsedDefaultChar:pointer):longint;
  483. stdcall; external 'kernel32' name 'WideCharToMultiByte';
  484. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  485. stdcall; external 'user32' name 'CharUpperBuffW';
  486. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  487. stdcall; external 'user32' name 'CharLowerBuffW';
  488. procedure Win32Unicode2AnsiMove(source:punicodechar;var dest:RawByteString;cp : TSystemCodePage;len:SizeInt);
  489. var
  490. destlen: SizeInt;
  491. begin
  492. // retrieve length including trailing #0
  493. // not anymore, because this must also be usable for single characters
  494. destlen:=WideCharToMultiByte(cp, 0, source, len, nil, 0, nil, nil);
  495. // this will null-terminate
  496. setlength(dest, destlen);
  497. if destlen>0 then
  498. begin
  499. WideCharToMultiByte(cp, 0, source, len, @dest[1], destlen, nil, nil);
  500. PAnsiRec(pointer(dest)-AnsiFirstOff)^.CodePage:=cp;
  501. end;
  502. end;
  503. procedure Win32Ansi2UnicodeMove(source:pchar;cp : TSystemCodePage;var dest:UnicodeString;len:SizeInt);
  504. var
  505. destlen: SizeInt;
  506. dwflags: DWORD;
  507. begin
  508. // retrieve length including trailing #0
  509. // not anymore, because this must also be usable for single characters
  510. if cp=CP_UTF8 then
  511. dwFlags:=0
  512. else
  513. dwFlags:=MB_PRECOMPOSED;
  514. destlen:=MultiByteToWideChar(cp, dwFlags, source, len, nil, 0);
  515. // this will null-terminate
  516. setlength(dest, destlen);
  517. if destlen>0 then
  518. begin
  519. MultiByteToWideChar(cp, dwFlags, source, len, @dest[1], destlen);
  520. PUnicodeRec(pointer(dest)-UnicodeFirstOff)^.CodePage:=CP_UTF16;
  521. end;
  522. end;
  523. function Win32UnicodeUpper(const s : UnicodeString) : UnicodeString;
  524. begin
  525. result:=s;
  526. UniqueString(result);
  527. if length(result)>0 then
  528. CharUpperBuff(LPWSTR(result),length(result));
  529. end;
  530. function Win32UnicodeLower(const s : UnicodeString) : UnicodeString;
  531. begin
  532. result:=s;
  533. UniqueString(result);
  534. if length(result)>0 then
  535. CharLowerBuff(LPWSTR(result),length(result));
  536. end;
  537. {******************************************************************************
  538. Widestring
  539. ******************************************************************************}
  540. procedure Win32Ansi2WideMove(source:pchar;cp : TSystemCodePage;var dest:widestring;len:SizeInt);
  541. var
  542. destlen: SizeInt;
  543. dwFlags: DWORD;
  544. begin
  545. // retrieve length including trailing #0
  546. // not anymore, because this must also be usable for single characters
  547. if cp=CP_UTF8 then
  548. dwFlags:=0
  549. else
  550. dwFlags:=MB_PRECOMPOSED;
  551. destlen:=MultiByteToWideChar(cp, dwFlags, source, len, nil, 0);
  552. // this will null-terminate
  553. setlength(dest, destlen);
  554. if destlen>0 then
  555. MultiByteToWideChar(cp, dwFlags, source, len, @dest[1], destlen);
  556. end;
  557. function Win32WideUpper(const s : WideString) : WideString;
  558. begin
  559. result:=s;
  560. if length(result)>0 then
  561. CharUpperBuff(LPWSTR(result),length(result));
  562. end;
  563. function Win32WideLower(const s : WideString) : WideString;
  564. begin
  565. result:=s;
  566. if length(result)>0 then
  567. CharLowerBuff(LPWSTR(result),length(result));
  568. end;
  569. type
  570. PWStrInitEntry = ^TWStrInitEntry;
  571. TWStrInitEntry = record
  572. addr: PPointer;
  573. data: Pointer;
  574. end;
  575. PWStrInitTablesTable = ^TWStrInitTablesTable;
  576. TWStrInitTablesTable = packed record
  577. count : {$ifdef VER2_6}longint{$else}sizeint{$endif};
  578. tables : packed array [1..32767] of PWStrInitEntry;
  579. end;
  580. var
  581. {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  582. WStrInitTablesTable: PWStrInitTablesTable;
  583. {$else FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  584. WStrInitTablesTableVar: TWStrInitTablesTable; external name 'FPC_WIDEINITTABLES';
  585. WStrInitTablesTable: PWStrInitTablesTable = @WStrInitTablesTableVar;
  586. {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
  587. function GetACP:UINT; stdcall; external 'kernel32' name 'GetACP';
  588. function GetConsoleCP:UINT; stdcall; external 'kernel32' name 'GetConsoleCP';
  589. function Win32GetStandardCodePage(const stdcp: TStandardCodePageEnum): TSystemCodePage;
  590. begin
  591. case stdcp of
  592. scpAnsi,
  593. scpFileSystemSingleByte: Result := GetACP;
  594. scpConsoleInput: Result := GetConsoleCP;
  595. scpConsoleOutput: Result := GetConsoleOutputCP;
  596. end;
  597. end;
  598. { there is a similiar procedure in sysutils which inits the fields which
  599. are only relevant for the sysutils units }
  600. procedure InitWin32Widestrings;
  601. var
  602. i: longint;
  603. ptable: PWStrInitEntry;
  604. begin
  605. {$if not(defined(VER2_2) or defined(VER2_4))}
  606. { assign initial values to global Widestring typed consts }
  607. for i:=1 to WStrInitTablesTable^.count do
  608. begin
  609. ptable:=WStrInitTablesTable^.tables[i];
  610. while Assigned(ptable^.addr) do
  611. begin
  612. fpc_widestr_assign(ptable^.addr^, ptable^.data);
  613. Inc(ptable);
  614. end;
  615. end;
  616. {$endif}
  617. { Note: since WideChar=UnicodeChar and PWideChar=PUnicodeChar,
  618. Wide2AnsiMoveProc is identical to Unicode2AnsiStrMoveProc. }
  619. { Widestring }
  620. widestringmanager.Wide2AnsiMoveProc:=@Win32Unicode2AnsiMove;
  621. widestringmanager.Ansi2WideMoveProc:=@Win32Ansi2WideMove;
  622. widestringmanager.UpperWideStringProc:=@Win32WideUpper;
  623. widestringmanager.LowerWideStringProc:=@Win32WideLower;
  624. { Unicode }
  625. widestringmanager.Unicode2AnsiMoveProc:=@Win32Unicode2AnsiMove;
  626. widestringmanager.Ansi2UnicodeMoveProc:=@Win32Ansi2UnicodeMove;
  627. widestringmanager.UpperUnicodeStringProc:=@Win32UnicodeUpper;
  628. widestringmanager.LowerUnicodeStringProc:=@Win32UnicodeLower;
  629. { Codepage }
  630. widestringmanager.GetStandardCodePageProc:=@Win32GetStandardCodePage;
  631. DefaultSystemCodePage:=GetACP;
  632. DefaultUnicodeCodePage:=CP_UTF16;
  633. DefaultFileSystemCodePage:=CP_UTF8;
  634. DefaultRTLFileSystemCodePage:=DefaultSystemCodePage;
  635. end;
  636. type
  637. WINBOOL = longbool;
  638. PHANDLER_ROUTINE = function (dwCtrlType:DWORD):WINBOOL; stdcall;
  639. function SetConsoleCtrlHandler(HandlerRoutine:PHANDLER_ROUTINE; Add:WINBOOL):WINBOOL; stdcall;
  640. external 'kernel32' name 'SetConsoleCtrlHandler';
  641. function WinCtrlBreakHandler(dwCtrlType:DWORD): WINBOOL;stdcall;
  642. const
  643. CTRL_BREAK_EVENT = 1;
  644. begin
  645. if Assigned(CtrlBreakHandler) then
  646. Result:=CtrlBreakHandler((dwCtrlType and CTRL_BREAK_EVENT > 0))
  647. else
  648. Result:=false;
  649. end;
  650. function SysSetCtrlBreakHandler (Handler: TCtrlBreakHandler): TCtrlBreakHandler;
  651. begin
  652. (* Return either nil or previous handler *)
  653. if (Assigned(CtrlBreakHandler)) and (not Assigned(Handler)) then
  654. SetConsoleCtrlHandler(@WinCtrlBreakHandler, false)
  655. else if (not Assigned(CtrlBreakHandler)) and (Assigned(Handler)) then
  656. SetConsoleCtrlHandler(@WinCtrlBreakHandler, true);
  657. SysSetCtrlBreakHandler := CtrlBreakHandler;
  658. CtrlBreakHandler := Handler;
  659. end;