Función CreateUnicastIpAddressEntry (netioapi.h)

La función CreateUnicastIpAddressEntry agrega una nueva entrada de dirección IP de unidifusión en el equipo local.

Sintaxis

IPHLPAPI_DLL_LINKAGE _NETIOAPI_SUCCESS_ NETIOAPI_API CreateUnicastIpAddressEntry(
  [in] const MIB_UNICASTIPADDRESS_ROW *Row
);

Parámetros

[in] Row

Puntero a una entrada de estructura de MIB_UNICASTIPADDRESS_ROW para una entrada de dirección IP de unidifusión.

Valor devuelto

Si la función se ejecuta correctamente, el valor devuelto es NO_ERROR.

Si se produce un error en la función, el valor devuelto es uno de los siguientes códigos de error.

Código devuelto Descripción
ERROR_ACCESS_DENIED
Acceso denegado. Este error se devuelve en varias condiciones que incluyen lo siguiente: el usuario carece de los privilegios administrativos necesarios en el equipo local o la aplicación no se ejecuta en un shell mejorado como administrador integrado (administrador de RunAs).
ERROR_INVALID_PARAMETER
Se pasó un parámetro no válido a la función. Este error se devuelve si se pasa un puntero NULL en el parámetro Row , el miembro Address del MIB_UNICASTIPADDRESS_ROW al que apunta el parámetro Row no se estableció en una dirección IPv4 o IPv6 de unidifusión válida, o los miembros InterfaceLuid e InterfaceIndex del MIB_UNICASTIPADDRESS_ROW señalados por el parámetro Row no se especificaron.

Este error también se devuelve para otros errores en los valores establecidos para los miembros de la estructura MIB_UNICASTIPADDRESS_ROW . Estos errores incluyen lo siguiente: si el miembro ValidLifetime es menor que el miembro PreferredLifetime , si el miembro PrefixOrigin está establecido en IpPrefixOriginUnchanged y el SuffixOrigin es el no establecido en IpSuffixOriginUnchanged, si el miembro PrefixOriginOrigin no está establecido en IpPrefixOriginUnchanged y El SuffixOrigin Se establece en IpSuffixOriginUnchanged, si el miembro PrefixOriginUnchanged . member no se establece en un valor de la enumeración NL_PREFIX_ORIGIN , si el miembro SuffixOrigin no está establecido en un valor de la enumeración NL_SUFFIX_ORIGIN , o si el miembro OnLinkPrefixLength se establece en un valor mayor que la longitud de la dirección IP, en bits (32 para una dirección IPv4 de unidifusión o 128 para una dirección IPv6 de unidifusión).

ERROR_NOT_FOUND
No se encontró la interfaz especificada. Este error se devuelve si no se encontró la interfaz de red especificada por el miembro InterfaceLuid o InterfaceIndex del MIB_UNICASTIPADDRESS_ROW señalado por el parámetro Row .
ERROR_NOT_SUPPORTED
No se admite la solicitud. Este error se devuelve si no hay ninguna pila IPv4 en el equipo local y se especificó una dirección IPv4 en el miembro Address del MIB_UNICASTIPADDRESS_ROW apuntado por el parámetro Row . Este error también se devuelve si no hay ninguna pila IPv6 en el equipo local y se especificó una dirección IPv6 en el miembro Address .
ERROR_OBJECT_ALREADY_EXISTS
El objeto ya existe. Este error se devuelve si el miembro Address del MIB_UNICASTIPADDRESS_ROW señalado por el parámetro Row es un duplicado de una dirección IP de unidifusión existente en la interfaz especificada por el miembro InterfaceLuid o InterfaceIndex del MIB_UNICASTIPADDRESS_ROW.
Otros
Use FormatMessage para obtener la cadena de mensaje para el error devuelto.

Comentarios

La función CreateUnicastIpAddressEntry se define en Windows Vista y versiones posteriores.

La función CreateUnicastIpAddressEntry se usa para agregar una nueva entrada de dirección IP de unidifusión en un equipo local. La dirección IP de unidifusión agregada por la función CreateUnicastIpAddressEntry no es persistente. La dirección IP solo existe mientras exista el objeto de adaptador. Al reiniciar el equipo, se destruye la dirección IP, como se restableced manualmente la tarjeta de interfaz de red (NIC). Además, ciertos eventos PnP pueden destruir la dirección.

Para crear una dirección IPv4 que persista, se puede usar el método EnableStatic de la clase Win32_NetworkAdapterConfiguration en los controles instrumental de administración de Windows (WMI). El comando netsh también se puede usar para crear una dirección IPv4 o IPv6 persistente.

Para obtener más información, consulte la documentación sobre Netsh.exe en la documentación de Windows Sockets.

La función InitializeUnicastIpAddressEntry debe usarse para inicializar los miembros de una entrada de estructura de MIB_UNICASTIPADDRESS_ROW con valores predeterminados. Después, una aplicación puede cambiar los miembros de la entrada MIB_UNICASTIPADDRESS_ROW que desea modificar y, a continuación, llamar a la función CreateUnicastIpAddressEntry .

El miembro Address de la estructura MIB_UNICASTIPADDRESS_ROW apuntado por el parámetro Row debe inicializarse en una dirección IPv4 o IPv6 de unidifusión válida. El miembro si_family de la estructura de SOCKADDR_INET del miembro Address debe inicializarse en AF_INET o AF_INET6 y el miembro Ipv4 o Ipv6 relacionado de la estructura de SOCKADDR_INET debe establecerse en una dirección IP de unidifusión válida. Además, al menos uno de los siguientes miembros de la estructura MIB_UNICASTIPADDRESS_ROW apunta al parámetro Row debe inicializarse en la interfaz: InterfaceLuid o InterfaceIndex.

Los campos se usan en el orden indicado anteriormente. Por lo tanto, si se especifica InterfaceLuid , este miembro se usa para determinar la interfaz en la que se va a agregar la dirección IP de unidifusión. Si no se estableció ningún valor para el miembro InterfaceLuid (los valores de este miembro se establecieron en cero), el miembro InterfaceIndex se usará a continuación para determinar la interfaz.

Si el miembro OnLinkPrefixLength del MIB_UNICASTIPADDRESS_ROW al que apunta el parámetro Row se establece en 255, CreateUnicastIpAddressEntry agregará la nueva dirección IP de unidifusión con el miembro OnLinkPrefixLength establecido igual a la longitud de la dirección IP. Por lo tanto, para una dirección IPv4 de unidifusión, OnLinkPrefixLength se establece en 32 y OnLinkPrefixLength se establece en 128 para una dirección IPv6 de unidifusión. Si esto provocaría la máscara de subred incorrecta para una dirección IPv4 o el prefijo de vínculo incorrecto para una dirección IPv6, la aplicación debe establecer este miembro en el valor correcto antes de llamar a CreateUnicastIpAddressEntry.

Si se crea una dirección IP de unidifusión con el miembro OnLinkPrefixLength establecido incorrectamente, la dirección IP se puede cambiar llamando a SetUnicastIpAddressEntry con el miembro OnLinkPrefixLength establecido en el valor correcto.

Los miembros DadState, ScopeId y CreationTimeStamp de la estructura MIB_UNICASTIPADDRESS_ROW a la que apunta la fila se omiten cuando se llama a la función CreateUnicastIpAddressEntry . La pila de red establece estos miembros. El miembro ScopeId viene determinado automáticamente por la interfaz en la que se agrega la dirección. A partir de Windows 10, si DadState se establece en IpDadStatePreferred en la estructura de MIB_UNICASTIPADDRESS_ROW al llamar a CreateUnicastIpAddressEntry, la pila establecerá el estado dad inicial de la dirección en "preferido" en lugar de "tentativo" y hará un DAD optimista para la dirección.

Se producirá un error en la función CreateUnicastIpAddressEntry si la dirección IP de unidifusión pasada en el miembro Address del MIB_UNICASTIPADDRESS_ROW apuntado por el parámetro Row es un duplicado de una dirección IP de unidifusión existente en la interfaz. Tenga en cuenta que una dirección IP de bucle invertido solo se puede agregar a una interfaz de bucle invertido mediante la función CreateUnicastIpAddressEntry .

La dirección IP de unidifusión pasada en el miembro Address del MIB_UNICASTIPADDRESS_ROW señalado por el parámetro Row no se puede usar inmediatamente. La dirección IP se puede usar después de que el proceso de detección de direcciones duplicadas se haya completado correctamente. El proceso de detección de direcciones duplicadas puede tardar varios segundos en completarse, ya que se deben enviar paquetes IP y se deben esperar posibles respuestas. En el caso de IPv6, el proceso de detección de direcciones duplicadas suele tardar aproximadamente un segundo. En el caso de IPv4, el proceso de detección de direcciones duplicadas suele tardar unos tres segundos.

Si una aplicación que necesita saber cuándo se puede usar una dirección IP después de una llamada a la función CreateUnicastIpAddressEntry , hay dos métodos que se pueden usar. Un método usa el sondeo y la función GetUnicastIpAddressEntry . El segundo método llama a una de las funciones de notificación, NotifyAddrChange, NotifyIpInterfaceChange o NotifyUnicastIpAddressChange para configurar una notificación asincrónica para cuando cambia una dirección.

En el método siguiente se describe cómo usar getUnicastIpAddressEntry y sondeo. Después de que la llamada a la función CreateUnicastIpAddressEntry se devuelva correctamente, pause durante uno a tres segundos (dependiendo de si se crea una dirección IPv6 o IPv4) para permitir el tiempo de finalización correcta del proceso de detección de direcciones de duplicación. A continuación, llame a la función GetUnicastIpAddressEntry para recuperar la estructura de MIB_UNICASTIPADDRESS_ROW actualizada y examinar el valor del miembro DadState . Si el valor del miembro DadState se establece en IpDadStatePreferred, la dirección IP ahora se puede usar. Si el valor del miembro DadState se establece en IpDadStateTentative, la detección de direcciones duplicadas aún no se ha completado. En este caso, llame de nuevo a la función GetUnicastIpAddressEntry cada medio segundo mientras el miembro DadState todavía está establecido en IpDadStateTentative. Si el valor del miembro DadState devuelve con algún valor distinto de IpDadStatePreferred o IpDadStateTentative, se ha producido un error en la detección de direcciones duplicadas y la dirección IP no se puede usar.

En el método siguiente se describe cómo usar una función de notificación adecuada. Después de que la llamada a la función CreateUnicastIpAddressEntry se devuelva correctamente, llame a la función NotifyUnicastIpAddressChange para registrarse para recibir notificaciones de cambios en direcciones IP de unidifusión IPv6 o IPv4, en función del tipo de dirección IP que se va a crear. Cuando se recibe una notificación para la dirección IP que se va a crear, llame a la función GetUnicastIpAddressEntry para recuperar el miembro DadState . Si el valor del miembro DadState se establece en IpDadStatePreferred, la dirección IP ahora se puede usar. Si el valor del miembro DadState se establece en IpDadStateTentative, la detección de direcciones duplicadas aún no se ha completado y la aplicación debe esperar a futuras notificaciones. Si el valor del miembro DadState devuelve con algún valor distinto de IpDadStatePreferred o IpDadStateTentative, se ha producido un error en la detección de direcciones duplicadas y la dirección IP no se puede usar.

Si durante el proceso de detección de direcciones duplicadas, el medio se desconecta y, a continuación, se vuelve a conectar, se reinicia el proceso de detección de direcciones duplicadas. Por lo tanto, es posible que el tiempo para completar el proceso aumente más allá del valor típico de 1 segundo para IPv6 o 3 segundos para IPv4.

Un usuario que inició sesión como miembro del grupo Administradores solo puede llamar a la función CreateUnicastIpAddressEntry . Si un usuario que no es miembro del grupo Administradores llama a CreateUnicastIpAddressEntry , se producirá un error en la llamada de función y se devolverá ERROR_ACCESS_DENIED. Esta función también puede producir un error debido al control de cuentas de usuario (UAC) en Windows Vista y versiones posteriores. Si un usuario que ha iniciado sesión como miembro del grupo Administradores que no sea el administrador integrado ejecuta esta función, se producirá un error en esta llamada a menos que la aplicación se haya marcado en el archivo de manifiesto con un valor requestedExecutionLevel establecido en requireAdministrator. Si la aplicación que no tiene este archivo de manifiesto, un usuario que inició sesión como miembro del grupo Administradores distinto del administrador integrado debe ejecutar la aplicación en un shell mejorado como administrador integrado (administrador de runas) para que esta función se realice correctamente.

Ejemplos

En el ejemplo siguiente se muestra cómo usar la función CreateUnicastIpAddressEntry para agregar una nueva entrada de dirección IP de unidifusión en el equipo local.


#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <winsock2.h>
#include <ws2ipdef.h> 
#include <iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>

// Need to link with Iphlpapi.lib and Ws2_32.lib
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")

HANDLE gCallbackComplete;
HANDLE gNotifyEvent;

void CALLBACK CallCompleted (VOID *callerContext, 
    PMIB_UNICASTIPADDRESS_ROW row, 
    MIB_NOTIFICATION_TYPE notificationType);

int main(int argc, char **argv)  {

    // Declare and initialize variables
    
    unsigned long ipAddress = INADDR_NONE;
    unsigned long ipMask = INADDR_NONE;

    DWORD dwRetVal = 0;

    DWORD dwSize = 0;
    unsigned long status = 0;

    DWORD lastError = 0;
    SOCKADDR_IN localAddress;

    NET_LUID interfaceLuid;
    PMIB_IPINTERFACE_TABLE pipTable = NULL; 
    MIB_UNICASTIPADDRESS_ROW ipRow;

    // Validate the parameters
    if (argc != 3) {
        printf("usage: %s IPv4address IPv4mask\n", argv[0]);
        exit(1);
    }

    ipAddress = inet_addr(argv[1]);
    if (ipAddress == INADDR_NONE) {
        printf("usage: %s IPv4address IPv4mask\n", argv[0]);
        exit(1);
    }

    ipMask = inet_addr(argv[2]);
    if (ipMask == INADDR_NONE) {
        printf("usage: %s IPv4address IPv4mask\n", argv[0]);
        exit(1);
    }


    status = GetIpInterfaceTable( AF_INET, &pipTable );
    if( status != NO_ERROR )
    {
        printf("GetIpInterfaceTable returned error: %ld\n", 
            status);
        exit(1);
    }

    // Use loopback interface
    interfaceLuid = pipTable->Table[0].InterfaceLuid;

    localAddress.sin_family            = AF_INET;
    localAddress.sin_addr.S_un.S_addr  = ipAddress;
    
    FreeMibTable(pipTable);
    pipTable = NULL;    

    // Initialize the row
    InitializeUnicastIpAddressEntry( &ipRow );

    ipRow.InterfaceLuid = interfaceLuid;
    ipRow.Address.Ipv4 = localAddress;

    // Create a Handle to be notified of IP address changes
    gCallbackComplete = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (gCallbackComplete == NULL) {
        printf("CreateEvent failed with error: %d\n", GetLastError() );
        exit(1);
    }    
    
    // Use NotifyUnicastIpAddressChange to determine when the address is ready
    NotifyUnicastIpAddressChange(AF_INET, &CallCompleted, NULL, FALSE, &gNotifyEvent);

    status = CreateUnicastIpAddressEntry(&ipRow);
    if(status != NO_ERROR)
    {
        CancelMibChangeNotify2(gNotifyEvent);
        switch(status)
        {
            case ERROR_INVALID_PARAMETER:
                printf("Error: CreateUnicastIpAddressEntry returned ERROR_INVALID_PARAMETER\n");
                break;
            case ERROR_NOT_FOUND:
                printf("Error: CreateUnicastIpAddressEntry returned ERROR_NOT_FOUND\n");
                break;
            case ERROR_NOT_SUPPORTED:
                printf("Error: CreateUnicastIpAddressEntry returned ERROR_NOT_SUPPORTED\n");
                break;
            case ERROR_OBJECT_ALREADY_EXISTS:
                printf("Error: CreateUnicastIpAddressEntry returned ERROR_OBJECT_ALREADY_EXISTS\n");
                break;
            default:
                //NOTE: Is this case needed? If not, we can remove the ErrorExit() function
                printf("CreateUnicastIpAddressEntry returned error: %d\n", status);
                break;
        }
        exit (status);
        
    }
    else
        printf("CreateUnicastIpAddressEntry succeeded\n");
        
    // Set timeout to 6 seconds
    status = WaitForSingleObject(gCallbackComplete, 6000);
    if(status != WAIT_OBJECT_0)
    {
        CancelMibChangeNotify2(gNotifyEvent);
        CancelMibChangeNotify2(gCallbackComplete);
        switch(status)
        {
            case WAIT_ABANDONED:
                printf("Wait on event was abandoned\n");
                break;
            case WAIT_TIMEOUT:
                printf("Wait on event timed out\n");
                break;
            default:
                printf("Wait on event exited with status %d\n", status);
                break;
        }
        return status;
    }
    printf("Task completed successfully\n");
    CancelMibChangeNotify2(gNotifyEvent);
    CancelMibChangeNotify2(gCallbackComplete);

    exit (0);
}


void CALLBACK CallCompleted(PVOID callerContext, PMIB_UNICASTIPADDRESS_ROW row, MIB_NOTIFICATION_TYPE notificationType)
{

    ADDRESS_FAMILY addressFamily; 
    SOCKADDR_IN sockv4addr;
    struct in_addr ipv4addr;
    
    // Ensure that this is the correct notification before setting gCallbackComplete
    // NOTE: Is there a stronger way to do this?
    if(notificationType == MibAddInstance) {
        printf("NotifyUnicastIpAddressChange received an Add instance\n");
        addressFamily = (ADDRESS_FAMILY) row->Address.si_family;
        switch (addressFamily) {
            case AF_INET:
                printf("\tAddressFamily: AF_INET\n");
                break;
            case AF_INET6:
                printf("\tAddressFamily: AF_INET6\n");
                break;
            default:    
                printf("\tAddressFamily: %d\n", addressFamily);
                break;
       }
       if (addressFamily == AF_INET) {
            sockv4addr = row->Address.Ipv4;
            ipv4addr = sockv4addr.sin_addr;
            printf("IPv4 address:  %s\n", inet_ntoa(ipv4addr) );
       }     
       if (callerContext != NULL)
           printf("Received a CallerContext value\n");
           
       SetEvent(gCallbackComplete);
    }    
    return;
}

Requisitos

Requisito Value
Cliente mínimo compatible Windows Vista [solo aplicaciones de escritorio]
Servidor mínimo compatible Windows Server 2008 [solo aplicaciones de escritorio]
Plataforma de destino Windows
Encabezado netioapi.h (include Iphlpapi.h)
Library Iphlpapi.lib
Archivo DLL Iphlpapi.dll

Consulte también

DeleteUnicastIpAddressEntry

GetUnicastIpAddressEntry

GetUnicastIpAddressTable

Referencia de la función auxiliar de IP

InitializeUnicastIpAddressEntry

MIB_UNICASTIPADDRESS_ROW

MIB_UNICASTIPADDRESS_TABLE

Netsh.exe

NotifyAddrChange

NotifyIpInterfaceChange

NotifyUnicastIpAddressChange

SetUnicastIpAddressEntry