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

标签 delphi winapi vcl kernel32

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

但是,我发现了一个功能,即 stdout/strderr 句柄由所有此类线程继承,而不仅仅是我希望它们继承的线程。因此,我开始在CreateProcess 函数来解决这个问题,但我被困住了。

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

对于我尝试使用的列表

TList<Cardinal>

还创建了一个枢机主教数组,但无法获得任何一种编译方法!

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

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

例如,InitializeProcThreadAttributeList( nil, 1, 0, vAListSize ); 由于 nil 参数而无法使用 Windows 单元进行编译,因为实际和形式 var 参数的类型必须是相同,但我使用 kernel32 中的没有这样的问题

问题:我应该使用这些函数/过程的哪个版本?

谢谢。

最佳答案

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

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;

// see https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873
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;

const
  PROC_THREAD_ATTRIBUTE_HANDLE_LIST = $00020002;

  // this flag is ignored these days, and struct size is used, but we may as well follow the letter of the docs
  EXTENDED_STARTUPINFO_PRESENT = $00080000;

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

var
  Handle: THandle;
  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 Handle in Handles do begin
        Win32Check(SetHandleInformation(Handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT));
      end;

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

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

更新:我已更新代码以包含 @blerontin 建议的 EXTENDED_STARTUPINFO_PRESENT 进程创建标志。我不认为这是必要的,因为启动信息结构的大小是系统用来做出该决定的。然而,文档说应该使用它,并且包含它是无害的。

我还查看了 RTL 中最新的 Delphi Windows 单元中的 InitializeProcThreadAttributeListUpdateProcThreadAttribute 的声明(我的版本是 11.3)写),它们确实是假的。

关于delphi - 如何将指向句柄列表的指针传递给 UpdateProcThreadAttribute 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60563608/

相关文章:

delphi - 从 Delphi 应用程序内激活文件病毒扫描

c++ - 用于泄漏检测的 Appverifier 和 Visual Studio

windows - 关于 DPI 问题

delphi - 创建自定义表单设计器

delphi - 如何将http下载图像从扩展转换为另一个?

delphi - 如何将 Delphi.NET 项目转换为 Delphi Prism?

delphi - 如何绘制旋转的圆角矩形

delphi - Delphi中Loaded()后调用的是什么

delphi - TObjectList E2003 未声明的标识符 TObjectList<>

.net - 如何在 vb.net 中闪烁/闪烁任务栏图标?