C# 如何处理;“无固定尺寸”;pinvoke结构中的数组?

C# 如何处理;“无固定尺寸”;pinvoke结构中的数组?,c#,arrays,struct,pinvoke,C#,Arrays,Struct,Pinvoke,您将如何用c#编写这种类型的结构 如果没有为ProcessIdList数组设置大小,您会怎么做?你是这样写的吗: [StructLayout(LayoutKind.Sequential)] struct JOBOBJECT_BASIC_PROCESS_ID_LIST { int NumberOfAssignedProcesses; int NumberOfProcessIdsInList; IntPtr ProcessIdList; //Must point to a allo

您将如何用c#编写这种类型的结构

如果没有为
ProcessIdList
数组设置大小,您会怎么做?你是这样写的吗:

[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
   int NumberOfAssignedProcesses;
   int NumberOfProcessIdsInList;
   IntPtr ProcessIdList; //Must point to a allocated array, thanks jdweng for letting me know.
}
或者您是否只指定一个足够大的尺寸,例如:

[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
   int NumberOfAssignedProcesses;
   int NumberOfProcessIdsInList;
   [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_PATH)]
   UIntPtr[] ProcessIdList; //Works just fine, but is limited to the SizeConst.
}

我认为你提到的任何一种方法都应该奏效

此外,c#中还有一个匹配功能:使用fixed关键字定义数组:

struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
   int NumberOfAssignedProcesses;
   int NumberOfProcessIdsInList;
   fixed IntPtr ProcessIdList[1];
}
见文件:

也没有边界检查,因此您应该能够轻松阅读struckt末尾后面的内容:

除了使用stackalloc创建的内存外,C#编译器和公共语言运行库(CLR)不执行任何安全缓冲区溢出检查。与所有不安全代码一样,请谨慎使用


通常会声明这种结构(例如,在WLan API中也有类似的结构):


你的第一种方法是正确的。您有一个32位指针。但是指针必须指向一个进程列表大小的已分配内存。内存必须在非托管内存中。哦,好的。我知道固定大小的缓冲区,但被告知使用它们是不明智的,所以我有点远离它们。如果您不介意回答另一个问题(与本问题不同),您会如何处理字符串,其中在结构中字段以
DWORD StrLength=>LPWSTR-Str=>DWORD-Attribute
的形式排列?这与数组(
IntPtr
/
fixed char[]
)是一样的吗?这是不正确的。非托管结构中的数组的要点是它可以容纳任意长度。@DavidHeffernan您没有对它进行边界检查。这意味着您可以访问x.ProcessIdList[2],即使数组大小定义为1。问问自己,如何使用长度大于1的数组声明这样的结构。只要别人声明了,它就好了,就像C++一样。但是你怎么用C语言声明这样的事情呢。考虑一下你实际回答的文本,“我认为你提到的任何一种方法都应该有效。”事实上,这两种方法中的两种方法都不能奏效。“DavidHeffernan我测试了这3种方法,而你对1种不可用的方法是正确的,第一种是用<代码>code>,你对第二个不正确,它工作得很好,因为它在技术上确实声明了新的uintpttr[MAX_PATH],唯一的缺点是,如果有超过260个进程ID,那么显然你将无法访问其他进程ID。这个答案中的一个不起作用,因为它基本上破坏了结构,而且你也不能做
修复IntPtr
。我只接受了这个答案,因为这是唯一的答案,如果你能提供一个更好的,那么就去吧。
struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
   int NumberOfAssignedProcesses;
   int NumberOfProcessIdsInList;
   fixed IntPtr ProcessIdList[1];
}
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct JOBOBJECT_BASIC_PROCESS_ID_LIST
    {
        public int NumberOfAssignedProcesses;
        public int NumberOfProcessIdsInList;
        public IntPtr[] ProcessIdList;
        public JOBOBJECT_BASIC_PROCESS_ID_LIST(IntPtr pList)
        {
            int nIntSize = Marshal.SizeOf<int>(); // 4
            NumberOfAssignedProcesses = Marshal.ReadInt32(pList, 0);
            NumberOfProcessIdsInList = Marshal.ReadInt32(pList, nIntSize);
            ProcessIdList = new IntPtr[NumberOfProcessIdsInList];
            for (int i = 0; i < NumberOfProcessIdsInList; i++)
            {
                IntPtr pItemList = IntPtr.Zero;
                if (Marshal.SizeOf<IntPtr>() == 4)
                    pItemList = new IntPtr(pList.ToInt32() + (i * Marshal.SizeOf<IntPtr>()) + (nIntSize * 2));
                else
                    pItemList = new IntPtr(pList.ToInt64() + (i * Marshal.SizeOf<IntPtr>()) + (nIntSize * 2));
                IntPtr nPID = new IntPtr();
                nPID = Marshal.ReadIntPtr(pItemList, 0);
                ProcessIdList[i] = nPID;
            }
        }
    }
        private IntPtr hJob = IntPtr.Zero;

        bool bRet = false;
        hJob  = CreateJobObject(IntPtr.Zero, "Test Job Object");
        JOBOBJECT_EXTENDED_LIMIT_INFORMATION jbeli = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
        jbeli.BasicLimitInformation.LimitFlags |= (JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_BREAKAWAY_OK);
        int nLength = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
        IntPtr pJobInfo = Marshal.AllocHGlobal(nLength);
        Marshal.StructureToPtr(jbeli, pJobInfo, false);           
        SetInformationJobObject(hJob, JOBOBJECTINFOCLASS.JobObjectExtendedLimitInformation, pJobInfo, (uint)nLength);
        Marshal.FreeHGlobal(pJobInfo);

        int nNbProcesses = 5;
        for (int i = 0; i < nNbProcesses; i++)
        {
            using (Process exeProcess = new Process())
            {
                exeProcess.StartInfo.FileName = "notepad";
                exeProcess.Start();
                exeProcess.WaitForInputIdle();
                IntPtr hProcess = exeProcess.Handle;
                bRet = AssignProcessToJobObject(hJob, hProcess);
            }
        }

        JOBOBJECT_BASIC_PROCESS_ID_LIST jobpil = new JOBOBJECT_BASIC_PROCESS_ID_LIST();
        jobpil.NumberOfAssignedProcesses = nNbProcesses;
        int nSize = Marshal.SizeOf<JOBOBJECT_BASIC_PROCESS_ID_LIST>() + (nNbProcesses - 1) * Marshal.SizeOf<IntPtr>();
        IntPtr pJobpil = Marshal.AllocHGlobal(nSize);
        Marshal.StructureToPtr(jobpil, pJobpil, false);
        int nReturnLength = 0;
        bRet = QueryInformationJobObject(hJob, JOBOBJECTINFOCLASS.JobObjectBasicProcessIdList,  pJobpil, nSize, out nReturnLength);
        if (bRet)
        {
            var processidlist = new JOBOBJECT_BASIC_PROCESS_ID_LIST(pJobpil);
            foreach (var pid in processidlist.ProcessIdList)
            {
                Console.WriteLine("PID: {0}", pid.ToString());
            }
        }
        else
        {
            int nErr = Marshal.GetLastWin32Error();
            Win32Exception win32Exception = new Win32Exception(nErr);
            this.Activate();
            MessageBox.Show("Error: " + win32Exception.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        Marshal.FreeHGlobal(pJobpil);


    // CloseHandle can be added in Form1_FormClosed :

    private void Form1_FormClosed(object sender, FormClosedEventArgs e)
    {
        CloseHandle(hJob);
    }
        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, string lpName);

        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool SetInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS JobObjectInfoClass, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);

        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool AssignProcessToJobObject(IntPtr hJob, IntPtr hProcess);

        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool CloseHandle(IntPtr hObject);

        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool QueryInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, [Out, MarshalAs(UnmanagedType.SysUInt)] IntPtr lpJobObjectInformation, int cbJobObjectInformationLength, out int lpReturnLength);

        [StructLayout(LayoutKind.Sequential)]
        struct JOBOBJECT_BASIC_LIMIT_INFORMATION
        {
            public ulong PerProcessUserTimeLimit;
            public ulong PerJobUserTimeLimit;
            public int LimitFlags;
            public IntPtr MinimumWorkingSetSize;
            public IntPtr MaximumWorkingSetSize;
            public int ActiveProcessLimit;
            public IntPtr Affinity;
            public int PriorityClass;
            public int SchedulingClass;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct IO_COUNTERS
        {
            public ulong ReadOperationCount;
            public ulong WriteOperationCount;
            public ulong OtherOperationCount;
            public ulong ReadTransferCount;
            public ulong WriteTransferCount;
            public ulong OtherTransferCount;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
        {
            public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
            public IO_COUNTERS IoInfo;
            public IntPtr ProcessMemoryLimit;
            public IntPtr JobMemoryLimit;
            public IntPtr PeakProcessMemoryUsed;
            public IntPtr PeakJobMemoryUsed;
        }

        //
        // Basic Limits
        //
        public const int JOB_OBJECT_LIMIT_WORKINGSET = 0x00000001;
        public const int JOB_OBJECT_LIMIT_PROCESS_TIME = 0x00000002;
        public const int JOB_OBJECT_LIMIT_JOB_TIME = 0x00000004;
        public const int JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 0x00000008;
        public const int JOB_OBJECT_LIMIT_AFFINITY = 0x00000010;
        public const int JOB_OBJECT_LIMIT_PRIORITY_CLASS = 0x00000020;
        public const int JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME = 0x00000040;
        public const int JOB_OBJECT_LIMIT_SCHEDULING_CLASS = 0x00000080;

        //
        // Extended Limits
        //
        public const int JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x00000100;
        public const int JOB_OBJECT_LIMIT_JOB_MEMORY = 0x00000200;
        public const int JOB_OBJECT_LIMIT_JOB_MEMORY_HIGH = JOB_OBJECT_LIMIT_JOB_MEMORY;
        public const int JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x00000400;
        public const int JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800;
        public const int JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000;
        public const int JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000;
        public const int JOB_OBJECT_LIMIT_SUBSET_AFFINITY = 0x00004000;
        public const int JOB_OBJECT_LIMIT_JOB_MEMORY_LOW = 0x00008000;

        public enum JOBOBJECTINFOCLASS
        {
            JobObjectBasicAccountingInformation = 1,
            JobObjectBasicLimitInformation,
            JobObjectBasicProcessIdList,
            JobObjectBasicUIRestrictions,
            JobObjectSecurityLimitInformation,  // deprecated
            JobObjectEndOfJobTimeInformation,
            JobObjectAssociateCompletionPortInformation,
            JobObjectBasicAndIoAccountingInformation,
            JobObjectExtendedLimitInformation,
            JobObjectJobSetInformation,
            JobObjectGroupInformation,
            JobObjectNotificationLimitInformation,
            JobObjectLimitViolationInformation,
            JobObjectGroupInformationEx,
            JobObjectCpuRateControlInformation,
            JobObjectCompletionFilter,
            JobObjectCompletionCounter,
            JobObjectReserved1Information = 18,
            JobObjectReserved2Information,
            JobObjectReserved3Information,
            JobObjectReserved4Information,
            JobObjectReserved5Information,
            JobObjectReserved6Information,
            JobObjectReserved7Information,
            JobObjectReserved8Information,
            JobObjectReserved9Information,
            JobObjectReserved10Information,
            JobObjectReserved11Information,
            JobObjectReserved12Information,
            JobObjectReserved13Information,
            JobObjectReserved14Information = 31,
            JobObjectNetRateControlInformation,
            JobObjectNotificationLimitInformation2,
            JobObjectLimitViolationInformation2,
            JobObjectCreateSilo,
            JobObjectSiloBasicInformation,
            JobObjectReserved15Information = 37,
            JobObjectReserved16Information,
            JobObjectReserved17Information,
            JobObjectReserved18Information,
            JobObjectReserved19Information = 41,
            JobObjectReserved20Information,
            MaxJobObjectInfoClass
        }