d3drm: Implement IDirect3DRMMesh_GetGroupColor.
[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     FIXME("(%p): stub\n", stacksize);
381     return TRUE;
382 }
383
384 /**********************************************************************
385  *           SetThreadAffinityMask   (KERNEL32.@)
386  */
387 DWORD_PTR WINAPI SetThreadAffinityMask( HANDLE hThread, DWORD_PTR dwThreadAffinityMask )
388 {
389     NTSTATUS                    status;
390     THREAD_BASIC_INFORMATION    tbi;
391
392     status = NtQueryInformationThread( hThread, ThreadBasicInformation, 
393                                        &tbi, sizeof(tbi), NULL );
394     if (status)
395     {
396         SetLastError( RtlNtStatusToDosError(status) );
397         return 0;
398     }
399     status = NtSetInformationThread( hThread, ThreadAffinityMask, 
400                                      &dwThreadAffinityMask,
401                                      sizeof(dwThreadAffinityMask));
402     if (status)
403     {
404         SetLastError( RtlNtStatusToDosError(status) );
405         return 0;
406     }
407     return tbi.AffinityMask;
408 }
409
410
411 /**********************************************************************
412  * SetThreadIdealProcessor [KERNEL32.@]  Sets preferred processor for thread.
413  *
414  * RETURNS
415  *    Success: Value of last call to SetThreadIdealProcessor
416  *    Failure: -1
417  */
418 DWORD WINAPI SetThreadIdealProcessor(
419     HANDLE hThread,          /* [in] Specifies the thread of interest */
420     DWORD dwIdealProcessor)  /* [in] Specifies the new preferred processor */
421 {
422     FIXME("(%p): stub\n",hThread);
423     if (dwIdealProcessor > MAXIMUM_PROCESSORS)
424     {
425         SetLastError(ERROR_INVALID_PARAMETER);
426         return ~0u;
427     }
428     return 0;
429 }
430
431
432 /***********************************************************************
433  *           GetThreadSelectorEntry   (KERNEL32.@)
434  */
435 BOOL WINAPI GetThreadSelectorEntry( HANDLE hthread, DWORD sel, LPLDT_ENTRY ldtent )
436 {
437     THREAD_DESCRIPTOR_INFORMATION tdi;
438     NTSTATUS status;
439
440     tdi.Selector = sel;
441     status = NtQueryInformationThread( hthread, ThreadDescriptorTableEntry, &tdi, sizeof(tdi), NULL);
442     if (status)
443     {
444         SetLastError( RtlNtStatusToDosError(status) );
445         return FALSE;
446     }
447     *ldtent = tdi.Entry;
448     return TRUE;
449 }
450
451
452 /* callback for QueueUserAPC */
453 static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
454 {
455     PAPCFUNC func = (PAPCFUNC)arg1;
456     func( arg2 );
457 }
458
459 /***********************************************************************
460  *              QueueUserAPC  (KERNEL32.@)
461  */
462 DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
463 {
464     NTSTATUS status = NtQueueApcThread( hthread, call_user_apc, (ULONG_PTR)func, data, 0 );
465
466     if (status) SetLastError( RtlNtStatusToDosError(status) );
467     return !status;
468 }
469
470 /***********************************************************************
471  *              QueueUserWorkItem  (KERNEL32.@)
472  */
473 BOOL WINAPI QueueUserWorkItem( LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags )
474 {
475     NTSTATUS status;
476
477     TRACE("(%p,%p,0x%08x)\n", Function, Context, Flags);
478
479     status = RtlQueueWorkItem( Function, Context, Flags );
480
481     if (status) SetLastError( RtlNtStatusToDosError(status) );
482     return !status;
483 }
484
485 /**********************************************************************
486  * GetThreadTimes [KERNEL32.@]  Obtains timing information.
487  *
488  * RETURNS
489  *    Success: TRUE
490  *    Failure: FALSE
491  */
492 BOOL WINAPI GetThreadTimes(
493     HANDLE thread,         /* [in]  Specifies the thread of interest */
494     LPFILETIME creationtime, /* [out] When the thread was created */
495     LPFILETIME exittime,     /* [out] When the thread was destroyed */
496     LPFILETIME kerneltime,   /* [out] Time thread spent in kernel mode */
497     LPFILETIME usertime)     /* [out] Time thread spent in user mode */
498 {
499     KERNEL_USER_TIMES   kusrt;
500     NTSTATUS            status;
501
502     status = NtQueryInformationThread(thread, ThreadTimes, &kusrt,
503                                       sizeof(kusrt), NULL);
504     if (status)
505     {
506         SetLastError( RtlNtStatusToDosError(status) );
507         return FALSE;
508     }
509     if (creationtime)
510     {
511         creationtime->dwLowDateTime = kusrt.CreateTime.u.LowPart;
512         creationtime->dwHighDateTime = kusrt.CreateTime.u.HighPart;
513     }
514     if (exittime)
515     {
516         exittime->dwLowDateTime = kusrt.ExitTime.u.LowPart;
517         exittime->dwHighDateTime = kusrt.ExitTime.u.HighPart;
518     }
519     if (kerneltime)
520     {
521         kerneltime->dwLowDateTime = kusrt.KernelTime.u.LowPart;
522         kerneltime->dwHighDateTime = kusrt.KernelTime.u.HighPart;
523     }
524     if (usertime)
525     {
526         usertime->dwLowDateTime = kusrt.UserTime.u.LowPart;
527         usertime->dwHighDateTime = kusrt.UserTime.u.HighPart;
528     }
529     
530     return TRUE;
531 }
532
533 /**********************************************************************
534  * GetThreadId [KERNEL32.@]
535  *
536  * Retrieve the identifier of a thread.
537  *
538  * PARAMS
539  *  Thread [I] The thread to retrieve the identifier of.
540  *
541  * RETURNS
542  *    Success: Identifier of the target thread.
543  *    Failure: 0
544  */
545 DWORD WINAPI GetThreadId(HANDLE Thread)
546 {
547     THREAD_BASIC_INFORMATION tbi;
548     NTSTATUS status;
549
550     TRACE("(%p)\n", Thread);
551
552     status = NtQueryInformationThread(Thread, ThreadBasicInformation, &tbi,
553                                       sizeof(tbi), NULL);
554     if (status)
555     {
556         SetLastError( RtlNtStatusToDosError(status) );
557         return 0;
558     }
559
560     return HandleToULong(tbi.ClientId.UniqueThread);
561 }
562
563
564 /***********************************************************************
565  * GetCurrentThread [KERNEL32.@]  Gets pseudohandle for current thread
566  *
567  * RETURNS
568  *    Pseudohandle for the current thread
569  */
570 #undef GetCurrentThread
571 HANDLE WINAPI GetCurrentThread(void)
572 {
573     return (HANDLE)~(ULONG_PTR)1;
574 }
575
576
577 #ifdef __i386__
578
579 /***********************************************************************
580  *              SetLastError (KERNEL32.@)
581  */
582 /* void WINAPI SetLastError( DWORD error ); */
583 __ASM_STDCALL_FUNC( SetLastError, 4,
584                    "movl 4(%esp),%eax\n\t"
585                    ".byte 0x64\n\t"
586                    "movl %eax,0x34\n\t"
587                    "ret $4" )
588
589 /***********************************************************************
590  *              GetLastError (KERNEL32.@)
591  */
592 /* DWORD WINAPI GetLastError(void); */
593 __ASM_STDCALL_FUNC( GetLastError, 0, ".byte 0x64\n\tmovl 0x34,%eax\n\tret" )
594
595 /***********************************************************************
596  *              GetCurrentProcessId (KERNEL32.@)
597  */
598 /* DWORD WINAPI GetCurrentProcessId(void) */
599 __ASM_STDCALL_FUNC( GetCurrentProcessId, 0, ".byte 0x64\n\tmovl 0x20,%eax\n\tret" )
600
601 /***********************************************************************
602  *              GetCurrentThreadId (KERNEL32.@)
603  */
604 /* DWORD WINAPI GetCurrentThreadId(void) */
605 __ASM_STDCALL_FUNC( GetCurrentThreadId, 0, ".byte 0x64\n\tmovl 0x24,%eax\n\tret" )
606
607 /***********************************************************************
608  *              GetProcessHeap (KERNEL32.@)
609  */
610 /* HANDLE WINAPI GetProcessHeap(void) */
611 __ASM_STDCALL_FUNC( GetProcessHeap, 0, ".byte 0x64\n\tmovl 0x30,%eax\n\tmovl 0x18(%eax),%eax\n\tret");
612
613 #elif defined(__x86_64__)
614
615 /***********************************************************************
616  *              SetLastError (KERNEL32.@)
617  */
618 /* void WINAPI SetLastError( DWORD error ); */
619 __ASM_STDCALL_FUNC( SetLastError, 8, ".byte 0x65\n\tmovl %ecx,0x68\n\tret" );
620
621 /***********************************************************************
622  *              GetLastError (KERNEL32.@)
623  */
624 /* DWORD WINAPI GetLastError(void); */
625 __ASM_STDCALL_FUNC( GetLastError, 0, ".byte 0x65\n\tmovl 0x68,%eax\n\tret" );
626
627 /***********************************************************************
628  *              GetCurrentProcessId (KERNEL32.@)
629  */
630 /* DWORD WINAPI GetCurrentProcessId(void) */
631 __ASM_STDCALL_FUNC( GetCurrentProcessId, 0, ".byte 0x65\n\tmovl 0x40,%eax\n\tret" );
632
633 /***********************************************************************
634  *              GetCurrentThreadId (KERNEL32.@)
635  */
636 /* DWORD WINAPI GetCurrentThreadId(void) */
637 __ASM_STDCALL_FUNC( GetCurrentThreadId, 0, ".byte 0x65\n\tmovl 0x48,%eax\n\tret" );
638
639 /***********************************************************************
640  *              GetProcessHeap (KERNEL32.@)
641  */
642 /* HANDLE WINAPI GetProcessHeap(void) */
643 __ASM_STDCALL_FUNC( GetProcessHeap, 0, ".byte 0x65\n\tmovq 0x60,%rax\n\tmovq 0x30(%rax),%rax\n\tret");
644
645 #else  /* __x86_64__ */
646
647 /**********************************************************************
648  *              SetLastError (KERNEL32.@)
649  *
650  * Sets the last-error code.
651  *
652  * RETURNS
653  * Nothing.
654  */
655 void WINAPI SetLastError( DWORD error ) /* [in] Per-thread error code */
656 {
657     NtCurrentTeb()->LastErrorValue = error;
658 }
659
660 /**********************************************************************
661  *              GetLastError (KERNEL32.@)
662  *
663  * Get the last-error code.
664  *
665  * RETURNS
666  *  last-error code.
667  */
668 DWORD WINAPI GetLastError(void)
669 {
670     return NtCurrentTeb()->LastErrorValue;
671 }
672
673 /***********************************************************************
674  *              GetCurrentProcessId (KERNEL32.@)
675  *
676  * Get the current process identifier.
677  *
678  * RETURNS
679  *  current process identifier
680  */
681 DWORD WINAPI GetCurrentProcessId(void)
682 {
683     return HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess);
684 }
685
686 /***********************************************************************
687  *              GetCurrentThreadId (KERNEL32.@)
688  *
689  * Get the current thread identifier.
690  *
691  * RETURNS
692  *  current thread identifier
693  */
694 DWORD WINAPI GetCurrentThreadId(void)
695 {
696     return HandleToULong(NtCurrentTeb()->ClientId.UniqueThread);
697 }
698
699 /***********************************************************************
700  *           GetProcessHeap    (KERNEL32.@)
701  */
702 HANDLE WINAPI GetProcessHeap(void)
703 {
704     return NtCurrentTeb()->Peb->ProcessHeap;
705 }
706
707 #endif  /* __i386__ */
708
709 /*************************************************************************
710  *              rtlmode_to_win32mode
711  */
712 static DWORD rtlmode_to_win32mode( DWORD rtlmode )
713 {
714     DWORD win32mode = 0;
715
716     if (rtlmode & 0x10)
717         win32mode |= SEM_FAILCRITICALERRORS;
718     if (rtlmode & 0x20)
719         win32mode |= SEM_NOGPFAULTERRORBOX;
720     if (rtlmode & 0x40)
721         win32mode |= SEM_NOOPENFILEERRORBOX;
722
723     return win32mode;
724 }
725
726 /***********************************************************************
727  *              SetThreadErrorMode (KERNEL32.@)
728  *
729  * Set the thread local error mode.
730  *
731  * PARAMS
732  *  mode    [I] The new error mode, a bitwise or of SEM_FAILCRITICALERRORS,
733  *              SEM_NOGPFAULTERRORBOX and SEM_NOOPENFILEERRORBOX.
734  *  oldmode [O] Destination of the old error mode (may be NULL)
735  *
736  * RETURNS
737  *  Success: TRUE
738  *  Failure: FALSE, check GetLastError
739  */
740 BOOL WINAPI SetThreadErrorMode( DWORD mode, LPDWORD oldmode )
741 {
742     NTSTATUS status;
743     DWORD tmp = 0;
744
745     if (mode & ~(SEM_FAILCRITICALERRORS |
746                  SEM_NOGPFAULTERRORBOX |
747                  SEM_NOOPENFILEERRORBOX))
748     {
749         SetLastError( ERROR_INVALID_PARAMETER );
750         return FALSE;
751     }
752
753     if (mode & SEM_FAILCRITICALERRORS)
754         tmp |= 0x10;
755     if (mode & SEM_NOGPFAULTERRORBOX)
756         tmp |= 0x20;
757     if (mode & SEM_NOOPENFILEERRORBOX)
758         tmp |= 0x40;
759
760     status = RtlSetThreadErrorMode( tmp, oldmode );
761     if (status)
762     {
763         SetLastError( RtlNtStatusToDosError(status) );
764         return FALSE;
765     }
766
767     if (oldmode)
768         *oldmode = rtlmode_to_win32mode(*oldmode);
769
770     return TRUE;
771 }
772
773 /***********************************************************************
774  *              GetThreadErrorMode (KERNEL32.@)
775  *
776  * Get the thread local error mode.
777  *
778  * PARAMS
779  *  None.
780  *
781  * RETURNS
782  *  The current thread local error mode.
783  */
784 DWORD WINAPI GetThreadErrorMode( void )
785 {
786     return rtlmode_to_win32mode( RtlGetThreadErrorMode() );
787 }
788
789 /***********************************************************************
790  *              GetThreadUILanguage (KERNEL32.@)
791  *
792  * Get the current thread's language identifier.
793  *
794  * PARAMS
795  *  None.
796  *
797  * RETURNS
798  *  The current thread's language identifier.
799  */
800 LANGID WINAPI GetThreadUILanguage( void )
801 {
802     LANGID lang;
803     NtQueryDefaultUILanguage( &lang );
804     FIXME(": stub, returning default language.\n");
805     return lang;
806 }
807
808 /***********************************************************************
809  *              GetThreadIOPendingFlag (KERNEL32.@)
810  */
811 BOOL WINAPI GetThreadIOPendingFlag( HANDLE thread, PBOOL io_pending )
812 {
813     FIXME("%p, %p\n", thread, io_pending);
814     *io_pending = FALSE;
815     return TRUE;
816 }
817
818 /***********************************************************************
819  *              SetThreadPreferredUILanguages (KERNEL32.@)
820  */
821 BOOL WINAPI SetThreadPreferredUILanguages( DWORD flags, PCZZWSTR buffer, PULONG count )
822 {
823     FIXME( "%u, %p, %p\n", flags, buffer, count );
824     return TRUE;
825 }
826
827 /***********************************************************************
828  *              GetThreadPreferredUILanguages (KERNEL32.@)
829  */
830 BOOL WINAPI GetThreadPreferredUILanguages( DWORD flags, PULONG count, PCZZWSTR buffer, PULONG buffersize )
831 {
832     FIXME( "%u, %p, %p %p\n", flags, count, buffer, buffersize );
833     *count = 0;
834     *buffersize = 0;
835     return TRUE;
836 }
837
838 /***********************************************************************
839  *              InitializeSRWLock (KERNEL32.@)
840  */
841 VOID WINAPI InitializeSRWLock( PSRWLOCK srwlock )
842 {
843     FIXME( "(%p): stub\n", srwlock );
844 }
845
846 /***********************************************************************
847  *              AcquireSRWLockExclusive (KERNEL32.@)
848  */
849 VOID WINAPI AcquireSRWLockExclusive( PSRWLOCK srwlock )
850 {
851     FIXME( "(%p): stub\n", srwlock );
852 }
853
854 /***********************************************************************
855  *              ReleaseSRWLockExclusive (KERNEL32.@)
856  */
857 VOID WINAPI ReleaseSRWLockExclusive( PSRWLOCK srwlock )
858 {
859     FIXME( "(%p): stub\n", srwlock );
860 }
861
862 /***********************************************************************
863  *              AcquireSRWLockShared (KERNEL32.@)
864  */
865 VOID WINAPI AcquireSRWLockShared( PSRWLOCK srwlock )
866 {
867     FIXME( "(%p): stub\n", srwlock );
868 }
869
870 /***********************************************************************
871  *              ReleaseSRWLockShared (KERNEL32.@)
872  */
873 VOID WINAPI ReleaseSRWLockShared( PSRWLOCK srwlock )
874 {
875     FIXME( "(%p): stub\n", srwlock );
876 }