CreateUnicastIpAddressEntry-Funktion (netioapi.h)

Die CreateUnicastIpAddressEntry-Funktion fügt einen neuen Unicast-IP-Adresseintrag auf dem lokalen Computer hinzu.

Syntax

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

Parameter

[in] Row

Ein Zeiger auf einen MIB_UNICASTIPADDRESS_ROW Struktureintrag für einen Unicast-IP-Adresseintrag.

Rückgabewert

Wenn die Funktion erfolgreich ist, wird der Rückgabewert NO_ERROR.

Wenn die Funktion fehlschlägt, ist der Rückgabewert einer der folgenden Fehlercodes.

Rückgabecode Beschreibung
ERROR_ACCESS_DENIED
Zugriff verweigert.“ Dieser Fehler wird unter folgenden Bedingungen zurückgegeben: Dem Benutzer fehlen die erforderlichen Administratorrechte auf dem lokalen Computer, oder die Anwendung wird nicht in einer erweiterten Shell als integrierter Administrator (RunAs-Administrator) ausgeführt.
ERROR_INVALID_PARAMETER
Es wurde ein ungültiger Parameter an die Funktion übergeben. Dieser Fehler wird zurückgegeben, wenn ein NULL-Zeiger im Row-Parameter übergeben wird, das Address-Element des MIB_UNICASTIPADDRESS_ROW , auf das vom Row-Parameter verwiesen wird, nicht auf eine gültige Unicast-IPv4- oder IPv6-Adresse festgelegt wurde, oder die Elemente InterfaceLuid und InterfaceIndex des MIB_UNICASTIPADDRESS_ROW , auf das vom Row-Parameter verwiesen wird, wurden nicht angegeben.

Dieser Fehler wird auch für andere Fehler in den Werten zurückgegeben, die für Member in der MIB_UNICASTIPADDRESS_ROW-Struktur festgelegt sind. Zu diesen Fehlern gehören folgendes: Wenn der ValidLifetime-Member kleiner als das PreferredLifetime-Element ist, wenn das PrefixOrigin-Element auf IpPrefixOriginUnchanged und das SuffixOrigin nicht auf IpSuffixOriginUnchanged festgelegt ist, wenn der PrefixOrigin-Member nicht auf IpPrefixOriginUnchanged festgelegt ist und das SuffixOrigin auf IpSuffixOriginUnchanged festgelegt ist, wenn das PrefixOrigin-Element nicht auf IpSuffixOriginUnchanged festgelegt ist, wenn das PrefixOrigin-Element nicht auf IpPrefixOriginUnchanged festgelegt ist. Member ist nicht auf einen Wert aus der NL_PREFIX_ORIGIN-Enumeration festgelegt, wenn das SuffixOrigin-Element nicht auf einen Wert aus der NL_SUFFIX_ORIGIN-Enumeration festgelegt ist oder wenn das OnLinkPrefixLength-Element auf einen Wert festgelegt ist, der größer als die IP-Adresslänge ist, in Bits (32 für eine Unicast-IPv4-Adresse oder 128 für eine Unicast-IPv6-Adresse).

ERROR_NOT_FOUND
Die angegebene Schnittstelle konnte nicht gefunden werden. Dieser Fehler wird zurückgegeben, wenn die Netzwerkschnittstelle, die vom InterfaceLuid - oder InterfaceIndex-Member des MIB_UNICASTIPADDRESS_ROW angegeben wurde, auf die der Row-Parameter verweist, nicht gefunden werden konnte.
ERROR_NOT_SUPPORTED
Die Anforderung wird nicht unterstützt. Dieser Fehler wird zurückgegeben, wenn sich kein IPv4-Stapel auf dem lokalen Computer befindet und eine IPv4-Adresse im Adresselement des MIB_UNICASTIPADDRESS_ROW durch den Row-Parameter angegeben wurde. Dieser Fehler wird auch zurückgegeben, wenn sich auf dem lokalen Computer kein IPv6-Stapel befindet und im Adresselement eine IPv6-Adresse angegeben wurde.
ERROR_OBJECT_ALREADY_EXISTS
Das Objekt ist bereits vorhanden. Dieser Fehler wird zurückgegeben, wenn das Adresselement des MIB_UNICASTIPADDRESS_ROW , auf das vom Row-Parameter verwiesen wird, ein Duplikat einer vorhandenen Unicast-IP-Adresse auf der Schnittstelle ist, die vom InterfaceLuid - oder InterfaceIndex-Member des MIB_UNICASTIPADDRESS_ROW angegeben wird.
Andere
Verwenden Sie FormatMessage , um die Nachrichtenzeichenfolge für den zurückgegebenen Fehler abzurufen.

Hinweise

Die CreateUnicastIpAddressEntry-Funktion ist unter Windows Vista und höher definiert.

Die CreateUnicastIpAddressEntry-Funktion wird verwendet, um einen neuen Unicast-IP-Adresseintrag auf einem lokalen Computer hinzuzufügen. Die unicast-IP-Adresse, die von der Funktion CreateUnicastIpAddressEntry hinzugefügt wurde, ist nicht persistent. Die IP-Adresse ist nur solange vorhanden, wie das Adapterobjekt vorhanden ist. Durch einen Neustart des Computers wird die IP-Adresse zerstört, ebenso wie das manuelle Zurücksetzen der Netzwerkschnittstelle Karte (NIC). Außerdem können bestimmte PnP-Ereignisse die Adresse zerstören.

Um eine IPv4-Adresse zu erstellen, die beibehalten wird, kann die EnableStatic-Methode der Win32_NetworkAdapterConfiguration-Klasse in den WMI-Steuerelementen (Windows Management Instrumentation) verwendet werden. Der netsh-Befehl kann auch verwendet werden, um eine persistente IPv4- oder IPv6-Adresse zu erstellen.

Weitere Informationen finden Sie in der Dokumentation zu Netsh.exe in der Dokumentation zu Windows Sockets.

Die InitializeUnicastIpAddressEntry-Funktion sollte verwendet werden, um die Member eines MIB_UNICASTIPADDRESS_ROW Struktureintrags mit Standardwerten zu initialisieren. Eine Anwendung kann dann die Member im MIB_UNICASTIPADDRESS_ROW Eintrag ändern, den sie ändern möchte, und dann die CreateUnicastIpAddressEntry-Funktion aufrufen.

Das Adresselement in der MIB_UNICASTIPADDRESS_ROW Struktur, auf die der Row-Parameter verweist, muss für eine gültige Unicast-IPv4- oder IPv6-Adresse initialisiert werden. Das si_family Element der SOCKADDR_INET-Struktur im Adresselement muss entweder für AF_INET oder AF_INET6 initialisiert werden, und das zugehörige Ipv4- oder Ipv6-Element der SOCKADDR_INET-Struktur muss auf eine gültige Unicast-IP-Adresse festgelegt werden. Darüber hinaus muss mindestens eines der folgenden Member in der MIB_UNICASTIPADDRESS_ROW Struktur, die auf den Row-Parameter verweist, für die Schnittstelle initialisiert werden: InterfaceLuid oder InterfaceIndex.

Die Felder werden in der oben aufgeführten Reihenfolge verwendet. Wenn also InterfaceLuid angegeben wird, wird dieser Member verwendet, um die Schnittstelle zu bestimmen, der die Unicast-IP-Adresse hinzugefügt werden soll. Wenn kein Wert für das InterfaceLuid-Element festgelegt wurde (die Werte dieses Members wurden auf Null festgelegt), wird das InterfaceIndex-Element als nächstes verwendet, um die Schnittstelle zu bestimmen.

Wenn das OnLinkPrefixLength-Element des MIB_UNICASTIPADDRESS_ROW vom Row-Parameter auf 255 festgelegt ist, fügt CreateUnicastIpAddressEntry die neue Unicast-IP-Adresse hinzu, wobei das OnLinkPrefixLength-Element der Länge der IP-Adresse entspricht. Für eine Unicast-IPv4-Adresse ist onLinkPrefixLength also auf 32 und OnLinkPrefixLength auf 128 für eine Unicast-IPv6-Adresse festgelegt. Wenn dies zu einer falschen Subnetzmaske für eine IPv4-Adresse oder dem falschen Linkpräfix für eine IPv6-Adresse führen würde, sollte die Anwendung diesen Member auf den richtigen Wert festlegen, bevor CreateUnicastIpAddressEntry aufgerufen wird.

Wenn eine Unicast-IP-Adresse mit falscher Einstellung des OnLinkPrefixLength-Members erstellt wird, kann die IP-Adresse geändert werden, indem SetUnicastIpAddressEntry aufgerufen wird, wobei das OnLinkPrefixLength-Member auf den richtigen Wert festgelegt ist.

Die Elemente DadState, ScopeId und CreationTimeStamp der MIB_UNICASTIPADDRESS_ROW Struktur, auf die die Zeile verweist, werden ignoriert, wenn die CreateUnicastIpAddressEntry-Funktion aufgerufen wird. Diese Member werden vom Netzwerkstapel festgelegt. Das ScopeId-Element wird automatisch von der Schnittstelle bestimmt, der die Adresse hinzugefügt wird. Wenn Ab Windows 10 DadState in der MIB_UNICASTIPADDRESS_ROW-Struktur beim Aufrufen von CreateUnicastIpAddressEntry auf IpDadStatePreferred festgelegt ist, legt der Stapel den anfänglichen DAD-Zustand der Adresse auf "bevorzugt" anstelle von "vorläufig" fest und führt eine optimistische DAD für die Adresse aus.

Die CreateUnicastIpAddressEntry-Funktion schlägt fehl, wenn die unicast-IP-Adresse, die im Adresselement des MIB_UNICASTIPADDRESS_ROW übergeben wird, auf die der Row-Parameter verweist, ein Duplikat einer vorhandenen Unicast-IP-Adresse auf der Schnittstelle ist. Beachten Sie, dass eine Loopback-IP-Adresse nur mithilfe der CreateUnicastIpAddressEntry-Funktion einer Loopbackschnittstelle hinzugefügt werden kann.

Die unicast-IP-Adresse, die im Adresselement des MIB_UNICASTIPADDRESS_ROW vom Row-Parameter übergeben wird, kann nicht sofort verwendet werden. Die IP-Adresse kann verwendet werden, nachdem der Prozess zur Erkennung doppelter Adressen erfolgreich abgeschlossen wurde. Es kann einige Sekunden dauern, bis der Prozess zur Erkennung doppelter Adressen abgeschlossen ist, da IP-Pakete gesendet und potenzielle Antworten abgewartet werden müssen. Bei IPv6 dauert die Erkennung doppelter Adressen in der Regel etwa eine Sekunde. Bei IPv4 dauert die Erkennung doppelter Adressen in der Regel etwa drei Sekunden.

Wenn eine Anwendung wissen muss, wann eine IP-Adresse nach einem Aufruf der CreateUnicastIpAddressEntry-Funktion verwendet werden kann, können zwei Methoden verwendet werden. Eine Methode verwendet Polling und die GetUnicastIpAddressEntry-Funktion . Die zweite Methode ruft eine der Benachrichtigungsfunktionen auf, NotifyAddrChange, NotifyIpInterfaceChange oder NotifyUnicastIpAddressChange , um eine asynchrone Benachrichtigung für den Fall einer Adressänderung einzurichten.

Die folgende Methode beschreibt die Verwendung von GetUnicastIpAddressEntry und polling. Nachdem der Aufruf der CreateUnicastIpAddressEntry-Funktion erfolgreich zurückgegeben wurde, halten Sie ein bis drei Sekunden an (je nachdem, ob eine IPv6- oder IPv4-Adresse erstellt wird), um Zeit für den erfolgreichen Abschluss des Prozesses zur Erkennung von Duplizierungsadressen zu ermöglichen. Rufen Sie dann die Funktion GetUnicastIpAddressEntry auf, um die aktualisierte MIB_UNICASTIPADDRESS_ROW-Struktur abzurufen und den Wert des DadState-Elements zu untersuchen. Wenn der Wert des DadState-Members auf IpDadStatePreferred festgelegt ist, ist die IP-Adresse jetzt nutzbar. Wenn der Wert des DadState-Members auf IpDadStateTentative festgelegt ist, ist die Erkennung doppelter Adressen noch nicht abgeschlossen. Rufen Sie in diesem Fall die GetUnicastIpAddressEntry-Funktion alle halbe Sekunde erneut auf, während der DadState-Member weiterhin auf IpDadStateTentative festgelegt ist. Wenn der Wert des DadState-Members mit einem anderen Wert als IpDadStatePreferred oder IpDadStateTentative zurückgegeben wird, ist die Erkennung doppelter Adressen fehlgeschlagen, und die IP-Adresse ist nicht verwendbar.

Die folgende Methode beschreibt die Verwendung einer entsprechenden Benachrichtigungsfunktion. Nachdem der Aufruf der CreateUnicastIpAddressEntry-Funktion erfolgreich zurückgegeben wurde, rufen Sie die Funktion NotifyUnicastIpAddressChange auf, um sich zu registrieren, um über Änderungen an IPv6- oder IPv4-Unicast-IP-Adressen benachrichtigt zu werden, abhängig vom Typ der zu erstellenden IP-Adresse. Wenn eine Benachrichtigung für die zu erstellende IP-Adresse empfangen wird, rufen Sie die Funktion GetUnicastIpAddressEntry auf, um das DadState-Element abzurufen. Wenn der Wert des DadState-Members auf IpDadStatePreferred festgelegt ist, ist die IP-Adresse jetzt nutzbar. Wenn der Wert des DadState-Members auf IpDadStateTentative festgelegt ist, ist die Erkennung doppelter Adressen noch nicht abgeschlossen, und die Anwendung muss auf zukünftige Benachrichtigungen warten. Wenn der Wert des DadState-Members mit einem anderen Wert als IpDadStatePreferred oder IpDadStateTentative zurückgegeben wird, ist die Erkennung doppelter Adressen fehlgeschlagen, und die IP-Adresse ist nicht verwendbar.

Wenn während der Erkennung doppelter Adressen die Medien getrennt und dann wieder verbunden werden, wird der Prozess zur Erkennung doppelter Adressen neu gestartet. So ist es möglich, dass die Zeit zum Abschließen des Prozesses über den typischen 1-Sekunden-Wert für IPv6 oder 3 Sekunden-Wert für IPv4 hinaus erhöht wird.

Die CreateUnicastIpAddressEntry-Funktion kann nur von einem Benutzer aufgerufen werden, der als Mitglied der Gruppe Administratoren angemeldet ist. Wenn CreateUnicastIpAddressEntry von einem Benutzer aufgerufen wird, der kein Mitglied der Gruppe Administratoren ist, schlägt der Funktionsaufruf fehl, und ERROR_ACCESS_DENIED wird zurückgegeben. Diese Funktion kann auch aufgrund der Benutzerkontensteuerung (User Account Control, UAC) unter Windows Vista und höher fehlschlagen. Wenn eine Anwendung, die diese Funktion enthält, von einem Benutzer ausgeführt wird, der nicht als mitglied der Gruppe Administratoren als der integrierte Administrator angemeldet ist, schlägt dieser Aufruf fehl, es sei denn, die Anwendung wurde in der Manifestdatei mit einem requestedExecutionLevel-Wert gekennzeichnet, der auf requireAdministrator festgelegt ist. Wenn der Anwendung in diese Manifestdatei fehlt, muss ein Benutzer, der sich als Mitglied der Administratorgruppe außer dem integrierten Administrator angemeldet hat, die Anwendung in einer erweiterten Shell als integrierter Administrator (RunAs-Administrator) ausführen, damit diese Funktion erfolgreich ist.

Beispiele

Im folgenden Beispiel wird veranschaulicht, wie Sie mithilfe der CreateUnicastIpAddressEntry-Funktion einen neuen Unicast-IP-Adresseintrag auf dem lokalen Computer hinzufügen.


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

Anforderungen

Anforderung Wert
Unterstützte Mindestversion (Client) Windows Vista [nur Desktop-Apps]
Unterstützte Mindestversion (Server) Windows Server 2008 [nur Desktop-Apps]
Zielplattform Windows
Kopfzeile netioapi.h (include Iphlpapi.h)
Bibliothek Iphlpapi.lib
DLL Iphlpapi.dll

Weitere Informationen

DeleteUnicastIpAddressEntry

GetUnicastIpAddressEntry

GetUnicastIpAddressTable

Ip-Hilfsfunktionsreferenz

InitializeUnicastIpAddressEntry

MIB_UNICASTIPADDRESS_ROW

MIB_UNICASTIPADDRESS_TABLE

Netsh.exe

NotifyAddrChange

NotifyIpInterfaceChange

NotifyUnicastIpAddressChange

SetUnicastIpAddressEntry