A successful get_ExcludedInterfaces call returning VT_EMPTY cannot be treated as a contractually documented encoding of zero excluded interfaces; the supported documentation defines an empty list as no exclusions but does not specify which VARIANT representation constitutes that list.
What is guaranteed
The method is per-profile, and NET_FW_PROFILE2_DOMAIN is a valid single profile value. Microsoft states:
- The property is a list of interfaces on which the firewall does not apply.
- An empty list means there are no excluded interfaces.
- Exactly one profile must be supplied; a multi-bit value from
CurrentProfileTypes must not be passed directly. ^1^
Microsoft’s published sample represents a nonempty value as an array of interface names, which confirms the normal populated shape but does not demonstrate the empty case. ^2^
Interpretation of the returned encodings
| Successful result |
Supported interpretation |
VT_ARRAY | <element type> with elements |
The returned interface list, provided the element type and contents are valid for the property. |
| Valid SAFEARRAY with zero elements |
An empty list, therefore no excluded interfaces. |
VT_EMPTY |
Observed implementation result, but not documented by this API as the empty-list encoding. Generic Automation terminology describes it as “not specified,” not as an empty array. |
VT_NULL |
A distinct Automation null value. This API does not document any property-specific meaning for it, so it should not be equated with an empty list. |
| Any other shape |
Undocumented for this property; do not infer policy state from it. |
VT_EMPTY and VT_NULL are separate VARENUM values: Microsoft labels them “Not specified” and “Null,” respectively. A SAFEARRAY in a VARIANT uses the VT_ARRAY flag; VT_EMPTY and VT_NULL cannot be combined with VT_ARRAY. ^3^ ^4^
Consequently, the most defensible contract-level result is:
S_OK + VT_EMPTY is not documented as either “zero exclusions” or “unset/unspecified” specifically for get_ExcludedInterfaces.
It may be the current implementation’s representation of the documented empty-list state, but that stronger mapping requires clarification from Microsoft’s Windows Firewall API owner.
Local policy versus effective policy
The get_ExcludedInterfaces page does not say whether the value is local-only or the effective result after applicable Group Policy processing. Therefore, VT_EMPTY cannot be used to infer:
- that local policy contains no configured value;
- that Group Policy contains no configured value; or
- that the merged/effective policy contains no exclusions.
This omission matters because other INetFwPolicy2 properties explicitly document local-versus-effective behavior. For example, get_FirewallEnabled says it reports whether the firewall is enabled locally and that the effective result may differ because of Group Policy. ^5^ No equivalent wording is provided for get_ExcludedInterfaces.
get_LocalPolicyModifyState can determine whether adding or setting a rule or rule group would take effect, but its documented scope does not establish the source or merge semantics of ExcludedInterfaces. ^6^
Defensive handling
Keep the encodings distinct in code rather than silently mapping both VT_EMPTY and VT_NULL to an empty collection:
VARIANT value;
VariantInit(&value);
HRESULT hr = policy->get_ExcludedInterfaces(
NET_FW_PROFILE2_DOMAIN, &value);
if (SUCCEEDED(hr)) {
if (value.vt & VT_ARRAY) {
// Enumerate the SAFEARRAY; zero elements means no exclusions.
} else if (value.vt == VT_EMPTY) {
// Observed, but API-specific meaning is undocumented.
} else if (value.vt == VT_NULL) {
// Undocumented for this property; do not treat as empty.
} else {
// Unexpected/undocumented representation.
}
}
VariantClear(&value);
VariantClear releases array contents where applicable and resets the variant to VT_EMPTY; initialized variants should be cleared when no longer needed. ^7^
Version guarantee
The method is documented for Windows Vista and Windows Server 2008 onward, but the documentation provides no version-specific encoding rules and no guarantee that VT_EMPTY will remain the empty-list representation across Windows releases. ^1^
For a supported contractual answer beyond this boundary, request clarification through Microsoft support and ask specifically for:
- the allowed
VARTYPE values for a successful return;
- whether
VT_EMPTY means an empty effective list;
- the meaning, if any, of
VT_NULL;
- whether the getter returns local, Group Policy, or merged policy; and
- whether those mappings are version-stable.
References
- INetFwPolicy2::get_ExcludedInterfaces method (netfw.h)
- Disabling the Firewall per Interface | Microsoft Learn
- C28717
- VARENUM enumeration (ks.h)
- INetFwPolicy2::get_FirewallEnabled method (netfw.h)
- INetFwPolicy2::get_LocalPolicyModifyState method (netfw.h)
- VariantClear function (oleauto.h)