Installing a Provider

The following sample code demonstrates the provider installation operation of the Windows Filtering Platform.

#include <windows.h>
#include <fwpmu.h>
#include <stdio.h>

#pragma comment(lib, "fwpuclnt.lib")

#define EXIT_ON_ERROR(fnName) \
   if (result != ERROR_SUCCESS) \
   { \
      printf(#fnName " = 0x%08X\n", result); \
      goto CLEANUP; \
   }


// 5fb216a8-e2e8-4024-b853-391a4168641e
const GUID PROVIDER_KEY =
{
   0x5fb216a8,
   0xe2e8,
   0x4024,
   { 0xb8, 0x53, 0x39, 0x1a, 0x41, 0x68, 0x64, 0x1e }
};

#define SESSION_NAME L"SDK Examples"

DWORD Install(
         __in const GUID* providerKey,
         __in PCWSTR providerName,
         __in const GUID* subLayerKey,
         __in PCWSTR subLayerName
         )
{
   DWORD result = ERROR_SUCCESS;
   HANDLE engine = NULL;
   FWPM_SESSION0 session;
   FWPM_PROVIDER0 provider;
   FWPM_SUBLAYER0 subLayer;

   memset(&session, 0, sizeof(session));
   // The session name isn't required but may be useful for diagnostics.
   session.displayData.name = SESSION_NAME;
   // Set an infinite wait timeout, so we don't have to handle FWP_E_TIMEOUT
   // errors while waiting to acquire the transaction lock.
   session.txnWaitTimeoutInMSec = INFINITE;

   // The authentication service should always be RPC_C_AUTHN_DEFAULT.
   result = FwpmEngineOpen0(
               NULL,
               RPC_C_AUTHN_DEFAULT,
               NULL,
               &session,
               &engine
               );
   EXIT_ON_ERROR(FwpmEngineOpen0);

   // We add the provider and sublayer from within a single transaction to make
   // it easy to clean up partial results in error paths.
   result = FwpmTransactionBegin0(engine, 0);
   EXIT_ON_ERROR(FwpmTransactionBegin0);

   memset(&provider, 0, sizeof(provider));
   // The provider and sublayer keys are going to be used repeatedly when
   // adding filters and other objects. It's easiest to use well-known GUIDs
   // defined in a header somewhere, rather than having BFE generate the keys.
   provider.providerKey = *providerKey;
   // For MUI compatibility, object names should be indirect strings. See
   // SHLoadIndirectString for details.
   provider.displayData.name = (PWSTR)providerName;
   // Since we always want the provider and sublayer to be present, it's
   // easiest to add them as persistent objects during install.  Alternatively,
   // we could add non-persistent objects every time our service starts.
   provider.flags = FWPM_PROVIDER_FLAG_PERSISTENT;

   result = FwpmProviderAdd0(engine, &provider, NULL);
   // Ignore FWP_E_ALREADY_EXISTS. This allows install to be re-run as needed
   // to repair a broken configuration.
   if (result != FWP_E_ALREADY_EXISTS)
   {
      EXIT_ON_ERROR(FwpmProviderAdd0);
   }

   memset(&subLayer, 0, sizeof(subLayer));
   subLayer.subLayerKey = *subLayerKey;
   subLayer.displayData.name = (PWSTR)subLayerName;
   subLayer.flags = FWPM_SUBLAYER_FLAG_PERSISTENT;
   // Link all our other objects to our provider. When multiple providers are
   // installed on a computer, this makes it easy to determine who added what.
   subLayer.providerKey = (GUID*)providerKey;
   // We don't care what our sublayer weight is, so we pick a weight in the
   // middle and let BFE assign the closest available.
   subLayer.weight = 0x8000;

   result = FwpmSubLayerAdd0(engine, &subLayer, NULL);
   if (result != FWP_E_ALREADY_EXISTS)
   {
      EXIT_ON_ERROR(FwpmSubLayerAdd0);
   }

   // Once all the adds have succeeded, we commit the transaction to persist
   // the new objects.
   result = FwpmTransactionCommit0(engine);
   EXIT_ON_ERROR(FwpmTransactionCommit0);

CLEANUP:
   // FwpmEngineClose0 accepts null engine handles, so we needn't precheck for
   // null. Also, when closing an engine handle, any transactions still in
   // progress are automatically aborted, so we needn't explicitly abort the
   // transaction in error paths.
   FwpmEngineClose0(engine);
   return result;
}