如何将指向句柄列表的指针传递给 UpdateProcThreadAttribute 函数

How to pass a pointer to a list of handles to the UpdateProcThreadAttribute function

我有一个生成多个 CreateProcess 线程的应用程序,我成功地将每个线程的 stdout 和 stderr 输出重定向到文本文件。

但是,我发现了 stdout/strderr 句柄被所有此类线程继承的特性,而不仅仅是我希望它们被继承的线程。所以我开始了使用 InitializeProcThreadAttributeListUpdateProcThreadAttribute 函数和 EXTENDED_STARTUPINFO_PRESENT[=44= 的旅程] 和 STARTUPINFOEX 函数中的 CreateProcess 结构来解决这个问题,但我被卡住了。

如果我在 UpdateProcThreadAttribute 过程中使用 PROC_THREAD_ATTRIBUTE_HANDLE_LIST 作为 Attribute 参数它期望 lpValue 参数是指向子进程继承的句柄列表的指针

对于列表,我尝试使用

TList<Cardinal>

并且还创建了一个 Cardinals 数组,但无法获得任何一种编译方法!

问题:如何创建和填充这样的列表?

其次,in this example 它正在使用 kernel32.dll 中的函数和过程,但它们也存在于 Windows 单元中(我使用的是 Delphi 10.3)尽管定义不同:

例如,由于 nil 参数,InitializeProcThreadAttributeList( nil, 1, 0, vAListSize ); 不会使用 Windows 单元进行编译,因为 实际和形式 var 参数的类型必须相同 但我使用 kernel32

中的那个没有这样的问题

问题:我应该使用 functions/procedures 中的哪个版本?

谢谢。

如果它有用,这里是我实现所有这些的代码:

type
  TStartupInfoEx = record
    StartupInfo: TStartupInfo;
    lpAttributeList: Pointer;
  end;

const
  PROC_THREAD_ATTRIBUTE_HANDLE_LIST = [=10=]020002;

function InitializeProcThreadAttributeList(
  lpAttributeList: Pointer;
  dwAttributeCount: DWORD;
  dwFlags: DWORD;
  var lpSize: SIZE_T
): BOOL; stdcall; external kernel32;

function UpdateProcThreadAttribute(
  lpAttributeList: Pointer;
  dwFlags: DWORD;
  Attribute: DWORD_PTR;
  lpValue: Pointer;
  cbSize: SIZE_T;
  lpPreviousValue: PPointer;
  lpReturnSize: PSIZE_T
): BOOL; stdcall; external kernel32;

function DeleteProcThreadAttributeList(
  lpAttributeList: Pointer
): BOOL; stdcall; external kernel32;

function CreateProcessWithInheritedHandles(
  lpApplicationName: LPCWSTR;
  lpCommandLine: LPWSTR;
  lpProcessAttributes,
  lpThreadAttributes: PSecurityAttributes;
  const Handles: array of THandle;
  dwCreationFlags: DWORD;
  lpEnvironment: Pointer;
  lpCurrentDirectory: LPCWSTR;
  const lpStartupInfo: TStartupInfo;
  var lpProcessInformation: TProcessInformation
): Boolean;
var
  i: Integer;
  StartupInfoEx: TStartupInfoEx;
  size: SIZE_T;
begin
  Assert(Length(Handles)>0);

  StartupInfoEx.StartupInfo := lpStartupInfo;
  StartupInfoEx.StartupInfo.cb := SizeOf(StartupInfoEx);
  StartupInfoEx.lpAttributeList := nil;

  Win32Check(not InitializeProcThreadAttributeList(nil, 1, 0, size) and (GetLastError=ERROR_INSUFFICIENT_BUFFER));
  GetMem(StartupInfoEx.lpAttributeList, size);
  try
    Win32Check(InitializeProcThreadAttributeList(StartupInfoEx.lpAttributeList, 1, 0, size));
    try
      Win32Check(UpdateProcThreadAttribute(
        StartupInfoEx.lpAttributeList,
        0,
        PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
        @Handles[0],
        Length(Handles) * SizeOf(Handles[0]),
        nil,
        nil
      ));

      for i := 0 to High(Handles) do begin
        Win32Check(SetHandleInformation(Handles[i], HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT));
      end;

      Result := CreateProcess(
        lpApplicationName,
        lpCommandLine,
        lpProcessAttributes,
        lpThreadAttributes,
        True,
        dwCreationFlags,
        lpEnvironment,
        lpCurrentDirectory,
        StartupInfoEx.StartupInfo,
        lpProcessInformation
      );
    finally
      DeleteProcThreadAttributeList(StartupInfoEx.lpAttributeList);
    end;
  finally
    FreeMem(StartupInfoEx.lpAttributeList);
  end;
end;

从你的 post 来看,最新版本的 Windows 单元中似乎有一些 InitializeProcThreadAttributeListUpdateProcThreadAttributeDeleteProcThreadAttributeList 的声明Delphi,但您的 post 暗示它们的声明不正确。已知以上代码可以正常工作。