2015-03-11 5 views
8

मैं यूएसबी सम्मिलन/निष्कासन का पता लगाने पर काम कर रहा हूं। मैंने CreateWindowEx() का उपयोग कर कोड लागू किया है, जो मेरी विंडो प्रक्रिया कॉलबैक के साथ एक WNCLASSEX गुजर रहा है। मेरे यूएसबी को डालने और हटाने पर, मुझे सफलतापूर्वक WM_DEVICECHANGE संदेश प्राप्त होता है, लेकिन wParam हमेशा DBT_DEVNODES_CHANGED पर सेट होता है।सी ++ Win32 WB_DEVICECHANGE पर DBT_DEVICEARRIVAL या DBT_DEVICEREMOVECOMPLETE प्राप्त नहीं कर रहा है

मुझे कभी भी DBT_DEVICEARRIVAL या DBT_DEVICEREMOVECOMPLETE नहीं मिलता है। मैं जो कुछ भी प्राप्त कर रहा हूं उसका उपयोग कर रहा हूं, लेकिन मुझे वास्तव में डिवाइस के आगमन और हटाने के बीच अंतर बताने में सक्षम होना चाहिए, ताकि मैं प्राप्त होने के आधार पर अलग-अलग कार्रवाइयां कर सकूं।

अभी, मुझे DBT_DEVNODES_CHANGED प्राप्त करने के बाद टाइमर डालना है, और फिर यह देखने के लिए परीक्षण करें कि सिस्टम पर कोई नया हटाने योग्य है या मेरी सूची में कोई भी नहीं है। मुझे यकीन है कि यह सही नहीं है, इसलिए मैंने सोचा कि मैं पूछूंगा। मैं टाइमर से छुटकारा पाने के लिए और इन दो संदेशों को प्राप्त करने के लिए बहुत कुछ करना चाहूंगा। इससे मुझे बहुत कुछ करने में मदद मिलेगी जो मुझे करना है। कोई सुझाव?

नोट:: 2015/03/12: कोड वास्तविक GUID और DoRegisterDeviceInterfaceToHwnd की परिभाषा (दिखाने के लिए अद्यतन) समारोह

यहाँ कोड मैं कॉलबैक पंजीकरण के लिए है, और साथ ही कॉलबैक ही है ।):

GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, 0x8a,0x6d,0xb5,0x4c,0x2b,0x4f,0xc8,0x35 }; 
//GUID WusbrawGUID = {0xa5dcbf10, 0x6530, 0x11d2, 0x90, 0x1f, 0x00, 0xc0, 0x4f, 0xb9, 0x51, 0xed }; 
//GUID WusbGUID = {0x88BAE032, 0x5A81, 0x49f0, 0xBC, 0x3D, 0xA4, 0xFF, 0x13, 0x82, 0x16, 0xD6 }; 

INT_PTR WINAPI WinProcCallback(HWND __hWnd, UINT message, WPARAM wParam, LPARAM lParam); 
BOOL DoRegisterDeviceInterfaceToHwnd(GUID InterfaceClassGuid, HWND __hWnd, HDEVNOTIFY *hDeviceNotify); 

bool UsbController::startNotifyUsbAddedRemoved(QString &errmsg) 
{ 
    WNDCLASSEX wndClass; 

    wndClass.cbSize = sizeof(wndClass); 
    wndClass.style = 0; 
    wndClass.hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(0)); 
    wndClass.lpfnWndProc = reinterpret_cast<WNDPROC>(WinProcCallback); 
    wndClass.cbClsExtra = 0; 
    wndClass.cbWndExtra = 0; 
    wndClass.hIcon = LoadIcon(0, IDI_APPLICATION); 
    wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 
    wndClass.hCursor = LoadCursor(0, IDC_ARROW); 
    wndClass.lpszClassName = WND_CLASS_NAME; 
    wndClass.lpszMenuName = NULL; 
    wndClass.hIconSm = LoadIcon(0, IDI_APPLICATION); 

    if (!RegisterClassEx(&wndClass)) 
    { 
     FormatErrorMsg("RegisterClassEx: ", errmsg); 
     return false; 
    } 

    HINSTANCE hInstance = (HINSTANCE)::GetModuleHandle(NULL); 
    __hWnd = CreateWindowEx(
        WS_EX_CLIENTEDGE | WS_EX_APPWINDOW, 
        WND_CLASS_NAME, 
        WND_APP_NAME, 
        WS_OVERLAPPEDWINDOW, // style 
        CW_USEDEFAULT, 0, 
        0, 0, 
        NULL, NULL, 
        hInstance, 
        NULL); 

    if (__hWnd == NULL) 
    { 
     FormatErrorMsg("CreateWindowEx: ", errmsg); 
     return false; 
    } 

    return true; 
} 

INT_PTR WINAPI WinProcCallback(HWND __hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    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. 
      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. 
      // 

      // Output some messages to the window. 
      UsbController *pusbctl; 
      switch (wParam) 
      { 
      case DBT_DEVICEARRIVAL: 
       msgCount++; 
       pusbctl = UsbController::instance(); 
       pusbctl->signalDeviceArrival(); 
       break; 
      case DBT_DEVICEREMOVECOMPLETE: 
       msgCount++; 
       pusbctl = UsbController::instance(); 
       pusbctl->signalDeviceRemoval(); 
       break; 
      case DBT_DEVNODES_CHANGED: 
       msgCount++; 
       pusbctl = UsbController::instance(); 
       pusbctl->signalDeviceAddedRemoved(); 
       break; 
      default: 
       msgCount++; 
       break; 
      } 
     } 
     break; 

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

    return lRet; 
} 

BOOL DoRegisterDeviceInterfaceToHwnd(GUID InterfaceClassGuid, HWND __hWnd, HDEVNOTIFY *hDeviceNotify) 
{ 
    DEV_BROADCAST_DEVICEINTERFACE NotificationFilter; 

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

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

    if (NULL == *hDeviceNotify) 
    { 
     return FALSE; 
    } 

    return TRUE; 
} 
+0

क्या आपने https://msdn.microsoft.com/en-us/library/windows/desktop/aa363215(v=vs.85).aspx देखा था?यह कहता है कि आपको मीडिया आगमन अधिसूचनाएं प्राप्त करने के लिए वास्तव में पंजीकरण करने की आवश्यकता नहीं है। मुझे आश्चर्य है कि यदि आप ** ** ** पंजीकरण कर रहे हैं तो यह तथ्य किसी तरह से हस्तक्षेप कर सकता है। –

+1

हम्म, मेरी क्रिस्टल बॉल कहती है कि आप इसे प्रोग्रामर के तरीके से कर रहे हैं, बस "सुरक्षित रूप से हार्डवेयर निकालें" के माध्यम से बिना डिवाइस को झटके कर रहे हैं। और फिर आशा करें कि विंडोज दूसरे अनुमान लगा सकता है कि क्या हो सकता है। अच्छा, ऐसा हुआ, यह आपको इसके बारे में बताया। –

+0

वास्तव में, मैंने निश्चित रूप से "सुरक्षित रूप से हार्डवेयर निकालें" प्रक्रिया की है। अधिसूचना जो मैं करता हूं वहां 7 का मान होता है, जो कि DBT_DEVNODES_CHANGED है। मुझे उस क्रिया से आने वाले कई संदेश मिलते हैं (अभी तक डिवाइस को अपने स्लॉट से नहीं खींच लिया गया है), जिनमें से सभी का मूल्य 7 है। बेशक, जब मैं डिवाइस खींचता हूं, तो मुझे वही मान मिलता है। डिवाइस डालने के समान सटीक परिणाम हैं। मुझे कई संदेश मिलते हैं, और उनमें से सभी के पास DBT_DEVNODES_CHANGED के लिए मान 7 है। – bmahf

उत्तर

10

आप MSDN के दस्तावेज़ पढ़ें, तो यह कहते हैं:

Detecting Media Insertion or Removal

विंडोज सभी शीर्ष-स्तरीय विंडोज़ डिफ़ॉल्ट WM_DEVICECHANGE संदेशों का एक सेट भेजता है जब नए डिवाइस या मीडिया (जैसे सीडी या डीवीडी) जोड़े जाते हैं और उपलब्ध हो जाते हैं, और जब मौजूदा डिवाइस या मीडिया हटा दिए जाते हैं। आपको इन डिफ़ॉल्ट संदेशों को प्राप्त करने के लिए पंजीकरण करने की आवश्यकता नहीं है। डिफ़ॉल्ट रूप से संदेश पर भेजे गए संदेशों के विवरण के लिए RegisterDeviceNotification में टिप्पणियां अनुभाग देखें।

RegisterDeviceNotification function

एक शीर्ष स्तर खिड़की के साथ किसी भी आवेदन WM_DEVICECHANGE संदेश प्रसंस्करण द्वारा बुनियादी सूचनाएं प्राप्त कर सकते हैं। आवेदन डिवाइस नोटिफिकेशन प्राप्त करने के लिए रजिस्टर करने के लिए RegisterDeviceNotification फ़ंक्शन का उपयोग कर सकते हैं।
...
DBT_DEVICEARRIVAL और DBT_DEVICEREMOVECOMPLETE घटनाओं स्वचालित रूप से पोर्ट उपकरणों के लिए सभी उच्च-स्तरीय खिड़कियों के लिए प्रसारित किया जाता है। इसलिए, बंदरगाहों के लिए RegisterDeviceNotification को कॉल करना आवश्यक नहीं है, और फ़ंक्शन विफल रहता है यदि dbch_devicetype सदस्य DBT_DEVTYP_PORT है।

DEV_BROADCAST_HDR structure

DBT_DEVTYP_PORT
0x00000003

पोर्ट डिवाइस (धारावाहिक या समानांतर)।यह संरचना एक DEV_BROADCAST_PORT संरचना है।

एक यूएसबी डिवाइस एक धारावाहिक/समांतर बंदरगाह नहीं है। यह इसके बजाय एक डिवाइस इंटरफेस (DBT_DEVTYP_DEVICEINTERFACE) है। और DBT_DEVICEARRIVAL/DBT_DEVICEREMOVECOMPLETE डिवाइस डिफ़ॉल्ट रूप से के लिए नहीं भेजे गए हैं। यदि आप उन्हें चाहते हैं, तो आपको अनुरोध करने के लिए RegisterDeviceNotification() का उपयोग करना होगा।

ऐसा लगता है कि अपने कोड की तरह इस MSDN उदाहरण पर आधारित है:

Registering for Device Notification

कि कोड में, WceusbshGUID{25dbce51-6c8f-4a72-8a6d-b54c2b4fc835} के रूप में परिभाषित किया गया है, जो वर्ग यूएसबी सीरियल मेजबान PnP चालकों के लिए guid होने के रूप में टिप्पणी की है। इस MSDN पेज के अनुसार: GUID वर्ग Windows CE यूएसबी ActiveSync डिवाइस (जो कोड में इस्तेमाल किया Wceusb... उपसर्ग के साथ और अधिक सुसंगत है) के लिए guid है

System-Defined Device Setup Classes Available to Vendors

है। यूएसबी डिवाइस (सभी यूएसबी डिवाइस किसी अन्य वर्ग से संबंधित नहीं हैं) पर उसी पृष्ठ पर {88BAE032-5A81-49f0-BC3D-A4FF138216D6} है।

निम्नलिखित CodeProject लेख:

Detecting Hardware Insertion and/or Removal

उल्लेख किए जाने पर यूएसबी कच्चे डिवाइस के लिए {a5dcbf10-6530-11d2-901f-00c04fb951ed}। उसी मार्गदर्शिका को एमएसडीएन पर GUID_DEVINTERFACE_USB_DEVICE के रूप में दस्तावेज किया गया है (जिसका नाम संभवतः पूर्व-एक्सपी दिनों में आता है जब क्लास गाइड और इंटरफ़ेस guids was not well separated का नामकरण)।

तो जब आप एक विशिष्ट वर्ग GUID साथ RegisterDeviceNotification() कहते हैं, यह सही वर्ग GUID है, जैसा कि आप डिवाइस के केवल उस विशिष्ट प्रकार के लिए डिवाइस घटनाओं पाने के लिए जा रहे हैं सुनिश्चित करें। ऐसा लगता है कि आपका यूएसबी डिवाइस आपके द्वारा पंजीकृत किए जा रहे एक से अधिक क्लास गाइड का उपयोग कर रहा है, और यही कारण है कि आपको डिवाइस की घटनाएं नहीं मिल रही हैं जिनकी आप उम्मीद कर रहे हैं।

आप अपने वर्ग GUID की परवाह किए बिना किसी भी USB डिवाइस का पता लगाने के लिए (और वहाँ कई यूएसबी वर्ग guids परिभाषित कर रहे हैं) चाहते हैं, आप जब RegisterDeviceNotification() बुला DEVICE_NOTIFY_ALL_INTERFACE_CLASSES ध्वज का उपयोग कर सकते, तो वर्ग GUID नजरअंदाज कर दिया जाएगा। DBT_DEVICEARRIVAL और DBT_DEVICEREMOVECOMPLETE संदेशों में (मान लीजिए कि आप उन्हें प्राप्त करने में सक्षम हैं), रिपोर्ट की गई dbcc_classguid आपको वास्तविक कक्षा मार्गदर्शिका बताएगी, और रिपोर्ट की गई dbcc_name\\?\USB: उपसर्ग के साथ शुरू होगी।

एक आखिरी बात - आपको केवल DBT_DEVICE... संदेश प्राप्त होने जा रहे हैं यदि आपका ऐप पहले से चल रहा है, तो एक यूएसबी डिवाइस डाला/हटा दिया गया है। यह पता लगाने के लिए कि क्या आपका ऐप शुरू होने पर एक यूएसबी डिवाइस पहले से प्लग हो चुका है, आपको उपलब्ध उपकरणों का आकलन करने के लिए SetupAPI फ़ंक्शन (SetupDiGetClassDevs(), SetupDiEnumDeviceInterfaces(), SetupDiGetDeviceInterfaceDetail(), आदि) का उपयोग करना होगा।

+0

हां, मुझे खेद है, मैंने प्रयुक्त GUID के लिए परिभाषाओं को छोड़ दिया है, और DoRegisterDeviceInterfaceToHwnd() को कॉल करने के लिए। मैंने बस उन्हें वहां वापस जोड़ा। – bmahf

+0

क्या आपने मुझे दिए गए अन्य क्लास गाइड की कोशिश की? –

+1

हो गया और परीक्षण किया गया। आपके सुझावों से, मैंने RegisterDeviceNotification() को कॉल बदलना समाप्त कर दिया ताकि मैं DEVICE_NOTIFY_ALL_INTERFACE_CLASSES को DEVICE_NOTIFY_WINDOW_HANDLE की बजाय ध्वज के रूप में पास कर सकूं। उसके बाद, मैं एलपीएआरएम के लिए एक गैर-शून्य मूल्य प्राप्त करने में सक्षम था। इसने मुझे paramguid और paramName दिया, जिनमें से दोनों मुझे वास्तव में देख रहे थे कि मैं वास्तव में क्या देख रहा हूं, में बहुत उपयोगी था, इसलिए मैं यह सुनिश्चित कर सकता हूं कि यह सुरक्षा प्लग के रूप में कुछ अन्य प्लग करने योग्य डिवाइस की बजाय यूएसबी ड्राइव है। पॉइंटर्स के लिए धन्यवाद। – bmahf

संबंधित मुद्दे