user-0 提问: 关于CreateProcess启动外部程序问题。

回复:
user: user-1
content: CreateProcess The CreateProcess function creates a new process and its primary thread. The new process executes the specified executable file.   BOOL CreateProcess(   LPCTSTR lpApplicationName,                          // pointer to name of executable module   LPTSTR lpCommandLine,  // pointer to command line string   LPSECURITY_ATTRIBUTES lpProcessAttributes,  // process security attributes   LPSECURITY_ATTRIBUTES lpThreadAttributes,   // thread security attributes   BOOL bInheritHandles,  // handle inheritance flag   DWORD dwCreationFlags, // creation flags   LPVOID lpEnvironment,  // pointer to new environment block   LPCTSTR lpCurrentDirectory,   // pointer to current directory name   LPSTARTUPINFO lpStartupInfo,  // pointer to STARTUPINFO   LPPROCESS_INFORMATION lpProcessInformation  // pointer to PROCESS_INFORMATION );   Parameters ……  Remarks The CreateProcess function is used to run a new program. The WinExec and LoadModule functions are still available, but they are implemented as calls to CreateProcess.   In addition to creating a process, CreateProcess also creates a thread object. The thread is created with an initial stack whose size is described in the image header of the specified program's executable file. The thread begins execution at the image's entry point.   The new process and the new thread handles are created with full access rights. For either handle, if a security descriptor is not provided, the handle can be used in any function that requires an object handle to that type. When a security descriptor is provided, an access check is performed on all subsequent uses of the handle before access is granted. If the access check denies access, the requesting process is not able to use the handle to gain access to the thread.   The process is assigned a 32-bit process identifier. The identifier is valid until the process terminates. It can be used to identify the process, or specified in the OpenProcess function to open a handle to the process. The initial thread in the process is also assigned a 32-bit thread identifier. The identifier is valid until the thread terminates and can be used to uniquely identify the thread within the system. These identifiers are returned in the PROCESS_INFORMATION structure.   When specifying an application name in the lpApplicationName or lpCommandLine strings, it doesn't matter whether the application name includes the filename extension, with one exception: an MS-DOS – based or Windows-based application whose filename extension is .COM must include the .COM extension.   The calling thread can use the WaitForInputIdle function to wait until the new process has finished its initialization and is waiting for user input with no input pending. This can be useful for synchronization between parent and child processes, because CreateProcess returns without waiting for the new process to finish its initialization. For example, the creating process would use WaitForInputIdle before trying to find a window associated with the new process.   The preferred way to shut down a process is by using the ExitProcess function, because this function notifies all dynamic-link libraries (DLLs) attached to the process of the approaching termination. Other means of shutting down a process do not notify the attached DLLs. Note that when a thread calls ExitProcess, other threads of the process are terminated without an opportunity to execute any additional code (including the thread termination code of attached DLLs).   ExitProcess, ExitThread, CreateThread, CreateRemoteThread, and a process that is starting (as the result of a call by CreateProcess) are serialized between each other within a process. Only one of these events can happen in an address space at a time. This means the following restrictions hold:   During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process.  Only one thread in a process can be in a DLL initialization or detach routine at a time.  The ExitProcess function does not return until no threads are in their DLL initialization or detach routines.  The created process remains in the system until all threads within the process have terminated and all handles to the process and any of its threads have been closed through calls to CloseHandle. The handles for both the process and the main thread must be closed through calls to CloseHandle. If these handles are not needed, it is best to close them immediately after the process is created.   When the last thread in a process terminates, the following events occur:   All objects opened by the process are implicitly closed.  The process's termination status (which is returned by GetExitCodeProcess) changes from its initial value of STILL_ACTIVE to the termination status of the last thread to terminate.  The thread object of the main thread is set to the signaled state, satisfying any threads that were waiting on the object.  The process object is set to the signaled state, satisfying any threads that were waiting on the object.  If the current directory on drive C is \MSVC\MFC, there is an environment variable called =C: whose value is C:\MSVC\MFC. As noted in the previous description of lpEnvironment, such current directory information for a system's drives does not automatically propagate to a new process when the CreateProcess function's lpEnvironment parameter is non-NULL. An application must manually pass the current directory information to the new process. To do so, the application must explicitly create the =X environment variable strings, get them into alphabetical order (because the system uses a sorted environment), and then put them into the environment block specified by lpEnvironment. Typically, they will go at the front of the environment block, due to the previously mentioned environment block sorting.   One way to obtain the current directory variable for a drive X is to call GetFullPathName("X:",. .). That avoids an application having to scan the environment block. If the full path returned is X:\, there is no need to pass that value on as environment data, since the root directory is the default current directory for drive X of a new process.   The handle returned by the CreateProcess function has PROCESS_ALL_ACCESS access to the process object.   The current directory specified by the lpcurrentDirectory parameter is the current directory for the child process. The current directory specified in item 2 under the lpCommandLine parameter is the current directory for the parent process.  Windows NT: When a process is created with CREATE_NEW_PROCESS_GROUP specified, an implicit call to SetConsoleCtrlHandler(NULL,TRUE) is made on behalf of the new process; this means that the new process has ctrl+c disabled. This lets good shells handle ctrl+c themselves, and selectively pass that signal on to sub-processes. ctrl+break is not disabled, and may be used to interrupt the process/process group.   Windows CE: The name of the module to execute must be specified by the lpApplicationName parameter. Windows CE does not support passing NULL for lpApplicationName. The execution module cannot be specified in the command line string.  Windows CE searches the directories indicated by the lpApplicationName parameter in the following order:   The root of the PC Card if it exists  The windows (\windows) directory  The root (\ ) directory of the device  The following parameters are not supported and require the following settings:   lpProcessAttributes must be NULL  lpThreadAttributes must be NULL  bInheritHandles must be FALSE  lpEnvironment must be NULL  lpCurrentDirectory must be NULL  lpStartupInfo must be NULL  For Windows CE version 1.0, the dwCreationFlags parameter only supports the following values: CREATE_SUSPENDED and zero.   For Windows CE version 2.0, the dwCreationFlags parameter only supports the following values: CREATE_SUSPENDED, DEBUG_PROCESS, DEBUG_ONLY_THIS_PROCESS and zero.   Priority classes for processes are not supported.  The loader has a limited search path.   QuickInfo   Windows NT: Requires version 3.1 or later.   Windows: Requires Windows 95 or later.   Windows CE: Requires version 1.0 or later.   Header: Declared in winbase.h.   Import Library: Use kernel32.lib.   Unicode: Implemented as Unicode and ANSI versions on Windows NT.  See Also Processes and Threads Overview, Process and Thread Functions, AllocConsole, CloseHandle, CreateRemoteThread, CreateThread, ExitProcess, ExitThread, GenerateConsoleCtrlEvent, GetCommandLine, GetEnvironmentStrings, GetExitCodeProcess, GetFullPathName, GetStartupInfo,GetSystemDirectory,GetWindowsDirectory, LoadModule, OpenProcess, PROCESS_INFORMATION, ResumeThread, SECURITY_ATTRIBUTES, SetConsoleCtrlHandler, SetErrorMode, STARTUPINFO, TerminateProcess, WaitForInputIdle, WaitForDebugEvent, WinExec

user: user-2
content: 纠正下2 GetLastError看返回值

user: user-2
content: 1.上代码比说故障更便于找错。 2.如果是使用P/Invoke，那么在DllImport属性中设置SetLastError=true。 然后就可以使用 Marshal.GetLastWin32Error来获取系统错误了。