SetupAPI简介与设备管理

来源:互联网 发布:最新软件代理 编辑:程序博客网 时间:2024/05/17 06:06

SetupAPI简介与设备管理

SetupAPI的定位


SetupAPI是一个被用来执行安装设备的一系列操作的方法的集合,主要用于安装设备驱动(device driver),被用在类安装程序(class installers)、协安装程序(co-installers)和设备安装应用程序(device installation applications)中。

下图描绘了设备安装过程中的组件,也包括SetupAPI在其中所扮演的角色

原文请进

SetupAPI Functions Set


SetupAPI的方法集分为两大部分:

  1. General setup functions

    • 读取和处理INF文件
    • 确定安装在目标系统上所需的可用空间大小
    • 将文件从源介质移至所安装的目标系统的介质上,如果需要的话要求用户介入
    • 创建在安装期间移动的文件的日志
    • 将日志条目写入SetupAPI text logs

    更多关于using-general-setup-functions

  2. Device installation functions

    • 安装驱动
    • 处理DIF代码
    • 管理设备信息集
    • 管理驱动列表
    • 管理设备接口
    • 管理图标以及其它的位图

    更多关于using-device-installation-functions

SetupAPI与枚举设备


从上一节中可见SetupAPI的方法集中有专门的一部分用以管理设备信息集。那么接下来,首先要做的就是最简单的功能——枚举设备信息。I

在SetupAPI中利用设备信息集(Device Information Sets)这样一种结构来组织各个设备的信息

更多关于device-information-sets

当需要获取一个或多个设备的描述信息时,必须先创建一个设备信息集,然后通过枚举列表中元素的方式获取设备信息元素(Device Information Element),进而获得所需的设备信息。

/************************************** BOOL EnumAllDevice( )* 功能    列举当前存在的设备* 返回值   是否成功**************************************/BOOL EnumAllDevice(){    HDEVINFO hDevInfo;    //包含了设备的ClassGUID和设备实例句柄,大体上相当于设备信息元素(无device interface)    SP_DEVINFO_DATA DeviceInfoData;    DWORD i;    printf("Displaying the Installed Devices\n\n");    TCHAR szGUID[] = _T("4D36E97C-E325-11CE-BFC1-08002BE10318");     GUID guid;                  //全局唯一标识符(GUID,Globally Unique Identifier)    UuidFromString((RPC_WSTR)szGUID, &guid);    //创建一个设备信息集(device information set),其中包含了我们请求的设备信息元素(device information element)    //该方法只用于获取本机设备,远程计算机上的设备需要使用SetupDiGetClassDevsEx    //成功则返回一个设备信息集的Handle,失败则返回INVALID_HANDLE_VALUE    hDevInfo = SetupDiGetClassDevs(    &guid,  // 指定一个GUID(for a device setup class or a device interface class)用以过滤元素    0,      // Enumerator 可为NULL    0,      // hwndParent 可为NULL    DIGCF_PRESENT | DIGCF_ALLCLASSES ); //列表的过滤选项,当为DIGCF_ALLCLASSES时,参数1指定的guid将不再起作用    if (hDevInfo == INVALID_HANDLE_VALUE)    {        return FALSE;    }    // 循环列举    DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);    //枚举设备信息列表中的元素,将元素以SP_DEVINFO_DATA结构体的方式输出    for (i=0;SetupDiEnumDeviceInfo(hDevInfo,i, &DeviceInfoData);i++)        {        DWORD DataT;        LPTSTR buffer = NULL;        DWORD buffersize = 0;        // 获取详细信息        while (!SetupDiGetDeviceRegistryProperty(            hDevInfo,            &DeviceInfoData,            SPDRP_DEVICEDESC,   //属性标识,用以指示buffer输出的是哪个属性值,在此是要求输出设备描述字符串            &DataT,            (PBYTE)buffer,      //输出值            buffersize,            &buffersize))       //所需的buff空间        {            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)            {                // 内存不足,则重新分配buff空间                if (buffer)                     HeapFree(GetProcessHeap(), 0, buffer);                buffer = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, buffersize);            }            else                break;        }        // 输出        wprintf(L"GUID:{%.8X-%.4X-%.4X--%.2X%.2X-%.2X%.2X%.2X%.2X%.2X%.2X} \tDevice: %s\n",            DeviceInfoData.ClassGuid.Data1,            DeviceInfoData.ClassGuid.Data2,            DeviceInfoData.ClassGuid.Data3,            DeviceInfoData.ClassGuid.Data4[0],            DeviceInfoData.ClassGuid.Data4[1],            DeviceInfoData.ClassGuid.Data4[2],            DeviceInfoData.ClassGuid.Data4[3],            DeviceInfoData.ClassGuid.Data4[4],            DeviceInfoData.ClassGuid.Data4[5],            DeviceInfoData.ClassGuid.Data4[6],            DeviceInfoData.ClassGuid.Data4[7],            buffer);        if (buffer) HeapFree(GetProcessHeap(), 0, buffer);    }    if ( GetLastError() != NO_ERROR         && GetLastError() != ERROR_NO_MORE_ITEMS )    {        return FALSE;    }    // 释放    SetupDiDestroyDeviceInfoList(hDevInfo);    return TRUE;}

Device Setup Class 和 Device Interface Class之间的区别 在于:

To facilitate device installation, devices that are set up and configured in the same manner are grouped into a device setup class.

更多关于device-setup-class

Device Setup Class是对于设备的安装进行分类,在安装过程中具有相同方式的设备被分为一类。一个设备的Device Setup Class决定了在安装过程中哪个类安装程序(class installer)和协安装程序(co-installers)将会参与进来。

A device interface class is a way of exporting device and driver functionality to other system components, including other drivers, as well as user-mode applications. A driver can register a device interface class, then enable an instance of the class for each device object to which user-mode I/O requests might be sent.

更多关于device-interface-class

Device Interface Class是在设备的使用过程中,对具有同样功能的设备进行的分类。驱动不再为每个设备单独命名,并将该名字交由用户模式下的程序来进行I/O请求,相反,对某个设备的直接请求转化为对该类的请求,也就是说,在请求一个打印机类打印文件的时候,用户将无法预测实际上是哪一台打印机实际打印了文件(当然,我们有多台打印机)。

禁用和开启设备


无论开启或禁用,都需要调用SetupAPI中的两个函数: SetupDiSetClassInstallParamsSetupDiCallClassInstaller 前者 用于设置类安装参数,后者用于调用类安装程序和任何注册过的协安装程序。

BOOL SetupDiSetClassInstallParams(    _In_ HDEVINFO DeviceInfoSet,    _In_opt_ PSP_DEVINFO_DATA DeviceInfoData,    _In_opt_ PSP_CLASSINSTALL_HEADER ClassInstallParams,    _In_ DWORD ClassInstallParamsSize);

SetupDiSetClassInstallParams 函数的核心在于第三个参数。

PSP_CLASSINSTALL_HEADER 是任何类安装参数(class install parameter)的第一个成员,里面主要内容是一个 DI_FUNCTION 类型的设备安装方法(DIF,Device Installation Function),且被定义为 DIF_XXX 的形式。

这里的 ClassInstallParams 要填入的也就是一个类安装参数的指针,当然它的第一个成员必须是 PSP_CLASSINSTALL_HEADER 。参数4的size指的是整个类安装参数的大小而不仅仅是 PSP_CLASSINSTALL_HEADER 的大小。

BOOL SetupDiCallClassInstaller(    _In_ DI_FUNCTION InstallFunction,    _In_ HDEVINFO DeviceInfoSet,    _In_opt_ PSP_DEVINFO_DATA DeviceInfoData);

这是改变设备状态的代码,如下:

BOOL StateChange( DWORD dwNewState, DWORD dwDevID, HDEVINFO hDevInfo){    SP_PROPCHANGE_PARAMS PropChangeParams;    SP_DEVINFO_DATA DevInfoData = {sizeof(SP_DEVINFO_DATA)};    SP_DEVINSTALL_PARAMS devParams;    //查询设备信息    if (!SetupDiEnumDeviceInfo( hDevInfo, dwDevID, &DevInfoData))    {        OutputDebugString("SetupDiEnumDeviceInfo FAILED");        return FALSE;    }    //设置设备属性变化参数    PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);    PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;    PropChangeParams.Scope = DICS_FLAG_GLOBAL; //使修改的属性保存在所有的硬件属性文件    PropChangeParams.StateChange = dwNewState;    PropChangeParams.HwProfile = 0;    //改变设备属性    if (!SetupDiSetClassInstallParams( hDevInfo,                                    &DevInfoData,                                    (SP_CLASSINSTALL_HEADER *)&PropChangeParams,                                    sizeof(PropChangeParams)))    {        OutputDebugString("SetupDiSetClassInstallParams FAILED");        return FALSE;    }    PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);    PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;    PropChangeParams.Scope = DICS_FLAG_CONFIGSPECIFIC;//使修改的属性保存在指定的属性文件    PropChangeParams.StateChange = dwNewState;    PropChangeParams.HwProfile = 0;    //改变设备属性并调用安装服务    if (!SetupDiSetClassInstallParams( hDevInfo,                                    &DevInfoData,                                    (SP_CLASSINSTALL_HEADER *)&PropChangeParams,                                    sizeof(PropChangeParams))         ||!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hDevInfo, &DevInfoData))    {        OutputDebugString("SetupDiSetClassInstallParams or SetupDiCallClassInstaller FAILED");        return TRUE;    }    else    {        //判断是否需要重新启动        devParams.cbSize = sizeof(devParams);        if (!SetupDiGetDeviceInstallParams( hDevInfo, &DevInfoData, &devParams))        {            OutputDebugString("SetupDiGetDeviceInstallParams FAILED");            return FALSE;        }        if (devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT))        {            OutputDebugString("Need Restart Computer");            return TRUE;        }        return TRUE;    }}

这里的类安装参数为 SP_PROPCHANGE_PARAMS 结构体,其 StateChange 参数指定了状态改变的动作,有 DICS_ENABLEDICS_DISABLEDICS_PROPCHANGEDICS_STARTDICS_STOP 可选。

更多关于SP_PROPCHANGE_PARAMS

我们需要实现的禁用和开启,不过是将 PropChangeParams.StateChange 设为 DICS_DISABLEDICS_ENABLE

原创粉丝点击