ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

proc.c
Go to the documentation of this file.
00001 /* $Id: proc.c 56643 2012-05-20 14:06:09Z tfaber $
00002  *
00003  * COPYRIGHT:       See COPYING in the top level directory
00004  * PROJECT:         ReactOS system libraries
00005  * FILE:            lib/kernel32/proc/proc.c
00006  * PURPOSE:         Process functions
00007  * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
00008  * UPDATE HISTORY:
00009  *                  Created 01/11/98
00010  */
00011 
00012 /* INCLUDES ****************************************************************/
00013 
00014 #include <k32.h>
00015 
00016 #define NDEBUG
00017 #include <debug.h>
00018 
00019 /* GLOBALS *******************************************************************/
00020 
00021 WaitForInputIdleType UserWaitForInputIdleRoutine;
00022 UNICODE_STRING BaseUnicodeCommandLine;
00023 ANSI_STRING BaseAnsiCommandLine;
00024 UNICODE_STRING BasePathVariableName = RTL_CONSTANT_STRING(L"PATH");
00025 LPSTARTUPINFOA BaseAnsiStartupInfo = NULL;
00026 PLDR_DATA_TABLE_ENTRY BasepExeLdrEntry;
00027 BOOLEAN g_AppCertInitialized;
00028 BOOLEAN g_HaveAppCerts;
00029 LIST_ENTRY BasepAppCertDllsList;
00030 RTL_CRITICAL_SECTION gcsAppCert;
00031 PBASEP_APPCERT_EMBEDDED_FUNC fEmbeddedCertFunc;
00032 NTSTATUS g_AppCertStatus;
00033 RTL_QUERY_REGISTRY_TABLE BasepAppCertTable[2] =
00034 {
00035     {
00036         BasepConfigureAppCertDlls,
00037         1,
00038         L"AppCertDlls",
00039         &BasepAppCertDllsList,
00040         0,
00041         NULL,
00042         0
00043     }
00044 };
00045 
00046 PSAFER_REPLACE_PROCESS_THREAD_TOKENS g_SaferReplaceProcessThreadTokens;
00047 HMODULE gSaferHandle = (HMODULE)-1;
00048 
00049 VOID WINAPI
00050 RegisterWaitForInputIdle(WaitForInputIdleType lpfnRegisterWaitForInputIdle);
00051 
00052 #define CMD_STRING L"cmd /c "
00053 
00054 /* FUNCTIONS ****************************************************************/
00055 
00056 VOID
00057 WINAPI
00058 StuffStdHandle(IN HANDLE ProcessHandle,
00059                IN HANDLE StandardHandle,
00060                IN PHANDLE Address)
00061 {
00062     NTSTATUS Status;
00063     HANDLE DuplicatedHandle;
00064     SIZE_T Dummy;
00065 
00066     /* Duplicate the handle */
00067     Status = NtDuplicateObject(NtCurrentProcess(),
00068                                StandardHandle,
00069                                ProcessHandle,
00070                                &DuplicatedHandle,
00071                                DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES,
00072                                0,
00073                                0);
00074     if (NT_SUCCESS(Status))
00075     {
00076         /* Write it */
00077         NtWriteVirtualMemory(ProcessHandle,
00078                              Address,
00079                              &DuplicatedHandle,
00080                              sizeof(HANDLE),
00081                              &Dummy);
00082     }
00083 }
00084 
00085 BOOLEAN
00086 WINAPI
00087 BuildSubSysCommandLine(IN LPWSTR SubsystemName,
00088                        IN LPWSTR ApplicationName,
00089                        IN LPWSTR CommandLine,
00090                        OUT PUNICODE_STRING SubsysCommandLine)
00091 {
00092     UNICODE_STRING CommandLineString, ApplicationNameString;
00093     PWCHAR Buffer;
00094     ULONG Length;
00095 
00096     /* Convert to unicode strings */
00097     RtlInitUnicodeString(&CommandLineString, ApplicationName);
00098     RtlInitUnicodeString(&ApplicationNameString, CommandLine);
00099 
00100     /* Allocate buffer for the output string */
00101     Length = CommandLineString.MaximumLength + ApplicationNameString.MaximumLength + 32;
00102     Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
00103     RtlInitEmptyUnicodeString(SubsysCommandLine, Buffer, Length);
00104     if (!Buffer)
00105     {
00106         /* Fail, no memory */
00107         BaseSetLastNTError(STATUS_NO_MEMORY);
00108         return FALSE;
00109     }
00110 
00111     /* Build the final subsystem command line */
00112     RtlAppendUnicodeToString(SubsysCommandLine, SubsystemName);
00113     RtlAppendUnicodeStringToString(SubsysCommandLine, &CommandLineString);
00114     RtlAppendUnicodeToString(SubsysCommandLine, L" /C ");
00115     RtlAppendUnicodeStringToString(SubsysCommandLine, &ApplicationNameString);
00116     return TRUE;
00117 }
00118 
00119 BOOLEAN
00120 WINAPI
00121 BasepIsImageVersionOk(IN ULONG ImageMajorVersion,
00122                       IN ULONG ImageMinorVersion)
00123 {
00124     /* Accept images for NT 3.1 or higher, as long as they're not newer than us */
00125     return ((ImageMajorVersion >= 3) &&
00126             ((ImageMajorVersion != 3) ||
00127              (ImageMinorVersion >= 10)) &&
00128             (ImageMajorVersion <= SharedUserData->NtMajorVersion) &&
00129             ((ImageMajorVersion != SharedUserData->NtMajorVersion) ||
00130              (ImageMinorVersion <= SharedUserData->NtMinorVersion)));
00131 }
00132 
00133 NTSTATUS
00134 WINAPI
00135 BasepCheckWebBladeHashes(IN HANDLE FileHandle)
00136 {
00137     NTSTATUS Status;
00138     CHAR Hash[16];
00139 
00140     /* Get all the MD5 hashes */
00141     Status = RtlComputeImportTableHash(FileHandle, Hash, 1);
00142     if (!NT_SUCCESS(Status)) return Status;
00143 
00144     /* Depending on which suite this is, run a bsearch and block the appropriate ones */
00145     if (SharedUserData->SuiteMask & VER_SUITE_COMPUTE_SERVER)
00146     {
00147         DPRINT1("Egad! This is a ReactOS Compute Server and we should prevent you from using certain APIs...but we won't.");
00148     }
00149     else if (SharedUserData->SuiteMask & VER_SUITE_STORAGE_SERVER)
00150     {
00151         DPRINT1("Gasp! This is a ReactOS Storage Server and we should prevent you from using certain APIs...but we won't.");
00152     }
00153     else if (SharedUserData->SuiteMask & VER_SUITE_BLADE)
00154     {
00155         DPRINT1("Golly! This is a ReactOS Web Blade Server and we should prevent you from using certain APIs...but we won't.");
00156     }
00157 
00158     /* Actually, fuck it, don't block anything, we're open source */
00159     return STATUS_SUCCESS;
00160 }
00161 
00162 NTSTATUS
00163 NTAPI
00164 BasepSaveAppCertRegistryValue(IN PLIST_ENTRY List,
00165                               IN PWCHAR ComponentName,
00166                               IN PWCHAR DllName)
00167 {
00168     /* Pretty much the only thing this key is used for, is malware */
00169     UNIMPLEMENTED;
00170     return STATUS_NOT_IMPLEMENTED;
00171 }
00172 
00173 NTSTATUS
00174 NTAPI
00175 BasepConfigureAppCertDlls(IN PWSTR ValueName,
00176                           IN ULONG ValueType,
00177                           IN PVOID ValueData,
00178                           IN ULONG ValueLength,
00179                           IN PVOID Context,
00180                           IN PVOID EntryContext)
00181 {
00182     /* Add this to the certification list */
00183     return BasepSaveAppCertRegistryValue(Context, ValueName, ValueData);
00184 }
00185 
00186 NTSTATUS
00187 WINAPI
00188 BasepIsProcessAllowed(IN PCHAR ApplicationName)
00189 {
00190     NTSTATUS Status;
00191     PWCHAR Buffer;
00192     UINT Length;
00193     HMODULE TrustLibrary;
00194     PBASEP_APPCERT_ENTRY Entry;
00195     ULONG CertFlag;
00196     PLIST_ENTRY NextEntry;
00197     HANDLE KeyHandle;
00198     UNICODE_STRING CertKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls");
00199     OBJECT_ATTRIBUTES KeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&CertKey, OBJ_CASE_INSENSITIVE);
00200 
00201     /* Try to initialize the certification subsystem */
00202     while (!g_AppCertInitialized)
00203     {
00204         /* Defaults */
00205         Status = STATUS_SUCCESS;
00206         Buffer = NULL;
00207 
00208         /* Acquire the lock while initializing and see if we lost a race */
00209         RtlEnterCriticalSection(&gcsAppCert);
00210         if (g_AppCertInitialized) break;
00211 
00212         /* On embedded, there is a special DLL */
00213         if (SharedUserData->SuiteMask & VER_SUITE_EMBEDDEDNT)
00214         {
00215             /* Allocate a buffer for the name */
00216             Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
00217                                      0,
00218                                      MAX_PATH * sizeof(WCHAR) +
00219                                      sizeof(UNICODE_NULL));
00220             if (!Buffer)
00221             {
00222                 /* Fail if no memory */
00223                 Status = STATUS_NO_MEMORY;
00224             }
00225             else
00226             {
00227                 /* Now get the system32 directory in our buffer, make sure it fits */
00228                 Length = GetSystemDirectoryW(Buffer, MAX_PATH - sizeof("EmbdTrst.DLL"));
00229                 if ((Length) && (Length <= MAX_PATH - sizeof("EmbdTrst.DLL")))
00230                 {
00231                     /* Add a slash if needed, and add the embedded cert DLL name */
00232                     if (Buffer[Length - 1] != '\\') Buffer[Length++] = '\\';
00233                     RtlCopyMemory(&Buffer[Length],
00234                                   L"EmbdTrst.DLL",
00235                                   sizeof(L"EmbdTrst.DLL"));
00236 
00237                     /* Try to load it */
00238                     TrustLibrary = LoadLibraryW(Buffer);
00239                     if (TrustLibrary)
00240                     {
00241                         /* And extract the special function out of it */
00242                         fEmbeddedCertFunc = (PVOID)GetProcAddress(TrustLibrary,
00243                                                                   "ImageOkToRunOnEmbeddedNT");
00244                     }
00245                 }
00246 
00247                 /* If we didn't get this far, set a failure code */
00248                 if (!fEmbeddedCertFunc) Status = STATUS_UNSUCCESSFUL;
00249             }
00250         }
00251         else
00252         {
00253             /* Other systems have a registry entry for this */
00254             Status = NtOpenKey(&KeyHandle, KEY_READ, &KeyAttributes);
00255             if (NT_SUCCESS(Status))
00256             {
00257                 /* Close it, we'll query it through Rtl */
00258                 NtClose(KeyHandle);
00259 
00260                 /* Do the query, which will call a special callback */
00261                 Status = RtlQueryRegistryValues(2,
00262                                                 L"Session Manager",
00263                                                 BasepAppCertTable,
00264                                                 0,
00265                                                 0);
00266                 if (Status == 0xC0000034) Status = STATUS_SUCCESS;
00267             }
00268         }
00269 
00270         /* Free any buffer if we had one */
00271         if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
00272 
00273         /* Check for errors, or a missing embedded/custom certification DLL */
00274         if (!NT_SUCCESS(Status) ||
00275             (!(fEmbeddedCertFunc) && (IsListEmpty(&BasepAppCertDllsList))))
00276         {
00277             /* The subsystem is not active on this machine, so give up */
00278             g_HaveAppCerts = FALSE;
00279             g_AppCertStatus = Status;
00280         }
00281         else
00282         {
00283             /* We have certification DLLs active, remember this */
00284             g_HaveAppCerts = TRUE;
00285         }
00286 
00287         /* We are done the initialization phase, release the lock */
00288         g_AppCertInitialized = TRUE;
00289         RtlLeaveCriticalSection(&gcsAppCert);
00290     }
00291 
00292     /* If there's no certification DLLs present, return the failure code */
00293     if (!g_HaveAppCerts) return g_AppCertStatus;
00294 
00295     /* Otherwise, assume success and make sure we have *something* */
00296     ASSERT(fEmbeddedCertFunc || !IsListEmpty(&BasepAppCertDllsList));
00297     Status = STATUS_SUCCESS;
00298 
00299     /* If the something is an embedded certification DLL, call it and return */
00300     if (fEmbeddedCertFunc) return fEmbeddedCertFunc(ApplicationName);
00301 
00302     /* Otherwise we have custom certification DLLs, parse them */
00303     NextEntry = BasepAppCertDllsList.Flink;
00304     CertFlag = 2;
00305     while (NextEntry != &BasepAppCertDllsList)
00306     {
00307         /* Make sure the entry has a callback */
00308         Entry = CONTAINING_RECORD(NextEntry, BASEP_APPCERT_ENTRY, Entry);
00309         ASSERT(Entry->fPluginCertFunc != NULL);
00310 
00311         /* Call it and check if it failed */
00312         Status = Entry->fPluginCertFunc(ApplicationName, 1);
00313         if (!NT_SUCCESS(Status)) CertFlag = 3;
00314 
00315         /* Move on */
00316         NextEntry = NextEntry->Flink;
00317     }
00318 
00319     /* Now loop them again */
00320     NextEntry = BasepAppCertDllsList.Flink;
00321     while (NextEntry != &BasepAppCertDllsList)
00322     {
00323         /* Make sure the entry has a callback */
00324         Entry = CONTAINING_RECORD(NextEntry, BASEP_APPCERT_ENTRY, Entry);
00325         ASSERT(Entry->fPluginCertFunc != NULL);
00326 
00327         /* Call it, this time with the flag from the loop above */
00328         Status = Entry->fPluginCertFunc(ApplicationName, CertFlag);
00329     }
00330 
00331     /* All done, return the status */
00332     return Status;
00333 }
00334 
00335 NTSTATUS
00336 WINAPI
00337 BasepReplaceProcessThreadTokens(IN HANDLE TokenHandle,
00338                                 IN HANDLE ProcessHandle,
00339                                 IN HANDLE ThreadHandle)
00340 {
00341     NTSTATUS Status;
00342     ANSI_STRING SaferiReplaceProcessThreadTokens = RTL_CONSTANT_STRING("SaferiReplaceProcessThreadTokens");
00343 
00344     /* Enter the application certification lock */
00345     RtlEnterCriticalSection(&gcsAppCert);
00346 
00347     /* Check if we already know the function */
00348     if (g_SaferReplaceProcessThreadTokens)
00349     {
00350         /* Call it */
00351         Status = g_SaferReplaceProcessThreadTokens(TokenHandle,
00352                                                    ProcessHandle,
00353                                                    ThreadHandle) ?
00354                                                    STATUS_SUCCESS :
00355                                                    STATUS_UNSUCCESSFUL;
00356     }
00357     else
00358     {
00359         /* Check if the app certification DLL isn't loaded */
00360         if (!(gSaferHandle) ||
00361             (gSaferHandle == (HMODULE)-1) ||
00362             (gSaferHandle == (HMODULE)-2))
00363         {
00364             /* Then we can't call the function */
00365             Status = STATUS_ENTRYPOINT_NOT_FOUND;
00366         }
00367         else
00368         {
00369             /* We have the DLL, find the address of the Safer function */
00370             Status = LdrGetProcedureAddress(gSaferHandle,
00371                                             &SaferiReplaceProcessThreadTokens,
00372                                             0,
00373                                             (PVOID*)&g_SaferReplaceProcessThreadTokens);
00374             if (NT_SUCCESS(Status))
00375             {
00376                 /* Found it, now call it */
00377                 Status = g_SaferReplaceProcessThreadTokens(TokenHandle,
00378                                                            ProcessHandle,
00379                                                            ThreadHandle) ?
00380                                                            STATUS_SUCCESS :
00381                                                            STATUS_UNSUCCESSFUL;
00382             }
00383             else
00384             {
00385                 /* We couldn't find it, so this must be an unsupported DLL */
00386                 LdrUnloadDll(gSaferHandle);
00387                 gSaferHandle = NULL;
00388                 Status = STATUS_ENTRYPOINT_NOT_FOUND;
00389             }
00390         }
00391     }
00392 
00393     /* Release the lock and return the result */
00394     RtlLeaveCriticalSection(&gcsAppCert);
00395     return Status;
00396 }
00397 
00398 VOID
00399 WINAPI
00400 BasepSxsCloseHandles(IN PBASE_MSG_SXS_HANDLES Handles)
00401 {
00402     NTSTATUS Status;
00403 
00404     /* Sanity checks */
00405     ASSERT(Handles != NULL);
00406     ASSERT(Handles->Process == NULL || Handles->Process == NtCurrentProcess());
00407 
00408     /* Close the file handle */
00409     if (Handles->File)
00410     {
00411         Status = NtClose(Handles->File);
00412         ASSERT(NT_SUCCESS(Status));
00413     }
00414 
00415     /* Close the section handle */
00416     if (Handles->Section)
00417     {
00418         Status = NtClose(Handles->Section);
00419         ASSERT(NT_SUCCESS(Status));
00420     }
00421 
00422     /* Unmap the section view */
00423     if (Handles->ViewBase.QuadPart)
00424     {
00425         Status = NtUnmapViewOfSection(NtCurrentProcess(),
00426                                       (PVOID)Handles->ViewBase.LowPart);
00427         ASSERT(NT_SUCCESS(Status));
00428     }
00429 }
00430 
00431 static
00432 LONG BaseExceptionFilter(EXCEPTION_POINTERS *ExceptionInfo)
00433 {
00434     LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER;
00435     LPTOP_LEVEL_EXCEPTION_FILTER RealFilter;
00436     RealFilter = RtlDecodePointer(GlobalTopLevelExceptionFilter);
00437 
00438     if (RealFilter != NULL)
00439     {
00440         _SEH2_TRY
00441         {
00442             ExceptionDisposition = RealFilter(ExceptionInfo);
00443         }
00444         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00445         {
00446         }
00447         _SEH2_END;
00448     }
00449     if ((ExceptionDisposition == EXCEPTION_CONTINUE_SEARCH || ExceptionDisposition == EXCEPTION_EXECUTE_HANDLER) &&
00450         RealFilter != UnhandledExceptionFilter)
00451     {
00452        ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo);
00453     }
00454 
00455     return ExceptionDisposition;
00456 }
00457 
00458 VOID
00459 WINAPI
00460 BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress)
00461 {
00462     DPRINT("BaseProcessStartup(..) - setting up exception frame.\n");
00463 
00464     _SEH2_TRY
00465     {
00466         /* Set our Start Address */
00467         NtSetInformationThread(NtCurrentThread(),
00468                                ThreadQuerySetWin32StartAddress,
00469                                &lpStartAddress,
00470                                sizeof(PPROCESS_START_ROUTINE));
00471 
00472         /* Call the Start Routine */
00473         ExitThread(lpStartAddress());
00474     }
00475     _SEH2_EXCEPT(BaseExceptionFilter(_SEH2_GetExceptionInformation()))
00476     {
00477         /* Get the Exit code from the SEH Handler */
00478         if (!BaseRunningInServerProcess)
00479         {
00480             /* Kill the whole process, usually */
00481             ExitProcess(_SEH2_GetExceptionCode());
00482         }
00483         else
00484         {
00485             /* If running inside CSRSS, kill just this thread */
00486             ExitThread(_SEH2_GetExceptionCode());
00487         }
00488     }
00489     _SEH2_END;
00490 }
00491 
00492 NTSTATUS
00493 WINAPI
00494 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle,
00495                        IN PCLIENT_ID ClientId)
00496 {
00497     ULONG Request = CREATE_THREAD;
00498     CSR_API_MESSAGE CsrRequest;
00499     NTSTATUS Status;
00500 
00501     DPRINT("BasepNotifyCsrOfThread: Thread: %lx, Handle %lx\n",
00502             ClientId->UniqueThread, ThreadHandle);
00503 
00504     /* Fill out the request */
00505     CsrRequest.Data.CreateThreadRequest.ClientId = *ClientId;
00506     CsrRequest.Data.CreateThreadRequest.ThreadHandle = ThreadHandle;
00507 
00508     /* Call CSR */
00509     Status = CsrClientCallServer(&CsrRequest,
00510                                  NULL,
00511                                  MAKE_CSR_API(Request, CSR_NATIVE),
00512                                  sizeof(CSR_API_MESSAGE));
00513     if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
00514     {
00515         DPRINT1("Failed to tell csrss about new thread: %lx %lx\n", Status, CsrRequest.Status);
00516         return CsrRequest.Status;
00517     }
00518 
00519     /* Return Success */
00520     return STATUS_SUCCESS;
00521 }
00522 
00523 /*
00524  * Creates the first Thread in a Proces
00525  */
00526 HANDLE
00527 WINAPI
00528 BasepCreateFirstThread(HANDLE ProcessHandle,
00529                        LPSECURITY_ATTRIBUTES lpThreadAttributes,
00530                        PSECTION_IMAGE_INFORMATION SectionImageInfo,
00531                        PCLIENT_ID ClientId,
00532                        BOOLEAN InheritHandles,
00533                        DWORD dwCreationFlags)
00534 {
00535     OBJECT_ATTRIBUTES LocalObjectAttributes;
00536     POBJECT_ATTRIBUTES ObjectAttributes;
00537     CONTEXT Context;
00538     INITIAL_TEB InitialTeb;
00539     NTSTATUS Status;
00540     HANDLE hThread;
00541     ULONG Request = CREATE_PROCESS;
00542     CSR_API_MESSAGE CsrRequest;
00543     DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle);
00544 
00545     /* Create the Thread's Stack */
00546     BaseCreateStack(ProcessHandle,
00547                      SectionImageInfo->MaximumStackSize,
00548                      SectionImageInfo->CommittedStackSize,
00549                      &InitialTeb);
00550 
00551     /* Create the Thread's Context */
00552     BaseInitializeContext(&Context,
00553                            NtCurrentPeb(),
00554                            SectionImageInfo->TransferAddress,
00555                            InitialTeb.StackBase,
00556                            0);
00557 
00558     /* Convert the thread attributes */
00559     ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
00560                                                     lpThreadAttributes,
00561                                                     NULL);
00562 
00563     /* Create the Kernel Thread Object */
00564     Status = NtCreateThread(&hThread,
00565                             THREAD_ALL_ACCESS,
00566                             ObjectAttributes,
00567                             ProcessHandle,
00568                             ClientId,
00569                             &Context,
00570                             &InitialTeb,
00571                             TRUE);
00572     if (!NT_SUCCESS(Status))
00573     {
00574         return NULL;
00575     }
00576 
00577     /* Fill out the request to notify CSRSS */
00578     CsrRequest.Data.CreateProcessRequest.ClientId = *ClientId;
00579     CsrRequest.Data.CreateProcessRequest.ProcessHandle = ProcessHandle;
00580     CsrRequest.Data.CreateProcessRequest.ThreadHandle = hThread;
00581     CsrRequest.Data.CreateProcessRequest.CreationFlags = dwCreationFlags;
00582     CsrRequest.Data.CreateProcessRequest.bInheritHandles = InheritHandles;
00583 
00584     /* Call CSR */
00585     Status = CsrClientCallServer(&CsrRequest,
00586                                  NULL,
00587                                  MAKE_CSR_API(Request, CSR_NATIVE),
00588                                  sizeof(CSR_API_MESSAGE));
00589     if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
00590     {
00591         DPRINT1("Failed to tell csrss about new process: %lx %lx\n", Status, CsrRequest.Status);
00592         return NULL;
00593     }
00594 
00595     /* Success */
00596     return hThread;
00597 }
00598 
00599 /*
00600  * Converts ANSI to Unicode Environment
00601  */
00602 PVOID
00603 WINAPI
00604 BasepConvertUnicodeEnvironment(OUT SIZE_T* EnvSize,
00605                                IN PVOID lpEnvironment)
00606 {
00607     PCHAR pcScan;
00608     ANSI_STRING AnsiEnv;
00609     UNICODE_STRING UnicodeEnv;
00610     NTSTATUS Status;
00611 
00612     DPRINT("BasepConvertUnicodeEnvironment\n");
00613 
00614     /* Scan the environment to calculate its Unicode size */
00615     AnsiEnv.Buffer = pcScan = (PCHAR)lpEnvironment;
00616     while (*pcScan)
00617     {
00618         pcScan += strlen(pcScan) + 1;
00619     }
00620 
00621     /* Create our ANSI String */
00622     if (pcScan == (PCHAR)lpEnvironment)
00623     {
00624         AnsiEnv.Length = 2 * sizeof(CHAR);
00625     }
00626     else
00627     {
00628 
00629         AnsiEnv.Length = (USHORT)((ULONG_PTR)pcScan - (ULONG_PTR)lpEnvironment + sizeof(CHAR));
00630     }
00631     AnsiEnv.MaximumLength = AnsiEnv.Length + 1;
00632 
00633     /* Allocate memory for the Unicode Environment */
00634     UnicodeEnv.Buffer = NULL;
00635     *EnvSize = AnsiEnv.MaximumLength * sizeof(WCHAR);
00636     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
00637                                      (PVOID)&UnicodeEnv.Buffer,
00638                                      0,
00639                                      EnvSize,
00640                                      MEM_COMMIT,
00641                                      PAGE_READWRITE);
00642     /* Failure */
00643     if (!NT_SUCCESS(Status))
00644     {
00645         SetLastError(Status);
00646         *EnvSize = 0;
00647         return NULL;
00648     }
00649 
00650     /* Use the allocated size */
00651     UnicodeEnv.MaximumLength = (USHORT)*EnvSize;
00652 
00653     /* Convert */
00654     RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE);
00655     return UnicodeEnv.Buffer;
00656 }
00657 
00658 /*
00659  * Converts a Win32 Priority Class to NT
00660  */
00661 ULONG
00662 WINAPI
00663 BasepConvertPriorityClass(IN ULONG dwCreationFlags)
00664 {
00665     ULONG ReturnClass;
00666 
00667     if(dwCreationFlags & IDLE_PRIORITY_CLASS)
00668     {
00669         ReturnClass = PROCESS_PRIORITY_CLASS_IDLE;
00670     }
00671     else if(dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS)
00672     {
00673         ReturnClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
00674     }
00675     else if(dwCreationFlags & NORMAL_PRIORITY_CLASS)
00676     {
00677         ReturnClass = PROCESS_PRIORITY_CLASS_NORMAL;
00678     }
00679     else if(dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS)
00680     {
00681         ReturnClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
00682     }
00683     else if(dwCreationFlags & HIGH_PRIORITY_CLASS)
00684     {
00685         ReturnClass = PROCESS_PRIORITY_CLASS_HIGH;
00686     }
00687     else if(dwCreationFlags & REALTIME_PRIORITY_CLASS)
00688     {
00689         /* Check for Privilege First */
00690         if (BasepIsRealtimeAllowed(TRUE))
00691         {
00692             ReturnClass = PROCESS_PRIORITY_CLASS_REALTIME;
00693         }
00694         else
00695         {
00696             ReturnClass = PROCESS_PRIORITY_CLASS_HIGH;
00697         }
00698     }
00699     else
00700     {
00701         ReturnClass = PROCESS_PRIORITY_CLASS_INVALID;
00702     }
00703 
00704     return ReturnClass;
00705 }
00706 
00707 /*
00708  * Duplicates a standard handle and writes it where requested.
00709  */
00710 VOID
00711 WINAPI
00712 BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle,
00713                              IN HANDLE StandardHandle,
00714                              IN PHANDLE Address)
00715 {
00716     NTSTATUS Status;
00717     HANDLE DuplicatedHandle;
00718     SIZE_T Dummy;
00719 
00720     DPRINT("BasepDuplicateAndWriteHandle. hProcess: %lx, Handle: %lx,"
00721            "Address: %p\n", ProcessHandle, StandardHandle, Address);
00722 
00723     /* Don't touch Console Handles */
00724     if (IsConsoleHandle(StandardHandle)) return;
00725 
00726     /* Duplicate the handle */
00727     Status = NtDuplicateObject(NtCurrentProcess(),
00728                                StandardHandle,
00729                                ProcessHandle,
00730                                &DuplicatedHandle,
00731                                DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES,
00732                                0,
00733                                0);
00734     if (NT_SUCCESS(Status))
00735     {
00736         /* Write it */
00737         NtWriteVirtualMemory(ProcessHandle,
00738                              Address,
00739                              &DuplicatedHandle,
00740                              sizeof(HANDLE),
00741                              &Dummy);
00742     }
00743 }
00744 
00745 BOOLEAN
00746 WINAPI
00747 BasePushProcessParameters(IN ULONG ParameterFlags,
00748                           IN HANDLE ProcessHandle,
00749                           IN PPEB RemotePeb,
00750                           IN LPCWSTR ApplicationPathName,
00751                           IN LPWSTR lpCurrentDirectory,
00752                           IN LPWSTR lpCommandLine,
00753                           IN LPVOID lpEnvironment,
00754                           IN LPSTARTUPINFOW StartupInfo,
00755                           IN DWORD CreationFlags,
00756                           IN BOOL InheritHandles,
00757                           IN ULONG ImageSubsystem,
00758                           IN PVOID AppCompatData,
00759                           IN ULONG AppCompatDataSize)
00760 {
00761     WCHAR FullPath[MAX_PATH + 5];
00762     PWCHAR Remaining, DllPathString, ScanChar;
00763     PRTL_USER_PROCESS_PARAMETERS ProcessParameters, RemoteParameters;
00764     PVOID RemoteAppCompatData;
00765     UNICODE_STRING DllPath, ImageName, CommandLine, CurrentDirectory;
00766     UNICODE_STRING Desktop, Shell, Runtime, Title;
00767     NTSTATUS Status;
00768     ULONG EnviroSize;
00769     SIZE_T Size;
00770     BOOLEAN HavePebLock = FALSE, Result;
00771     PPEB Peb = NtCurrentPeb();
00772 
00773     /* Get the full path name */
00774     Size = GetFullPathNameW(ApplicationPathName,
00775                             MAX_PATH + 4,
00776                             FullPath,
00777                             &Remaining);
00778     if ((Size) && (Size <= (MAX_PATH + 4)))
00779     {
00780         /* Get the DLL Path */
00781         DllPathString = BaseComputeProcessDllPath(FullPath, lpEnvironment);
00782         if (!DllPathString)
00783         {
00784             /* Fail */
00785             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
00786             return FALSE;
00787         }
00788 
00789         /* Initialize Strings */
00790         RtlInitUnicodeString(&DllPath, DllPathString);
00791         RtlInitUnicodeString(&ImageName, FullPath);
00792     }
00793     else
00794     {
00795         /* Couldn't get the path name. Just take the original path */
00796         DllPathString = BaseComputeProcessDllPath((LPWSTR)ApplicationPathName,
00797                                                   lpEnvironment);
00798         if (!DllPathString)
00799         {
00800             /* Fail */
00801             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
00802             return FALSE;
00803         }
00804 
00805         /* Initialize Strings */
00806         RtlInitUnicodeString(&DllPath, DllPathString);
00807         RtlInitUnicodeString(&ImageName, ApplicationPathName);
00808     }
00809 
00810     /* Initialize Strings */
00811     RtlInitUnicodeString(&CommandLine, lpCommandLine);
00812     RtlInitUnicodeString(&CurrentDirectory, lpCurrentDirectory);
00813 
00814     /* Initialize more Strings from the Startup Info */
00815     if (StartupInfo->lpDesktop)
00816     {
00817         RtlInitUnicodeString(&Desktop, StartupInfo->lpDesktop);
00818     }
00819     else
00820     {
00821         RtlInitUnicodeString(&Desktop, L"");
00822     }
00823     if (StartupInfo->lpReserved)
00824     {
00825         RtlInitUnicodeString(&Shell, StartupInfo->lpReserved);
00826     }
00827     else
00828     {
00829         RtlInitUnicodeString(&Shell, L"");
00830     }
00831     if (StartupInfo->lpTitle)
00832     {
00833         RtlInitUnicodeString(&Title, StartupInfo->lpTitle);
00834     }
00835     else
00836     {
00837         RtlInitUnicodeString(&Title, ApplicationPathName);
00838     }
00839 
00840     /* This one is special because the length can differ */
00841     Runtime.Buffer = (LPWSTR)StartupInfo->lpReserved2;
00842     Runtime.MaximumLength = Runtime.Length = StartupInfo->cbReserved2;
00843 
00844     /* Enforce no app compat data if the pointer was NULL */
00845     if (!AppCompatData) AppCompatDataSize = 0;
00846 
00847     /* Create the Parameter Block */
00848     ProcessParameters = NULL;
00849     Status = RtlCreateProcessParameters(&ProcessParameters,
00850                                         &ImageName,
00851                                         &DllPath,
00852                                         lpCurrentDirectory ?
00853                                         &CurrentDirectory : NULL,
00854                                         &CommandLine,
00855                                         lpEnvironment,
00856                                         &Title,
00857                                         &Desktop,
00858                                         &Shell,
00859                                         &Runtime);
00860     if (!NT_SUCCESS(Status)) goto FailPath;
00861 
00862     /* Clear the current directory handle if not inheriting */
00863     if (!InheritHandles) ProcessParameters->CurrentDirectory.Handle = NULL;
00864 
00865     /* Check if the user passed in an environment */
00866     if (lpEnvironment)
00867     {
00868         /* We should've made it part of the parameters block, enforce this */
00869         ASSERT(ProcessParameters->Environment == lpEnvironment);
00870         lpEnvironment = ProcessParameters->Environment;
00871     }
00872     else
00873     {
00874         /* The user did not, so use the one from the current PEB */
00875         HavePebLock = TRUE;
00876         RtlAcquirePebLock();
00877         lpEnvironment = Peb->ProcessParameters->Environment;
00878     }
00879 
00880     /* Save pointer and start lookup */
00881     ScanChar = lpEnvironment;
00882     if (lpEnvironment)
00883     {
00884         /* Find the environment size */
00885         while ((ScanChar[0]) || (ScanChar[1])) ++ScanChar;
00886         ScanChar += (2 * sizeof(UNICODE_NULL));
00887         EnviroSize = (ULONG_PTR)ScanChar - (ULONG_PTR)lpEnvironment;
00888 
00889         /* Allocate and Initialize new Environment Block */
00890         Size = EnviroSize;
00891         ProcessParameters->Environment = NULL;
00892         Status = NtAllocateVirtualMemory(ProcessHandle,
00893                                          (PVOID*)&ProcessParameters->Environment,
00894                                          0,
00895                                          &Size,
00896                                          MEM_COMMIT,
00897                                          PAGE_READWRITE);
00898         if (!NT_SUCCESS(Status)) goto FailPath;
00899 
00900         /* Write the Environment Block */
00901         Status = NtWriteVirtualMemory(ProcessHandle,
00902                                       ProcessParameters->Environment,
00903                                       lpEnvironment,
00904                                       EnviroSize,
00905                                       NULL);
00906 
00907         /* No longer need the PEB lock anymore */
00908         if (HavePebLock)
00909         {
00910             /* Release it */
00911             RtlReleasePebLock();
00912             HavePebLock = FALSE;
00913         }
00914 
00915         /* Check if the write failed */
00916         if (!NT_SUCCESS(Status)) goto FailPath;
00917     }
00918 
00919     /* Write new parameters */
00920     ProcessParameters->StartingX = StartupInfo->dwX;
00921     ProcessParameters->StartingY = StartupInfo->dwY;
00922     ProcessParameters->CountX = StartupInfo->dwXSize;
00923     ProcessParameters->CountY = StartupInfo->dwYSize;
00924     ProcessParameters->CountCharsX = StartupInfo->dwXCountChars;
00925     ProcessParameters->CountCharsY = StartupInfo->dwYCountChars;
00926     ProcessParameters->FillAttribute = StartupInfo->dwFillAttribute;
00927     ProcessParameters->WindowFlags = StartupInfo->dwFlags;
00928     ProcessParameters->ShowWindowFlags = StartupInfo->wShowWindow;
00929 
00930     /* Write the handles only if we have to */
00931     if (StartupInfo->dwFlags &
00932         (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE))
00933     {
00934         ProcessParameters->StandardInput = StartupInfo->hStdInput;
00935         ProcessParameters->StandardOutput = StartupInfo->hStdOutput;
00936         ProcessParameters->StandardError = StartupInfo->hStdError;
00937     }
00938 
00939     /* Use Special Flags for ConDllInitialize in Kernel32 */
00940     if (CreationFlags & DETACHED_PROCESS)
00941     {
00942         ProcessParameters->ConsoleHandle = HANDLE_DETACHED_PROCESS;
00943     }
00944     else if (CreationFlags & CREATE_NO_WINDOW)
00945     {
00946         ProcessParameters->ConsoleHandle = HANDLE_CREATE_NO_WINDOW;
00947     }
00948     else if (CreationFlags & CREATE_NEW_CONSOLE)
00949     {
00950         ProcessParameters->ConsoleHandle = HANDLE_CREATE_NEW_CONSOLE;
00951     }
00952     else
00953     {
00954         /* Inherit our Console Handle */
00955         ProcessParameters->ConsoleHandle = Peb->ProcessParameters->ConsoleHandle;
00956 
00957         /* Make sure that the shell isn't trampling on our handles first */
00958         if (!(StartupInfo->dwFlags &
00959              (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
00960         {
00961             /* Copy the handle if we are inheriting or if it's a console handle */
00962             if ((InheritHandles) ||
00963                 (IsConsoleHandle(Peb->ProcessParameters->StandardInput)))
00964             {
00965                 ProcessParameters->StandardInput = Peb->ProcessParameters->StandardInput;
00966             }
00967             if ((InheritHandles) ||
00968                 (IsConsoleHandle(Peb->ProcessParameters->StandardOutput)))
00969             {
00970                 ProcessParameters->StandardOutput = Peb->ProcessParameters->StandardOutput;
00971             }
00972             if ((InheritHandles) ||
00973                 (IsConsoleHandle(Peb->ProcessParameters->StandardError)))
00974             {
00975                 ProcessParameters->StandardError = Peb->ProcessParameters->StandardError;
00976             }
00977         }
00978     }
00979 
00980     /* Also set the Console Flag */
00981     if ((CreationFlags & CREATE_NEW_PROCESS_GROUP) &&
00982         (!(CreationFlags & CREATE_NEW_CONSOLE)))
00983     {
00984         ProcessParameters->ConsoleFlags = 1;
00985     }
00986 
00987     /* See if the first 1MB should be reserved */
00988     if (ParameterFlags & 1)
00989     {
00990         ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB;
00991     }
00992 
00993     /* See if the first 16MB should be reserved */
00994     if (ParameterFlags & 2)
00995     {
00996         ProcessParameters->Flags |= RTL_USER_PROCESS_PARAMETERS_RESERVE_16MB;
00997     }
00998 
00999     /* Allocate memory for the parameter block */
01000     Size = ProcessParameters->Length;
01001     RemoteParameters = NULL;
01002     Status = NtAllocateVirtualMemory(ProcessHandle,
01003                                      (PVOID*)&RemoteParameters,
01004                                      0,
01005                                      &Size,
01006                                      MEM_COMMIT,
01007                                      PAGE_READWRITE);
01008     if (!NT_SUCCESS(Status)) goto FailPath;
01009 
01010     /* Set the allocated size */
01011     ProcessParameters->MaximumLength = Size;
01012 
01013     /* Handle some Parameter Flags */
01014     ProcessParameters->Flags |= (CreationFlags & PROFILE_USER) ?
01015                                  RTL_USER_PROCESS_PARAMETERS_PROFILE_USER : 0;
01016     ProcessParameters->Flags |= (CreationFlags & PROFILE_KERNEL) ?
01017                                  RTL_USER_PROCESS_PARAMETERS_PROFILE_KERNEL : 0;
01018     ProcessParameters->Flags |= (CreationFlags & PROFILE_SERVER) ?
01019                                  RTL_USER_PROCESS_PARAMETERS_PROFILE_SERVER : 0;
01020     ProcessParameters->Flags |= (Peb->ProcessParameters->Flags &
01021                                  RTL_USER_PROCESS_PARAMETERS_DISABLE_HEAP_CHECKS);
01022 
01023     /* Write the Parameter Block */
01024     Status = NtWriteVirtualMemory(ProcessHandle,
01025                                   RemoteParameters,
01026                                   ProcessParameters,
01027                                   ProcessParameters->Length,
01028                                   NULL);
01029     if (!NT_SUCCESS(Status)) goto FailPath;
01030 
01031     /* Write the PEB Pointer */
01032     Status = NtWriteVirtualMemory(ProcessHandle,
01033                                   &RemotePeb->ProcessParameters,
01034                                   &RemoteParameters,
01035                                   sizeof(PVOID),
01036                                   NULL);
01037     if (!NT_SUCCESS(Status)) goto FailPath;
01038 
01039     /* Check if there's any app compat data to write */
01040     RemoteAppCompatData = NULL;
01041     if (AppCompatData)
01042     {
01043         /* Allocate some space for the application compatibility data */
01044         Size = AppCompatDataSize;
01045         Status = NtAllocateVirtualMemory(ProcessHandle,
01046                                          &RemoteAppCompatData,
01047                                          0,
01048                                          &Size,
01049                                          MEM_COMMIT,
01050                                          PAGE_READWRITE);
01051         if (!NT_SUCCESS(Status)) goto FailPath;
01052 
01053         /* Write the application compatibility data */
01054         Status = NtWriteVirtualMemory(ProcessHandle,
01055                                       RemoteAppCompatData,
01056                                       AppCompatData,
01057                                       AppCompatDataSize,
01058                                       NULL);
01059         if (!NT_SUCCESS(Status)) goto FailPath;
01060     }
01061 
01062     /* Write the PEB Pointer to the app compat data (might be NULL) */
01063     Status = NtWriteVirtualMemory(ProcessHandle,
01064                                   &RemotePeb->pShimData,
01065                                   &RemoteAppCompatData,
01066                                   sizeof(PVOID),
01067                                   NULL);
01068     if (!NT_SUCCESS(Status)) goto FailPath;
01069 
01070     /* Now write Peb->ImageSubSystem */
01071     if (ImageSubsystem)
01072     {
01073         NtWriteVirtualMemory(ProcessHandle,
01074                              &RemotePeb->ImageSubsystem,
01075                              &ImageSubsystem,
01076                              sizeof(ImageSubsystem),
01077                              NULL);
01078     }
01079 
01080     /* Success path */
01081     Result = TRUE;
01082 
01083 Quickie:
01084     /* Cleanup */
01085     if (HavePebLock) RtlReleasePebLock();
01086     RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath.Buffer);
01087     if (ProcessParameters) RtlDestroyProcessParameters(ProcessParameters);
01088     return Result;
01089 FailPath:
01090     DPRINT1("Failure to create proecss parameters: %lx\n", Status);
01091     BaseSetLastNTError(Status);
01092     Result = FALSE;
01093     goto Quickie;
01094 }
01095 
01096 VOID
01097 WINAPI
01098 InitCommandLines(VOID)
01099 {
01100     NTSTATUS Status;
01101 
01102     /* Read the UNICODE_STRING from the PEB */
01103     BaseUnicodeCommandLine = NtCurrentPeb()->ProcessParameters->CommandLine;
01104 
01105     /* Convert to ANSI_STRING for the *A callers */
01106     Status = RtlUnicodeStringToAnsiString(&BaseAnsiCommandLine,
01107                                           &BaseUnicodeCommandLine,
01108                                           TRUE);
01109     if (!NT_SUCCESS(Status)) RtlInitEmptyAnsiString(&BaseAnsiCommandLine, 0, 0);
01110 }
01111 
01112 /* PUBLIC FUNCTIONS ***********************************************************/
01113 
01114 /*
01115  * @implemented
01116  */
01117 BOOL
01118 WINAPI
01119 GetProcessAffinityMask(IN HANDLE hProcess,
01120                        OUT PDWORD_PTR lpProcessAffinityMask,
01121                        OUT PDWORD_PTR lpSystemAffinityMask)
01122 {
01123     PROCESS_BASIC_INFORMATION ProcessInfo;
01124     NTSTATUS Status;
01125 
01126     /* Query information on the process from the kernel */
01127     Status = NtQueryInformationProcess(hProcess,
01128                                        ProcessBasicInformation,
01129                                        (PVOID)&ProcessInfo,
01130                                        sizeof(PROCESS_BASIC_INFORMATION),
01131                                        NULL);
01132     if (!NT_SUCCESS(Status))
01133     {
01134         /* Fail */
01135         BaseSetLastNTError(Status);
01136         return FALSE;
01137     }
01138 
01139     /* Copy the affinity mask, and get the system one from our shared data */
01140     *lpProcessAffinityMask = (DWORD)ProcessInfo.AffinityMask;
01141     *lpSystemAffinityMask = (DWORD)BaseStaticServerData->SysInfo.ActiveProcessorsAffinityMask;
01142     return TRUE;
01143 }
01144 
01145 /*
01146  * @implemented
01147  */
01148 BOOL
01149 WINAPI
01150 SetProcessAffinityMask(IN HANDLE hProcess,
01151                        IN DWORD_PTR dwProcessAffinityMask)
01152 {
01153     NTSTATUS Status;
01154 
01155     /* Directly set the affinity mask */
01156     Status = NtSetInformationProcess(hProcess,
01157                                      ProcessAffinityMask,
01158                                      (PVOID)&dwProcessAffinityMask,
01159                                      sizeof(DWORD));
01160     if (!NT_SUCCESS(Status))
01161     {
01162         /* Handle failure */
01163         BaseSetLastNTError(Status);
01164         return FALSE;
01165     }
01166 
01167     /* Everything was ok */
01168     return TRUE;
01169 }
01170 
01171 /*
01172  * @implemented
01173  */
01174 BOOL
01175 WINAPI
01176 GetProcessShutdownParameters(OUT LPDWORD lpdwLevel,
01177                              OUT LPDWORD lpdwFlags)
01178 {
01179     CSR_API_MESSAGE CsrRequest;
01180     NTSTATUS Status;
01181 
01182     /* Ask CSRSS for shutdown information */
01183     Status = CsrClientCallServer(&CsrRequest,
01184                                  NULL,
01185                                  MAKE_CSR_API(GET_SHUTDOWN_PARAMETERS, CSR_NATIVE),
01186                                  sizeof(CSR_API_MESSAGE));
01187     if (!(NT_SUCCESS(Status)) || !(NT_SUCCESS(CsrRequest.Status)))
01188     {
01189         /* Return the failure from CSRSS */
01190         BaseSetLastNTError(CsrRequest.Status);
01191         return FALSE;
01192     }
01193 
01194     /* Get the data out of the LCP reply */
01195     *lpdwLevel = CsrRequest.Data.GetShutdownParametersRequest.Level;
01196     *lpdwFlags = CsrRequest.Data.GetShutdownParametersRequest.Flags;
01197     return TRUE;
01198 }
01199 
01200 /*
01201  * @implemented
01202  */
01203 BOOL
01204 WINAPI
01205 SetProcessShutdownParameters(IN DWORD dwLevel,
01206                              IN DWORD dwFlags)
01207 {
01208     CSR_API_MESSAGE CsrRequest;
01209     NTSTATUS Status;
01210 
01211     /* Write the data into the CSRSS request and send it */
01212     CsrRequest.Data.SetShutdownParametersRequest.Level = dwLevel;
01213     CsrRequest.Data.SetShutdownParametersRequest.Flags = dwFlags;
01214     Status = CsrClientCallServer(&CsrRequest,
01215                                  NULL,
01216                                  MAKE_CSR_API(SET_SHUTDOWN_PARAMETERS, CSR_NATIVE),
01217                                  sizeof(CSR_API_MESSAGE));
01218     if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status))
01219     {
01220         /* Return the failure from CSRSS */
01221         BaseSetLastNTError(CsrRequest.Status);
01222         return FALSE;
01223     }
01224 
01225     /* All went well */
01226     return TRUE;
01227 }
01228 
01229 /*
01230  * @implemented
01231  */
01232 BOOL
01233 WINAPI
01234 GetProcessWorkingSetSizeEx(IN HANDLE hProcess,
01235                            OUT PSIZE_T lpMinimumWorkingSetSize,
01236                            OUT PSIZE_T lpMaximumWorkingSetSize,
01237                            OUT PDWORD Flags)
01238 {
01239     QUOTA_LIMITS_EX QuotaLimits;
01240     NTSTATUS Status;
01241 
01242     /* Query the kernel about this */
01243     Status = NtQueryInformationProcess(hProcess,
01244                                        ProcessQuotaLimits,
01245                                        &QuotaLimits,
01246                                        sizeof(QUOTA_LIMITS_EX),
01247                                        NULL);
01248     if (!NT_SUCCESS(Status))
01249     {
01250         /* Return error */
01251         BaseSetLastNTError(Status);
01252         return FALSE;
01253     }
01254 
01255     /* Copy the quota information out */
01256     *lpMinimumWorkingSetSize = QuotaLimits.MinimumWorkingSetSize;
01257     *lpMaximumWorkingSetSize = QuotaLimits.MaximumWorkingSetSize;
01258     *Flags = QuotaLimits.Flags;
01259     return TRUE;
01260 }
01261 
01262 /*
01263  * @implemented
01264  */
01265 BOOL
01266 WINAPI
01267 GetProcessWorkingSetSize(IN HANDLE hProcess,
01268                          OUT PSIZE_T lpMinimumWorkingSetSize,
01269                          OUT PSIZE_T lpMaximumWorkingSetSize)
01270 {
01271     DWORD Dummy;
01272     return GetProcessWorkingSetSizeEx(hProcess,
01273                                       lpMinimumWorkingSetSize,
01274                                       lpMaximumWorkingSetSize,
01275                                       &Dummy);
01276 }
01277 
01278 /*
01279  * @implemented
01280  */
01281 BOOL
01282 WINAPI
01283 SetProcessWorkingSetSizeEx(IN HANDLE hProcess,
01284                            IN SIZE_T dwMinimumWorkingSetSize,
01285                            IN SIZE_T dwMaximumWorkingSetSize,
01286                            IN DWORD Flags)
01287 {
01288     QUOTA_LIMITS_EX QuotaLimits;
01289     NTSTATUS Status, ReturnStatus;
01290     BOOL Result;
01291     PVOID State;
01292     ULONG Privilege = SE_INC_BASE_PRIORITY_PRIVILEGE;
01293 
01294     /* Zero out the input structure */
01295     RtlZeroMemory(&QuotaLimits, sizeof(QuotaLimits));
01296 
01297     /* Check if the caller sent any limits */
01298     if ((dwMinimumWorkingSetSize) && (dwMaximumWorkingSetSize))
01299     {
01300         /* Write the quota information */
01301         QuotaLimits.MinimumWorkingSetSize = dwMinimumWorkingSetSize;
01302         QuotaLimits.MaximumWorkingSetSize = dwMaximumWorkingSetSize;
01303         QuotaLimits.Flags = Flags;
01304 
01305         /* Acquire the required privilege */
01306         Status = RtlAcquirePrivilege(&Privilege, 1, 0, &State);
01307 
01308         /* Request the new quotas */
01309         ReturnStatus = NtSetInformationProcess(hProcess,
01310                                                ProcessQuotaLimits,
01311                                                &QuotaLimits,
01312                                                sizeof(QuotaLimits));
01313         Result = NT_SUCCESS(ReturnStatus);
01314         if (NT_SUCCESS(Status))
01315         {
01316             /* Release the privilege and set succes code */
01317             ASSERT(State != NULL);
01318             RtlReleasePrivilege(State);
01319             State = NULL;
01320         }
01321     }
01322     else
01323     {
01324         /* No limits, fail the call */
01325         ReturnStatus = STATUS_INVALID_PARAMETER;
01326         Result = FALSE;
01327     }
01328 
01329     /* Return result code, set error code if this was a failure */
01330     if (!Result) BaseSetLastNTError(ReturnStatus);
01331     return Result;
01332 }
01333 
01334 /*
01335  * @implemented
01336  */
01337 BOOL
01338 WINAPI
01339 SetProcessWorkingSetSize(IN HANDLE hProcess,
01340                          IN SIZE_T dwMinimumWorkingSetSize,
01341                          IN SIZE_T dwMaximumWorkingSetSize)
01342 {
01343     /* Call the newer API */
01344     return SetProcessWorkingSetSizeEx(hProcess,
01345                                       dwMinimumWorkingSetSize,
01346                                       dwMaximumWorkingSetSize,
01347                                       0);
01348 }
01349 
01350 /*
01351  * @implemented
01352  */
01353 BOOL
01354 WINAPI
01355 GetProcessTimes(IN HANDLE hProcess,
01356                 IN LPFILETIME lpCreationTime,
01357                 IN LPFILETIME lpExitTime,
01358                 IN LPFILETIME lpKernelTime,
01359                 IN LPFILETIME lpUserTime)
01360 {
01361     KERNEL_USER_TIMES Kut;
01362     NTSTATUS Status;
01363 
01364     /* Query the times */
01365     Status = NtQueryInformationProcess(hProcess,
01366                                        ProcessTimes,
01367                                        &Kut,
01368                                        sizeof(Kut),
01369                                        NULL);
01370     if (!NT_SUCCESS(Status))
01371     {
01372         /* Handle failure */
01373         BaseSetLastNTError(Status);
01374         return FALSE;
01375     }
01376 
01377     /* Copy all the times and return success */
01378     lpCreationTime->dwLowDateTime = Kut.CreateTime.u.LowPart;
01379     lpCreationTime->dwHighDateTime = Kut.CreateTime.u.HighPart;
01380     lpExitTime->dwLowDateTime = Kut.ExitTime.u.LowPart;
01381     lpExitTime->dwHighDateTime = Kut.ExitTime.u.HighPart;
01382     lpKernelTime->dwLowDateTime = Kut.KernelTime.u.LowPart;
01383     lpKernelTime->dwHighDateTime = Kut.KernelTime.u.HighPart;
01384     lpUserTime->dwLowDateTime = Kut.UserTime.u.LowPart;
01385     lpUserTime->dwHighDateTime = Kut.UserTime.u.HighPart;
01386     return TRUE;
01387 }
01388 
01389 /*
01390  * @implemented
01391  */
01392 HANDLE
01393 WINAPI
01394 GetCurrentProcess(VOID)
01395 {
01396     return (HANDLE)NtCurrentProcess();
01397 }
01398 
01399 /*
01400  * @implemented
01401  */
01402 HANDLE
01403 WINAPI
01404 GetCurrentThread(VOID)
01405 {
01406     return (HANDLE)NtCurrentThread();
01407 }
01408 
01409 /*
01410  * @implemented
01411  */
01412 DWORD
01413 WINAPI
01414 GetCurrentProcessId(VOID)
01415 {
01416     return HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess);
01417 }
01418 
01419 /*
01420  * @implemented
01421  */
01422 BOOL
01423 WINAPI
01424 GetExitCodeProcess(IN HANDLE hProcess,
01425                    IN LPDWORD lpExitCode)
01426 {
01427     PROCESS_BASIC_INFORMATION ProcessBasic;
01428     NTSTATUS Status;
01429 
01430     /* Ask the kernel */
01431     Status = NtQueryInformationProcess(hProcess,
01432                                        ProcessBasicInformation,
01433                                        &ProcessBasic,
01434                                        sizeof(PROCESS_BASIC_INFORMATION),
01435                                        NULL);
01436     if (!NT_SUCCESS(Status))
01437     {
01438         /* We failed, was this because this is a VDM process? */
01439         if (BaseCheckForVDM(hProcess, lpExitCode) == TRUE) return TRUE;
01440 
01441         /* Not a VDM process, fail the call */
01442         BaseSetLastNTError(Status);
01443         return FALSE;
01444     }
01445 
01446     /* Succes case, return the exit code */
01447     *lpExitCode = (DWORD)ProcessBasic.ExitStatus;
01448     return TRUE;
01449 }
01450 
01451 /*
01452  * @implemented
01453  */
01454 DWORD
01455 WINAPI
01456 GetProcessId(IN HANDLE Process)
01457 {
01458     PROCESS_BASIC_INFORMATION ProcessBasic;
01459     NTSTATUS Status;
01460 
01461     /* Query the kernel */
01462     Status = NtQueryInformationProcess(Process,
01463                                        ProcessBasicInformation,
01464                                        &ProcessBasic,
01465                                        sizeof(PROCESS_BASIC_INFORMATION),
01466                                        NULL);
01467     if (!NT_SUCCESS(Status))
01468     {
01469         /* Handle failure */
01470         BaseSetLastNTError(Status);
01471         return 0;
01472     }
01473 
01474     /* Return the PID */
01475     return (DWORD)ProcessBasic.UniqueProcessId;
01476 }
01477 
01478 /*
01479  * @implemented
01480  */
01481 HANDLE
01482 WINAPI
01483 OpenProcess(IN DWORD dwDesiredAccess,
01484             IN BOOL bInheritHandle,
01485             IN DWORD dwProcessId)
01486 {
01487     NTSTATUS Status;
01488     HANDLE ProcessHandle;
01489     OBJECT_ATTRIBUTES ObjectAttributes;
01490     CLIENT_ID ClientId;
01491 
01492     /* Setup the input client ID structure */
01493     ClientId.UniqueProcess = UlongToHandle(dwProcessId);
01494     ClientId.UniqueThread = 0;
01495 
01496     /* This is needed just to define the inheritance flags */
01497     InitializeObjectAttributes(&ObjectAttributes,
01498                                NULL,
01499                                (bInheritHandle ? OBJ_INHERIT : 0),
01500                                NULL,
01501                                NULL);
01502 
01503     /* Now try to open the process */
01504     Status = NtOpenProcess(&ProcessHandle,
01505                            dwDesiredAccess,
01506                            &ObjectAttributes,
01507                            &ClientId);
01508     if (!NT_SUCCESS(Status))
01509     {
01510         /* Handle failure */
01511         BaseSetLastNTError(Status);
01512         return NULL;
01513     }
01514 
01515     /* Otherwise return a handle to the process */
01516     return ProcessHandle;
01517 }
01518 
01519 /*
01520  * @implemented
01521  */
01522 VOID
01523 WINAPI
01524 RegisterWaitForInputIdle(IN WaitForInputIdleType lpfnRegisterWaitForInputIdle)
01525 {
01526     /* Write the global function pointer */
01527     UserWaitForInputIdleRoutine = lpfnRegisterWaitForInputIdle;
01528 }
01529 
01530 /*
01531  * @implemented
01532  */
01533 VOID
01534 WINAPI
01535 GetStartupInfoW(IN LPSTARTUPINFOW lpStartupInfo)
01536 {
01537     PRTL_USER_PROCESS_PARAMETERS Params;
01538 
01539     /* Get the process parameters */
01540     Params = NtCurrentPeb()->ProcessParameters;
01541 
01542     /* Copy the data out of there */
01543     lpStartupInfo->cb = sizeof(STARTUPINFOW);
01544     lpStartupInfo->lpReserved = Params->ShellInfo.Buffer;
01545     lpStartupInfo->lpDesktop = Params->DesktopInfo.Buffer;
01546     lpStartupInfo->lpTitle = Params->WindowTitle.Buffer;
01547     lpStartupInfo->dwX = Params->StartingX;
01548     lpStartupInfo->dwY = Params->StartingY;
01549     lpStartupInfo->dwXSize = Params->CountX;
01550     lpStartupInfo->dwYSize = Params->CountY;
01551     lpStartupInfo->dwXCountChars = Params->CountCharsX;
01552     lpStartupInfo->dwYCountChars = Params->CountCharsY;
01553     lpStartupInfo->dwFillAttribute = Params->FillAttribute;
01554     lpStartupInfo->dwFlags = Params->WindowFlags;
01555     lpStartupInfo->wShowWindow = (WORD)Params->ShowWindowFlags;
01556     lpStartupInfo->cbReserved2 = Params->RuntimeData.Length;
01557     lpStartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeData.Buffer;
01558 
01559     /* Check if the standard handles are being used for other features */
01560     if (lpStartupInfo->dwFlags & (STARTF_USESTDHANDLES |
01561                                   STARTF_USEHOTKEY |
01562                                   STARTF_SHELLPRIVATE))
01563     {
01564         /* These are, so copy the standard handles too */
01565         lpStartupInfo->hStdInput = Params->StandardInput;
01566         lpStartupInfo->hStdOutput = Params->StandardOutput;
01567         lpStartupInfo->hStdError = Params->StandardError;
01568     }
01569 }
01570 
01571 /*
01572  * @implemented
01573  */
01574 VOID
01575 WINAPI
01576 GetStartupInfoA(IN LPSTARTUPINFOA lpStartupInfo)
01577 {
01578     PRTL_USER_PROCESS_PARAMETERS Params;
01579     ANSI_STRING TitleString, ShellString, DesktopString;
01580     LPSTARTUPINFOA StartupInfo;
01581     NTSTATUS Status;
01582 
01583     /* Get the cached information as well as the PEB parameters */
01584     StartupInfo = BaseAnsiStartupInfo;
01585     Params = NtCurrentPeb()->ProcessParameters;
01586 
01587     /* Check if this is the first time we have to get the cached version */
01588     while (!StartupInfo)
01589     {
01590         /* Create new ANSI startup info */
01591         StartupInfo = RtlAllocateHeap(RtlGetProcessHeap(),
01592                                       0,
01593                                       sizeof(*StartupInfo));
01594         if (StartupInfo)
01595         {
01596             /* Zero out string pointers in case we fail to create them */
01597             StartupInfo->lpReserved = 0;
01598             StartupInfo->lpDesktop = 0;
01599             StartupInfo->lpTitle = 0;
01600 
01601             /* Set the size */
01602             StartupInfo->cb = sizeof(*StartupInfo);
01603 
01604             /* Copy what's already stored in the PEB */
01605             StartupInfo->dwX = Params->StartingX;
01606             StartupInfo->dwY = Params->StartingY;
01607             StartupInfo->dwXSize = Params->CountX;
01608             StartupInfo->dwYSize = Params->CountY;
01609             StartupInfo->dwXCountChars = Params->CountCharsX;
01610             StartupInfo->dwYCountChars = Params->CountCharsY;
01611             StartupInfo->dwFillAttribute = Params->FillAttribute;
01612             StartupInfo->dwFlags = Params->WindowFlags;
01613             StartupInfo->wShowWindow = (WORD)Params->ShowWindowFlags;
01614             StartupInfo->cbReserved2 = Params->RuntimeData.Length;
01615             StartupInfo->lpReserved2 = (LPBYTE)Params->RuntimeData.Buffer;
01616             StartupInfo->hStdInput = Params->StandardInput;
01617             StartupInfo->hStdOutput = Params->StandardOutput;
01618             StartupInfo->hStdError = Params->StandardError;
01619 
01620             /* Copy shell info string */
01621             Status = RtlUnicodeStringToAnsiString(&ShellString,
01622                                                   &Params->ShellInfo,
01623                                                   TRUE);
01624             if (NT_SUCCESS(Status))
01625             {
01626                 /* Save it */
01627                 StartupInfo->lpReserved = ShellString.Buffer;
01628 
01629                 /* Copy desktop info string */
01630                 Status = RtlUnicodeStringToAnsiString(&DesktopString,
01631                                                       &Params->DesktopInfo,
01632                                                       TRUE);
01633                 if (NT_SUCCESS(Status))
01634                 {
01635                     /* Save it */
01636                     StartupInfo->lpDesktop = DesktopString.Buffer;
01637 
01638                     /* Copy window title string */
01639                     Status = RtlUnicodeStringToAnsiString(&TitleString,
01640                                                           &Params->WindowTitle,
01641                                                           TRUE);
01642                     if (NT_SUCCESS(Status))
01643                     {
01644                         /* Save it */
01645                         StartupInfo->lpTitle = TitleString.Buffer;
01646 
01647                         /* We finished with the ANSI version, try to cache it */
01648                         if (!InterlockedCompareExchangePointer(&BaseAnsiStartupInfo,
01649                                                                StartupInfo,
01650                                                                NULL))
01651                         {
01652                             /* We were the first thread through, use the data */
01653                             break;
01654                         }
01655 
01656                         /* Someone beat us to it, use their data instead */
01657                         StartupInfo = BaseAnsiStartupInfo;
01658                         Status = STATUS_SUCCESS;
01659 
01660                         /* We're going to free our own stuff, but not raise */
01661                         RtlFreeAnsiString(&TitleString);
01662                     }
01663                     RtlFreeAnsiString(&DesktopString);
01664                 }
01665                 RtlFreeAnsiString(&ShellString);
01666             }
01667             RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo);
01668         }
01669         else
01670         {
01671             /* No memory, fail */
01672             Status = STATUS_NO_MEMORY;
01673         }
01674 
01675         /* Raise an error unless we got here due to the race condition */
01676         if (!NT_SUCCESS(Status)) RtlRaiseStatus(Status);
01677     }
01678 
01679     /* Now copy from the cached ANSI version */
01680     lpStartupInfo->cb = StartupInfo->cb;
01681     lpStartupInfo->lpReserved = StartupInfo->lpReserved;
01682     lpStartupInfo->lpDesktop = StartupInfo->lpDesktop;
01683     lpStartupInfo->lpTitle = StartupInfo->lpTitle;
01684     lpStartupInfo->dwX = StartupInfo->dwX;
01685     lpStartupInfo->dwY = StartupInfo->dwY;
01686     lpStartupInfo->dwXSize = StartupInfo->dwXSize;
01687     lpStartupInfo->dwYSize = StartupInfo->dwYSize;
01688     lpStartupInfo->dwXCountChars = StartupInfo->dwXCountChars;
01689     lpStartupInfo->dwYCountChars = StartupInfo->dwYCountChars;
01690     lpStartupInfo->dwFillAttribute = StartupInfo->dwFillAttribute;
01691     lpStartupInfo->dwFlags = StartupInfo->dwFlags;
01692     lpStartupInfo->wShowWindow = StartupInfo->wShowWindow;
01693     lpStartupInfo->cbReserved2 = StartupInfo->cbReserved2;
01694     lpStartupInfo->lpReserved2 = StartupInfo->lpReserved2;
01695 
01696     /* Check if the shell is hijacking the handles for other features */
01697     if (lpStartupInfo->dwFlags &
01698         (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE))
01699     {
01700         /* It isn't, so we can return the raw values */
01701         lpStartupInfo->hStdInput = StartupInfo->hStdInput;
01702         lpStartupInfo->hStdOutput = StartupInfo->hStdOutput;
01703         lpStartupInfo->hStdError = StartupInfo->hStdError;
01704     }
01705     else
01706     {
01707         /* It is, so make sure nobody uses these as console handles */
01708         lpStartupInfo->hStdInput = INVALID_HANDLE_VALUE;
01709         lpStartupInfo->hStdOutput = INVALID_HANDLE_VALUE;
01710         lpStartupInfo->hStdError = INVALID_HANDLE_VALUE;
01711     }
01712 }
01713 
01714 /*
01715  * @implemented
01716  */
01717 BOOL
01718 WINAPI
01719 FlushInstructionCache(IN HANDLE hProcess,
01720                       IN LPCVOID lpBaseAddress,
01721                       IN SIZE_T dwSize)
01722 {
01723     NTSTATUS Status;
01724 
01725     /* Call the native function */
01726     Status = NtFlushInstructionCache(hProcess, (PVOID)lpBaseAddress, dwSize);
01727     if (!NT_SUCCESS(Status))
01728     {
01729         /* Handle failure case */
01730         BaseSetLastNTError(Status);
01731         return FALSE;
01732     }
01733 
01734     /* All good */
01735     return TRUE;
01736 }
01737 
01738 /*
01739  * @implemented
01740  */
01741 VOID
01742 WINAPI
01743 ExitProcess(IN UINT uExitCode)
01744 {
01745     CSR_API_MESSAGE CsrRequest;
01746     ASSERT(!BaseRunningInServerProcess);
01747 
01748     _SEH2_TRY
01749     {
01750         /* Acquire the PEB lock */
01751         RtlAcquirePebLock();
01752 
01753         /* Kill all the threads */
01754         NtTerminateProcess(NULL, 0);
01755 
01756         /* Unload all DLLs */
01757         LdrShutdownProcess();
01758 
01759         /* Notify Base Server of process termination */
01760         CsrRequest.Data.TerminateProcessRequest.uExitCode = uExitCode;
01761         CsrClientCallServer(&CsrRequest,
01762                             NULL,
01763                             MAKE_CSR_API(TERMINATE_PROCESS, CSR_NATIVE),
01764                             sizeof(CSR_API_MESSAGE));
01765 
01766         /* Now do it again */
01767         NtTerminateProcess(NtCurrentProcess(), uExitCode);
01768     }
01769     _SEH2_FINALLY
01770     {
01771         /* Release the PEB lock */
01772         RtlReleasePebLock();
01773     }
01774     _SEH2_END;
01775 
01776     /* should never get here */
01777     ASSERT(0);
01778     while(1);
01779 }
01780 
01781 /*
01782  * @implemented
01783  */
01784 BOOL
01785 WINAPI
01786 TerminateProcess(IN HANDLE hProcess,
01787                  IN UINT uExitCode)
01788 {
01789     NTSTATUS Status;
01790 
01791     /* Check if no handle was passed in */
01792     if (!hProcess)
01793     {
01794         /* Set error code */
01795         SetLastError(ERROR_INVALID_HANDLE);
01796     }
01797     else
01798     {
01799         /* Otherwise, try to terminate the process */
01800         Status = NtTerminateProcess(hProcess, uExitCode);
01801         if (NT_SUCCESS(Status)) return TRUE;
01802 
01803         /* It failed, convert error code */
01804         BaseSetLastNTError(Status);
01805     }
01806 
01807     /* This is the failure path */
01808     return FALSE;
01809 }
01810 
01811 /*
01812  * @implemented
01813  */
01814 VOID
01815 WINAPI
01816 FatalAppExitA(UINT uAction,
01817               LPCSTR lpMessageText)
01818 {
01819     PUNICODE_STRING MessageTextU;
01820     ANSI_STRING MessageText;
01821     NTSTATUS Status;
01822 
01823     /* Initialize the string using the static TEB pointer */
01824     MessageTextU = &NtCurrentTeb()->StaticUnicodeString;
01825     RtlInitAnsiString(&MessageText, (LPSTR)lpMessageText);
01826 
01827     /* Convert to unicode and just exit normally if this failed */
01828     Status = RtlAnsiStringToUnicodeString(MessageTextU, &MessageText, FALSE);
01829     if (!NT_SUCCESS(Status)) ExitProcess(0);
01830 
01831     /* Call the Wide function */
01832     FatalAppExitW(uAction, MessageTextU->Buffer);
01833 }
01834 
01835 /*
01836  * @implemented
01837  */
01838 VOID
01839 WINAPI
01840 FatalAppExitW(IN UINT uAction,
01841               IN LPCWSTR lpMessageText)
01842 {
01843     UNICODE_STRING UnicodeString;
01844     ULONG Response;
01845     NTSTATUS Status;
01846 
01847     /* Setup the stirng to print out */
01848     RtlInitUnicodeString(&UnicodeString, lpMessageText);
01849 
01850     /* Display the hard error no matter what */
01851     Status = NtRaiseHardError(STATUS_FATAL_APP_EXIT | HARDERROR_OVERRIDE_ERRORMODE,
01852                               1,
01853                               1,
01854                               (PULONG_PTR)&UnicodeString,
01855                               OptionOkCancel,
01856                               &Response);
01857 
01858     /* Give the user a chance to abort */
01859     if ((NT_SUCCESS(Status)) && (Response == ResponseCancel)) return;
01860 
01861     /* Otherwise kill the process */
01862     ExitProcess(0);
01863 }
01864 
01865 /*
01866  * @implemented
01867  */
01868 VOID
01869 WINAPI
01870 FatalExit(IN int ExitCode)
01871 {
01872 #if DBG
01873     /* On Checked builds, Windows gives you a nice little debugger UI */
01874     CHAR ch[2];
01875     DbgPrint("FatalExit...\n");
01876     DbgPrint("\n");
01877 
01878     while (TRUE)
01879     {
01880         DbgPrompt( "A (Abort), B (Break), I (Ignore)? ", ch, sizeof(ch));
01881         switch (ch[0])
01882         {
01883             case 'B': case 'b':
01884                  DbgBreakPoint();
01885                  break;
01886 
01887             case 'A': case 'a':
01888                 ExitProcess(ExitCode);
01889 
01890             case 'I': case 'i':
01891                 return;
01892         }
01893     }
01894 #endif
01895     /* On other builds, just kill the process */
01896     ExitProcess(ExitCode);
01897 }
01898 
01899 /*
01900  * @implemented
01901  */
01902 DWORD
01903 WINAPI
01904 GetPriorityClass(IN HANDLE hProcess)
01905 {
01906     NTSTATUS Status;
01907     PROCESS_PRIORITY_CLASS PriorityClass;
01908 
01909     /* Query the kernel */
01910     Status = NtQueryInformationProcess(hProcess,
01911                                        ProcessPriorityClass,
01912                                        &PriorityClass,
01913                                        sizeof(PROCESS_PRIORITY_CLASS),
01914                                        NULL);
01915     if (NT_SUCCESS(Status))
01916     {
01917         /* Handle the conversion from NT to Win32 classes */
01918         switch (PriorityClass.PriorityClass)
01919         {
01920             case PROCESS_PRIORITY_CLASS_IDLE: return IDLE_PRIORITY_CLASS;
01921             case PROCESS_PRIORITY_CLASS_BELOW_NORMAL: return BELOW_NORMAL_PRIORITY_CLASS;
01922             case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL: return ABOVE_NORMAL_PRIORITY_CLASS;
01923             case PROCESS_PRIORITY_CLASS_HIGH: return HIGH_PRIORITY_CLASS;
01924             case PROCESS_PRIORITY_CLASS_REALTIME: return REALTIME_PRIORITY_CLASS;
01925             case PROCESS_PRIORITY_CLASS_NORMAL: default: return NORMAL_PRIORITY_CLASS;
01926         }
01927     }
01928 
01929     /* Failure path */
01930     BaseSetLastNTError(Status);
01931     return FALSE;
01932 }
01933 
01934 /*
01935  * @implemented
01936  */
01937 BOOL
01938 WINAPI
01939 SetPriorityClass(IN HANDLE hProcess,
01940                  IN DWORD dwPriorityClass)
01941 {
01942     NTSTATUS Status;
01943     PVOID State = NULL;
01944     PROCESS_PRIORITY_CLASS PriorityClass;
01945 
01946     /* Handle conversion from Win32 to NT priority classes */
01947     switch (dwPriorityClass)
01948     {
01949         case IDLE_PRIORITY_CLASS:
01950             PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE;
01951             break;
01952 
01953         case BELOW_NORMAL_PRIORITY_CLASS:
01954             PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
01955             break;
01956 
01957         case NORMAL_PRIORITY_CLASS:
01958             PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
01959             break;
01960 
01961         case ABOVE_NORMAL_PRIORITY_CLASS:
01962             PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
01963             break;
01964 
01965         case HIGH_PRIORITY_CLASS:
01966             PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
01967             break;
01968 
01969         case REALTIME_PRIORITY_CLASS:
01970             /* Try to acquire the privilege. If it fails, just use HIGH */
01971             State = BasepIsRealtimeAllowed(TRUE);
01972             PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
01973             PriorityClass.PriorityClass += (State != NULL);
01974             break;
01975 
01976         default:
01977             /* Unrecognized priority classes don't make it to the kernel */
01978             SetLastError(ERROR_INVALID_PARAMETER);
01979             return FALSE;
01980     }
01981 
01982     /* Send the request to the kernel, and don't touch the foreground flag */
01983     PriorityClass.Foreground = FALSE;
01984     Status = NtSetInformationProcess(hProcess,
01985                                      ProcessPriorityClass,
01986                                      &PriorityClass,
01987                                      sizeof(PROCESS_PRIORITY_CLASS));
01988 
01989     /* Release the privilege if we had it */
01990     if (State) RtlReleasePrivilege(State);
01991     if (!NT_SUCCESS(Status))
01992     {
01993         /* Handle error path */
01994         BaseSetLastNTError(Status);
01995         return FALSE;
01996     }
01997 
01998     /* All done */
01999     return TRUE;
02000 }
02001 
02002 /*
02003  * @implemented
02004  */
02005 DWORD
02006 WINAPI
02007 GetProcessVersion(IN DWORD ProcessId)
02008 {
02009     DWORD Version = 0;
02010     PIMAGE_NT_HEADERS NtHeader;
02011     PIMAGE_DOS_HEADER DosHeader;
02012     PPEB Peb;
02013     PROCESS_BASIC_INFORMATION ProcessBasicInfo;
02014     PVOID BaseAddress;
02015     ULONG e_lfanew;
02016     HANDLE ProcessHandle = NULL;
02017     NTSTATUS Status;
02018     USHORT VersionData[2];
02019     BOOLEAN Result;
02020 
02021     /* We'll be accessing stuff that can fault, so protect everything with SEH */
02022     _SEH2_TRY
02023     {
02024         /* It this an in-process or out-of-process request? */
02025         if (!(ProcessId) || (GetCurrentProcessId() == ProcessId))
02026         {
02027             /* It's in-process, so just read our own header */
02028             NtHeader = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
02029             if (!NtHeader)
02030             {
02031                 /* Unable to read the NT header, something is wrong here... */
02032                 Status = STATUS_INVALID_IMAGE_FORMAT;
02033                 goto Error;
02034             }
02035 
02036             /* Get the version straight out of the NT header */
02037             Version = MAKELONG(NtHeader->OptionalHeader.MinorSubsystemVersion,
02038                                NtHeader->OptionalHeader.MajorSubsystemVersion);
02039         }
02040         else
02041         {
02042             /* Out-of-process, so open it */
02043             ProcessHandle = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
02044                                         FALSE,
02045                                         ProcessId);
02046             if (!ProcessHandle) return 0;
02047 
02048             /* Try to find out where its PEB lives */
02049             Status = NtQueryInformationProcess(ProcessHandle,
02050                                                ProcessBasicInformation,
02051                                                &ProcessBasicInfo,
02052                                                sizeof(ProcessBasicInfo),
02053                                                NULL);
02054 
02055             if (!NT_SUCCESS(Status)) goto Error;
02056             Peb = ProcessBasicInfo.PebBaseAddress;
02057 
02058             /* Now that we have the PEB, read the image base address out of it */
02059             Result = ReadProcessMemory(ProcessHandle,
02060                                        &Peb->ImageBaseAddress,
02061                                        &BaseAddress,
02062                                        sizeof(BaseAddress),
02063                                        NULL);
02064             if (!Result) goto Error;
02065 
02066             /* Now read the e_lfanew (offset to NT header) from the base */
02067             DosHeader = BaseAddress;
02068             Result = ReadProcessMemory(ProcessHandle,
02069                                        &DosHeader->e_lfanew,
02070                                        &e_lfanew,
02071                                        sizeof(e_lfanew),
02072                                        NULL);
02073             if (!Result) goto Error;
02074 
02075             /* And finally, read the NT header itself by adding the offset */
02076             NtHeader = (PVOID)((ULONG_PTR)BaseAddress + e_lfanew);
02077             Result = ReadProcessMemory(ProcessHandle,
02078                                        &NtHeader->OptionalHeader.MajorSubsystemVersion,
02079                                        &VersionData,
02080                                        sizeof(VersionData),
02081                                        NULL);
02082             if (!Result) goto Error;
02083 
02084             /* Get the version straight out of the NT header */
02085             Version = MAKELONG(VersionData[0], VersionData[1]);
02086 
02087 Error:
02088             /* If there was an error anywhere, set the last error */
02089             if (!NT_SUCCESS(Status)) BaseSetLastNTError(Status);
02090         }
02091     }
02092     _SEH2_FINALLY
02093     {
02094         /* Close the process handle */
02095         if (ProcessHandle) CloseHandle(ProcessHandle);
02096     }
02097     _SEH2_END;
02098 
02099     /* And return the version data */
02100     return Version;
02101 }
02102 
02103 /*
02104  * @implemented
02105  */
02106 BOOL
02107 WINAPI
02108 GetProcessIoCounters(IN HANDLE hProcess,
02109                      OUT PIO_COUNTERS lpIoCounters)
02110 {
02111     NTSTATUS Status;
02112 
02113     /* Query the kernel. Structures are identical, so let it do the copy too. */
02114     Status = NtQueryInformationProcess(hProcess,
02115                                        ProcessIoCounters,
02116                                        lpIoCounters,
02117                                        sizeof(IO_COUNTERS),
02118                                        NULL);
02119     if (!NT_SUCCESS(Status))
02120     {
02121         /* Handle error path */
02122         BaseSetLastNTError(Status);
02123         return FALSE;
02124     }
02125 
02126     /* All done */
02127     return TRUE;
02128 }
02129 
02130 /*
02131  * @implemented
02132  */
02133 BOOL
02134 WINAPI
02135 GetProcessPriorityBoost(IN HANDLE hProcess,
02136                         OUT PBOOL pDisablePriorityBoost)
02137 {
02138     NTSTATUS Status;
02139     ULONG PriorityBoost;
02140 
02141     /* Query the kernel */
02142     Status = NtQueryInformationProcess(hProcess,
02143                                        ProcessPriorityBoost,
02144                                        &PriorityBoost,
02145                                        sizeof(ULONG),
02146                                        NULL);
02147     if (NT_SUCCESS(Status))
02148     {
02149         /* Convert from ULONG to a BOOL */
02150         *pDisablePriorityBoost = PriorityBoost ? TRUE : FALSE;
02151         return TRUE;
02152     }
02153 
02154     /* Handle error path */
02155     BaseSetLastNTError(Status);
02156     return FALSE;
02157 }
02158 
02159 /*
02160  * @implemented
02161  */
02162 BOOL
02163 WINAPI
02164 SetProcessPriorityBoost(IN HANDLE hProcess,
02165                         IN BOOL bDisablePriorityBoost)
02166 {
02167     NTSTATUS Status;
02168     ULONG PriorityBoost;
02169 
02170     /* Enforce that this is a BOOL, and send it to the kernel as a ULONG */
02171     PriorityBoost = (bDisablePriorityBoost ? TRUE : FALSE);
02172     Status = NtSetInformationProcess(hProcess,
02173                                      ProcessPriorityBoost,
02174                                      &PriorityBoost,
02175                                      sizeof(ULONG));
02176     if (!NT_SUCCESS(Status))
02177     {
02178         /* Handle error path */
02179         BaseSetLastNTError(Status);
02180         return FALSE;
02181     }
02182 
02183     /* All done */
02184     return TRUE;
02185 }
02186 
02187 /*
02188  * @implemented
02189  */
02190 BOOL
02191 WINAPI
02192 GetProcessHandleCount(IN HANDLE hProcess,
02193                       OUT PDWORD pdwHandleCount)
02194 {
02195     ULONG phc;
02196     NTSTATUS Status;
02197 
02198     /* Query the kernel */
02199     Status = NtQueryInformationProcess(hProcess,
02200                                        ProcessHandleCount,
02201                                        &phc,
02202                                        sizeof(ULONG),
02203                                        NULL);
02204     if (NT_SUCCESS(Status))
02205     {
02206         /* Copy the count and return sucecss */
02207         *pdwHandleCount = phc;
02208         return TRUE;
02209     }
02210 
02211     /* Handle error path */
02212     BaseSetLastNTError(Status);
02213     return FALSE;
02214 }
02215 
02216 /*
02217  * @implemented
02218  */
02219 BOOL
02220 WINAPI
02221 IsWow64Process(IN HANDLE hProcess,
02222                OUT PBOOL Wow64Process)
02223 {
02224     ULONG_PTR pbi;
02225     NTSTATUS Status;
02226 
02227     /* Query the kernel */
02228     Status = NtQueryInformationProcess(hProcess,
02229                                        ProcessWow64Information,
02230                                        &pbi,
02231                                        sizeof(pbi),
02232                                        NULL);
02233     if (!NT_SUCCESS(Status))
02234     {
02235         /* Handle error path */
02236         BaseSetLastNTError(Status);
02237         return FALSE;
02238     }
02239 
02240     /* Enforce this is a BOOL, and return success */
02241     *Wow64Process = (pbi != 0);
02242     return TRUE;
02243 }
02244 
02245 /*
02246  * @implemented
02247  */
02248 LPSTR
02249 WINAPI
02250 GetCommandLineA(VOID)
02251 {
02252     return BaseAnsiCommandLine.Buffer;
02253 }
02254 
02255 /*
02256  * @implemented
02257  */
02258 LPWSTR
02259 WINAPI
02260 GetCommandLineW(VOID)
02261 {
02262     return BaseUnicodeCommandLine.Buffer;
02263 }
02264 
02265 /*
02266  * @implemented
02267  */
02268 BOOL
02269 NTAPI
02270 ReadProcessMemory(IN HANDLE hProcess,
02271                   IN LPCVOID lpBaseAddress,
02272                   IN LPVOID lpBuffer,
02273                   IN SIZE_T nSize,
02274                   OUT SIZE_T* lpNumberOfBytesRead)
02275 {
02276     NTSTATUS Status;
02277 
02278     /* Do the read */
02279     Status = NtReadVirtualMemory(hProcess,
02280                                  (PVOID)lpBaseAddress,
02281                                  lpBuffer,
02282                                  nSize,
02283                                  &nSize);
02284 
02285     /* In user-mode, this parameter is optional */
02286     if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
02287     if (!NT_SUCCESS(Status))
02288     {
02289         /* We failed */
02290         BaseSetLastNTError(Status);
02291         return FALSE;
02292     }
02293 
02294     /* Return success */
02295     return TRUE;
02296 }
02297 
02298 /*
02299  * @implemented
02300  */
02301 BOOL
02302 NTAPI
02303 WriteProcessMemory(IN HANDLE hProcess,
02304                    IN LPVOID lpBaseAddress,
02305                    IN LPCVOID lpBuffer,
02306                    IN SIZE_T nSize,
02307                    OUT SIZE_T *lpNumberOfBytesWritten)
02308 {
02309     NTSTATUS Status;
02310     ULONG OldValue;
02311     SIZE_T RegionSize;
02312     PVOID Base;
02313     BOOLEAN UnProtect;
02314 
02315     /* Set parameters for protect call */
02316     RegionSize = nSize;
02317     Base = lpBaseAddress;
02318 
02319     /* Check the current status */
02320     Status = NtProtectVirtualMemory(hProcess,
02321                                     &Base,
02322                                     &RegionSize,
02323                                     PAGE_EXECUTE_READWRITE,
02324                                     &OldValue);
02325     if (NT_SUCCESS(Status))
02326     {
02327         /* Check if we are unprotecting */
02328         UnProtect = OldValue & (PAGE_READWRITE |
02329                                 PAGE_WRITECOPY |
02330                                 PAGE_EXECUTE_READWRITE |
02331                                 PAGE_EXECUTE_WRITECOPY) ? FALSE : TRUE;
02332         if (!UnProtect)
02333         {
02334             /* Set the new protection */
02335             Status = NtProtectVirtualMemory(hProcess,
02336                                             &Base,
02337                                             &RegionSize,
02338                                             OldValue,
02339                                             &OldValue);
02340 
02341             /* Write the memory */
02342             Status = NtWriteVirtualMemory(hProcess,
02343                                           lpBaseAddress,
02344                                           (LPVOID)lpBuffer,
02345                                           nSize,
02346                                           &nSize);
02347 
02348             /* In Win32, the parameter is optional, so handle this case */
02349             if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
02350 
02351             if (!NT_SUCCESS(Status))
02352             {
02353                 /* We failed */
02354                 BaseSetLastNTError(Status);
02355                 return FALSE;
02356             }
02357 
02358             /* Flush the ITLB */
02359             NtFlushInstructionCache(hProcess, lpBaseAddress, nSize);
02360             return TRUE;
02361         }
02362         else
02363         {
02364             /* Check if we were read only */
02365             if (OldValue & (PAGE_NOACCESS | PAGE_READONLY))
02366             {
02367                 /* Restore protection and fail */
02368                 NtProtectVirtualMemory(hProcess,
02369                                        &Base,
02370                                        &RegionSize,
02371                                        OldValue,
02372                                        &OldValue);
02373                 BaseSetLastNTError(STATUS_ACCESS_VIOLATION);
02374 
02375                 /* Note: This is what Windows returns and code depends on it */
02376                 return STATUS_ACCESS_VIOLATION;
02377             }
02378 
02379             /* Otherwise, do the write */
02380             Status = NtWriteVirtualMemory(hProcess,
02381                                           lpBaseAddress,
02382                                           (LPVOID)lpBuffer,
02383                                           nSize,
02384                                           &nSize);
02385 
02386             /* In Win32, the parameter is optional, so handle this case */
02387             if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
02388 
02389             /* And restore the protection */
02390             NtProtectVirtualMemory(hProcess,
02391                                    &Base,
02392                                    &RegionSize,
02393                                    OldValue,
02394                                    &OldValue);
02395             if (!NT_SUCCESS(Status))
02396             {
02397                 /* We failed */
02398                 BaseSetLastNTError(STATUS_ACCESS_VIOLATION);
02399 
02400                 /* Note: This is what Windows returns and code depends on it */
02401                 return STATUS_ACCESS_VIOLATION;
02402             }
02403 
02404             /* Flush the ITLB */
02405             NtFlushInstructionCache(hProcess, lpBaseAddress, nSize);
02406             return TRUE;
02407         }
02408     }
02409     else
02410     {
02411         /* We failed */
02412         BaseSetLastNTError(Status);
02413         return FALSE;
02414     }
02415 }
02416 
02417 /*
02418  * @implemented
02419  */
02420 BOOL
02421 WINAPI
02422 ProcessIdToSessionId(IN DWORD dwProcessId,
02423                      OUT PDWORD pSessionId)
02424 {
02425     PROCESS_SESSION_INFORMATION SessionInformation;
02426     OBJECT_ATTRIBUTES ObjectAttributes;
02427     CLIENT_ID ClientId;
02428     HANDLE ProcessHandle;
02429     NTSTATUS Status;
02430 
02431     /* Do a quick check if the pointer is not writable */
02432     if (IsBadWritePtr(pSessionId, sizeof(DWORD)))
02433     {
02434         /* Fail fast */
02435         SetLastError(ERROR_INVALID_PARAMETER);
02436         return FALSE;
02437     }
02438 
02439     /* Open the process passed in by ID */
02440     ClientId.UniqueProcess = UlongToHandle(dwProcessId);
02441     ClientId.UniqueThread = 0;
02442     InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
02443     Status = NtOpenProcess(&ProcessHandle,
02444                            PROCESS_QUERY_INFORMATION,
02445                            &ObjectAttributes,
02446                            &ClientId);
02447     if (NT_SUCCESS(Status))
02448     {
02449         /* Query the session ID from the kernel */
02450         Status = NtQueryInformationProcess(ProcessHandle,
02451                                            ProcessSessionInformation,
02452                                            &SessionInformation,
02453                                            sizeof(SessionInformation),
02454                                            NULL);
02455 
02456         /* Close the handle and check if we suceeded */
02457         NtClose(ProcessHandle);
02458         if (NT_SUCCESS(Status))
02459         {
02460             /* Return the session ID */
02461             *pSessionId = SessionInformation.SessionId;
02462             return TRUE;
02463         }
02464     }
02465 
02466     /* Set error code and fail */
02467     BaseSetLastNTError(Status);
02468     return FALSE;
02469 }
02470 
02471 /*
02472  * @implemented
02473  */
02474 BOOL
02475 WINAPI
02476 CreateProcessInternalW(HANDLE hToken,
02477                        LPCWSTR lpApplicationName,
02478                        LPWSTR lpCommandLine,
02479                        LPSECURITY_ATTRIBUTES lpProcessAttributes,
02480                        LPSECURITY_ATTRIBUTES lpThreadAttributes,
02481                        BOOL bInheritHandles,
02482                        DWORD dwCreationFlags,
02483                        LPVOID lpEnvironment,
02484                        LPCWSTR lpCurrentDirectory,
02485                        LPSTARTUPINFOW lpStartupInfo,
02486                        LPPROCESS_INFORMATION lpProcessInformation,
02487                        PHANDLE hNewToken)
02488 {
02489     NTSTATUS Status;
02490     PROCESS_PRIORITY_CLASS PriorityClass;
02491     BOOLEAN FoundQuotes = FALSE;
02492     BOOLEAN QuotesNeeded = FALSE;
02493     BOOLEAN CmdLineIsAppName = FALSE;
02494     UNICODE_STRING ApplicationName = { 0, 0, NULL };
02495     OBJECT_ATTRIBUTES LocalObjectAttributes;
02496     POBJECT_ATTRIBUTES ObjectAttributes;
02497     HANDLE hSection = NULL, hProcess = NULL, hThread = NULL, hDebug = NULL;
02498     SECTION_IMAGE_INFORMATION SectionImageInfo;
02499     LPWSTR CurrentDirectory = NULL;
02500     LPWSTR CurrentDirectoryPart;
02501     PROCESS_BASIC_INFORMATION ProcessBasicInfo;
02502     STARTUPINFOW StartupInfo;
02503     ULONG Dummy;
02504     LPWSTR BatchCommandLine;
02505     ULONG CmdLineLength;
02506     UNICODE_STRING CommandLineString;
02507     PWCHAR Extension;
02508     LPWSTR QuotedCmdLine = NULL;
02509     LPWSTR ScanString;
02510     LPWSTR NullBuffer = NULL;
02511     LPWSTR NameBuffer = NULL;
02512     WCHAR SaveChar = 0;
02513     ULONG RetVal;
02514     UINT Error = 0;
02515     BOOLEAN SearchDone = FALSE;
02516     BOOLEAN Escape = FALSE;
02517     CLIENT_ID ClientId;
02518     PPEB OurPeb = NtCurrentPeb();
02519     PPEB RemotePeb;
02520     SIZE_T EnvSize = 0;
02521     BOOL Ret = FALSE;
02522 
02523     /* FIXME should process
02524      * HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
02525      * key (see http://blogs.msdn.com/oldnewthing/archive/2005/12/19/505449.aspx)
02526      */
02527 
02528     DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S"
02529            " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n",
02530            lpApplicationName, lpCommandLine, lpEnvironment, lpCurrentDirectory,
02531            dwCreationFlags);
02532 
02533     /* Flags we don't handle yet */
02534     if (dwCreationFlags & CREATE_SEPARATE_WOW_VDM)
02535     {
02536         DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n");
02537     }
02538     if (dwCreationFlags & CREATE_SHARED_WOW_VDM)
02539     {
02540         DPRINT1("CREATE_SHARED_WOW_VDM not handled\n");
02541     }
02542     if (dwCreationFlags & CREATE_FORCEDOS)
02543     {
02544         DPRINT1("CREATE_FORCEDOS not handled\n");
02545     }
02546 
02547     /* Fail on this flag, it's only valid with the WithLogonW function */
02548     if (dwCreationFlags & CREATE_PRESERVE_CODE_AUTHZ_LEVEL)
02549     {
02550         DPRINT1("Invalid flag used\n");
02551         SetLastError(ERROR_INVALID_PARAMETER);
02552         return FALSE;
02553     }
02554 
02555     /* This combination is illegal (see MSDN) */
02556     if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) ==
02557         (DETACHED_PROCESS | CREATE_NEW_CONSOLE))
02558     {
02559         DPRINT1("Invalid flag combo used\n");
02560         SetLastError(ERROR_INVALID_PARAMETER);
02561         return FALSE;
02562     }
02563 
02564     /* Another illegal combo */
02565     if ((dwCreationFlags & (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM)) ==
02566         (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM))
02567     {
02568         DPRINT1("Invalid flag combo used\n");
02569         SetLastError(ERROR_INVALID_PARAMETER);
02570         return FALSE;
02571     }
02572 
02573     if (lpCurrentDirectory)
02574     {
02575         if ((GetFileAttributesW(lpCurrentDirectory) == INVALID_FILE_ATTRIBUTES) ||
02576             !(GetFileAttributesW(lpCurrentDirectory) & FILE_ATTRIBUTE_DIRECTORY))
02577         {
02578             SetLastError(ERROR_DIRECTORY);
02579             return FALSE;
02580         }
02581     }
02582 
02583     /*
02584      * We're going to modify and mask out flags and stuff in lpStartupInfo,
02585      * so we'll use our own local copy for that.
02586      */
02587     StartupInfo = *lpStartupInfo;
02588 
02589     /* FIXME: Use default Separate/Shared VDM Flag */
02590 
02591     /* If we are inside a Job, use Separate VDM so it won't escape the Job */
02592     if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM))
02593     {
02594         if (NtIsProcessInJob(NtCurrentProcess(), NULL))
02595         {
02596             /* Remove the shared flag and add the separate flag. */
02597             dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) |
02598                                                   CREATE_SEPARATE_WOW_VDM;
02599         }
02600     }
02601 
02602     /*
02603      * According to some sites, ShellExecuteEx uses an undocumented flag to
02604      * send private handle data (such as HMONITOR or HICON). See:
02605      * www.catch22.net/tuts/undoc01.asp. This implies that we can't use the
02606      * standard handles anymore since we'd be overwriting this private data
02607      */
02608     if ((StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
02609         (StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_SHELLPRIVATE)))
02610     {
02611         StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES;
02612     }
02613 
02614     /* Start by zeroing out the fields */
02615     RtlZeroMemory(lpProcessInformation, sizeof(PROCESS_INFORMATION));
02616 
02617     /* Easy stuff first, convert the process priority class */
02618     PriorityClass.Foreground = FALSE;
02619     PriorityClass.PriorityClass = (UCHAR)BasepConvertPriorityClass(dwCreationFlags);
02620 
02621     if (lpCommandLine)
02622     {
02623         /* Search for escape sequences */
02624         ScanString = lpCommandLine;
02625         while (NULL != (ScanString = wcschr(ScanString, L'^')))
02626         {
02627             ScanString++;
02628             if (*ScanString == L'\"' || *ScanString == L'^' || *ScanString == L'\"')
02629             {
02630                 Escape = TRUE;
02631                 break;
02632             }
02633         }
02634     }
02635 
02636     /* Get the application name and do all the proper formating necessary */
02637 GetAppName:
02638     /* See if we have an application name (oh please let us have one!) */
02639     if (!lpApplicationName)
02640     {
02641         /* The fun begins */
02642         NameBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
02643                                      0,
02644                                      MAX_PATH * sizeof(WCHAR));
02645         if (NameBuffer == NULL)
02646         {
02647             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
02648             goto Cleanup;
02649         }
02650 
02651         /* This is all we have to work with :( */
02652         lpApplicationName = lpCommandLine;
02653 
02654         /* Initialize our friends at the beginning */
02655         NullBuffer = (LPWSTR)lpApplicationName;
02656         ScanString = (LPWSTR)lpApplicationName;
02657 
02658         /* We will start by looking for a quote */
02659         if (*ScanString == L'\"')
02660         {
02661              /* That was quick */
02662              SearchDone = TRUE;
02663 
02664              /* Advance past quote */
02665              ScanString++;
02666              lpApplicationName = ScanString;
02667 
02668              /* Find the closing quote */
02669              while (*ScanString)
02670              {
02671                  if (*ScanString == L'\"' && *(ScanString - 1) != L'^')
02672                  {
02673                      /* Found it */
02674                      NullBuffer = ScanString;
02675                      FoundQuotes = TRUE;
02676                      break;
02677                  }
02678 
02679                  /* Keep looking */
02680                  ScanString++;
02681                  NullBuffer = ScanString;
02682              }
02683         }
02684         else
02685         {
02686             /* No quotes, so we'll be looking for white space */
02687         WhiteScan:
02688             /* Reset the pointer */
02689             lpApplicationName = lpCommandLine;
02690 
02691             /* Find whitespace of Tab */
02692             while (*ScanString)
02693             {
02694                 if (*ScanString == ' ' || *ScanString == '\t')
02695                 {
02696                     /* Found it */
02697                     NullBuffer = ScanString;
02698                     break;
02699                 }
02700 
02701                 /* Keep looking */
02702                 ScanString++;
02703                 NullBuffer = ScanString;
02704             }
02705         }
02706 
02707         /* Set the Null Buffer */
02708         SaveChar = *NullBuffer;
02709         *NullBuffer = UNICODE_NULL;
02710 
02711         /* Do a search for the file */
02712         DPRINT("Ready for SearchPathW: %S\n", lpApplicationName);
02713         RetVal = SearchPathW(NULL,
02714                              lpApplicationName,
02715                              L".exe",
02716                              MAX_PATH,
02717                              NameBuffer,
02718                              NULL) * sizeof(WCHAR);
02719 
02720         /* Did it find something? */
02721         if (RetVal)
02722         {
02723             /* Get file attributes */
02724             ULONG Attributes = GetFileAttributesW(NameBuffer);
02725             if (Attributes & FILE_ATTRIBUTE_DIRECTORY)
02726             {
02727                 /* Give it a length of 0 to fail, this was a directory. */
02728                 RetVal = 0;
02729             }
02730             else
02731             {
02732                 /* It's a file! */
02733                 RetVal += sizeof(WCHAR);
02734             }
02735         }
02736 
02737         /* Now check if we have a file, and if the path size is OK */
02738         if (!RetVal || RetVal >= (MAX_PATH * sizeof(WCHAR)))
02739         {
02740             ULONG PathType;
02741             HANDLE hFile;
02742 
02743             /* We failed, try to get the Path Type */
02744             DPRINT("SearchPathW failed. Retval: %ld\n", RetVal);
02745             PathType = RtlDetermineDosPathNameType_U(lpApplicationName);
02746 
02747             /* If it's not relative, try to get the error */
02748             if (PathType != RtlPathTypeRelative)
02749             {
02750                 /* This should fail, and give us a detailed LastError */
02751                 hFile = CreateFileW(lpApplicationName,
02752                                     GENERIC_READ,
02753                                     FILE_SHARE_READ | FILE_SHARE_WRITE,
02754                                     NULL,
02755                                     OPEN_EXISTING,
02756                                     FILE_ATTRIBUTE_NORMAL,
02757                                     NULL);
02758 
02759                 /* Did it actually NOT fail? */
02760                 if (hFile != INVALID_HANDLE_VALUE)
02761                 {
02762                     /* Fake the error */
02763                     CloseHandle(hFile);
02764                     BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
02765                 }
02766             }
02767             else
02768             {
02769                 /* Immediately set the error */
02770                 BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
02771             }
02772 
02773             /* Did we already fail once? */
02774             if (Error)
02775             {
02776                 SetLastError(Error);
02777             }
02778             else
02779             {
02780                 /* Not yet, cache it */
02781                 Error = GetLastError();
02782             }
02783 
02784             /* Put back the command line */
02785             *NullBuffer = SaveChar;
02786             lpApplicationName = NameBuffer;
02787 
02788             /*
02789              * If the search isn't done and we still have cmdline
02790              * then start over. Ex: c:\ha ha ha\haha.exe
02791              */
02792             if (*ScanString && !SearchDone)
02793             {
02794                 /* Move in the buffer */
02795                 ScanString++;
02796                 NullBuffer = ScanString;
02797 
02798                 /* We will have to add a quote, since there is a space*/
02799                 QuotesNeeded = TRUE;
02800 
02801                 /* And we will also fake the fact we found one */
02802                 FoundQuotes = TRUE;
02803 
02804                 /* Start over */
02805                 goto WhiteScan;
02806             }
02807 
02808             /* We totally failed */
02809             goto Cleanup;
02810         }
02811 
02812         /* Put back the command line */
02813         *NullBuffer = SaveChar;
02814         lpApplicationName = NameBuffer;
02815         DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal, NameBuffer);
02816     }
02817     else if (!lpCommandLine || *lpCommandLine == UNICODE_NULL)
02818     {
02819         /* We have an app name (good!) but no command line */
02820         CmdLineIsAppName = TRUE;
02821         lpCommandLine = (LPWSTR)lpApplicationName;
02822     }
02823 
02824     /* At this point the name has been toyed with enough to be openable */
02825     Status = BasepMapFile(lpApplicationName, &hSection, &ApplicationName);
02826 
02827     /* Check for failure */
02828     if (!NT_SUCCESS(Status))
02829     {
02830         /* Could be a non-PE File */
02831         switch (Status)
02832         {
02833             /* Check if the Kernel tells us it's not even valid MZ */
02834             case STATUS_INVALID_IMAGE_NE_FORMAT:
02835             case STATUS_INVALID_IMAGE_PROTECT:
02836             case STATUS_INVALID_IMAGE_NOT_MZ:
02837 
02838 #if 0
02839             /* If it's a DOS app, use VDM */
02840             if ((BasepCheckDosApp(&ApplicationName)))
02841             {
02842                 DPRINT1("Launching VDM...\n");
02843                 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
02844                 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
02845                 return CreateProcessW(L"ntvdm.exe",
02846                                       (LPWSTR)((ULONG_PTR)lpApplicationName), /* FIXME: Buffer must be writable!!! */
02847                                       lpProcessAttributes,
02848                                       lpThreadAttributes,
02849                                       bInheritHandles,
02850                                       dwCreationFlags,
02851                                       lpEnvironment,
02852                                       lpCurrentDirectory,
02853                                       &StartupInfo,
02854                                       lpProcessInformation);
02855             }
02856 #endif
02857             /* It's a batch file */
02858             Extension = &ApplicationName.Buffer[ApplicationName.Length /
02859                                                 sizeof(WCHAR) - 4];
02860 
02861             /* Make sure the extensions are correct */
02862             if (_wcsnicmp(Extension, L".bat", 4) && _wcsnicmp(Extension, L".cmd", 4))
02863             {
02864                 SetLastError(ERROR_BAD_EXE_FORMAT);
02865                 return FALSE;
02866             }
02867 
02868             /* Calculate the length of the command line */
02869             CmdLineLength = wcslen(CMD_STRING) + wcslen(lpCommandLine) + 1;
02870 
02871             /* If we found quotes, then add them into the length size */
02872             if (CmdLineIsAppName || FoundQuotes) CmdLineLength += 2;
02873             CmdLineLength *= sizeof(WCHAR);
02874 
02875             /* Allocate space for the new command line */
02876             BatchCommandLine = RtlAllocateHeap(RtlGetProcessHeap(),
02877                                                0,
02878                                                CmdLineLength);
02879             if (BatchCommandLine == NULL)
02880             {
02881                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
02882                 goto Cleanup;
02883             }
02884 
02885             /* Build it */
02886             wcscpy(BatchCommandLine, CMD_STRING);
02887             if (CmdLineIsAppName || FoundQuotes)
02888             {
02889                 wcscat(BatchCommandLine, L"\"");
02890             }
02891             wcscat(BatchCommandLine, lpCommandLine);
02892             if (CmdLineIsAppName || FoundQuotes)
02893             {
02894                 wcscat(BatchCommandLine, L"\"");
02895             }
02896 
02897             /* Create it as a Unicode String */
02898             RtlInitUnicodeString(&CommandLineString, BatchCommandLine);
02899 
02900             /* Set the command line to this */
02901             lpCommandLine = CommandLineString.Buffer;
02902             lpApplicationName = NULL;
02903 
02904             /* Free memory */
02905             RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
02906             ApplicationName.Buffer = NULL;
02907             goto GetAppName;
02908             break;
02909 
02910             case STATUS_INVALID_IMAGE_WIN_16:
02911 
02912                 /* It's a Win16 Image, use VDM */
02913                 DPRINT1("Launching VDM...\n");
02914                 RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
02915                 RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
02916                 return CreateProcessW(L"ntvdm.exe",
02917                                       (LPWSTR)((ULONG_PTR)lpApplicationName), /* FIXME: Buffer must be writable!!! */
02918                                       lpProcessAttributes,
02919                                       lpThreadAttributes,
02920                                       bInheritHandles,
02921                                       dwCreationFlags,
02922                                       lpEnvironment,
02923                                       lpCurrentDirectory,
02924                                       &StartupInfo,
02925                                       lpProcessInformation);
02926 
02927             case STATUS_OBJECT_NAME_NOT_FOUND:
02928             case STATUS_OBJECT_PATH_NOT_FOUND:
02929                 BaseSetLastNTError(Status);
02930                 goto Cleanup;
02931 
02932             default:
02933                 /* Invalid Image Type */
02934                 SetLastError(ERROR_BAD_EXE_FORMAT);
02935                 goto Cleanup;
02936         }
02937     }
02938 
02939     /* Use our desktop if we didn't get any */
02940     if (!StartupInfo.lpDesktop)
02941     {
02942         StartupInfo.lpDesktop = OurPeb->ProcessParameters->DesktopInfo.Buffer;
02943     }
02944 
02945     /* FIXME: Check if Application is allowed to run */
02946 
02947     /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */
02948 
02949     /* Get some information about the executable */
02950     Status = NtQuerySection(hSection,
02951                             SectionImageInformation,
02952                             &SectionImageInfo,
02953                             sizeof(SectionImageInfo),
02954                             NULL);
02955     if(!NT_SUCCESS(Status))
02956     {
02957         DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status);
02958         BaseSetLastNTError(Status);
02959         goto Cleanup;
02960     }
02961 
02962     /* Don't execute DLLs */
02963     if (SectionImageInfo.ImageCharacteristics & IMAGE_FILE_DLL)
02964     {
02965         DPRINT1("Can't execute a DLL\n");
02966         SetLastError(ERROR_BAD_EXE_FORMAT);
02967         goto Cleanup;
02968     }
02969 
02970     /* FIXME: Check for Debugger */
02971 
02972     /* FIXME: Check if Machine Type and SubSys Version Match */
02973 
02974     /* We don't support POSIX or anything else for now */
02975     if (IMAGE_SUBSYSTEM_WINDOWS_GUI != SectionImageInfo.SubSystemType &&
02976         IMAGE_SUBSYSTEM_WINDOWS_CUI != SectionImageInfo.SubSystemType)
02977     {
02978         DPRINT1("Invalid subsystem %d\n", SectionImageInfo.SubSystemType);
02979         SetLastError(ERROR_BAD_EXE_FORMAT);
02980         goto Cleanup;
02981     }
02982 
02983     if (IMAGE_SUBSYSTEM_WINDOWS_GUI == SectionImageInfo.SubSystemType)
02984     {
02985         /* Do not create a console for GUI applications */
02986         dwCreationFlags &= ~CREATE_NEW_CONSOLE;
02987         dwCreationFlags |= DETACHED_PROCESS;
02988     }
02989 
02990     /* Initialize the process object attributes */
02991     ObjectAttributes = BaseFormatObjectAttributes(&LocalObjectAttributes,
02992                                                     lpProcessAttributes,
02993                                                     NULL);
02994 
02995     /* Check if we're going to be debugged */
02996     if (dwCreationFlags & DEBUG_PROCESS)
02997     {
02998         /* FIXME: Set process flag */
02999     }
03000 
03001     /* Check if we're going to be debugged */
03002     if (dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
03003     {
03004         /* Connect to DbgUi */
03005         Status = DbgUiConnectToDbg();
03006         if (!NT_SUCCESS(Status))
03007         {
03008             DPRINT1("Failed to connect to DbgUI!\n");
03009             BaseSetLastNTError(Status);
03010             goto Cleanup;
03011         }
03012 
03013         /* Get the debug object */
03014         hDebug = DbgUiGetThreadDebugObject();
03015 
03016         /* Check if only this process will be debugged */
03017         if (dwCreationFlags & DEBUG_ONLY_THIS_PROCESS)
03018         {
03019             /* Set process flag */
03020             hDebug = (HANDLE)((ULONG_PTR)hDebug | 0x1);
03021         }
03022     }
03023 
03024     /* Create the Process */
03025     Status = NtCreateProcess(&hProcess,
03026                              PROCESS_ALL_ACCESS,
03027                              ObjectAttributes,
03028                              NtCurrentProcess(),
03029                              (BOOLEAN)bInheritHandles,
03030                              hSection,
03031                              hDebug,
03032                              NULL);
03033     if (!NT_SUCCESS(Status))
03034     {
03035         DPRINT1("Unable to create process, status 0x%x\n", Status);
03036         BaseSetLastNTError(Status);
03037         goto Cleanup;
03038     }
03039 
03040     if (PriorityClass.PriorityClass != PROCESS_PRIORITY_CLASS_INVALID)
03041     {
03042         /* Set new class */
03043         Status = NtSetInformationProcess(hProcess,
03044                                          ProcessPriorityClass,
03045                                          &PriorityClass,
03046                                          sizeof(PROCESS_PRIORITY_CLASS));
03047         if(!NT_SUCCESS(Status))
03048         {
03049             DPRINT1("Unable to set new process priority, status 0x%x\n", Status);
03050             BaseSetLastNTError(Status);
03051             goto Cleanup;
03052         }
03053     }
03054 
03055     /* Set Error Mode */
03056     if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
03057     {
03058         ULONG ErrorMode = SEM_FAILCRITICALERRORS;
03059         NtSetInformationProcess(hProcess,
03060                                 ProcessDefaultHardErrorMode,
03061                                 &ErrorMode,
03062                                 sizeof(ULONG));
03063     }
03064 
03065     /* Convert the directory to a full path */
03066     if (lpCurrentDirectory)
03067     {
03068         /* Allocate a buffer */
03069         CurrentDirectory = RtlAllocateHeap(RtlGetProcessHeap(),
03070                                            0,
03071                                            (MAX_PATH + 1) * sizeof(WCHAR));
03072         if (CurrentDirectory == NULL)
03073         {
03074             DPRINT1("Cannot allocate memory for directory name\n");
03075             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
03076             goto Cleanup;
03077         }
03078 
03079         /* Get the length */
03080         if (GetFullPathNameW(lpCurrentDirectory,
03081                              MAX_PATH,
03082                              CurrentDirectory,
03083                              &CurrentDirectoryPart) > MAX_PATH)
03084         {
03085             DPRINT1("Directory name too long\n");
03086             SetLastError(ERROR_DIRECTORY);
03087             goto Cleanup;
03088         }
03089     }
03090 
03091     /* Insert quotes if needed */
03092     if (QuotesNeeded || CmdLineIsAppName)
03093     {
03094         /* Allocate a buffer */
03095         QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
03096                                         0,
03097                                         (wcslen(lpCommandLine) + 2 + 1) *
03098                                         sizeof(WCHAR));
03099         if (QuotedCmdLine == NULL)
03100         {
03101             DPRINT1("Cannot allocate memory for quoted command line\n");
03102             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
03103             goto Cleanup;
03104         }
03105 
03106         /* Copy the first quote */
03107         wcscpy(QuotedCmdLine, L"\"");
03108 
03109         /* Save a null char */
03110         if (QuotesNeeded)
03111         {
03112             SaveChar = *NullBuffer;
03113             *NullBuffer = UNICODE_NULL;
03114         }
03115 
03116         /* Add the command line and the finishing quote */
03117         wcscat(QuotedCmdLine, lpCommandLine);
03118         wcscat(QuotedCmdLine, L"\"");
03119 
03120         /* Add the null char */
03121         if (QuotesNeeded)
03122         {
03123             *NullBuffer = SaveChar;
03124             wcscat(QuotedCmdLine, NullBuffer);
03125         }
03126 
03127         DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine);
03128     }
03129 
03130     if (Escape)
03131     {
03132         if (QuotedCmdLine == NULL)
03133         {
03134             QuotedCmdLine = RtlAllocateHeap(RtlGetProcessHeap(),
03135                                             0,
03136                                             (wcslen(lpCommandLine) + 1) * sizeof(WCHAR));
03137             if (QuotedCmdLine == NULL)
03138             {
03139                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
03140                 goto Cleanup;
03141             }
03142             wcscpy(QuotedCmdLine, lpCommandLine);
03143         }
03144 
03145         ScanString = QuotedCmdLine;
03146         while (NULL != (ScanString = wcschr(ScanString, L'^')))
03147         {
03148             ScanString++;
03149             if (*ScanString == L'\"' || *ScanString == L'^' || *ScanString == L'\\')
03150             {
03151                 memmove(ScanString-1, ScanString, wcslen(ScanString) * sizeof(WCHAR) + sizeof(WCHAR));
03152             }
03153         }
03154     }
03155 
03156     /* Get the Process Information */
03157     Status = NtQueryInformationProcess(hProcess,
03158                                        ProcessBasicInformation,
03159                                        &ProcessBasicInfo,
03160                                        sizeof(ProcessBasicInfo),
03161                                        NULL);
03162 
03163     /* Convert the environment */
03164     if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
03165     {
03166         lpEnvironment = BasepConvertUnicodeEnvironment(&EnvSize, lpEnvironment);
03167         if (!lpEnvironment) goto Cleanup;
03168     }
03169 
03170     /* Create Process Environment */
03171     RemotePeb = ProcessBasicInfo.PebBaseAddress;
03172     Ret = BasePushProcessParameters(0,
03173                                     hProcess,
03174                                     RemotePeb,
03175                                     (LPWSTR)lpApplicationName,
03176                                     CurrentDirectory,
03177                                     (QuotesNeeded || CmdLineIsAppName || Escape) ?
03178                                     QuotedCmdLine : lpCommandLine,
03179                                     lpEnvironment,
03180                                     &StartupInfo,
03181                                     dwCreationFlags,
03182                                     bInheritHandles,
03183                                     0,
03184                                     NULL,
03185                                     0);
03186     if (!Ret) goto Cleanup;
03187 
03188     /* Cleanup Environment */
03189     if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT))
03190     {
03191         RtlDestroyEnvironment(lpEnvironment);
03192     }
03193 
03194     /* Close the section */
03195     NtClose(hSection);
03196     hSection = NULL;
03197 
03198     /* Duplicate the handles if needed */
03199     if (!bInheritHandles && !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
03200         SectionImageInfo.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI)
03201     {
03202         PRTL_USER_PROCESS_PARAMETERS RemoteParameters;
03203 
03204         /* Get the remote parameters */
03205         Status = NtReadVirtualMemory(hProcess,
03206                                      &RemotePeb->ProcessParameters,
03207                                      &RemoteParameters,
03208                                      sizeof(PVOID),
03209                                      NULL);
03210         if (!NT_SUCCESS(Status))
03211         {
03212             DPRINT1("Failed to read memory\n");
03213             goto Cleanup;
03214         }
03215 
03216         /* Duplicate and write the handles */
03217         BasepDuplicateAndWriteHandle(hProcess,
03218                                      OurPeb->ProcessParameters->StandardInput,
03219                                      &RemoteParameters->StandardInput);
03220         BasepDuplicateAndWriteHandle(hProcess,
03221                                      OurPeb->ProcessParameters->StandardOutput,
03222                                      &RemoteParameters->StandardOutput);
03223         BasepDuplicateAndWriteHandle(hProcess,
03224                                      OurPeb->ProcessParameters->StandardError,
03225                                      &RemoteParameters->StandardError);
03226     }
03227 
03228     /* Create the first thread */
03229     DPRINT("Creating thread for process (EntryPoint = 0x%p)\n",
03230             SectionImageInfo.TransferAddress);
03231     hThread = BasepCreateFirstThread(hProcess,
03232                                      lpThreadAttributes,
03233                                      &SectionImageInfo,
03234                                      &ClientId,
03235                                      bInheritHandles,
03236                                      dwCreationFlags);
03237 
03238     if (hThread == NULL)
03239     {
03240         DPRINT1("Could not create Initial Thread\n");
03241         /* FIXME - set last error code */
03242         goto Cleanup;
03243     }
03244 
03245     if (!(dwCreationFlags & CREATE_SUSPENDED))
03246     {
03247         NtResumeThread(hThread, &Dummy);
03248     }
03249 
03250     /* Return Data */
03251     lpProcessInformation->dwProcessId = (DWORD)ClientId.UniqueProcess;
03252     lpProcessInformation->dwThreadId = (DWORD)ClientId.UniqueThread;
03253     lpProcessInformation->hProcess = hProcess;
03254     lpProcessInformation->hThread = hThread;
03255     DPRINT("hThread[%p]: %p inside hProcess[%p]: %p\n", hThread,
03256             ClientId.UniqueThread, ClientId.UniqueProcess, hProcess);
03257     hProcess = hThread = NULL;
03258     Ret = TRUE;
03259 
03260 Cleanup:
03261     /* De-allocate heap strings */
03262     if (NameBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, NameBuffer);
03263     if (ApplicationName.Buffer)
03264         RtlFreeHeap(RtlGetProcessHeap(), 0, ApplicationName.Buffer);
03265     if (CurrentDirectory) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDirectory);
03266     if (QuotedCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, QuotedCmdLine);
03267 
03268     /* Kill any handles still alive */
03269     if (hSection) NtClose(hSection);
03270     if (hThread)
03271     {
03272         /* We don't know any more details then this */
03273         NtTerminateProcess(hProcess, STATUS_UNSUCCESSFUL);
03274         NtClose(hThread);
03275     }
03276     if (hProcess) NtClose(hProcess);
03277 
03278     /* Return Success */
03279     return Ret;
03280 }
03281 
03282 /*
03283  * @implemented
03284  */
03285 BOOL
03286 WINAPI
03287 CreateProcessW(LPCWSTR lpApplicationName,
03288                LPWSTR lpCommandLine,
03289                LPSECURITY_ATTRIBUTES lpProcessAttributes,
03290                LPSECURITY_ATTRIBUTES lpThreadAttributes,
03291                BOOL bInheritHandles,
03292                DWORD dwCreationFlags,
03293                LPVOID lpEnvironment,
03294                LPCWSTR lpCurrentDirectory,
03295                LPSTARTUPINFOW lpStartupInfo,
03296                LPPROCESS_INFORMATION lpProcessInformation)
03297 {
03298     /* Call the internal (but exported) version */
03299     return CreateProcessInternalW(0,
03300                                   lpApplicationName,
03301                                   lpCommandLine,
03302                                   lpProcessAttributes,
03303                                   lpThreadAttributes,
03304                                   bInheritHandles,
03305                                   dwCreationFlags,
03306                                   lpEnvironment,
03307                                   lpCurrentDirectory,
03308                                   lpStartupInfo,
03309                                   lpProcessInformation,
03310                                   NULL);
03311 }
03312 
03313 /*
03314  * @implemented
03315  */
03316 BOOL
03317 WINAPI
03318 CreateProcessInternalA(HANDLE hToken,
03319                        LPCSTR lpApplicationName,
03320                        LPSTR lpCommandLine,
03321                        LPSECURITY_ATTRIBUTES lpProcessAttributes,
03322                        LPSECURITY_ATTRIBUTES lpThreadAttributes,
03323                        BOOL bInheritHandles,
03324                        DWORD dwCreationFlags,
03325                        LPVOID lpEnvironment,
03326                        LPCSTR lpCurrentDirectory,
03327                        LPSTARTUPINFOA lpStartupInfo,
03328                        LPPROCESS_INFORMATION lpProcessInformation,
03329                        PHANDLE hNewToken)
03330 {
03331     PUNICODE_STRING CommandLine = NULL;
03332     UNICODE_STRING DummyString;
03333     UNICODE_STRING LiveCommandLine;
03334     UNICODE_STRING ApplicationName;
03335     UNICODE_STRING CurrentDirectory;
03336     BOOL bRetVal;
03337     STARTUPINFOW StartupInfo;
03338 
03339     DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, "
03340             "lpStartupInfo %x, lpProcessInformation %x\n",
03341             dwCreationFlags, lpEnvironment, lpCurrentDirectory,
03342             lpStartupInfo, lpProcessInformation);
03343 
03344     /* Copy Startup Info */
03345     RtlMoveMemory(&StartupInfo, lpStartupInfo, sizeof(*lpStartupInfo));
03346 
03347     /* Initialize all strings to nothing */
03348     LiveCommandLine.Buffer = NULL;
03349     DummyString.Buffer = NULL;
03350     ApplicationName.Buffer = NULL;
03351     CurrentDirectory.Buffer = NULL;
03352     StartupInfo.lpDesktop = NULL;
03353     StartupInfo.lpReserved = NULL;
03354     StartupInfo.lpTitle = NULL;
03355 
03356     /* Convert the Command line */
03357     if (lpCommandLine)
03358     {
03359         /* If it's too long, then we'll have a problem */
03360         if ((strlen(lpCommandLine) + 1) * sizeof(WCHAR) <
03361             NtCurrentTeb()->StaticUnicodeString.MaximumLength)
03362         {
03363             /* Cache it in the TEB */
03364             CommandLine = Basep8BitStringToStaticUnicodeString(lpCommandLine);
03365         }
03366         else
03367         {
03368             /* Use a dynamic version */
03369             Basep8BitStringToDynamicUnicodeString(&LiveCommandLine,
03370                                                   lpCommandLine);
03371         }
03372     }
03373     else
03374     {
03375         /* The logic below will use CommandLine, so we must make it valid */
03376         CommandLine = &DummyString;
03377     }
03378 
03379     /* Convert the Name and Directory */
03380     if (lpApplicationName)
03381     {
03382         Basep8BitStringToDynamicUnicodeString(&ApplicationName,
03383                                               lpApplicationName);
03384     }
03385     if (lpCurrentDirectory)
03386     {
03387         Basep8BitStringToDynamicUnicodeString(&CurrentDirectory,
03388                                               lpCurrentDirectory);
03389     }
03390 
03391     /* Now convert Startup Strings */
03392     if (lpStartupInfo->lpReserved)
03393     {
03394         BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpReserved,
03395                                            &StartupInfo.lpReserved);
03396     }
03397     if (lpStartupInfo->lpDesktop)
03398     {
03399         BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpDesktop,
03400                                            &StartupInfo.lpDesktop);
03401     }
03402     if (lpStartupInfo->lpTitle)
03403     {
03404         BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpTitle,
03405                                            &StartupInfo.lpTitle);
03406     }
03407 
03408     /* Call the Unicode function */
03409     bRetVal = CreateProcessInternalW(hToken,
03410                                      ApplicationName.Buffer,
03411                                      LiveCommandLine.Buffer ?
03412                                      LiveCommandLine.Buffer : CommandLine->Buffer,
03413                                      lpProcessAttributes,
03414                                      lpThreadAttributes,
03415                                      bInheritHandles,
03416                                      dwCreationFlags,
03417                                      lpEnvironment,
03418                                      CurrentDirectory.Buffer,
03419                                      &StartupInfo,
03420                                      lpProcessInformation,
03421                                      hNewToken);
03422 
03423     /* Clean up */
03424     RtlFreeUnicodeString(&ApplicationName);
03425     RtlFreeUnicodeString(&LiveCommandLine);
03426     RtlFreeUnicodeString(&CurrentDirectory);
03427     RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpDesktop);
03428     RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpReserved);
03429     RtlFreeHeap(RtlGetProcessHeap(), 0, StartupInfo.lpTitle);
03430 
03431     /* Return what Unicode did */
03432     return bRetVal;
03433 }
03434 
03435 /*
03436  * FUNCTION: The CreateProcess function creates a new process and its
03437  * primary thread. The new process executes the specified executable file
03438  * ARGUMENTS:
03439  *
03440  *     lpApplicationName = Pointer to name of executable module
03441  *     lpCommandLine = Pointer to command line string
03442  *     lpProcessAttributes = Process security attributes
03443  *     lpThreadAttributes = Thread security attributes
03444  *     bInheritHandles = Handle inheritance flag
03445  *     dwCreationFlags = Creation flags
03446  *     lpEnvironment = Pointer to new environment block
03447  *     lpCurrentDirectory = Pointer to current directory name
03448  *     lpStartupInfo = Pointer to startup info
03449  *     lpProcessInformation = Pointer to process information
03450  *
03451  * @implemented
03452  */
03453 BOOL
03454 WINAPI
03455 CreateProcessA(LPCSTR lpApplicationName,
03456                LPSTR lpCommandLine,
03457                LPSECURITY_ATTRIBUTES lpProcessAttributes,
03458                LPSECURITY_ATTRIBUTES lpThreadAttributes,
03459                BOOL bInheritHandles,
03460                DWORD dwCreationFlags,
03461                LPVOID lpEnvironment,
03462                LPCSTR lpCurrentDirectory,
03463                LPSTARTUPINFOA lpStartupInfo,
03464                LPPROCESS_INFORMATION lpProcessInformation)
03465 {
03466     /* Call the internal (but exported) version */
03467     return CreateProcessInternalA(0,
03468                                   lpApplicationName,
03469                                   lpCommandLine,
03470                                   lpProcessAttributes,
03471                                   lpThreadAttributes,
03472                                   bInheritHandles,
03473                                   dwCreationFlags,
03474                                   lpEnvironment,
03475                                   lpCurrentDirectory,
03476                                   lpStartupInfo,
03477                                   lpProcessInformation,
03478                                   NULL);
03479 }
03480 
03481 /*
03482  * @implemented
03483  */
03484 UINT
03485 WINAPI
03486 WinExec(LPCSTR lpCmdLine,
03487         UINT uCmdShow)
03488 {
03489     STARTUPINFOA StartupInfo;
03490     PROCESS_INFORMATION  ProcessInformation;
03491     DWORD dosErr;
03492 
03493     RtlZeroMemory(&StartupInfo, sizeof(StartupInfo));
03494     StartupInfo.cb = sizeof(STARTUPINFOA);
03495     StartupInfo.wShowWindow = (WORD)uCmdShow;
03496     StartupInfo.dwFlags = 0;
03497 
03498     if (!CreateProcessA(NULL,
03499                         (PVOID)lpCmdLine,
03500                         NULL,
03501                         NULL,
03502                         FALSE,
03503                         0,
03504                         NULL,
03505                         NULL,
03506                         &StartupInfo,
03507                         &ProcessInformation))
03508     {
03509         dosErr = GetLastError();
03510         return dosErr < 32 ? dosErr : ERROR_BAD_FORMAT;
03511     }
03512 
03513     if (NULL != UserWaitForInputIdleRoutine)
03514     {
03515         UserWaitForInputIdleRoutine(ProcessInformation.hProcess,
03516                                            10000);
03517     }
03518 
03519     NtClose(ProcessInformation.hProcess);
03520     NtClose(ProcessInformation.hThread);
03521 
03522     return 33; /* Something bigger than 31 means success. */
03523 }
03524 
03525 /* EOF */

Generated on Sat May 26 2012 04:23:01 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.