【问题标题】:Any Windows API for detecting MTP devices?任何用于检测 MTP 设备的 Windows API?
【发布时间】:2016-11-20 16:46:42
【问题描述】:

我正在寻找通过 Windows API 检测 MTP 设备,而不仅仅是枚举已连接的设备。

【问题讨论】:

  • 我不知道这意味着什么 - 您将如何检测未连接到计算机的设备?您的问题不是特定的 API,而是了解 Windows 如何管理设备。即插即用是自动的。
  • 是的,我想知道用于设备插件检测的 api。每当有任何类型的设备插头时,我都会收到通知。
  • AFAIK 实际上不可能监听 MTP 设备 但是您通常可以监听设备事件,您只需要在每个事件上过滤掉您想要的事件,然后应该是这样。 MSalters 的回答将为您提供指导 - this 将向您介绍该主题。
  • 如何通过 API 阻止这些 MTP 设备??
  • ....什么? “通过 API 阻止” 是什么意思?

标签: c++ windows mtp wpd


【解决方案1】:
【解决方案2】:

那就是DBT_DEVICEARRIVAL 事件。

【讨论】:

    【解决方案3】:

    详细说明 MSalters 的答案,这个问题的答案可能会对您有所帮助 - C++ Win32 Not receiving DBT_DEVICEARRIVAL or DBT_DEVICEREMOVECOMPLETE on WM_DEVICECHANGE

    基本总结如下:

    1. 在处理WM_CREATE 消息时,调用RegisterDeviceNotification,将要过滤的USB 类GUID 作为第二个参数传递,或者将DEVICE_NOTIFY_ALL_INTERFACE_CLASSES 作为第三个参数传递以处理所有USB 设备类
    2. 在处理WM_DEVICECHANGE消息时,将消息的lParam字段转换为PDEV_BROADCAST_HDR结构,如果其dbch_devicetype字段表明它是DBT_DEVTYP_DEVICEINTERFACE,则进一步将其转换为PDEV_BROADCAST_DEVICEINTERFACE;同时使用wParam字段来确定消息是否与DBT_DEVICEARRIVALDBT_DEVICEREMOVECOMPLETEDBT_DEVNODES_CHANGED事件相关联(lParam将在最后一种情况下为NULL
    3. 在处理WM_CLOSE 消息时,使用从步骤1 返回的句柄调用UnregisterDeviceNotification

    除了上面链接的 SO 问题外,我还引用了 Detecting Media Insertion or RemovalRegistering for device notification。我相信这个问题也引用了他们。

    以下是我的主要源代码的完整列表,最初基于库存的 Windows 桌面向导项目模板,应用程序类型桌面应用程序 (.exe) 并选择了预编译头。不是我最干净的代码,有点像上面引用的科学怪人,但它明白了这一点。

    // DevDetectDemo.cpp : Defines the entry point for the application.
    //
    
    #include "pch.h"
    #include "framework.h"
    #include "DevDetectDemo.h"
    
    #define MAX_LOADSTRING 100
    
    // Global Variables:
    HINSTANCE hInst;                                // current instance
    WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
    WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
    
    // Forward declarations of functions included in this code module:
    ATOM                MyRegisterClass(HINSTANCE hInstance);
    BOOL                InitInstance(HINSTANCE, int);
    LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
    INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
    BOOL                DoRegisterDeviceInterfaceToHwnd(GUID, HWND, HDEVNOTIFY*);
    void                Main_OnDeviceChange(HWND hwnd, WPARAM wParam, LPARAM lParam);
    
    int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                         _In_opt_ HINSTANCE hPrevInstance,
                         _In_ LPWSTR    lpCmdLine,
                         _In_ int       nCmdShow)
    {
        UNREFERENCED_PARAMETER(hPrevInstance);
        UNREFERENCED_PARAMETER(lpCmdLine);
    
        // TODO: Place code here.
    
        // Initialize global strings
        LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
        LoadStringW(hInstance, IDC_DEVDETECTDEMO, szWindowClass, MAX_LOADSTRING);
        MyRegisterClass(hInstance);
    
        // Perform application initialization:
        if (!InitInstance (hInstance, nCmdShow))
        {
            return FALSE;
        }
    
        HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_DEVDETECTDEMO));
    
        MSG msg;
    
        // Main message loop:
        while (GetMessage(&msg, nullptr, 0, 0))
        {
            if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    
        return (int) msg.wParam;
    }
    
    
    
    //
    //  FUNCTION: MyRegisterClass()
    //
    //  PURPOSE: Registers the window class.
    //
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
        WNDCLASSEXW wcex;
    
        wcex.cbSize = sizeof(WNDCLASSEX);
    
        wcex.style          = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc    = WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = hInstance;
        wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DEVDETECTDEMO));
        wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
        wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_DEVDETECTDEMO);
        wcex.lpszClassName  = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    
        return RegisterClassExW(&wcex);
    }
    
    //
    //   FUNCTION: InitInstance(HINSTANCE, int)
    //
    //   PURPOSE: Saves instance handle and creates main window
    //
    //   COMMENTS:
    //
    //        In this function, we save the instance handle in a global variable and
    //        create and display the main program window.
    //
    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
       hInst = hInstance; // Store instance handle in our global variable
    
       HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
    
       if (!hWnd)
       {
          return FALSE;
       }
    
       ShowWindow(hWnd, nCmdShow);
       UpdateWindow(hWnd);
    
       return TRUE;
    }
    
    //
    //  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
    //
    //  PURPOSE: Processes messages for the main window.
    //
    //  WM_COMMAND  - process the application menu
    //  WM_PAINT    - Paint the main window
    //  WM_DESTROY  - post a quit message and return
    //
    //
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        static HDEVNOTIFY hDeviceNotify;
    
        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(
                GUID_DEVINTERFACE_USB_DEVICE,
                hWnd,
                &hDeviceNotify))
            {
                // Terminate on failure.
                ExitProcess(1);
            }
            break;
        case WM_COMMAND:
            {
                int wmId = LOWORD(wParam);
                // Parse the menu selections:
                switch (wmId)
                {
                case IDM_ABOUT:
                    DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                    break;
                case IDM_EXIT:
                    DestroyWindow(hWnd);
                    break;
                default:
                    return DefWindowProc(hWnd, message, wParam, lParam);
                }
            }
            break;
        case WM_PAINT:
            {
                PAINTSTRUCT ps;
                HDC hdc = BeginPaint(hWnd, &ps);
                // TODO: Add any drawing code that uses hdc here...
                EndPaint(hWnd, &ps);
            }
            break;
        case WM_DEVICECHANGE:
            Main_OnDeviceChange(hWnd, wParam, lParam);
            break;
        case WM_CLOSE:
            UnregisterDeviceNotification(hDeviceNotify);
            DestroyWindow(hWnd);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
    
    // Message handler for about box.
    INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
        UNREFERENCED_PARAMETER(lParam);
        switch (message)
        {
        case WM_INITDIALOG:
            return (INT_PTR)TRUE;
    
        case WM_COMMAND:
            if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
            {
                EndDialog(hDlg, LOWORD(wParam));
                return (INT_PTR)TRUE;
            }
            break;
        }
        return (INT_PTR)FALSE;
    }
    
    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; can also be
                                        // DEVICE_NOTIFY_ALL_INTERFACE_CLASSES to
                                        // ignore filter and notify of all devices
        );
    
        if (NULL == *hDeviceNotify)
        {
            return FALSE;
        }
    
        return TRUE;
    }
    
    /*------------------------------------------------------------------
       Main_OnDeviceChange( hwnd, wParam, lParam )
    
       Description
          Handles WM_DEVICECHANGE messages sent to the application's
          top-level window.
    --------------------------------------------------------------------*/
    
    void Main_OnDeviceChange(HWND hwnd, WPARAM wParam, LPARAM lParam)
    {
        PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
        TCHAR szMsg[256];
    
        switch (wParam)
        {
        case DBT_DEVICEARRIVAL:
            // Check whether a device was inserted.
            if (lpdb->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
            {
                PDEV_BROADCAST_DEVICEINTERFACE lpdbd = (PDEV_BROADCAST_DEVICEINTERFACE)lpdb;
    
                GUID guid = lpdbd->dbcc_classguid;
                StringCchPrintf(szMsg, sizeof(szMsg) / sizeof(szMsg[0]),
                    TEXT("Device %s Media with class GUID {%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX} has arrived.\n"),
                    lpdbd->dbcc_name,
                    guid.Data1, guid.Data2, guid.Data3,
                    guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
                    guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
    
                MessageBox(hwnd, szMsg, TEXT("WM_DEVICECHANGE"), MB_OK);
            }
            break;
    
        case DBT_DEVICEREMOVECOMPLETE:
            // Check whether a device was removed.
            if (lpdb->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
            {
                PDEV_BROADCAST_DEVICEINTERFACE lpdbd = (PDEV_BROADCAST_DEVICEINTERFACE)lpdb;
    
                GUID guid = lpdbd->dbcc_classguid;
                StringCchPrintf(szMsg, sizeof(szMsg) / sizeof(szMsg[0]),
                    TEXT("Device %s Media with class GUID {%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX} was removed.\n"),
                    lpdbd->dbcc_name,
                    guid.Data1, guid.Data2, guid.Data3,
                    guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
                    guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
    
                MessageBox(hwnd, szMsg, TEXT("WM_DEVICECHANGE"), MB_OK);
            }
            break;
    
        case DBT_DEVNODES_CHANGED:
            // Check whether a device has been added to or removed from the system.
            StringCchPrintf(szMsg, sizeof(szMsg) / sizeof(szMsg[0]),
                TEXT("Device was was added/removed.\n"));
    
            MessageBox(hwnd, szMsg, TEXT("WM_DEVICECHANGE"), MB_OK);
            break;
    
        default:
            /*
              Process other WM_DEVICECHANGE notifications for other
              devices or reasons.
            */
            ;
        }
    }
    

    随附的标题:

    // pch.h: This is a precompiled header file.
    // Files listed below are compiled only once, improving build performance for future builds.
    // This also affects IntelliSense performance, including code completion and many code browsing features.
    // However, files listed here are ALL re-compiled if any one of them is updated between builds.
    // Do not add files here that you will be updating frequently as this negates the performance advantage.
    
    #ifndef PCH_H
    #define PCH_H
    
    // add headers that you want to pre-compile here
    #include "framework.h"
    #include <Dbt.h>
    #include <strsafe.h>
    
    #include <initguid.h>
    #include <Usbiodef.h>
    
    #pragma comment(lib, "user32.lib")
    
    #endif //PCH_H
    

    框架.h

    #pragma once
    
    #include "targetver.h"
    #define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
    // Windows Header Files
    #include <windows.h>
    // C RunTime Header Files
    #include <stdlib.h>
    #include <malloc.h>
    #include <memory.h>
    #include <tchar.h>
    

    DevDetectDemo.h

    #pragma once
    
    #include "resource.h"
    

    我发现对于我的设备,使用DEVICE_NOTIFY_ALL_INTERFACE_CLASSES 进行连接和断开连接会导致指示许多类 GUID,具体取决于是否在开发人员选项中启用了 USB 调试。不带USB调试:

    带USB调试:

    如您所见,这两组之间唯一共同的 GUID 是 GUID_DEVINTERFACE_USB_DEVICE,这是我在上面的示例中使用的。

    【讨论】:

    • targetver.h 和 resource.h 是什么?
    • @DonaldDuck 不是这些方面的专家;它们通常与项目模板一起生成。就我目前的理解而言,targetver.h 用于定义每个目标规范(例如操作系统版本)正在使用的 Win32 API 定义的子集; resource.h 定义了应用程序的资源标识符,例如图标或本地化字符串,您可能会在随附的 resource.rc 编译资源文件中找到这些内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-05
    • 2010-11-20
    • 2018-03-22
    • 2012-12-30
    • 1970-01-01
    • 2018-01-25
    相关资源
    最近更新 更多