CreatePersistentTcpPortReservation 関数 (iphlpapi.h)

CreatePersistentTcpPortReservation 関数は、ローカル コンピューター上の TCP ポートの連続するブロックに対して永続的な TCP ポート予約を作成します。

構文

IPHLPAPI_DLL_LINKAGE ULONG CreatePersistentTcpPortReservation(
  [in]  USHORT   StartPort,
  [in]  USHORT   NumberOfPorts,
  [out] PULONG64 Token
);

パラメーター

[in] StartPort

ネットワーク バイト順の開始 TCP ポート番号。

[in] NumberOfPorts

予約する TCP ポート番号の数。

[out] Token

関数が成功した場合に返されるポート予約トークンへのポインター。

戻り値

関数が成功した場合、戻り値はNO_ERROR。

関数が失敗した場合、戻り値は次のいずれかのエラー コードになります。

リターン コード 説明
ERROR_ACCESS_DENIED
アクセスが拒否されました。 このエラーは、次のようないくつかの条件で返されます。ユーザーがローカル コンピューターに必要な管理特権を持っていないか、アプリケーションが組み込みの管理者 (RunAs 管理者) として拡張シェルで実行されていません。
ERROR_INVALID_PARAMETER
無効なパラメーターが関数に渡されました。

StartPort パラメーターまたは NumberOfPorts パラメーターで 0 が渡された場合、このエラーが返されます。 このエラーは、 NumberOfPorts パラメーターが StartPort パラメーターに応じてポートのブロックが大きすぎる場合にも返されます。これは、割り当て可能なポートのブロックが割り当て可能な最大ポートを超える可能性があります。

ERROR_SHARING_VIOLATION
ファイルは別のプロセスで使用されているため、このプロセスからアクセスすることはできません。 StartPort パラメーターと NumberOfPorts パラメーターで指定された TCP ポートブロック内の TCP ポートが既に使用されている場合、このエラーが返されます。 このエラーは、StartPort パラメーターと NumberOfPorts パラメーターで指定された TCP ポートのブロックに対する永続的な予約が、既に作成されている TCP ポートのブロックの永続的な予約と一致するか、重複している場合にも返されます。
その他
FormatMessage を使用して、返されたエラーのメッセージ文字列を取得します。

注釈

CreatePersistentTcpPortReservation 関数は、Windows Vista 以降で定義されています。

CreatePersistentTcpPortReservation 関数は、TCP ポートのブロックに永続的な予約を追加するために使用されます。

ポートを予約する必要があるアプリケーションとサービスは、2 つのカテゴリに分類されます。 最初のカテゴリには、操作の一部として特定のポートを必要とするコンポーネントが含まれています。 このようなコンポーネントは、通常、インストール時に必要なポートを指定することを好みます (たとえば、アプリケーション マニフェストで)。 2 番目のカテゴリには、実行時に使用可能なポートまたはポート ブロックが必要なコンポーネントが含まれています。

これら 2 つのカテゴリは、特定のポート予約要求とワイルドカード ポート予約要求に対応しています。 特定の予約要求は永続的または実行時である場合があります。一方、ワイルドカード ポート予約要求は実行時にのみサポートされます。

CreatePersistentTcpPortReservation 関数は、アプリケーションまたはサービスが TCP ポートの永続的なブロックを予約する機能を提供します。 永続的な TCP ポート予約は、Windows の TCP モジュールの永続ストアに記録されます。

呼び出し元は、必要なポートの数と特定の範囲が必要かどうかを指定して、永続的なポート予約を取得します。 要求が満たされる場合、 CreatePersistentTcpPortReservation 関数は一意の不透明なULONG64 トークンを返し、その後予約を識別します。 永続的な TCP ポート予約は、 DeletePersistentTcpPortReservation 関数を呼び出すことによって解放できます。 特定の永続的な TCP ポート予約のトークンは、システムが再起動されるたびに変更される場合があることに注意してください。

Windows では、これらの関数を使用して取得された永続的な予約のコンポーネント間セキュリティは実装されません。 つまり、コンポーネントに永続的なポート予約を取得する機能が付与されている場合、そのコンポーネントは、システム上の他のコンポーネントに付与された永続的なポート予約を自動的に使用できるようになります。 ランタイム予約にはプロセス レベルのセキュリティが適用されますが、このような制御は、CreatePersistentTcpPortReservation 関数または CreatePersistentUdpPortReservation 関数を使用して作成された永続的なポート予約に拡張することはできません。

永続的な TCP ポート予約が取得されると、アプリケーションは TCP ソケットを開き、ソケットでバインド関数の呼び出しを発行する前に、SIO_ASSOCIATE_PORT_RESERVATION IOCTL を指定して予約トークンを渡す WSAIoctl 関数を呼び出すことによって、TCP ポート予約からのポート割り当てを要求できます。

SIO_ACQUIRE_PORT_RESERVATION IOCTL を使用して、TCP または UDP ポートのブロックのランタイム予約を要求できます。 ランタイム ポート予約の場合、ポート プールでは、予約が許可されたソケット上のプロセスから予約を使用する必要があります。 ランタイム ポート予約は、 SIO_ACQUIRE_PORT_RESERVATION IOCTL が呼び出されたソケットの有効期間の間だけ続きます。 これに対し、 CreatePersistentTcpPortReservation 関数を使用して作成された永続的なポート予約は、永続的な予約を取得できる任意のプロセスで使用できます。

CreatePersistentTcpPortReservation 関数は、Administrators グループのメンバーとしてログオンしているユーザーのみが呼び出すことができます。 Administrators グループのメンバーではないユーザーが CreatePersistentTcpPortReservation を呼び出すと、関数呼び出しは失敗し、 ERROR_ACCESS_DENIED が返されます。 この関数は、Windows Vista 以降のユーザー アカウント制御 (UAC) が原因で失敗する場合もあります。 この関数を含むアプリケーションが、組み込みの Administrator 以外の Administrators グループのメンバーとしてログオンしているユーザーによって実行された場合、 requestedExecutionLevel が requireAdministrator に設定されたマニフェスト ファイルでアプリケーションがマークされていない限り、この呼び出しは失敗します。 アプリケーションにこのマニフェスト ファイルがない場合、組み込みの Administrator 以外の Administrators グループのメンバーとしてログオンしているユーザーは、この関数を成功させるために、組み込みの Administrator (RunAs 管理者) として拡張シェルでアプリケーションを実行する必要があります。

次の例では、永続的な TCP ポート予約を作成し、ソケットを作成し、ポート予約からポートを割り当ててから、ソケットを閉じて TCP ポート予約を削除します。

この例は、Administrators グループのメンバーであるユーザーが実行する必要があります。 この例を実行する最も簡単な方法は、組み込みの Administrator (RunAs 管理者) としての拡張シェルにあります。

#ifndef UNICODE
#define UNICODE
#endif

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <Windows.h.>
#include <winsock2.h>
#include <mstcpip.h>
#include <ws2ipdef.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>

// Need to link with iphlpapi.lib
#pragma comment(lib, "iphlpapi.lib")

// Need to link with Ws2_32.lib for Winsock functions
#pragma comment(lib, "ws2_32.lib")

int wmain(int argc, WCHAR ** argv)
{

    // Declare and initialize variables

    int startPort = 0;         // host byte order
    int numPorts = 0;
    USHORT startPortns = 0;    // Network byte order
    ULONG64 resToken = { 0 };

    unsigned long status = 0;

    WSADATA wsaData = { 0 };
    int iResult = 0;

    SOCKET sock = INVALID_SOCKET;
    int iFamily = AF_INET;
    int iType = SOCK_STREAM;
    int iProtocol = IPPROTO_TCP;

    DWORD bytesReturned = 0;


    // Note that the sockaddr_in struct works only with AF_INET not AF_INET6
    // An application needs to use the sockaddr_in6 for AF_INET6
    sockaddr_in service; 
    sockaddr_in sockName;
    int nameLen = sizeof(sockName);
    
    // Validate the parameters
    if (argc != 3) {
        wprintf(L"usage: %s <Starting Port> <Number of Ports>\n",
             argv[0]);
        wprintf(L"Creates a persistent TCP port reservation\n");
        wprintf(L"Example usage:\n");
        wprintf(L"   %s 5000 20\n", argv[0]);
        wprintf(L"   where StartPort=5000 NumPorts=20");
        return 1;
    }

    startPort = _wtoi(argv[1]);
    if (startPort < 0 || startPort > 65535) {
        wprintf(L"Starting point must be either 0 or between 1 and 65,535\n");
        return 1;
    }
    startPortns = htons((USHORT) startPort);

    numPorts = _wtoi(argv[2]);
    if (numPorts < 0) {
        wprintf(L"Number of ports must be a positive number\n");
        return 1;
    }

    status =
        CreatePersistentTcpPortReservation((USHORT) startPortns, (USHORT) numPorts,
                                           &resToken);
    if (status != NO_ERROR) {
        wprintf(L"CreatePersistentTcpPortReservation returned error: %ld\n", status);
        return 1;
    }

    wprintf(L"CreatePersistentTcpPortReservation call succeeded\n");
    wprintf(L"  Token = %I64d\n", resToken);

    // Comment out this block if you don't want to create a socket and associate it with the 
    // persistent reservation

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        wprintf(L"WSAStartup failed with error = %d\n", iResult);
        // return 1;
    }

    sock = socket(iFamily, iType, iProtocol);
    if (sock == INVALID_SOCKET)
        wprintf(L"socket function failed with error = %d\n", WSAGetLastError());
    else {
        wprintf(L"socket function succeeded\n");

        iResult =
            WSAIoctl(sock, SIO_ASSOCIATE_PORT_RESERVATION, (LPVOID) & resToken,
                     sizeof (ULONG64), NULL, 0, &bytesReturned, NULL, NULL);
        if (iResult != 0) {
            wprintf
                (L"WSAIoctl(SIO_ASSOCIATE_PORT_RESERVATION) failed with error = %d\n",
                 WSAGetLastError());
        } else {
            wprintf(L"WSAIoctl(SIO_ASSOCIATE_PORT_RESERVATION) succeeded, bytesReturned = %u\n", 
                bytesReturned);                

            service.sin_family = AF_INET;
            service.sin_addr.s_addr = INADDR_ANY;
            service.sin_port = 0;

            iResult = bind(sock, (SOCKADDR*) &service, sizeof(service) );
            if (iResult == SOCKET_ERROR)
                wprintf(L"bind failed with error = %d\n", WSAGetLastError());
            else {
                wprintf(L"bind succeeded\n");
                iResult = getsockname(sock, (SOCKADDR*) &sockName, &nameLen);
                if (iResult == SOCKET_ERROR) 
                    wprintf(L"getsockname failed with error = %d\n", WSAGetLastError() );
                else {
                    wprintf(L"getsockname succeeded\n");
                    wprintf(L"Port number allocated = %u\n", ntohs(sockName.sin_port) );
                }
            }                  
        }

        if (sock != INVALID_SOCKET) {
            iResult = closesocket(sock);
            if (iResult == SOCKET_ERROR) {
                wprintf(L"closesocket failed with error = %d\n", WSAGetLastError());
                WSACleanup();
            }
        }
    }

    // comment out this block of code if you don't want to delete the reservation just created
    status = DeletePersistentTcpPortReservation((USHORT) startPortns, (USHORT) numPorts);
    if (status != NO_ERROR) {
        wprintf(L"DeletePersistentTcpPortReservation returned error: %ld\n", status);
        return 1;
    }
    wprintf(L"DeletePersistentTcpPortReservation call succeeded\n");

    return 0;
}

要件

要件
サポートされている最小のクライアント Windows Vista [デスクトップ アプリのみ]
サポートされている最小のサーバー Windows Server 2008 [デスクトップ アプリのみ]
対象プラットフォーム Windows
ヘッダー iphlpapi.h
Library Iphlpapi.lib
[DLL] Iphlpapi.dll

こちらもご覧ください

CreatePersistentUdpPortReservation

DeletePersistentTcpPortReservation

DeletePersistentUdpPortReservation

LookupPersistentTcpPortReservation

LookupPersistentUdpPortReservation

SIO_ACQUIRE_PORT_RESERVATION

SIO_ASSOCIATE_PORT_RESERVATION

SIO_RELEASE_PORT_RESERVATION

WSAIoctl

bind