2017-09-09 1 views
0

Je voudrais évaluer si un lecteur est en cours d'utilisation (si je ne me trompe pas, cela signifie que certaines choses en lecture/écriture se passe avec le lecteur) en utilisant C#. Cela ne me dérangerait pas pour une solution utilisant des scripts bash ou similaire non plus, comme je pourrais les utiliser dans une application C#. J'ai déjà trouvé une question concernant les scripts bash here, mais n'a pas pu résoudre mon problème avec les réponses données.Évaluer si le lecteur est en cours d'utilisation

Je pensais déjà utiliser la classe DriveInfo, mais elle ne semblait pas avoir d'utilité pour moi. Je me demandais si je pouvais utiliser la propriété IsReady de DriveInfo, parce que je devinais que ce ne serait pas prêt pendant qu'il est lu/écrit, mais cette tentative semble plutôt bâclée pour moi.

Cependant, je encore essayé il:

private static bool IsDriveInUse() 
{ 
    var drive = DriveInfo.GetDrives().FirstOrDefault(info => info.Name.StartsWith(DRIVE_LETTER.ToString())); 
    return drive != null && !drive.IsReady; 
} 

Mais il ne fonctionne pas (il est revenu faux pendant que je jouais la musique de mon lecteur).

Une solution optimale pour moi serait une fonction qui me dit si le lecteur a été utilisé dans un laps de temps spécifique (maintenons le nom IsDriveInUse). Cela signifie que si le temps était par exemple de 60 secondes, IsDriveInUse devrait retourner true si 5 secondes avant que le contenu de l'appel de fonction du lecteur ait été lu et false s'il n'y avait aucune action de lecture/écriture dans les 60 secondes écoulées.


EDIT Pour préciser ce que je veux dire exactement par utilisé, je vais essayer d'expliquer ce que je suis en train de faire. J'écris un outil qui fait automatiquement défiler mon disque dur, qu'il soit inactif ou que j'appuie sur un raccourci clavier. J'ai réussi à le faire tourner par programmation (même si l'outil intégré de Windows ou d'autres outils que j'ai trouvés étaient capables de le faire, mais c'est un autre problème). Cependant, il tourne maintenant le disque dur chaque minute, indépendamment du fait qu'il soit actuellement utilisé ou non. Cela signifie que si je joue de la musique à partir de mon disque dur, il est toujours débloqué, juste pour tourner juste après, ce qui ne diminue pas le développement du bruit.

J'espère que cela a clarifié la question.


EDIT je maintenant essayé d'utiliser le code de contrôle FSCTL_LOCK_VOLUME (je ne pouvais pas trouver une valeur pour IOCTL_DISK_PERFORMANCE), mais il encore retourné false pour IsDriveInUse() pendant que je jouais la musique. De plus, cela a provoqué des fenêtres qui ont fait tourner directement le disque à mesure que je l'ai fait pivoter (probablement parce que le fait que Windows ait été libéré pensait que quelque chose utilisait le disque). Voilà ce que j'ai essayé:

public class DriveManager 
{ 
    public const int FSCTL_LOCK_VOLUME = 0x00090018; 
    public const int FSCTL_UNLOCK_VOLUME = 0x0009001c; 

    [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); 

    [return: MarshalAs (UnmanagedType.Bool)] 
    [DllImport ("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    public static extern bool DeviceIoControl (
     [In] SafeFileHandle hDevice, 
     [In] int dwIoControlCode, [In] IntPtr lpInBuffer, 
     [In] int nInBufferSize, [Out] IntPtr lpOutBuffer, 
     [In] int nOutBufferSize, out int lpBytesReturned, 
     [In] IntPtr lpOverlapped); 

    public static SafeFileHandle CreateFileR (string device) 
    { 
     string str = device.EndsWith (@"\") ? device.Substring (0, device.Length - 1) : device; 
     return new SafeFileHandle (
      CreateFile (@"\\.\" + str, WinntConst.GENERIC_READ, WinntConst.FILE_SHARE_READ, IntPtr.Zero, 
         WinntConst.OPEN_EXISTING, WinntConst.FILE_ATTRIBUTE_NORMAL, IntPtr.Zero), true); 
    } 

    internal class WinntConst 
    { 
     // Fields 
     internal static uint FILE_ATTRIBUTE_NORMAL = 0x80; 

     internal static uint FILE_SHARE_READ = 1; 
     internal static uint GENERIC_READ = 0x80000000; 
     internal static uint OPEN_EXISTING = 3; 
    } 

    public static bool IsDriveInUse (string deviceName) 
    { 
     var handle = CreateFileR (deviceName); 
     var buffer = Marshal.AllocHGlobal (sizeof (int)); 
     try 
     { 
      return 
       DeviceIoControl (handle, 
           FSCTL_LOCK_VOLUME, 
        IntPtr.Zero, 
        0, 
        buffer, 
        sizeof(int), 
        out var bytesReturned, 
        IntPtr.Zero 
       ); 
     } 
     finally 
     { 
      var sessionId = Marshal.ReadInt32 (buffer); 
      Marshal.FreeHGlobal (buffer); 
      handle.Close(); 
     } 
    } 

Et la mise en œuvre:

private static bool IsDriveInUse() => DriveManager.IsDriveInUse ([email protected]"{DRIVE_LETTER}:\"); 

Peut-être qu'il aide à voir la partie où je tourne le disque vers le bas aussi bien (je Smartmontools pour cela):

internal static class Program 
{ 
    private const string PROGRAM_PATH = @"External\smartctl.exe"; 
    private const string ARGUMENTS_SHUTDOWN = @"-s standby,now {0}:"; 
    private const char DRIVE_LETTER = 'd'; 


    public static void Main (string [] args) 
    { 
     InitializeHotKey(); 
     Console.WriteLine ("Hotkey registered!"); 

     while (true) 
     { 
      Thread.Sleep (60000); 
      if (!IsDriveInUse()) 
       ShutDownDrive (true); 
     } 
    } 

    private static bool IsDriveInUse() => DriveManager.IsDriveInUse ([email protected]"{DRIVE_LETTER}:\"); 

    private static void InitializeHotKey() 
    { 
     HotKeyManager.RegisterHotKey (Keys.D, KeyModifiers.Alt | KeyModifiers.Control); 
     HotKeyManager.HotKeyPressed += HotKeyPressed; 
    } 

    private static void HotKeyPressed (object sender, HotKeyEventArgs hotKeyEventArgs) => ShutDownDrive (true); 

    private static void ShutDownDrive (bool withDialog = false) 
    { 
     Process process; 
     (process = new Process 
     { 
      StartInfo = new ProcessStartInfo 
      { 
       WindowStyle = ProcessWindowStyle.Hidden, 
       FileName = PROGRAM_PATH, 
       Arguments = string.Format (ARGUMENTS_SHUTDOWN, DRIVE_LETTER) 
      } 
     }).Start(); 

     process.WaitForExit(); 
     process.Close(); 

     if (withDialog) 
      Console.WriteLine ("Drive shut down!"); 
    } 
} 
+0

Spécifiez exactement ce que vous entendez par «en service» et «prêt». Les disques peuvent faire plusieurs choses à la fois, grâce à la planification. Sur un poste de travail, ainsi que sur un disque dur de serveur, il y a presque toujours de la lecture ou de l'écriture. Quel problème essayez-vous précisément de résoudre? Est-ce un lecteur fixé dans une machine, un lecteur amovible ou un lecteur réseau? – CodeCaster

+0

Supposons également que vous puissiez obtenir les informations correctes sur "InUse". Son état peut changer avant que vous ne preniez une action. –

+0

@ L.B comme j'écris cet outil principalement pour moi, je peux vous promettre que ce ne sera pas le cas, car je n'utilise pas mon disque dur très souvent. – MetaColon

Répondre