如何只用 JOB_OBJECT_BASIC_LIMIT_INFORMATION 调用 SetInformationJobObject?

How to call SetInformationJobObject with just JOB_OBJECT_BASIC_LIMIT_INFORMATION?

我有一份工作的基本翻译API,如下:

type
  TJobObjectInfoClass = (
    JobObjectBasicLimitInformation = 2,
    JobObjectExtendedLimitInformation = 9
  );

  TJobObjectBasicLimitInformation = record
    PerProcessUserTimeLimit: TLargeInteger;
    PerJobUserTimeLimit: TLargeInteger;
    LimitFlags: DWORD;
    MinimumWorkingSetSize: DWORD;
    MaximumWorkingSetSize: DWORD;
    ActiveProcessLimit: DWORD;
    Affinity: DWORD;
    PriorityClass: DWORD;
    SchedulingClass: DWORD;
  end;

  TIOCounters = record
    ReadOperationCount: UInt64;
    WriteOperationCount: UInt64;
    OtherOperationCount: UInt64;
    ReadTransferCount: UInt64;
    WriteTransferCount: UInt64;
    OtherTransferCount: UInt64;
  end;

  TJobObjectExtendedLimitInformation = record
    BasicLimitInformation: TJobObjectBasicLimitInformation;
    IoInfo: TIOCounters;
    ProcessMemoryLimit: DWORD;
    JobMemoryLimit: DWORD;
    PeakProcessMemoryUsed: DWORD;
    PeakJobMemoryUsed: DWORD;
  end;

const
  CREATE_BREAKAWAY_FROM_JOB = 000000;
  JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = [=11=]002000;

function AssignProcessToJobObject(const hJob, hProcess: THandle): BOOL; stdcall;
external kernel32 name 'AssignProcessToJobObject';

function CreateJobObject(const lpJobAttributes: PSecurityAttributes;
  const lpName: PChar): THandle; stdcall;
external kernel32 name {$IFDEF UNICODE}'CreateJobObjectW'{$ELSE}'CreateJobObjectA'{$ENDIF};

function SetInformationJobObject(const hJob: THandle;
  const JobObjectInformationClass: TJobObjectInfoClass;
  const lpJobObjectInformation: Pointer;
  const cbJobObjectInformationLength: DWORD): BOOL; stdcall;
external kernel32 name 'SetInformationJobObject';

当我如下使用它时,它工作正常:

Job := CreateJobObject(nil, nil);
if Job = 0 then
  RaiseLastOSError;

ZeroMemory(@JELI, SizeOf(JELI));
JELI.BasicLimitInformation.LimitFlags := JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
Win32Check(SetInformationJobObject(
  Job, JobObjectExtendedLimitInformation, @JELI, SizeOf(JELI))
);

因为我只设置了 BasicLimitInformation,我希望能够改为调用 SetInformationJobObject

ZeroMemory(@JBLI, SizeOf(JBLI));
JBLI.LimitFlags := JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
Win32Check(SetInformationJobObject(
  Job, JobObjectBasicLimitInformation, @JBLI, SizeOf(JBLI))
);

MSDN 上的文档没有给我任何不支持的迹象。为什么它会失败并显示代码 87 ("The parameter is incorrect")?

我最好的猜测是我的记录与 Windows 期望的结构不完全匹配,这意味着某些位在错误的位置。然而,当它嵌入另一个时,它工作正常。在那里,它是第一个字段,因此填充不太可能是原因。

来自 JOB_OBJECT_BASIC_LIMIT_INFORMATION 的文档:

[JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE] requires use of a JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure. Its BasicLimitInformation member is a JOBOBJECT_BASIC_LIMIT_INFORMATION structure."

extended 结构以 basic 结构开始,因此这两个结构至少部分兼容,这就是您不会得到随机结果的原因。

这应该给出正确的结果:

ZeroMemory(@JELI, SizeOf(JELI));
JELI.BasicLimitInformation.LimitFlags := JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
Win32Check(SetInformationJobObject(
  Job, JobObjectBasicLimitInformation, @JELI, SizeOf(JELI))
);