65.9K
CodeProject 正在变化。 阅读更多。
Home

设备属性表对话框

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (21投票s)

2004年7月31日

CPOL

3分钟阅读

viewsIcon

138299

downloadIcon

1509

显示特定设备的属性表对话框。

Sample Image - DevicePropertySheet.jpg

引言

在我之前的文章中 (枚举已安装设备的属性),我使用了 Setup API 来枚举已安装设备的所有属性。但是这些属性对于所有设备都是通用的,没有特定属性与其他设备的属性不同。例如,声卡具有一些属性,这些属性与网络适配器的属性不同。

而且,在这几个月里,一些开发者询问我关于设备特定属性以及如何以编程方式更改它们。我在网上搜索了,但找不到任何相关文章。现在,这篇文章是我为解决这个问题所做的努力。

逆向工程设备管理器

第一步是搜索 MSDN。我搜索了 MSDN 以查找与设备管理器相关的任何 API;例如,一个获取设备的一些信息(例如,DevNode,设备 GUID 等)并显示属性的对话框(可能是设备属性表)的 API。但是没有这样的 API。至少,我找不到任何一个,如果有人知道这样的 API,我很乐意被告知。

第二步是更多地研究设备管理器。设备管理器是一个 DLL (DevMgr.dll),它在 MMC 中用作管理单元。图 2 显示了它

Device Manager

我使用了 PE File Explorer(一个带有源代码的免费实用程序)来浏览 PE(可移植可执行)文件,如 *.exe*.dll*.ocx 等。

使用这个实用程序,我找到了导出的函数。这给了我一个想法。其他程序如何调用这些导出的(以及未文档化的)函数来显示设备属性表?

图 3 显示了打开 DevMgr.dll 的 PEFileExplorer。

Sample screenshot

使用 PEFileExplorer 完成了一大步。现在我知道了 DLL 导出了哪些函数,这让我可以搜索关于导出的函数。

从 MSDN,我发现 Rundll.exeRundll32.exe 允许调用从 DLL 导出的函数。但是,RundllRundll32 程序不允许您调用来自任何 DLL 的任何导出的函数。例如,您不能使用这些实用程序程序来调用从系统 DLL 导出的 Win32 API(应用程序编程接口)调用。这些程序只允许您调用 DLL 中的函数,这些函数是专门为它们调用的而编写的。

Rundll32.exe 的命令行如下

Rundll32.exe <name of dll> 
       <entry point function> <arguments>

通过深入研究导出的函数列表,每个人都可以理解 DevMgr.dll 的入口点是 DeviceProperties_RunDLLA (ANSI 版本) 和 DeviceProperties_RunDLLW (UNICODE 版本)。正如 Microsoft 知识库文章 - 164787 建议的那样,Rundll32.exe 可以处理入口点函数而无需使用 A 或 W。换句话说,我们需要如下调用入口点

Rundll32.exe devmgr.dll DeviceProperties_RunDLL /DeviceID 
                                            root\system\0000

上面的语法意味着 Rundll32.exe 应该调用 DeviceProperties_RunDll(作为 DevMgr.dll 的入口点)并将 /DeviceID root\system\0000 作为函数的参数传递。

解决方案

在之前的文章中,我向您展示了我们如何获取已安装设备的 DeviceID。然后通过使用适当的参数调用 Rundll32.exe,将出现已安装设备的属性表。

以下代码显示了一个示例

void CDevicePropertySheetDialogDlg::OnDeviceProperty() 
{
    DEVNODE dn;
    
    for (int i=0; i<m_Devices.GetItemCount(); i++)
    {
        if (m_Devices.GetItemState(i, LVIS_SELECTED)) //item was selected
        {
            dn=(DEVNODE) m_Devices.GetItemData(i);
            break;
        }
    }
    
    CString CommandLine;

    //Enumerate properties
    for (int j=0; j<DeviceProperty.size(); j++)
    {
        if (DeviceProperty[j].dn==dn)
        {
            CommandLine.Format(_T("DevMgr.dll 
                  DeviceProperties_RunDLL /DeviceID \"%s\""),
                  DeviceProperty[j].Properties[ID_DEVICEID].PropertyValue);
            break;
        }
    }
    
    ShellExecute(m_hWnd, _T("open"), _T("Rundll32.exe"), 
                                CommandLine, NULL, SW_SHOW);
}

我假设列表视图控件 (m_Devices) 中列出的所有设备以及设备的属性(包括 DeviceID)都保存在 DevicePropert 向量中。

备用方法

另一种方法是使用 LoadLibrary API 动态加载 DevMgr.dll。 这是使用 LoadLibrary API 加载设备属性表而更改的代码

void CDevicePropertySheetDialogDlg::OnDeviceProperty() 
{
    DEVNODE dn;

    for (int i=0; i<m_Devices.GetItemCount(); i++)
    {
        if (m_Devices.GetItemState(i, LVIS_SELECTED)) //item was selected
        {
            //AfxMessageBox(m_Devices.GetItemText(i, 0));
            dn=(DEVNODE) m_Devices.GetItemData(i);
            break;
        }
    }

    CString CommandLine;

    //Enumerate properties
    for (int j=0; j<DeviceProperty.size(); j++)
    {
        if (DeviceProperty[j].dn==dn)
        {
            CommandLine.Format(_T("/MachineName \"\" /DeviceID %s"),
                        DeviceProperty[j].Properties[ID_DEVICEID].PropertyValue);

            break;
        }
    }

    PDEVICEPROPERTIES pDeviceProperties;
    HINSTANCE hInst=AfxGetInstanceHandle();
    HINSTANCE  hDevMgr = LoadLibrary(_TEXT("devmgr.dll"));
    if (hDevMgr) 
    {
        pDeviceProperties = (PDEVICEPROPERTIES) GetProcAddress((HMODULE) hDevMgr, 
            DeviceProperties_RunDLL);
    }

    if (pDeviceProperties)
    {
        pDeviceProperties(m_hWnd, hInst, CommandLine.GetBuffer(0), SW_SHOW);
    }

}

应该注意的是,DeviceProperties_RunDLL 定义如下

#ifdef _UNICODE 
#define DeviceProperties_RunDLL  "DeviceProperties_RunDLLW"
typedef void (_stdcall *PDEVICEPROPERTIES)(
                   HWND hwndStub,
                   HINSTANCE hAppInstance,
                   LPWSTR lpCmdLine,
                   int    nCmdShow
                   );

#else
#define DeviceProperties_RunDLL  "DeviceProperties_RunDLLA"
typedef void (_stdcall *PDEVICEPROPERTIES)(
                   HWND hwndStub,
                   HINSTANCE hAppInstance,
                   LPSTR lpCmdLine,
                   int    nCmdShow
                   );
#endif

感谢 Martin Rubas 的评论。

尽情享用!

© . All rights reserved.