2017-09-10 4 views
2

J'ai essayé de regarder autour et a trouvé quelques solutions pour détecter une insertion de clé USB, mais aucun que j'ai trouvé était en fait travaillé dans C.détecter l'insertion d'une clé USB dans C (Windows)

Je voulais demander, comment J'aborde ce problème? Quelle est l'idée derrière le processus de détection (Comme, comment est-ce fait)?

Merci d'avance! :)

+0

Une recherche de google révèle ceci [question C++ précédente] (https://stackoverflow.com/questions/4078909/detecting-usb-insertion-removal-events-in-windows-using-c) et [Enregistrement pour notification de périphérique] (https://msdn.microsoft.com/en-us/library/windows/desktop/aa363432(v=vs.85).aspx) et [Détecter l'insertion ou la suppression de médias] (https://msdn.microsoft.com /en-us/library/windows/desktop/aa363215(v=vs.85).aspx). –

+0

@WeatherVane Salut :)! J'ai vu cette solution, mais malheureusement j'ai besoin d'une solution pour cela en C:/ Merci! : D – Jonathan

+0

Eh bien, vous pouvez en écrire un en fonction de l'information? –

Répondre

3

L'exemple sur le lien https://msdn.microsoft.com/en-us/library/windows/desktop/aa363432(v=vs.85).aspx, donné par Weather Vane, fonctionne en langage C, comme je l'ai dit dans les commentaires, avec de simples modifications.

Vous trouverez ci-dessous le code modifié.

#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'); 
} 

Fondamentalement, supprimer reinterpret_cast en C coulées. I.e. .:

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

à

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

Et ajouter le nom des paramètres non utilisés dans la définition des fonctions (non autorisé dans la norme C). C'est à dire. changement de:

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 
        ) 

Ces simples modifications permettent l'utilisation de presque tous les échantillons sous MS compilateurs C-ordinaire.

J'ai également ajouté des informations sur le volume. Pour expliquer ici en détail le fonctionnement du cadre de notification de périphérique, il suffit de perdre du temps. La documentation MS est complète et exhaustive, vous pouvez trouver toutes les informations sur MSDN. La traduction que j'ai faite vous donne l'opportunité d'étudier et de tester votre environnement de développement en langage C, ce qui permettra de faire des expérimentations. De toute façon l'essentiel est: l'application (votre programme) s'enregistre auprès du serveur de notification, qui à son tour, à partir de maintenant jusqu'à ce que vous l'annuliez, envoie tous les messages de notification de Windows OS à votre application. Chaque notification contient des informations spécifiques dans des structures spécialisées.

L'ensemble complet de la structure fournie avec chaque notification (documenté sur MSDN) vous donne des informations détaillées sur le type de modification.

+0

Je comprends. Pouvez-vous expliquer comment fonctionne la détection? C'est la partie dont je parlais surtout dans ma question. Encore une fois, merci! :) – Jonathan