다음을 통해 공유


CreateUnicastIpAddressEntry 함수(netioapi.h)

CreateUnicastIpAddressEntry 함수는 로컬 컴퓨터에 새 유니캐스트 IP 주소 항목을 추가합니다.

구문

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

매개 변수

[in] Row

유니캐스트 IP 주소 항목에 대한 MIB_UNICASTIPADDRESS_ROW 구조 항목에 대한 포인터입니다.

반환 값

함수가 성공하면 반환 값이 NO_ERROR.

함수가 실패하면 반환 값은 다음 오류 코드 중 하나입니다.

반환 코드 설명
ERROR_ACCESS_DENIED
액세스가 거부되었습니다. 이 오류는 사용자가 로컬 컴퓨터에서 필요한 관리 권한이 없거나 애플리케이션이 기본 제공 관리자(RunAs 관리자)로 향상된 셸에서 실행되고 있지 않음을 포함하는 여러 조건에서 반환됩니다.
ERROR_INVALID_PARAMETER
잘못된 매개 변수가 함수에 전달되었습니다. 이 오류는 NULL 포인터가 Row 매개 변수에 전달되거나 Row 매개 변수가 가리키는 MIB_UNICASTIPADDRESS_ROWAddress 멤버가 유효한 유니캐스트 IPv4 또는 IPv6 주소로 설정되지 않았거나 Row 매개 변수가 가리키는 MIB_UNICASTIPADDRESS_ROWInterfaceLuidInterfaceIndex 멤버가 모두 지정되지 않은 경우 반환됩니다.

이 오류는 MIB_UNICASTIPADDRESS_ROW 구조체의 멤버에 대해 설정된 값의 다른 오류에도 반환됩니다. 이러한 오류에는 ValidLifetime 멤버가 PreferredLifetime 멤버보다 작은 경우 다음 이 포함됩니다. PrefixOrigin 멤버가 IpPrefixOriginUnchanged로 설정되고 SuffixOriginIpSuffixOriginUnchanged로 설정되지 않은 경우 PrefixOrigin 멤버가 IpPrefixOriginUnchanged로 설정되지 않고 SuffixOriginIpSuffixOriginUnchanged로 설정된 경우 PrefixOrigin이 IpSuffixOriginUnchanged로 설정된 경우 SuffixOrigin 멤버가 NL_SUFFIX_ORIGIN 열거형의 값으로 설정되지 않았거나 OnLinkPrefixLength 멤버가 IP 주소 길이보다 큰 값(유니캐스트 IPv4 주소의 경우 32개 또는 유니캐스트 IPv6 주소의 경우 128)으로 설정된 경우 멤버는 NL_PREFIX_ORIGIN 열거형의 값으로 설정되지 않습니다.

ERROR_NOT_FOUND
지정된 인터페이스를 찾을 수 없습니다. 이 오류는 Row 매개 변수가 가리키는 MIB_UNICASTIPADDRESS_ROWInterfaceLuid 또는 InterfaceIndex 멤버가 지정한 네트워크 인터페이스를 찾을 수 없는 경우 반환됩니다.
ERROR_NOT_SUPPORTED
요청이 지원되지 않습니다. 이 오류는 로컬 컴퓨터에 IPv4 스택이 없고 Row 매개 변수가 가리키는 MIB_UNICASTIPADDRESS_ROWAddress 멤버에 IPv4 주소를 지정한 경우 반환됩니다. 이 오류는 로컬 컴퓨터에 IPv6 스택이 없고 주소 멤버에 IPv6 주소를 지정한 경우에도 반환됩니다.
ERROR_OBJECT_ALREADY_EXISTS
개체가 이미 있습니다. 이 오류는 Row 매개 변수가 가리키는 MIB_UNICASTIPADDRESS_ROWAddress 멤버가 MIB_UNICASTIPADDRESS_ROW InterfaceLuid 또는 InterfaceIndex 멤버로 지정된 인터페이스의 기존 유니캐스트 IP 주소와 중복된 경우 반환됩니다.
기타
FormatMessage를 사용하여 반환된 오류에 대한 메시지 문자열을 가져옵니다.

설명

CreateUnicastIpAddressEntry 함수는 Windows Vista 이상에서 정의됩니다.

CreateUnicastIpAddressEntry 함수는 로컬 컴퓨터에 새 유니캐스트 IP 주소 항목을 추가하는 데 사용됩니다. CreateUnicastIpAddressEntry 함수에 의해 추가된 유니캐스트 IP 주소는 영구적이지 않습니다. IP 주소는 어댑터 개체가 있는 경우에만 존재합니다. 컴퓨터를 다시 시작하면 NIC(네트워크 인터페이스 카드)를 수동으로 다시 설정하는 것처럼 IP 주소가 삭제됩니다. 또한 특정 PnP 이벤트는 주소를 삭제할 수 있습니다.

유지되는 IPv4 주소를 만들려면 WMI(Windows Management Instrumentation) 컨트롤에서 Win32_NetworkAdapterConfiguration 클래스의 EnableStatic 메서드 를 사용할 수 있습니다. netsh 명령을 사용하여 영구 IPv4 또는 IPv6 주소를 만들 수도 있습니다.

자세한 내용은 Windows 소켓 설명서의 Netsh.exe 설명서를 참조하세요.

InitializeUnicastIpAddressEntry 함수를 사용하여 기본값으로 MIB_UNICASTIPADDRESS_ROW 구조체 항목의 멤버를 초기화해야 합니다. 그런 다음 애플리케이션은 수정하려는 MIB_UNICASTIPADDRESS_ROW 항목의 멤버를 변경한 다음 CreateUnicastIpAddressEntry 함수를 호출할 수 있습니다.

Row 매개 변수가 가리키는 MIB_UNICASTIPADDRESS_ROW 구조체의 Address 멤버를 유효한 유니캐스트 IPv4 또는 IPv6 주소로 초기화해야 합니다. Address 멤버에서 SOCKADDR_INET 구조체의 si_family 멤버를 AF_INET 또는 AF_INET6 초기화해야 하며 SOCKADDR_INET구조체의 관련 Ipv4 또는 Ipv6 멤버를 유효한 유니캐스트 IP 주소로 설정해야 합니다. 또한 Row 매개 변수를 가리키는 MIB_UNICASTIPADDRESS_ROW 구조체의 다음 멤버 중 하나 이상을 InterfaceLuid 또는 InterfaceIndex 인터페이스로 초기화해야 합니다.

필드는 위에 나열된 순서대로 사용됩니다. 따라서 InterfaceLuid 를 지정하면 이 멤버를 사용하여 유니캐스트 IP 주소를 추가할 인터페이스를 결정합니다. InterfaceLuid 멤버에 대해 값이 설정되지 않은 경우(이 멤버의 값이 0으로 설정된 경우) InterfaceIndex 멤버가 인터페이스를 결정하는 데 사용됩니다.

Row 매개 변수가 가리키는 MIB_UNICASTIPADDRESS_ROWOnLinkPrefixLength 멤버가 255로 설정된 경우 CreateUnicastIpAddressEntryOnLinkPrefixLength 멤버가 IP 주소의 길이와 동일하게 설정된 새 유니캐스트 IP 주소를 추가합니다. 따라서 유니캐스트 IPv4 주소의 경우 OnLinkPrefixLength 가 32로 설정되고 유니캐스트 IPv6 주소의 경우 OnLinkPrefixLength 가 128로 설정됩니다. 이로 인해 IPv4 주소의 서브넷 마스크가 잘못되거나 IPv6 주소에 대한 잘못된 링크 접두사가 발생하는 경우 애플리케이션은 CreateUnicastIpAddressEntry를 호출하기 전에 이 멤버를 올바른 값으로 설정해야 합니다.

OnLinkPrefixLength 멤버가 잘못 설정된 유니캐스트 IP 주소를 만든 경우 OnLinkPrefixLength 멤버가 올바른 값으로 설정된 SetUnicastIpAddressEntry를 호출하여 IP 주소를 변경할 수 있습니다.

Row가 가리키는 MIB_UNICASTIPADDRESS_ROW 구조체의 DadState, ScopeIdCreationTimeStamp멤버는CreateUnicastIpAddressEntry 함수가 호출될 때 무시됩니다. 이러한 멤버는 네트워크 스택에 의해 설정됩니다. ScopeId 멤버는 주소가 추가되는 인터페이스에 의해 자동으로 결정됩니다. Windows 10 시작하여 CreateUnicastIpAddressEntry를 호출할 때 dadStateMIB_UNICASTIPADDRESS_ROW 구조에서 참조되는 IpDadStateP로 설정된 경우 스택은 주소의 초기 DAD 상태를 "미정" 대신 "기본 설정"으로 설정하고 주소에 대해 낙관적 DAD를 수행합니다.

Row 매개 변수가 가리키는 MIB_UNICASTIPADDRESS_ROWAddress 멤버에 전달된 유니캐스트 IP 주소가 인터페이스의 기존 유니캐스트 IP 주소와 중복된 경우 CreateUnicastIpAddressEntry 함수가 실패합니다. 루프백 IP 주소는 CreateUnicastIpAddressEntry 함수를 사용하여 루프백 인터페이스에만 추가할 수 있습니다.

Row 매개 변수가 가리키는 MIB_UNICASTIPADDRESS_ROWAddress 멤버에 전달된 유니캐스트 IP 주소는 즉시 사용할 수 없습니다. 중복 주소 검색 프로세스가 성공적으로 완료된 후 IP 주소를 사용할 수 있습니다. IP 패킷을 보내야 하고 잠재적인 응답을 기다려야 하므로 중복 주소 검색 프로세스가 완료되는 데 몇 초 정도 걸릴 수 있습니다. IPv6의 경우 중복 주소 검색 프로세스는 일반적으로 약 1초가 걸립니다. IPv4의 경우 중복 주소 검색 프로세스는 일반적으로 약 3초가 걸립니다.

CreateUnicastIpAddressEntry 함수를 호출한 후 IP 주소를 사용할 수 있는 시기를 알아야 하는 애플리케이션의 경우 두 가지 메서드를 사용할 수 있습니다. 한 메서드는 폴링 및 GetUnicastIpAddressEntry 함수를 사용합니다. 두 번째 메서드는 NotificationAddrChange, NotifyIpInterfaceChange 또는 NotifyUnicastIpAddressChange 중 하나를 호출하여 주소가 변경되는 경우에 대한 비동기 알림을 설정합니다.

다음 메서드는 GetUnicastIpAddressEntry 및 폴링을 사용하는 방법을 설명합니다. CreateUnicastIpAddressEntry 함수에 대한 호출이 성공적으로 반환된 후 1~3초 동안 일시 중지합니다(IPv6 또는 IPv4 주소가 만들어지는지 여부에 따라 다름). 복제 주소 검색 프로세스를 성공적으로 완료할 수 있는 시간을 허용합니다. 그런 다음 GetUnicastIpAddressEntry 함수를 호출하여 업데이트된 MIB_UNICASTIPADDRESS_ROW 구조를 검색하고 DadState 멤버의 값을 검사합니다. DadState 멤버의 값이 IpDadStatePreferred로 설정된 경우 이제 IP 주소를 사용할 수 있습니다. DadState 멤버의 값이 IpDadStateTentative로 설정된 경우 중복 주소 검색이 아직 완료되지 않았습니다. 이 경우 DadState 멤버가 여전히 IpDadStateTentative로 설정되어 있는 동안 1초마다 GetUnicastIpAddressEntry 함수를 다시 호출합니다. DadState 멤버의 값이 IpDadStatePreferred 또는 IpDadStateTentative 이외의 값으로 반환되면 중복 주소 검색이 실패하고 IP 주소를 사용할 수 없습니다.

다음 메서드는 적절한 알림 함수를 사용하는 방법을 설명합니다. CreateUnicastIpAddressEntry 함수 호출이 성공적으로 반환된 후 NotifyUnicastIpAddressChange 함수를 호출하여 생성되는 IP 주소의 유형에 따라 IPv6 또는 IPv4 유니캐스트 IP 주소에 대한 변경 내용을 알리도록 등록합니다. 생성되는 IP 주소에 대한 알림을 받으면 GetUnicastIpAddressEntry 함수를 호출하여 DadState 멤버를 검색합니다. DadState 멤버의 값이 IpDadStatePreferred로 설정된 경우 이제 IP 주소를 사용할 수 있습니다. DadState 멤버의 값이 IpDadStateTentative로 설정된 경우 중복 주소 검색이 아직 완료되지 않았으며 애플리케이션은 이후 알림을 기다려야 합니다. DadState 멤버의 값이 IpDadStatePreferred 또는 IpDadStateTentative 이외의 값으로 반환되면 중복 주소 검색이 실패하고 IP 주소를 사용할 수 없습니다.

중복 주소 검색 프로세스 중에 미디어의 연결이 끊긴 후 다시 연결되면 중복 주소 검색 프로세스가 다시 시작됩니다. 따라서 프로세스를 완료하는 시간이 IPv6의 일반적인 1초 값 또는 IPv4의 3초 값 이상으로 증가할 수 있습니다.

CreateUnicastIpAddressEntry 함수는 Administrators 그룹의 구성원으로 로그온한 사용자만 호출할 수 있습니다. Administrators 그룹의 구성원이 아닌 사용자가 CreateUnicastIpAddressEntry 를 호출하면 함수 호출이 실패하고 ERROR_ACCESS_DENIED 반환됩니다. Windows Vista 이상에서 UAC(사용자 계정 제어)로 인해 이 함수가 실패할 수도 있습니다. 이 함수를 포함하는 애플리케이션이 기본 제공 관리자가 아닌 Administrators 그룹의 구성원으로 로그온한 사용자에 의해 실행되는 경우 애플리케이션이 requireAdministrator로 설정된 requestedExecutionLevel 이 매니페스트 파일에 표시되지 않는 한 이 호출은 실패합니다. 애플리케이션에 이 매니페스트 파일이 없는 경우 기본 제공 관리자가 아닌 Administrators 그룹의 구성원으로 로그온한 사용자는 이 함수가 성공하려면 기본 제공 관리자(RunAs 관리자)로 향상된 셸에서 애플리케이션을 실행해야 합니다.

예제

다음 예제에서는 CreateUnicastIpAddressEntry 함수를 사용하여 로컬 컴퓨터에 새 유니캐스트 IP 주소 항목을 추가하는 방법을 보여 줍니다.


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

요구 사항

요구 사항
지원되는 최소 클라이언트 Windows Vista [데스크톱 앱만 해당]
지원되는 최소 서버 Windows Server 2008 [데스크톱 앱만 해당]
대상 플랫폼 Windows
헤더 netioapi.h(Iphlpapi.h 포함)
라이브러리 Iphlpapi.lib
DLL Iphlpapi.dll

추가 정보

DeleteUnicastIpAddressEntry

GetUnicastIpAddressEntry

GetUnicastIpAddressTable

IP 도우미 함수 참조

InitializeUnicastIpAddressEntry

MIB_UNICASTIPADDRESS_ROW

MIB_UNICASTIPADDRESS_TABLE

Netsh.exe

NotifyAddrChange

NotifyIpInterfaceChange

NotifyUnicastIpAddressChange

SetUnicastIpAddressEntry