Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > .NET для новичков > ZwQuerySystemInformation && C#


Автор: CL0NE 9.9.2009, 03:29
Синтаксис данной функции (в дополнение к ссылке на мсдн - http://msdn.microsoft.com/en-us/library/ms725506(VS.85).aspx): 
Цитата
Код
NTSTATUS WINAPI ZwquoteuerySystemInformation(
  __in       SYSTEM_INFORMATION_CLASS SystemInformationClass,
  __inout    PVOID SystemInformation,
  __in       ULONG SystemInformationLength,
  __out_opt  PULONG ReturnLength
);

 
Привел я ее к такому виду в своем коде:
Код

[DllImport("Ntdll.dll", EntryPoint="ZwquoteuerySystemInformation")]
static extern Int32 APIquoteuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass,
               IntPtr SystemInformation,
               int SystemInformationLength,
               out long ReturnLength);


Первый параметр указывает на тип получаемой информации:

Цитата

SystemInformationClass 
The type of system information to be retrieved. This parameter can be one of the following values from the SYSTEM_INFORMATION_CLASS enumeration type.



сделал его енумерейшном:
Код

        public enum SYSTEM_INFORMATION_CLASS
        {
            SystemBasicInformation = 0x02c,
            SystemPerformanceInformation = 0x138,
            SystemTimeOfDayInformation = 0x020,
            SystemProcessInformation = 0x088,
            SystemProcessorPerformanceInformation = 0x030,
            SystemInterruptInformation = 0x018,
            SystemExceptionInformation = 0x010
       } 

Ради теста использовал первый вариант, самый простой:
Цитата
SystemBasicInformation

The number of processors in the system in a SYSTEM_BASIC_INFORMATION structure. Use the GetSystemInfo function instead.


Второй параметр - 
Цитата
SystemInformation
A pointer to a buffer that receives the requoteuested information. The size and structure of this information varies depending on the value of the SystemInformationClass parameter, as indicated in the following table.
 (лень переводить, да и, думаю, те, кто сможеть помочь, в состоянии читать англицкий текст)

Следовательно, при первом варианте получим структуру:

Цитата
SYSTEM_BASIC_INFORMATION

When the SystemInformationClass parameter is SystemBasicInformation, the buffer pointed to by the SystemInformation parameter should be large enough to hold a single SYSTEM_BASIC_INFORMATION structure having the following layout: 

Код
typedef struct _SYSTEM_BASIC_INFORMATION {
    BYTE Reserved1[24];
    PVOID Reserved2[4];
    CCHAR NumberOfProcessors;
} SYSTEM_BASIC_INFORMATION;



The NumberOfProcessors member contains the number of processors present in the system. Use GetSystemInfo instead to retrieve this information.

The other members of the structure are reserved for internal use by the operating system.


Привел ее к "надлежащему" виду:


Код

[StructLayout(LayoutKind.Sequoteuential)]
public struct SYSTEM_BASIC_INFORMATION {
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
      public byte[] Reserved1;
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
      public IntPtr[] Reserved2;
      public Char NumberOfProcessors;
}


При вызове функция возвращает код NTSATUS

Цитата
Код

//STATUS_SUCCESS              = NTStatus($00000000);
//STATUS_ACCESS_DENIED        = NTStatus($C0000022);
//STATUS_INFO_LENGTH_MISMATCH = NTStatus($C0000004);
//SEVERITY_ERROR              = NTStatus($C0000000);


Первый при удачном вызове, третий - при слишком маленьком буфере.

Третий параметр у функции - размер выделенного нами буфера, четвертый - обьем байт, записанных в буфер.

Мой тестовый код, попытка использовать данную функцию:


Код
long formal;
int size = Marshal.SizeOf(typeof(SYSTEM_BASIC_INFORMATION));
IntPtr ptr = Marshal.AllocHGlobal(size); 

Console.WriteLine("NTSTATUS: " + APIquoteuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemBasicInformation, ptr, size, out formal).ToString("X"));
            
SYSTEM_BASIC_INFORMATION INFO = ((SYSTEM_BASIC_INFORMATION)Marshal.PtrToStructure(ptr, typeof(SYSTEM_BASIC_INFORMATION)));
Console.WriteLine(INFO.NumberOfProcessors);
Console.WriteLine(formal);


Ну а теперь, самое "вкусное" (смысл топика smile):
  • Если я неправильно привел к "надлежащему виду" сигнатуру функции и сами структуры - поправьте, пожалуйста, буду очень признателен smile
  • Проблема: при вызове функция возвращает STATUS_INFO_LENGTH_MISMATCH. с чем это может быть связано?

Автор: mihryak 9.9.2009, 21:01
а откуда ты взял значения энума SYSTEM_INFORMATION_CLASS?
везде, где попадались, SystemBasicInformation был равен 0
например, http://processhacker.sourceforge.net/hacking/structs.php#systembasicinformation
если взять оттуда и структуру
Код

[StructLayout(LayoutKind.Sequential)]
struct SYSTEM_BASIC_INFORMATION
{
    public int Reserved;
    public int TimerResolution;
    public int PageSize; // 4096 (4kB) on 32-bit systems, 8192 (8kB) on 64-bit systems
    public int NumberOfPhysicalPages; // pages of physical memory
    public int LowestPhysicalPageNumber;
    public int HighestPhysicalPageNumber;
    public int AllocationGranularity;
    public int MinimumUserModeAddress;
    public int MaximumUserModeAddress;
    public int ActiveProcessorsAffinityMask;
    public byte NumberOfProcessors;
}

то на домашней висте успешно выдалось 2 процессора
а вот на рабочем 2003 сервере не прокатило
тем не менее, и там, и там по коду 0x02c мне выдавался требуемый размер памяти, равный 172, ни из твоего варианта структуры, ни из моего такой размер не получить, у нас 44
так, кстати, я и убедился, что 0 - подходящее значение, при нём и при 62(0x3E) выдавалось 44 требуемых байта (при 62 те же значения полей структуры). ни одно другое число из интервала 0..99999999 44 не дало

как бы то ни было, ZW-функции не предназначены для использования вне внутренностей системы, советую поискать альтернативный вариант. тот же МСДН рекомендует для получения числа процессоров http://msdn.microsoft.com/en-us/library/ms724381(VS.85).aspx

Автор: CL0NE 10.9.2009, 00:13
Цитата

как бы то ни было, ZW-функции не предназначены для использования вне внутренностей системы, советую поискать альтернативный вариант. тот же МСДН рекомендует для получения числа процессоров GetSystemInfo

Цитата

Ради теста использовал первый вариант, самый простой:

Вообще-то мне нужа функция ради SystemProcessorPerformanceInformation. Ибо функция GetSystemTimes, предлагаемая, как альтернатива, возвращает суммарную загрузку процессора. Так же само и WMI (который я использовал до этого, причем, как на каком-то форуме упоминалось, добавляет загрузку процессора на 10% Оо). А хочется на каждое ядро smile

Цитата

а откуда ты взял значения энума SYSTEM_INFORMATION_CLASS?

Только что, погуглив, нашел где я их взял. http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/System%20Information/SYSTEM_INFORMATION_CLASS.html#SystemBasicInformation
о_О Спросонья я почемуто посчитал
Цитата

Buffer size : 0x02C 
 значением...

Мораль: никогда не пишите код на сонную голову! smile

mihryak спасибо огромное, все работает!

Автор: CL0NE 13.9.2009, 05:39
все. да не все smile как оказалось для второго ядра не выводит правильную загрузку. выводит заоблачные цифры от -1ххххххх до 1хххххххх smile
Это при использовании SystemProcessorPerformanceInformation

Цитата


[StructLayout(LayoutKind.Sequential)]
        public struct SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
        {
            public long IdleTime;
            public long KernelTime;
            public long UserTime;
            public long Reserved1;
            public ulong Reserved2;
        }



Код

[S][StructLayout(LayoutKind.Sequential)]
        public struct SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
        {
            public Int32 IdleTime;
            public Int32 KernelTime;
            public Int32 UserTime;
            public Int32 Reserved1;
            public UInt32 Reserved2;
        }[/S]


Первое поле - время, проведенное процессором в режиме бездействия, измеряется в тиках. Берем определенный промежуток (n tick, тик- 100 наносекунд, если не ошибаюсь). Замеряем время простоя процессора в начале промежутка и в конце. Делим на время промежутка и получаем процент бездействия. Отняв от единицы - получим процент загрузки smile.
Цитата
1 - (idleCurrent - idleOld)/(tickNow - tickOld)

что ж, будем дальше ломать код smile

p.s.: сделал поправку, т.к. упустил момент о размерах типов в С++ (long - 32-bit signed integer), C# (64-bit signed integer.) Теперь появилась проблема... постоянно выводит загрузку 100% оО

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)