syswin.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  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. Const
  13. DLL_PROCESS_ATTACH = 1;
  14. DLL_THREAD_ATTACH = 2;
  15. DLL_PROCESS_DETACH = 0;
  16. DLL_THREAD_DETACH = 3;
  17. DLLExitOK : boolean = true;
  18. Var
  19. DLLBuf : Jmp_buf;
  20. function Dll_entry{$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}(const info : TEntryInformation){$endif FPC_HAS_INDIRECT_MAIN_INFORMATION} : longbool; [public,alias:'_FPC_DLL_Entry'];
  21. begin
  22. {$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}
  23. EntryInformation:=info;
  24. {$endif FPC_HAS_INDIRECT_MAIN_INFORMATION}
  25. IsLibrary:=true;
  26. Dll_entry:=false; { return value is ignored, except when DLLreason=DLL_PROCESS_ATTACH }
  27. case DLLreason of
  28. DLL_PROCESS_ATTACH :
  29. begin
  30. MainThreadIdWin32 := Win32GetCurrentThreadId;
  31. If SetJmp(DLLBuf) = 0 then
  32. begin
  33. {$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}
  34. EntryInformation.PascalMain();
  35. {$else FPC_HAS_INDIRECT_MAIN_INFORMATION}
  36. PascalMain;
  37. {$endif FPC_HAS_INDIRECT_MAIN_INFORMATION}
  38. Dll_entry:=true;
  39. end
  40. else
  41. Dll_entry:=DLLExitOK;
  42. end;
  43. DLL_THREAD_ATTACH :
  44. begin
  45. { SysInitMultithreading must not be called here,
  46. see comments in exec_tls_callback below }
  47. { Allocate Threadvars }
  48. SysAllocateThreadVars;
  49. { NS : no idea what is correct to pass here - pass dummy value for now }
  50. { passing a dummy is ok, the correct value is read from the coff header of SysInstance (FK) }
  51. InitThread($1000000); { Assume everything is idempotent there, as the thread could have been created with BeginThread... }
  52. if assigned(Dll_Thread_Attach_Hook) then
  53. Dll_Thread_Attach_Hook(DllParam);
  54. end;
  55. DLL_THREAD_DETACH :
  56. begin
  57. if assigned(Dll_Thread_Detach_Hook) then
  58. Dll_Thread_Detach_Hook(DllParam);
  59. { Release Threadvars }
  60. if TlsGetValue(TLSKey)<>nil then
  61. DoneThread; { Assume everything is idempotent there }
  62. end;
  63. DLL_PROCESS_DETACH :
  64. begin
  65. if MainThreadIDWin32=0 then // already been here.
  66. exit;
  67. If SetJmp(DLLBuf) = 0 then
  68. FPC_Do_Exit;
  69. if assigned(Dll_Process_Detach_Hook) then
  70. Dll_Process_Detach_Hook(DllParam);
  71. SysReleaseThreadVars;
  72. { Free TLS resources used by ThreadVars }
  73. SysFiniMultiThreading;
  74. MainThreadIDWin32:=0;
  75. end;
  76. end;
  77. end;
  78. Procedure ExitDLL(Exitcode : longint);
  79. begin
  80. DLLExitOK:=ExitCode=0;
  81. LongJmp(DLLBuf,1);
  82. end;
  83. {$ifdef FPC_USE_TLS_DIRECTORY}
  84. { Process TLS callback function }
  85. { This is only useful for executables
  86. for DLLs, DLL_Entry gets called. PM }
  87. procedure Exec_Tls_callback(Handle : pointer; reason : Dword; Reserved : pointer);
  88. stdcall; [public,alias:'_FPC_Tls_Callback'];
  89. begin
  90. if IsLibrary then
  91. Exit;
  92. case reason of
  93. { For executables, DLL_PROCESS_ATTACH is called *before* the entry point,
  94. and DLL_PROCESS_DETACH is called *after* RTL shuts down and calls ExitProcess.
  95. It isn't a good idea to handle resources of the main thread at these points. }
  96. DLL_THREAD_ATTACH :
  97. begin
  98. { !!! SysInitMultithreading must NOT be called here. Windows guarantees that
  99. the main thread invokes PROCESS_ATTACH, not THREAD_ATTACH. So this always
  100. executes in non-main thread. SysInitMultithreading() here will cause
  101. initial threadvars to be copied to TLS of non-main thread, and threadvars
  102. of the main thread will be reinitialized upon the next access with zeroes,
  103. ending up in a delayed failure which is very hard to debug.
  104. Fortunately this nasty scenario can happen only when the first non-main thread
  105. was created outside of RTL (Sergei).
  106. }
  107. { Allocate Threadvars }
  108. SysAllocateThreadVars;
  109. { NS : no idea what is correct to pass here - pass dummy value for now }
  110. { passing a dummy is ok, the correct value is read from the coff header of SysInstance (FK) }
  111. InitThread($1000000); { Assume everything is idempotent there, as the thread could have been created with BeginThread... }
  112. end;
  113. DLL_THREAD_DETACH :
  114. begin
  115. if TlsGetValue(TLSKey)<>nil then
  116. DoneThread; { Assume everything is idempotent there }
  117. end;
  118. end;
  119. end;
  120. const
  121. FreePascal_TLS_callback : pointer = @Exec_Tls_callback;
  122. public name '__FPC_tls_callbacks' section '.CRT$XLFPC';
  123. FreePascal_end_of_TLS_callback : pointer = nil;
  124. public name '__FPC_end_of_tls_callbacks' section '.CRT$XLZZZ';
  125. var
  126. tls_callbacks : pointer; external name '___crt_xl_start__';
  127. tls_data_start : pointer; external name '___tls_start__';
  128. tls_data_end : pointer; external name '___tls_end__';
  129. _tls_index : dword; cvar; external;
  130. const
  131. _tls_used : TTlsDirectory = (
  132. data_start : @tls_data_start;
  133. data_end : @tls_data_end;
  134. index_pointer : @_tls_index;
  135. callbacks_pointer : @tls_callbacks;
  136. zero_fill_size : 0;
  137. flags : 0;
  138. ); cvar; public;
  139. {$ifdef win64}
  140. { This is a hack to support external linking.
  141. All released win64 versions of GNU binutils miss proper prefix handling
  142. when searching for _tls_used and expect two leading underscores.
  143. The issue has been fixed in binutils snapshots, but not released yet.
  144. TODO: This should be removed as soon as next version of binutils (>2.21) is
  145. released and we upgrade to it. }
  146. __tls_used : TTlsDirectory = (
  147. data_start : @tls_data_start;
  148. data_end : @tls_data_end;
  149. index_pointer : @_tls_index;
  150. callbacks_pointer : @tls_callbacks;
  151. zero_fill_size : 0;
  152. flags : 0;
  153. ); cvar; public;
  154. {$endif win64}
  155. {$endif FPC_USE_TLS_DIRECTORY}
  156. {****************************************************************************
  157. Error Message writing using messageboxes
  158. ****************************************************************************}
  159. function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
  160. stdcall;external 'user32' name 'MessageBoxA';
  161. const
  162. ErrorBufferLength = 1024;
  163. var
  164. ErrorBuf : array[0..ErrorBufferLength] of char;
  165. ErrorLen : SizeInt;
  166. Function ErrorWrite(Var F: TextRec): Integer;
  167. {
  168. An error message should always end with #13#10#13#10
  169. }
  170. var
  171. i : SizeInt;
  172. Begin
  173. while F.BufPos>0 do
  174. begin
  175. begin
  176. if F.BufPos+ErrorLen>ErrorBufferLength then
  177. i:=ErrorBufferLength-ErrorLen
  178. else
  179. i:=F.BufPos;
  180. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  181. inc(ErrorLen,i);
  182. ErrorBuf[ErrorLen]:=#0;
  183. end;
  184. if ErrorLen=ErrorBufferLength then
  185. begin
  186. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  187. ErrorLen:=0;
  188. end;
  189. Dec(F.BufPos,i);
  190. end;
  191. ErrorWrite:=0;
  192. End;
  193. Function ErrorClose(Var F: TextRec): Integer;
  194. begin
  195. if ErrorLen>0 then
  196. begin
  197. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  198. ErrorLen:=0;
  199. end;
  200. ErrorLen:=0;
  201. ErrorClose:=0;
  202. end;
  203. Function ErrorOpen(Var F: TextRec): Integer;
  204. Begin
  205. TextRec(F).InOutFunc:=@ErrorWrite;
  206. TextRec(F).FlushFunc:=@ErrorWrite;
  207. TextRec(F).CloseFunc:=@ErrorClose;
  208. ErrorLen:=0;
  209. ErrorOpen:=0;
  210. End;
  211. procedure AssignError(Var T: Text);
  212. begin
  213. Assign(T,'');
  214. TextRec(T).OpenFunc:=@ErrorOpen;
  215. Rewrite(T);
  216. end;
  217. procedure SysInitStdIO;
  218. begin
  219. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  220. displayed in a messagebox }
  221. StdInputHandle:=longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  222. StdOutputHandle:=longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  223. StdErrorHandle:=longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  224. if not IsConsole then
  225. begin
  226. AssignError(stderr);
  227. AssignError(StdOut);
  228. Assign(Output,'');
  229. Assign(Input,'');
  230. Assign(ErrOutput,'');
  231. end
  232. else
  233. begin
  234. OpenStdIO(Input,fmInput,StdInputHandle);
  235. OpenStdIO(Output,fmOutput,StdOutputHandle);
  236. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  237. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  238. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  239. end;
  240. end;
  241. { ProcessID cached to avoid repeated calls to GetCurrentProcess. }
  242. var
  243. ProcessID: SizeUInt;
  244. function GetProcessID: SizeUInt;
  245. begin
  246. GetProcessID := ProcessID;
  247. end;
  248. {******************************************************************************
  249. Unicode
  250. ******************************************************************************}
  251. const
  252. { MultiByteToWideChar }
  253. MB_PRECOMPOSED = 1;
  254. CP_ACP = 0;
  255. WC_NO_BEST_FIT_CHARS = $400;
  256. function MultiByteToWideChar(CodePage:UINT; dwFlags:DWORD; lpMultiByteStr:PChar; cchMultiByte:longint; lpWideCharStr:PWideChar;cchWideChar:longint):longint;
  257. stdcall; external 'kernel32' name 'MultiByteToWideChar';
  258. function WideCharToMultiByte(CodePage:UINT; dwFlags:DWORD; lpWideCharStr:PWideChar; cchWideChar:longint; lpMultiByteStr:PChar;cchMultiByte:longint; lpDefaultChar:PChar; lpUsedDefaultChar:pointer):longint;
  259. stdcall; external 'kernel32' name 'WideCharToMultiByte';
  260. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  261. stdcall; external 'user32' name 'CharUpperBuffW';
  262. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  263. stdcall; external 'user32' name 'CharLowerBuffW';
  264. procedure Win32Unicode2AnsiMove(source:punicodechar;var dest:ansistring;cp : TSystemCodePage;len:SizeInt);
  265. var
  266. destlen: SizeInt;
  267. begin
  268. // retrieve length including trailing #0
  269. // not anymore, because this must also be usable for single characters
  270. destlen:=WideCharToMultiByte(cp, WC_NO_BEST_FIT_CHARS, source, len, nil, 0, nil, nil);
  271. // this will null-terminate
  272. setlength(dest, destlen);
  273. WideCharToMultiByte(cp, WC_NO_BEST_FIT_CHARS, source, len, @dest[1], destlen, nil, nil);
  274. end;
  275. procedure Win32Ansi2UnicodeMove(source:pchar;cp : TSystemCodePage;var dest:UnicodeString;len:SizeInt);
  276. var
  277. destlen: SizeInt;
  278. begin
  279. // retrieve length including trailing #0
  280. // not anymore, because this must also be usable for single characters
  281. destlen:=MultiByteToWideChar(cp, MB_PRECOMPOSED, source, len, nil, 0);
  282. // this will null-terminate
  283. setlength(dest, destlen);
  284. MultiByteToWideChar(cp, MB_PRECOMPOSED, source, len, @dest[1], destlen);
  285. end;
  286. function Win32UnicodeUpper(const s : UnicodeString) : UnicodeString;
  287. begin
  288. result:=s;
  289. UniqueString(result);
  290. if length(result)>0 then
  291. CharUpperBuff(LPWSTR(result),length(result));
  292. end;
  293. function Win32UnicodeLower(const s : UnicodeString) : UnicodeString;
  294. begin
  295. result:=s;
  296. UniqueString(result);
  297. if length(result)>0 then
  298. CharLowerBuff(LPWSTR(result),length(result));
  299. end;
  300. {******************************************************************************
  301. Widestring
  302. ******************************************************************************}
  303. procedure Win32Wide2AnsiMove(source:pwidechar;var dest:ansistring;cp : TSystemCodePage;len:SizeInt);
  304. var
  305. destlen: SizeInt;
  306. begin
  307. // retrieve length including trailing #0
  308. // not anymore, because this must also be usable for single characters
  309. destlen:=WideCharToMultiByte(cp, WC_NO_BEST_FIT_CHARS, source, len, nil, 0, nil, nil);
  310. // this will null-terminate
  311. setlength(dest, destlen);
  312. WideCharToMultiByte(cp, WC_NO_BEST_FIT_CHARS, source, len, @dest[1], destlen, nil, nil);
  313. end;
  314. procedure Win32Ansi2WideMove(source:pchar;cp : TSystemCodePage;var dest:widestring;len:SizeInt);
  315. var
  316. destlen: SizeInt;
  317. begin
  318. // retrieve length including trailing #0
  319. // not anymore, because this must also be usable for single characters
  320. destlen:=MultiByteToWideChar(cp, MB_PRECOMPOSED, source, len, nil, 0);
  321. // this will null-terminate
  322. setlength(dest, destlen);
  323. MultiByteToWideChar(cp, MB_PRECOMPOSED, source, len, @dest[1], destlen);
  324. end;
  325. function Win32WideUpper(const s : WideString) : WideString;
  326. begin
  327. result:=s;
  328. if length(result)>0 then
  329. CharUpperBuff(LPWSTR(result),length(result));
  330. end;
  331. function Win32WideLower(const s : WideString) : WideString;
  332. begin
  333. result:=s;
  334. if length(result)>0 then
  335. CharLowerBuff(LPWSTR(result),length(result));
  336. end;
  337. type
  338. PWStrInitEntry = ^TWStrInitEntry;
  339. TWStrInitEntry = record
  340. addr: PPointer;
  341. data: Pointer;
  342. end;
  343. PWStrInitTablesTable = ^TWStrInitTablesTable;
  344. TWStrInitTablesTable = packed record
  345. count : longint;
  346. tables : packed array [1..32767] of PWStrInitEntry;
  347. end;
  348. {$if not(defined(VER2_2) or defined(VER2_4))}
  349. var
  350. WStrInitTablesTable: TWStrInitTablesTable; external name 'FPC_WIDEINITTABLES';
  351. {$endif}
  352. { there is a similiar procedure in sysutils which inits the fields which
  353. are only relevant for the sysutils units }
  354. procedure InitWin32Widestrings;
  355. var
  356. i: longint;
  357. ptable: PWStrInitEntry;
  358. begin
  359. {$if not(defined(VER2_2) or defined(VER2_4))}
  360. { assign initial values to global Widestring typed consts }
  361. for i:=1 to WStrInitTablesTable.count do
  362. begin
  363. ptable:=WStrInitTablesTable.tables[i];
  364. while Assigned(ptable^.addr) do
  365. begin
  366. fpc_widestr_assign(ptable^.addr^, ptable^.data);
  367. Inc(ptable);
  368. end;
  369. end;
  370. {$endif}
  371. { Note: since WideChar=UnicodeChar and PWideChar=PUnicodeChar,
  372. Wide2AnsiMoveProc is identical to Unicode2AnsiStrMoveProc. }
  373. { Widestring }
  374. widestringmanager.Wide2AnsiMoveProc:=@Win32Unicode2AnsiMove;
  375. widestringmanager.Ansi2WideMoveProc:=@Win32Ansi2WideMove;
  376. widestringmanager.UpperWideStringProc:=@Win32WideUpper;
  377. widestringmanager.LowerWideStringProc:=@Win32WideLower;
  378. {$ifndef VER2_2}
  379. { Unicode }
  380. widestringmanager.Unicode2AnsiMoveProc:=@Win32Unicode2AnsiMove;
  381. widestringmanager.Ansi2UnicodeMoveProc:=@Win32Ansi2UnicodeMove;
  382. widestringmanager.UpperUnicodeStringProc:=@Win32UnicodeUpper;
  383. widestringmanager.LowerUnicodeStringProc:=@Win32UnicodeLower;
  384. {$endif VER2_2}
  385. end;