Delphi 如何将指向句柄列表的指针传递给UpdateProctThreadAttribute函数
我有一个生成多个CreateProcess线程的应用程序,我正在成功地将stdout和stderr输出重定向到每个线程的文本文件 然而,我发现了一个特性,即stdout/strderr句柄被所有这样的线程继承,而不仅仅是我希望它们被继承的线程。因此,我开始了一段旅程,使用InitializeProctThreadAttributeList、UpdateProctThreadAttribute函数和扩展的_STARTUPINFO_PRESENT以及CreateProcess函数中的STARTUPINFOEX结构来解决这个问题,但我被卡住了 如果我在UpdateProcThreadAttribute过程中使用PROC_THREAD_ATTRIBUTE_HANDLE_LIST作为属性参数,它希望lpValue参数是指向要由子进程继承的句柄列表的指针 对于列表,我尝试使用Delphi 如何将指向句柄列表的指针传递给UpdateProctThreadAttribute函数,delphi,winapi,vcl,kernel32,Delphi,Winapi,Vcl,Kernel32,我有一个生成多个CreateProcess线程的应用程序,我正在成功地将stdout和stderr输出重定向到每个线程的文本文件 然而,我发现了一个特性,即stdout/strderr句柄被所有这样的线程继承,而不仅仅是我希望它们被继承的线程。因此,我开始了一段旅程,使用InitializeProctThreadAttributeList、UpdateProctThreadAttribute函数和扩展的_STARTUPINFO_PRESENT以及CreateProcess函数中的STARTUPI
TList<Cardinal>
并且还创建了一个基数数组,但无法获得任何一种编译方法
问题:如何创建和填充这样的列表
其次,它使用的是kernel32.dll中的函数和过程,但它们也存在于Windows单元中。我使用的是Delphi 10.3,尽管定义不同:
例如,InitializeProcThreadAttributeList nil,1,0,vAListSize;由于nil参数,我不会使用Windows单元进行编译,因为实际变量和形式变量参数的类型必须相同,但我使用kernel32中的参数时没有此类问题
问题:我应该使用这些函数/过程的哪个版本
谢谢。如果有用的话,下面是我实现所有这些的代码:
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;
从您的帖子中可以看出,在最新版本的Delphi中,Windows单元中似乎有一些InitializepRoctThreadAttributeList、UpdatepRoctThreadAttribute和DeleteProcThreadAttributeList的声明,但您的帖子暗示这些声明不正确。以上代码可以正常工作。如果有用,下面是我的代码来实现所有这些:
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;
从您的帖子中可以看出,在最新版本的Delphi中,Windows单元中似乎有一些InitializepRoctThreadAttributeList、UpdatepRoctThreadAttribute和DeleteProcThreadAttributeList的声明,但您的帖子暗示这些声明不正确。上面的代码工作正常。您需要将指针传递到handles的数组句柄h[n]当函数需要THandle时,您为什么会考虑使用Cardinal?如果您不能将nil传递给InitializeProcThreadAttributeList,那么我怀疑您应该自己声明InitializeProcThreadAttributeList,并正确执行它。我就是这么做的,好问题!我到那里可能是因为定义上说的是pValue-System。Cardinal和我一直在想方设法让它工作,但都没有用!在UpdateProcThreadAttribute中使用@vMyHandles(其中vMyHandles是句柄数组)不会编译。我对使用指针有些困惑。不要使用IDE作为Windows API的参考。使用实际的Windows API参考。不要相信Emba的标题翻译。它们通常是错误的。@vMyHandles是指向数组地址的指针。这是一个间接的层次太远了。不管怎样,我的答案中已经包含了所有需要的内容。您需要将指针传递给handles的数组句柄h[n],当函数需要THandle时,您为什么会考虑使用Cardinal?如果您不能将nil传递给InitializeProcThreadAttributeList,那么我怀疑您应该自己声明InitializeProcThreadAttributeList,并正确执行它。我就是这么做的,好问题!我到那里可能是因为定义上说的是pValue-System。Cardinal和我一直在想方设法让它工作,但都没有用!在UpdateProcThreadAttribute中使用@vMyHandles(其中vMyHandles是句柄数组)不会编译。我对使用指针有些困惑。不要使用IDE作为Windows API的参考。使用实际的Windows API参考。不要相信Emba的标题翻译。它们通常是错误的。@vMyHandles是指向数组地址的指针。这是一个间接的层次太远了。不管怎样,从我的回答中你已经得到了你所需要的一切。