Erreur DeviceIOControl : Fonction Incorrecte

Résolu
tuxama Messages postés 6 Date d'inscription lundi 28 janvier 2008 Statut Membre Dernière intervention 18 février 2008 - 9 févr. 2008 à 20:45
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 - 19 févr. 2008 à 06:34
Bonsoir,

Je tente de récupérer quelques caractéristiques de mon disque physique principal.
DeviceIOControl me retourne une erreur '1' : Fonction Incorrecte
Malgrès différents essais je ne parviens pas à trouver de solution.

Quelqu'un a t-il une idée, voir même LA solution ?
Merci de votre aide.

        private void getPhysicalDrive( ) {
            IntPtr handle = IntPtr.Zero;
            uint ndevice = 0;

            Win32Functions.CHANGER_PRODUCT_DATA cpd = new Win32Functions.CHANGER_PRODUCT_DATA( );
            IntPtr pcpd = Marshal.AllocHGlobal( Marshal.SizeOf( cpd ) );
            Marshal.StructureToPtr( cpd, pcpd, true );

            do {
                string s = "\\\\.\\PHYSICALDRIVE" + ndevice.ToString( );
                Console.WriteLine( s );

                handle = Win32Functions.CreateFile( s,
                                                    0,
                                                    Win32Functions.FILE_SHARE_WRITE,
                                                    IntPtr.Zero,
                                                    Win32Functions.OPEN_EXISTING,
                                                    0,
                                                    IntPtr.Zero );
                if ( handle == IntPtr.Zero ) {
                    Console.WriteLine( "not Found" );
                }
                else {
                    uint nBytes = 0;
                    if ( Win32Functions.DeviceIoControl( handle,
                                                         Win32Functions.IOCTL_CHANGER_GET_PRODUCT_DATA,
                                                         IntPtr.Zero, 0,
                                                         pcpd, ( uint )Marshal.SizeOf( pcpd ),
                                                         ref nBytes,
                                                         IntPtr.Zero )
                                                         > 0 ) {

                        Console.WriteLine( cpd.ProductId );
                        Console.WriteLine( cpd.DeviceType );
                    }
                    else {
                        Int32 err = Marshal.GetLastWin32Error( );
                        Console.WriteLine( "The last Win32 Error was: " + err );
                        Console.WriteLine( GetLastWin32ErrorMessage( Marshal.GetLastWin32Error( ) ) );

                    }
                    Marshal.FreeHGlobal( pcpd );
                    if ( !Win32Functions.CloseHandle( handle ) ) {
                        Console.WriteLine( "CloseHandle code erreur: {0}", Marshal.GetLastWin32Error( ) );
                    }
                    ndevice++;
                }
            } while ( handle == IntPtr.Zero );
        }

        static void Main( string[ ] args ) {
            RawDiskAccess ld = new RawDiskAccess( );
            ld.getPhysicalDrive( );
        }
    }

////////////////////////////////////////////////////////////////

namespace RawDeviceAccess.Disk {
    /// <summary>
    /// Classe Wrapper pour des fonctions Win32 et les structures associées.
    /// </summary>
    internal class Win32Functions {
        // Types d'accès
        public const uint GENERIC_READ = 0x80000000;
        public const uint GENERIC_WRITE = 0x40000000;
        public const uint GENERIC_EXECUTE = 0x20000000;
        public const uint GENERIC_ALL = 0x10000000;

        // Partages
        public const uint FILE_SHARE_READ = 0x00000001;
        public const uint FILE_SHARE_WRITE = 0x00000002;
        public const uint FILE_SHARE_DELETE = 0x00000004;

        // Dispositions
        public const uint CREATE_NEW = 1;
        public const uint CREATE_ALWAYS = 2;
        public const uint OPEN_EXISTING = 3;
        public const uint OPEN_ALWAYS = 4;
        public const uint TRUNCATE_EXISTING = 5;

        //
        public const uint IOCTL_CHANGER_GET_PRODUCT_DATA = 0x00000002; //0x0002;

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

        [System.Runtime.InteropServices.DllImport( "kernel32", SetLastError = true, CharSet = CharSet.Auto )]
        public extern static bool CloseHandle( IntPtr handle );

        [System.Runtime.InteropServices.DllImport( "Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto )]
        public extern static int DeviceIoControl(
            IntPtr hDevice,
            uint IoControlCode,
            IntPtr lpInBuffer,
            uint InBufferSize,
            IntPtr lpOutBuffer,
            uint nOutBufferSize,
            ref uint lpBytesReturned,
            IntPtr lpOverlapped
        );

        [StructLayout( LayoutKind.Sequential, CharSet = CharSet.Auto )]
        public struct CHANGER_PRODUCT_DATA {
            [MarshalAs( UnmanagedType.ByValArray, SizeConst = 255 )]
            public byte[ ] VendorId;
            [MarshalAs( UnmanagedType.ByValArray, SizeConst = 255 )]
            public byte[ ] ProductId;
            [MarshalAs( UnmanagedType.ByValArray, SizeConst = 255 )]
            public byte[ ] Revision;
            [MarshalAs( UnmanagedType.ByValArray, SizeConst = 255 )]
            public byte[ ] SerialNumber;
            [MarshalAs( UnmanagedType.ByValArray, SizeConst = 255 )]
            public byte[ ] DeviceType;
        };
    }
}

L'éternité c'est long surtout vers la fin...[Insert_Emoticon%28%27/imgs2/smile_wink.gif%27%29; ]

11 réponses

cs_coq Messages postés 6349 Date d'inscription samedi 1 juin 2002 Statut Membre Dernière intervention 2 août 2014 101
10 févr. 2008 à 01:29
Salut,

A vue de nez ta définition de la valeur de IOCTL_CHANGER_GET_PRODUCT_DATA me parait louche.

/*
coq
MVP Visual C#
CoqBlog
*/
3
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
10 févr. 2008 à 13:31
Salut, DeviceIoControl renvoie un bool sur 32 bits, et 1 c'est TRUE.
3
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
10 févr. 2008 à 18:38
Oui je pense que c'est ça, les disques ne doivent pas être considérés comme des "changer". J'arrive à obtenir les réultats des codes DISK mais pas avec les code CHANGER.

( Exécuter en tant qu'administrateur ).

using System;
using System.Runtime.InteropServices;


namespace DeviceIO // compile with -unsafe
{
    internal class Program /*** Run as Administrator !! ***/
    {
        //[ StructLayout( LayoutKind.Sequential ) ]
        //private unsafe struct CHANGER_PRODUCT_DATA
        //{
        //    public fixed byte VendorId8;
        //    public fixed byte ProductId16;
        //    public fixed byte Revision4;
        //    public fixed byte SerialNumber32;
        //    byte DeviceType;
        //}


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


        [ DllImport( "kernel32.dll", SetLastError = true ) ]
        [ return: MarshalAs( UnmanagedType.Bool ) ]
        private static extern bool CloseHandle( IntPtr hObject );


        [ DllImport( "kernel32", SetLastError = true ) ]
        [ return: MarshalAs( UnmanagedType.Bool ) ]
        private static extern bool DeviceIoControl
        (
            IntPtr hDevice,
            uint dwIoControlCode,
            IntPtr lpInBuffer,
            uint nInBufferSize,
            IntPtr lpOutBuffer,
            uint nOutBufferSize,
            out uint lpBytesReturned,
            IntPtr lpOverlapped
        );


        [ DllImport( "kernel32.dll", CharSet = CharSet.Auto/*, SetLastError = true */ ) ]
        private static extern uint FormatMessage
        (
            uint dwFlags,
            IntPtr lpSource,
            uint dwMessageId,
            uint dwLanguageId,
            ref IntPtr lpBuffer,
            uint nSize,
            IntPtr Arguments
        );


        public static string GetLastWin32ErrorMessage( int errorCode )
        {
            IntPtr buffer = IntPtr.Zero;


            uint cnt = FormatMessage
            (
                0x00000100 |
                0x00000200 |
                0x00001000,
                IntPtr.Zero,
                ( uint )errorCode,
                0,
                ref buffer,
                0,
                IntPtr.Zero
            );


            if ( cnt 0 || buffer IntPtr.Zero )
                return String.Format( "Unknown error: {0}.", errorCode );


            string errorMessage = Marshal.PtrToStringAuto( buffer, ( int )cnt );
            Marshal.FreeHGlobal( buffer ); // LocalFree.


            return errorMessage;
        }


        private const string DISK_NAME = @"[file://\\.\PhysicalDrive0 \\.\PhysicalDrive0]"; // @"[file://\\.\C \\.\C]:"
        private const uint GENERIC_READ = 0x80000000;
        private const uint OPEN_EXISTING = 3;
        private const uint FILE_SHARE_READ = 0x00000001;
        private const uint FILE_SHARE_WRITE = 0x00000002;
        //private const uint IOCTL_CHANGER_GET_PRODUCT_DATA =
        //    ( ( 0x00000030 ) << 16 ) | ( ( 0x0001 ) << 14 ) | ( ( 0x0002  ) << 2 ) | ( 0x00 );
        private const uint IOCTL_DISK_GET_LENGTH_INFO =
            ( ( 0x00000007 ) << 16 ) | ( ( 0x0001 ) << 14 ) | ( ( 0x0017  ) << 2 ) | ( 0x00 );


        private static readonly IntPtr INVALID_HANDLE_VALUE = ( IntPtr )( -1 );


        private static unsafe void Main( )
        {
            IntPtr hDevice = CreateFile( DISK_NAME, GENERIC_READ,
                FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero );


            if ( hDevice == INVALID_HANDLE_VALUE )
            {
                Console.WriteLine( GetLastWin32ErrorMessage( Marshal.GetLastWin32Error( ) ) );
                goto exit;
            }


            Console.WriteLine( "Disk Handle: OK ..\r\n" );


            uint lpBytesReturned = 0U;
            long length  = 0L; // GET_LENGTH_INFORMATION.Length


            bool res = DeviceIoControl( hDevice, IOCTL_DISK_GET_LENGTH_INFO,
                IntPtr.Zero, 0, ( IntPtr )( &length ), sizeof( long ), out lpBytesReturned, IntPtr.Zero );


            if ( !res )
            {
                Console.WriteLine( GetLastWin32ErrorMessage( Marshal.GetLastWin32Error( ) ) );
                goto exit;
            }


            Console.WriteLine( "Disk Length: {0}Go / {1}Gio",
                ( uint )( length / Math.Pow( 1000, 3 ) ), ( uint )( length / Math.Pow( 1024, 3 ) )  );


            exit:


            Console.ReadLine( ); // Wait.


            if ( hDevice != IntPtr.Zero )
            {
                CloseHandle( hDevice );
                //hDevice = IntPtr.Zero;
            }
        }
    }
}
3
cs_wizad Messages postés 355 Date d'inscription samedi 30 octobre 2004 Statut Membre Dernière intervention 14 avril 2009
9 févr. 2008 à 22:41
A vu de nez (oui un nez peut voire suffit de bien l'éduquer) je dirais que tu te complique beaucoup <strike>trop</strike> la vie. A priori tu devrais plutôt passer par la couche WMI qui est faite pour ça (entre autre) et qui est accéssible en C# sans devoir wrapper divers couche native.

Pour info :
http://www.geekpedia.com/tutorial233_Getting-Disk-Drive-Information-using-WMI-and-Csharp.html
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
tuxama Messages postés 6 Date d'inscription lundi 28 janvier 2008 Statut Membre Dernière intervention 18 février 2008
10 févr. 2008 à 11:24
L'objectif n'est pas ici de répondre à une problématique projet, mais à me former.
Je tente donc de découvrir l'utilisation des DLL natives.

L'éternité c'est long surtout vers la fin...[Insert_Emoticon%28%27/imgs2/smile_wink.gif%27%29; ]
0
tuxama Messages postés 6 Date d'inscription lundi 28 janvier 2008 Statut Membre Dernière intervention 18 février 2008
10 févr. 2008 à 11:28
J'ai revu la définition de IOCTL_CHANGER_GET_PRODUCT_DATA c'était une des erreurs. Mais il doit en rester d'autre...

// CHANGER
ChangerBase = EFileDevice.Changer,
ChangerGetParameters = ( ChangerBase << 16 ) | ( 0x0000 << 2 ) | EMethod.Buffered | ( FileAccess.Read << 14 ),
ChangerGetStatus = ( ChangerBase << 16 ) | ( 0x0001 << 2 ) | EMethod.Buffered | ( FileAccess.Read << 14 ),
ChangerGetProductData = ( ChangerBase << 16 ) | ( 0x0002 << 2 ) | EMethod.Buffered | ( FileAccess.Read << 14 ),
ChangerSetAccess = ( ChangerBase << 16 ) | ( 0x0004 << 2 ) | EMethod.Buffered | ( ( FileAccess.Read | FileAccess.Write ) << 14 ),
ChangerGetElementStatus = ( ChangerBase << 16 ) | ( 0x0005 << 2 ) | EMethod.Buffered | ( ( FileAccess.Read | FileAccess.Write ) << 14 ),
ChangerInitializeElementStatus = ( ChangerBase << 16 ) | ( 0x0006 << 2 ) | EMethod.Buffered | ( FileAccess.Read << 14 ),
ChangerSetPosition = ( ChangerBase << 16 ) | ( 0x0007 << 2 ) | EMethod.Buffered | ( FileAccess.Read << 14 ),
ChangerExchangeMedium = ( ChangerBase << 16 ) | ( 0x0008 << 2 ) | EMethod.Buffered | ( FileAccess.Read << 14 ),
ChangerMoveMedium = ( ChangerBase << 16 ) | ( 0x0009 << 2 ) | EMethod.Buffered | ( FileAccess.Read << 14 ),
ChangerReinitializeTarget = ( ChangerBase << 16 ) | ( 0x000A << 2 ) | EMethod.Buffered | ( FileAccess.Read << 14 ),
ChangerQueryVolumeTags = ( ChangerBase << 16 ) | ( 0x000B << 2 ) | EMethod.Buffered | ( ( FileAccess.Read | FileAccess.Write ) << 14 ),

public string GetLastWin32ErrorMessage( int errorCode ) {
    IntPtr buffer = IntPtr.Zero;

    uint cnt = FormatMessage
    (
        0x00000100 |    // FORMAT_MESSAGE_ALLOCATE_BUFFER
        0x00000200 |    // FORMAT_MESSAGE_IGNORE_INSERTS
        0x00001000,     // FORMAT_MESSAGE_FROM_SYSTEM
        IntPtr.Zero,
        ( uint )errorCode,
        0,              // LANGIDs : Neutral, Thread, User, System, en-US
        ref buffer,
        0,
        IntPtr.Zero
    );
    if ( cnt 0 || buffer IntPtr.Zero )
        return String.Format( "Unknown error: {0}.", errorCode );

    string errorMessage = Marshal.PtrToStringAuto( buffer, ( int )cnt );
    Marshal.FreeHGlobal( buffer ); // LocalFree.

    return errorMessage;
}

private void getPhysicalDrive( ) {
    IntPtr handle = IntPtr.Zero;
    uint ndevice = 0;

    Win32Functions.CHANGER_PRODUCT_DATA cpd = new Win32Functions.CHANGER_PRODUCT_DATA( );
    IntPtr pcpd = Marshal.AllocHGlobal( Marshal.SizeOf( cpd ) );
    Marshal.StructureToPtr( cpd, pcpd, true );

    do {
        string s = "\\\\.\\PHYSICALDRIVE" + ndevice.ToString( );
        Console.WriteLine( s );

        handle = Win32Functions.CreateFile( s,
                                            0,
                                            Win32Functions.FILE_SHARE_READ | Win32Functions.FILE_SHARE_WRITE,
                                            IntPtr.Zero,
                                            Win32Functions.OPEN_EXISTING,
                                            0,
                                            IntPtr.Zero );
        if ( handle == IntPtr.Zero ) {
            Console.WriteLine( "not Found" );
        }
        else {
            uint nBytes = 0;
            if ( Win32Functions.DeviceIoControl( handle,
                                                 (uint) EIOControlCode.ChangerGetProductData,
                                                 IntPtr.Zero, 0,
                                                 pcpd, ( uint )Marshal.SizeOf( pcpd ),
                                                 ref nBytes,
                                                 IntPtr.Zero )
                                                 > 0 ) {

                Console.WriteLine( cpd.ProductId );
                Console.WriteLine( cpd.DeviceType );
            }
            else {
                Int32 err = Marshal.GetLastWin32Error( );
                Console.WriteLine( "The last Win32 Error was: " + err );
                Console.WriteLine( GetLastWin32ErrorMessage( Marshal.GetLastWin32Error( ) ) );

            }
            Marshal.FreeHGlobal( pcpd );
            if ( !Win32Functions.CloseHandle( handle ) ) {
                Console.WriteLine( "CloseHandle code erreur: {0}", Marshal.GetLastWin32Error( ) );
            }
            ndevice++;
        }
    } while ( handle == IntPtr.Zero );
}

static void Main( string[ ] args ) {
    RawDiskAccess ld = new RawDiskAccess( );
    ld.getPhysicalDrive( );
}

L'éternité c'est long surtout vers la fin...[Insert_Emoticon%28%27/imgs2/smile_wink.gif%27%29; ]
0
tuxama Messages postés 6 Date d'inscription lundi 28 janvier 2008 Statut Membre Dernière intervention 18 février 2008
10 févr. 2008 à 13:47
Merci de ton aide. DeviceIOControl retourne effectivmeent un bool et je viens de modifier l'appel et la définition ainsi :

if ( Win32Functions.DeviceIoControl( handle,
                                                         (uint) EIOControlCode.ChangerGetProductData,
                                                         IntPtr.Zero, 0,
                                                         pcpd, ( uint )Marshal.SizeOf( pcpd ),
                                                         ref nBytes,
                                                         IntPtr.Zero ) ) {
                                                        
                        Console.WriteLine( cpd.ProductId );
                        Console.WriteLine( cpd.DeviceType );
                    }

[System.Runtime.InteropServices.DllImport( "Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto )]
public extern static bool DeviceIoControl(
    IntPtr hDevice,
    uint IoControlCode,
    IntPtr lpInBuffer,
    uint InBufferSize,
    IntPtr lpOutBuffer,
    uint nOutBufferSize,
    ref uint lpBytesReturned,
    IntPtr lpOverlapped
    );

Mais j'ai toujous une erreur "Accès refusé"...

L'éternité c'est long surtout vers la fin...[Insert_Emoticon%28%27/imgs2/smile_wink.gif%27%29; ]
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
10 févr. 2008 à 15:07
Es-tu sûr que IOCTL_CHANGER_GET_PRODUCT_DATA s'applique aux disques et pas aux autres péréiphériques, les codes disque me semblent réunis dans "Disk Management Control Codes" ( IOCTL_DISK_* ).
0
tuxama Messages postés 6 Date d'inscription lundi 28 janvier 2008 Statut Membre Dernière intervention 18 février 2008
18 févr. 2008 à 22:32
Bonsoir Lutinore,

Ta réponse est me semble t-il à la fois juste et imcomplète. Car en effet s'il ne faut pas confondre les DISK et les CHANGER il n'en demeure pas moins que la possibilité nous est offerte (dans la doc msdn) de récupérer des infos uniquement accessiblent par IOCTL_GET_CHANGER_PRODUCT_DATA.

Pour récupérer comme dans les exemples MS la géométrie du disque pas de problème (en C# et C++ non managé sous VS 2008).
En revanche (pas d'exemple MS, j'en trouve pas) je prends un code retour 5, accès refusé, dès lors que je tente de récupérer les infos CHANGER_PRODUCT_DATA (en C# et C++ non managé sous VS 2008).

la doc msdn
The following control codes are used with changer devices.

Value |Meaning |----
[Insert_Emoticon%28%27/imgs2/smile_wink.gif%27%29; ]
0
tuxama Messages postés 6 Date d'inscription lundi 28 janvier 2008 Statut Membre Dernière intervention 18 février 2008
18 févr. 2008 à 23:12
Après re-lecture de ton post j'ai voulu vérifier quelque chose (parfois je suis un peu borné )

Lors du createfile( DEVICE_NAME, ....
l'on précise le "nom de device". ET LA OUI TU AS RAISON il faut indiquer @"\\.\Changer0" dès lors que l'on indique un code de controle IOCTL_CHANGER !!

C'est en clair dans la doc :
Changer Device
The IOCTL_CHANGER_* control codes accept a handle to a changer device. To
open a changer device, use a file name of the following form:
\\.\Changerx where x is a number that indicates which device to
open, starting with zero (0). To open changer device zero (0) in an application
that is written in C or C++, use the following file name: "\\\\.\\Changer0".

Merci de m'avoir ouvert les yeux !

L'éternité c'est long surtout vers la fin...[Insert_Emoticon%28%27/imgs2/smile_wink.gif%27%29; ]
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
19 févr. 2008 à 06:34
lu.
0
Rejoignez-nous