青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

天行健 君子當自強而不息

使用DirectPlay進行網絡互聯(3)


本篇是使用DirectPlay進行網絡互聯(2)的續篇。

銷毀玩家

當玩家斷開連接時,服務器端會收到消息 DPN_MSGID_DESTROY_PLAYER,這時需要將消息緩沖區轉換為DPNMSG_DESTROY_PLAYER類型。

The DPNMSG_DESTROY_PLAYER structure contains information for the DPN_MSGID_DESTROY_PLAYER system message.

typedef struct _DPNMSG_DESTROY_PLAYER{
DWORD dwSize;
DPNID dpnidPlayer;
PVOID pvPlayerContext;
DWORD dwReason;
} DPNMSG_DESTROY_PLAYER, *PDPNMSG_DESTROY_PLAYER;
dwSize
Size of this structure.
dpnidPlayer
DPNID of the player deleted from the session.
pvPlayerContext
Player context value.
dwReason
One of the following flags indicating why the player was destroyed.
DPNDESTROYPLAYERREASON_NORMAL
The player is being deleted for normal reasons.
DPNDESTROYPLAYERREASON_CONNECTIONLOST
The player is being deleted because the connection was lost.
DPNDESTROYPLAYERREASON_SESSIONTERMINATED
The player is being deleted because the session was terminated.
DPNDESTROYPLAYERREASON_HOSTDESTROYEDPLAYER
The player is being deleted because the host called IDirectPlay8Peer::DestroyPeer.

Return Values

Return DPN_OK.

Remarks

In client/server mode, this message is received only by the server. In peer-to-peer mode, all players receive this message.

When the server closes a session, it receives a DPN_MSGID_DESTROY_PLAYER message for all connected players. Because the server knows that it is disconnecting, this is normal behavior, and the dwReason member of the associated structure is set to DPNDESTROYPLAYERREASON_NORMAL. The DPNDESTROYPLAYERREASON_SESSIONTERMINATED value is only set for unexpected disconnections.

You might receive DPN_MSGID_CREATE_PLAYER and DPN_MSGID_DESTROY_PLAYER messages on different threads. However, you will not receive a DPN_MSGID_DESTROY_PLAYER message before your callback function has returned from receiving a DPN_MSGID_CREATE_PLAYER message.

要強制一個玩家斷開連接,使用IDirectPlay8Server::DestroyClient函數即可。

Deletes a client from the session.

HRESULT DestroyClient(
const DPNID
dpnidClient,
const VOID *const pDestroyInfo,
const DWORD dwDestroyInfoSize,
const DWORD dwFlags
);

Parameters

dpnidClient
[in] Variable of type DPNID that specifies the identifier of the client to delete.
pDestroyInfo
[in] Pointer that describes additional delete data information.
dwDestroyInfoSize
[in] Variable of type DWORD that specifies the size of the data in the pDestroyInfo parameter.
dwFlags
[in] Reserved. Must be 0.

Return Values

Returns S_OK if successful, or one of the following error values.

DPNERR_INVALIDPARAM
DPNERR_INVALIDPLAYER
DPNERR_NOTHOST

以下代碼示例了如何處理消息DPN_MSGID_DESTROY_PLAYER。

// application variables
struct PLAYER_INFO
{
    DPNID   player_id;  
// DirectPlay Player ID
    char    name[26];   // Player Name

    PLAYER_INFO()   { player_id = 0; }
};

// window handles, class.
HWND g_hwnd;
char g_class_name[] = "ServerClass";

// application GUID
GUID g_app_guid = { 0xababbe60, 0x1ac0, 0x11d5, { 0x90, 0x89, 0x44, 0x45, 0x53, 0x54, 0x0, 0x1 } };

IDirectPlay8Server*         g_dp_server;    
// DirectPlay Server
DPN_SERVICE_PROVIDER_INFO*  g_adapter_list; // adapters
DWORD                       g_num_adapters; // number of adapters

PLAYER_INFO g_player_info[256]; 
// player information
BOOL g_is_hosting;              // flag indicates whether host started or not

//----------------------------------------------------------------------------------------
// Callback function that receives all messages from the client, and receives indications 
// of session changes from the IDirectPlay8Client interface. 
//----------------------------------------------------------------------------------------
HRESULT WINAPI Net_Msg_Handle(PVOID user_context, DWORD message_id, PVOID msg_buffer)
{

    DPNMSG_DESTROY_PLAYER*  destroy_player; // contains information for the DPN_MSGID_DESTROY_PLAYER system message
    DPN_PLAYER_INFO*        dpn_player_info;// describes static player informaion
    DPN_BUFFER_DESC         buffer_desc;    // used dy DirectPlay for generic buffer information

    DPNHANDLE       async_handle;
    PLAYER_INFO*    player_info;
    
int             index;
    DWORD           size;
    
char            message[512];
    HRESULT         rv;

    
switch(message_id)
    {
    
// Microsoft DirectPlay generates the DPN_MSGID_DESTROY_PLAYER message when a player leaves a peer-to-peer 
    // or client/server session.
    case DPN_MSGID_DESTROY_PLAYER:
        destroy_player = (DPNMSG_DESTROY_PLAYER *) msg_buffer;

        
// make sure it is not the host
        if((player_info = (PLAYER_INFO*) destroy_player->pvPlayerContext) == NULL)
            
break;

        
// remove the player from list

        player_info->player_id = 0;

        
// An application sends an LB_FINDSTRING message to find the first string in a list box that begins 
        // with the specified string. 
        //
        // The return value is the index of the matching item, or LB_ERR if the search was unsuccessful. 
        //
        // wParam:
        //    Specifies the zero-based index of the item before the first item to be searched. 
        //    When the search reaches the bottom of the list box, it continues searching from the top of the 
        //    list box back to the item specified by the wParam parameter. If wParam is –1, the entire list 
        //    box is searched from the beginning. 
        // 
        // lParam:
        //    Pointer to the null-terminated string that contains the string for which to search. 
        //    The search is case independent, so this string can contain any combination of uppercase and 
        //    lowercase letters.       
        index = (int) SendMessage(GetDlgItem(g_hwnd, IDC_USERS), LB_FINDSTRING, -1, (LPARAM)player_info->name);

        
if(index != LB_ERR)
            
// An application sends an LB_DELETESTRING message to delete a string in a list box. 
            //
            // wParam:
            //      Specifies the zero-based index of the string to be deleted. 
            // lParam:
            //      This parameter is not used. 
            SendMessage(GetDlgItem(g_hwnd, IDC_USERS), LB_DELETESTRING, index, 0);

        
// send message to remaining players notifying player left
        sprintf(message, "%s quit.", player_info->name);
        Send_Text_Msg(DPNID_ALL_PLAYERS_GROUP, message);

        
break;
    }

    
// return S_OK to signify the message was handled OK.
    return S_OK;
}

 

接收數據

實際的游戲數據采取應用程序指定消息的形式,但總是封裝在DPN_MSGID_RECEIVE消息類型中,使用DPNMSG_RECEIVE結構體。

The DPNMSG_RECEIVE structure contains information for the DPN_MSGID_RECEIVE system message.

typedef struct {
DWORD dwSize;
DPNID dpnidSender;
PVOID pvPlayerContext;
PBYTE pReceiveData;
DWORD dwReceiveDataSize;
DPNHANDLE hBufferHandle;
} DPNMSG_RECEIVE, *PDPNMSG_RECEIVE;
dwSize
Size of this structure.
dpnidSender
DPNID of the player that sent the message.
pvPlayerContext
Player context value of the player that sent the message.
pReceiveData
PBYTE pointer to the message data buffer. This buffer is normally only valid while the DPN_MSGID_RECEIVE message is being processed by the callback message handler.
dwReceiveDataSize
Size of the data, in bytes, of the pReceiveData member.
hBufferHandle
Buffer handle for the pReceiveData member. If you have returned DPNSUCCESS_PENDING , pass this value to ReturnBuffer to notify Microsoft® DirectPlay® to free the buffer.

Return Values

Return DPNSUCCESS_PENDING to transfer ownership of the data buffer to your application. Otherwise, return DPN_OK.

Remarks

Because you should not spend large amounts of time processing messages, you should copy the data, and process the message. Alternatively, you can return DPNSUCCESS_PENDING from the callback message handler. Doing so transfers ownership of the buffer to the application. If you return DPNSUCCESS_PENDING, you must call IDirectPlay8Peer::ReturnBuffer, IDirectPlay8Client::ReturnBuffer, or IDirectPlay8Server::ReturnBuffer when you are finished with the buffer. Pass the method the value you receive in the hBufferHandle member to identify the buffer. If you fail to call ReturnBuffer, you will create a memory leak.


以下代碼示例了如何處理消息DPN_MSGID_RECEIVE。
 
IDirectPlay8Server*         g_dp_server;    // DirectPlay Server

//----------------------------------------------------------------------------------------
// Callback function that receives all messages from the client, and receives indications 
// of session changes from the IDirectPlay8Client interface. 
//----------------------------------------------------------------------------------------
HRESULT WINAPI Net_Msg_Handle(PVOID user_context, DWORD message_id, PVOID msg_buffer)
{
    DPNMSG_RECEIVE*         receive_data;   
// contains information for the DPN_MSGID_RECEIVE system message
    DPN_BUFFER_DESC         buffer_desc;    // used dy DirectPlay for generic buffer information

    DPNHANDLE       async_handle;

    
switch(message_id)
    {
    
// Microsoft DirectPlay generates the DPN_MSGID_RECEIVE message when a message has been processed by 
    // the receiver.
    case DPN_MSGID_RECEIVE:
        receive_data = (DPNMSG_RECEIVE*) msg_buffer;

        
// forward message to all player except host
        buffer_desc.dwBufferSize = receive_data->dwReceiveDataSize;
        buffer_desc.pBufferData  = receive_data->pReceiveData;

        g_dp_server->SendTo(DPNID_ALL_PLAYERS_GROUP, &buffer_desc, 1, 0, NULL, &async_handle, DPNSEND_NOLOOPBACK);

        
break;
    }

    
// return S_OK to signify the message was handled OK.
    return S_OK;
}

 

發送服務器端消息

如果網絡不傳輸數據,它就一無是處。要讓服務器端對象發送數據到一個已經連接的客戶端,需要使用SendTo函數,該函數發送數據到單個玩家,或一次發送到所有玩家,或發送到屬于某一特定組的所有玩家。

Transmits data to a client or group within the session. The message can be sent synchronously or asynchronously.

HRESULT SendTo(
const DPNID
dpnid,
const DPN_BUFFER_DESC *const pBufferDesc,
const DWORD cBufferDesc,
const DWORD dwTimeOut,
void *const pvAsyncContext,
DPNHANDLE *const phAsyncHandle,
const DWORD dwFlags
);

Parameters

dpnid
[in] Identifier of the client or group to receive data. Set this parameter to DPNID_ALL_PLAYERS_GROUP to send a message to all players in the session.
pBufferDesc
[in] Pointer to a DPN_BUFFER_DESC structure that describes the data to send.
cBufferDesc
[in] Number of DPN_BUFFER_DESC structures pointed to by pBufferDesc. There can be only one buffer in this version of Microsoft® DirectPlay® .
dwTimeOut
[in] Number of milliseconds to wait for the message to send. If the message has not been sent by the dwTimeOut value, it is deleted from the send queue. If you set this parameter to 0, the message remains in the send queue until it is sent or until the link is dropped.
pvAsyncContext
[in] Pointer to the user-supplied context, which is returned in the pvUserContext member of the DPN_MSGID_SEND_COMPLETE system message.
phAsyncHandle
[out] A DPNHANDLE. When the method returns, phAsyncHandle will point to a handle that you can pass to IDirectPlay8Server::CancelAsyncOperation to cancel the operation. This parameter must be set to NULL if you set the DPNSEND_SYNC flag in dwFlags.
dwFlags
[in] Flags that describe send behavior. You can set one or more of the following flags.
DPNSEND_SYNC
Process the SendTo request synchronously.
DPNSEND_NOCOPY
Use the data in the DPN_BUFFER_DESC structure and do not make an internal copy. This may be a more efficient method of sending data. However, it is less robust because the sender might be able to modify the message before the receiver has processed it. This flag cannot be used with DPNSEND_NOCOMPLETE.
DPNSEND_NOCOMPLETE
Do not send the DPN_MSGID_SEND_COMPLETE structure to the message handler. This flag may not be used with DPNSEND_NOCOPY or DPNSEND_GUARANTEED. Additionally, when using this flag pvAsyncContext must be NULL.
DPNSEND_COMPLETEONPROCESS
Send the DPN_MSGID_SEND_COMPLETE to the message handler when this message has been delivered to the target and the target's message handler returns from indicating its reception. There is additional internal message overhead when this flag is set, and the message transmission process may become significantly slower. If you set this flag, DPNSEND_GUARANTEED must also be set.
DPNSEND_GUARANTEED
Send the message by a guaranteed method of delivery.
DPNSEND_PRIORITY_HIGH
Sets the priority of the message to high. This flag cannot be used with DPNSEND_PRIORITY_LOW.
DPNSEND_PRIORITY_LOW
Sets the priority of the message to low. This flag cannot be used with DPNSEND_PRIORITY_HIGH.
DPNSEND_NOLOOPBACK
Suppress the DPN_MSGID_RECEIVE system message to your message handler when you are sending to a group that includes the local player. For example, this flag is useful if you are broadcasting to the entire session.
DPNSEND_NONSEQUENTIAL
If this flag is set, the target application will receive the messages in the order that they arrive at the user's computer. If this flag is not set, messages are delivered sequentially, and will be received by the target application in the order that they were sent. Doing so may require buffering incoming messages until missing messages arrive.

Return Values

Returns S_OK if this method is processed synchronously and is successful. By default, this method is run asynchronously and generally returns DPNSUCCESS_PENDING or one of the following error values.

DPNERR_CONNECTIONLOST
DPNERR_INVALIDFLAGS
DPNERR_INVALIDPARAM
DPNERR_INVALIDPLAYER
DPNERR_TIMEDOUT

Remarks

This method generates a DPN_MSGID_RECEIVE system message in the receiver's message handler. The data is contained in the pReceiveData member of the associated structure.

Messages can have one of three priorities: low, normal, and high. To specify a low or high priority for the message set the appropriate flag in dwFlags. If neither of the priority flags is set, the message will have normal priority. See Basic Networking for a discussion of send priorities.

When the SendTo request is completed, a DPN_MSGID_SEND_COMPLETE system message is posted to the sender's message handler. The success or failure of the request is contained in the hResultCode member of the associated structure. You can suppress the send completion by setting the DPNSEND_NOCOMPLETE flag in dwflags.

Send completions are typically posted on the source computer as soon as the message is sent. In other words, a send completion does not necessarily mean that the message has been processed on the target. It may still be in a queue. If you want to be certain that the message has been processed by the target, set the DPNSEND_COMPLETEONPROCESS flag in dwFlags. This flag ensures that the send completion will not be sent until the target's message handler has processed the message, and returned.

Note  Do not assume that resources such as the data buffer will remain valid until the method has returned. If you call this method asynchronously, the DPN_MSGID_SEND_COMPLETE message may be received and processed by your message handler before the call has returned. If your message handler deallocates or otherwise invalidates a resource such as the data buffer, that resource may become invalid at any time after the method has been called.


下面這個函數發送消息數據到指定的玩家ID組。
 
//--------------------------------------------------------------------------------
// Send text to all clients which specified by player_id.
//--------------------------------------------------------------------------------
void Send_Text_Msg(DPNID player_id, char* text)
{
    DPNHANDLE async_handle;
    DPN_BUFFER_DESC buffer_desc;

    
if(g_dp_server == NULL)
        
return;

    
// build a data structure
    buffer_desc.dwBufferSize = (DWORD) (strlen(text) + 1);
    buffer_desc.pBufferData  = (BYTE*) text;

    
// Send message (async method - reason for handle)
    //
    // Transmits data to a client or group within the session. 
    // The message can be sent synchronously or asynchronously.
    g_dp_server->SendTo(player_id, &buffer_desc, 1, 0, NULL, &async_handle, DPNSEND_NOLOOPBACK);
}
 

結束主持會話

一旦服務器端完成了工作,就是停止會話的時候了,停止會話也就是停止所有傳輸并銷毀所有玩家,這可以通過IDirectPlay8Server:: Close來完成。因為該函數采用同步方式工作,所以在所有傳輸完成以及所有連接關閉之前不會返回,這就保證了無須有任何顧慮,就能關閉應用程序。

Closes the open connection to a session.

HRESULT Close(
const DWORD
dwFlags
);

Parameters

dwFlags
[in] Reserved. Must be 0.

Return Values

Returns S_OK if successful, or the following error value.

DPNERR_UNINITIALIZED
 

Remarks

This method must be called on any object successfully initialized with IDirectPlay8Server::Initialize.

This method is a counterpart to IDirectPlay8Server::Host. It closes all active network connections hosted by the server. This method is synchronous, and will not return until the server has processed all DPN_MSGID_DESTROY_PLAYER messages. This feature guarantees that when Close returns, you can safely shut down the server application.

Calling Close will cancel all outstanding operations, including data sent as guaranteed. To make sure all messages are sent, wait for all outstanding SendTo calls to complete before calling Close.


以下給出一個完整的服務器端代碼示例:

點擊下載源碼和工程

 
/***************************************************************************************
PURPOSE:
    Server Network Demo
 ***************************************************************************************/


#include <windows.h>
#include <stdio.h>
#include <dplay8.h>
#include <dpaddr.h>
#include "resource.h"

#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "dplayx.lib")

#pragma warning(disable : 4996)

#define Safe_Release(p) if((p)) (p)->Release();

// application variables
struct PLAYER_INFO
{
    DPNID   player_id;  
// DirectPlay Player ID
    char    name[26];   // Player Name

    PLAYER_INFO()   { player_id = 0; }
};

// window handles, class.
HWND g_hwnd;
char g_class_name[] = "ServerClass";

// application GUID
GUID g_app_guid = { 0xababbe60, 0x1ac0, 0x11d5, { 0x90, 0x89, 0x44, 0x45, 0x53, 0x54, 0x0, 0x1 } };

IDirectPlay8Server*         g_dp_server;    
// DirectPlay Server
DPN_SERVICE_PROVIDER_INFO*  g_adapter_list; // adapters
DWORD                       g_num_adapters; // number of adapters

PLAYER_INFO g_player_info[256]; 
// player information
BOOL g_is_hosting;              // flag indicates whether host started or not

//--------------------------------------------------------------------------------
// Send text to all clients which specified by player_id.
//--------------------------------------------------------------------------------
void Send_Text_Msg(DPNID player_id, char* text)
{
    DPNHANDLE async_handle;
    DPN_BUFFER_DESC buffer_desc;

    
if(g_dp_server == NULL)
        
return;

    
// build a data structure
    buffer_desc.dwBufferSize = (DWORD) (strlen(text) + 1);
    buffer_desc.pBufferData  = (BYTE*) text;

    
// Send message (async method - reason for handle)
    //
    // Transmits data to a client or group within the session. 
    // The message can be sent synchronously or asynchronously.
    g_dp_server->SendTo(player_id, &buffer_desc, 1, 0, NULL, &async_handle, DPNSEND_NOLOOPBACK);
}

//----------------------------------------------------------------------------------------
// Callback function that receives all messages from the client, and receives indications 
// of session changes from the IDirectPlay8Client interface. 
//----------------------------------------------------------------------------------------
HRESULT WINAPI Net_Msg_Handle(PVOID user_context, DWORD message_id, PVOID msg_buffer)
{
    DPNMSG_CREATE_PLAYER*   create_player;  
// contains information for the DPN_MSGID_CREATE_PLAYER system message
    DPNMSG_DESTROY_PLAYER*  destroy_player; // contains information for the DPN_MSGID_DESTROY_PLAYER system message
    DPNMSG_RECEIVE*         receive_data;   // contains information for the DPN_MSGID_RECEIVE system message
    DPN_PLAYER_INFO*        dpn_player_info;// describes static player informaion
    DPN_BUFFER_DESC         buffer_desc;    // used dy DirectPlay for generic buffer information

    DPNHANDLE       async_handle;
    PLAYER_INFO*    player_info;
    
int             index;
    DWORD           size;
    
char            message[512];
    HRESULT         rv;

    
switch(message_id)
    {
    
// Microsoft DirectPlay generates the DPN_MSGID_CREATE_PLAYER message when a player is added to a 
    // peer-to-peer or client/server session.
    case DPN_MSGID_CREATE_PLAYER:
        create_player = (DPNMSG_CREATE_PLAYER*) msg_buffer;

        
// get player name and save it

        size = 0;
        dpn_player_info = NULL;

        
// Retrieves the client information set for the specified client
        rv = g_dp_server->GetClientInfo(create_player->dpnidPlayer, dpn_player_info, &size, 0);

        
if(FAILED(rv) && rv != DPNERR_BUFFERTOOSMALL)
        {
            
// skip this if this is a host player
            if(rv == DPNERR_INVALIDPLAYER)
                
break;

            
return E_FAIL;
        }

        
if((dpn_player_info = (DPN_PLAYER_INFO*) new BYTE[size]) == NULL)
            
return E_FAIL;

        ZeroMemory(dpn_player_info, size);
        dpn_player_info->dwSize = 
sizeof(DPN_PLAYER_INFO);

        
// retrieves the client information set again
        if(FAILED(g_dp_server->GetClientInfo(create_player->dpnidPlayer, dpn_player_info, &size, 0)))
        {
            delete[] dpn_player_info;
            
return E_FAIL;
        }

        
// Find an empty player structure to use

        index = -1;

        
for(int i = 0; i < 256; i++)
        {
            
if(g_player_info[i].player_id == 0)
            {
                index = i;
                
break;
            }
        }

        
if(index == -1)
        {
            delete[] dpn_player_info;
            
return E_FAIL;
        }

        
// set player context pointer
        create_player->pvPlayerContext = (void*) &g_player_info[index];

        
// save player ID
        g_player_info[index].player_id = create_player->dpnidPlayer;
        
        wcstombs(g_player_info[index].name, dpn_player_info->pwszName, 256);
        
        
// add player to list
        SendMessage(GetDlgItem(g_hwnd, IDC_USERS), LB_ADDSTRING, 0, (LPARAM) g_player_info[index].name);

        
// send a message to all players notifying someone joined
        sprintf(message, "%s joined!", g_player_info[index].name);
        Send_Text_Msg(DPNID_ALL_PLAYERS_GROUP, message);

        delete[] dpn_player_info;

        
break;

    
// Microsoft DirectPlay generates the DPN_MSGID_DESTROY_PLAYER message when a player leaves a peer-to-peer 
    // or client/server session.
    case DPN_MSGID_DESTROY_PLAYER:
        destroy_player = (DPNMSG_DESTROY_PLAYER *) msg_buffer;

        
// make sure it is not the host
        if((player_info = (PLAYER_INFO*) destroy_player->pvPlayerContext) == NULL)
            
break;

        
// remove the player from list

        player_info->player_id = 0;

        
// An application sends an LB_FINDSTRING message to find the first string in a list box that begins 
        // with the specified string. 
        //
        // The return value is the index of the matching item, or LB_ERR if the search was unsuccessful. 
        //
        // wParam:
        //    Specifies the zero-based index of the item before the first item to be searched. 
        //    When the search reaches the bottom of the list box, it continues searching from the top of the 
        //    list box back to the item specified by the wParam parameter. If wParam is –1, the entire list 
        //    box is searched from the beginning. 
        // 
        // lParam:
        //    Pointer to the null-terminated string that contains the string for which to search. 
        //    The search is case independent, so this string can contain any combination of uppercase and 
        //    lowercase letters.       
        index = (int) SendMessage(GetDlgItem(g_hwnd, IDC_USERS), LB_FINDSTRING, -1, (LPARAM)player_info->name);

        
if(index != LB_ERR)
            
// An application sends an LB_DELETESTRING message to delete a string in a list box. 
            //
            // wParam:
            //      Specifies the zero-based index of the string to be deleted. 
            // lParam:
            //      This parameter is not used. 
            SendMessage(GetDlgItem(g_hwnd, IDC_USERS), LB_DELETESTRING, index, 0);

        
// send message to remaining players notifying player left
        sprintf(message, "%s quit.", player_info->name);
        Send_Text_Msg(DPNID_ALL_PLAYERS_GROUP, message);

        
break;

    
// Microsoft DirectPlay generates the DPN_MSGID_RECEIVE message when a message has been processed by 
    // the receiver.
    case DPN_MSGID_RECEIVE:
        receive_data = (DPNMSG_RECEIVE*) msg_buffer;

        
// forward message to all player except host
        buffer_desc.dwBufferSize = receive_data->dwReceiveDataSize;
        buffer_desc.pBufferData  = receive_data->pReceiveData;

        g_dp_server->SendTo(DPNID_ALL_PLAYERS_GROUP, &buffer_desc, 1, 0, NULL, &async_handle, DPNSEND_NOLOOPBACK);

        
break;
    }

    
// return S_OK to signify the message was handled OK.
    return S_OK;
}

//--------------------------------------------------------------------------------
// Create DirectPlay Server and initialize it.
//--------------------------------------------------------------------------------
BOOL Init_DirectPlay_Server()
{
    
// create DirectPlay Server component
    if(FAILED(CoCreateInstance(CLSID_DirectPlay8Server, NULL, CLSCTX_INPROC, IID_IDirectPlay8Server, 
                               (
void**)&g_dp_server)))
        
return FALSE;

    
// Assign a message handler to network component
    //
    // Registers an entry point in the client's code that receives the messages from the IDirectPlay8Client
    // interface and from the server.
    if(FAILED(g_dp_server->Initialize(NULL, Net_Msg_Handle, 0)))
        
return FALSE;

    
return TRUE;
}

//--------------------------------------------------------------------------------
// Enumerate all TCP/IP adapters.
//--------------------------------------------------------------------------------
void Enum_Adapters()
{
    
// return if no server object or GUID
    if(g_dp_server == NULL)
        
return;

    
// get a handle of the list box
    HWND adapters_ctrl = GetDlgItem(g_hwnd, IDC_ADAPTERS);

    
// clear the list box
    SendMessage(adapters_ctrl, LB_RESETCONTENT, 0, 0);

    
// free prior adapter list
    delete[] g_adapter_list;
    g_adapter_list = NULL;

    g_num_adapters = 0;

    DWORD adapter_list_size = 0;

    
// query the required size of the data buffer
    HRESULT rv = g_dp_server->EnumServiceProviders(&CLSID_DP8SP_TCPIP, NULL, g_adapter_list, &adapter_list_size, 
                                                   &g_num_adapters, 0);

    
if(rv != DPNERR_BUFFERTOOSMALL)
        
return;

    
// allocate a buffer
    if((g_adapter_list = (DPN_SERVICE_PROVIDER_INFO*) new BYTE[adapter_list_size]) == NULL)
        
return;

    
// enumerate again
    if(SUCCEEDED(g_dp_server->EnumServiceProviders(&CLSID_DP8SP_TCPIP, NULL, g_adapter_list, &adapter_list_size, 
                                                   &g_num_adapters, 0)))
    {
        
char adapter_name[1024];

        
// enumeration is complete, scan through entries.
        DPN_SERVICE_PROVIDER_INFO* adapter_ptr = g_adapter_list;

        
for(DWORD i = 0; i < g_num_adapters; i++)
        {
            
// convert wide string into multi-byte string
            wcstombs(adapter_name, adapter_ptr->pwszName, 1024);

            
// add the adapter name int listbox
            SendMessage(adapters_ctrl, CB_ADDSTRING, 0, (LPARAM)adapter_name);

            
// go to next servicec provider
            adapter_ptr++;
        }
    }

    
// Select first adapter
    //
    // An application sends a CB_SETCURSEL message to select a string in the list of a combo box. 
    // If necessary, the list scrolls the string into view. The text in the edit control of the combo box 
    // changes to reflect the new selection, and any previous selection in the list is removed. 
    //
    // wParam:
    //    Specifies the zero-based index of the string to select. If this parameter is –1, any current selection 
    //    in the list is removed and the edit control is cleared. 
    //
    // lParam:
    //    This parameter is not used. 
    SendMessage(adapters_ctrl, CB_SETCURSEL, 0, 0);    
}

//--------------------------------------------------------------------------------
// Release all resource which allocated for DirectPlay.
//--------------------------------------------------------------------------------
void Release_DirectPlay()
{
    
// release client service provider list memory
    delete[] g_adapter_list;
    g_adapter_list = NULL;
    
    g_num_adapters = 0;

    
// release client component
    if(g_dp_server != NULL)
    {
        
// Closes the open connection to a session. This method must be called on any object that is successfully 
        // initialized with a call to the IDirectPlay8Client::Initialize method.
        g_dp_server->Close(0);

        g_dp_server->Release();

        g_dp_server = NULL;
    }
}

//--------------------------------------------------------------------------------
// Start hosting a server which GUID specified by adapter_guid.
//--------------------------------------------------------------------------------
BOOL Start_Session(GUID* adapter_guid)
{
    
// Make sure there's an adapter
    if(adapter_guid == NULL)
        
return FALSE;

    
// Need to re-assign a network handler as quitting a previous session to clears it.
    // Close the connection first before assigning a new network handler.
    //
    // Closes the open connnection to a session.
    g_dp_server->Close(0);

    
// Initialize DirectPlay Server
    if(FAILED(g_dp_server->Initialize(NULL, Net_Msg_Handle, 0)))
        
return FALSE;

    IDirectPlay8Address*    dp_address;

    
// Create an address object and fill it with information
    if(FAILED(CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC, IID_IDirectPlay8Address, 
                               (
void**)&dp_address)))
        
return FALSE;

    
// Set the protocol to TCP/IP
    //
    // Sets the service provider GUID in the address object.
    // If a service provider is specified for this address, it is overwrittern by this call.
    if(FAILED(dp_address->SetSP(&CLSID_DP8SP_TCPIP)))
    {
        dp_address->Release();
        
return FALSE;
    }

    
// Set the port
    DWORD port = 21234;

    
// Adds a component to the address.
    // If the component is part of the address, it is replaced by the new value in this call.

    // Set port
    if(FAILED(dp_address->AddComponent(DPNA_KEY_PORT, &port, sizeof(DWORD), DPNA_DATATYPE_DWORD)))
    {
        dp_address->Release();
        
return FALSE;
    }

    
// Set the adapter
    if(FAILED(dp_address->AddComponent(DPNA_KEY_DEVICE, adapter_guid, sizeof(GUID), DPNA_DATATYPE_GUID)))
    {
        dp_address->Release();
        
return FALSE;
    }

    DPN_APPLICATION_DESC app_desc;  
// Describes the settings for a Microsoft DirectPlay application

    // Setup the application description structure

    ZeroMemory(&app_desc, 
sizeof(DPN_APPLICATION_DESC));

    app_desc.dwSize          = 
sizeof(DPN_APPLICATION_DESC);
    app_desc.dwFlags         = DPNSESSION_CLIENT_SERVER;
    app_desc.guidApplication = g_app_guid;
    app_desc.pwszSessionName = L"SercverSession";
    app_desc.dwMaxPlayers    = 256;

    
// Start hosting
    //
    // Creates a new client/server session, hosted by the local computer.
    if(FAILED(g_dp_server->Host(&app_desc, &dp_address, 1, NULL, NULL, NULL, 0)))
    {
        dp_address->Release();
        
return FALSE;
    }

    
// Release the address component
    dp_address->Release();

    
// Disables combo-box control.
    //
    // Enables or disables mouse and keyboard input to the specified window or control. 
    // When input is disabled, the window does not receive input such as mouse clicks and key presses. 
    // When input is enabled, the window receives all input. 
    EnableWindow(GetDlgItem(g_hwnd, IDC_ADAPTERS), FALSE);

    
// Setup the dialog information
    SetWindowText(GetDlgItem(g_hwnd, IDC_STARTSTOP), "Stop");

    g_is_hosting = TRUE;

    
return TRUE;
}

//--------------------------------------------------------------------------------
// Stoping hosting server.
//--------------------------------------------------------------------------------
void Stop_Session()
{
    
// Close the connection
    if(g_dp_server)
        g_dp_server->Close(0);

    
// Enables combo-box control
    EnableWindow(GetDlgItem(g_hwnd, IDC_ADAPTERS), TRUE);

    
// Setup the dialog information
    SetWindowText(GetDlgItem(g_hwnd, IDC_STARTSTOP), "Start");

    g_is_hosting = FALSE;
}

//--------------------------------------------------------------------------------
// Window procedure.
//--------------------------------------------------------------------------------
long WINAPI Window_Proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    unsigned 
int selected;
    
char name[256];
    DPN_SERVICE_PROVIDER_INFO*  adapter_ptr;

    
switch(msg)
    {
    
case WM_COMMAND:
        
// The WM_COMMAND message is sent when the user selects a command item from a menu, when a control sends a 
        // notification message to its parent window, or when an accelerator keystroke is translated. 
        //
        // wParam:
        //    The high-order word specifies the notification code if the message is from a control. 
        //    If the message is from an accelerator, this value is 1. If the message is from a menu, this value is zero. 
        //    The low-order word specifies the identifier of the menu item, control, or accelerator. 
        //
        // lParam:
        //     Handle to the control sending the message if the message is from a control. 
        //     Otherwise, this parameter is NULL. 
        switch(LOWORD(wParam))
        {
        
case IDC_STARTSTOP:
            
if(! g_is_hosting)
            {
                
// Get adapter to use 
                if((selected = (int) SendMessage(GetDlgItem(hwnd, IDC_ADAPTERS), CB_GETCURSEL, 0, 0)) == LB_ERR)
                    
// invalid selected item
                    break;

                
// Make sure it's valid and start session
                if(selected < g_num_adapters)
                {
                    
// pointer adapter pointer to selected position
                    adapter_ptr  = g_adapter_list;
                    adapter_ptr += selected;

                    
if(! Start_Session(&adapter_ptr->guid))
                        MessageBox(hwnd, "Unable to start server!", "Error", MB_OK | MB_ICONEXCLAMATION);
                }
            }
            
else
                Stop_Session();

            
break;

        
case IDC_DISCONNECT:
            
// Make sure we're hosting
            if(g_is_hosting)
            {
                
// Get user from list to disconnect
                selected = (int) SendMessage(GetDlgItem(hwnd, IDC_USERS), LB_GETCURSEL, 0, 0);

                
if(selected != LB_ERR)
                {
                    
// Find the player in list
                    //
                    // An application sends an LB_GETTEXT message to retrieve a string from a list box. 
                    //
                    // wParam:
                    //      Specifies the zero-based index of the string to retrieve. 
                    //
                    // lParam:
                    //      Pointer to the buffer that will receive the string; it is type LPTSTR which is subsequently 
                    //      cast to an LPARAM. The buffer must have sufficient space for the string and a terminating 
                    //      null character. An LB_GETTEXTLEN message can be sent before the LB_GETTEXT message to 
                    //      retrieve the length, in TCHARs, of the string.
                    SendMessage(GetDlgItem(hwnd, IDC_USERS), LB_GETTEXT, selected, (LPARAM)name);

                    
for(unsigned int i = 0; i < 256; i++)
                    {
                        
if(g_player_info[i].player_id != 0 && !strcmp(g_player_info[i].name, name))
                        {
                            
// Disconnect them
                            //
                            // Deletes a client from the session
                            g_dp_server->DestroyClient(g_player_info[i].player_id, NULL, 0, 0);

                            
break;
                        }
                    }
                }
            }

            
break;
        }   
// end - case WM_COMMAND:

        
break;

    
case WM_DESTROY:
        Stop_Session();
        Release_DirectPlay();
        PostQuitMessage(0);
        
break;

    
default:
        
return (long) DefWindowProc(hwnd, msg, wParam, lParam);
    }

    
return 0;
}

//--------------------------------------------------------------------------------
// Main function, routine entry.
//--------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
    WNDCLASS            win_class;
    MSG                 msg;    

    
// create window class and register it
    win_class.style         = CS_HREDRAW | CS_VREDRAW;
    win_class.lpfnWndProc   = Window_Proc;
    win_class.cbClsExtra    = 0;
    win_class.cbWndExtra    = DLGWINDOWEXTRA;
    win_class.hInstance     = inst;
    win_class.hIcon         = LoadIcon(inst, IDI_APPLICATION);
    win_class.hCursor       = LoadCursor(NULL, IDC_ARROW);
    win_class.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
    win_class.lpszMenuName  = NULL;
    win_class.lpszClassName = g_class_name;    

    
if(! RegisterClass(&win_class))
        
return FALSE;

    
// create the main window
    g_hwnd = CreateDialog(inst, MAKEINTRESOURCE(IDD_SERVER), 0, NULL);    

    
// initialize COM
    //
    // initialize the COM library on the current thread and identifies the concurrency model as single-thread
    // apartment (STA).
    CoInitialize(0);

    
// Initialzie DirectPlay and enumerate service providers.
    if(! Init_DirectPlay_Server())
    {
        MessageBox(NULL, "Error initializing DirectPlay.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
        
goto exit;
    }

    
// enumerate all TCP/IP adapters
    Enum_Adapters();

    
// Make sure there's an adapter to use
    if(g_num_adapters == 0)
    {
        MessageBox(g_hwnd, "There is no TCP/IP adapters to use!", "ERROR", MB_OK | MB_ICONEXCLAMATION);
        
goto exit;
    }

    ShowWindow(g_hwnd, cmd_show);
    UpdateWindow(g_hwnd);

    
// start message pump, waiting for signal to quit.
    ZeroMemory(&msg, sizeof(MSG));

    
while(msg.message != WM_QUIT)
    {
        
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);            
        }             
    }

exit:
    UnregisterClass(g_class_name, inst);

    
// release COM system
    //
    // Closes the COM library on the current thread, unloads all DLLs loaded by the thread, frees any other
    // resources that the thread maintains, and forces all RPC connections on the thread to close.
    CoUninitialize();
    
    
return (int) msg.wParam;
}
 

運行截圖:



posted on 2007-08-13 20:05 lovedday 閱讀(987) 評論(0)  編輯 收藏 引用

公告

導航

統計

常用鏈接

隨筆分類(178)

3D游戲編程相關鏈接

搜索

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产日韩免费| 久久久999精品免费| 欧美视频你懂的| 欧美肥婆bbw| 欧美精品日韩www.p站| 欧美激情第4页| 欧美精品久久99| 欧美日韩综合另类| 国产精品影视天天线| 国产伦精品一区二区三区| 欧美高清视频一区二区三区在线观看| 亚洲视频一二三| 午夜精品免费在线| 久久伊人亚洲| 欧美日韩亚洲一区二区三区在线观看| 国产精品久久久久久久午夜片| 国产精品视频一区二区高潮| 黄色精品一二区| 亚洲人成网站在线观看播放| 亚洲午夜一区二区| 久久岛国电影| 欧美成人日韩| 日韩一区二区久久| 香蕉成人伊视频在线观看| 美女主播精品视频一二三四| 91久久线看在观草草青青| 裸体丰满少妇做受久久99精品| 欧美激情91| 亚洲日本aⅴ片在线观看香蕉| 亚洲欧美成人网| 欧美激情综合五月色丁香小说| 国产乱理伦片在线观看夜一区| 亚洲黄色视屏| 久久精品视频99| 日韩视频专区| 久久久久久欧美| 国产精品日韩欧美| 一区二区成人精品 | 一区二区三区久久久| 久久激情综合网| 亚洲三级性片| 久久久久久久久久久一区| 国产精品成人一区二区三区吃奶| 在线免费观看日本欧美| 亚洲综合国产| 亚洲美女色禁图| 老司机成人在线视频| 国产一区二区在线观看免费| 亚洲主播在线观看| 亚洲人午夜精品免费| 欧美激情精品久久久久| 欧美国产精品日韩| 亚洲精选大片| 亚洲激情在线观看| 男人插女人欧美| 在线观看日韩av电影| 久久久久久9999| 欧美影院午夜播放| 国产一区二区精品久久| 久久精品系列| 久久精品水蜜桃av综合天堂| 国产亚洲欧美一区二区| 欧美伊人久久久久久久久影院| av不卡免费看| 国产精品va在线播放我和闺蜜| 一区二区高清| 一本久道久久综合婷婷鲸鱼| 国产精品久久国产愉拍| 亚洲综合成人婷婷小说| 亚洲私人影院| 国产深夜精品| 蜜臀av国产精品久久久久| 久久久伊人欧美| 一区二区在线观看av| 久久精品观看| 免费欧美在线视频| 一区二区三区视频观看| 亚洲深夜影院| 国产一区二区激情| 欧美第一黄色网| 欧美国产视频在线| 老司机午夜免费精品视频| 久久久久久久久久看片| 欧美一区二区视频观看视频| 在线观看国产欧美| 亚洲欧洲综合| 国产伦精品一区二区三区视频黑人 | 欧美福利电影在线观看| 欧美激情精品久久久久久蜜臀 | 欧美视频一区二区三区…| 欧美夜福利tv在线| 久久伊人一区二区| 午夜精品久久99蜜桃的功能介绍| 性欧美1819性猛交| 日韩午夜精品视频| 欧美一级淫片aaaaaaa视频| 在线看无码的免费网站| 一区二区三区国产盗摄| 黄色资源网久久资源365| 日韩视频一区二区三区在线播放免费观看 | 久久久7777| 欧美国产精品中文字幕| 欧美一区二区| 欧美精品福利| 牛牛国产精品| 国产视频久久网| 日韩午夜剧场| 亚洲福利视频网站| 午夜精品久久久久久久99水蜜桃| 亚洲欧洲精品一区二区三区波多野1战4| 日韩视频在线一区二区| 国产亚洲视频在线| 一本久道久久综合婷婷鲸鱼| 国产综合久久久久久| 亚洲欧洲一区二区三区在线观看 | 影音先锋亚洲电影| 亚洲淫性视频| 一区二区欧美在线观看| 久久久国际精品| 久久国产一二区| 国产精品欧美日韩一区| 日韩午夜激情| 99国产精品久久久| 欧美大片国产精品| 男女激情视频一区| 亚洲福利av| 免费观看久久久4p| 欧美激情精品久久久久久黑人 | 国产精品乱人伦中文| 免费看成人av| 精品91在线| 久久久久久91香蕉国产| 久久激情五月丁香伊人| 国产欧美日韩精品a在线观看| 亚洲天堂av图片| 午夜亚洲福利| 国产伦精品一区| 午夜精品美女自拍福到在线 | 亚洲精品乱码久久久久久黑人| 久久九九免费视频| 免费视频一区| 亚洲精品无人区| 欧美成人在线免费观看| 亚洲国产精品一区制服丝袜| 亚洲激情精品| 欧美日韩精品免费观看视一区二区 | 篠田优中文在线播放第一区| 欧美日韩一区二区三区免费| 91久久国产综合久久| 9i看片成人免费高清| 欧美三日本三级少妇三2023| 99精品福利视频| 先锋资源久久| 尤物九九久久国产精品的分类| 久久9热精品视频| 欧美二区乱c少妇| 一本色道久久精品| 国产精品久久久久久久久久三级 | 欧美日韩国产一区二区| 99视频一区二区| 久久激情五月激情| 亚洲福利电影| 国产精品草莓在线免费观看| 午夜精品久久久| 欧美99在线视频观看| 一本色道**综合亚洲精品蜜桃冫 | 亚洲综合视频1区| 久久综合久久美利坚合众国| 亚洲人www| 国产精品视频xxx| 久久久久天天天天| 亚洲免费av观看| 久久综合久久综合久久综合| 日韩小视频在线观看| 国产精品亚洲综合一区在线观看 | 欧美日韩亚洲高清一区二区| 亚洲欧美综合国产精品一区| 亚洲成人在线视频播放 | 国产毛片久久| 久久夜精品va视频免费观看| 99re66热这里只有精品4| 久久久精品久久久久| 在线亚洲精品| 亚洲国产精品久久人人爱蜜臀 | 99综合视频| 狠狠色伊人亚洲综合网站色| 欧美精品一区二区三区很污很色的| 亚洲欧美中文另类| 亚洲日本无吗高清不卡| 久久久久久久尹人综合网亚洲| 亚洲午夜视频在线| 亚洲高清中文字幕| 国产在线观看精品一区二区三区 | 亚洲国产天堂久久国产91| 国产精品丝袜白浆摸在线| 欧美日韩国产首页| 欧美精品亚洲二区| 欧美成人高清视频| 麻豆成人综合网| 久久青草福利网站|