我已经根据以下描述安装了实例提供程序:
https://learn.microsoft.com/en-us/windows/win32/wmisdk/supplying-data-to-wmi-by-writing-a-provider
它已注册到 regsvr32 并创建了一个实例:
#PRAGMA AUTORECOVER
#PRAGMA NAMESPACE ("\\\\.\\Root\\MyNamespace")
instance of __Win32Provider as $P
{
Name = "myprovider";
CLSID = "{014D660A-59C4-483F-9F99-1237308B8E98}";
};
instance of __InstanceProviderRegistration
{
Provider = $P;
SupportsGet = TRUE;
SupportsEnumeration = TRUE;
SupportsPut = FALSE;
SupportsDelete = FALSE;
QuerySupportLevels;
};
当我以管理员权限启动 Windows Powershell 并执行以下命令时,失败:
Get-WmiObject -Namespace "root/MyNamespace" -Class "MyInfoClass"
Get-WmiObject :
At line:1 char:1
+ Get-WmiObject -Namespace "root/MyNamespace" -Class "MyInfoClass"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
事件日志显示:
Id = {ABDF9D5E-3FCE-000A-4B9F-DFABCE3FDB01}; ClientMachine = XYZ; User = XYZ\AnUser;
ClientProcessId = 3884; Component = Unknown; Operation = Start IWbemServices::ExecQuery - root\MyNamespace: select * from MyInfoClass;
ResultCode = 0x800706BE; PossibleCause = Unknown
根据我的提供程序的跟踪,我可以看到调用了 DllGetClassObject,创建了 IClassFactory 类型的工厂,并且在返回之前将工厂的引用设置为 1。最后的跟踪显示进程 WmiPrvSE.exe 已终止,代码为 0xc0000005 (EXCEPTION_ACCESS_VIOLATION)。
工厂的 CreateInstance 方法永远不会被调用。
尝试更改 __Win32Provider 和 __InstanceProviderRegistration 的属性没有帮助。
即使使用“winmgmt /resetrepository”修复 WMI 存储库也无济于事。
有人知道问题出在哪里吗?
更新:
我没有使用 Windows Powershell,而是使用控制台程序从提供商处获取信息。为了清楚起见,这里缺少错误处理:
CoInitializeEx(
nullptr, //[in, optional] LPVOID pvReserved,
COINIT_MULTITHREADED //[in] DWORD dwCoInit
);
{
CoInitializeSecurity(
nullptr, //[in, optional] PSECURITY_DESCRIPTOR pSecDesc,
-1, //[in] LONG cAuthSvc,
nullptr, //[in, optional] SOLE_AUTHENTICATION_SERVICE * asAuthSvc,
nullptr, //[in, optional] void* pReserved1,
RPC_C_AUTHN_LEVEL_DEFAULT, //[in] DWORD dwAuthnLevel,
RPC_C_IMP_LEVEL_IMPERSONATE,//[in] DWORD dwImpLevel,
nullptr, //[in, optional] void* pAuthList,
EOAC_NONE, //[in] DWORD dwCapabilities,
nullptr //[in, optional] void* pReserved3
);
CComPtr<IWbemLocator> locator = nullptr;
locator.CoCreateInstance(
CLSID_WbemLocator, //[in] REFCLSID rclsid,
nullptr, //[in] LPUNKNOWN pUnkOuter,
CLSCTX_INPROC_SERVER //[in] DWORD dwClsContext
);
CComPtr<IWbemServices> myNamespace = nullptr;
hr = locator->ConnectServer(
bstr_t(L"\\\\.\\root\\MyNamespace"), //[in] const BSTR strNetworkResource,
nullptr, //[in] const BSTR strUser,
nullptr, //[in] const BSTR strPassword,
nullptr, //[in] const BSTR strLocale,
0, //[in] long lSecurityFlags,
nullptr, //[in] const BSTR strAuthority,
nullptr, //[in] IWbemContext * pCtx,
&myNamespace //[out] IWbemServices * *ppNamespace
);
CoSetProxyBlanket(
myNamespace, //[in] IUnknown * pProxy,
RPC_C_AUTHN_WINNT, //[in] DWORD dwAuthnSvc,
RPC_C_AUTHZ_NONE, //[in] DWORD dwAuthzSvc,
nullptr, //[in, optional] OLECHAR * pServerPrincName,
RPC_C_AUTHN_LEVEL_CALL, //[in] DWORD dwAuthnLevel,
RPC_C_IMP_LEVEL_IMPERSONATE, //[in] DWORD dwImpLevel,
nullptr, //[in, optional] RPC_AUTH_IDENTITY_HANDLE pAuthInfo,
EOAC_NONE //[in] DWORD dwCapabilities
);
CComPtr<IEnumWbemClassObject> enumerator = nullptr;
myNamespace->ExecQuery(
bstr_t(L"WQL"), //[in] const BSTR strQueryLanguage,
bstr_t(L"SELECT * FROM MyInfoClass"), //[in] const BSTR strQuery,
(WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY), //[in] long lFlags,
nullptr, //[in] IWbemContext * pCtx,
&enumerator //[out] IEnumWbemClassObject * *ppEnum
);
ULONG returnedObjCount = 0;
for (;;) {
CComPtr<IWbemClassObject> classObj = nullptr;
enumerator->Next(
WBEM_INFINITE, ///* [in] */ long lTimeout,
1, ///* [in] */ ULONG uCount,
&classObj, ///* [length_is][size_is][out] */ __RPC__out_ecount_part(uCount, *puReturned) IWbemClassObject * *apObjects,
&returnedObjCount ///* [out] */ __RPC__out ULONG * puReturned
);
!!! => ERROR 0x800706BE
...
}
}
CoUninitialize();
我还使用管理控制台扩展了对命名空间“MyNamespace”的访问权限作为测试。没有成功。使用现有的命名空间,例如“cimv2”或“default”,也没有效果。
为了查看代码是否正常工作,我查询了另一个 WMI 提供程序:
SELECT * FROM Win32_Process(在命名空间 cimv2 中)。
这工作没有任何问题!?
我的提供商在采取任何行动之前就已被拒绝,这可能是什么原因?
如果您查看互联网上的各种报告,错误 0x800706BE 显然是 WMI 框架非常常用的。不幸的是,事件日志也无法使用。
就我而言,原因最终非常简单。当重构https://learn.microsoft.com/en-us/windows/win32/wmisdk/supplying-data-to-wmi-by-writing-a-provider中的示例代码时,我构建了一个错误: 即使 QueryInterface 成功,DllGetClassObject 方法在使用后也会删除工厂。因此,CreateInstance 方法当然永远不会被调用。