Как передать указатель на список дескрипторов в функцию UpdateProcThreadAttribute - PullRequest
1 голос
/ 06 марта 2020

У меня есть приложение, которое порождает несколько потоков CreateProcess , и я успешно перенаправляю вывод stdout и stderr в текстовые файлы для каждого.

Однако я обнаружил эту функцию посредством чего дескрипторы stdout / strderr наследуются всеми такими потоками, а не только теми, которые я хочу, чтобы они наследовали. Итак, я отправился в путь, чтобы использовать InitializeProcThreadAttributeList , UpdateProcThreadAttribute функций и EXTENDED_STARTUPINFO_PRESENT и STARTUPINFOEX в Функция CreateProcess , чтобы обойти это, но я застрял.

Если я использую PROC_THREAD_ATTRIBUTE_HANDLE_LIST в качестве аргумента Атрибут в UpdateProcThreadAttribute , процедура ожидает, что параметр lpValue будет указателем на список дескрипторов, которые должны наследоваться дочерним процессом .

Для списка, который я пробовал использовать

TList<Cardinal>

, а также создать массив кардиналов, но не смог получить Подходы к компиляции!

Вопрос: Как мне создать и заполнить такой список?

Во-вторых, в этом примере он использует функции и процедуры из kernel32.dll но они также существуют в модуле Windows (я использую Delphi 10.3), хотя определения отличаются:

Например, InitializeProcThreadAttributeList( nil, 1, 0, vAListSize ); не будет компилироваться с использованием модуля Windows из-за аргумент nil, потому что Типы фактических и формальных параметров var должны быть идентичны , но у меня нет такой проблемы с использованием проблемы в kernel32

Вопрос: Какую версию этих функций / процедур мне следует Вы используете?

Спасибо.

1 Ответ

3 голосов
/ 06 марта 2020

В случае, если это полезно, вот мой код для реализации всего этого:

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;

Из вашего поста может показаться, что есть некоторые объявления InitializeProcThreadAttributeList, UpdateProcThreadAttribute и DeleteProcThreadAttributeList в блоке Windows в последних версиях Delphi, но ваш пост подразумевает, что они объявлены неправильно. Известно, что приведенный выше код работает правильно.

...