Проблема с маршалом - PullRequest
       16

Проблема с маршалом

0 голосов
/ 25 ноября 2010

Сегодня я проходил урок по Win32, чтобы поработать над некоторыми необходимыми улучшениями. Я застрял на моем коде геометрии диска. На

var ob = (DiskGeometry) Marshal.PtrToStructure (geomp, typeof (DiskGeometry));

строка, она продолжает выдавать исключение ..

Попытка чтения или записи в защищенную память. Это часто указывает на то, что другая память повреждена.

Мой код ..

        if (Handle.IsInvalid)
        {
            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            return new DiskGeometry();
        }
        var geom = new DiskGeometry();
        var geomp = Marshal.AllocHGlobal(Marshal.SizeOf(geom));
        Marshal.StructureToPtr(geom, geomp, false);
        uint returnedBytes;
        if (!DeviceIoControl(Handle, (uint) IOCTL_CONTROL_CODE_CONSTANTS.IOCTL_DISK_GET_DRIVE_GEOMETRY, IntPtr.Zero, 0, ref geomp, (uint)Marshal.SizeOf(typeof(DiskGeometry)), out returnedBytes, IntPtr.Zero))
        {
            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            return new DiskGeometry();
        }
        var ob = (DiskGeometry)Marshal.PtrToStructure(geomp, typeof (DiskGeometry));

Что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 25 ноября 2010

При маршалинге из неуправляемой памяти в управляемую память " Попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена. " Ошибки являются хорошим признаком того, соответствующие разрешения для доступа к ячейке памяти, указанной в данной ячейке указателя.

Это определения, используемые для проверки правильности вашего кода:

[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode,
        IntPtr lpInBuffer, uint nInBufferSize,
        IntPtr lpOutBuffer, uint nOutBufferSize,
        out uint lpBytesReturned, IntPtr lpOverlapped);

(другой код опущен)

IntPtr Handle = CreateFile("\\\\.\\PhysicalDrive0", (EFileAccess)0, EFileShare.Read | EFileShare.Write, IntPtr.Zero, ECreationDisposition.OpenExisting, (EFileAttributes)0, IntPtr.Zero);

            var geom = new DiskGeometry();
            var geomp = Marshal.AllocHGlobal(Marshal.SizeOf(geom));
            uint returnedBytes = 0;

            Marshal.StructureToPtr(geom, geomp, false);

            if (!DeviceIoControl(Handle, (uint)IOCTL_DISK_GET_DRIVE_GEOMETRY, IntPtr.Zero, 0, geomp, 
                (uint)Marshal.SizeOf(typeof(DiskGeometry)), 
                out returnedBytes, 
                IntPtr.Zero))
            {
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
                return;
            }

            var ob = (DiskGeometry)Marshal.PtrToStructure(geomp, typeof(DiskGeometry));
0 голосов
/ 25 ноября 2010

Попробуйте что-то вроде этого:

//you don't need to instantiate the managed type before this
var geomp = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DiskGeometry)));

//remove this
Marshal.StructureToPtr(geom, geomp, false);

Вам просто нужно выделить блок памяти, который DiskIoControl будет заполнять неуправляемым типом. После того, как указатель ссылается на эти данные, вы перенаправляете их в управляемый тип.

Вы также можете проверить Marshal.GetlastWin32Error() для ERROR_INSUFFICIENT_BUFFER после вызова DeviceIoControl и убедиться, что returnedBytes == Marshal.SizeOf(typeof(DiskGeometry))

...