update for HEAD-2003091401
[reactos.git] / lib / kernel32 / process / proc.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS system libraries
5  * FILE:            lib/kernel32/proc/proc.c
6  * PURPOSE:         Process functions
7  * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
8  * UPDATE HISTORY:
9  *                  Created 01/11/98
10  */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <k32.h>
15
16
17 #define NDEBUG
18 #include <kernel32/kernel32.h>
19
20
21 /* GLOBALS *******************************************************************/
22
23 WaitForInputIdleType  lpfnGlobalRegisterWaitForInputIdle;
24
25 LPSTARTUPINFOA lpLocalStartupInfo = NULL;
26
27 VOID STDCALL
28 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle);
29
30 WINBOOL STDCALL
31 InternalGetProcessId (HANDLE hProcess, LPDWORD lpProcessId);
32
33
34 /* FUNCTIONS ****************************************************************/
35
36 /*
37  * @implemented
38  */
39 BOOL STDCALL
40 GetProcessAffinityMask (HANDLE hProcess,
41                         LPDWORD lpProcessAffinityMask,
42                         LPDWORD lpSystemAffinityMask)
43 {
44   PROCESS_BASIC_INFORMATION ProcessInfo;
45   ULONG BytesWritten;
46   NTSTATUS Status;
47
48   Status = NtQueryInformationProcess (hProcess,
49                                       ProcessBasicInformation,
50                                       (PVOID)&ProcessInfo,
51                                       sizeof(PROCESS_BASIC_INFORMATION),
52                                       &BytesWritten);
53   if (!NT_SUCCESS(Status))
54     {
55       SetLastError (Status);
56       return FALSE;
57     }
58
59   *lpProcessAffinityMask = (DWORD)ProcessInfo.AffinityMask;
60
61   /* FIXME */
62   *lpSystemAffinityMask  = 0x00000001;
63
64   return TRUE;
65 }
66
67
68 /*
69  * @implemented
70  */
71 BOOL STDCALL
72 SetProcessAffinityMask (HANDLE hProcess,
73                         DWORD dwProcessAffinityMask)
74 {
75   NTSTATUS Status;
76
77   Status = NtSetInformationProcess (hProcess,
78                                     ProcessAffinityMask,
79                                     (PVOID)&dwProcessAffinityMask,
80                                     sizeof(DWORD));
81   if (!NT_SUCCESS(Status))
82     {
83       SetLastError (Status);
84       return FALSE;
85     }
86
87   return TRUE;
88 }
89
90
91 /*
92  * @implemented
93  */
94 WINBOOL STDCALL
95 GetProcessShutdownParameters (LPDWORD lpdwLevel,
96                               LPDWORD lpdwFlags)
97 {
98   CSRSS_API_REQUEST CsrRequest;
99   CSRSS_API_REPLY CsrReply;
100   NTSTATUS Status;
101
102   CsrRequest.Type = CSRSS_GET_SHUTDOWN_PARAMETERS;
103   Status = CsrClientCallServer(&CsrRequest,
104                                &CsrReply,
105                                sizeof(CSRSS_API_REQUEST),
106                                sizeof(CSRSS_API_REPLY));
107   if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
108     {
109       SetLastError(Status);
110       return(FALSE);
111     }
112
113   *lpdwLevel = CsrReply.Data.GetShutdownParametersReply.Level;
114   *lpdwFlags = CsrReply.Data.GetShutdownParametersReply.Flags;
115
116   return(TRUE);
117 }
118
119
120 /*
121  * @implemented
122  */
123 WINBOOL STDCALL
124 SetProcessShutdownParameters (DWORD dwLevel,
125                               DWORD dwFlags)
126 {
127   CSRSS_API_REQUEST CsrRequest;
128   CSRSS_API_REPLY CsrReply;
129   NTSTATUS Status;
130
131   CsrRequest.Data.SetShutdownParametersRequest.Level = dwLevel;
132   CsrRequest.Data.SetShutdownParametersRequest.Flags = dwFlags;
133
134   CsrRequest.Type = CSRSS_SET_SHUTDOWN_PARAMETERS;
135   Status = CsrClientCallServer(&CsrRequest,
136                                &CsrReply,
137                                sizeof(CSRSS_API_REQUEST),
138                                sizeof(CSRSS_API_REPLY));
139   if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
140     {
141       SetLastError(Status);
142       return(FALSE);
143     }
144
145   return(TRUE);
146 }
147
148
149 /*
150  * @implemented
151  */
152 WINBOOL STDCALL
153 GetProcessWorkingSetSize (HANDLE hProcess,
154                           LPDWORD lpMinimumWorkingSetSize,
155                           LPDWORD lpMaximumWorkingSetSize)
156 {
157   QUOTA_LIMITS QuotaLimits;
158   NTSTATUS Status;
159
160   Status = NtQueryInformationProcess(hProcess,
161                                      ProcessQuotaLimits,
162                                      &QuotaLimits,
163                                      sizeof(QUOTA_LIMITS),
164                                      NULL);
165   if (!NT_SUCCESS(Status))
166     {
167       SetLastErrorByStatus(Status);
168       return(FALSE);
169     }
170
171   *lpMinimumWorkingSetSize = (DWORD)QuotaLimits.MinimumWorkingSetSize;
172   *lpMaximumWorkingSetSize = (DWORD)QuotaLimits.MaximumWorkingSetSize;
173
174   return(TRUE);
175 }
176
177
178 /*
179  * @unimplemented
180  */
181 WINBOOL STDCALL
182 SetProcessWorkingSetSize(HANDLE hProcess,
183                          DWORD dwMinimumWorkingSetSize,
184                          DWORD dwMaximumWorkingSetSize)
185 {
186   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
187   return(FALSE);
188 }
189
190
191 /*
192  * @implemented
193  */
194 WINBOOL STDCALL
195 GetProcessTimes(HANDLE hProcess,
196                 LPFILETIME lpCreationTime,
197                 LPFILETIME lpExitTime,
198                 LPFILETIME lpKernelTime,
199                 LPFILETIME lpUserTime)
200 {
201   KERNEL_USER_TIMES Kut;
202   NTSTATUS Status;
203
204   Status = NtQueryInformationProcess(hProcess,
205                                      ProcessTimes,
206                                      &Kut,
207                                      sizeof(Kut),
208                                      NULL);
209   if (!NT_SUCCESS(Status))
210     {
211       SetLastErrorByStatus(Status);
212       return(FALSE);
213     }
214
215   lpCreationTime->dwLowDateTime = Kut.CreateTime.u.LowPart;
216   lpCreationTime->dwHighDateTime = Kut.CreateTime.u.HighPart;
217
218   lpExitTime->dwLowDateTime = Kut.ExitTime.u.LowPart;
219   lpExitTime->dwHighDateTime = Kut.ExitTime.u.HighPart;
220
221   lpKernelTime->dwLowDateTime = Kut.KernelTime.u.LowPart;
222   lpKernelTime->dwHighDateTime = Kut.KernelTime.u.HighPart;
223
224   lpUserTime->dwLowDateTime = Kut.UserTime.u.LowPart;
225   lpUserTime->dwHighDateTime = Kut.UserTime.u.HighPart;
226
227   return(TRUE);
228 }
229
230
231 /*
232  * @implemented
233  */
234 HANDLE STDCALL
235 GetCurrentProcess(VOID)
236 {
237   return((HANDLE)NtCurrentProcess());
238 }
239
240
241 /*
242  * @implemented
243  */
244 HANDLE STDCALL
245 GetCurrentThread(VOID)
246 {
247   return((HANDLE)NtCurrentThread());
248 }
249
250
251 /*
252  * @implemented
253  */
254 DWORD STDCALL
255 GetCurrentProcessId(VOID)
256 {
257   return((DWORD)GetTeb()->Cid.UniqueProcess);
258 }
259
260
261 /*
262  * @implemented
263  */
264 WINBOOL STDCALL
265 GetExitCodeProcess(HANDLE hProcess,
266                    LPDWORD lpExitCode)
267 {
268   PROCESS_BASIC_INFORMATION ProcessBasic;
269   ULONG BytesWritten;
270   NTSTATUS Status;
271
272   Status = NtQueryInformationProcess(hProcess,
273                                      ProcessBasicInformation,
274                                      &ProcessBasic,
275                                      sizeof(PROCESS_BASIC_INFORMATION),
276                                      &BytesWritten);
277   if (!NT_SUCCESS(Status))
278     {
279       SetLastErrorByStatus(Status);
280       return(FALSE);
281      }
282
283   memcpy(lpExitCode, &ProcessBasic.ExitStatus, sizeof(DWORD));
284
285   return(TRUE);
286 }
287
288
289 /*
290  * @implemented
291  */
292 WINBOOL STDCALL
293 InternalGetProcessId(HANDLE hProcess,
294              LPDWORD lpProcessId)
295 {
296   PROCESS_BASIC_INFORMATION ProcessBasic;
297   ULONG BytesWritten;
298   NTSTATUS Status;
299
300   Status = NtQueryInformationProcess(hProcess,
301                                      ProcessBasicInformation,
302                                      &ProcessBasic,
303                                      sizeof(PROCESS_BASIC_INFORMATION),
304                                      &BytesWritten);
305   if (!NT_SUCCESS(Status))
306     {
307       SetLastErrorByStatus(Status);
308       return(FALSE);
309     }
310
311   memcpy(lpProcessId, &ProcessBasic.UniqueProcessId, sizeof(DWORD));
312
313   return(TRUE);
314 }
315
316
317 /*
318  * @implemented
319  */
320 HANDLE STDCALL
321 OpenProcess(DWORD dwDesiredAccess,
322             WINBOOL bInheritHandle,
323             DWORD dwProcessId)
324 {
325    NTSTATUS errCode;
326    HANDLE ProcessHandle;
327    OBJECT_ATTRIBUTES ObjectAttributes;
328    CLIENT_ID ClientId ;
329    
330    ClientId.UniqueProcess = (HANDLE)dwProcessId;
331    ClientId.UniqueThread = INVALID_HANDLE_VALUE;
332    
333    ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
334    ObjectAttributes.RootDirectory = (HANDLE)NULL;
335    ObjectAttributes.SecurityDescriptor = NULL;
336    ObjectAttributes.SecurityQualityOfService = NULL;
337    ObjectAttributes.ObjectName = NULL;
338    
339    if (bInheritHandle == TRUE)
340      ObjectAttributes.Attributes = OBJ_INHERIT;
341    else
342      ObjectAttributes.Attributes = 0;
343    
344    errCode = NtOpenProcess(&ProcessHandle,
345                            dwDesiredAccess,
346                            &ObjectAttributes,
347                            &ClientId);
348    if (!NT_SUCCESS(errCode))
349      {
350         SetLastErrorByStatus (errCode);
351         return NULL;
352      }
353    return ProcessHandle;
354 }
355
356
357 /*
358  * @implemented
359  */
360 UINT STDCALL
361 WinExec(LPCSTR lpCmdLine,
362         UINT uCmdShow)
363 {
364    STARTUPINFOA StartupInfo;
365    PROCESS_INFORMATION  ProcessInformation;
366    HINSTANCE hInst;
367    DWORD dosErr;
368
369    StartupInfo.cb = sizeof(STARTUPINFOA);
370    StartupInfo.wShowWindow = uCmdShow;
371    StartupInfo.dwFlags = 0;
372
373    hInst = (HINSTANCE)CreateProcessA(NULL,
374                                      (PVOID)lpCmdLine,
375                                      NULL,
376                                      NULL,
377                                      FALSE,
378                                      0,
379                                      NULL,
380                                      NULL,
381                                      &StartupInfo,
382                                      &ProcessInformation);
383    if ( hInst == NULL )
384      {
385         dosErr = GetLastError();
386         return dosErr;
387      }
388    if (NULL != lpfnGlobalRegisterWaitForInputIdle)
389    {
390      lpfnGlobalRegisterWaitForInputIdle (
391         ProcessInformation.hProcess,
392         10000
393         );
394    }
395    NtClose (ProcessInformation.hProcess);
396    NtClose (ProcessInformation.hThread);
397    return 0;    
398 }
399
400
401 /*
402  * @implemented
403  */
404 VOID STDCALL
405 RegisterWaitForInputIdle (
406         WaitForInputIdleType    lpfnRegisterWaitForInputIdle
407         )
408 {
409         lpfnGlobalRegisterWaitForInputIdle = lpfnRegisterWaitForInputIdle;
410         return;
411 }
412
413
414 /*
415  * @unimplemented
416  */
417 DWORD STDCALL
418 WaitForInputIdle (
419         HANDLE  hProcess,
420         DWORD   dwMilliseconds
421         )
422 {
423         return 0;
424 }
425
426
427 /*
428  * @implemented
429  */
430 VOID STDCALL
431 Sleep(DWORD dwMilliseconds)
432 {
433   SleepEx(dwMilliseconds, FALSE);
434   return;
435 }
436
437
438 /*
439  * @implemented
440  */
441 DWORD STDCALL
442 SleepEx(DWORD dwMilliseconds,
443         BOOL bAlertable)
444 {
445   TIME Interval;
446   NTSTATUS errCode;
447   
448   if (dwMilliseconds != INFINITE)
449     {
450       /*
451        * System time units are 100 nanoseconds (a nanosecond is a billionth of
452        * a second).
453        */
454       Interval.QuadPart = dwMilliseconds;
455       Interval.QuadPart = -(Interval.QuadPart * 10000);
456     }  
457   else
458     {
459       /* Approximately 292000 years hence */
460       Interval.QuadPart = -0x7FFFFFFFFFFFFFFF;
461     }
462
463   errCode = NtDelayExecution (bAlertable, &Interval);
464   if (!NT_SUCCESS(errCode))
465     {
466       SetLastErrorByStatus (errCode);
467       return -1;
468     }
469   return 0;
470 }
471
472
473 /*
474  * @implemented
475  */
476 VOID STDCALL
477 GetStartupInfoW(LPSTARTUPINFOW lpStartupInfo)
478 {
479   PRTL_USER_PROCESS_PARAMETERS Params;
480
481   if (lpStartupInfo == NULL)
482     {
483       SetLastError(ERROR_INVALID_PARAMETER);
484       return;
485     }
486
487   Params = NtCurrentPeb()->ProcessParameters;
488
489   lpStartupInfo->cb = sizeof(STARTUPINFOW);
490   lpStartupInfo->lpDesktop = Params->DesktopInfo.Buffer;
491   lpStartupInfo->lpTitle = Params->WindowTitle.Buffer;
492   lpStartupInfo->dwX = Params->dwX;
493   lpStartupInfo->dwY = Params->dwY;
494   lpStartupInfo->dwXSize = Params->dwXSize;
495   lpStartupInfo->dwYSize = Params->dwYSize;
496   lpStartupInfo->dwXCountChars = Params->dwXCountChars;
497   lpStartupInfo->dwYCountChars = Params->dwYCountChars;
498   lpStartupInfo->dwFillAttribute = Params->dwFillAttribute;
499   lpStartupInfo->dwFlags = Params->dwFlags;
500   lpStartupInfo->wShowWindow = Params->wShowWindow;
501   lpStartupInfo->lpReserved = Params->ShellInfo.Buffer;
502   lpStartupInfo->cbReserved2 = Params->RuntimeInfo.Length;
503   lpStartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeInfo.Buffer;
504
505   lpStartupInfo->hStdInput = Params->hStdInput;
506   lpStartupInfo->hStdOutput = Params->hStdOutput;
507   lpStartupInfo->hStdError = Params->hStdError;
508 }
509
510
511 /*
512  * @implemented
513  */
514 VOID STDCALL
515 GetStartupInfoA(LPSTARTUPINFOA lpStartupInfo)
516 {
517   PRTL_USER_PROCESS_PARAMETERS Params;
518   ANSI_STRING AnsiString;
519
520   if (lpStartupInfo == NULL)
521     {
522         SetLastError(ERROR_INVALID_PARAMETER);
523         return;
524     }
525
526   Params = NtCurrentPeb ()->ProcessParameters;
527
528   RtlAcquirePebLock ();
529
530   if (lpLocalStartupInfo == NULL)
531     {
532         /* create new local startup info (ansi) */
533         lpLocalStartupInfo = RtlAllocateHeap (RtlGetProcessHeap (),
534                                               0,
535                                               sizeof(STARTUPINFOA));
536
537         lpLocalStartupInfo->cb = sizeof(STARTUPINFOA);
538
539         /* copy window title string */
540         RtlUnicodeStringToAnsiString (&AnsiString,
541                                       &Params->WindowTitle,
542                                       TRUE);
543         lpLocalStartupInfo->lpTitle = AnsiString.Buffer;
544
545         /* copy desktop info string */
546         RtlUnicodeStringToAnsiString (&AnsiString,
547                                       &Params->DesktopInfo,
548                                       TRUE);
549         lpLocalStartupInfo->lpDesktop = AnsiString.Buffer;
550
551         /* copy shell info string */
552         RtlUnicodeStringToAnsiString (&AnsiString,
553                                       &Params->ShellInfo,
554                                       TRUE);
555         lpLocalStartupInfo->lpReserved = AnsiString.Buffer;
556
557         lpLocalStartupInfo->dwX = Params->dwX;
558         lpLocalStartupInfo->dwY = Params->dwY;
559         lpLocalStartupInfo->dwXSize = Params->dwXSize;
560         lpLocalStartupInfo->dwYSize = Params->dwYSize;
561         lpLocalStartupInfo->dwXCountChars = Params->dwXCountChars;
562         lpLocalStartupInfo->dwYCountChars = Params->dwYCountChars;
563         lpLocalStartupInfo->dwFillAttribute = Params->dwFillAttribute;
564         lpLocalStartupInfo->dwFlags = Params->dwFlags;
565         lpLocalStartupInfo->wShowWindow = Params->wShowWindow;
566         lpLocalStartupInfo->cbReserved2 = Params->RuntimeInfo.Length;
567         lpLocalStartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeInfo.Buffer;
568
569         lpLocalStartupInfo->hStdInput = Params->hStdInput;
570         lpLocalStartupInfo->hStdOutput = Params->hStdOutput;
571         lpLocalStartupInfo->hStdError = Params->hStdError;
572      }
573
574    RtlReleasePebLock ();
575
576    /* copy local startup info data to external startup info */
577    memcpy (lpStartupInfo,
578            lpLocalStartupInfo,
579            sizeof(STARTUPINFOA));
580 }
581
582
583 /*
584  * @implemented
585  */
586 BOOL STDCALL
587 FlushInstructionCache (HANDLE   hProcess,
588                        LPCVOID  lpBaseAddress,
589                        DWORD    dwSize)
590 {
591   NTSTATUS Status;
592   
593   Status = NtFlushInstructionCache(hProcess,
594                                    (PVOID)lpBaseAddress,
595                                    dwSize);
596   if (!NT_SUCCESS(Status))
597     {
598       SetLastErrorByStatus(Status);
599       return FALSE;
600     }
601   return TRUE;
602 }
603
604
605 /*
606  * @implemented
607  */
608 VOID STDCALL
609 ExitProcess(UINT uExitCode)
610 {
611   CSRSS_API_REQUEST CsrRequest;
612   CSRSS_API_REPLY CsrReply;
613   NTSTATUS Status;
614   
615   /* unload all dll's */
616   LdrShutdownProcess ();
617
618   /* notify csrss of process termination */
619   CsrRequest.Type = CSRSS_TERMINATE_PROCESS;
620   Status = CsrClientCallServer(&CsrRequest, 
621                                &CsrReply,
622                                sizeof(CSRSS_API_REQUEST),
623                                sizeof(CSRSS_API_REPLY));
624   if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrReply.Status))
625     {
626       DbgPrint("Failed to tell csrss about terminating process. "
627                "Expect trouble.\n");
628     }
629   
630   
631   NtTerminateProcess (NtCurrentProcess (),
632                       uExitCode);
633
634   /* should never get here */
635   assert(0);
636   while(1);
637 }
638
639
640 /*
641  * @implemented
642  */
643 WINBOOL STDCALL
644 TerminateProcess (HANDLE        hProcess,
645                   UINT  uExitCode)
646 {
647   NTSTATUS Status;
648
649   Status = NtTerminateProcess (hProcess, uExitCode);
650   if (NT_SUCCESS(Status))
651     {
652       return TRUE;
653     }
654   SetLastErrorByStatus (Status);
655   return FALSE;
656 }
657
658
659 /*
660  * @unimplemented
661  */
662 VOID STDCALL
663 FatalAppExitA (UINT     uAction,
664                LPCSTR   lpMessageText)
665 {
666   UNICODE_STRING MessageTextU;
667   ANSI_STRING MessageText;
668   
669   RtlInitAnsiString (&MessageText, (LPSTR) lpMessageText);
670
671   RtlAnsiStringToUnicodeString (&MessageTextU,
672                                 &MessageText,
673                                 TRUE);
674
675   FatalAppExitW (uAction, MessageTextU.Buffer);
676
677   RtlFreeUnicodeString (&MessageTextU);
678 }
679
680
681 /*
682  * @unimplemented
683  */
684 VOID STDCALL
685 FatalAppExitW(UINT uAction,
686               LPCWSTR lpMessageText)
687 {
688   return;
689 }
690
691
692 /*
693  * @implemented
694  */
695 VOID STDCALL
696 FatalExit (int ExitCode)
697 {
698   ExitProcess(ExitCode);
699 }
700
701
702 /*
703  * @implemented
704  */
705 DWORD STDCALL
706 GetPriorityClass (HANDLE        hProcess)
707 {
708   HANDLE                hProcessTmp;
709   DWORD         CsrPriorityClass = 0; // This tells CSRSS we want to GET it!
710   NTSTATUS      Status;
711         
712   Status = 
713     NtDuplicateObject (GetCurrentProcess(),
714                        hProcess,
715                        GetCurrentProcess(),
716                        &hProcessTmp,
717                        (PROCESS_SET_INFORMATION | PROCESS_QUERY_INFORMATION),
718                        FALSE,
719                        0);
720   if (!NT_SUCCESS(Status))
721     {
722       SetLastErrorByStatus (Status);
723       return (0); /* ERROR */
724     }
725   /* Ask CSRSS to set it */
726   CsrSetPriorityClass (hProcessTmp, &CsrPriorityClass);
727   NtClose (hProcessTmp);
728   /* Translate CSR->W32 priorities */
729   switch (CsrPriorityClass)
730     {
731     case CSR_PRIORITY_CLASS_NORMAL:
732       return (NORMAL_PRIORITY_CLASS);   /* 32 */
733     case CSR_PRIORITY_CLASS_IDLE:
734       return (IDLE_PRIORITY_CLASS);     /* 64 */
735     case CSR_PRIORITY_CLASS_HIGH:
736       return (HIGH_PRIORITY_CLASS);     /* 128 */
737     case CSR_PRIORITY_CLASS_REALTIME:
738       return (REALTIME_PRIORITY_CLASS); /* 256 */
739     }
740   SetLastError (ERROR_ACCESS_DENIED);
741   return (0); /* ERROR */
742 }
743
744
745 /*
746  * @implemented
747  */
748 WINBOOL STDCALL
749 SetPriorityClass (HANDLE        hProcess,
750                   DWORD dwPriorityClass)
751 {
752   HANDLE                hProcessTmp;
753   DWORD         CsrPriorityClass;
754   NTSTATUS      Status;
755   
756   switch (dwPriorityClass)
757     {
758     case NORMAL_PRIORITY_CLASS: /* 32 */
759       CsrPriorityClass = CSR_PRIORITY_CLASS_NORMAL;
760       break;
761     case IDLE_PRIORITY_CLASS:   /* 64 */
762       CsrPriorityClass = CSR_PRIORITY_CLASS_IDLE;
763       break;
764     case HIGH_PRIORITY_CLASS:   /* 128 */
765       CsrPriorityClass = CSR_PRIORITY_CLASS_HIGH;
766       break;
767     case REALTIME_PRIORITY_CLASS:       /* 256 */
768       CsrPriorityClass = CSR_PRIORITY_CLASS_REALTIME;
769       break;
770     default:
771       SetLastError (ERROR_INVALID_PARAMETER);
772       return (FALSE);
773     }
774   Status = 
775     NtDuplicateObject (GetCurrentProcess(),
776                        hProcess,
777                        GetCurrentProcess(),
778                        &hProcessTmp,
779                        (PROCESS_SET_INFORMATION | PROCESS_QUERY_INFORMATION),
780                        FALSE,
781                        0);
782   if (!NT_SUCCESS(Status))
783     {
784       SetLastErrorByStatus (Status);
785       return (FALSE); /* ERROR */
786     }
787   /* Ask CSRSS to set it */
788   Status = CsrSetPriorityClass (hProcessTmp, &CsrPriorityClass);
789   NtClose (hProcessTmp);
790   if (!NT_SUCCESS(Status))
791     {
792       SetLastErrorByStatus (Status);
793       return (FALSE);
794     }
795   return (TRUE);
796 }
797
798
799 /*
800  * @implemented
801  */
802 DWORD STDCALL
803 GetProcessVersion (DWORD ProcessId)
804 {
805   DWORD                 Version = 0;
806   PIMAGE_NT_HEADERS     NtHeader = NULL;
807   PVOID                 BaseAddress = NULL;
808
809   /* Caller's */
810   if (0 == ProcessId || GetCurrentProcessId() == ProcessId)
811     {
812       BaseAddress = (PVOID) NtCurrentPeb()->ImageBaseAddress;
813       NtHeader = RtlImageNtHeader (BaseAddress);
814       if (NULL != NtHeader)
815         {
816           Version =
817             (NtHeader->OptionalHeader.MajorOperatingSystemVersion << 16) | 
818             (NtHeader->OptionalHeader.MinorOperatingSystemVersion);
819         }
820     }
821   else /* other process */
822     {
823       /* FIXME: open the other process */
824       SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
825     }
826   return (Version);
827 }
828
829 /* EOF */