Any c# programmers about who have used deviceIoControl before?

kernow

Surfer of Carewaves
20 Year Member
Joined
Sep 1, 2001
Posts
31,815
If there is, I have a boggle I'd like to ask you about, regarding using deviceIoControl to return driveGeometry struct.

Cheers.
 

RabbitTroop

Mayor of Southtown, ,
20 Year Member
Joined
Dec 26, 2000
Posts
13,852
Hey Kernow, didn't know you'd migrated over to the evil-side of computing. ;) Most of my day to day, these days, is in C#, but I really haven't played with deviceIOcontrol at all. What are you working on, by the way? Is it a professional or personal project?
 

kernow

Surfer of Carewaves
20 Year Member
Joined
Sep 1, 2001
Posts
31,815
Just something to read and wrie raw images to flash media, like dd I guess, except in c# you have no access to raw devices so have to import functions from kernel32.dll. It's a nightmare. I don't use desktop Linux anymore and just installed visual studio to fuck about, really. Plenty of image writers out there already but I needed a project I'd use else I lose motivation.

Need to call deviceiocontrol to get the number of sectors and the call keeps failing, sigh.


You might be able to help me though, it's more passing a pointer to a struct into deviceiocontrol than the call itself. I'll post some code later.
 
Last edited:

kernow

Surfer of Carewaves
20 Year Member
Joined
Sep 1, 2001
Posts
31,815
Heres where I import the function from kernel32.dll
Code:
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern bool DeviceIoControl(IntPtr handle, uint dwIoControlCode, IntPtr lpInBuffer, int unInBufferSize, [Out] IntPtr lpOutBuffer, uint nOutBufferSize, uint lpBytesReturned, IntPtr lpOverlapped);

Heres my DISK_GEOMETRY struct
Code:
struct DISK_GEOMETRY
        {
            public long Cylinders;
            //public MEDIA_TYPE MediaType; // don't really want to add MEDIA_TYPE constants when they aren't needed here
            public int TracksPerCylinder;
            public int SectorsPerTrack;
            public int BytesPerSector;
        }

Heres a function which I try and call deviceiocontrol in, I'm getting a valid file/device handle from CreateFile as I half know how to use it, I can read an image from a USB flash device or sdcard perfectly fine, but at present I'm hard-coding the total amount of sectors when I need to probe it. getdiskinfo windows call doesn't give the right amount of sectors and neither does WMI. So I need to use deviceiocontrol to fill out a DISK_GEOMETRY struct which I can then calculate total_sectors * sector_size to give me the totaldevicebytes which I can use instead of my lame hardcoded value.

Code:
private void getDiskGeometry()
        {
            // takes a physicaldevice string and returns the number of bytes - 
            // maybe i'll build this into filling out the struct in the function below and get rid of getfreediskspace
            //long numSectors = 0;
            uint bytesReturned = 0;
            //DISK_GEOMETRY diskGeom = new DISK_GEOMETRY();
            //DISK_GEOMETRY diskGeom;
            var diskGeom = new DISK_GEOMETRY();


            /*using (*/
            var diskGeomPtr = new UnmanagedStruct<DISK_GEOMETRY>();//)
            //{
                diskGeomPtr.Data = diskGeom;
                //do something with diskGeomPtr.Handle here

                IntPtr p = IntPtr.Zero; // file handle for createfile and deviceIoControl
                bool result;

                //device, command, no input buffer(2args), output buffer, size of output buffer, bytes returned, synchronous I/O
                p = CreateFile("\\.\\PhysicalDrive1", GENERIC_READ | GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero);
                // this opens the device fine, don't need GENERIC_READ|GENERIC_WRITE if it's just for IOCTL operations

                // check if our file handle is valid
                if (p != null)
                    MessageBox.Show("device opened ok"); // valid
                else MessageBox.Show("device not opened ok"); // invalid

                // ok, it seems to be getting opened fine, so I need to find out why this DeviceIoControl call isn't
                result = DeviceIoControl(p, IOCTL_DISK_GET_DRIVE_GEOMETRY, IntPtr.Zero, 0, diskGeomPtr.Handle, diskGeomPtr.Size, bytesReturned, IntPtr.Zero);
                // closest I've got is error 87, wrong parameter or something. 

                MessageBox.Show(result.ToString(), "result is");
                MessageBox.Show(bytesReturned.ToString(), "bytes returned");


                if (result)
                {

                    MessageBox.Show(bytesReturned.ToString(), "bytes from deviceio call");
                    MessageBox.Show(diskGeom.BytesPerSector.ToString(), "bytes per sector");
                }
                else
                {
                   int error = Marshal.GetLastWin32Error();
                   MessageBox.Show("Error " + error.ToString(), "getlastwin32error");
                }

                CloseHandle(p);

            //} // end using
            //return numSectors;
        }


Heres the IOCTL I'm trying to use
Code:
internal const int IOCTL_DISK_GET_DRIVE_GEOMETRY = unchecked((int)0x00070000);


Someone gave me code for a class which gets a pointer from a struct. I'm not sure if it's helped but you can see me using at above. I've read hundreds of pages about using this deviceiocontrol call and tried different values and types for the initial function prototype.

errors
Code:
Warning	4	Field 'WindowsFormsApplication1.frmMainWindow.DISK_GEOMETRY.BytesPerSector' is never assigned to, and will always have its default value 0	C:\Users\Shaun\Desktop\IMGtool\IMGtool\Form1.cs	48	24	IMGtool

Warning	1	Field 'WindowsFormsApplication1.frmMainWindow.DISK_GEOMETRY.Cylinders' is never assigned to, and will always have its default value 0	C:\Users\Shaun\Desktop\IMGtool\IMGtool\Form1.cs	44	25	IMGtool

Warning	3	Field 'WindowsFormsApplication1.frmMainWindow.DISK_GEOMETRY.SectorsPerTrack' is never assigned to, and will always have its default value 0	C:\Users\Shaun\Desktop\IMGtool\IMGtool\Form1.cs	47	24	IMGtool

Warning	2	Field 'WindowsFormsApplication1.frmMainWindow.DISK_GEOMETRY.TracksPerCylinder' is never assigned to, and will always have its default value 0	C:\Users\Shaun\Desktop\IMGtool\IMGtool\Form1.cs	46	24	IMGtool


The call is currently returning error 6 which is invalid file handle (which is bollocks so I tend to not believe that error), and bytes returned = 0;
 
Last edited:

lantus360

Fu'un-Ken Master
Joined
Feb 25, 2012
Posts
1,527
your problem is your file handle 'p' returns -1

your check for p is if its not null but it should be > 0
 

lantus360

Fu'un-Ken Master
Joined
Feb 25, 2012
Posts
1,527
change

Code:
CreateFile("\\.\\PhysicalDrive1".....

to

Code:
CreateFile("\\\\.\\PhysicalDrive1"

your welcome
 

kernow

Surfer of Carewaves
20 Year Member
Joined
Sep 1, 2001
Posts
31,815
The createfile call works fine, the device is opened, I build a physicaldevice string in a read() function a few hundred lines above to actually read raw from the device, and it works fine, so it's not something as simple as specifying a wrong physicaldevice string.
 

lantus360

Fu'un-Ken Master
Joined
Feb 25, 2012
Posts
1,527
'p' was returning -1. I fail to see how it could have ever worked properly. The first arg you pass into CreateFile is incorrect

in any case my code works..i get the correct bytes per sectors back. Here is the entire source for you. Enjoy


Code:
using System;
using System.Diagnostics;
using System.Collections;
using System.Runtime.InteropServices;


namespace DiskGeometryTest
{
    class Program
    {

        //
        // CreateFile constants
        //
        const uint FILE_SHARE_READ = 0x00000001;
        const uint FILE_SHARE_WRITE = 0x00000002;
        const uint FILE_SHARE_DELETE = 0x00000004;
        const uint OPEN_EXISTING = 3;

        const uint GENERIC_READ = (0x80000000);
        const uint GENERIC_WRITE = (0x40000000);

        const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
        const uint FILE_READ_ATTRIBUTES = (0x0080);
        const uint FILE_WRITE_ATTRIBUTES = 0x0100;

        internal const int IOCTL_DISK_GET_DRIVE_GEOMETRY = unchecked((int)0x00070000);


        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr CreateFile(
            string lpFileName,
            uint dwDesiredAccess,
            uint dwShareMode,
            IntPtr lpSecurityAttributes,
            uint dwCreationDisposition,
            uint dwFlagsAndAttributes,
            IntPtr hTemplateFile);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern int CloseHandle(IntPtr hObject);

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

        struct DISK_GEOMETRY
        {
            public long Cylinders;
            //public MEDIA_TYPE MediaType; // don't really want to add MEDIA_TYPE constants when they aren't needed here
            public int TracksPerCylinder;
            public int SectorsPerTrack;
            public int BytesPerSector;
        }

        static void getDiskGeometry()
        {
            // takes a physicaldevice string and returns the number of bytes - 
            // maybe i'll build this into filling out the struct in the function below and get rid of getfreediskspace
            //long numSectors = 0;
            uint bytesReturned = 0;
 
            var diskGeom = new DISK_GEOMETRY();
            var geomp = Marshal.AllocHGlobal(Marshal.SizeOf(diskGeom));
            Marshal.StructureToPtr(diskGeom, geomp, false);
 

            IntPtr p = IntPtr.Zero; // file handle for createfile and deviceIoControl
            bool result;

            //device, command, no input buffer(2args), output buffer, size of output buffer, bytes returned, synchronous I/O
            p = CreateFile("\\\\.\\PhysicalDrive1", GENERIC_READ | GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero);
            // this opens the device fine, don't need GENERIC_READ|GENERIC_WRITE if it's just for IOCTL operations

            // check if our file handle is valid
            if (p != null)
                Console.WriteLine("device opened ok"); // valid
            else Console.WriteLine("device not opened ok"); // invalid

            // ok, it seems to be getting opened fine, so I need to find out why this DeviceIoControl call isn't
            result = DeviceIoControl(p, IOCTL_DISK_GET_DRIVE_GEOMETRY, IntPtr.Zero, 0,  geomp, (uint)Marshal.SizeOf(typeof(DISK_GEOMETRY)), ref bytesReturned, IntPtr.Zero);
            // closest I've got is error 87, wrong parameter or something. 
            var ob = (DISK_GEOMETRY)Marshal.PtrToStructure(geomp, typeof(DISK_GEOMETRY));
            Console.WriteLine(result.ToString(), "result is");
            Console.WriteLine(bytesReturned.ToString(), "bytes returned");


            if (result)
            {

                Console.WriteLine(bytesReturned.ToString(), "bytes from deviceio call");
                Console.WriteLine(ob.BytesPerSector.ToString(), "bytes per sector");
            }
            else
            {
                int error = Marshal.GetLastWin32Error();
                Console.WriteLine("Error " + error.ToString(), "getlastwin32error");
            }

            CloseHandle(p);

            //} // end using
            //return numSectors;
        }

        static void Main(string[] args)
        {


            getDiskGeometry();

        }
    }
}
 

kernow

Surfer of Carewaves
20 Year Member
Joined
Sep 1, 2001
Posts
31,815
Hah, cheers man, I'll give it a go later, thanks
 

kernow

Surfer of Carewaves
20 Year Member
Joined
Sep 1, 2001
Posts
31,815
It's still not working for me. 0 bytes returned, error 6, false

Code:
private void getDiskGeometry()
        {
            // takes a physicaldevice string and returns the number of bytes - 
            // maybe i'll build this into filling out the struct in the function below and get rid of getfreediskspace
            //long numSectors = 0;
            uint bytesReturned = 0;
            var diskGeom = new DISK_GEOMETRY();
            var geomp = Marshal.AllocHGlobal(Marshal.SizeOf(diskGeom));
            Marshal.StructureToPtr(diskGeom, geomp, false);
            IntPtr p = IntPtr.Zero; // file handle for createfile and deviceIoControl
            bool result;

            p = CreateFile("\\\\.\\PhysicalDrive1", GENERIC_READ | GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero);
            // check if our file handle is valid
            if (p != null)
                MessageBox.Show("device opened ok"); // valid
            else MessageBox.Show("device not opened ok"); // invalid

            // ok, it seems to be getting opened fine, so I need to find out why this DeviceIoControl call isn't
            result = DeviceIoControl(p, IOCTL_DISK_GET_DRIVE_GEOMETRY, IntPtr.Zero, 0, geomp, (uint)Marshal.SizeOf(typeof(DISK_GEOMETRY)), ref bytesReturned, IntPtr.Zero);
            var ob = (DISK_GEOMETRY)Marshal.PtrToStructure(geomp, typeof(DISK_GEOMETRY));
            
            MessageBox.Show(result.ToString(), "result is");
            MessageBox.Show(bytesReturned.ToString(), "bytes returned");

            if (result)
            {
                MessageBox.Show(bytesReturned.ToString(), "bytes from deviceio call");
                MessageBox.Show(ob.BytesPerSector.ToString(), "bytes per sector");
            }
            else
            {
                int error = Marshal.GetLastWin32Error();
                MessageBox.Show("Error " + error.ToString(), "getlastwin32error");
                }

                CloseHandle(p);

            //} // end using
            //return numSectors;
        }


link to project: http://www.sendspace.com/file/9y4z3t
 
Last edited:

kernow

Surfer of Carewaves
20 Year Member
Joined
Sep 1, 2001
Posts
31,815
Still getting these also:
Code:
Warning	4	Field 'WindowsFormsApplication1.frmMainWindow.DISK_GEOMETRY.BytesPerSector' is never assigned to, and will always have its default value 0	C:\Users\Shaun\Desktop\IMGtool\IMGtool\Form1.cs	48	24	IMGtool

Warning	1	Field 'WindowsFormsApplication1.frmMainWindow.DISK_GEOMETRY.Cylinders' is never assigned to, and will always have its default value 0	C:\Users\Shaun\Desktop\IMGtool\IMGtool\Form1.cs	44	25	IMGtool

Warning	3	Field 'WindowsFormsApplication1.frmMainWindow.DISK_GEOMETRY.SectorsPerTrack' is never assigned to, and will always have its default value 0	C:\Users\Shaun\Desktop\IMGtool\IMGtool\Form1.cs	47	24	IMGtool

Warning	2	Field 'WindowsFormsApplication1.frmMainWindow.DISK_GEOMETRY.TracksPerCylinder' is never assigned to, and will always have its default value 0	C:\Users\Shaun\Desktop\IMGtool\IMGtool\Form1.cs	46	24	IMGtool

:crying:

Well, I was two seconds ago and now they seem to have disappeared.

edit: now they're back

*LIVEBLOG*
 
Last edited:

lantus360

Fu'un-Ken Master
Joined
Feb 25, 2012
Posts
1,527
they are just warnings, i get them too

unsure why it doesnt work for you but ill take a look at your project when i get a sec

edit: what kind of device are you attempting to connect to?
 

kernow

Surfer of Carewaves
20 Year Member
Joined
Sep 1, 2001
Posts
31,815
An 8MB panasonic SDcard. I was reading from it fine and making a perfect image using safefilehandles but for some reason when I turned to using readFile() it's not working anymore, reads are failing. If you could take a look at the read loop that would be good also.

(number of sectors is hardcoded in one of the disk detection functions - hence the main point I'm trying to probe using deviceiocontrol), multiplied by 512 so you'll only ever get 6,799,360 bytes from any flash media you try read from. (that's if the fucking read function worked which it was a couple days ago).
 
Last edited:

kernow

Surfer of Carewaves
20 Year Member
Joined
Sep 1, 2001
Posts
31,815
lantuscodetest.png


Compiled your code as a separate project.
This is just taking the piss now. Gotta be something regarding my system surely. But what?

What device were you using? your main hard disk? or? Maybe this ioctl code only works on fixed disks.
 

lantus360

Fu'un-Ken Master
Joined
Feb 25, 2012
Posts
1,527
tried it with a USB flash drive - as mentioned no issues...wonder if its a security thing
 
Top