使用COM组件枚举Windows系统防火墙规则
参考资料
参考了官网给出的一个其他COM组件写了枚举,链接如下:
链接: https://learn.microsoft.com/en-us/windows/win32/api/iads/nf-iads-iadscollection-get__newenum
这个链接中的例子还有BUG,调试它的时候,它会崩溃在画红框这行,原因是和上一行蓝框的这行冲突了。
VariantClear(&var);它本身已经做了释放,但是下面又使用pDisp->Release();
两次操作导致var->pdispVal被释放了2次,因此产生了崩溃。
关键点:
- CoInitializeEx,COM组件初始化
- CoUninitialize,COM组件释放
- INetFwPolicy2,防火墙COM组件接口
- INetFwRules,防火墙规则组COM组件接口
- IUnknown,COM组件基类
- IEnumVARIANT,COM组件的枚举接口
- VariantInit,用于初始化VARIANT 结构
- VariantClear,用于清理VARIANT 结构
- get__NewEnum,获取枚举,入参作为返回需要使用的值,固定是基类IUnknown
- QueryInterface,用于获取接口,第一处调用的位置,用于获取一个枚举的接口
- VARIANT,VARIANT结构体主要是使用在COM(组件对象模型)中用于传递参数使用,它的存在主要是为了保持一个在COM参数传递方法的统一性,它几乎包含了所有普通常用类型的数据类型的传递。
- Next( 1, &var, &lFetch ),用于枚举数据,参数1是每次枚举的数量,参数2是返回元素的大小至少为参数1的数组,参数3是实际返回的数量。
- var.punkVal->QueryInterface
IDispatch继承于IUnknown,其实这里使用的是IUnknown的QueryInterface查询接口,通过枚举返回了一个元素后,查询这个元素是否包含了防火墙规则信息IID_INetFwRule的接口
官方例子使用的是var.pdispVal,其实这里使用var.punkVal也是一样的。
代码
我的demo代码,hr的异常判定没做。
#pragma once
#include <WinSock2.h>
#include <stdio.h>
#include <windows.h>
#include <WS2tcpip.h>
#include <netfw.h>
#include <process.h>
#include <tchar.h>
#include <time.h>
#include <atlstr.h>
#include <string>
#include <list>
#include <mutex>
using namespace std;
#pragma comment( lib, "ws2_32.lib")
#define ReleaseCOM( x ) { if(NULL !=(x)) { (x)->Release(); (x) = NULL; } }
int main()
{
HRESULT m_hrCoInitialize = CoInitializeEx( 0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE );
if( RPC_E_CHANGED_MODE != m_hrCoInitialize )
{
if( FAILED( m_hrCoInitialize ) )
{
return 1;
}
}
HRESULT hr = S_OK;
INetFwPolicy2* pNetFwPolicy2 = NULL;
INetFwRules* pNetFwRules = NULL;
IUnknown *pUnk = NULL;
IEnumVARIANT *pEnum = NULL;
hr = CoCreateInstance( __uuidof( NetFwPolicy2 ), NULL, CLSCTX_INPROC_SERVER, __uuidof( INetFwPolicy2 ), ( void** )&pNetFwPolicy2 );
hr = pNetFwPolicy2->get_Rules( &pNetFwRules );
hr = pNetFwRules->get__NewEnum( &pUnk );
hr = pUnk->QueryInterface( IID_IEnumVARIANT, ( void** )&pEnum );// 查询一个枚举接口
// Enumerate the collection.
BSTR bstr = NULL;
VARIANT var;
ULONG lFetch;
IDispatch *pDisp = NULL;
VariantInit( &var );
while( S_OK == pEnum->Next( 1, &var, &lFetch ) )
{
INetFwRule* pNetFwRule = NULL;
if( lFetch == 1 )
{
var.punkVal->QueryInterface( IID_INetFwRule, ( void** )&pNetFwRule );
pNetFwRule->get_Name( &bstr );
printf( "Rule name: %S\n", bstr );
SysFreeString( bstr );
pNetFwRule->Release();
pNetFwRule = NULL;
}
VariantClear( &var );
};
ReleaseCOM( pEnum );
ReleaseCOM( pUnk );
ReleaseCOM( pNetFwRules );
ReleaseCOM( pNetFwPolicy2 );
if( SUCCEEDED( m_hrCoInitialize ) )
{
CoUninitialize();
}
return 0;
}