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