4 * This file contains the Nt* API functions of NTDLL.DLL.
5 * In the original ntdll.dll they all seem to just call int 0x2e (down to the NTOSKRNL)
7 * Copyright 1996-1998 Marcus Meissner
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
36 #define WIN32_NO_STATUS
37 #include "wine/debug.h"
40 #include "ntdll_misc.h"
41 #include "wine/server.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(ntdll
);
45 static ULONG execute_flags
= MEM_EXECUTE_OPTION_DISABLE
;
51 /******************************************************************************
52 * NtTerminateProcess [NTDLL.@]
54 * Native applications must kill themselves when done
56 NTSTATUS WINAPI
NtTerminateProcess( HANDLE handle
, LONG exit_code
)
60 SERVER_START_REQ( terminate_process
)
62 req
->handle
= wine_server_obj_handle( handle
);
63 req
->exit_code
= exit_code
;
64 ret
= wine_server_call( req
);
65 self
= !ret
&& reply
->self
;
68 if (self
&& handle
) _exit( exit_code
);
72 /******************************************************************************
73 * RtlGetCurrentPeb [NTDLL.@]
76 PEB
* WINAPI
RtlGetCurrentPeb(void)
78 return NtCurrentTeb()->Peb
;
81 /***********************************************************************
82 * __wine_make_process_system (NTDLL.@)
84 * Mark the current process as a system process.
85 * Returns the event that is signaled when all non-system processes have exited.
87 HANDLE CDECL
__wine_make_process_system(void)
90 SERVER_START_REQ( make_process_system
)
92 if (!wine_server_call( req
)) ret
= wine_server_ptr_handle( reply
->event
);
98 static UINT process_error_mode
;
100 #define UNIMPLEMENTED_INFO_CLASS(c) \
102 FIXME("(process=%p) Unimplemented information class: " #c "\n", ProcessHandle); \
103 ret = STATUS_INVALID_INFO_CLASS; \
106 ULONG_PTR
get_system_affinity_mask(void)
108 ULONG num_cpus
= NtCurrentTeb()->Peb
->NumberOfProcessors
;
109 if (num_cpus
>= sizeof(ULONG_PTR
) * 8) return ~(ULONG_PTR
)0;
110 return ((ULONG_PTR
)1 << num_cpus
) - 1;
113 /******************************************************************************
114 * NtQueryInformationProcess [NTDLL.@]
115 * ZwQueryInformationProcess [NTDLL.@]
118 NTSTATUS WINAPI
NtQueryInformationProcess(
119 IN HANDLE ProcessHandle
,
120 IN PROCESSINFOCLASS ProcessInformationClass
,
121 OUT PVOID ProcessInformation
,
122 IN ULONG ProcessInformationLength
,
123 OUT PULONG ReturnLength
)
125 NTSTATUS ret
= STATUS_SUCCESS
;
128 TRACE("(%p,0x%08x,%p,0x%08x,%p)\n",
129 ProcessHandle
,ProcessInformationClass
,
130 ProcessInformation
,ProcessInformationLength
,
133 switch (ProcessInformationClass
)
135 UNIMPLEMENTED_INFO_CLASS(ProcessQuotaLimits
);
136 UNIMPLEMENTED_INFO_CLASS(ProcessBasePriority
);
137 UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority
);
138 UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort
);
139 UNIMPLEMENTED_INFO_CLASS(ProcessAccessToken
);
140 UNIMPLEMENTED_INFO_CLASS(ProcessLdtInformation
);
141 UNIMPLEMENTED_INFO_CLASS(ProcessLdtSize
);
142 UNIMPLEMENTED_INFO_CLASS(ProcessIoPortHandlers
);
143 UNIMPLEMENTED_INFO_CLASS(ProcessPooledUsageAndLimits
);
144 UNIMPLEMENTED_INFO_CLASS(ProcessWorkingSetWatch
);
145 UNIMPLEMENTED_INFO_CLASS(ProcessUserModeIOPL
);
146 UNIMPLEMENTED_INFO_CLASS(ProcessEnableAlignmentFaultFixup
);
147 UNIMPLEMENTED_INFO_CLASS(ProcessPriorityClass
);
148 UNIMPLEMENTED_INFO_CLASS(ProcessWx86Information
);
149 UNIMPLEMENTED_INFO_CLASS(ProcessPriorityBoost
);
150 UNIMPLEMENTED_INFO_CLASS(ProcessDeviceMap
);
151 UNIMPLEMENTED_INFO_CLASS(ProcessSessionInformation
);
152 UNIMPLEMENTED_INFO_CLASS(ProcessForegroundInformation
);
153 UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled
);
154 UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination
);
155 UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing
);
157 case ProcessBasicInformation
:
159 PROCESS_BASIC_INFORMATION pbi
;
160 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
162 if (ProcessInformationLength
>= sizeof(PROCESS_BASIC_INFORMATION
))
164 if (!ProcessInformation
)
165 ret
= STATUS_ACCESS_VIOLATION
;
166 else if (!ProcessHandle
)
167 ret
= STATUS_INVALID_HANDLE
;
170 SERVER_START_REQ(get_process_info
)
172 req
->handle
= wine_server_obj_handle( ProcessHandle
);
173 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
175 pbi
.ExitStatus
= reply
->exit_code
;
176 pbi
.PebBaseAddress
= wine_server_get_ptr( reply
->peb
);
177 pbi
.AffinityMask
= reply
->affinity
& affinity_mask
;
178 pbi
.BasePriority
= reply
->priority
;
179 pbi
.UniqueProcessId
= reply
->pid
;
180 pbi
.InheritedFromUniqueProcessId
= reply
->ppid
;
185 memcpy(ProcessInformation
, &pbi
, sizeof(PROCESS_BASIC_INFORMATION
));
187 len
= sizeof(PROCESS_BASIC_INFORMATION
);
190 if (ProcessInformationLength
> sizeof(PROCESS_BASIC_INFORMATION
))
191 ret
= STATUS_INFO_LENGTH_MISMATCH
;
195 len
= sizeof(PROCESS_BASIC_INFORMATION
);
196 ret
= STATUS_INFO_LENGTH_MISMATCH
;
200 case ProcessIoCounters
:
204 if (ProcessInformationLength
>= sizeof(IO_COUNTERS
))
206 if (!ProcessInformation
)
207 ret
= STATUS_ACCESS_VIOLATION
;
208 else if (!ProcessHandle
)
209 ret
= STATUS_INVALID_HANDLE
;
212 /* FIXME : real data */
213 memset(&pii
, 0 , sizeof(IO_COUNTERS
));
215 memcpy(ProcessInformation
, &pii
, sizeof(IO_COUNTERS
));
217 len
= sizeof(IO_COUNTERS
);
220 if (ProcessInformationLength
> sizeof(IO_COUNTERS
))
221 ret
= STATUS_INFO_LENGTH_MISMATCH
;
225 len
= sizeof(IO_COUNTERS
);
226 ret
= STATUS_INFO_LENGTH_MISMATCH
;
230 case ProcessVmCounters
:
234 /* older Windows versions don't have the PrivatePageCount field */
235 if (ProcessInformationLength
>= FIELD_OFFSET(VM_COUNTERS
,PrivatePageCount
))
237 if (!ProcessInformation
)
238 ret
= STATUS_ACCESS_VIOLATION
;
239 else if (!ProcessHandle
)
240 ret
= STATUS_INVALID_HANDLE
;
243 /* FIXME : real data */
244 memset(&pvmi
, 0 , sizeof(VM_COUNTERS
));
246 len
= ProcessInformationLength
;
247 if (len
!= FIELD_OFFSET(VM_COUNTERS
,PrivatePageCount
)) len
= sizeof(VM_COUNTERS
);
249 memcpy(ProcessInformation
, &pvmi
, min(ProcessInformationLength
,sizeof(VM_COUNTERS
)));
252 if (ProcessInformationLength
!= FIELD_OFFSET(VM_COUNTERS
,PrivatePageCount
) &&
253 ProcessInformationLength
!= sizeof(VM_COUNTERS
))
254 ret
= STATUS_INFO_LENGTH_MISMATCH
;
259 ret
= STATUS_INFO_LENGTH_MISMATCH
;
265 KERNEL_USER_TIMES pti
;
267 if (ProcessInformationLength
>= sizeof(KERNEL_USER_TIMES
))
269 if (!ProcessInformation
)
270 ret
= STATUS_ACCESS_VIOLATION
;
271 else if (!ProcessHandle
)
272 ret
= STATUS_INVALID_HANDLE
;
275 /* FIXME : User- and KernelTime have to be implemented */
276 memset(&pti
, 0, sizeof(KERNEL_USER_TIMES
));
278 SERVER_START_REQ(get_process_info
)
280 req
->handle
= wine_server_obj_handle( ProcessHandle
);
281 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
283 pti
.CreateTime
.QuadPart
= reply
->start_time
;
284 pti
.ExitTime
.QuadPart
= reply
->end_time
;
289 memcpy(ProcessInformation
, &pti
, sizeof(KERNEL_USER_TIMES
));
290 len
= sizeof(KERNEL_USER_TIMES
);
293 if (ProcessInformationLength
> sizeof(KERNEL_USER_TIMES
))
294 ret
= STATUS_INFO_LENGTH_MISMATCH
;
298 len
= sizeof(KERNEL_USER_TIMES
);
299 ret
= STATUS_INFO_LENGTH_MISMATCH
;
303 case ProcessDebugPort
:
304 len
= sizeof(DWORD_PTR
);
305 if (ProcessInformationLength
== len
)
307 if (!ProcessInformation
)
308 ret
= STATUS_ACCESS_VIOLATION
;
309 else if (!ProcessHandle
)
310 ret
= STATUS_INVALID_HANDLE
;
313 SERVER_START_REQ(get_process_info
)
315 req
->handle
= wine_server_obj_handle( ProcessHandle
);
316 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
318 *(DWORD_PTR
*)ProcessInformation
= reply
->debugger_present
? ~(DWORD_PTR
)0 : 0;
325 ret
= STATUS_INFO_LENGTH_MISMATCH
;
327 case ProcessDebugFlags
:
329 if (ProcessInformationLength
== len
)
331 if (!ProcessInformation
)
332 ret
= STATUS_ACCESS_VIOLATION
;
333 else if (!ProcessHandle
)
334 ret
= STATUS_INVALID_HANDLE
;
337 SERVER_START_REQ(get_process_info
)
339 req
->handle
= wine_server_obj_handle( ProcessHandle
);
340 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
342 *(DWORD
*)ProcessInformation
= reply
->debug_children
;
349 ret
= STATUS_INFO_LENGTH_MISMATCH
;
351 case ProcessDefaultHardErrorMode
:
352 len
= sizeof(process_error_mode
);
353 if (ProcessInformationLength
== len
)
354 memcpy(ProcessInformation
, &process_error_mode
, len
);
356 ret
= STATUS_INFO_LENGTH_MISMATCH
;
358 case ProcessDebugObjectHandle
:
359 /* "These are not the debuggers you are looking for." *
360 * set it to 0 aka "no debugger" to satisfy copy protections */
361 len
= sizeof(HANDLE
);
362 if (ProcessInformationLength
== len
)
364 if (!ProcessInformation
)
365 ret
= STATUS_ACCESS_VIOLATION
;
366 else if (!ProcessHandle
)
367 ret
= STATUS_INVALID_HANDLE
;
370 memset(ProcessInformation
, 0, ProcessInformationLength
);
371 ret
= STATUS_PORT_NOT_SET
;
375 ret
= STATUS_INFO_LENGTH_MISMATCH
;
377 case ProcessHandleCount
:
378 if (ProcessInformationLength
>= 4)
380 if (!ProcessInformation
)
381 ret
= STATUS_ACCESS_VIOLATION
;
382 else if (!ProcessHandle
)
383 ret
= STATUS_INVALID_HANDLE
;
386 memset(ProcessInformation
, 0, 4);
390 if (ProcessInformationLength
> 4)
391 ret
= STATUS_INFO_LENGTH_MISMATCH
;
396 ret
= STATUS_INFO_LENGTH_MISMATCH
;
400 case ProcessAffinityMask
:
401 len
= sizeof(ULONG_PTR
);
402 if (ProcessInformationLength
== len
)
404 const ULONG_PTR system_mask
= get_system_affinity_mask();
406 SERVER_START_REQ(get_process_info
)
408 req
->handle
= wine_server_obj_handle( ProcessHandle
);
409 if (!(ret
= wine_server_call( req
)))
410 *(ULONG_PTR
*)ProcessInformation
= reply
->affinity
& system_mask
;
414 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
417 case ProcessWow64Information
:
418 len
= sizeof(ULONG_PTR
);
419 if (ProcessInformationLength
!= len
) ret
= STATUS_INFO_LENGTH_MISMATCH
;
420 else if (!ProcessInformation
) ret
= STATUS_ACCESS_VIOLATION
;
421 else if(!ProcessHandle
) ret
= STATUS_INVALID_HANDLE
;
426 if (ProcessHandle
== GetCurrentProcess()) val
= is_wow64
;
427 else if (server_cpus
& ((1 << CPU_x86_64
) | (1 << CPU_ARM64
)))
429 SERVER_START_REQ( get_process_info
)
431 req
->handle
= wine_server_obj_handle( ProcessHandle
);
432 if (!(ret
= wine_server_call( req
)))
433 val
= (reply
->cpu
!= CPU_x86_64
&& reply
->cpu
!= CPU_ARM64
);
437 *(ULONG_PTR
*)ProcessInformation
= val
;
440 case ProcessImageFileName
:
441 /* FIXME: this will return a DOS path. Windows returns an NT path. Changing this would require also changing kernel32.QueryFullProcessImageName.
442 * The latter may be harder because of the lack of RtlNtPathNameToDosPathName. */
443 SERVER_START_REQ(get_dll_info
)
445 UNICODE_STRING
*image_file_name_str
= ProcessInformation
;
447 req
->handle
= wine_server_obj_handle( ProcessHandle
);
448 req
->base_address
= 0; /* main module */
449 wine_server_set_reply( req
, image_file_name_str
? image_file_name_str
+ 1 : NULL
,
450 ProcessInformationLength
> sizeof(UNICODE_STRING
) ? ProcessInformationLength
- sizeof(UNICODE_STRING
) : 0 );
451 ret
= wine_server_call( req
);
452 if (ret
== STATUS_BUFFER_TOO_SMALL
) ret
= STATUS_INFO_LENGTH_MISMATCH
;
454 len
= sizeof(UNICODE_STRING
) + reply
->filename_len
;
455 if (ret
== STATUS_SUCCESS
)
457 image_file_name_str
->MaximumLength
= image_file_name_str
->Length
= reply
->filename_len
;
458 image_file_name_str
->Buffer
= (PWSTR
)(image_file_name_str
+ 1);
463 case ProcessExecuteFlags
:
465 if (ProcessInformationLength
== len
)
466 *(ULONG
*)ProcessInformation
= execute_flags
;
468 ret
= STATUS_INFO_LENGTH_MISMATCH
;
471 FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n",
472 ProcessHandle
,ProcessInformationClass
,
473 ProcessInformation
,ProcessInformationLength
,
475 ret
= STATUS_INVALID_INFO_CLASS
;
479 if (ReturnLength
) *ReturnLength
= len
;
484 /******************************************************************************
485 * NtSetInformationProcess [NTDLL.@]
486 * ZwSetInformationProcess [NTDLL.@]
488 NTSTATUS WINAPI
NtSetInformationProcess(
489 IN HANDLE ProcessHandle
,
490 IN PROCESSINFOCLASS ProcessInformationClass
,
491 IN PVOID ProcessInformation
,
492 IN ULONG ProcessInformationLength
)
494 NTSTATUS ret
= STATUS_SUCCESS
;
496 switch (ProcessInformationClass
)
498 case ProcessDefaultHardErrorMode
:
499 if (ProcessInformationLength
!= sizeof(UINT
)) return STATUS_INVALID_PARAMETER
;
500 process_error_mode
= *(UINT
*)ProcessInformation
;
502 case ProcessAffinityMask
:
504 const ULONG_PTR system_mask
= get_system_affinity_mask();
506 if (ProcessInformationLength
!= sizeof(DWORD_PTR
)) return STATUS_INVALID_PARAMETER
;
507 if (*(PDWORD_PTR
)ProcessInformation
& ~system_mask
)
508 return STATUS_INVALID_PARAMETER
;
509 if (!*(PDWORD_PTR
)ProcessInformation
)
510 return STATUS_INVALID_PARAMETER
;
511 SERVER_START_REQ( set_process_info
)
513 req
->handle
= wine_server_obj_handle( ProcessHandle
);
514 req
->affinity
= *(PDWORD_PTR
)ProcessInformation
;
515 req
->mask
= SET_PROCESS_INFO_AFFINITY
;
516 ret
= wine_server_call( req
);
521 case ProcessPriorityClass
:
522 if (ProcessInformationLength
!= sizeof(PROCESS_PRIORITY_CLASS
))
523 return STATUS_INVALID_PARAMETER
;
526 PROCESS_PRIORITY_CLASS
* ppc
= ProcessInformation
;
528 SERVER_START_REQ( set_process_info
)
530 req
->handle
= wine_server_obj_handle( ProcessHandle
);
531 /* FIXME Foreground isn't used */
532 req
->priority
= ppc
->PriorityClass
;
533 req
->mask
= SET_PROCESS_INFO_PRIORITY
;
534 ret
= wine_server_call( req
);
540 case ProcessExecuteFlags
:
541 if (ProcessInformationLength
!= sizeof(ULONG
))
542 return STATUS_INVALID_PARAMETER
;
543 else if (execute_flags
& MEM_EXECUTE_OPTION_PERMANENT
)
544 return STATUS_ACCESS_DENIED
;
548 switch (*(ULONG
*)ProcessInformation
& (MEM_EXECUTE_OPTION_ENABLE
|MEM_EXECUTE_OPTION_DISABLE
))
550 case MEM_EXECUTE_OPTION_ENABLE
:
553 case MEM_EXECUTE_OPTION_DISABLE
:
557 return STATUS_INVALID_PARAMETER
;
559 execute_flags
= *(ULONG
*)ProcessInformation
;
560 VIRTUAL_SetForceExec( enable
);
565 FIXME("(%p,0x%08x,%p,0x%08x) stub\n",
566 ProcessHandle
,ProcessInformationClass
,ProcessInformation
,
567 ProcessInformationLength
);
568 ret
= STATUS_NOT_IMPLEMENTED
;
574 /******************************************************************************
575 * NtFlushInstructionCache [NTDLL.@]
576 * ZwFlushInstructionCache [NTDLL.@]
578 NTSTATUS WINAPI
NtFlushInstructionCache(
579 IN HANDLE ProcessHandle
,
580 IN LPCVOID BaseAddress
,
586 #if defined(__x86_64__) || defined(__i386__)
587 TRACE("%p %p %ld - no-op on x86 and x86_64\n", ProcessHandle
, BaseAddress
, Size
);
589 FIXME("%p %p %ld\n", ProcessHandle
, BaseAddress
, Size
);
592 return STATUS_SUCCESS
;
595 /******************************************************************
596 * NtOpenProcess [NTDLL.@]
597 * ZwOpenProcess [NTDLL.@]
599 NTSTATUS WINAPI
NtOpenProcess(PHANDLE handle
, ACCESS_MASK access
,
600 const OBJECT_ATTRIBUTES
* attr
, const CLIENT_ID
* cid
)
604 SERVER_START_REQ( open_process
)
606 req
->pid
= HandleToULong(cid
->UniqueProcess
);
607 req
->access
= access
;
608 req
->attributes
= attr
? attr
->Attributes
: 0;
609 status
= wine_server_call( req
);
610 if (!status
) *handle
= wine_server_ptr_handle( reply
->handle
);