【问题标题】:Force USB Thumb Drive to Mount Before Continue在继续之前强制安装 USB 拇指驱动器
【发布时间】:2013-11-10 14:10:03
【问题描述】:

我正在使用 Windows 7 上的 Visual Studio 2008 在 C# 中编写更新程序。我希望用户插入 USB 拇指驱动器,如果程序在驱动器上找到驱动器和更新,那么它会自动将它们复制过来。我希望在启动时只检查一次,然后执行一个不知道更新的程序(更新确实需要在程序关闭时发生)。

我的问题是更新程序在安装拇指驱动器之前正在运行,因此计算机检测到没有拇指驱动器和更新并过早地继续运行。我想让一切都尽可能快地运行,但我需要在检测之前强制安装任何拇指驱动器。一切都必须是自动的,无需用户输入。

这在 c# 中可行吗?

更详细地编辑:

我目前在启动时运行一个批处理文件(实际上是作为 Windows 7 shell,但我不确定这会有所不同)。批处理文件运行更新检查,然后运行实际程序。如果用户在启动时卡住了 USB 驱动器,那么我希望更新程序查看驱动器并复制任何新文件。

当前编码如下:

 DriveInfo[] ListDrives = DriveInfo.GetDrives();
 foreach (DriveInfo Drive in ListDrives)
 {
      if(Drive.DriveType == DriveType.Removable)
      {
           // double check it's valid and copy over stuff
      }
 }

但它目前在启动时找不到驱动器。如果我稍后运行它,那么一切都很好。我假设由于我这么早就运行了更新程序,它只是没有机会安装,但我不想等待 N 秒,如果我不需要,因为在正常情况下这只是死时间。

如果我能轻松完成这项检查,那么它比必须持续监控事件然后关闭所有内容并进行更新要简单得多。

【问题讨论】:

  • 我觉得你省略了一些必要的细节来理解你试图解决什么问题。你的程序什么时候运行?它从哪里跑?它如何知道哪个驱动器是 USB 驱动器?因为您选择在后台启动时仅执行一次更新检查....那么您如何通知用户他们应该在适当的时间插入驱动器,这样您就不会与现实存在竞争条件?跨度>
  • @P.Brian.Mackey 谢谢,我在问题中添加了更多信息。

标签: c# windows visual-studio


【解决方案1】:

我会建议如下解决方案:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;

/// <summary>
/// Represents our program class which contains the entry point of our application.
/// </summary>
public class Program
{
    /// <summary>
    /// Represents the entry point of our application.
    /// </summary>
    /// <param name="args">Possibly spcified command line arguments.</param>
    public static void Main(string[] args)
    {
        RemovableDriveWatcher rdw = new RemovableDriveWatcher();   // Create a new instance of the RemoveableDriveWatcher class.
        rdw.NewDriveFound += NewDriveFound;                        // Connect to the "NewDriveFound" event.
        rdw.DriveRemoved += DriveRemoved;                          // Connect to the "DriveRemoved" event.
        rdw.Start();                                               // Start watching.

        // Do something here...
        Console.ReadLine();

        rdw.Stop();                                                // Stop watching.
    }

    /// <summary>
    /// Is executed when a new drive has been found.
    /// </summary>
    /// <param name="sender">The sender of this event.</param>
    /// <param name="e">The event arguments containing the changed drive.</param>
    private static void NewDriveFound(object sender, RemovableDriveWatcherEventArgs e)
    {
        Console.WriteLine(string.Format("Found a new drive, the name is: {0}", e.ChangedDrive.Name));
    }

    /// <summary>
    /// Is executed when a drive has been removed.
    /// </summary>
    /// <param name="sender">The sender of this event.</param>
    /// <param name="e">The event arguments containing the changed drive.</param>
    private static void DriveRemoved(object sender, RemovableDriveWatcherEventArgs e)
    {
        Console.WriteLine(string.Format("The drive with the name {0} has been removed.", e.ChangedDrive.Name));
    }
}

RemoveableDriveWatcher 类如下所示:

/// <summary>
/// Repesents a watcher class for removable drives.
/// </summary>
public class RemovableDriveWatcher
{
    /// <summary>
    /// Represents the watcher thread which watches for new drives.
    /// </summary>
    private Thread watcherThread;

    /// <summary>
    /// Continas all found logical drives of this system.
    /// </summary>
    private List<DriveInfo> foundDrives;

    /// <summary>
    /// Initializes a new instance of the <see cref="RemovableDriveWatcher"/> class.
    /// </summary>
    public RemovableDriveWatcher()
    {
        this.foundDrives = new List<DriveInfo>();
        this.watcherThread = new Thread(new ThreadStart(ScanLogicalDrives));
        this.WaitBetweenScansDelay = 1000;
    }

    /// <summary>
    /// Is fired if a new drive has been detected.
    /// </summary>
    public event EventHandler<RemovableDriveWatcherEventArgs> NewDriveFound;

    /// <summary>
    /// Is fired if a drive has been removed.
    /// </summary>
    public event EventHandler<RemovableDriveWatcherEventArgs> DriveRemoved;

    /// <summary>
    /// Gets or sets the delay in ms between two scans.
    /// </summary>
    public int WaitBetweenScansDelay
    {
        get;
        set;
    }

    /// <summary>
    /// Starts the watcher.
    /// </summary>
    public void Start()
    {
        if (!this.watcherThread.IsAlive)
        {
            this.watcherThread.Start();
        }
    }

    /// <summary>
    /// Stops the watcher.
    /// </summary>
    public void Stop()
    {
        if (this.watcherThread.IsAlive)
        {
            this.watcherThread.Abort();
            this.watcherThread.Join();
        }
    }

    /// <summary>
    /// Scans for logical drives and fires an event every time a new
    /// drive has been found or a drive was removed.
    /// </summary>
    private void ScanLogicalDrives()
    {
        DriveInfo[] drives;

        do
        {
            drives = DriveInfo.GetDrives();

            // Check for new drives
            foreach (DriveInfo drive in drives)
            {
                if (!(drive.DriveType == DriveType.Removable))
                {
                    continue;
                }

                if (!drive.IsReady)
                {
                    continue;
                }

                if (!this.foundDrives.ContainsWithName(drive))
                {
                    this.foundDrives.Add(drive);

                    if (this.NewDriveFound != null)
                    {
                        this.NewDriveFound(this, new RemovableDriveWatcherEventArgs(drives, drive));
                    }
                }
            }

            // Check for removed drives
            for (int i = this.foundDrives.Count - 1; i >= 0; i--)
            {
                DriveInfo drive = this.foundDrives[i];
                if (!drives.ContainsWithName(drive))
                {
                    if (this.DriveRemoved != null)
                    {
                        this.DriveRemoved(this, new RemovableDriveWatcherEventArgs(drives, drive));
                    }

                    this.foundDrives.RemoveWithName(drive);
                }
            }

            // Sleep
            Thread.Sleep(this.WaitBetweenScansDelay);
        }
        while (true);
    }
}

为了让一切正常工作,您需要 RemovableDriveWatcherEventArgs:

/// <summary>
/// Represents the RemovableDriveWatcherEventArgs
/// </summary>
public class RemovableDriveWatcherEventArgs : EventArgs
{
    /// <summary>
    /// Initializes a new instance of the <see cref="RemovableDriveWatcherEventArgs"/> class.
    /// </summary>
    /// <param name="allDrives">All currently available logical drives in the system.</param>
    /// <param name="changedDrive">The changed drive.</param>
    public RemovableDriveWatcherEventArgs(DriveInfo[] allDrives, DriveInfo changedDrive)
    {
        this.Drives = allDrives;
        this.ChangedDrive = changedDrive;
    }

    /// <summary>
    /// Gets the changed logical drive that has either been detected or removed.
    /// </summary>
    public DriveInfo ChangedDrive { get; private set; }

    /// <summary>
    /// Gets all currently available logical drives.
    /// </summary>
    public DriveInfo[] Drives { get; private set; }
}

当然还有扩展:

/// <summary>
/// Contains extensions used by the RemovableDriveWatcher class.
/// </summary>
public static class RemovableDriveWatcherExtensions
{
    /// <summary>
    /// Extends the DiveInfo[] by the ContainsWithName method.
    /// </summary>
    /// <param name="all">The array where we want to find the specified instance.</param>
    /// <param name="search">The instance which we want to find in the array.</param>
    /// <returns>TRUE if the specified instance was found, FALSE if the specified instance was not found.</returns>
    public static bool ContainsWithName(this DriveInfo[] all, DriveInfo search)
    {
        for (int i = 0; i < all.Length; i++)
        {
            if (all[i].Name == search.Name)
            {
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// Extends the List<DriveInfo> by the ContainsWithName method.
    /// </summary>
    /// <param name="all">The array where we want to find the specified instance.</param>
    /// <param name="search">The instance which we want to find in the list.</param>
    /// <returns>TRUE if the specified instance was found, FALSE if the specified instance was not found.</returns>
    public static bool ContainsWithName(this List<DriveInfo> all, DriveInfo search)
    {
        for (int i = 0; i < all.Count; i++)
        {
            if (all[i].Name == search.Name)
            {
                return true;
            }
        }

        return false;
    }

    /// <summary>
    /// Extends the List<DriveInfo> by the RemoveWithName method.
    /// </summary>
    /// <param name="all">The array where we want to removed the specified instance.</param>
    /// <param name="search">The instance which we want to remove in the list.</param>
    public static void RemoveWithName(this List<DriveInfo> all, DriveInfo search)
    {
        for (int i = 0; i < all.Count; i++)
        {
            if (all[i].Name == search.Name)
            {
                all.RemoveAt(i);
                return;
            }
        }
    }
}

我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    您没有提供太多细节,但您似乎可以调用 DriveInfo.GetDrives() 来返回 DriveInfo[] 类型的数组

    DriveInfo 有一个 IsReady() 方法。大概一旦您检查驱动器已准备就绪,您可以在 USB drive() 上查找一个众所周知的文件,以验证它们是否已安装正确的 USB

    您可以循环轮询直到找到所需的内容,但如果您在 60 秒内没有找到所需的内容,则需要通知用户您找不到所需的 USB 驱动器。

    【讨论】:

      【解决方案3】:

      我没有在 if 语句中看到就绪检查。根据 MSDN:

      IsReady 指示驱动器是否准备就绪。例如,它表示 CD 是否在 CD 驱动器中或可移动存储设备是否 准备好读/写操作。如果不测试驱动器是否 准备好,它还没有准备好,使用 DriveInfo 查询驱动器将 引发 IOException。

      您在检查 IOException 吗?我没有看到 IsReady 事件,因此您可能必须旋转等待或挂钩到较低级别的 Windows API 才能找到指示驱动器准备就绪的事件。在此期间有一个想法:

      try
      {
          DriveInfo[] ListDrives = DriveInfo.GetDrives();
           foreach (DriveInfo Drive in ListDrives)
           {
                if(!Drive.IsReady)//spin
      
                if(Drive.DriveType == DriveType.Removable)
                {
                     // double check it's valid and copy over stuff
                }
           }
      }
      catch(IOException ex)//...
      

      我现在没有任何方法可以测试这个。请让我知道它对您的效果如何,或者我需要了解更多细节。

      但是,由于您在启动时开始此过程,所以IsReady 总是有可能不够用,您可能不得不再次寻找其他东西(我想是 Windows API)。我还没有发现任何说明有任何效果的文档。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-15
        • 2017-07-16
        • 2021-01-04
        • 2017-10-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多