Функция CreateUnicastIpAddressEntry (netioapi.h)
Функция CreateUnicastIpAddressEntry добавляет новую запись одноадресного IP-адреса на локальном компьютере.
Синтаксис
IPHLPAPI_DLL_LINKAGE _NETIOAPI_SUCCESS_ NETIOAPI_API CreateUnicastIpAddressEntry(
[in] const MIB_UNICASTIPADDRESS_ROW *Row
);
Параметры
[in] Row
Указатель на запись структуры MIB_UNICASTIPADDRESS_ROW для записи одноадресного IP-адреса.
Возвращаемое значение
Если функция выполняется успешно, возвращаемое значение будет NO_ERROR.
Если функция завершается сбоем, возвращаемое значение представляет собой один из следующих кодов ошибок.
Код возврата | Описание |
---|---|
|
Отказано в доступе". Эта ошибка возвращается при нескольких условиях, которые включают следующее: у пользователя отсутствуют необходимые права администратора на локальном компьютере или приложение не выполняется в расширенной оболочке в качестве встроенного администратора (администратора запуска от имени). |
|
В функцию передан недопустимый параметр. Эта ошибка возвращается, если в параметре Row передается указатель NULL, члену AddressMIB_UNICASTIPADDRESS_ROW, на который указывает параметр Row, не задан допустимый адрес IPv4 или IPv6 одноадресной рассылки, или оба элемента InterfaceLuid и InterfaceIndexMIB_UNICASTIPADDRESS_ROW, на которые указывает параметр Row, были не указаны.
Эта ошибка также возвращается для других ошибок в значениях, заданных для членов структуры MIB_UNICASTIPADDRESS_ROW . К этим ошибкам относятся следующие: если элемент ValidLifetime меньше элемента PreferredLifetime , Значение , если элемент PrefixOrigin имеет значение IpPrefixOriginUnchanged , а SuffixOrigin — не ipSuffixOriginUnchanged, если для элемента PrefixOrigin не задано значение IpPrefixOriginUnchanged , а для SuffixOrigin задано значение IpSuffixOriginUnchanged, если prefixOrigin Для элемента не задано значение из перечисления NL_PREFIX_ORIGIN , если для элемента SuffixOrigin не задано значение из перечисления NL_SUFFIX_ORIGIN или если для элемента OnLinkPrefixLength задано значение, превышающее длину IP-адреса, в битах (32 для IPv4-адреса одноадресной рассылки или 128 для одноадресного IPv6-адреса). |
|
Не удалось найти указанный интерфейс. Эта ошибка возвращается, если не удалось найти сетевой интерфейс, заданный элементом InterfaceLuid или InterfaceIndexMIB_UNICASTIPADDRESS_ROW , на который указывает параметр Row . |
|
Запрос не поддерживается. Эта ошибка возвращается, если на локальном компьютере нет стека IPv4 и в элементе AddressMIB_UNICASTIPADDRESS_ROW , на который указывает параметр Row , указан IPv4-адрес. Эта ошибка также возвращается, если на локальном компьютере нет стека IPv6 и в элементе Address был указан IPv6-адрес. |
|
Объект уже существует. Эта ошибка возвращается, если элемент AddressMIB_UNICASTIPADDRESS_ROW , на который указывает параметр Row , является дубликатом существующего одноадресного IP-адреса в интерфейсе, указанном элементом InterfaceLuid или InterfaceIndexMIB_UNICASTIPADDRESS_ROW. |
|
Используйте FormatMessage , чтобы получить строку сообщения для возвращенной ошибки. |
Комментарии
Функция CreateUnicastIpAddressEntry определена в Windows Vista и более поздних версиях.
Функция CreateUnicastIpAddressEntry используется для добавления новой записи одноадресной рассылки IP-адреса на локальном компьютере. Ip-адрес одноадресной рассылки, добавленный функцией CreateUnicastIpAddressEntry , не является постоянным. IP-адрес существует только до тех пор, пока существует объект адаптера. Перезагрузка компьютера приводит к удалению IP-адреса, как и при сбросе сетевого интерфейса вручную карта (NIC). Кроме того, некоторые события PnP могут уничтожить адрес.
Чтобы создать IPv4-адрес, который сохраняется, можно использовать метод EnableStatic класса Win32_NetworkAdapterConfiguration в элементах управления инструментария управления Windows (WMI). Команду netsh также можно использовать для создания постоянного адреса IPv4 или IPv6.
Дополнительные сведения см. в документации по Netsh.exe документации по сокетам Windows.
Функция InitializeUnicastIpAddressEntry должна использоваться для инициализации элементов записи структуры MIB_UNICASTIPADDRESS_ROW значениями по умолчанию. Затем приложение может изменить члены в MIB_UNICASTIPADDRESS_ROW записи, которую оно хочет изменить, а затем вызвать функцию CreateUnicastIpAddressEntry .
Элемент Address в структуре MIB_UNICASTIPADDRESS_ROW , на который указывает параметр Row , должен быть инициализирован допустимым адресом IPv4 или IPv6 одноадресной рассылки. Элемент si_family структуры SOCKADDR_INET в элементе Address должен быть инициализирован для AF_INET или AF_INET6, а соответствующий элемент Ipv4 или Ipv6 структуры SOCKADDR_INET должен иметь допустимый IP-адрес одноадресной рассылки. Кроме того, по крайней мере один из следующих элементов в структуре MIB_UNICASTIPADDRESS_ROW , указываемой на параметр Row , должен быть инициализирован в интерфейсе: InterfaceLuid или InterfaceIndex.
Поля используются в указанном выше порядке. Поэтому если указан InterfaceLuid , то этот элемент используется для определения интерфейса, к которому добавляется одноадресный IP-адрес. Если для элемента InterfaceLuid не задано значение (значения этого элемента были равны нулю), то для определения интерфейса используется элемент InterfaceIndex .
Если элемент OnLinkPrefixLengthMIB_UNICASTIPADDRESS_ROW , на который указывает параметр Row , имеет значение 255, то CreateUnicastIpAddressEntry добавит новый одноадресный IP-адрес с набором элементов OnLinkPrefixLength , равным длине IP-адреса. Поэтому для одноадресного IPv4-адреса OnLinkPrefixLength имеет значение 32, а OnLinkPrefixLength — 128 для одноадресного IPv6-адреса. Если это приведет к неправильной маске подсети для IPv4-адреса или неправильному префиксу ссылки для IPv6-адреса, приложение должно задать для этого элемента правильное значение перед вызовом CreateUnicastIpAddressEntry.
Если ip-адрес одноадресной рассылки создается с неправильно заданным элементом OnLinkPrefixLength , ip-адрес можно изменить, вызвав Метод SetUnicastIpAddressEntry с правильным значением элемента OnLinkPrefixLength .
Элементы DadState, ScopeId и CreationTimeStampструктуры MIB_UNICASTIPADDRESS_ROW , на которую указывает Строка , игнорируются при вызове функции CreateUnicastIpAddressEntry . Эти элементы задаются сетевым стеком. Элемент ScopeId автоматически определяется интерфейсом, в который добавляется адрес. Начиная с Windows 10, если для dadState задано значение IpDadStatePreferred в структуре MIB_UNICASTIPADDRESS_ROW при вызове Метода CreateUnicastIpAddressEntry, стек установит начальное состояние DAD адреса на "предпочтительное", а не "предварительное" и выполнит оптимистичный DAD для адреса.
Функция CreateUnicastIpAddressEntry завершится ошибкой , если одноадресный IP-адрес, переданный в элементе AddressMIB_UNICASTIPADDRESS_ROW , на который указывает параметр Row , является дубликатом существующего одноадресного IP-адреса в интерфейсе. Обратите внимание, что IP-адрес замыкания на себя можно добавить в интерфейс замыкания на себя только с помощью функции CreateUnicastIpAddressEntry .
Ip-адрес одноадресной рассылки, переданный в элементе AddressMIB_UNICASTIPADDRESS_ROW , на который указывает параметр Row , нельзя использовать сразу. IP-адрес можно использовать после успешного завершения процесса обнаружения повторяющихся адресов. Процесс обнаружения повторяющихся адресов может занять несколько секунд, так как необходимо отправлять IP-пакеты и ожидать потенциальных ответов. Для IPv6 процесс обнаружения повторяющихся адресов обычно занимает около секунды. Для IPv4 процесс обнаружения повторяющихся адресов обычно занимает около трех секунд.
Если приложению необходимо знать, когда IP-адрес можно использовать после вызова функции CreateUnicastIpAddressEntry , можно использовать два метода. Один из методов использует опрос и функцию GetUnicastIpAddressEntry . Второй метод вызывает одну из функций уведомлений NotifyAddrChange, NotifyIpInterfaceChange или NotifyUnicastIpAddressChange , чтобы настроить асинхронное уведомление об изменении адреса.
Следующий метод описывает, как использовать GetUnicastIpAddressEntry и опрос. После успешного возврата функции CreateUnicastIpAddressEntry приостановите работу на одну-три секунды (в зависимости от того, создается ли IPv6- или IPv4-адрес), чтобы предоставить время для успешного завершения процесса обнаружения адресов дублирования. Затем вызовите функцию GetUnicastIpAddressEntry , чтобы получить обновленную структуру MIB_UNICASTIPADDRESS_ROW и проверить значение элемента DadState . Если для элемента DadState задано значение IpDadStatePreferred, IP-адрес теперь можно использовать. Если для элемента DadState задано значение IpDadStateTentative, обнаружение повторяющихся адресов еще не завершено. В этом случае вызывайте функцию GetUnicastIpAddressEntry каждые полсекунды, пока член DadState по-прежнему имеет значение IpDadStateTentative. Если значение элемента DadState возвращает значение, отличное от IpDadStatePreferred или IpDadStateTentative, обнаружение повторяющихся адресов завершилось ошибкой и IP-адрес недоступен.
Следующий метод описывает, как использовать соответствующую функцию уведомления. После успешного возврата функции CreateUnicastIpAddressEntry вызовите функцию NotifyUnicastIpAddressChange , чтобы зарегистрироваться для уведомления об изменениях ip-адресов одноадресной рассылки IPv6 или IPv4 в зависимости от типа создаваемого IP-адреса. При получении уведомления о создаваемом IP-адресе вызовите функцию GetUnicastIpAddressEntry , чтобы получить элемент DadState . Если для элемента DadState задано значение IpDadStatePreferred, IP-адрес теперь можно использовать. Если для элемента DadState задано значение IpDadStateTentative, обнаружение повторяющихся адресов еще не завершено и приложению необходимо дождаться будущих уведомлений. Если значение элемента DadState возвращает значение, отличное от IpDadStatePreferred или IpDadStateTentative, обнаружение повторяющихся адресов завершилось ошибкой и IP-адрес недоступен.
Если во время процесса обнаружения повторяющихся адресов носитель отключается, а затем повторно подключается, процесс обнаружения повторяющихся адресов перезапускается. Таким образом, время завершения процесса может превысить обычное значение 1 секунды для IPv6 или 3 секунды для IPv4.
Функция CreateUnicastIpAddressEntry может вызываться только пользователем, вошедшего в систему как член группы Администраторы. Если метод CreateUnicastIpAddressEntry вызывается пользователем, не входящий в группу Администраторы, вызов функции завершится ошибкой и возвращается ERROR_ACCESS_DENIED. Эта функция также может завершиться ошибкой из-за контроля учетных записей (UAC) в Windows Vista и более поздних версиях. Если приложение, содержащее эту функцию, выполняется пользователем, вошедшего в систему как участник группы администраторов, отличный от встроенного администратора, этот вызов завершится ошибкой, если приложение не было отмечено в файле манифеста параметром requestedExecutionLevel , для которого задано значение requireAdministrator. Если в приложении отсутствует этот файл манифеста, пользователь, вошедший в систему как член группы администраторов, отличный от встроенного администратора, должен выполнять приложение в расширенной оболочке в качестве встроенного администратора (администратора запуска от имени) для успешного выполнения этой функции.
Примеры
В следующем примере показано, как использовать функцию 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 |
Header | netioapi.h (включая Iphlpapi.h) |
Библиотека | Iphlpapi.lib |
DLL | Iphlpapi.dll |
См. также раздел
Справочник по вспомогательным функциям IP