2009-03-06 56 views
50

Nhìn vào khả năng làm cho một USB phân phối ứng dụng
mà sẽ tự khởi động trên chèn một thanh USB và tắt máy khi tháo thanh
Phát hiện chèn ổ đĩa USB và loại bỏ sử dụng các cửa sổ dịch vụ và C#

Sẽ sử dụng Net và C#.
Tìm kiếm gợi ý cách tiếp cận điều này bằng C#?


Cập nhật: Hai giải pháp khả thi thực hiện điều này như một dịch vụ.
- ghi đè WndProc
hoặc
- sử dụng WMI truy vấn với ManagementEventWatcher

+1

Tốt câu hỏi về dịch vụ bẫy sự kiện này. Suy nghĩ đầu tiên của tôi là bạn phải đánh dấu dịch vụ của mình là "cho phép tương tác với máy tính để bàn" và sau đó tạo một cửa sổ ẩn. Tùy chọn an toàn hơn có thể là tạo ứng dụng windows chạy khi khởi động - nó có thể tạo cửa sổ và sau đó liên lạc với svc –

+0

Related: http: // stackoverflow.com/questions/6003822/how-to-detect-a-usb-drive-đã được cắm-in – DuckMaestro

Trả lời

44

Bạn có thể sử dụng WMI, thật dễ dàng và nó hoạt động tốt hơn rất nhiều so với giải pháp WndProc với các dịch vụ.

Dưới đây là một ví dụ đơn giản:

using System.Management; 

ManagementEventWatcher watcher = new ManagementEventWatcher(); 
WqlEventQuery query = new WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2"); 
watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived); 
watcher.Query = query; 
watcher.Start(); 
watcher.WaitForNextEvent(); 

Và đó là nó :)

+4

Điều đó hoạt động tốt nhưng Làm thế nào tôi có thể nhận được ký tự ổ đĩa USB được lắp vào? –

+0

[Bài viết này] (http://www.ravichaganti.com/blog/monitoring-volume-change-events-in-powershell-using-wmi/) dường như nhận được thông tin này trong Powershell. Không nên quá khó để dịch nó sang C#. – VitalyB

+3

Trong trình xử lý sự kiện của bạn, 'e.NewEvent.Properties [" DriveName "]. Value.ToString()' – lambinator

5

Bạn cũng có thể sử dụng WMI để phát hiện sự kiện chèn. Nó phức tạp hơn một chút so với việc giám sát các tin nhắn WM_CHANGEDEVICE, nhưng nó không yêu cầu một cửa sổ xử lý mà có thể hữu ích nếu bạn đang chạy trong nền như một dịch vụ.

+2

@John Conrad: +1 WMI là một lựa chọn tốt. Cũng tìm thấy một chủ đề SO về điều này: http://stackoverflow.com/questions/39704/wmi-and-win32devicechangeevent-wrong-event-type-returned –

+0

Thực ra WMI là giải pháp đơn giản hơn nhiều. Tôi đăng nó dưới đây như một giải pháp khác. – VitalyB

4

Dưới đây là những gì chúng ta đã làm với C# .Net 4.0 dưới một ứng dụng WPF. Chúng tôi vẫn đang tìm kiếm câu trả lời cho "cách cho biết loại thiết bị đã được chèn/xóa", nhưng đây là bước bắt đầu:

using System.Windows.Interop; 
... 
public partial class MainWindow : Window 
{ 
    ... 
    public MainWindow() 
    { 
    ... 
    } 

    //============================================================ 
    // WINDOWS MESSAGE HANDLERS 
    // 

    private const int WM_DEVICECHANGE = 0x0219; // int = 537 
    private const int DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 0x00000004; 

    /// <summary> 
    /// 
    /// </summary> 
    /// <param name="e"></param> 
    protected override void OnSourceInitialized(EventArgs e) 
    { 
     base.OnSourceInitialized(e); 
     HwndSource source = PresentationSource.FromVisual(this) as HwndSource; 
     source.AddHook(WndProc); 
    } 

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) 
    { 
     if (msg == WM_DEVICECHANGE) 
     { 
      ReadDongleHeader(); 
     } 
     return IntPtr.Zero; 
    } 

} 
+2

Bất kỳ cải tiến nào để tìm ra thiết bị nào được chèn vào? – Kcvin

+0

@Kevin điều này có thể dễ dàng được tìm thấy ở nơi khác để có được danh sách các thiết bị. Đây là một giải pháp đầy đủ mà tôi đã đến đầu tiên. Chỉ WM_DEVICECHANGE được kích hoạt cho tôi. https://social.msdn.microsoft.com/Forums/vstudio/en-US/ea183afd-d070-4abd-8e00-a1784fdfedc5/detecting-usb-device-insertion-and-removal?forum=csharpgeneral – CularBytes

19

Thêm vào bài đăng của VitalyB.

Để nâng một sự kiện mà BẤT CỨ thiết bị USB được chèn, sử dụng như sau:

var watcher = new ManagementEventWatcher(); 
var query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2"); 
watcher.EventArrived += new EventArrivedEventHandler(watcher_EventArrived); 
watcher.Query = query; 
watcher.Start(); 

này sẽ nâng cao một sự kiện bất cứ khi nào một thiết bị USB được cắm. Nó thậm chí hoạt động với DAQ của National Instruments mà tôi đang cố gắng tự động phát hiện.

+0

@Lee Taylor That hoạt động tốt nhưng làm thế nào tôi có thể nhận được ký tự ổ đĩa của USB được chèn vào? –

+0

@NeverQuit - Tôi chỉ chỉnh sửa câu hỏi, hỏi @Syn! Ngoài ra, nếu bạn có câu hỏi mới thì hãy tạo một câu hỏi mới. –

+0

@Syn Điều đó hoạt động tốt nhưng Làm thế nào tôi có thể nhận được ký tự ổ đĩa USB được lắp vào? –

29

Điều này phù hợp với tôi, ngoài ra bạn có thể tìm hiểu thêm thông tin về thiết bị.

using System.Management; 

private void DeviceInsertedEvent(object sender, EventArrivedEventArgs e) 
{ 
    ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"]; 
    foreach (var property in instance.Properties) 
    { 
     Console.WriteLine(property.Name + " = " + property.Value); 
    } 
} 

private void DeviceRemovedEvent(object sender, EventArrivedEventArgs e) 
{ 
    ManagementBaseObject instance = (ManagementBaseObject)e.NewEvent["TargetInstance"]; 
    foreach (var property in instance.Properties) 
    { 
     Console.WriteLine(property.Name + " = " + property.Value); 
    } 
}    

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    WqlEventQuery insertQuery = new WqlEventQuery("SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'"); 

    ManagementEventWatcher insertWatcher = new ManagementEventWatcher(insertQuery); 
    insertWatcher.EventArrived += new EventArrivedEventHandler(DeviceInsertedEvent); 
    insertWatcher.Start(); 

    WqlEventQuery removeQuery = new WqlEventQuery("SELECT * FROM __InstanceDeletionEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_USBHub'"); 
    ManagementEventWatcher removeWatcher = new ManagementEventWatcher(removeQuery); 
    removeWatcher.EventArrived += new EventArrivedEventHandler(DeviceRemovedEvent); 
    removeWatcher.Start(); 

    // Do something while waiting for events 
    System.Threading.Thread.Sleep(20000000); 
} 
+0

Hoạt động hoàn hảo. Không kích hoạt nhiều sự kiện như một số câu trả lời khác ở đây khi chèn/xóa. Đây sẽ là câu trả lời được chấp nhận. – samuelesque

+0

Tôi đồng ý với @samuelAndThe, điều này có vẻ là aproach tốt nhất. Nếu bạn đang tìm kiếm cũng phát hiện các thay đổi đối với ổ đĩa cứng và không chỉ ổ đĩa USB, bạn có thể sử dụng lớp 'Win32_DiskDrive' –

+0

'private void backgroundWorker1_DoWork (đối tượng người gửi, DoWorkEventArgs e)', tại sao bạn có '(đối tượng người gửi, DoWorkEventArgs e) '??? (Tôi đã cam kết một đề xuất chỉnh sửa cho điều này.) – Turtle

11

Câu trả lời của VitalyB không bao gồm tháo thiết bị. Tôi đã thay đổi nó một chút để kích hoạt sự kiện cả khi phương tiện được chènxóa và cũng có mã để lấy ký tự ổ đĩa của phương tiện được chèn.

using System; 
using System.Management; 

namespace MonitorDrives 
{ 
    class Program 
    { 
     public enum EventType 
     { 
      Inserted = 2, 
      Removed = 3 
     } 

     static void Main(string[] args) 
     { 
      ManagementEventWatcher watcher = new ManagementEventWatcher(); 
      WqlEventQuery query = new WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2 or EventType = 3"); 

      watcher.EventArrived += (s, e) => 
      { 
       string driveName = e.NewEvent.Properties["DriveName"].Value.ToString(); 
       EventType eventType = (EventType)(Convert.ToInt16(e.NewEvent.Properties["EventType"].Value)); 

       string eventName = Enum.GetName(typeof(EventType), eventType); 

       Console.WriteLine("{0}: {1} {2}", DateTime.Now, driveName, eventName); 
      }; 

      watcher.Query = query; 
      watcher.Start(); 

      Console.ReadKey(); 
     } 
    } 
} 
+0

Điều này thật tuyệt, nhưng vì một số lý do nó kích hoạt sự kiện nhiều lần mỗi khi tôi cắm vào hoặc ra một thiết bị - bạn có biết tại sao điều này có thể và cách ngăn chặn nó? – colmde

+0

Vì bạn chưa đăng mã của mình nên khó mà nói, nhưng có thể bạn đang đính kèm sự kiện nhiều lần. –

+0

đây không phải là một mã *** đầy đủ! vì vậy bạn cần phải thay thế một số câu trả lời của VitalyB cho điều này. – Turtle

2

Một chút chỉnh sửa trên tất cả các câu trả lời ở trên:

using System.Management; 

public partial class MainForm : Form 
{ 
    public MainForm() 
    { 
     InitializeComponent(); 

     bgwDriveDetector.DoWork += bgwDriveDetector_DoWork; 
     bgwDriveDetector.RunWorkerAsync(); 
    } 

    private void DeviceInsertedEvent(object sender, EventArrivedEventArgs e) 
    { 
     string driveName = e.NewEvent.Properties["DriveName"].Value.ToString(); 
     MessageBox.Show(driveName + " inserted"); 
    } 

    private void DeviceRemovedEvent(object sender, EventArrivedEventArgs e) 
    { 
     string driveName = e.NewEvent.Properties["DriveName"].Value.ToString(); 
     MessageBox.Show(driveName + " removed"); 
    } 

    void bgwDriveDetector_DoWork(object sender, DoWorkEventArgs e) 
    { 
     var insertQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2"); 
     var insertWatcher = new ManagementEventWatcher(insertQuery); 
     insertWatcher.EventArrived += DeviceInsertedEvent; 
     insertWatcher.Start(); 

     var removeQuery = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3"); 
     var removeWatcher = new ManagementEventWatcher(removeQuery); 
     removeWatcher.EventArrived += DeviceRemovedEvent; 
     removeWatcher.Start(); 
    } 
} 
Các vấn đề liên quan