开始新进程,而不是产卵进程的孩子

问题描述 投票:0回答:8

如果它不是调用进程的子进程,我将如何开始一个新进程。

例子:

主程序(Caller.exe)

process.start("file.exe")

图片:

c# vb.net process parent-child
8个回答
25
投票

如果生成进程(父进程)在生成进程(子进程)结束之前结束,则父子链被破坏。要使用它,您必须使用像这样的中间存根进程:

Caller.exe → Stub.exe → File.exe。

这里的 Stub.exe 是简单的启动程序,它在启动 File.exe 后立即结束。


14
投票

如果你启动一个进程,那么你将成为它的父进程。

也许你可以尝试从 cmd.exe 启动你的进程,所以 cmd.exe 将成为父进程。

Process proc = Process.Start(new ProcessStartInfo { Arguments = "/C explorer", FileName = "cmd", WindowStyle = ProcessWindowStyle.Hidden });

11
投票

我一直在尝试启动一个更新程序进程,该进程删除调用进程的文件并用新文件替换它们。通过设置

UseShellExecute = true
,我能够在调用进程退出时避免衍生进程退出。

这是在使用 WPF 的 .Net Core 3.0 应用程序中。

var startInfo = new ProcessStartInfo("Updater.exe");
startInfo.UseShellExecute = true;
Process.Start(startInfo);
Environment.Exit(0);

7
投票

这会在没有父进程的情况下运行新进程:

System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
psi.FileName = @"cmd";
psi.Arguments = "/C start notepad.exe";
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
System.Diagnostics.Process.Start(psi);

1
投票

Process.Start(string fileName)
的文档说

a new process that’s started alongside already running instances 
of the same process will be independent

它说

Starting a process by specifying its file name is similar to 
typing the information in the Run dialog box of the Windows Start menu

在我看来这与独立流程一致。

所以根据文档,

Process.Start
应该做你想做的。


0
投票

System.Diagnostics.Process.Start()
方法在幕后调用
kernel32!CreateProcess()
。使用
kernel32!CreateProcess()
创建进程时,您可以使用进程属性指定不同的父进程。这是一个用 C++ 编写的函数,它就是这样做的——尽管我不确定 .Net 如何支持这些功能。

bool CreateProcessWithParent(DWORD parentId, PWSTR commandline) {
    auto hProcess = ::OpenProcess(PROCESS_CREATE_PROCESS, FALSE, parentId);
    if (!hProcess)
        return false;
 
    SIZE_T size;
    //
    // call InitializeProcThreadAttributeList twice
    // first, get required size
    //
    ::InitializeProcThreadAttributeList(nullptr, 1, 0, &size);
 
    //
    // now allocate a buffer with the required size and call again
    //
    auto buffer = std::make_unique<BYTE[]>(size);
    auto attributes = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(buffer.get());
    ::InitializeProcThreadAttributeList(attributes, 1, 0, &size);
 
    //
    // add the parent attribute
    //
    ::UpdateProcThreadAttribute(attributes, 0, 
        PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, 
        &hProcess, sizeof(hProcess), nullptr, nullptr);
 
    STARTUPINFOEX si = { sizeof(si) };
    //
    // set the attribute list
    //
    si.lpAttributeList = attributes;
    PROCESS_INFORMATION pi;
 
    //
    // create the process
    //
    BOOL created = ::CreateProcess(nullptr, commandline, nullptr, nullptr, 
        FALSE, EXTENDED_STARTUPINFO_PRESENT, nullptr, nullptr, 
        (STARTUPINFO*)&si, &pi);
 
    //
    // cleanup
    //
    ::CloseHandle(hProcess);
    ::DeleteProcThreadAttributeList(attributes);
 
    return created;
}

源代码取自https://scorpiosoftware.net/2021/01/10/parent-process-vs-creator-process/


0
投票

我正在使用这段代码。优点是您不必使用 PInvoke。我发现带有

CreateProcess
标志的
DETACHED_PROCESS
api 不是 100% 可靠的,子进程有时仍然会在父进程死亡时死亡。

https://github.com/dahall/taskscheduler

// you need two variables:
string fileName = ...
string arguments = ...

// Get the task service on the local machine
using TaskService ts = new();

// create task name
var taskName = "DetachedProcess_" + Convert.ToHexString(MD5.HashData(Encoding.UTF8.GetBytes(Path.GetFileName(fileName))));

// remove the task if it already exists
ts.RootFolder.DeleteTask(taskName, false);

// create a new task definition and assign properties
TaskDefinition td = ts.NewTask();
td.RegistrationInfo.Description = "Detached process for " + fileName;

// create a trigger that will run the process in 5 seconds
td.Triggers.Add(new TimeTrigger(IPBanService.UtcNow.AddSeconds(5.0)));

// create the action to run the process
td.Actions.Add(new ExecAction(fileName, arguments, Path.GetDirectoryName(fileName)));

// delete task upon completion
td.Actions.Add(new ExecAction("schtasks.exe", "/Delete /TN \"" + taskName + "\" /F", null));

// register the task in the root folder
var task = ts.RootFolder.RegisterTaskDefinition(taskName, td);
task.Run(); // just run it now

-1
投票

这是我现在使用的代码。我认为这可能对某人有用。它接受一个参数。该参数是一个 base64 编码的字符串,可解码为您要运行的文件的路径。

 Module Module1

    Sub Main()
        Dim CommandLineArgs As System.Collections.ObjectModel.ReadOnlyCollection(Of String) = My.Application.CommandLineArgs
        If CommandLineArgs.Count = 1 Then
            Try
                Dim path As String = FromBase64(CommandLineArgs(0))
                Diagnostics.Process.Start(path)
            Catch
            End Try
            End
        End If
    End Sub

    Function FromBase64(ByVal base64 As String) As String
        Dim b As Byte() = Convert.FromBase64String(base64)
        Return System.Text.Encoding.UTF8.GetString(b)
    End Function

End Module
© www.soinside.com 2019 - 2024. All rights reserved.