4 * Copyright 1996-1998 Marcus Meissner
5 * Copyright 2018 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/port.h"
32 #ifdef HAVE_SYS_SOCKET_H
33 #include <sys/socket.h>
35 #include <sys/types.h>
36 #ifdef HAVE_SYS_WAIT_H
37 # include <sys/wait.h>
44 #define WIN32_NO_STATUS
45 #include "wine/debug.h"
48 #include "ntdll_misc.h"
49 #include "wine/library.h"
50 #include "wine/server.h"
51 #include "wine/unicode.h"
53 #ifdef HAVE_MACH_MACH_H
54 #include <mach/mach.h>
57 WINE_DEFAULT_DEBUG_CHANNEL(process
);
59 static ULONG execute_flags
= MEM_EXECUTE_OPTION_DISABLE
;
61 static const BOOL is_win64
= (sizeof(void *) > sizeof(int));
63 static const char * const cpu_names
[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64" };
65 static inline BOOL
is_64bit_arch( cpu_type_t cpu
)
67 return (cpu
== CPU_x86_64
|| cpu
== CPU_ARM64
);
74 /******************************************************************************
75 * NtTerminateProcess [NTDLL.@]
77 * Native applications must kill themselves when done
79 NTSTATUS WINAPI
NtTerminateProcess( HANDLE handle
, LONG exit_code
)
83 SERVER_START_REQ( terminate_process
)
85 req
->handle
= wine_server_obj_handle( handle
);
86 req
->exit_code
= exit_code
;
87 ret
= wine_server_call( req
);
88 self
= !ret
&& reply
->self
;
91 if (self
&& handle
) _exit( exit_code
);
95 /******************************************************************************
96 * RtlGetCurrentPeb [NTDLL.@]
99 PEB
* WINAPI
RtlGetCurrentPeb(void)
101 return NtCurrentTeb()->Peb
;
104 /***********************************************************************
105 * __wine_make_process_system (NTDLL.@)
107 * Mark the current process as a system process.
108 * Returns the event that is signaled when all non-system processes have exited.
110 HANDLE CDECL
__wine_make_process_system(void)
113 SERVER_START_REQ( make_process_system
)
115 if (!wine_server_call( req
)) ret
= wine_server_ptr_handle( reply
->event
);
121 static UINT process_error_mode
;
123 #define UNIMPLEMENTED_INFO_CLASS(c) \
125 FIXME("(process=%p) Unimplemented information class: " #c "\n", ProcessHandle); \
126 ret = STATUS_INVALID_INFO_CLASS; \
129 ULONG_PTR
get_system_affinity_mask(void)
131 ULONG num_cpus
= NtCurrentTeb()->Peb
->NumberOfProcessors
;
132 if (num_cpus
>= sizeof(ULONG_PTR
) * 8) return ~(ULONG_PTR
)0;
133 return ((ULONG_PTR
)1 << num_cpus
) - 1;
136 #if defined(HAVE_MACH_MACH_H)
138 static void fill_VM_COUNTERS(VM_COUNTERS
* pvmi
)
140 #if defined(MACH_TASK_BASIC_INFO)
141 struct mach_task_basic_info info
;
142 mach_msg_type_number_t infoCount
= MACH_TASK_BASIC_INFO_COUNT
;
143 if(task_info(mach_task_self(), MACH_TASK_BASIC_INFO
, (task_info_t
)&info
, &infoCount
) == KERN_SUCCESS
)
145 pvmi
->VirtualSize
= info
.resident_size
+ info
.virtual_size
;
146 pvmi
->PagefileUsage
= info
.virtual_size
;
147 pvmi
->WorkingSetSize
= info
.resident_size
;
148 pvmi
->PeakWorkingSetSize
= info
.resident_size_max
;
155 static void fill_VM_COUNTERS(VM_COUNTERS
* pvmi
)
161 f
= fopen("/proc/self/status", "r");
164 while (fgets(line
, sizeof(line
), f
))
166 if (sscanf(line
, "VmPeak: %lu", &value
))
167 pvmi
->PeakVirtualSize
= (ULONG64
)value
* 1024;
168 else if (sscanf(line
, "VmSize: %lu", &value
))
169 pvmi
->VirtualSize
= (ULONG64
)value
* 1024;
170 else if (sscanf(line
, "VmHWM: %lu", &value
))
171 pvmi
->PeakWorkingSetSize
= (ULONG64
)value
* 1024;
172 else if (sscanf(line
, "VmRSS: %lu", &value
))
173 pvmi
->WorkingSetSize
= (ULONG64
)value
* 1024;
174 else if (sscanf(line
, "RssAnon: %lu", &value
))
175 pvmi
->PagefileUsage
+= (ULONG64
)value
* 1024;
176 else if (sscanf(line
, "VmSwap: %lu", &value
))
177 pvmi
->PagefileUsage
+= (ULONG64
)value
* 1024;
179 pvmi
->PeakPagefileUsage
= pvmi
->PagefileUsage
;
186 static void fill_VM_COUNTERS(VM_COUNTERS
* pvmi
)
188 /* FIXME : real data */
193 /******************************************************************************
194 * NtQueryInformationProcess [NTDLL.@]
195 * ZwQueryInformationProcess [NTDLL.@]
198 NTSTATUS WINAPI
NtQueryInformationProcess(
199 IN HANDLE ProcessHandle
,
200 IN PROCESSINFOCLASS ProcessInformationClass
,
201 OUT PVOID ProcessInformation
,
202 IN ULONG ProcessInformationLength
,
203 OUT PULONG ReturnLength
)
205 NTSTATUS ret
= STATUS_SUCCESS
;
208 TRACE("(%p,0x%08x,%p,0x%08x,%p)\n",
209 ProcessHandle
,ProcessInformationClass
,
210 ProcessInformation
,ProcessInformationLength
,
213 switch (ProcessInformationClass
)
215 UNIMPLEMENTED_INFO_CLASS(ProcessQuotaLimits
);
216 UNIMPLEMENTED_INFO_CLASS(ProcessBasePriority
);
217 UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority
);
218 UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort
);
219 UNIMPLEMENTED_INFO_CLASS(ProcessAccessToken
);
220 UNIMPLEMENTED_INFO_CLASS(ProcessLdtInformation
);
221 UNIMPLEMENTED_INFO_CLASS(ProcessLdtSize
);
222 UNIMPLEMENTED_INFO_CLASS(ProcessIoPortHandlers
);
223 UNIMPLEMENTED_INFO_CLASS(ProcessPooledUsageAndLimits
);
224 UNIMPLEMENTED_INFO_CLASS(ProcessWorkingSetWatch
);
225 UNIMPLEMENTED_INFO_CLASS(ProcessUserModeIOPL
);
226 UNIMPLEMENTED_INFO_CLASS(ProcessEnableAlignmentFaultFixup
);
227 UNIMPLEMENTED_INFO_CLASS(ProcessWx86Information
);
228 UNIMPLEMENTED_INFO_CLASS(ProcessPriorityBoost
);
229 UNIMPLEMENTED_INFO_CLASS(ProcessDeviceMap
);
230 UNIMPLEMENTED_INFO_CLASS(ProcessSessionInformation
);
231 UNIMPLEMENTED_INFO_CLASS(ProcessForegroundInformation
);
232 UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled
);
233 UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination
);
234 UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing
);
236 case ProcessBasicInformation
:
238 PROCESS_BASIC_INFORMATION pbi
;
239 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
241 if (ProcessInformationLength
>= sizeof(PROCESS_BASIC_INFORMATION
))
243 if (!ProcessInformation
)
244 ret
= STATUS_ACCESS_VIOLATION
;
245 else if (!ProcessHandle
)
246 ret
= STATUS_INVALID_HANDLE
;
249 SERVER_START_REQ(get_process_info
)
251 req
->handle
= wine_server_obj_handle( ProcessHandle
);
252 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
254 pbi
.ExitStatus
= reply
->exit_code
;
255 pbi
.PebBaseAddress
= wine_server_get_ptr( reply
->peb
);
256 pbi
.AffinityMask
= reply
->affinity
& affinity_mask
;
257 pbi
.BasePriority
= reply
->priority
;
258 pbi
.UniqueProcessId
= reply
->pid
;
259 pbi
.InheritedFromUniqueProcessId
= reply
->ppid
;
264 memcpy(ProcessInformation
, &pbi
, sizeof(PROCESS_BASIC_INFORMATION
));
266 len
= sizeof(PROCESS_BASIC_INFORMATION
);
269 if (ProcessInformationLength
> sizeof(PROCESS_BASIC_INFORMATION
))
270 ret
= STATUS_INFO_LENGTH_MISMATCH
;
274 len
= sizeof(PROCESS_BASIC_INFORMATION
);
275 ret
= STATUS_INFO_LENGTH_MISMATCH
;
279 case ProcessIoCounters
:
283 if (ProcessInformationLength
>= sizeof(IO_COUNTERS
))
285 if (!ProcessInformation
)
286 ret
= STATUS_ACCESS_VIOLATION
;
287 else if (!ProcessHandle
)
288 ret
= STATUS_INVALID_HANDLE
;
291 /* FIXME : real data */
292 memset(&pii
, 0 , sizeof(IO_COUNTERS
));
294 memcpy(ProcessInformation
, &pii
, sizeof(IO_COUNTERS
));
296 len
= sizeof(IO_COUNTERS
);
299 if (ProcessInformationLength
> sizeof(IO_COUNTERS
))
300 ret
= STATUS_INFO_LENGTH_MISMATCH
;
304 len
= sizeof(IO_COUNTERS
);
305 ret
= STATUS_INFO_LENGTH_MISMATCH
;
309 case ProcessVmCounters
:
313 /* older Windows versions don't have the PrivatePageCount field */
314 if (ProcessInformationLength
>= FIELD_OFFSET(VM_COUNTERS
,PrivatePageCount
))
316 if (!ProcessInformation
)
317 ret
= STATUS_ACCESS_VIOLATION
;
320 memset(&pvmi
, 0 , sizeof(VM_COUNTERS
));
321 if (ProcessHandle
== GetCurrentProcess())
322 fill_VM_COUNTERS(&pvmi
);
325 SERVER_START_REQ(get_process_vm_counters
)
327 req
->handle
= wine_server_obj_handle( ProcessHandle
);
328 if (!(ret
= wine_server_call( req
)))
330 pvmi
.PeakVirtualSize
= reply
->peak_virtual_size
;
331 pvmi
.VirtualSize
= reply
->virtual_size
;
332 pvmi
.PeakWorkingSetSize
= reply
->peak_working_set_size
;
333 pvmi
.WorkingSetSize
= reply
->working_set_size
;
334 pvmi
.PagefileUsage
= reply
->pagefile_usage
;
335 pvmi
.PeakPagefileUsage
= reply
->peak_pagefile_usage
;
342 len
= ProcessInformationLength
;
343 if (len
!= FIELD_OFFSET(VM_COUNTERS
,PrivatePageCount
)) len
= sizeof(VM_COUNTERS
);
345 memcpy(ProcessInformation
, &pvmi
, min(ProcessInformationLength
,sizeof(VM_COUNTERS
)));
348 if (ProcessInformationLength
!= FIELD_OFFSET(VM_COUNTERS
,PrivatePageCount
) &&
349 ProcessInformationLength
!= sizeof(VM_COUNTERS
))
350 ret
= STATUS_INFO_LENGTH_MISMATCH
;
355 ret
= STATUS_INFO_LENGTH_MISMATCH
;
361 KERNEL_USER_TIMES pti
;
363 if (ProcessInformationLength
>= sizeof(KERNEL_USER_TIMES
))
365 if (!ProcessInformation
)
366 ret
= STATUS_ACCESS_VIOLATION
;
367 else if (!ProcessHandle
)
368 ret
= STATUS_INVALID_HANDLE
;
371 /* FIXME : User- and KernelTime have to be implemented */
372 memset(&pti
, 0, sizeof(KERNEL_USER_TIMES
));
374 SERVER_START_REQ(get_process_info
)
376 req
->handle
= wine_server_obj_handle( ProcessHandle
);
377 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
379 pti
.CreateTime
.QuadPart
= reply
->start_time
;
380 pti
.ExitTime
.QuadPart
= reply
->end_time
;
385 memcpy(ProcessInformation
, &pti
, sizeof(KERNEL_USER_TIMES
));
386 len
= sizeof(KERNEL_USER_TIMES
);
389 if (ProcessInformationLength
> sizeof(KERNEL_USER_TIMES
))
390 ret
= STATUS_INFO_LENGTH_MISMATCH
;
394 len
= sizeof(KERNEL_USER_TIMES
);
395 ret
= STATUS_INFO_LENGTH_MISMATCH
;
399 case ProcessDebugPort
:
400 len
= sizeof(DWORD_PTR
);
401 if (ProcessInformationLength
== len
)
403 if (!ProcessInformation
)
404 ret
= STATUS_ACCESS_VIOLATION
;
405 else if (!ProcessHandle
)
406 ret
= STATUS_INVALID_HANDLE
;
409 SERVER_START_REQ(get_process_info
)
411 req
->handle
= wine_server_obj_handle( ProcessHandle
);
412 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
414 *(DWORD_PTR
*)ProcessInformation
= reply
->debugger_present
? ~(DWORD_PTR
)0 : 0;
421 ret
= STATUS_INFO_LENGTH_MISMATCH
;
423 case ProcessDebugFlags
:
425 if (ProcessInformationLength
== len
)
427 if (!ProcessInformation
)
428 ret
= STATUS_ACCESS_VIOLATION
;
429 else if (!ProcessHandle
)
430 ret
= STATUS_INVALID_HANDLE
;
433 SERVER_START_REQ(get_process_info
)
435 req
->handle
= wine_server_obj_handle( ProcessHandle
);
436 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
438 *(DWORD
*)ProcessInformation
= reply
->debug_children
;
445 ret
= STATUS_INFO_LENGTH_MISMATCH
;
447 case ProcessDefaultHardErrorMode
:
448 len
= sizeof(process_error_mode
);
449 if (ProcessInformationLength
== len
)
450 memcpy(ProcessInformation
, &process_error_mode
, len
);
452 ret
= STATUS_INFO_LENGTH_MISMATCH
;
454 case ProcessDebugObjectHandle
:
455 /* "These are not the debuggers you are looking for." *
456 * set it to 0 aka "no debugger" to satisfy copy protections */
457 len
= sizeof(HANDLE
);
458 if (ProcessInformationLength
== len
)
460 if (!ProcessInformation
)
461 ret
= STATUS_ACCESS_VIOLATION
;
462 else if (!ProcessHandle
)
463 ret
= STATUS_INVALID_HANDLE
;
466 memset(ProcessInformation
, 0, ProcessInformationLength
);
467 ret
= STATUS_PORT_NOT_SET
;
471 ret
= STATUS_INFO_LENGTH_MISMATCH
;
473 case ProcessHandleCount
:
474 if (ProcessInformationLength
>= 4)
476 if (!ProcessInformation
)
477 ret
= STATUS_ACCESS_VIOLATION
;
478 else if (!ProcessHandle
)
479 ret
= STATUS_INVALID_HANDLE
;
482 memset(ProcessInformation
, 0, 4);
486 if (ProcessInformationLength
> 4)
487 ret
= STATUS_INFO_LENGTH_MISMATCH
;
492 ret
= STATUS_INFO_LENGTH_MISMATCH
;
496 case ProcessAffinityMask
:
497 len
= sizeof(ULONG_PTR
);
498 if (ProcessInformationLength
== len
)
500 const ULONG_PTR system_mask
= get_system_affinity_mask();
502 SERVER_START_REQ(get_process_info
)
504 req
->handle
= wine_server_obj_handle( ProcessHandle
);
505 if (!(ret
= wine_server_call( req
)))
506 *(ULONG_PTR
*)ProcessInformation
= reply
->affinity
& system_mask
;
510 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
513 case ProcessWow64Information
:
514 len
= sizeof(ULONG_PTR
);
515 if (ProcessInformationLength
!= len
) ret
= STATUS_INFO_LENGTH_MISMATCH
;
516 else if (!ProcessInformation
) ret
= STATUS_ACCESS_VIOLATION
;
517 else if(!ProcessHandle
) ret
= STATUS_INVALID_HANDLE
;
522 if (ProcessHandle
== GetCurrentProcess()) val
= is_wow64
;
523 else if (server_cpus
& ((1 << CPU_x86_64
) | (1 << CPU_ARM64
)))
525 SERVER_START_REQ( get_process_info
)
527 req
->handle
= wine_server_obj_handle( ProcessHandle
);
528 if (!(ret
= wine_server_call( req
)))
529 val
= (reply
->cpu
!= CPU_x86_64
&& reply
->cpu
!= CPU_ARM64
);
533 *(ULONG_PTR
*)ProcessInformation
= val
;
536 case ProcessImageFileName
:
537 /* FIXME: Should return a device path */
538 case ProcessImageFileNameWin32
:
539 SERVER_START_REQ(get_dll_info
)
541 UNICODE_STRING
*image_file_name_str
= ProcessInformation
;
543 req
->handle
= wine_server_obj_handle( ProcessHandle
);
544 req
->base_address
= 0; /* main module */
545 wine_server_set_reply( req
, image_file_name_str
? image_file_name_str
+ 1 : NULL
,
546 ProcessInformationLength
> sizeof(UNICODE_STRING
) ? ProcessInformationLength
- sizeof(UNICODE_STRING
) : 0 );
547 ret
= wine_server_call( req
);
548 if (ret
== STATUS_BUFFER_TOO_SMALL
) ret
= STATUS_INFO_LENGTH_MISMATCH
;
550 len
= sizeof(UNICODE_STRING
) + reply
->filename_len
;
551 if (ret
== STATUS_SUCCESS
)
553 image_file_name_str
->MaximumLength
= image_file_name_str
->Length
= reply
->filename_len
;
554 image_file_name_str
->Buffer
= (PWSTR
)(image_file_name_str
+ 1);
559 case ProcessExecuteFlags
:
561 if (ProcessInformationLength
== len
)
562 *(ULONG
*)ProcessInformation
= execute_flags
;
564 ret
= STATUS_INFO_LENGTH_MISMATCH
;
566 case ProcessPriorityClass
:
567 len
= sizeof(PROCESS_PRIORITY_CLASS
);
568 if (ProcessInformationLength
== len
)
570 if (!ProcessInformation
)
571 ret
= STATUS_ACCESS_VIOLATION
;
572 else if (!ProcessHandle
)
573 ret
= STATUS_INVALID_HANDLE
;
576 PROCESS_PRIORITY_CLASS
*priority
= ProcessInformation
;
578 SERVER_START_REQ(get_process_info
)
580 req
->handle
= wine_server_obj_handle( ProcessHandle
);
581 if ((ret
= wine_server_call( req
)) == STATUS_SUCCESS
)
583 priority
->PriorityClass
= reply
->priority
;
584 /* FIXME: Not yet supported by the wineserver */
585 priority
->Foreground
= FALSE
;
592 ret
= STATUS_INFO_LENGTH_MISMATCH
;
595 FIXME("ProcessCookie (%p,%p,0x%08x,%p) stub\n",
596 ProcessHandle
,ProcessInformation
,
597 ProcessInformationLength
,ReturnLength
);
599 if(ProcessHandle
== NtCurrentProcess())
602 if (ProcessInformationLength
== len
)
603 *(ULONG
*)ProcessInformation
= 0;
605 ret
= STATUS_INFO_LENGTH_MISMATCH
;
608 ret
= STATUS_INVALID_PARAMETER
;
611 FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n",
612 ProcessHandle
,ProcessInformationClass
,
613 ProcessInformation
,ProcessInformationLength
,
615 ret
= STATUS_INVALID_INFO_CLASS
;
619 if (ReturnLength
) *ReturnLength
= len
;
624 /******************************************************************************
625 * NtSetInformationProcess [NTDLL.@]
626 * ZwSetInformationProcess [NTDLL.@]
628 NTSTATUS WINAPI
NtSetInformationProcess(
629 IN HANDLE ProcessHandle
,
630 IN PROCESSINFOCLASS ProcessInformationClass
,
631 IN PVOID ProcessInformation
,
632 IN ULONG ProcessInformationLength
)
634 NTSTATUS ret
= STATUS_SUCCESS
;
636 switch (ProcessInformationClass
)
638 case ProcessDefaultHardErrorMode
:
639 if (ProcessInformationLength
!= sizeof(UINT
)) return STATUS_INVALID_PARAMETER
;
640 process_error_mode
= *(UINT
*)ProcessInformation
;
642 case ProcessAffinityMask
:
644 const ULONG_PTR system_mask
= get_system_affinity_mask();
646 if (ProcessInformationLength
!= sizeof(DWORD_PTR
)) return STATUS_INVALID_PARAMETER
;
647 if (*(PDWORD_PTR
)ProcessInformation
& ~system_mask
)
648 return STATUS_INVALID_PARAMETER
;
649 if (!*(PDWORD_PTR
)ProcessInformation
)
650 return STATUS_INVALID_PARAMETER
;
651 SERVER_START_REQ( set_process_info
)
653 req
->handle
= wine_server_obj_handle( ProcessHandle
);
654 req
->affinity
= *(PDWORD_PTR
)ProcessInformation
;
655 req
->mask
= SET_PROCESS_INFO_AFFINITY
;
656 ret
= wine_server_call( req
);
661 case ProcessPriorityClass
:
662 if (ProcessInformationLength
!= sizeof(PROCESS_PRIORITY_CLASS
))
663 return STATUS_INVALID_PARAMETER
;
666 PROCESS_PRIORITY_CLASS
* ppc
= ProcessInformation
;
668 SERVER_START_REQ( set_process_info
)
670 req
->handle
= wine_server_obj_handle( ProcessHandle
);
671 /* FIXME Foreground isn't used */
672 req
->priority
= ppc
->PriorityClass
;
673 req
->mask
= SET_PROCESS_INFO_PRIORITY
;
674 ret
= wine_server_call( req
);
680 case ProcessExecuteFlags
:
681 if (ProcessInformationLength
!= sizeof(ULONG
))
682 return STATUS_INVALID_PARAMETER
;
683 else if (execute_flags
& MEM_EXECUTE_OPTION_PERMANENT
)
684 return STATUS_ACCESS_DENIED
;
688 switch (*(ULONG
*)ProcessInformation
& (MEM_EXECUTE_OPTION_ENABLE
|MEM_EXECUTE_OPTION_DISABLE
))
690 case MEM_EXECUTE_OPTION_ENABLE
:
693 case MEM_EXECUTE_OPTION_DISABLE
:
697 return STATUS_INVALID_PARAMETER
;
699 execute_flags
= *(ULONG
*)ProcessInformation
;
700 VIRTUAL_SetForceExec( enable
);
705 FIXME("(%p,0x%08x,%p,0x%08x) stub\n",
706 ProcessHandle
,ProcessInformationClass
,ProcessInformation
,
707 ProcessInformationLength
);
708 ret
= STATUS_NOT_IMPLEMENTED
;
714 /******************************************************************************
715 * NtFlushInstructionCache [NTDLL.@]
716 * ZwFlushInstructionCache [NTDLL.@]
718 NTSTATUS WINAPI
NtFlushInstructionCache( HANDLE handle
, const void *addr
, SIZE_T size
)
720 #if defined(__x86_64__) || defined(__i386__)
722 #elif defined(HAVE___CLEAR_CACHE)
723 if (handle
== GetCurrentProcess())
725 __clear_cache( (char *)addr
, (char *)addr
+ size
);
730 if (!once
++) FIXME( "%p %p %ld other process not supported\n", handle
, addr
, size
);
734 if (!once
++) FIXME( "%p %p %ld\n", handle
, addr
, size
);
736 return STATUS_SUCCESS
;
739 /******************************************************************
740 * NtOpenProcess [NTDLL.@]
741 * ZwOpenProcess [NTDLL.@]
743 NTSTATUS WINAPI
NtOpenProcess(PHANDLE handle
, ACCESS_MASK access
,
744 const OBJECT_ATTRIBUTES
* attr
, const CLIENT_ID
* cid
)
748 SERVER_START_REQ( open_process
)
750 req
->pid
= HandleToULong(cid
->UniqueProcess
);
751 req
->access
= access
;
752 req
->attributes
= attr
? attr
->Attributes
: 0;
753 status
= wine_server_call( req
);
754 if (!status
) *handle
= wine_server_ptr_handle( reply
->handle
);
760 /******************************************************************************
764 NTSTATUS WINAPI
NtResumeProcess( HANDLE handle
)
766 FIXME("stub: %p\n", handle
);
767 return STATUS_NOT_IMPLEMENTED
;
770 /******************************************************************************
774 NTSTATUS WINAPI
NtSuspendProcess( HANDLE handle
)
776 FIXME("stub: %p\n", handle
);
777 return STATUS_NOT_IMPLEMENTED
;
781 /***********************************************************************
784 * Build an argv array from a command-line.
785 * 'reserved' is the number of args to reserve before the first one.
787 static char **build_argv( const UNICODE_STRING
*cmdlineW
, int reserved
)
791 char *arg
, *s
, *d
, *cmdline
;
792 int in_quotes
, bcount
, len
;
794 len
= ntdll_wcstoumbs( 0, cmdlineW
->Buffer
, cmdlineW
->Length
/ sizeof(WCHAR
), NULL
, 0, NULL
, NULL
);
795 if (!(cmdline
= RtlAllocateHeap( GetProcessHeap(), 0, len
+ 1 ))) return NULL
;
796 ntdll_wcstoumbs( 0, cmdlineW
->Buffer
, cmdlineW
->Length
/ sizeof(WCHAR
), cmdline
, len
, NULL
, NULL
);
805 if (*s
== '\0' || ((*s
== ' ' || *s
== '\t') && !in_quotes
))
809 /* skip the remaining spaces */
810 while (*s
== ' ' || *s
== '\t') s
++;
811 if (*s
== '\0') break;
815 else if (*s
== '\\') bcount
++; /* '\', count them */
816 else if ((*s
== '"') && ((bcount
& 1) == 0))
819 in_quotes
= !in_quotes
;
822 else bcount
= 0; /* a regular character */
825 if (!(argv
= RtlAllocateHeap( GetProcessHeap(), 0, argc
* sizeof(*argv
) + len
)))
827 RtlFreeHeap( GetProcessHeap(), 0, cmdline
);
831 arg
= d
= s
= (char *)(argv
+ argc
);
832 memcpy( d
, cmdline
, len
);
838 if ((*s
== ' ' || *s
== '\t') && !in_quotes
)
840 /* Close the argument and copy it */
843 /* skip the remaining spaces */
847 } while (*s
== ' ' || *s
== '\t');
849 /* Start with a new argument */
860 if ((bcount
& 1) == 0)
862 /* Preceded by an even number of '\', this is half that
863 * number of '\', plus a '"' which we discard.
867 in_quotes
= !in_quotes
;
871 /* Preceded by an odd number of '\', this is half that
872 * number of '\' followed by a '"'
874 d
= d
- bcount
/ 2 - 1;
882 /* a regular character */
894 RtlFreeHeap( GetProcessHeap(), 0, cmdline
);
899 static inline const WCHAR
*get_params_string( const RTL_USER_PROCESS_PARAMETERS
*params
,
900 const UNICODE_STRING
*str
)
902 if (params
->Flags
& PROCESS_PARAMS_FLAG_NORMALIZED
) return str
->Buffer
;
903 return (const WCHAR
*)((const char *)params
+ (UINT_PTR
)str
->Buffer
);
906 static inline DWORD
append_string( void **ptr
, const RTL_USER_PROCESS_PARAMETERS
*params
,
907 const UNICODE_STRING
*str
)
909 const WCHAR
*buffer
= get_params_string( params
, str
);
910 memcpy( *ptr
, buffer
, str
->Length
);
911 *ptr
= (WCHAR
*)*ptr
+ str
->Length
/ sizeof(WCHAR
);
915 /***********************************************************************
916 * create_startup_info
918 static startup_info_t
*create_startup_info( const RTL_USER_PROCESS_PARAMETERS
*params
, DWORD
*info_size
)
920 startup_info_t
*info
;
924 size
= sizeof(*info
);
925 size
+= params
->CurrentDirectory
.DosPath
.Length
;
926 size
+= params
->DllPath
.Length
;
927 size
+= params
->ImagePathName
.Length
;
928 size
+= params
->CommandLine
.Length
;
929 size
+= params
->WindowTitle
.Length
;
930 size
+= params
->Desktop
.Length
;
931 size
+= params
->ShellInfo
.Length
;
932 size
+= params
->RuntimeInfo
.Length
;
933 size
= (size
+ 1) & ~1;
936 if (!(info
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
))) return NULL
;
938 info
->console_flags
= params
->ConsoleFlags
;
939 info
->console
= wine_server_obj_handle( params
->ConsoleHandle
);
940 info
->hstdin
= wine_server_obj_handle( params
->hStdInput
);
941 info
->hstdout
= wine_server_obj_handle( params
->hStdOutput
);
942 info
->hstderr
= wine_server_obj_handle( params
->hStdError
);
943 info
->x
= params
->dwX
;
944 info
->y
= params
->dwY
;
945 info
->xsize
= params
->dwXSize
;
946 info
->ysize
= params
->dwYSize
;
947 info
->xchars
= params
->dwXCountChars
;
948 info
->ychars
= params
->dwYCountChars
;
949 info
->attribute
= params
->dwFillAttribute
;
950 info
->flags
= params
->dwFlags
;
951 info
->show
= params
->wShowWindow
;
954 info
->curdir_len
= append_string( &ptr
, params
, ¶ms
->CurrentDirectory
.DosPath
);
955 info
->dllpath_len
= append_string( &ptr
, params
, ¶ms
->DllPath
);
956 info
->imagepath_len
= append_string( &ptr
, params
, ¶ms
->ImagePathName
);
957 info
->cmdline_len
= append_string( &ptr
, params
, ¶ms
->CommandLine
);
958 info
->title_len
= append_string( &ptr
, params
, ¶ms
->WindowTitle
);
959 info
->desktop_len
= append_string( &ptr
, params
, ¶ms
->Desktop
);
960 info
->shellinfo_len
= append_string( &ptr
, params
, ¶ms
->ShellInfo
);
961 info
->runtime_len
= append_string( &ptr
, params
, ¶ms
->RuntimeInfo
);
966 /***********************************************************************
967 * get_alternate_loader
969 * Get the name of the alternate (32 or 64 bit) Wine loader.
971 static const char *get_alternate_loader( char **ret_env
)
974 const char *loader
= NULL
;
975 const char *loader_env
= getenv( "WINELOADER" );
979 if (wine_get_build_dir()) loader
= is_win64
? "loader/wine" : "server/../loader/wine64";
983 int len
= strlen( loader_env
);
986 if (!(env
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof("WINELOADER=") + len
+ 2 ))) return NULL
;
987 strcpy( env
, "WINELOADER=" );
988 strcat( env
, loader_env
);
993 if (!(env
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof("WINELOADER=") + len
))) return NULL
;
994 strcpy( env
, "WINELOADER=" );
995 strcat( env
, loader_env
);
996 len
+= sizeof("WINELOADER=") - 1;
997 if (!strcmp( env
+ len
- 2, "64" )) env
[len
- 2] = 0;
1001 if ((loader
= strrchr( env
, '/' ))) loader
++;
1006 if (!loader
) loader
= is_win64
? "wine" : "wine64";
1011 /***********************************************************************
1014 static NTSTATUS
spawn_loader( const RTL_USER_PROCESS_PARAMETERS
*params
, int socketfd
,
1015 const char *unixdir
, char *winedebug
, const pe_image_info_t
*pe_info
)
1018 int stdin_fd
= -1, stdout_fd
= -1;
1019 char *wineloader
= NULL
;
1020 const char *loader
= NULL
;
1022 NTSTATUS status
= STATUS_SUCCESS
;
1024 argv
= build_argv( ¶ms
->CommandLine
, 1 );
1026 if (!is_win64
^ !is_64bit_arch( pe_info
->cpu
))
1027 loader
= get_alternate_loader( &wineloader
);
1029 wine_server_handle_to_fd( params
->hStdInput
, FILE_READ_DATA
, &stdin_fd
, NULL
);
1030 wine_server_handle_to_fd( params
->hStdOutput
, FILE_WRITE_DATA
, &stdout_fd
, NULL
);
1032 if (!(pid
= fork())) /* child */
1034 if (!(pid
= fork())) /* grandchild */
1036 char preloader_reserve
[64], socket_env
[64];
1037 ULONGLONG res_start
= pe_info
->base
;
1038 ULONGLONG res_end
= pe_info
->base
+ pe_info
->map_size
;
1040 if (params
->ConsoleFlags
||
1041 params
->ConsoleHandle
== (HANDLE
)1 /* KERNEL32_CONSOLE_ALLOC */ ||
1042 (params
->hStdInput
== INVALID_HANDLE_VALUE
&& params
->hStdOutput
== INVALID_HANDLE_VALUE
))
1044 int fd
= open( "/dev/null", O_RDWR
);
1046 /* close stdin and stdout */
1056 if (stdin_fd
!= -1) dup2( stdin_fd
, 0 );
1057 if (stdout_fd
!= -1) dup2( stdout_fd
, 1 );
1060 if (stdin_fd
!= -1) close( stdin_fd
);
1061 if (stdout_fd
!= -1) close( stdout_fd
);
1063 /* Reset signals that we previously set to SIG_IGN */
1064 signal( SIGPIPE
, SIG_DFL
);
1066 sprintf( socket_env
, "WINESERVERSOCKET=%u", socketfd
);
1067 sprintf( preloader_reserve
, "WINEPRELOADRESERVE=%x%08x-%x%08x",
1068 (ULONG
)(res_start
>> 32), (ULONG
)res_start
, (ULONG
)(res_end
>> 32), (ULONG
)res_end
);
1070 putenv( preloader_reserve
);
1071 putenv( socket_env
);
1072 if (winedebug
) putenv( winedebug
);
1073 if (wineloader
) putenv( wineloader
);
1074 if (unixdir
) chdir( unixdir
);
1076 if (argv
) wine_exec_wine_binary( loader
, argv
, getenv("WINELOADER") );
1088 wret
= waitpid(pid
, NULL
, 0);
1089 } while (wret
< 0 && errno
== EINTR
);
1091 else status
= FILE_GetNtStatus();
1093 if (stdin_fd
!= -1) close( stdin_fd
);
1094 if (stdout_fd
!= -1) close( stdout_fd
);
1095 RtlFreeHeap( GetProcessHeap(), 0, wineloader
);
1096 RtlFreeHeap( GetProcessHeap(), 0, argv
);
1101 /***********************************************************************
1104 static NTSTATUS
get_pe_file_info( UNICODE_STRING
*path
, ULONG attributes
,
1105 HANDLE
*handle
, pe_image_info_t
*info
)
1109 OBJECT_ATTRIBUTES attr
;
1112 InitializeObjectAttributes( &attr
, path
, attributes
, 0, 0 );
1113 if ((status
= NtOpenFile( handle
, GENERIC_READ
, &attr
, &io
,
1114 FILE_SHARE_READ
| FILE_SHARE_DELETE
, 0 ))) return status
;
1116 if (!(status
= NtCreateSection( &mapping
, STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
|
1117 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
,
1118 NULL
, NULL
, PAGE_EXECUTE_READ
, SEC_IMAGE
, *handle
)))
1120 SERVER_START_REQ( get_mapping_info
)
1122 req
->handle
= wine_server_obj_handle( mapping
);
1123 req
->access
= SECTION_QUERY
;
1124 wine_server_set_reply( req
, info
, sizeof(*info
) );
1125 status
= wine_server_call( req
);
1134 /***********************************************************************
1137 static ULONG
get_env_size( const RTL_USER_PROCESS_PARAMETERS
*params
, char **winedebug
)
1139 WCHAR
*ptr
= params
->Environment
;
1143 static const WCHAR WINEDEBUG
[] = {'W','I','N','E','D','E','B','U','G','=',0};
1144 if (!*winedebug
&& !strncmpW( ptr
, WINEDEBUG
, ARRAY_SIZE( WINEDEBUG
) - 1 ))
1146 DWORD len
= ntdll_wcstoumbs( 0, ptr
, strlenW(ptr
) + 1, NULL
, 0, NULL
, NULL
);
1147 if ((*winedebug
= RtlAllocateHeap( GetProcessHeap(), 0, len
)))
1148 ntdll_wcstoumbs( 0, ptr
, strlenW(ptr
) + 1, *winedebug
, len
, NULL
, NULL
);
1150 ptr
+= strlenW(ptr
) + 1;
1153 return (ptr
- params
->Environment
) * sizeof(WCHAR
);
1157 /***********************************************************************
1160 static char *get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS
*params
)
1162 UNICODE_STRING nt_name
;
1163 ANSI_STRING unix_name
;
1166 if (!RtlDosPathNameToNtPathName_U( params
->CurrentDirectory
.DosPath
.Buffer
, &nt_name
, NULL
, NULL
))
1168 status
= wine_nt_to_unix_file_name( &nt_name
, &unix_name
, FILE_OPEN_IF
, FALSE
);
1169 RtlFreeUnicodeString( &nt_name
);
1170 if (status
&& status
!= STATUS_NO_SUCH_FILE
) return NULL
;
1171 return unix_name
.Buffer
;
1175 /**********************************************************************
1176 * RtlCreateUserProcess (NTDLL.@)
1178 NTSTATUS WINAPI
RtlCreateUserProcess( UNICODE_STRING
*path
, ULONG attributes
,
1179 RTL_USER_PROCESS_PARAMETERS
*params
,
1180 SECURITY_DESCRIPTOR
*process_descr
,
1181 SECURITY_DESCRIPTOR
*thread_descr
,
1182 HANDLE parent
, BOOLEAN inherit
, HANDLE debug
, HANDLE exception
,
1183 RTL_USER_PROCESS_INFORMATION
*info
)
1186 BOOL success
= FALSE
;
1187 HANDLE file_handle
, process_info
= 0, process_handle
= 0, thread_handle
= 0;
1188 ULONG process_id
, thread_id
;
1189 struct object_attributes
*objattr
;
1190 data_size_t attr_len
;
1191 char *unixdir
= NULL
, *winedebug
= NULL
;
1192 startup_info_t
*startup_info
= NULL
;
1193 ULONG startup_info_size
, env_size
;
1194 int err
, socketfd
[2] = { -1, -1 };
1195 OBJECT_ATTRIBUTES attr
;
1196 pe_image_info_t pe_info
;
1198 RtlNormalizeProcessParams( params
);
1200 TRACE( "%s image %s cmdline %s\n", debugstr_us( path
),
1201 debugstr_us( ¶ms
->ImagePathName
), debugstr_us( ¶ms
->CommandLine
));
1203 if ((status
= get_pe_file_info( path
, attributes
, &file_handle
, &pe_info
))) goto done
;
1204 if (!(startup_info
= create_startup_info( params
, &startup_info_size
))) goto done
;
1205 env_size
= get_env_size( params
, &winedebug
);
1206 unixdir
= get_unix_curdir( params
);
1208 InitializeObjectAttributes( &attr
, NULL
, 0, NULL
, process_descr
);
1209 if ((status
= alloc_object_attributes( &attr
, &objattr
, &attr_len
))) goto done
;
1211 /* create the socket for the new process */
1213 if (socketpair( PF_UNIX
, SOCK_STREAM
, 0, socketfd
) == -1)
1215 status
= STATUS_TOO_MANY_OPENED_FILES
;
1216 RtlFreeHeap( GetProcessHeap(), 0, objattr
);
1223 setsockopt( socketfd
[0], SOL_SOCKET
, SO_PASSCRED
, &enable
, sizeof(enable
) );
1227 wine_server_send_fd( socketfd
[1] );
1228 close( socketfd
[1] );
1230 /* create the process on the server side */
1232 SERVER_START_REQ( new_process
)
1234 req
->inherit_all
= inherit
;
1235 req
->create_flags
= 0;
1236 req
->socket_fd
= socketfd
[1];
1237 req
->exe_file
= wine_server_obj_handle( file_handle
);
1238 req
->access
= PROCESS_ALL_ACCESS
;
1239 req
->cpu
= pe_info
.cpu
;
1240 req
->info_size
= startup_info_size
;
1241 wine_server_add_data( req
, objattr
, attr_len
);
1242 wine_server_add_data( req
, startup_info
, startup_info_size
);
1243 wine_server_add_data( req
, params
->Environment
, env_size
);
1244 if (!(status
= wine_server_call( req
)))
1246 process_id
= reply
->pid
;
1247 process_handle
= wine_server_ptr_handle( reply
->handle
);
1249 process_info
= wine_server_ptr_handle( reply
->info
);
1252 RtlFreeHeap( GetProcessHeap(), 0, objattr
);
1258 case STATUS_INVALID_IMAGE_WIN_64
:
1259 ERR( "64-bit application %s not supported in 32-bit prefix\n",
1260 debugstr_us( ¶ms
->ImagePathName
));
1262 case STATUS_INVALID_IMAGE_FORMAT
:
1263 ERR( "%s not supported on this installation (%s binary)\n",
1264 debugstr_us( ¶ms
->ImagePathName
), cpu_names
[pe_info
.cpu
] );
1270 InitializeObjectAttributes( &attr
, NULL
, 0, NULL
, thread_descr
);
1271 if ((status
= alloc_object_attributes( &attr
, &objattr
, &attr_len
))) goto done
;
1273 SERVER_START_REQ( new_thread
)
1275 req
->process
= wine_server_obj_handle( process_handle
);
1276 req
->access
= THREAD_ALL_ACCESS
;
1278 req
->request_fd
= -1;
1279 wine_server_add_data( req
, objattr
, attr_len
);
1280 if (!(status
= wine_server_call( req
)))
1282 thread_handle
= wine_server_ptr_handle( reply
->handle
);
1283 thread_id
= reply
->tid
;
1287 RtlFreeHeap( GetProcessHeap(), 0, objattr
);
1288 if (status
) goto done
;
1290 /* create the child process */
1292 if ((status
= spawn_loader( params
, socketfd
[0], unixdir
, winedebug
, &pe_info
))) goto done
;
1294 close( socketfd
[0] );
1297 /* wait for the new process info to be ready */
1299 NtWaitForSingleObject( process_info
, FALSE
, NULL
);
1300 SERVER_START_REQ( get_new_process_info
)
1302 req
->info
= wine_server_obj_handle( process_info
);
1303 wine_server_call( req
);
1304 success
= reply
->success
;
1305 err
= reply
->exit_code
;
1311 TRACE( "%s pid %04x tid %04x handles %p/%p\n", debugstr_us( path
),
1312 process_id
, thread_id
, process_handle
, thread_handle
);
1313 info
->Process
= process_handle
;
1314 info
->Thread
= thread_handle
;
1315 info
->ClientId
.UniqueProcess
= ULongToHandle( process_id
);
1316 info
->ClientId
.UniqueThread
= ULongToHandle( thread_id
);
1317 process_handle
= thread_handle
= 0;
1318 status
= STATUS_SUCCESS
;
1320 else status
= err
? err
: ERROR_INTERNAL_ERROR
;
1323 NtClose( file_handle
);
1324 if (process_info
) NtClose( process_info
);
1325 if (process_handle
) NtClose( process_handle
);
1326 if (thread_handle
) NtClose( thread_handle
);
1327 if (socketfd
[0] != -1) close( socketfd
[0] );
1328 RtlFreeHeap( GetProcessHeap(), 0, startup_info
);
1329 RtlFreeHeap( GetProcessHeap(), 0, winedebug
);
1330 RtlFreeHeap( GetProcessHeap(), 0, unixdir
);