📄 dplayx_messages.c
字号:
/* DirectPlay & DirectPlayLobby messaging implementation
*
* Copyright 2000,2001 - Peter Hunnisett
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* NOTES
* o Messaging interface required for both DirectPlay and DirectPlayLobby.
*/
#include <stdarg.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winerror.h"
#include "dplayx_messages.h"
#include "dplay_global.h"
#include "dplayx_global.h"
#include "name_server.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dplay);
typedef struct tagMSGTHREADINFO
{
HANDLE hStart;
HANDLE hDeath;
HANDLE hSettingRead;
HANDLE hNotifyEvent;
} MSGTHREADINFO, *LPMSGTHREADINFO;
static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext );
static LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA data,
DWORD dwWaitTime, WORD wReplyCommandId,
LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize );
/* Create the message reception thread to allow the application to receive
* asynchronous message reception
*/
DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
HANDLE hDeath, HANDLE hConnRead )
{
DWORD dwMsgThreadId;
LPMSGTHREADINFO lpThreadInfo;
lpThreadInfo = HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo ) );
if( lpThreadInfo == NULL )
{
return 0;
}
/* The notify event may or may not exist. Depends if async comm or not */
if( hNotifyEvent &&
!DuplicateHandle( GetCurrentProcess(), hNotifyEvent,
GetCurrentProcess(), &lpThreadInfo->hNotifyEvent,
0, FALSE, DUPLICATE_SAME_ACCESS ) )
{
ERR( "Unable to duplicate event handle\n" );
goto error;
}
/* These 3 handles don't need to be duplicated because we don't keep a
* reference to them where they're created. They're created specifically
* for the message thread
*/
lpThreadInfo->hStart = hStart;
lpThreadInfo->hDeath = hDeath;
lpThreadInfo->hSettingRead = hConnRead;
if( !CreateThread( NULL, /* Security attribs */
0, /* Stack */
DPL_MSG_ThreadMain, /* Msg reception function */
lpThreadInfo, /* Msg reception func parameter */
0, /* Flags */
&dwMsgThreadId /* Updated with thread id */
)
)
{
ERR( "Unable to create msg thread\n" );
goto error;
}
/* FIXME: Should I be closing the handle to the thread or does that
terminate the thread? */
return dwMsgThreadId;
error:
HeapFree( GetProcessHeap(), 0, lpThreadInfo );
return 0;
}
static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext )
{
LPMSGTHREADINFO lpThreadInfo = (LPMSGTHREADINFO)lpContext;
DWORD dwWaitResult;
TRACE( "Msg thread created. Waiting on app startup\n" );
/* Wait to ensure that the lobby application is started w/ 1 min timeout */
dwWaitResult = WaitForSingleObject( lpThreadInfo->hStart, 10000 /* 10 sec */ );
if( dwWaitResult == WAIT_TIMEOUT )
{
FIXME( "Should signal app/wait creation failure (0x%08lx)\n", dwWaitResult );
goto end_of_thread;
}
/* Close this handle as it's not needed anymore */
CloseHandle( lpThreadInfo->hStart );
lpThreadInfo->hStart = 0;
/* Wait until the lobby knows what it is */
dwWaitResult = WaitForSingleObject( lpThreadInfo->hSettingRead, INFINITE );
if( dwWaitResult == WAIT_TIMEOUT )
{
ERR( "App Read connection setting timeout fail (0x%08lx)\n", dwWaitResult );
}
/* Close this handle as it's not needed anymore */
CloseHandle( lpThreadInfo->hSettingRead );
lpThreadInfo->hSettingRead = 0;
TRACE( "App created && intialized starting main message reception loop\n" );
for ( ;; )
{
MSG lobbyMsg;
GetMessageW( &lobbyMsg, 0, 0, 0 );
}
end_of_thread:
TRACE( "Msg thread exiting!\n" );
HeapFree( GetProcessHeap(), 0, lpThreadInfo );
return 0;
}
/* DP messageing stuff */
static HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This,
LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
WORD wReplyCommandId );
static LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize );
static
HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This,
LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, WORD wReplyCommandId )
{
lpReplyStructList->replyExpected.hReceipt = CreateEventW( NULL, FALSE, FALSE, NULL );
lpReplyStructList->replyExpected.wExpectedReply = wReplyCommandId;
lpReplyStructList->replyExpected.lpReplyMsg = NULL;
lpReplyStructList->replyExpected.dwMsgBodySize = 0;
/* Insert into the message queue while locked */
EnterCriticalSection( &This->unk->DP_lock );
DPQ_INSERT( This->dp2->replysExpected, lpReplyStructList, replysExpected );
LeaveCriticalSection( &This->unk->DP_lock );
return lpReplyStructList->replyExpected.hReceipt;
}
static
LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize )
{
CloseHandle( lpReplyStructList->replyExpected.hReceipt );
*lplpReplyMsg = lpReplyStructList->replyExpected.lpReplyMsg;
*lpdwMsgBodySize = lpReplyStructList->replyExpected.dwMsgBodySize;
return lpReplyStructList->replyExpected.lpReplyMsg;
}
HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
LPDPID lpdpidAllocatedId )
{
LPVOID lpMsg;
LPDPMSG_REQUESTNEWPLAYERID lpMsgBody;
DWORD dwMsgSize;
HRESULT hr = DP_OK;
dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
lpMsgBody = (LPDPMSG_REQUESTNEWPLAYERID)( (BYTE*)lpMsg +
This->dp2->spData.dwSPHeaderSize );
/* Compose dplay message envelope */
lpMsgBody->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
lpMsgBody->envelope.wCommandId = DPMSGCMD_REQUESTNEWPLAYERID;
lpMsgBody->envelope.wVersion = DPMSGVER_DP6;
/* Compose the body of the message */
lpMsgBody->dwFlags = dwFlags;
/* Send the message */
{
DPSP_SENDDATA data;
data.dwFlags = DPSEND_GUARANTEED;
data.idPlayerTo = 0; /* Name server */
data.idPlayerFrom = 0; /* Sending from DP */
data.lpMessage = lpMsg;
data.dwMessageSize = dwMsgSize;
data.bSystemMessage = TRUE; /* Allow reply to be sent */
data.lpISP = This->dp2->spData.lpISP;
TRACE( "Asking for player id w/ dwFlags 0x%08lx\n",
lpMsgBody->dwFlags );
DP_MSG_ExpectReply( This, &data, DPMSG_DEFAULT_WAIT_TIME, DPMSGCMD_NEWPLAYERIDREPLY,
&lpMsg, &dwMsgSize );
}
/* Need to examine the data and extract the new player id */
if( !FAILED(hr) )
{
LPCDPMSG_NEWPLAYERIDREPLY lpcReply;
lpcReply = (LPCDPMSG_NEWPLAYERIDREPLY)lpMsg;
*lpdpidAllocatedId = lpcReply->dpidNewPlayerId;
TRACE( "Received reply for id = 0x%08lx\n", lpcReply->dpidNewPlayerId );
/* FIXME: I think that the rest of the message has something to do
* with remote data for the player that perhaps I need to setup.
* However, with the information that is passed, all that it could
* be used for is a standardized intialization value, which I'm
* guessing we can do without. Unless the message content is the same
* for several different messages?
*/
HeapFree( GetProcessHeap(), 0, lpMsg );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -