1

Windows 7 で Visual Studio 2008 を使用して C# でアップデータ プログラムを作成しています。ユーザーに USB サム ドライブを挿入してもらいたいのですが、プログラムがドライブを見つけてドライブを更新すると、自動的にコピーされます。起動時に一度だけチェックしてから、更新を認識しないプログラムを実行したいと考えています (更新は、プログラムのシャットダウンで実際に発生する必要があります)。

私の問題は、サムドライブがマウントされる前に更新プログラムが実行されているため、コンピューターがサムドライブも更新も検出せず、途中で移動することです。すべてをできるだけ速く実行したいのですが、サムドライブを検出する前に強制的にマウントする必要があります。ユーザーからの入力なしで、すべてが自動化されている必要があります。

これはC#で可能ですか?

詳細を編集します。

現在、起動時にバッチ ファイルを実行しています (実際には Windows 7 シェルとして実行していますが、違いがあるかどうかはわかりません)。バッチ ファイルは、更新チェックを実行してから、実際のプログラムを実行します。ユーザーが起動時に 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 秒待ちたくありません。

このチェックを簡単に行うことができれば、イベントを継続的に監視し、すべてをシャットダウンして更新するよりもはるかに簡単です。

4

3 に答える 3

2

次のような解決策を提案します。

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;
            }
        }
    }
}

これが少し役立つことを願っています。

于 2013-10-30T20:38:49.600 に答える
1

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)。私は、効果があると言っているドキュメントを発見していません。

于 2013-10-30T19:59:34.397 に答える
1

詳細はわかりませんが、 DriveInfo[] 型の配列を返す DriveInfo.GetDrives() を呼び出すことができるようです。

DriveInfo には IsReady() メソッドがあります。おそらく、ドライブの準備ができていることを確認したら、USB drive() でよく知られているファイルを探して、正しい USB がマウントされていることを確認できます。

必要なものが見つかるまでループでポーリングできますが、たとえば 60 秒以内に必要なものが見つからない場合は、必要な USB ドライブが見つからないことをユーザーに通知する必要があります。

于 2013-10-30T19:21:10.770 に答える