我正在开发一个新的 WMI 实例提供程序,但我遇到了一些麻烦。我能够使用regsvr32.exe
成功注册我的提供商。regsvr32
应用程序调用我的DllRegisterServer
实现,并创建以下注册表项和值:
HKEY_LOCAL_MACHINESOFTWAREClassesCLSID{00000001-0000-0000-0000-00000000000F} : (default) = "WMI Provider"
HKEY_LOCAL_MACHINESOFTWAREClassesCLSID{00000001-0000-0000-0000-00000000000F}InprocServer32 : (default) = "C:MyWmiProvider.dll"
HKEY_LOCAL_MACHINESOFTWAREClassesCLSID{00000001-0000-0000-0000-00000000000F}InprocServer32 : ThreadingModel = Neutral
HKEY_LOCAL_MACHINESOFTWAREClassesCLSID{00000001-0000-0000-0000-00000000000F}Version : (default) = 1.0.0
(其中{00000001-0000-0000-0000-00000000000F}
只是一个测试类 ID (CLSID((
我还能够使用mofcomp.exe
成功添加在我的ManagedObjectFormat (MOF( 文件中定义的 WMI 类定义。我能够通过运行以下命令来验证我的定义是否存在于 WMI 存储库中:
Get-CimClass -Namespace "root/MyNamespace" | Where-Object CimClassName -like "MyClass_*"
下面是我的 MOF 文件的外观示例:
#pragma namespace("\\.\root\MyNamespace")
#pragma autorecover
instance of __Win32Provider as $P
{
Name = "MyWmiProvider";
ClsId = "{00000001-0000-0000-0000-00000000000F}";
};
instance of __InstanceProviderRegistration
{
Provider = $P;
SupportsGet = FALSE;
SupportsPut = FALSE;
SupportsDelete = FALSE;
SupportsEnumeration = TRUE;
};
[dynamic, provider("MyWmiProvider")]
class MyClass_ExampleName
{
[key]
uint14 Id;
[PropertyContext("Name")]
String Name;
};
现在,如果我运行以下内容:
Get-CimInstance -Namespace "root/MyNamespace" -Class "MyClass_ExampleName"
这会在 PowerShell 中生成以下错误:
Get-CimInstance : Provider load failure
At line:1 char:1
+ Get-CimInstance -Namespace "root/MyNamespace" -Class "MyClass_ExampleName"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (root/Surface:Device_Status:String) [Get-CimInstance], CimException
+ FullyQualifiedErrorId : HRESULT 0x80041013,Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand
同样,执行此命令时会生成三 (3( 个事件查看器日志:
MyWmiProvider 提供程序从结果代码0x80041013开始。HostProcess = wmiprvse.exe;进程 ID = 2144;ProviderPath = C:\MyWmiProvider.dll
ID = {FB6B3CF7-293E-0002-9316-73FB3E29D601};客户端计算机 = RTR 用户名;用户 = 我的域\用户名;客户端进程 ID = 19416;组件 = 未知;操作 = 启动 IWbemServices::CreateInstanceEnum - root\MyNamespace : MyClass_ExampleName;结果代码 = 0x80041013;可能的原因 = 未知
MyWmiProvider 提供程序从结果代码0x80041013开始。HostProcess = wmiprvse.exe;进程 ID = 24636;ProviderPath = C:\MyWmiProvider.dll
(显示 WMI 确实正确找到了 DLL(
如果我尝试调用Get-WMIObject
,我会得到类似的结果,除了第二个事件查看器日志显示"操作">是"启动IWbemServices::ExecQuery - root\MyNamespace : MyClass_ExampleName"。
Get-WMIObject
和Get-CimInstance
在后台到底在做什么?
我已经查找了Get-WMIObject
源代码[这里],尽管有简单的 6 行,但查找尊重类和函数调用并不能产生详细的细节。我的DLL接口只包括四(4(个导出的函数:DllGetClassObject()
、DllCanUnloadNow()
、DllRegisterServer()
和DllUnregisterServer()
。我认为Get-WMIObject
和Get-CimInstance
首先调用DllGetClassObject()
以获取WMI类工厂,但是如果我放置函数调用以将字符串保存到DllGetClassObject()
中的临时文件,则在调用这些PowerShell命令时,我注意到不会创建临时文件。
通过在此答案之后创建一个新项目,我变得更加具体,以便我可以调用以下内容:
DEFINE_GUID(InstanceProviderClassID, 0x00000001, 0x00000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F);
IWbemServices * pLoc = NULL;
CoCreateInstance(InstanceProviderClassID, NULL, CLSCTX_INPROC_SERVER, IID_IWbemServices, (LPVOID *)&pLoc);
在这种情况下,调用CoCreateInstance()
成功。我什至注意到创建了临时日志文件,表明实际上调用了DllGetClassObject()
!
即使我采用我拥有的工作实例提供程序并将相同的打印语句(或类似地调用创建注册表项/值(放在其DllGetClassObject()
函数中,也不会保存任何内容来指示在调用这些 PowerShell 命令时调用此函数。
1. 我在这里错过了什么?
2. 为什么在执行Get-WMIObject
和Get-CimInstance
时从不调用DllGetClassObject()
函数?
3. 为什么我能够成功执行CoCreateInstance()
,证明我的提供程序编码正确,但在执行其中一个 PowerShell 命令时出现"提供程序加载失败">?
(旁注:为了使事情变得简单,我用WBEM_E_NOT_SUPPORTED
标记了所有服务功能。在工作实例提供程序中执行此操作时,我仍然看不到">提供程序加载失败",而是"不支持"。
Get-CimInstance
和Get-WmiObject
都使用 .NET API 与 WMI 通信。在第一种情况下,它使用 https://learn.microsoft.com/en-us/dotnet/api/microsoft.management.infrastructure,在后一种情况下使用 https://learn.microsoft.com/en-us/dotnet/api/system.management。 这两者之间的主要区别在于CIM API是跨平台兼容的,而WMI API具有仅适用于Windows的CIM的Windows扩展。
无论您决定使用 PowerShell cmdlet、WMIC、wbemtest 还是其他东西,它们最终都会调用 WMI COM API https://learn.microsoft.com/en-us/windows/win32/wmisdk/com-api-for-wmi 与 WMI 通信,以便与 WMI 提供程序通信。
你跟着 https://learn.microsoft.com/en-us/windows/win32/wmisdk/writing-an-instance-provider 吗? 您似乎没有在 COM 服务器中实现 IWbemServices?