Dynamische Firewallschlüsselwörter
Sie verwenden die FIREWALL-APIs für dynamische Schlüsselwörter, um dynamische Schlüsselwort (keyword)Adressen in Microsoft Defender Firewall zu verwalten. Eine dynamische Schlüsselwortadresse wird verwendet, um einen Satz von IP-Adressen zu erstellen, auf die eine oder mehrere Firewallregeln verweisen können. Dynamische Schlüsselwortadressen unterstützen sowohl IPv4 als auch IPv6.
Hinweis
Api-Referenzinhalte für die in diesem Thema eingeführten APIs finden Sie unter Referenz zu dynamischen Firewallschlüsselwörtern.
Vorgänge für dynamische Schlüsselwort (keyword)Adressen
Mit den dynamischen Firewallschlüsselwort-APIs können Sie die folgenden Vorgänge ausführen.
- Hinzufügen dynamischer Schlüsselwort (keyword)Adressen
- Löschen dynamischer Schlüsselwort (keyword)Adressen
- Auflisten dynamischer Schlüsselwort (keyword) Adressen nach ID oder Typ
- Aktualisieren dynamischer Schlüsselwort (keyword)Adressen
- Abonnieren und Verarbeiten von dynamischen Schlüsselwort (keyword) Adressänderungsbenachrichtigungen
Es gibt Codebeispiele für all diese Vorgänge weiter unten in diesem Thema.
Nachdem Sie eine dynamische Schlüsselwort (keyword) Adresse hinzugefügt haben, wird sie über Neustarts hinweg beibehalten. Sie müssen eine dynamische Schlüsselwort (keyword) Adresse löschen, sobald Sie mit dem Objekt fertig sind.
Es gibt zwei Klassen dynamischer Schlüsselwort (keyword) Adressen, wie in den nächsten beiden Abschnitten beschrieben.
Dynamische Schlüsselwort (keyword)adressen für AutoResolve
Der erste Typ ist AutoResolve, wobei das feld Schlüsselwort (keyword) einen auflösbaren Namen darstellt und die IP-Adressen bei der Erstellung nicht definiert werden.
Diese Objekte sollen ihre IP-Adressen automatisch auflösen. Das heißt, nicht durch einen Administrator zum Zeitpunkt der Objekterstellung; noch über das Betriebssystem selbst. Eine Komponente außerhalb des Firewalldiensts muss die IP-Adressauflösung für diese Objekte durchführen und sie entsprechend aktualisieren. Die Implementierung einer solchen Komponente liegt außerhalb des Rahmens dieses Inhalts.
Eine dynamische Schlüsselwort (keyword) Adresse wird als AutoResolve angegeben, indem beim Aufrufen der FUNKTION FWAddDynamicKeywordAddress0 das flag FW_DYNAMIC_KEYWORD_ADDRESS_FLAGS_AUTO_RESOLVE im -Objekt festgelegt wird. Das Feld Schlüsselwort (keyword) sollte verwendet werden, um den aufgelösten Wert darzustellen, d. h. einen vollqualifizierten Domänennamen (FQDN) oder einen Hostnamen. Das Adressfeld muss für diese Objekte zunächst NULL sein. Die IP-Adressen dieser Objekte werden nicht über Startzyklen hinweg beibehalten, und Sie sollten ihre Adressen während des nächsten Startzyklus erneut auswerten/erneut auffüllen.
Hinweis
AutoResolve dynamic Schlüsselwort (keyword) address objects trigger notifications on FWAddDynamicKeywordAddress0 and FWDeleteDynamicKeywordAddress0, but not FWUpdateDynamicKeywordAddress0.
Dynamische Schlüsselwort (keyword)adressen ohne AutoResolve
Der zweite Typ ist non-AutoResolve, wobei das Schlüsselwort (keyword) Feld eine beliebige Zeichenfolge ist und die Adressen bei der Erstellung definiert werden.
Diese Objekte werden verwendet, um eine Reihe von IP-Adressen, Subnetzen oder Bereichen zu speichern. Das feld Schlüsselwort (keyword) wird zur Vereinfachung der Verwaltung verwendet und kann auf eine beliebige Zeichenfolge festgelegt werden. Das Adressfeld muss bei der Erstellung ungleich NULL sein. Adressen für diese Objekte werden über Neustarts hinweg beibehalten.
Hinweis
Nicht-AutoResolve dynamische Schlüsselwort (keyword) Adressobjekte lösen Benachrichtigungen für FWAddDynamicKeywordAddress0, FWDeleteDynamicKeywordAddress0 und FWUpdateDynamicKeywordAddress0 aus.
Weitere Informationen zu dynamischen Schlüsselwort (keyword)-Adressen
Alle dynamischen Schlüsselwort (keyword) Adressen müssen über einen eindeutigen GUID-Bezeichner verfügen, um sie darzustellen.
Die FwpmDynamicKeywordSubscribe0-API sendet Benachrichtigungen an einen Client, wenn sich dynamische Schlüsselwort (keyword) Adressen ändern. Es wird keine Nutzlast an den Client übermittelt, die genau beschreibt, was sich auf dem System geändert hat. Wenn Sie wissen müssen, welche Objekte sich geändert haben, sollten Sie den aktuellen Zustand von Objekten im System mithilfe der APIs FWEnumDynamicKeywordAddressById0 oder FWEnumDynamicKeywordAddressesByType0 abfragen. Sie können die verschiedenen Flags verwenden, um nur für eine Teilmenge von Objekten Benachrichtigungen anzufordern. Wenn Sie keine Flags verwenden, werden Änderungsbenachrichtigungen für alle Objekte übermittelt.
Eine Firewallregel kann dynamische Schlüsselwort (keyword)-Adressen verwenden, anstatt ip-Adressen explizit für die Remoteadressenbedingung zu definieren. Eine Firewallregel kann sowohl dynamische Schlüsselwort (keyword) Adressen als auch statisch definierte Remoteadressbereiche verwenden. Ein einzelnes dynamisches Schlüsselwort (keyword)-Adressobjekt kann über mehrere Firewallregeln hinweg wiederverwendet werden. Wenn eine Firewallregel über keine konfigurierten Remoteadressen verfügt (d. h. nur mit AutoResolve-Objekten konfiguriert ist, die noch nicht aufgelöst wurden), wird die Regel nicht erzwungen. Wenn eine Regel mehrere dynamische Schlüsselwort (keyword) Adressen verwendet, wird die Regel für alle Adressen erzwungen, die derzeit aufgelöst werden, auch wenn andere Objekte noch nicht aufgelöst wurden. Wenn eine dynamische Schlüsselwort (keyword) Adresse aktualisiert wird, werden auch ihre Remoteadressen für alle zugeordneten Regelobjekte aktualisiert.
Das Betriebssystem selbst erzwingt keine Abhängigkeiten zwischen einer Regel und einer dynamischen Schlüsselwort (keyword)Adresse. Dies bedeutet, dass beide Objekte zuerst erstellt werden können. Die Regel kann auf dynamische Schlüsselwort (keyword) Adress-IDs verweisen, die noch nicht vorhanden sind (in diesem Fall wird die Regel nicht erzwungen). Darüber hinaus können Sie eine dynamische Schlüsselwort (keyword)Adresse auch dann löschen, wenn sie von einer Firewallregel verwendet wird. In diesem Thema wird beschrieben, wie ein Administrator Regeln für die Verwendung dynamischer Schlüsselwort (keyword)-Adressen konfigurieren kann.
Codebeispiele
Um jedes dieser Codebeispiele auszuprobieren, starten Sie zuerst Visual Studio, und erstellen Sie ein neues Projekt basierend auf der Projektvorlage Konsolen-App . Sie können einfach den Inhalt von main.cpp
durch den Codeeintrag ersetzen.
Die meisten Codebeispiele verwenden die Windows-Implementierungsbibliotheken (Windows Implementation Libraries, WIL). Eine bequeme Möglichkeit zum Installieren von WIL besteht darin, zu Visual Studio zu wechseln und auf Projekt>NuGet-Pakete verwalten... zu klicken.>Suchen SieMicrosoft.Windows.ImplementationLibrary in das Suchfeld, wählen Sie das Element in den Suchergebnissen aus, und klicken Sie dann auf Installieren, um das Paket für dieses Projekt zu installieren.
Hinweis
Zeigertypen für die freien NetFw-Funktionen werden über NetFw.h
veröffentlicht, aber eine Static-Link-Bibliothek wird nicht veröffentlicht. Verwenden Sie das LoadLibraryExW/GetProcAddress-Muster zum Aufrufen dieser Funktionen, wie in diesen Codebeispielen gezeigt.
Hinzufügen einer dynamischen Schlüsselwort (keyword)Adresse
In diesem Beispiel wird gezeigt, wie die Funktion FWAddDynamicKeywordAddress0 verwendet wird.
// main.cpp in a Console App project.
#include <windows.h>
#include <wil/resource.h>
#include <netfw.h>
// {26548e4f-d486-4a1d-8a1d-22b0837cd53b}
const GUID DYNAMIC_KEYWORD_ADDRESS_ID_1 =
{
0x26548e4f,
0xd486,
0x4a1d,
{0x8a,0x1d,0x22,0xb0,0x83,0x7c,0xd5,0x3b}
};
// {e9d5c993-9369-4a96-8228-9c5c37aac51a}
const GUID DYNAMIC_KEYWORD_ADDRESS_ID_2 =
{
0xe9d5c993,
0x9369,
0x4a96,
{0x82,0x28,0x9c,0x5c,0x37,0xaa,0xc5,0x1a}
};
int main()
{
DWORD error = ERROR_SUCCESS;
PFN_FWADDDYNAMICKEYWORDADDRESS0 addDynamicKeywordAddressFn = NULL;
HMODULE moduleHandle = NULL;
FW_DYNAMIC_KEYWORD_ADDRESS0 autoResolveKeywordAddress = { 0 };
FW_DYNAMIC_KEYWORD_ADDRESS0 nonAutoResolveKeywordAddress = { 0 };
// Use LoadLibrary/GetProcAddress to invoke this function
moduleHandle = LoadLibraryExW(L"firewallapi.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
auto onExitFreeModuleHandle = wil::scope_exit([&]
{
if (moduleHandle)
{
FreeLibrary(moduleHandle);
}
});
if (moduleHandle != NULL)
{
addDynamicKeywordAddressFn = (PFN_FWADDDYNAMICKEYWORDADDRESS0)GetProcAddress(
moduleHandle,
"FWAddDynamicKeywordAddress0"
);
}
if (addDynamicKeywordAddressFn == NULL)
{
error = GetLastError();
return error;
}
// Ensure the ID is unique. If not, the add operation will fail with ERROR_ALREADY_EXISTS
// and you should invoke the API with a new ID.
// Initialize and add an auto-resolve dynamic keyword address
autoResolveKeywordAddress.id = DYNAMIC_KEYWORD_ADDRESS_ID_1;
autoResolveKeywordAddress.keyword = L"bing.com";
autoResolveKeywordAddress.flags = FW_DYNAMIC_KEYWORD_ADDRESS_FLAGS_AUTO_RESOLVE;
// must be NULL as we have set the auto resolve flag
autoResolveKeywordAddress.addresses = NULL;
error = addDynamicKeywordAddressFn(&autoResolveKeywordAddress);
if (error != ERROR_SUCCESS)
{
return error;
}
// Initialize and add a non auto-resolve dynamic keyword address
nonAutoResolveKeywordAddress.id = DYNAMIC_KEYWORD_ADDRESS_ID_2;
nonAutoResolveKeywordAddress.keyword = L"myServerIPs";
nonAutoResolveKeywordAddress.flags = 0;
nonAutoResolveKeywordAddress.addresses = L"10.0.0.5,20.0.0.0/24,30.0.0.0-40.0.0.0";
error = addDynamicKeywordAddressFn(&nonAutoResolveKeywordAddress);
if (error != ERROR_SUCCESS)
{
return error;
}
return error;
}
Löschen einer dynamischen Schlüsselwort (keyword)Adresse
In diesem Beispiel wird gezeigt, wie die FUNKTION FWDeleteDynamicKeywordAddress0 verwendet wird.
// main.cpp in a Console App project.
#include <windows.h>
#include <wil/resource.h>
#include <netfw.h>
// {26548e4f-d486-4a1d-8a1d-22b0837cd53b}
const GUID DYNAMIC_KEYWORD_ADDRESS_ID_1 =
{
0x26548e4f,
0xd486,
0x4a1d,
{0x8a,0x1d,0x22,0xb0,0x83,0x7c,0xd5,0x3b}
};
// {e9d5c993-9369-4a96-8228-9c5c37aac51a}
const GUID DYNAMIC_KEYWORD_ADDRESS_ID_2 =
{
0xe9d5c993,
0x9369,
0x4a96,
{0x82,0x28,0x9c,0x5c,0x37,0xaa,0xc5,0x1a}
};
int main()
{
DWORD error = ERROR_SUCCESS;
PFN_FWDELETEDYNAMICKEYWORDADDRESS0 deleteDynamicKeywordAddressFn = NULL;
HMODULE moduleHandle = NULL;
// Use LoadLibrary/GetProcAddress to invoke this function
moduleHandle = LoadLibraryExW(L"firewallapi.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
auto onExitFreeModuleHandle = wil::scope_exit([&]
{
if (moduleHandle)
{
FreeLibrary(moduleHandle);
}
});
if (moduleHandle != NULL)
{
deleteDynamicKeywordAddressFn = (PFN_FWDELETEDYNAMICKEYWORDADDRESS0)GetProcAddress(
moduleHandle,
"FWDeleteDynamicKeywordAddress0"
);
}
if (deleteDynamicKeywordAddressFn == NULL)
{
error = GetLastError();
return error;
}
// Invoke the functions
error = deleteDynamicKeywordAddressFn(DYNAMIC_KEYWORD_ADDRESS_ID_1);
if (error != ERROR_SUCCESS)
{
wprintf(L"Failed to delete object with ID 1, err=[%d]", error);
}
error = deleteDynamicKeywordAddressFn(DYNAMIC_KEYWORD_ADDRESS_ID_2);
if (error != ERROR_SUCCESS)
{
wprintf(L"Failed to delete object with ID 2, err=[%d]", error);
}
return error;
}
Auflisten und freie dynamische Schlüsselwort (keyword) Adressen nach ID
In diesem Beispiel wird gezeigt, wie die Funktionen FWEnumDynamicKeywordAddressById0 und FWFreeDynamicKeywordAddressData0 verwendet werden .
// main.cpp in a Console App project.
#include <windows.h>
#include <wil/resource.h>
#include <netfw.h>
// {26548e4f-d486-4a1d-8a1d-22b0837cd53b}
const GUID DYNAMIC_KEYWORD_ADDRESS_ID_1 =
{
0x26548e4f,
0xd486,
0x4a1d,
{0x8a,0x1d,0x22,0xb0,0x83,0x7c,0xd5,0x3b}
};
// {e9d5c993-9369-4a96-8228-9c5c37aac51a}
const GUID DYNAMIC_KEYWORD_ADDRESS_ID_2 =
{
0xe9d5c993,
0x9369,
0x4a96,
{0x82,0x28,0x9c,0x5c,0x37,0xaa,0xc5,0x1a}
};
int main()
{
DWORD error = ERROR_SUCCESS;
PFN_FWENUMDYNAMICKEYWORDADDRESSBYID0 enumDynamicKeywordAddressByIdFn = NULL;
PFN_FWFREEDYNAMICKEYWORDADDRESSDATA0 freeDynamicKeywordAddressDataFn = NULL;
HMODULE moduleHandle = NULL;
PFW_DYNAMIC_KEYWORD_ADDRESS_DATA0 dynamicKeywordAddressData = NULL;
// Use LoadLibrary/GetProcAddress to invoke this function
moduleHandle = LoadLibraryExW(L"firewallapi.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
auto onExitFreeModuleHandle = wil::scope_exit([&]
{
if (moduleHandle)
{
FreeLibrary(moduleHandle);
}
});
if (moduleHandle != NULL)
{
enumDynamicKeywordAddressByIdFn = (PFN_FWENUMDYNAMICKEYWORDADDRESSBYID0)GetProcAddress(
moduleHandle,
"FWEnumDynamicKeywordAddressById0"
);
freeDynamicKeywordAddressDataFn = (PFN_FWFREEDYNAMICKEYWORDADDRESSDATA0)GetProcAddress(
moduleHandle,
"FWFreeDynamicKeywordAddressData0"
);
}
if (enumDynamicKeywordAddressByIdFn == NULL ||
freeDynamicKeywordAddressDataFn == NULL)
{
error = GetLastError();
return error;
}
error = enumDynamicKeywordAddressByIdFn(
DYNAMIC_KEYWORD_ADDRESS_ID_1,
&dynamicKeywordAddressData
);
if (error != ERROR_SUCCESS)
{
return error;
}
if (dynamicKeywordAddressData != NULL)
{
// Process this dynamic keyword address
}
// Free the dynamic keyword address
freeDynamicKeywordAddressDataFn(dynamicKeywordAddressData);
return error;
}
Auflisten und freie dynamische Schlüsselwort (keyword) Adressen nach Typ
In diesem Beispiel wird gezeigt, wie die Funktionen FWEnumDynamicKeywordAddressesByType0 und FWFreeDynamicKeywordAddressData0 verwendet werden .
// main.cpp in a Console App project.
#include <windows.h>
#include <wil/resource.h>
#include <netfw.h>
int main()
{
DWORD error = ERROR_SUCCESS;
PFN_FWENUMDYNAMICKEYWORDADDRESSESBYTYPE0 enumDynamicKeywordAddressesByTypeFn = NULL;
PFN_FWFREEDYNAMICKEYWORDADDRESSDATA0 freeDynamicKeywordAddressDataFn = NULL;
HMODULE moduleHandle = NULL;
PFW_DYNAMIC_KEYWORD_ADDRESS_DATA0 dynamicKeywordAddressData = NULL;
PFW_DYNAMIC_KEYWORD_ADDRESS_DATA0 currDynamicKeywordAddressData = NULL;
// Use LoadLibrary/GetProcAddress to invoke this function
moduleHandle = LoadLibraryExW(L"firewallapi.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
auto onExitFreeModuleHandle = wil::scope_exit([&]
{
if (moduleHandle)
{
FreeLibrary(moduleHandle);
}
});
if (moduleHandle != NULL)
{
enumDynamicKeywordAddressesByTypeFn = (PFN_FWENUMDYNAMICKEYWORDADDRESSESBYTYPE0)GetProcAddress(
moduleHandle,
"FWEnumDynamicKeywordAddressesByType0"
);
freeDynamicKeywordAddressDataFn = (PFN_FWFREEDYNAMICKEYWORDADDRESSDATA0)GetProcAddress(
moduleHandle,
"FWFreeDynamicKeywordAddressData0"
);
}
if (enumDynamicKeywordAddressesByTypeFn == NULL ||
freeDynamicKeywordAddressDataFn == NULL)
{
error = GetLastError();
return error;
}
// Invoke enum for ALL dynamic keyword addresses
error = enumDynamicKeywordAddressesByTypeFn(
FW_DYNAMIC_KEYWORD_ADDRESS_ENUM_FLAGS_ALL,
&dynamicKeywordAddressData
);
if (error != ERROR_SUCCESS)
{
return error;
}
currDynamicKeywordAddressData = dynamicKeywordAddressData;
while (currDynamicKeywordAddressData != NULL)
{
// Process this dynamic keyword address
// iterate to the next one in the list
currDynamicKeywordAddressData = currDynamicKeywordAddressData->next;
}
// Free the dynamic keyword addresses
freeDynamicKeywordAddressDataFn(dynamicKeywordAddressData);
return error;
}
Aktualisieren dynamischer Schlüsselwort (keyword)Adressen
In diesem Beispiel wird gezeigt, wie die FUNKTION FWUpdateDynamicKeywordAddress0 verwendet wird.
// main.cpp in a Console App project.
#include <windows.h>
#include <wil/resource.h>
#include <netfw.h>
// {26548e4f-d486-4a1d-8a1d-22b0837cd53b}
const GUID DYNAMIC_KEYWORD_ADDRESS_ID_1 =
{
0x26548e4f,
0xd486,
0x4a1d,
{0x8a,0x1d,0x22,0xb0,0x83,0x7c,0xd5,0x3b}
};
int main()
{
DWORD error = ERROR_SUCCESS;
PFN_FWUPDATEDYNAMICKEYWORDADDRESS0 updateDynamicKeywordAddressFn = NULL;
HMODULE moduleHandle = NULL;
BOOL appendToCurrentAddresses = TRUE;
// Use LoadLibrary/GetProcAddress to invoke this function
moduleHandle = LoadLibraryExW(L"firewallapi.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
auto onExitFreeModuleHandle = wil::scope_exit([&]
{
if (moduleHandle)
{
FreeLibrary(moduleHandle);
}
});
if (moduleHandle != NULL)
{
updateDynamicKeywordAddressFn = (PFN_FWUPDATEDYNAMICKEYWORDADDRESS0)GetProcAddress(
moduleHandle,
"FWUpdateDynamicKeywordAddress0"
);
}
if (updateDynamicKeywordAddressFn == NULL)
{
error = GetLastError();
return error;
}
// Invoke the function
error = updateDynamicKeywordAddressFn(
DYNAMIC_KEYWORD_ADDRESS_ID_1,
L"20.0.0.5",
appendToCurrentAddresses);
return error;
}
Abonnieren und Verarbeiten von dynamischen Schlüsselwort (keyword) Adressänderungsbenachrichtigungen
In diesem Beispiel wird gezeigt, wie die Funktionen FwpmDynamicKeywordSubscribe0 und FwpmDynamicKeywordUnsubscribe0 sowie der FWPM_DYNAMIC_KEYWORD_CALLBACK0 Rückruf verwendet werden.
// main.cpp in a Console App project.
#include <windows.h>
#include <netfw.h>
#include <fwpmu.h>
#pragma comment(lib, "Fwpuclnt")
void CALLBACK TestCallback(_Inout_ VOID* /*pNotification*/, _Inout_ VOID* pContext)
{
DWORD error = ERROR_SUCCESS;
PFN_FWENUMDYNAMICKEYWORDADDRESSESBYTYPE0 enumDynamicKeywordAddressesByTypeFn = NULL;
PFN_FWFREEDYNAMICKEYWORDADDRESSDATA0 freeDynamicKeywordAddressDataFn = NULL;
HMODULE moduleHandle = NULL;
PFW_DYNAMIC_KEYWORD_ADDRESS_DATA0 dynamicKeywordAddressData = NULL;
PFW_DYNAMIC_KEYWORD_ADDRESS_DATA0 currDynamicKeywordAddressData = NULL;
HANDLE* waitHandle = (HANDLE*)pContext;
// Use LoadLibrary/GetProcAddress to invoke this function
moduleHandle = LoadLibraryW(L"firewallapi.dll");
if (moduleHandle != NULL)
{
enumDynamicKeywordAddressesByTypeFn = (PFN_FWENUMDYNAMICKEYWORDADDRESSESBYTYPE0)GetProcAddress(
moduleHandle,
"FWEnumDynamicKeywordAddressesByType0"
);
freeDynamicKeywordAddressDataFn = (PFN_FWFREEDYNAMICKEYWORDADDRESSDATA0)GetProcAddress(
moduleHandle,
"FWFreeDynamicKeywordAddressData0"
);
}
if (enumDynamicKeywordAddressesByTypeFn == NULL ||
freeDynamicKeywordAddressDataFn == NULL)
{
return;
}
// Invoke enum for ALL AutoResolve dynamic keyword addresses
error = enumDynamicKeywordAddressesByTypeFn(
FW_DYNAMIC_KEYWORD_ADDRESS_ENUM_FLAGS_AUTO_RESOLVE,
&dynamicKeywordAddressData
);
if (error != ERROR_SUCCESS)
{
return;
}
currDynamicKeywordAddressData = dynamicKeywordAddressData;
while (currDynamicKeywordAddressData != NULL)
{
// Process this dynamic keyword address
currDynamicKeywordAddressData = currDynamicKeywordAddressData->next;
}
// Free the dynamic keyword addresses
freeDynamicKeywordAddressDataFn(dynamicKeywordAddressData);
SetEvent(*waitHandle);
}
int main()
{
DWORD error = ERROR_SUCCESS;
HANDLE notifyHandle;
HANDLE waitHandle;
waitHandle = CreateEventW(
NULL,
TRUE,
FALSE,
L"subscriptionWaitEvent"
);
// Subscribe for change notifications
error = FwpmDynamicKeywordSubscribe0(
FWPM_NOTIFY_ADDRESSES_AUTO_RESOLVE,
TestCallback,
&waitHandle,
¬ifyHandle);
if (error != ERROR_SUCCESS)
{
return error;
}
WaitForSingleObject(waitHandle, INFINITE);
// When client is ready to unsubscribe
error = FwpmDynamicKeywordUnsubscribe0(notifyHandle);
return error;
}