Partager via


CreateUnicastIpAddressEntry, fonction (netioapi.h)

La fonction CreateUnicastIpAddressEntry ajoute une nouvelle entrée d’adresse IP de monodiffusion sur l’ordinateur local.

Syntaxe

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

Paramètres

[in] Row

Pointeur vers une entrée de structure MIB_UNICASTIPADDRESS_ROW pour une entrée d’adresse IP en monodiffusion.

Valeur retournée

Si la fonction réussit, la valeur de retour est NO_ERROR.

Si la fonction échoue, la valeur de retour est l’un des codes d’erreur suivants.

Code de retour Description
ERROR_ACCESS_DENIED
L’accès est refusé. Cette erreur est retournée dans plusieurs conditions, notamment : l’utilisateur n’a pas les privilèges d’administration requis sur l’ordinateur local ou l’application ne s’exécute pas dans un interpréteur de commandes amélioré en tant qu’administrateur intégré (administrateur RunAs).
ERROR_INVALID_PARAMETER
Un paramètre non valide a été transmis à la fonction. Cette erreur est retournée si un pointeur NULL est passé dans le paramètre Row , si le membre Address du MIB_UNICASTIPADDRESS_ROW pointé par le paramètre Row n’a pas été défini sur une adresse IPv4 ou IPv6 de monodiffusion valide, ou si les membres InterfaceLuid et InterfaceIndex du MIB_UNICASTIPADDRESS_ROW pointés par le paramètre Row n’ont pas été spécifiés.

Cette erreur est également retournée pour d’autres erreurs dans les valeurs définies pour les membres de la structure MIB_UNICASTIPADDRESS_ROW . Ces erreurs sont les suivantes : si le membre ValidLifetime est inférieur au membre PreferredLifetime , si le membre PrefixOrigin est défini sur IpPrefixOriginUnchanged et que SuffixOrigin n’est pas défini sur IpSuffixOriginUnchanged, si le membre PrefixOrigin n’est pas défini sur IpPrefixOriginUnchanged et que SuffixOrigin est défini sur IpSuffixOriginUnchanged, si prefixOriginUnchanged le membre n’est pas défini sur une valeur de l’énumération NL_PREFIX_ORIGIN , si le membre SuffixOrigin n’est pas défini sur une valeur de l’énumération NL_SUFFIX_ORIGIN , ou si le membre OnLinkPrefixLength est défini sur une valeur supérieure à la longueur de l’adresse IP, en bits (32 pour une adresse IPv4 en monodiffusion ou 128 pour une adresse IPv6 en monodiffusion).

ERROR_NOT_FOUND
L’interface spécifiée est introuvable. Cette erreur est retournée si l’interface réseau spécifiée par le membre InterfaceLuid ou InterfaceIndex du MIB_UNICASTIPADDRESS_ROW pointé par le paramètre Row est introuvable.
ERROR_NOT_SUPPORTED
La demande n'est pas prise en charge. Cette erreur est retournée si aucune pile IPv4 ne se trouve sur l’ordinateur local et qu’une adresse IPv4 a été spécifiée dans le membre Address du MIB_UNICASTIPADDRESS_ROW pointé par le paramètre Row . Cette erreur est également retournée si aucune pile IPv6 ne se trouve sur l’ordinateur local et qu’une adresse IPv6 a été spécifiée dans le membre Address .
ERROR_OBJECT_ALREADY_EXISTS
L'objet existe déjà. Cette erreur est retournée si le membre Address du MIB_UNICASTIPADDRESS_ROW pointé par le paramètre Row est un doublon d’une adresse IP de monodiffusion existante sur l’interface spécifiée par le membre InterfaceLuid ou InterfaceIndex du MIB_UNICASTIPADDRESS_ROW.
Autres
Utilisez FormatMessage pour obtenir la chaîne de message de l’erreur retournée.

Remarques

La fonction CreateUnicastIpAddressEntry est définie sur Windows Vista et versions ultérieures.

La fonction CreateUnicastIpAddressEntry permet d’ajouter une nouvelle entrée d’adresse IP de monodiffusion sur un ordinateur local. L’adresse IP de monodiffusion ajoutée par la fonction CreateUnicastIpAddressEntry n’est pas persistante. L’adresse IP existe uniquement tant que l’objet adaptateur existe. Le redémarrage de l’ordinateur détruit l’adresse IP, tout comme la réinitialisation manuelle de l’interface réseau carte (carte réseau). En outre, certains événements PnP peuvent détruire l’adresse.

Pour créer une adresse IPv4 qui persiste, la méthode EnableStatic de la classe Win32_NetworkAdapterConfiguration dans les contrôles WMI (Windows Management Instrumentation) peut être utilisée. La commande netsh peut également être utilisée pour créer une adresse IPv4 ou IPv6 persistante.

Pour plus d’informations, consultez la documentation sur Netsh.exe dans la documentation Windows Sockets.

La fonction InitializeUnicastIpAddressEntry doit être utilisée pour initialiser les membres d’une entrée de structure MIB_UNICASTIPADDRESS_ROW avec des valeurs par défaut. Une application peut ensuite modifier les membres de l’entrée MIB_UNICASTIPADDRESS_ROW qu’elle souhaite modifier, puis appeler la fonction CreateUnicastIpAddressEntry .

Le membre Address dans la structure MIB_UNICASTIPADDRESS_ROW pointée par le paramètre Row doit être initialisé vers une adresse IPv4 ou IPv6 en monodiffusion valide. Le membre si_family de la structure SOCKADDR_INET dans le membre Address doit être initialisé en AF_INET ou AF_INET6 et le membre Ipv4 ou Ipv6 associé de la structure SOCKADDR_INET doit être défini sur une adresse IP de monodiffusion valide. En outre, au moins un des membres suivants dans la structure MIB_UNICASTIPADDRESS_ROW pointant vers le paramètre Row doit être initialisé vers l’interface : InterfaceLuid ou InterfaceIndex.

Les champs sont utilisés dans l’ordre indiqué ci-dessus. Ainsi, si InterfaceLuid est spécifié, ce membre est utilisé pour déterminer l’interface sur laquelle ajouter l’adresse IP de monodiffusion. Si aucune valeur n’a été définie pour le membre InterfaceLuid (les valeurs de ce membre ont été définies sur zéro), le membre InterfaceIndex est ensuite utilisé pour déterminer l’interface.

Si le membre OnLinkPrefixLength du MIB_UNICASTIPADDRESS_ROW pointé par le paramètre Row est défini sur 255, CreateUnicastIpAddressEntry ajoute la nouvelle adresse IP de monodiffusion avec le membre OnLinkPrefixLength défini sur la longueur de l’adresse IP. Par conséquent, pour une adresse IPv4 en monodiffusion, OnLinkPrefixLength a la valeur 32 et OnLinkPrefixLength est défini sur 128 pour une adresse IPv6 en monodiffusion. Si cela entraîne un masque de sous-réseau incorrect pour une adresse IPv4 ou un préfixe de lien incorrect pour une adresse IPv6, l’application doit définir ce membre sur la valeur correcte avant d’appeler CreateUnicastIpAddressEntry.

Si une adresse IP de monodiffusion est créée avec le membre OnLinkPrefixLength défini incorrectement, l’adresse IP peut être modifiée en appelant SetUnicastIpAddressEntry avec le membre OnLinkPrefixLength défini sur la valeur correcte.

Les membres DadState, ScopeId et CreationTimeStamp de la structure MIB_UNICASTIPADDRESS_ROW pointée par la ligne sont ignorés lorsque la fonction CreateUnicastIpAddressEntry est appelée. Ces membres sont définis par la pile réseau. Le membre ScopeId est automatiquement déterminé par l’interface à laquelle l’adresse est ajoutée. À compter de Windows 10, si DadState est défini sur IpDadStatePreferred dans la structure de MIB_UNICASTIPADDRESS_ROW lors de l’appel de CreateUnicastIpAddressEntry, la pile définit l’état DAD initial de l’adresse sur « preferred » au lieu de « provisoire » et fait DAD optimiste pour l’adresse.

La fonction CreateUnicastIpAddressEntry échoue si l’adresse IP de monodiffusion passée dans le membre Address du MIB_UNICASTIPADDRESS_ROW pointé par le paramètre Row est un doublon d’une adresse IP de monodiffusion existante sur l’interface. Notez qu’une adresse IP de bouclage peut uniquement être ajoutée à une interface de bouclage à l’aide de la fonction CreateUnicastIpAddressEntry .

L’adresse IP de monodiffusion passée dans le membre Address du MIB_UNICASTIPADDRESS_ROW pointé par le paramètre Row n’est pas utilisable immédiatement. L’adresse IP est utilisable une fois le processus de détection d’adresse en double terminé. Le processus de détection des adresses en double peut prendre plusieurs secondes, car les paquets IP doivent être envoyés et les réponses potentielles doivent être attendues. Pour IPv6, le processus de détection des adresses en double prend généralement environ une seconde. Pour IPv4, le processus de détection des adresses en double prend généralement environ trois secondes.

Si une application doit savoir quand une adresse IP est utilisable après un appel à la fonction CreateUnicastIpAddressEntry , il existe deux méthodes qui peuvent être utilisées. Une méthode utilise l’interrogation et la fonction GetUnicastIpAddressEntry . La deuxième méthode appelle l’une des fonctions de notification NotifyAddrChange, NotifyIpInterfaceChange ou NotifyUnicastIpAddressChange pour configurer une notification asynchrone pour lorsqu’une adresse change.

La méthode suivante décrit comment utiliser GetUnicastIpAddressEntry et l’interrogation. Une fois que l’appel à la fonction CreateUnicastIpAddressEntry est retourné avec succès, suspendez pendant une à trois secondes (selon qu’une adresse IPv6 ou IPv4 est en cours de création) pour laisser le temps nécessaire à la réussite du processus de détection des adresses de duplication. Appelez ensuite la fonction GetUnicastIpAddressEntry pour récupérer la structure MIB_UNICASTIPADDRESS_ROW mise à jour et examiner la valeur du membre DadState . Si la valeur du membre DadState est définie sur IpDadStatePreferred, l’adresse IP est désormais utilisable. Si la valeur du membre DadState est définie sur IpDadStateTentative, la détection des adresses en double n’est pas encore terminée. Dans ce cas, appelez à nouveau la fonction GetUnicastIpAddressEntry toutes les demi-secondes pendant que le membre DadState est toujours défini sur IpDadStateTentative. Si la valeur du membre DadState est retournée avec une valeur autre que IpDadStatePreferred ou IpDadStateTentative, la détection des adresses en double a échoué et l’adresse IP n’est pas utilisable.

La méthode suivante décrit comment utiliser une fonction de notification appropriée. Une fois que l’appel à la fonction CreateUnicastIpAddressEntry est retourné, appelez la fonction NotifyUnicastIpAddressChange pour vous inscrire afin d’être informé des modifications apportées aux adresses IP monodiffusion IPv6 ou IPv4, selon le type d’adresse IP créée. Lorsqu’une notification est reçue pour l’adresse IP en cours de création, appelez la fonction GetUnicastIpAddressEntry pour récupérer le membre DadState . Si la valeur du membre DadState est définie sur IpDadStatePreferred, l’adresse IP est désormais utilisable. Si la valeur du membre DadState est définie sur IpDadStateTentative, la détection des adresses en double n’est pas encore terminée et l’application doit attendre les notifications ultérieures. Si la valeur du membre DadState est retournée avec une valeur autre que IpDadStatePreferred ou IpDadStateTentative, la détection des adresses en double a échoué et l’adresse IP n’est pas utilisable.

Si, pendant le processus de détection des adresses en double, le média est déconnecté, puis reconnecté, le processus de détection des adresses en double est redémarré. Il est donc possible que le temps nécessaire pour terminer le processus augmente au-delà de la valeur classique de 1 seconde pour IPv6 ou de 3 secondes pour IPv4.

La fonction CreateUnicastIpAddressEntry ne peut être appelée que par un utilisateur connecté en tant que membre du groupe Administrateurs. Si CreateUnicastIpAddressEntry est appelé par un utilisateur qui n’est pas membre du groupe Administrateurs, l’appel de fonction échoue et ERROR_ACCESS_DENIED est retourné. Cette fonction peut également échouer en raison du contrôle de compte d’utilisateur (UAC) sur Windows Vista et versions ultérieures. Si une application qui contient cette fonction est exécutée par un utilisateur connecté en tant que membre du groupe Administrateurs autre que l’administrateur intégré, cet appel échoue, sauf si l’application a été marquée dans le fichier manifeste avec un requestedExecutionLevel défini sur requireAdministrator. Si l’application sur ne dispose pas de ce fichier manifeste, un utilisateur connecté en tant que membre du groupe Administrateurs autre que l’administrateur intégré doit ensuite exécuter l’application dans un interpréteur de commandes amélioré en tant qu’administrateur intégré (administrateur d’exécution) pour que cette fonction réussisse.

Exemples

L’exemple suivant montre comment utiliser la fonction CreateUnicastIpAddressEntry pour ajouter une nouvelle entrée d’adresse IP de monodiffusion sur l’ordinateur 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;
}

Configuration requise

Condition requise Valeur
Client minimal pris en charge Windows Vista [applications de bureau uniquement]
Serveur minimal pris en charge Windows Server 2008 [applications de bureau uniquement]
Plateforme cible Windows
En-tête netioapi.h (inclure Iphlpapi.h)
Bibliothèque Iphlpapi.lib
DLL Iphlpapi.dll

Voir aussi

DeleteUnicastIpAddressEntry

GetUnicastIpAddressEntry

GetUnicastIpAddressTable

Informations de référence sur la fonction d’assistance IP

InitializeUnicastIpAddressEntry

MIB_UNICASTIPADDRESS_ROW

MIB_UNICASTIPADDRESS_TABLE

Netsh.exe

NotifyAddrChange

NotifyIpInterfaceChange

NotifyUnicastIpAddressChange

SetUnicastIpAddressEntry