简体   繁体   中英

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

I have an application that spawns multiple CreateProcess threads and I'm successfully redirecting the stdout and stderr output to text files for each one.

However, I've discovered the feature whereby the stdout/strderr handles are inherited by all such threads and not just the ones I want them to be inherited by. So I've embarked on a journey to use the InitializeProcThreadAttributeList , UpdateProcThreadAttribute functions and EXTENDED_STARTUPINFO_PRESENT and a STARTUPINFOEX structure in the CreateProcess function to get around this but I'm stuck.

If I use PROC_THREAD_ATTRIBUTE_HANDLE_LIST as the Attribute argument in UpdateProcThreadAttribute procedure it expects the lpValue parameter to be a pointer to a list of handles to be inherited by the child process .

For the List I've tried using a

TList<Cardinal>

and also creating an array of Cardinals but couldn't get either approaches to compile!

Question: How do I create and populate such a list?

Secondly, in this example it is using the functions and procedures from kernel32.dll but they also exist in the Windows unit too (I'm using Delphi 10.3) although the definitions differ:

For example, InitializeProcThreadAttributeList( nil, 1, 0, vAListSize ); won't compile using the Windows unit due to the nil argument because Types of actual and formal var parameters must be identical but I have no such issue using the one in kernel32

Question: Which version of these functions/procedures should I be using?

Thanks.

In case it is useful, here's my code to implement all of this:

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

const
  PROC_THREAD_ATTRIBUTE_HANDLE_LIST = $00020002;

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;

From your post it would seem that there are some declarations of InitializeProcThreadAttributeList , UpdateProcThreadAttribute and DeleteProcThreadAttributeList in the Windows unit in the latest versions of Delphi, but your post implies that they are incorrectly declared. The above code is known to work correctly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM