Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Передача массивов в структурах и Marshal  (Прочитано 4341 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« : 11-10-2011 18:25 » 

Задача заключалась в получении списка процессов системы. Для этого в WinAPI существует TlHelp32.h, где определены функции Process32First и Process32Next, каковые в качестве параметра принимают структуру PROCESSENTRY32.

Сама эта структура, в общем-то, обычная, но есть внутри неё массив символов, хранящий название процесса. Длина массива составляет MAX_PATH.

Как известно, в .NET массивы - ссылочные типы, поэтому структуру просто так не объявить: вместо цепочки символов там будет указатель, что в данном случае не надо. Но эта проблема обходится при помощи соответствующего атрибута.

Итак, на C# усечённый тестовый вариант выглядит следующим образом:
Код: (C#)
    class ClrImport
    {
            const int MaxPath = 260;
            const int Th32CsSnapProcess = 0x00000002;

            private struct ProcessEntry32
            {
                    public uint dwSize;
                    public uint cntUsage;
                    public uint th32ProcessID;
                    public uint th32DefaultHeapID;
                    public uint th32ModuleID;
                    public uint cntThreads;
                    public uint th32ParentProcessID;
                    public uint pcPriClassBase;
                    public uint dwFlags;
                    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ClrImport.MaxPath)]
                    public string szExeFile;
                    public uint th32MemoryBase;
                    public uint th32AccessKey;
            };
       
            [DllImport("kernel32.dll", CallingConvention = CallingConvention.Winapi)]
            private static extern bool Process32First(IntPtr hSnapshot, ref ClrImport.ProcessEntry32 lppe);

            [DllImport("kernel32.dll", CallingConvention = CallingConvention.Winapi)]
            private static extern IntPtr CreateToolhelp32Snapshot(UInt32 dwFlags, UInt32 th32ProcessID);

            [DllImport("kernel32.dll", CallingConvention = CallingConvention.Winapi)]
            private static extern bool CloseHandle(IntPtr hObject);

            public static void Test()
            {
                    IntPtr snapshotHandle = ClrImport.CreateToolhelp32Snapshot(ClrImport.Th32CsSnapProcess, 0);

                    ClrImport.ProcessEntry32 processEntry = new ClrImport.ProcessEntry32();
                    processEntry.dwSize = Convert.ToUInt32(Marshal.SizeOf(typeof(ClrImport.ProcessEntry32)));
                    ClrImport.Process32First(snapshotHandle, ref processEntry);
       
                    ClrImport.CloseHandle(snapshotHandle);
            }

    }
Мучался я с ним полдня.

Феномен заключается в том, что значения полей структуры начинают "разъезжаться". Не помогает ни замена типов с uint на явный UInt32, ни явное указание кодировки символов, ни явный переход на Unicode, ни Explicit-декларация с явным указанием offset в байтах для каждого поля.

Заменив string на char[] чисто эмпирически установил, что начало строки с названием процесса "уезжает" вперёд на 8 символов (или 16 байт, несмотря на то, что данные поступают в ANSI-кодировке).

Феномен не зависит ни от версии .NET, ни от режима Debug/Release. Однако после переписывания этого кода один в один на C++.NET (с поправкой на синтаксис) феномен исчезает. Кроме того, он наблюдается в проектах VS2005 и VS2008, но отсутствует в проектах VS2010.

Как оказалось, причиной является конфигурация сборки: "Any CPU". Как только конфигурация устанавливается в "x86" - всё становится нормальным.

Однако другие структуры с полями простых типов (без массивов внутри) нормально работают и в "Any CPU".

Видимо, в Marshal какой-то баг, касающийся передачи именно внедрённых в структуры массивов.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines