oleaut32: Use a saner calling convention for the marshaller asm thunks.
[wine] / dlls / kernel32 / thread.c
1 /*
2  * Win32 threads
3  *
4  * Copyright 1996 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <fcntl.h>
26 #include <stdarg.h>
27 #include <sys/types.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31
32 #include "ntstatus.h"
33 #define WIN32_NO_STATUS
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winternl.h"
38 #include "wine/exception.h"
39 #include "wine/library.h"
40 #include "wine/server.h"
41 #include "wine/debug.h"
42
43 #include "kernel_private.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(thread);
46
47
48 /***********************************************************************
49  *           CreateThread   (KERNEL32.@)
50  */
51 HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread( SECURITY_ATTRIBUTES *sa, SIZE_T stack, LPTHREAD_START_ROUTINE start,
52                                               LPVOID param, DWORD flags, LPDWORD id )
53 {
54      return CreateRemoteThread( GetCurrentProcess(),
55                                 sa, stack, start, param, flags, id );
56 }
57
58
59 /***************************************************************************
60  *                  CreateRemoteThread   (KERNEL32.@)
61  *
62  * Creates a thread that runs in the address space of another process
63  *
64  * PARAMS
65  *
66  * RETURNS
67  *   Success: Handle to the new thread.
68  *   Failure: NULL. Use GetLastError() to find the error cause.
69  *
70  * BUGS
71  *   Improper memory allocation: there's no ability to free new_thread_info
72  *   in other process.
73  *   Bad start address for RtlCreateUserThread because the library
74  *   may be loaded at different address in other process.
75  */
76 HANDLE WINAPI CreateRemoteThread( HANDLE hProcess, SECURITY_ATTRIBUTES *sa, SIZE_T stack,
77                                   LPTHREAD_START_ROUTINE start, LPVOID param,
78                                   DWORD flags, LPDWORD id )
79 {
80     HANDLE handle;
81     CLIENT_ID client_id;
82     NTSTATUS status;
83     SIZE_T stack_reserve = 0, stack_commit = 0;
84
85     if (flags & STACK_SIZE_PARAM_IS_A_RESERVATION) stack_reserve = stack;
86     else stack_commit = stack;
87
88     status = RtlCreateUserThread( hProcess, NULL, TRUE,
89                                   NULL, stack_reserve, stack_commit,
90                                   (PRTL_THREAD_START_ROUTINE)start, param, &handle, &client_id );
91     if (status == STATUS_SUCCESS)
92     {
93         if (id) *id = HandleToULong(client_id.UniqueThread);
94         if (sa && (sa->nLength >= sizeof(*sa)) && sa->bInheritHandle)
95             SetHandleInformation( handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT );
96         if (!(flags & CREATE_SUSPENDED))
97         {
98             ULONG ret;
99             if (NtResumeThread( handle, &ret ))
100             {
101                 NtClose( handle );
102                 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
103                 handle = 0;
104             }
105         }
106     }
107     else
108     {
109         SetLastError( RtlNtStatusToDosError(status) );
110         handle = 0;
111     }
112     return handle;
113 }
114
115
116 /***********************************************************************
117  * OpenThread  [KERNEL32.@]   Retrieves a handle to a thread from its thread id
118  */
119 HANDLE WINAPI OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId )
120 {
121     NTSTATUS status;
122     HANDLE handle;
123     OBJECT_ATTRIBUTES attr;
124     CLIENT_ID cid;
125
126     attr.Length = sizeof(attr);
127     attr.RootDirectory = 0;
128     attr.Attributes = bInheritHandle ? OBJ_INHERIT : 0;
129     attr.ObjectName = NULL;
130     attr.SecurityDescriptor = NULL;
131     attr.SecurityQualityOfService = NULL;
132
133     cid.UniqueProcess = 0; /* FIXME */
134     cid.UniqueThread = ULongToHandle(dwThreadId);
135     status = NtOpenThread( &handle, dwDesiredAccess, &attr, &cid );
136     if (status)
137     {
138         SetLastError( RtlNtStatusToDosError(status) );
139         handle = 0;
140     }
141     return handle;
142 }
143
144
145 /***********************************************************************
146  * ExitThread [KERNEL32.@]  Ends a thread
147  *
148  * RETURNS
149  *    None
150  */
151 void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
152 {
153     RtlFreeThreadActivationContextStack();
154     RtlExitUserThread( code );
155 }
156
157
158 /**********************************************************************
159  * TerminateThread [KERNEL32.@]  Terminates a thread
160  *
161  * RETURNS
162  *    Success: TRUE
163  *    Failure: FALSE
164  */
165 BOOL WINAPI TerminateThread( HANDLE handle,    /* [in] Handle to thread */
166                              DWORD exit_code)  /* [in] Exit code for thread */
167 {
168     NTSTATUS status = NtTerminateThread( handle, exit_code );
169     if (status) SetLastError( RtlNtStatusToDosError(status) );
170     return !status;
171 }
172
173
174 /***********************************************************************
175  *           FreeLibraryAndExitThread (KERNEL32.@)
176  */
177 void WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
178 {
179     FreeLibrary(hLibModule);
180     ExitThread(dwExitCode);
181 }
182
183
184 /**********************************************************************
185  *              GetExitCodeThread (KERNEL32.@)
186  *
187  * Gets termination status of thread.
188  *
189  * RETURNS
190  *    Success: TRUE
191  *    Failure: FALSE
192  */
193 BOOL WINAPI GetExitCodeThread(
194     HANDLE hthread, /* [in]  Handle to thread */
195     LPDWORD exitcode) /* [out] Address to receive termination status */
196 {
197     THREAD_BASIC_INFORMATION info;
198     NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
199                                                 &info, sizeof(info), NULL );
200
201     if (status)
202     {
203         SetLastError( RtlNtStatusToDosError(status) );
204         return FALSE;
205     }
206     if (exitcode) *exitcode = info.ExitStatus;
207     return TRUE;
208 }
209
210
211 /***********************************************************************
212  * SetThreadContext [KERNEL32.@]  Sets context of thread.
213  *
214  * RETURNS
215  *    Success: TRUE
216  *    Failure: FALSE
217  */
218 BOOL WINAPI SetThreadContext( HANDLE handle,           /* [in]  Handle to thread with context */
219                               const CONTEXT *context ) /* [in] Address of context structure */
220 {
221     NTSTATUS status = NtSetContextThread( handle, context );
222     if (status) SetLastError( RtlNtStatusToDosError(status) );
223     return !status;
224 }
225
226
227 /***********************************************************************
228  * GetThreadContext [KERNEL32.@]  Retrieves context of thread.
229  *
230  * RETURNS
231  *    Success: TRUE
232  *    Failure: FALSE
233  */
234 BOOL WINAPI GetThreadContext( HANDLE handle,     /* [in]  Handle to thread with context */
235                               CONTEXT *context ) /* [out] Address of context structure */
236 {
237     NTSTATUS status = NtGetContextThread( handle, context );
238     if (status) SetLastError( RtlNtStatusToDosError(status) );
239     return !status;
240 }
241
242
243 /**********************************************************************
244  * SuspendThread [KERNEL32.@]  Suspends a thread.
245  *
246  * RETURNS
247  *    Success: Previous suspend count
248  *    Failure: 0xFFFFFFFF
249  */
250 DWORD WINAPI SuspendThread( HANDLE hthread ) /* [in] Handle to the thread */
251 {
252     DWORD ret;
253     NTSTATUS status = NtSuspendThread( hthread, &ret );
254
255     if (status)
256     {
257         ret = ~0U;
258         SetLastError( RtlNtStatusToDosError(status) );
259     }
260     return ret;
261 }
262
263
264 /**********************************************************************
265  * ResumeThread [KERNEL32.@]  Resumes a thread.
266  *
267  * Decrements a thread's suspend count.  When count is zero, the
268  * execution of the thread is resumed.
269  *
270  * RETURNS
271  *    Success: Previous suspend count
272  *    Failure: 0xFFFFFFFF
273  *    Already running: 0
274  */
275 DWORD WINAPI ResumeThread( HANDLE hthread ) /* [in] Identifies thread to restart */
276 {
277     DWORD ret;
278     NTSTATUS status = NtResumeThread( hthread, &ret );
279
280     if (status)
281     {
282         ret = ~0U;
283         SetLastError( RtlNtStatusToDosError(status) );
284     }
285     return ret;
286 }
287
288
289 /**********************************************************************
290  * GetThreadPriority [KERNEL32.@]  Returns priority for thread.
291  *
292  * RETURNS
293  *    Success: Thread's priority level.
294  *    Failure: THREAD_PRIORITY_ERROR_RETURN
295  */
296 INT WINAPI GetThreadPriority(
297     HANDLE hthread) /* [in] Handle to thread */
298 {
299     THREAD_BASIC_INFORMATION info;
300     NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
301                                                 &info, sizeof(info), NULL );
302
303     if (status)
304     {
305         SetLastError( RtlNtStatusToDosError(status) );
306         return THREAD_PRIORITY_ERROR_RETURN;
307     }
308     return info.Priority;
309 }
310
311
312 /**********************************************************************
313  * SetThreadPriority [KERNEL32.@]  Sets priority for thread.
314  *
315  * RETURNS
316  *    Success: TRUE
317  *    Failure: FALSE
318  */
319 BOOL WINAPI SetThreadPriority(
320     HANDLE hthread, /* [in] Handle to thread */
321     INT priority)   /* [in] Thread priority level */
322 {
323     DWORD       prio = priority;
324     NTSTATUS    status;
325
326     status = NtSetInformationThread(hthread, ThreadBasePriority,
327                                     &prio, sizeof(prio));
328
329     if (status)
330     {
331         SetLastError( RtlNtStatusToDosError(status) );
332         return FALSE;
333     }
334
335     return TRUE;
336 }
337
338
339 /**********************************************************************
340  * GetThreadPriorityBoost [KERNEL32.@]  Returns priority boost for thread.
341  *
342  * Always reports that priority boost is disabled.
343  *
344  * RETURNS
345  *    Success: TRUE.
346  *    Failure: FALSE
347  */
348 BOOL WINAPI GetThreadPriorityBoost(
349     HANDLE hthread, /* [in] Handle to thread */
350     PBOOL pstate)   /* [out] pointer to var that receives the boost state */
351 {
352     if (pstate) *pstate = FALSE;
353     return TRUE;
354 }
355
356
357 /**********************************************************************
358  * SetThreadPriorityBoost [KERNEL32.@]  Sets priority boost for thread.
359  *
360  * Priority boost is not implemented. This function always returns
361  * FALSE and sets last error to ERROR_CALL_NOT_IMPLEMENTED
362  *
363  * RETURNS
364  *    Always returns FALSE to indicate a failure
365  */
366 BOOL WINAPI SetThreadPriorityBoost(
367     HANDLE hthread, /* [in] Handle to thread */
368     BOOL disable)   /* [in] TRUE to disable priority boost */
369 {
370     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
371     return FALSE;
372 }
373
374
375 /**********************************************************************
376  *           SetThreadStackGuarantee   (KERNEL32.@)
377  */
378 BOOL WINAPI SetThreadStackGuarantee(PULONG stacksize)
379 {
380     static int once;
381     if (once++ == 0)
382         FIXME("(%p): stub\n", stacksize);
383     return TRUE;
384 }
385
386 /**********************************************************************
387  *           SetThreadAffinityMask   (KERNEL32.@)
388  */
389 DWORD_PTR WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD_PTR dwThreadAffinityMask )
390 {
391     NTSTATUS                    status;
392     THREAD_BASIC_INFORMATION    tbi;
393
394     status = NtQueryInformationThread( hThread, ThreadBasicInformation, 
395                                        &tbi, sizeof(tbi), NULL );
396     if (status)
397     {
398         SetLastError( RtlNtStatusToDosError(status) );
399         return 0;
400     }
401     status = NtSetInformationThread( hThread, ThreadAffinityMask, 
402                                      &dwThreadAffinityMask,
403                                      sizeof(dwThreadAffinityMask));
404     if (status)
405     {
406         SetLastError( RtlNtStatusToDosError(status) );
407         return 0;
408     }
409     return tbi.AffinityMask;
410 }
411
412
413 /**********************************************************************
414  * SetThreadIdealProcessor [KERNEL32.@]  Sets preferred processor for thread.
415  *
416  * RETURNS
417  *    Success: Value of last call to SetThreadIdealProcessor
418  *    Failure: -1
419  */
420 DWORD WINAPI SetThreadIdealProcessor(
421     HANDLE hThread,          /* [in] Specifies the thread of interest */
422     DWORD dwIdealProcessor)  /* [in] Specifies the new preferred processor */
423 {
424     FIXME("(%p): stub\n",hThread);
425     if (dwIdealProcessor > MAXIMUM_PROCESSORS)
426     {
427         SetLastError(ERROR_INVALID_PARAMETER);
428         return ~0u;
429     }
430     return 0;
431 }
432
433
434 /***********************************************************************
435  *           GetThreadSelectorEntry   (KERNEL32.@)
436  */
437 BOOL WINAPI GetThreadSelectorEntry( HANDLE hthread, DWORD sel, LPLDT_ENTRY ldtent )
438 {
439     THREAD_DESCRIPTOR_INFORMATION tdi;
440     NTSTATUS status;
441
442     tdi.Selector = sel;
443     status = NtQueryInformationThread( hthread, ThreadDescriptorTableEntry, &tdi, sizeof(tdi), NULL);
444     if (status)
445     {
446         SetLastError( RtlNtStatusToDosError(status) );
447         return FALSE;
448     }
449     *ldtent = tdi.Entry;
450     return TRUE;
451 }
452
453
454 /* callback for QueueUserAPC */
455 static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
456 {
457     PAPCFUNC func = (PAPCFUNC)arg1;
458     func( arg2 );
459 }
460
461 /***********************************************************************
462  *              QueueUserAPC  (KERNEL32.@)
463  */
464 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
465 {
466     NTSTATUS status = NtQueueApcThread( hthread, call_user_apc, (ULONG_PTR)func, data, 0 );
467
468     if (status) SetLastError( RtlNtStatusToDosError(status) );
469     return !status;
470 }
471
472 /***********************************************************************
473  *              QueueUserWorkItem  (KERNEL32.@)
474  */
475 BOOL WINAPI QueueUserWorkItem( LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags )
476 {
477     NTSTATUS status;
478
479     TRACE("(%p,%p,0x%08x)\n", Function, Context, Flags);
480
481     status = RtlQueueWorkItem( Function, Context, Flags );
482
483     if (status) SetLastError( RtlNtStatusToDosError(status) );
484     return !status;
485 }
486
487 /**********************************************************************
488  * GetThreadTimes [KERNEL32.@]  Obtains timing information.
489  *
490  * RETURNS
491  *    Success: TRUE
492  *    Failure: FALSE
493  */
494 BOOL WINAPI GetThreadTimes(
495     HANDLE thread,         /* [in]  Specifies the thread of interest */
496     LPFILETIME creationtime, /* [out] When the thread was created */
497     LPFILETIME exittime,     /* [out] When the thread was destroyed */
498     LPFILETIME kerneltime,   /* [out] Time thread spent in kernel mode */
499     LPFILETIME usertime)     /* [out] Time thread spent in user mode */
500 {
501     KERNEL_USER_TIMES   kusrt;
502     NTSTATUS            status;
503
504     status = NtQueryInformationThread(thread, ThreadTimes, &kusrt,
505                                       sizeof(kusrt), NULL);
506     if (status)
507     {
508         SetLastError( RtlNtStatusToDosError(status) );
509         return FALSE;
510     }
511     if (creationtime)
512     {
513         creationtime->dwLowDateTime = kusrt.CreateTime.u.LowPart;
514         creationtime->dwHighDateTime = kusrt.CreateTime.u.HighPart;
515     }
516     if (exittime)
517     {
518         exittime->dwLowDateTime = kusrt.ExitTime.u.LowPart;
519         exittime->dwHighDateTime = kusrt.ExitTime.u.HighPart;
520     }
521     if (kerneltime)
522     {
523         kerneltime->dwLowDateTime = kusrt.KernelTime.u.LowPart;
524         kerneltime->dwHighDateTime = kusrt.KernelTime.u.HighPart;
525     }
526     if (usertime)
527     {
528         usertime->dwLowDateTime = kusrt.UserTime.u.LowPart;
529         usertime->dwHighDateTime = kusrt.UserTime.u.HighPart;
530     }
531     
532     return TRUE;
533 }
534
535 /**********************************************************************
536  * GetThreadId [KERNEL32.@]
537  *
538  * Retrieve the identifier of a thread.
539  *
540  * PARAMS
541  *  Thread [I] The thread to retrieve the identifier of.
542  *
543  * RETURNS
544  *    Success: Identifier of the target thread.
545  *    Failure: 0
546  */
547 DWORD WINAPI GetThreadId(HANDLE Thread)
548 {
549     THREAD_BASIC_INFORMATION tbi;
550     NTSTATUS status;
551
552     TRACE("(%p)\n", Thread);
553
554     status = NtQueryInformationThread(Thread, ThreadBasicInformation, &tbi,
555                                       sizeof(tbi), NULL);
556     if (status)
557     {
558         SetLastError( RtlNtStatusToDosError(status) );
559         return 0;
560     }
561
562     return HandleToULong(tbi.ClientId.UniqueThread);
563 }
564
565
566 /***********************************************************************
567  * GetCurrentThread [KERNEL32.@]  Gets pseudohandle for current thread
568  *
569  * RETURNS
570  *    Pseudohandle for the current thread
571  */
572 #undef GetCurrentThread
573 HANDLE WINAPI GetCurrentThread(void)
574 {
575     return (HANDLE)~(ULONG_PTR)1;
576 }
577
578
579 #ifdef __i386__
580
581 /***********************************************************************
582  *              SetLastError (KERNEL32.@)
583  */
584 /* void WINAPI SetLastError( DWORD error ); */
585 __ASM_STDCALL_FUNC( SetLastError, 4,
586                    "movl 4(%esp),%eax\n\t"
587                    ".byte 0x64\n\t"
588                    "movl %eax,0x34\n\t"
589                    "ret $4" )
590
591 /***********************************************************************
592  *              GetLastError (KERNEL32.@)
593  */
594 /* DWORD WINAPI GetLastError(void); */
595 __ASM_STDCALL_FUNC( GetLastError, 0, ".byte 0x64\n\tmovl 0x34,%eax\n\tret" )
596
597 /***********************************************************************
598  *              GetCurrentProcessId (KERNEL32.@)
599  */
600 /* DWORD WINAPI GetCurrentProcessId(void) */
601 __ASM_STDCALL_FUNC( GetCurrentProcessId, 0, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" )
602
603 /***********************************************************************
604  *              GetCurrentThreadId (KERNEL32.@)
605  */
606 /* DWORD WINAPI GetCurrentThreadId(void) */
607 __ASM_STDCALL_FUNC( GetCurrentThreadId, 0, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" )
608
609 /***********************************************************************
610  *              GetProcessHeap (KERNEL32.@)
611  */
612 /* HANDLE WINAPI GetProcessHeap(void) */
613 __ASM_STDCALL_FUNC( GetProcessHeap, 0, ".byte 0x64\n\tmovl 0x30,%eax\n\tmovl 0x18(%eax),%eax\n\tret");
614
615 #elif defined(__x86_64__)
616
617 /***********************************************************************
618  *              SetLastError (KERNEL32.@)
619  */
620 /* void WINAPI SetLastError( DWORD error ); */
621 __ASM_STDCALL_FUNC( SetLastError, 8, ".byte 0x65\n\tmovl %ecx,0x68\n\tret" );
622
623 /***********************************************************************
624  *              GetLastError (KERNEL32.@)
625  */
626 /* DWORD WINAPI GetLastError(void); */
627 __ASM_STDCALL_FUNC( GetLastError, 0, ".byte 0x65\n\tmovl 0x68,%eax\n\tret" );
628
629 /***********************************************************************
630  *              GetCurrentProcessId (KERNEL32.@)
631  */
632 /* DWORD WINAPI GetCurrentProcessId(void) */
633 __ASM_STDCALL_FUNC( GetCurrentProcessId, 0, ".byte 0x65\n\tmovl 0x40,%eax\n\tret" );
634
635 /***********************************************************************
636  *              GetCurrentThreadId (KERNEL32.@)
637  */
638 /* DWORD WINAPI GetCurrentThreadId(void) */
639 __ASM_STDCALL_FUNC( GetCurrentThreadId, 0, ".byte 0x65\n\tmovl 0x48,%eax\n\tret" );
640
641 /***********************************************************************
642  *              GetProcessHeap (KERNEL32.@)
643  */
644 /* HANDLE WINAPI GetProcessHeap(void) */
645 __ASM_STDCALL_FUNC( GetProcessHeap, 0, ".byte 0x65\n\tmovq 0x60,%rax\n\tmovq 0x30(%rax),%rax\n\tret");
646
647 #else  /* __x86_64__ */
648
649 /**********************************************************************
650  *              SetLastError (KERNEL32.@)
651  *
652  * Sets the last-error code.
653  *
654  * RETURNS
655  * Nothing.
656  */
657 void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
658 {
659     NtCurrentTeb()->LastErrorValue = error;
660 }
661
662 /**********************************************************************
663  *              GetLastError (KERNEL32.@)
664  *
665  * Get the last-error code.
666  *
667  * RETURNS
668  *  last-error code.
669  */
670 DWORD WINAPI GetLastError(void)
671 {
672     return NtCurrentTeb()->LastErrorValue;
673 }
674
675 /***********************************************************************
676  *              GetCurrentProcessId (KERNEL32.@)
677  *
678  * Get the current process identifier.
679  *
680  * RETURNS
681  *  current process identifier
682  */
683 DWORD WINAPI GetCurrentProcessId(void)
684 {
685     return HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess);
686 }
687
688 /***********************************************************************
689  *              GetCurrentThreadId (KERNEL32.@)
690  *
691  * Get the current thread identifier.
692  *
693  * RETURNS
694  *  current thread identifier
695  */
696 DWORD WINAPI GetCurrentThreadId(void)
697 {
698     return HandleToULong(NtCurrentTeb()->ClientId.UniqueThread);
699 }
700
701 /***********************************************************************
702  *           GetProcessHeap    (KERNEL32.@)
703  */
704 HANDLE WINAPI GetProcessHeap(void)
705 {
706     return NtCurrentTeb()->Peb->ProcessHeap;
707 }
708
709 #endif  /* __i386__ */
710
711 /*************************************************************************
712  *              rtlmode_to_win32mode
713  */
714 static DWORD rtlmode_to_win32mode( DWORD rtlmode )
715 {
716     DWORD win32mode = 0;
717
718     if (rtlmode & 0x10)
719         win32mode |= SEM_FAILCRITICALERRORS;
720     if (rtlmode & 0x20)
721         win32mode |= SEM_NOGPFAULTERRORBOX;
722     if (rtlmode & 0x40)
723         win32mode |= SEM_NOOPENFILEERRORBOX;
724
725     return win32mode;
726 }
727
728 /***********************************************************************
729  *              SetThreadErrorMode (KERNEL32.@)
730  *
731  * Set the thread local error mode.
732  *
733  * PARAMS
734  *  mode    [I] The new error mode, a bitwise or of SEM_FAILCRITICALERRORS,
735  *              SEM_NOGPFAULTERRORBOX and SEM_NOOPENFILEERRORBOX.
736  *  oldmode [O] Destination of the old error mode (may be NULL)
737  *
738  * RETURNS
739  *  Success: TRUE
740  *  Failure: FALSE, check GetLastError
741  */
742 BOOL WINAPI SetThreadErrorMode( DWORD mode, LPDWORD oldmode )
743 {
744     NTSTATUS status;
745     DWORD tmp = 0;
746
747     if (mode & ~(SEM_FAILCRITICALERRORS |
748                  SEM_NOGPFAULTERRORBOX |
749                  SEM_NOOPENFILEERRORBOX))
750     {
751         SetLastError( ERROR_INVALID_PARAMETER );
752         return FALSE;
753     }
754
755     if (mode & SEM_FAILCRITICALERRORS)
756         tmp |= 0x10;
757     if (mode & SEM_NOGPFAULTERRORBOX)
758         tmp |= 0x20;
759     if (mode & SEM_NOOPENFILEERRORBOX)
760         tmp |= 0x40;
761
762     status = RtlSetThreadErrorMode( tmp, oldmode );
763     if (status)
764     {
765         SetLastError( RtlNtStatusToDosError(status) );
766         return FALSE;
767     }
768
769     if (oldmode)
770         *oldmode = rtlmode_to_win32mode(*oldmode);
771
772     return TRUE;
773 }
774
775 /***********************************************************************
776  *              GetThreadErrorMode (KERNEL32.@)
777  *
778  * Get the thread local error mode.
779  *
780  * PARAMS
781  *  None.
782  *
783  * RETURNS
784  *  The current thread local error mode.
785  */
786 DWORD WINAPI GetThreadErrorMode( void )
787 {
788     return rtlmode_to_win32mode( RtlGetThreadErrorMode() );
789 }
790
791 /***********************************************************************
792  *              GetThreadUILanguage (KERNEL32.@)
793  *
794  * Get the current thread's language identifier.
795  *
796  * PARAMS
797  *  None.
798  *
799  * RETURNS
800  *  The current thread's language identifier.
801  */
802 LANGID WINAPI GetThreadUILanguage( void )
803 {
804     LANGID lang;
805     NtQueryDefaultUILanguage( &lang );
806     FIXME(": stub, returning default language.\n");
807     return lang;
808 }
809
810 /***********************************************************************
811  *              GetThreadIOPendingFlag (KERNEL32.@)
812  */
813 BOOL WINAPI GetThreadIOPendingFlag( HANDLE thread, PBOOL io_pending )
814 {
815     FIXME("%p, %p\n", thread, io_pending);
816     *io_pending = FALSE;
817     return TRUE;
818 }
819
820 /***********************************************************************
821  *              SetThreadPreferredUILanguages (KERNEL32.@)
822  */
823 BOOL WINAPI SetThreadPreferredUILanguages( DWORD flags, PCZZWSTR buffer, PULONG count )
824 {
825     FIXME( "%u, %p, %p\n", flags, buffer, count );
826     return TRUE;
827 }
828
829 /***********************************************************************
830  *              GetThreadPreferredUILanguages (KERNEL32.@)
831  */
832 BOOL WINAPI GetThreadPreferredUILanguages( DWORD flags, PULONG count, PCZZWSTR buffer, PULONG buffersize )
833 {
834     FIXME( "%u, %p, %p %p\n", flags, count, buffer, buffersize );
835     *count = 0;
836     *buffersize = 0;
837     return TRUE;
838 }
839
840 /***********************************************************************
841  *              InitializeSRWLock (KERNEL32.@)
842  */
843 VOID WINAPI InitializeSRWLock( PSRWLOCK srwlock )
844 {
845     FIXME( "(%p): stub\n", srwlock );
846 }
847
848 /***********************************************************************
849  *              AcquireSRWLockExclusive (KERNEL32.@)
850  */
851 VOID WINAPI AcquireSRWLockExclusive( PSRWLOCK srwlock )
852 {
853     FIXME( "(%p): stub\n", srwlock );
854 }
855
856 /***********************************************************************
857  *              ReleaseSRWLockExclusive (KERNEL32.@)
858  */
859 VOID WINAPI ReleaseSRWLockExclusive( PSRWLOCK srwlock )
860 {
861     FIXME( "(%p): stub\n", srwlock );
862 }
863
864 /***********************************************************************
865  *              AcquireSRWLockShared (KERNEL32.@)
866  */
867 VOID WINAPI AcquireSRWLockShared( PSRWLOCK srwlock )
868 {
869     FIXME( "(%p): stub\n", srwlock );
870 }
871
872 /***********************************************************************
873  *              ReleaseSRWLockShared (KERNEL32.@)
874  */
875 VOID WINAPI ReleaseSRWLockShared( PSRWLOCK srwlock )
876 {
877     FIXME( "(%p): stub\n", srwlock );
878 }