Bagikan melalui


Fungsi CreateUnicastIpAddressEntry (netioapi.h)

Fungsi CreateUnicastIpAddressEntry menambahkan entri alamat IP unicast baru di komputer lokal.

Sintaks

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

Parameter

[in] Row

Penunjuk ke entri struktur MIB_UNICASTIPADDRESS_ROW untuk entri alamat IP unicast.

Nilai kembali

Jika fungsi berhasil, nilai yang dikembalikan NO_ERROR.

Jika fungsi gagal, nilai yang dikembalikan adalah salah satu kode kesalahan berikut.

Menampilkan kode Deskripsi
ERROR_ACCESS_DENIED
Akses ditolak. Kesalahan ini dikembalikan dalam beberapa kondisi yang mencakup hal berikut: pengguna tidak memiliki hak istimewa administratif yang diperlukan di komputer lokal atau aplikasi tidak berjalan dalam shell yang ditingkatkan sebagai Administrator bawaan (administrator RunAs).
ERROR_INVALID_PARAMETER
Parameter yang tidak valid diteruskan ke fungsi. Kesalahan ini dikembalikan jika penunjuk NULL diteruskan dalam parameter Baris , anggota AlamatMIB_UNICASTIPADDRESS_ROW yang diarahkan oleh parameter Baris tidak diatur ke alamat IPv4 atau IPv6 unicast yang valid, atau anggota InterfaceLuid dan InterfaceIndexdari MIB_UNICASTIPADDRESS_ROW yang diarahkan oleh parameter Baris tidak ditentukan.

Kesalahan ini juga dikembalikan untuk kesalahan lain dalam nilai yang ditetapkan untuk anggota dalam struktur MIB_UNICASTIPADDRESS_ROW . Kesalahan ini mencakup hal berikut: jika anggota ValidLifetime kurang dari anggota PreferredLifetime , jika anggota PrefixOrigin diatur ke IpPrefixOriginUnchanged dan SuffixOrigin tidak diatur ke IpSuffixOriginUnchanged, jika anggota PrefixOrigin tidak diatur ke IpPrefixOriginUnchanged dan SuffixOrigin diatur ke IpSuffixOriginUnchanged, jika PrefixOrigin anggota tidak diatur ke nilai dari enumerasi NL_PREFIX_ORIGIN , jika anggota SuffixOrigin tidak diatur ke nilai dari enumerasi NL_SUFFIX_ORIGIN , atau jika anggota OnLinkPrefixLength diatur ke nilai yang lebih besar dari panjang alamat IP, dalam bit (32 untuk alamat IPv4 unicast atau 128 untuk alamat IPv6 unicast).

ERROR_NOT_FOUND
Antarmuka yang ditentukan tidak dapat ditemukan. Kesalahan ini dikembalikan jika antarmuka jaringan yang ditentukan oleh anggota InterfaceLuid atau InterfaceIndexdari MIB_UNICASTIPADDRESS_ROW yang ditunjukkan oleh parameter Baris tidak dapat ditemukan.
ERROR_NOT_SUPPORTED
Permintaan tidak didukung. Kesalahan ini dikembalikan jika tidak ada tumpukan IPv4 di komputer lokal dan alamat IPv4 ditentukan dalam anggota AlamatMIB_UNICASTIPADDRESS_ROW yang ditunjukkan oleh parameter Baris . Kesalahan ini juga dikembalikan jika tidak ada tumpukan IPv6 di komputer lokal dan alamat IPv6 ditentukan dalam anggota Alamat .
ERROR_OBJECT_ALREADY_EXISTS
Objek sudah ada. Kesalahan ini dikembalikan jika anggota AlamatMIB_UNICASTIPADDRESS_ROW yang diarahkan oleh parameter Baris adalah duplikat alamat IP unicast yang ada pada antarmuka yang ditentukan oleh anggota InterfaceLuid atau InterfaceIndex dari MIB_UNICASTIPADDRESS_ROW.
Lainnya
Gunakan FormatMessage untuk mendapatkan string pesan untuk kesalahan yang dikembalikan.

Keterangan

Fungsi CreateUnicastIpAddressEntry didefinisikan pada Windows Vista dan yang lebih baru.

Fungsi CreateUnicastIpAddressEntry digunakan untuk menambahkan entri alamat IP unicast baru di komputer lokal. Alamat IP unicast yang ditambahkan oleh fungsi CreateUnicastIpAddressEntry tidak persisten. Alamat IP hanya ada selama objek adaptor ada. Menghidupkan ulang komputer menghancurkan alamat IP, seperti halnya mengatur ulang kartu antarmuka jaringan (NIC) secara manual. Selain itu, peristiwa PnP tertentu dapat menghancurkan alamat.

Untuk membuat alamat IPv4 yang berlanjut, metode EnableStatic dari Win32_NetworkAdapterConfiguration Class dalam kontrol Windows Management Instrumentation (WMI) dapat digunakan. Perintah netsh juga dapat digunakan untuk membuat alamat IPv4 atau IPv6 persisten.

Untuk informasi selengkapnya, silakan lihat dokumentasi tentang Netsh.exe dalam dokumentasi Windows Sockets.

Fungsi InitializeUnicastIpAddressEntry harus digunakan untuk menginisialisasi anggota entri struktur MIB_UNICASTIPADDRESS_ROW dengan nilai default. Aplikasi kemudian dapat mengubah anggota dalam entri MIB_UNICASTIPADDRESS_ROW yang ingin dimodifikasi, lalu memanggil fungsi CreateUnicastIpAddressEntry .

Anggota Alamat dalam struktur MIB_UNICASTIPADDRESS_ROW yang ditunjukkan oleh parameter Baris harus diinisialisasi ke alamat IPv4 atau IPv6 unicast yang valid. Anggota si_family struktur SOCKADDR_INET di anggota Alamat harus diinisialisasi ke AF_INET atau AF_INET6 dan anggota Ipv4 atau Ipv6 terkait dari struktur SOCKADDR_INET harus diatur ke alamat IP unicast yang valid. Selain itu, setidaknya salah satu anggota berikut dalam struktur MIB_UNICASTIPADDRESS_ROW yang menunjuk ke parameter Baris harus diinisialisasi ke antarmuka: InterfaceLuid atau InterfaceIndex.

Bidang digunakan dalam urutan yang tercantum di atas. Jadi, jika InterfaceLuid ditentukan, maka anggota ini digunakan untuk menentukan antarmuka untuk menambahkan alamat IP unicast. Jika tidak ada nilai yang ditetapkan untuk anggota InterfaceLuid (nilai anggota ini diatur ke nol), maka anggota InterfaceIndex selanjutnya digunakan untuk menentukan antarmuka.

Jika anggota OnLinkPrefixLength dari MIB_UNICASTIPADDRESS_ROW yang ditunjukkan oleh parameter Baris diatur ke 255, maka CreateUnicastIpAddressEntry akan menambahkan alamat IP unicast baru dengan anggota OnLinkPrefixLength yang diatur sama dengan panjang alamat IP. Jadi untuk alamat IPv4 unicast, OnLinkPrefixLength diatur ke 32 dan OnLinkPrefixLength diatur ke 128 untuk alamat IPv6 unicast. Jika ini akan mengakibatkan subnet mask yang salah untuk alamat IPv4 atau awalan tautan yang salah untuk alamat IPv6, maka aplikasi harus mengatur anggota ini ke nilai yang benar sebelum memanggil CreateUnicastIpAddressEntry.

Jika alamat IP unicast dibuat dengan anggota OnLinkPrefixLength salah diatur, maka alamat IP dapat diubah dengan memanggil SetUnicastIpAddressEntry dengan anggota OnLinkPrefixLength diatur ke nilai yang benar.

Anggota DadState, ScopeId, dan CreationTimeStamp dari struktur MIB_UNICASTIPADDRESS_ROW yang diabaikan oleh Baris diabaikan saat fungsi CreateUnicastIpAddressEntry dipanggil. Anggota ini diatur oleh tumpukan jaringan. Anggota ScopeId secara otomatis ditentukan oleh antarmuka tempat alamat ditambahkan. Dimulai di Windows 10, jika DadState diatur ke IpDadStatePreferred dalam struktur MIB_UNICASTIPADDRESS_ROW saat memanggil CreateUnicastIpAddressEntry, tumpukan akan mengatur status DAD awal alamat ke "pilihan" alih-alih "tentatif" dan akan melakukan DAD optimis untuk alamat.

Fungsi CreateUnicastIpAddressEntry akan gagal jika alamat IP unicast yang diteruskan di anggota AlamatMIB_UNICASTIPADDRESS_ROW yang ditunjukkan oleh parameter Baris adalah duplikat dari alamat IP unicast yang ada pada antarmuka. Perhatikan bahwa alamat IP loopback hanya dapat ditambahkan ke antarmuka loopback menggunakan fungsi CreateUnicastIpAddressEntry .

Alamat IP unicast yang diteruskan di anggota AlamatMIB_UNICASTIPADDRESS_ROW yang ditunjukkan oleh parameter Baris tidak dapat digunakan segera. Alamat IP dapat digunakan setelah proses deteksi alamat duplikat berhasil diselesaikan. Dibutuhkan beberapa detik agar proses deteksi alamat duplikat selesai karena paket IP perlu dikirim dan respons potensial harus ditunggu. Untuk IPv6, proses deteksi alamat duplikat biasanya memakan waktu sekitar satu detik. Untuk IPv4, proses deteksi alamat duplikat biasanya memakan waktu sekitar tiga detik.

Jika aplikasi yang perlu mengetahui kapan alamat IP dapat digunakan setelah panggilan ke fungsi CreateUnicastIpAddressEntry , ada dua metode yang dapat digunakan. Satu metode menggunakan polling dan fungsi GetUnicastIpAddressEntry . Metode kedua memanggil salah satu fungsi pemberitahuan, NotifyAddrChange, NotifyIpInterfaceChange, atau NotifyUnicastIpAddressChange untuk menyiapkan pemberitahuan asinkron saat alamat berubah.

Metode berikut menjelaskan cara menggunakan GetUnicastIpAddressEntry dan polling. Setelah panggilan ke fungsi CreateUnicastIpAddressEntry berhasil dikembalikan, jeda selama satu hingga tiga detik (tergantung pada apakah alamat IPv6 atau IPv4 sedang dibuat) untuk memungkinkan waktu untuk keberhasilan penyelesaian proses deteksi alamat duplikasi. Kemudian panggil fungsi GetUnicastIpAddressEntry untuk mengambil struktur MIB_UNICASTIPADDRESS_ROW yang diperbarui dan memeriksa nilai anggota DadState . Jika nilai anggota DadState diatur ke IpDadStatePreferred, alamat IP sekarang dapat digunakan. Jika nilai anggota DadState diatur ke IpDadStateTentative, maka deteksi alamat duplikat belum selesai. Dalam hal ini, panggil fungsi GetUnicastIpAddressEntry lagi setiap setengah detik sementara anggota DadState masih diatur ke IpDadStateTentative. Jika nilai anggota DadState kembali dengan beberapa nilai selain IpDadStatePreferred atau IpDadStateTentative, deteksi alamat duplikat telah gagal dan alamat IP tidak dapat digunakan.

Metode berikut menjelaskan cara menggunakan fungsi pemberitahuan yang sesuai. Setelah panggilan ke fungsi CreateUnicastIpAddressEntry berhasil dikembalikan, panggil fungsi NotifyUnicastIpAddressChange untuk mendaftar untuk diberi tahu tentang perubahan pada alamat IP unicast IPv6 atau IPv4, tergantung pada jenis alamat IP yang dibuat. Saat pemberitahuan diterima untuk alamat IP yang dibuat, panggil fungsi GetUnicastIpAddressEntry untuk mengambil anggota DadState . Jika nilai anggota DadState diatur ke IpDadStatePreferred, alamat IP sekarang dapat digunakan. Jika nilai anggota DadState diatur ke IpDadStateTentative, maka deteksi alamat duplikat belum selesai dan aplikasi perlu menunggu pemberitahuan di masa mendatang. Jika nilai anggota DadState kembali dengan beberapa nilai selain IpDadStatePreferred atau IpDadStateTentative, deteksi alamat duplikat telah gagal dan alamat IP tidak dapat digunakan.

Jika selama proses deteksi alamat duplikat, media terputus dan kemudian disambungkan kembali, proses deteksi alamat duplikat dimulai ulang. Jadi dimungkinkan bagi waktu untuk menyelesaikan proses untuk meningkatkan melebihi nilai 1 detik yang khas untuk IPv6 atau nilai 3 detik untuk IPv4.

Fungsi CreateUnicastIpAddressEntry hanya dapat dipanggil oleh pengguna yang masuk sebagai anggota grup Administrator. Jika CreateUnicastIpAddressEntry dipanggil oleh pengguna yang bukan anggota grup Administrator, panggilan fungsi akan gagal dan ERROR_ACCESS_DENIED dikembalikan. Fungsi ini juga dapat gagal karena kontrol akun pengguna (UAC) pada Windows Vista dan yang lebih baru. Jika aplikasi yang berisi fungsi ini dijalankan oleh pengguna yang masuk sebagai anggota grup Administrator selain Administrator bawaan, panggilan ini akan gagal kecuali aplikasi telah ditandai dalam file manifes dengan requestedExecutionLevel diatur ke requireAdministrator. Jika aplikasi pada tidak memiliki file manifes ini, pengguna yang masuk sebagai anggota grup Administrator selain Administrator bawaan kemudian harus menjalankan aplikasi dalam shell yang ditingkatkan sebagai Administrator bawaan (administrator RunAs) agar fungsi ini berhasil.

Contoh

Contoh berikut menunjukkan cara menggunakan fungsi CreateUnicastIpAddressEntry untuk menambahkan entri alamat IP unicast baru di komputer lokal.


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

Persyaratan

Persyaratan Nilai
Klien minimum yang didukung Windows Vista [hanya aplikasi desktop]
Server minimum yang didukung Windows Server 2008 [hanya aplikasi desktop]
Target Platform Windows
Header netioapi.h (termasuk Iphlpapi.h)
Pustaka Iphlpapi.lib
DLL Iphlpapi.dll

Lihat juga

DeleteUnicastIpAddressEntry

GetUnicastIpAddressEntry

GetUnicastIpAddressTable

Referensi Fungsi Pembantu IP

InitializeUnicastIpAddressEntry

MIB_UNICASTIPADDRESS_ROW

MIB_UNICASTIPADDRESS_TABLE

Netsh.exe

NotifyAddrChange

NotifyIpInterfaceChange

NotifyUnicastIpAddressChange

SetUnicastIpAddressEntry