2017-09-10 66 views
2

我試圖尋找了一圈,發現了幾個解決方案來檢測USB驅動器插入,但沒有我發現在C.檢測在C(Windows)中的USB驅動器插入

實際上是工作,我想問問,怎麼辦我處理這個問題? 檢測過程背後的想法是什麼(比如,它是如何完成的)?

預先感謝您! :)

+0

一些谷歌搜索顯示這[以前的C++問題](https://stackoverflow.com/questions/4078909/detecting-usb-insertion-removal-events-in-windows-using-c)和[註冊設備通知] (https://msdn.microsoft.com/en-us/library/windows/desktop/aa363432(v=vs.85).aspx)和[檢測介質插入或刪除](https://msdn.microsoft.com /en-us/library/windows/desktop/aa363215(v=vs.85).aspx)。 –

+0

@WeatherVane嘿:)! 我見過這個解決方案,但不幸的是我需要一個解決方案,在C:/ 謝謝你! :D – Jonathan

+0

那麼你可以根據這些信息寫一個嗎? –

回答

3

Weather Vane鏈接https://msdn.microsoft.com/en-us/library/windows/desktop/aa363432(v=vs.85).aspx上的示例使用普通C語言,正如我在評論中所說的那樣,只進行了簡單的修改。

下面是工作修改後的代碼。

#define UNICODE 1 
#define _UNICODE 1 
#include <windows.h> 
#include <stdio.h> 
#include <tchar.h> 
#include <strsafe.h> 
#include <dbt.h> 
#pragma comment(lib, "user32.lib") 
#pragma comment(lib, "Shell32.lib") 

void Main_OnDeviceChange(HWND hwnd, WPARAM wParam, LPARAM lParam); 
char FirstDriveFromMask(ULONG unitmask); //prototype 


// This GUID is for all USB serial host PnP drivers, but you can replace it 
// with any valid device class guid. 
GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, 
         0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 }; 

// For informational messages and window titles 
PWSTR g_pszAppName; 

// Forward declarations 
void OutputMessage(HWND hOutWnd, WPARAM wParam, LPARAM lParam); 
void ErrorHandler(LPTSTR lpszFunction); 

// 
// DoRegisterDeviceInterfaceToHwnd 
// 
BOOL DoRegisterDeviceInterfaceToHwnd( 
    IN GUID InterfaceClassGuid, 
    IN HWND hWnd, 
    OUT HDEVNOTIFY *hDeviceNotify 
) 
// Routine Description: 
//  Registers an HWND for notification of changes in the device interfaces 
//  for the specified interface class GUID. 

// Parameters: 
//  InterfaceClassGuid - The interface class GUID for the device 
//   interfaces. 

//  hWnd - Window handle to receive notifications. 

//  hDeviceNotify - Receives the device notification handle. On failure, 
//   this value is NULL. 

// Return Value: 
//  If the function succeeds, the return value is TRUE. 
//  If the function fails, the return value is FALSE. 

// Note: 
//  RegisterDeviceNotification also allows a service handle be used, 
//  so a similar wrapper function to this one supporting that scenario 
//  could be made from this template. 
{ 
    DEV_BROADCAST_DEVICEINTERFACE NotificationFilter; 

    ZeroMemory(&NotificationFilter, sizeof(NotificationFilter)); 
    NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); 
    NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; 
    NotificationFilter.dbcc_classguid = InterfaceClassGuid; 

    *hDeviceNotify = RegisterDeviceNotification( 
     hWnd,      // events recipient 
     &NotificationFilter,  // type of device 
     DEVICE_NOTIFY_WINDOW_HANDLE // type of recipient handle 
     ); 

    if (NULL == *hDeviceNotify) 
    { 
     ErrorHandler(TEXT("RegisterDeviceNotification")); 
     return FALSE; 
    } 

    return TRUE; 
} 

// 
// MessagePump 
// 
void MessagePump(
    HWND hWnd 
) 
// Routine Description: 
//  Simple main thread message pump. 
// 

// Parameters: 
//  hWnd - handle to the window whose messages are being dispatched 

// Return Value: 
//  None. 
{ 
    MSG msg; 
    int retVal; 

    // Get all messages for any window that belongs to this thread, 
    // without any filtering. Potential optimization could be 
    // obtained via use of filter values if desired. 

    while((retVal = GetMessage(&msg, NULL, 0, 0)) != 0) 
    { 
     if (retVal == -1) 
     { 
      ErrorHandler(TEXT("GetMessage")); 
      break; 
     } 
     else 
     { 
      TranslateMessage(&msg); 
      DispatchMessage(&msg); 
     } 
    } 
} 

// 
// WinProcCallback 
// 
INT_PTR WINAPI WinProcCallback(
           HWND hWnd, 
           UINT message, 
           WPARAM wParam, 
           LPARAM lParam 
          ) 
// Routine Description: 
//  Simple Windows callback for handling messages. 
//  This is where all the work is done because the example 
//  is using a window to process messages. This logic would be handled 
//  differently if registering a service instead of a window. 

// Parameters: 
//  hWnd - the window handle being registered for events. 

//  message - the message being interpreted. 

//  wParam and lParam - extended information provided to this 
//   callback by the message sender. 

//  For more information regarding these parameters and return value, 
//  see the documentation for WNDCLASSEX and CreateWindowEx. 
{ 
    LRESULT lRet = 1; 
    static HDEVNOTIFY hDeviceNotify; 
    static HWND hEditWnd; 
    static ULONGLONG msgCount = 0; 

    switch (message) 
    { 
    case WM_CREATE: 
     // 
     // This is the actual registration., In this example, registration 
     // should happen only once, at application startup when the window 
     // is created. 
     // 
     // If you were using a service, you would put this in your main code 
     // path as part of your service initialization. 
     // 
     if (! DoRegisterDeviceInterfaceToHwnd(
         WceusbshGUID, 
         hWnd, 
         &hDeviceNotify)) 
     { 
      // Terminate on failure. 
      ErrorHandler(TEXT("DoRegisterDeviceInterfaceToHwnd")); 
      ExitProcess(1); 
     } 


     // 
     // Make the child window for output. 
     // 
     hEditWnd = CreateWindow(TEXT("EDIT"),// predefined class 
           NULL,  // no window title 
           WS_CHILD | WS_VISIBLE | WS_VSCROLL | 
           ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, 
           0, 0, 0, 0, // set size in WM_SIZE message 
           hWnd,  // parent window 
           (HMENU)1, // edit control ID 
           (HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE), 
           NULL);  // pointer not needed 

     if (hEditWnd == NULL) 
     { 
      // Terminate on failure. 
      ErrorHandler(TEXT("CreateWindow: Edit Control")); 
      ExitProcess(1); 
     } 
     // Add text to the window. 
     SendMessage(hEditWnd, WM_SETTEXT, 0, 
      (LPARAM)TEXT("Registered for USB device notification...\n")); 

     break; 

    case WM_SETFOCUS: 
     SetFocus(hEditWnd); 

     break; 

    case WM_SIZE: 
     // Make the edit control the size of the window's client area. 
     MoveWindow(hEditWnd, 
        0, 0,     // starting x- and y-coordinates 
        LOWORD(lParam),  // width of client area 
        HIWORD(lParam),  // height of client area 
        TRUE);     // repaint window 

     break; 

    case WM_DEVICECHANGE: 
    { 
     // 
     // This is the actual message from the interface via Windows messaging. 
     // This code includes some additional decoding for this particular device type 
     // and some common validation checks. 
     // 
     // Note that not all devices utilize these optional parameters in the same 
     // way. Refer to the extended information for your particular device type 
     // specified by your GUID. 
     // 
     PDEV_BROADCAST_DEVICEINTERFACE b = (PDEV_BROADCAST_DEVICEINTERFACE) lParam; 
     (void)b; 
     TCHAR strBuff[256]; 

     Main_OnDeviceChange(hEditWnd, wParam, lParam); 

     // Output some messages to the window. 
     switch (wParam) 
     { 
     case DBT_DEVICEARRIVAL: 
      msgCount++; 
      StringCchPrintf(
       strBuff, 256, 
       TEXT("Message %d: DBT_DEVICEARRIVAL\n"), msgCount); 
      break; 
     case DBT_DEVICEREMOVECOMPLETE: 
      msgCount++; 
      StringCchPrintf(
       strBuff, 256, 
       TEXT("Message %d: DBT_DEVICEREMOVECOMPLETE\n"), msgCount); 
      break; 
     case DBT_DEVNODES_CHANGED: 
      msgCount++; 
      StringCchPrintf(
       strBuff, 256, 
       TEXT("Message %d: DBT_DEVNODES_CHANGED\n"), msgCount); 
      break; 
     default: 
      msgCount++; 
      StringCchPrintf(
       strBuff, 256, 
       TEXT("Message %d: WM_DEVICECHANGE message received, value %d unhandled.\n"), 
       msgCount, wParam); 
      break; 
     } 
     OutputMessage(hEditWnd, wParam, (LPARAM)strBuff); 
    } 
      break; 
    case WM_CLOSE: 
     if (! UnregisterDeviceNotification(hDeviceNotify)) 
     { 
      ErrorHandler(TEXT("UnregisterDeviceNotification")); 
     } 
     DestroyWindow(hWnd); 
     break; 

    case WM_DESTROY: 
     PostQuitMessage(0); 
     break; 

    default: 
     // Send all other messages on to the default windows handler. 
     lRet = DefWindowProc(hWnd, message, wParam, lParam); 
     break; 
    } 

    return lRet; 
} 

#define WND_CLASS_NAME TEXT("SampleAppWindowClass") 

// 
// InitWindowClass 
// 
BOOL InitWindowClass(void) 
// Routine Description: 
//  Simple wrapper to initialize and register a window class. 

// Parameters: 
//  None 

// Return Value: 
//  TRUE on success, FALSE on failure. 

// Note: 
//  wndClass.lpfnWndProc and wndClass.lpszClassName are the 
//  important unique values used with CreateWindowEx and the 
//  Windows message pump. 
{ 
    WNDCLASSEX wndClass; 

    wndClass.cbSize = sizeof(WNDCLASSEX); 
    wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; 
    wndClass.hInstance = (HINSTANCE)(GetModuleHandle(0)); 
    wndClass.lpfnWndProc = (WNDPROC)(WinProcCallback); 
    wndClass.cbClsExtra = 0; 
    wndClass.cbWndExtra = 0; 
    wndClass.hIcon = LoadIcon(0,IDI_APPLICATION); 
    wndClass.hbrBackground = CreateSolidBrush(RGB(192,192,192)); 
    wndClass.hCursor = LoadCursor(0, IDC_ARROW); 
    wndClass.lpszClassName = WND_CLASS_NAME; 
    wndClass.lpszMenuName = NULL; 
    wndClass.hIconSm = wndClass.hIcon; 


    if (! RegisterClassEx(&wndClass)) 
    { 
     ErrorHandler(TEXT("RegisterClassEx")); 
     return FALSE; 
    } 
    return TRUE; 
} 

// 
// main 
// 

int __stdcall _tWinMain(
         HINSTANCE hInstanceExe, 
         HINSTANCE hInst, // should not reference this parameter 
         PTSTR lpstrCmdLine, 
         int nCmdShow 
        ) 
{ 
// 
// To enable a console project to compile this code, set 
// Project->Properties->Linker->System->Subsystem: Windows. 
// 

    int nArgC = 0; 
    PWSTR* ppArgV = CommandLineToArgvW(lpstrCmdLine, &nArgC); 
    g_pszAppName = ppArgV[0]; 

    if (! InitWindowClass()) 
    { 
     // InitWindowClass displays any errors 
     return -1; 
    } 

    // Main app window 

    HWND hWnd = CreateWindowEx(
        WS_EX_CLIENTEDGE | WS_EX_APPWINDOW, 
        WND_CLASS_NAME, 
        g_pszAppName, 
        WS_OVERLAPPEDWINDOW, // style 
        CW_USEDEFAULT, 0, 
        640, 480, 
        NULL, NULL, 
        hInstanceExe, 
        NULL); 

    if (hWnd == NULL) 
    { 
     ErrorHandler(TEXT("CreateWindowEx: main appwindow hWnd")); 
     return -1; 
    } 

    // Actually draw the window. 

    ShowWindow(hWnd, SW_SHOWNORMAL); 
    UpdateWindow(hWnd); 

    // The message pump loops until the window is destroyed. 

    MessagePump(hWnd); 

    return 1; 
} 

// 
// OutputMessage 
// 
void OutputMessage(
    HWND hOutWnd, 
    WPARAM wParam, 
    LPARAM lParam 
) 
// Routine Description: 
//  Support routine. 
//  Send text to the output window, scrolling if necessary. 

// Parameters: 
//  hOutWnd - Handle to the output window. 
//  wParam - Standard windows message code, not used. 
//  lParam - String message to send to the window. 

// Return Value: 
//  None 

// Note: 
//  This routine assumes the output window is an edit control 
//  with vertical scrolling enabled. 

//  This routine has no error checking. 
{ 
    LRESULT lResult; 
    LONG  bufferLen; 
    LONG  numLines; 
    LONG  firstVis; 

    // Make writable and turn off redraw. 
    lResult = SendMessage(hOutWnd, EM_SETREADONLY, FALSE, 0L); 
    lResult = SendMessage(hOutWnd, WM_SETREDRAW, FALSE, 0L); 

    // Obtain current text length in the window. 
    bufferLen = SendMessage (hOutWnd, WM_GETTEXTLENGTH, 0, 0L); 
    numLines = SendMessage (hOutWnd, EM_GETLINECOUNT, 0, 0L); 
    firstVis = SendMessage (hOutWnd, EM_GETFIRSTVISIBLELINE, 0, 0L); 
    lResult = SendMessage (hOutWnd, EM_SETSEL, bufferLen, bufferLen); 

    // Write the new text. 
    lResult = SendMessage (hOutWnd, EM_REPLACESEL, 0, lParam); 

    // See whether scrolling is necessary. 
    if (numLines > (firstVis + 1)) 
    { 
     int  lineLen = 0; 
     int  lineCount = 0; 
     int  charPos; 

     // Find the last nonblank line. 
     numLines--; 
     while(!lineLen) 
     { 
      charPos = SendMessage(
       hOutWnd, EM_LINEINDEX, (WPARAM)numLines, 0L); 
      lineLen = SendMessage(
       hOutWnd, EM_LINELENGTH, charPos, 0L); 
      if(!lineLen) 
       numLines--; 
     } 
     // Prevent negative value finding min. 
     lineCount = numLines - firstVis; 
     lineCount = (lineCount >= 0) ? lineCount : 0; 

     // Scroll the window. 
     lResult = SendMessage(
      hOutWnd, EM_LINESCROLL, 0, (LPARAM)lineCount); 
    } 

    // Done, make read-only and allow redraw. 
    lResult = SendMessage(hOutWnd, WM_SETREDRAW, TRUE, 0L); 
    lResult = SendMessage(hOutWnd, EM_SETREADONLY, TRUE, 0L); 
} 

// 
// ErrorHandler 
// 
void ErrorHandler(
    LPTSTR lpszFunction 
) 
// Routine Description: 
//  Support routine. 
//  Retrieve the system error message for the last-error code 
//  and pop a modal alert box with usable info. 

// Parameters: 
//  lpszFunction - String containing the function name where 
//  the error occurred plus any other relevant data you'd 
//  like to appear in the output. 

// Return Value: 
//  None 

// Note: 
//  This routine is independent of the other windowing routines 
//  in this application and can be used in a regular console 
//  application without modification. 
{ 

    LPVOID lpMsgBuf; 
    LPVOID lpDisplayBuf; 
    DWORD dw = GetLastError(); 

    FormatMessage(
     FORMAT_MESSAGE_ALLOCATE_BUFFER | 
     FORMAT_MESSAGE_FROM_SYSTEM | 
     FORMAT_MESSAGE_IGNORE_INSERTS, 
     NULL, 
     dw, 
     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
     (LPTSTR) &lpMsgBuf, 
     0, NULL); 

    // Display the error message and exit the process. 

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
     (lstrlen((LPCTSTR)lpMsgBuf) 
        + lstrlen((LPCTSTR)lpszFunction)+40) 
        * sizeof(TCHAR)); 
    StringCchPrintf((LPTSTR)lpDisplayBuf, 
     LocalSize(lpDisplayBuf)/sizeof(TCHAR), 
     TEXT("%s failed with error %d: %s"), 
     lpszFunction, dw, lpMsgBuf); 
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, g_pszAppName, MB_OK); 

    LocalFree(lpMsgBuf); 
    LocalFree(lpDisplayBuf); 
} 

/*[email protected]@[email protected]@----------------------------------------------------------------*//*! 
\brief  Main_OnDeviceChange 
\date  Created on Sun Sep 10 15:10:10 2017 
\date  Modified on Sun Sep 10 15:10:10 2017 
\*//*[email protected]@[email protected]@----------------------------------------------------------------*/ 
void Main_OnDeviceChange(HWND hwnd, WPARAM wParam, LPARAM lParam) 
{ 
    PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam; 
    TCHAR szMsg[80]; 

    switch (wParam) 
    { 
     case DBT_DEVICEARRIVAL: 
      // Check whether a CD or DVD was inserted into a drive. 
      if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME) 
      { 
       PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb; 

       if (lpdbv->dbcv_flags & DBTF_MEDIA) 
       { 
        StringCchPrintf(szMsg, sizeof(szMsg)/sizeof(szMsg[0]), TEXT("Drive %c: Media has arrived.\n"), FirstDriveFromMask(lpdbv->dbcv_unitmask)); 

        //MessageBox(hwnd, szMsg, TEXT("WM_DEVICECHANGE"), MB_OK); 
       } 
       else 
       { 
        StringCchPrintf(szMsg, sizeof(szMsg)/sizeof(szMsg[0]), TEXT("Assigned drive letter '%c'\n"), FirstDriveFromMask(lpdbv->dbcv_unitmask)); 
       } 
       OutputMessage(hwnd, wParam, (LPARAM)szMsg); 
      } 
      break; 

     case DBT_DEVICEREMOVECOMPLETE: 
      // Check whether a CD or DVD was removed from a drive. 
      if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME) 
      { 
       PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb; 

       if (lpdbv->dbcv_flags & DBTF_MEDIA) 
       { 
        StringCchPrintf(szMsg, sizeof(szMsg)/sizeof(szMsg[0]), TEXT("Drive %c: Media was removed.\n"), FirstDriveFromMask(lpdbv->dbcv_unitmask)); 

        //MessageBox(hwnd, szMsg, TEXT("WM_DEVICECHANGE"), MB_OK); 
       } 
       else 
       { 
        StringCchPrintf(szMsg, sizeof(szMsg)/sizeof(szMsg[0]), TEXT("Disconnected drive '%c'\n"), FirstDriveFromMask(lpdbv->dbcv_unitmask)); 
       } 
       OutputMessage(hwnd, wParam, (LPARAM)szMsg); 
      } 
      break; 

     default: 
      /* 
       Process other WM_DEVICECHANGE notifications for other 
       devices or reasons. 
      */ 
      ; 
    } 
} 

/*------------------------------------------------------------------ 
    FirstDriveFromMask(unitmask) 

    Description 
    Finds the first valid drive letter from a mask of drive letters. 
    The mask must be in the format bit 0 = A, bit 1 = B, bit 2 = C, 
    and so on. A valid drive letter is defined when the 
    corresponding bit is set to 1. 

    Returns the first drive letter that was found. 
--------------------------------------------------------------------*/ 

char FirstDriveFromMask(ULONG unitmask) 
{ 
    char i; 

    for (i = 0; i < 26; ++i) 
    { 
    if (unitmask & 0x1) 
     break; 
    unitmask = unitmask >> 1; 
    } 

    return(i + 'A'); 
} 

基本上將reinterpret_cast刪除到C劇組。即:

wndClass.hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(0)); 

wndClass.hInstance = (HINSTANCE)(GetModuleHandle(0)); 

,並添加功能定義未使用的參數名稱(這是不允許的標準C)。即變化從:

int __stdcall _tWinMain(
         HINSTANCE hInstanceExe, 
         HINSTANCE, // should not reference this parameter 
         PTSTR lpstrCmdLine, 
         int nCmdShow 
        ) 

到:

int __stdcall _tWinMain(
         HINSTANCE hInstanceExe, 
         HINSTANCE hInst, // you **must define this parameter** even if it's not referenced 
         PTSTR lpstrCmdLine, 
         int nCmdShow 
        ) 

這些簡單的修改允許下純C編譯器的使用幾乎所有的MS的樣品。

我也添加了音量信息。

這裏詳細解釋設備通知框架如何工作只是浪費時間。 MS文檔是完整且詳盡的,您可以在MSDN上找到所有信息。

我所做的翻譯讓您有機會在簡單的C語言中研究和測試您的開發環境,這將允許您進行實驗。

無論如何,最基本的本質是:應用程序(您的程序)向通知服務器註冊自己,從現在開始,直到您取消註冊,將所有的Windows操作系統通知消息發送到您的應用程序。每個通知都攜帶特定結構中的特定信息數據。

隨每個通知提供的全套結構(記錄在MSDN上)爲您提供有關更改類型的詳細信息。

+0

我明白。 你能解釋一下如何檢測工作嗎? 這是我主要在我的問題中提到的部分。 再次,謝謝! :) – Jonathan

相關問題