Condividi tramite


Funzione CreateUnicastIpAddressEntry (netioapi.h)

La funzione CreateUnicastIpAddressEntry aggiunge una nuova voce di indirizzo IP unicast nel computer locale.

Sintassi

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

Parametri

[in] Row

Puntatore a una voce di struttura MIB_UNICASTIPADDRESS_ROW per una voce di indirizzo IP unicast.

Valore restituito

Se la funzione ha esito positivo, il valore restituito è NO_ERROR.

Se la funzione ha esito negativo, il valore restituito è uno dei codici di errore seguenti.

Codice restituito Descrizione
ERROR_ACCESS_DENIED
Accesso negato. Questo errore viene restituito in diverse condizioni che includono quanto segue: l'utente non dispone dei privilegi amministrativi necessari nel computer locale o l'applicazione non è in esecuzione in una shell avanzata come amministratore predefinito (amministratore RunAs).
ERROR_INVALID_PARAMETER
Un parametro non valido è stato passato alla funzione. Questo errore viene restituito se un puntatore NULL viene passato nel parametro Row , il membro Address del MIB_UNICASTIPADDRESS_ROW puntato dal parametro Row non è stato impostato su un indirizzo IPv4 o IPv6 valido o entrambi i membri InterfaceLuid e InterfaceIndexMIB_UNICASTIPADDRESS_ROW del parametro Row non sono stati specificati.

Questo errore viene restituito anche per altri errori nei valori impostati per i membri nella struttura MIB_UNICASTIPADDRESS_ROW . Questi errori includono quanto segue: se il membro ValidLifetime è minore del membro PreferredLifetime, se il membro PrefixOrigin è impostato su IpPrefixOriginUnchanged e il suffissoOrigin Non è impostato su IpSuffixOriginUnchanged, se il membro PrefixOrigin non è impostato su IpPrefixOriginUnchanged e su SuffixOriginOrigin è impostato su IpSuffixOriginUnchanged, se il prefixOriginUnchanged membro non è impostato su un valore dall'enumerazione NL_PREFIX_ORIGIN, se il membro SuffixOrigin non è impostato su un valore dall'enumerazione NL_SUFFIX_ORIGIN o se il membro OnLinkPrefixLength è impostato su un valore maggiore della lunghezza dell'indirizzo IP, in bit (32 per un indirizzo IPv4 unicast o 128 per un indirizzo IPv6 unicast).

ERROR_NOT_FOUND
Impossibile trovare l'interfaccia specificata. Questo errore viene restituito se non è stato possibile trovare l'interfaccia di rete specificata dal membro InterfaceLuid o InterfaceIndex del MIB_UNICASTIPADDRESS_ROW puntato dal parametro Row .
ERROR_NOT_SUPPORTED
La richiesta non è supportata. Questo errore viene restituito se non si trova alcun stack IPv4 nel computer locale e un indirizzo IPv4 è stato specificato nel membro Indirizzo del MIB_UNICASTIPADDRESS_ROW a cui punta il parametro Row . Questo errore viene restituito anche se non è presente alcun stack IPv6 nel computer locale e un indirizzo IPv6 è stato specificato nel membro Address .
ERROR_OBJECT_ALREADY_EXISTS
L'oggetto esiste già. Questo errore viene restituito se il membro Address del MIB_UNICASTIPADDRESS_ROW puntato dal parametro Row è un duplicato di un indirizzo IP unicast esistente nell'interfaccia specificata dal membro InterfaceLuid o InterfaceIndex del MIB_UNICASTIPADDRESS_ROW.
Altri
Usare FormatMessage per ottenere la stringa di messaggio per l'errore restituito.

Commenti

La funzione CreateUnicastIpAddressEntry è definita in Windows Vista e versioni successive.

La funzione CreateUnicastIpAddressEntry viene utilizzata per aggiungere una nuova voce di indirizzo IP unicast in un computer locale. L'indirizzo IP unicast aggiunto dalla funzione CreateUnicastIpAddressEntry non è persistente. L'indirizzo IP esiste solo a condizione che l'oggetto adapter esista. Il riavvio del computer elimina l'indirizzo IP, perché reimposta manualmente la scheda di interfaccia di rete (NIC). Inoltre, alcuni eventi PnP possono distruggere l'indirizzo.

Per creare un indirizzo IPv4 che persiste, è possibile usare il metodo EnableStatic della classe Win32_NetworkAdapterConfiguration nei controlli WMI (Windows Management Instrumentation). Il comando netsh può essere usato anche per creare un indirizzo IPv4 o IPv6 persistente.

Per altre informazioni, vedere la documentazione su Netsh.exe nella documentazione di Windows Sockets.

La funzione InitializeUnicastIpAddressEntry deve essere usata per inizializzare i membri di una voce di struttura MIB_UNICASTIPADDRESS_ROW con valori predefiniti. Un'applicazione può quindi modificare i membri nella voce MIB_UNICASTIPADDRESS_ROW che desidera modificare e quindi chiamare la funzione CreateUnicastIpAddressEntry .

Il membro Address nella struttura MIB_UNICASTIPADDRESS_ROW puntato dal parametro Row deve essere inizializzato in un indirizzo IPv4 o IPv6 valido. Il membro si_family della struttura SOCKADDR_INET nel membro Address deve essere inizializzato in AF_INET oAF_INET6 e il membro Ipv4 o Ipv6 correlato della struttura SOCKADDR_INET deve essere impostato su un indirizzo IP unicast valido. Inoltre, almeno uno dei membri seguenti nella struttura MIB_UNICASTIPADDRESS_ROW punta al parametro Row deve essere inizializzato all'interfaccia: InterfaceLuid o InterfaceIndex.

I campi vengono usati nell'ordine elencato sopra. Quindi, se si specifica InterfaceLuid , questo membro viene usato per determinare l'interfaccia in cui aggiungere l'indirizzo IP unicast. Se non è stato impostato alcun valore per il membro InterfaceLuid (i valori di questo membro è stato impostato su zero), il membro InterfaceIndex viene usato successivamente per determinare l'interfaccia.

Se il membro OnLinkPrefixLength del MIB_UNICASTIPADDRESS_ROW indicato dal parametro Row è impostato su 255, CreateUnicastIpAddressEntry aggiungerà il nuovo indirizzo IP unicast con il membro OnLinkPrefixLength impostato uguale alla lunghezza dell'indirizzo IP. Pertanto, per un indirizzo IPv4 unicast, OnLinkPrefixLength è impostato su 32 e OnLinkPrefixLength è impostato su 128 per un indirizzo IPv6 unicast. Se ciò comporta la subnet mask errata per un indirizzo IPv4 o il prefisso di collegamento non corretto per un indirizzo IPv6, l'applicazione deve impostare questo membro sul valore corretto prima di chiamare CreateUnicastIpAddressEntry.

Se viene creato un indirizzo IP unicast con il membro OnLinkPrefixLength impostato in modo errato, l'indirizzo IP può essere modificato chiamando SetUnicastIpAddressEntry con il membro OnLinkPrefixLength impostato sul valore corretto.

I membri DadState, ScopeId e CreationTimeStamp della struttura MIB_UNICASTIPADDRESS_ROW puntati dalla riga vengono ignorati quando viene chiamata la funzione CreateUnicastIpAddressEntry . Questi membri vengono impostati dallo stack di rete. Il membro ScopeId viene determinato automaticamente dall'interfaccia in cui viene aggiunto l'indirizzo. A partire da Windows 10, se DadState è impostato su IpDadStatePreferred nella struttura di MIB_UNICASTIPADDRESS_ROW quando si chiama CreateUnicastIpAddressEntry, lo stack imposta lo stato daD iniziale dell'indirizzo su "preferito" anziché "tentativo" e farà daD ottimistico per l'indirizzo.

La funzione CreateUnicastIpAddressEntry avrà esito negativo se l'indirizzo IP unicast passato nel membro Address del MIB_UNICASTIPADDRESS_ROW puntato dal parametro Row è un duplicato di un indirizzo IP unicast esistente nell'interfaccia. Si noti che un indirizzo IP di loopback può essere aggiunto solo a un'interfaccia di loopback usando la funzione CreateUnicastIpAddressEntry .

L'indirizzo IP unicast passato nel membro Address del MIB_UNICASTIPADDRESS_ROW puntato dal parametro Row non è utilizzabile immediatamente. L'indirizzo IP è utilizzabile dopo il completamento del processo di rilevamento degli indirizzi duplicato. È possibile richiedere diversi secondi per completare il processo di rilevamento degli indirizzi duplicati poiché i pacchetti IP devono essere inviati e le potenziali risposte devono essere attese. Per IPv6, il processo di rilevamento degli indirizzi duplicati richiede in genere circa un secondo. Per IPv4, il processo di rilevamento degli indirizzi duplicato richiede in genere circa tre secondi.

Se un'applicazione che deve conoscere quando un indirizzo IP è utilizzabile dopo una chiamata alla funzione CreateUnicastIpAddressEntry , è possibile usare due metodi. Un metodo usa il polling e la funzione GetUnicastIpAddressEntry . Il secondo metodo chiama una delle funzioni di notifica, NotifyAddrChange, NotifyIpInterfaceChange o NotifyUnicastIpAddressChange per configurare una notifica asincrona per quando un indirizzo cambia.

Il metodo seguente descrive come usare GetUnicastIpAddressEntry e polling. Dopo che la chiamata alla funzione CreateUnicastIpAddressEntry restituisce correttamente, sospendere per uno a tre secondi (a seconda che venga creato un indirizzo IPv6 o IPv4) per consentire il completamento corretto del processo di rilevamento degli indirizzi di duplicazione. Chiamare quindi la funzione GetUnicastIpAddressEntry per recuperare la struttura di MIB_UNICASTIPADDRESS_ROW aggiornata ed esaminare il valore del membro DadState . Se il valore del membro DadState è impostato su IpDadStatePreferred, l'indirizzo IP è ora utilizzabile. Se il valore del membro DadState è impostato su IpDadStateTentative, il rilevamento degli indirizzi duplicati non è ancora stato completato. In questo caso, chiamare nuovamente la funzione GetUnicastIpAddressEntry ogni metà del secondo mentre il membro DadState è ancora impostato su IpDadStateTentative. Se il valore del membro DadState restituisce con un valore diverso da IpDadStatePreferred o IpDadStateTentative, il rilevamento degli indirizzi duplicati non è riuscito e l'indirizzo IP non è utilizzabile.

Il metodo seguente descrive come usare una funzione di notifica appropriata. Dopo che la chiamata alla funzione CreateUnicastIpAddressEntry restituisce correttamente, chiamare la funzione NotifyUnicastIpAddressChange per ricevere una notifica delle modifiche agli indirizzi IP unicast IPv6 o IPv4, a seconda del tipo di indirizzo IP creato. Quando viene ricevuta una notifica per l'indirizzo IP creato, chiamare la funzione GetUnicastIpAddressEntry per recuperare il membro DadState . Se il valore del membro DadState è impostato su IpDadStatePreferred, l'indirizzo IP è ora utilizzabile. Se il valore del membro DadState è impostato su IpDadStateTentative, il rilevamento degli indirizzi duplicati non è ancora stato completato e l'applicazione deve attendere le notifiche future. Se il valore del membro DadState restituisce con un valore diverso da IpDadStatePreferred o IpDadStateTentative, il rilevamento degli indirizzi duplicati non è riuscito e l'indirizzo IP non è utilizzabile.

Se durante il processo di rilevamento degli indirizzi duplicati il supporto viene disconnesso e quindi riconnesso, viene riavviato il processo di rilevamento degli indirizzi duplicati. È quindi possibile completare il processo per aumentare oltre il valore tipico di 1 secondo per IPv6 o 3 secondi per IPv4.

La funzione CreateUnicastIpAddressEntry può essere chiamata solo da un utente connesso come membro del gruppo Administrators. Se CreateUnicastIpAddressEntry viene chiamato da un utente che non è membro del gruppo Administrators, la chiamata alla funzione avrà esito negativo e ERROR_ACCESS_DENIED viene restituita. Questa funzione può anche non riuscire a causa del controllo account utente (UAC) in Windows Vista e versioni successive. Se un'applicazione contenente questa funzione viene eseguita da un utente connesso come membro del gruppo Administrators diverso dall'amministratore predefinito, questa chiamata avrà esito negativo a meno che l'applicazione non sia stata contrassegnata nel file manifesto con un set requestedExecutionLevel per richiedereAdministrator. Se l'applicazione in mancanza di questo file manifesto, un utente ha eseguito l'accesso come membro del gruppo Administrators diverso dall'amministratore predefinito, deve quindi eseguire l'applicazione in una shell avanzata come amministratore predefinito (amministratore RunAs) per la riuscita di questa funzione.

Esempio

Nell'esempio seguente viene illustrato come usare la funzione CreateUnicastIpAddressEntry per aggiungere una nuova voce di indirizzo IP unicast nel computer locale.


#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;
}

Requisiti

Requisito Valore
Client minimo supportato Windows Vista [solo app desktop]
Server minimo supportato Windows Server 2008 [solo app desktop]
Piattaforma di destinazione Windows
Intestazione netioapi.h (include Iphlpapi.h)
Libreria Iphlpapi.lib
DLL Iphlpapi.dll

Vedi anche

DeleteUnicastIpAddressEntry

GetUnicastIpAddressEntry

GetUnicastIpAddressTable

Informazioni di riferimento sulle funzioni helper IP

InitializeUnicastIpAddressEntry

MIB_UNICASTIPADDRESS_ROW

MIB_UNICASTIPADDRESS_TABLE

Netsh.exe

NotifyAddrChange

NotifyIpInterfaceChange

NotifyUnicastIpAddressChange

SetUnicastIpAddressEntry