1 | // $Id: dplayx_messages.cpp,v 1.3 2000-10-06 19:49:05 hugh Exp $
|
---|
2 | /* DirectPlay & DirectPlayLobby messaging implementation
|
---|
3 | *
|
---|
4 | * Copyright 2000 - Peter Hunnisett
|
---|
5 | *
|
---|
6 | * <presently under construction - contact hunnise@nortelnetworks.com>
|
---|
7 | *
|
---|
8 | */
|
---|
9 | #include <string.h>
|
---|
10 |
|
---|
11 | #include <odin.h>
|
---|
12 | #define ICOM_CINTERFACE 1
|
---|
13 | #define CINTERFACE
|
---|
14 |
|
---|
15 | #include "winbase.h"
|
---|
16 | #include "debugtools.h"
|
---|
17 |
|
---|
18 | #include "wingdi.h"
|
---|
19 | #include "winuser.h"
|
---|
20 | #include "winerror.h"
|
---|
21 |
|
---|
22 | #include "dplayx_messages.h"
|
---|
23 | #include "dplay_global.h"
|
---|
24 | #include "dplayx_global.h"
|
---|
25 |
|
---|
26 | DEFAULT_DEBUG_CHANNEL(dplay)
|
---|
27 |
|
---|
28 | #undef debugstr_guid
|
---|
29 | #define debugstr_guid(a) a
|
---|
30 |
|
---|
31 | typedef struct tagMSGTHREADINFO
|
---|
32 | {
|
---|
33 | HANDLE hStart;
|
---|
34 | HANDLE hDeath;
|
---|
35 | HANDLE hSettingRead;
|
---|
36 | HANDLE hNotifyEvent;
|
---|
37 | } MSGTHREADINFO, *LPMSGTHREADINFO;
|
---|
38 |
|
---|
39 |
|
---|
40 | static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext );
|
---|
41 |
|
---|
42 | /* Create the message reception thread to allow the application to receive
|
---|
43 | * asynchronous message reception
|
---|
44 | */
|
---|
45 | DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
|
---|
46 | HANDLE hDeath, HANDLE hConnRead )
|
---|
47 | {
|
---|
48 | DWORD dwMsgThreadId;
|
---|
49 | LPMSGTHREADINFO lpThreadInfo;
|
---|
50 |
|
---|
51 | lpThreadInfo = (LPMSGTHREADINFO) HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo ) );
|
---|
52 | if( lpThreadInfo == NULL )
|
---|
53 | {
|
---|
54 | return 0;
|
---|
55 | }
|
---|
56 |
|
---|
57 | /* The notify event may or may not exist. Depends if async comm or not */
|
---|
58 | if( hNotifyEvent &&
|
---|
59 | !DuplicateHandle( GetCurrentProcess(), hNotifyEvent,
|
---|
60 | GetCurrentProcess(), &lpThreadInfo->hNotifyEvent,
|
---|
61 | 0, FALSE, DUPLICATE_SAME_ACCESS ) )
|
---|
62 | {
|
---|
63 | ERR( "Unable to duplicate event handle\n" );
|
---|
64 | goto error;
|
---|
65 | }
|
---|
66 |
|
---|
67 | /* These 3 handles don't need to be duplicated because we don't keep a
|
---|
68 | * reference to them where they're created. They're created specifically
|
---|
69 | * for the message thread
|
---|
70 | */
|
---|
71 | lpThreadInfo->hStart = hStart;
|
---|
72 | lpThreadInfo->hDeath = hDeath;
|
---|
73 | lpThreadInfo->hSettingRead = hConnRead;
|
---|
74 |
|
---|
75 | if( !CreateThread( NULL, /* Security attribs */
|
---|
76 | 0, /* Stack */
|
---|
77 | DPL_MSG_ThreadMain, /* Msg reception function */
|
---|
78 | lpThreadInfo, /* Msg reception func parameter */
|
---|
79 | 0, /* Flags */
|
---|
80 | &dwMsgThreadId /* Updated with thread id */
|
---|
81 | )
|
---|
82 | )
|
---|
83 | {
|
---|
84 | ERR( "Unable to create msg thread\n" );
|
---|
85 | goto error;
|
---|
86 | }
|
---|
87 |
|
---|
88 | /* FIXME: Should I be closing the handle to the thread or does that
|
---|
89 | terminate the thread? */
|
---|
90 |
|
---|
91 | return dwMsgThreadId;
|
---|
92 |
|
---|
93 | error:
|
---|
94 |
|
---|
95 | HeapFree( GetProcessHeap(), 0, lpThreadInfo );
|
---|
96 |
|
---|
97 | return 0;
|
---|
98 | }
|
---|
99 |
|
---|
100 | static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext )
|
---|
101 | {
|
---|
102 | LPMSGTHREADINFO lpThreadInfo = (LPMSGTHREADINFO)lpContext;
|
---|
103 | DWORD dwWaitResult;
|
---|
104 |
|
---|
105 | TRACE( "Msg thread created. Waiting on app startup\n" );
|
---|
106 |
|
---|
107 | /* Wait to ensure that the lobby application is started w/ 1 min timeout */
|
---|
108 | dwWaitResult = WaitForSingleObject( lpThreadInfo->hStart, 10000 /* 10 sec */ );
|
---|
109 | if( dwWaitResult == WAIT_TIMEOUT )
|
---|
110 | {
|
---|
111 | FIXME( "Should signal app/wait creation failure (0x%08lx)\n", dwWaitResult );
|
---|
112 | goto end_of_thread;
|
---|
113 | }
|
---|
114 |
|
---|
115 | /* Close this handle as it's not needed anymore */
|
---|
116 | CloseHandle( lpThreadInfo->hStart );
|
---|
117 | lpThreadInfo->hStart = 0;
|
---|
118 |
|
---|
119 | /* Wait until the lobby knows what it is */
|
---|
120 | dwWaitResult = WaitForSingleObject( lpThreadInfo->hSettingRead, INFINITE );
|
---|
121 | if( dwWaitResult == WAIT_TIMEOUT )
|
---|
122 | {
|
---|
123 | ERR( "App Read connection setting timeout fail (0x%08lx)\n", dwWaitResult );
|
---|
124 | }
|
---|
125 |
|
---|
126 | /* Close this handle as it's not needed anymore */
|
---|
127 | CloseHandle( lpThreadInfo->hSettingRead );
|
---|
128 | lpThreadInfo->hSettingRead = 0;
|
---|
129 |
|
---|
130 | TRACE( "App created && intialized starting main message reception loop\n" );
|
---|
131 |
|
---|
132 | for ( ;; )
|
---|
133 | {
|
---|
134 | MSG lobbyMsg;
|
---|
135 | #ifdef STRICT
|
---|
136 | HANDLE hNullHandle = NULL;
|
---|
137 | #else
|
---|
138 | HANDLE hNullHandle = 0;
|
---|
139 | #endif
|
---|
140 |
|
---|
141 | GetMessageW( &lobbyMsg, hNullHandle, 0, 0 );
|
---|
142 | }
|
---|
143 |
|
---|
144 | end_of_thread:
|
---|
145 | TRACE( "Msg thread exiting!\n" );
|
---|
146 | HeapFree( GetProcessHeap(), 0, lpThreadInfo );
|
---|
147 |
|
---|
148 | return 0;
|
---|
149 | }
|
---|
150 |
|
---|
151 |
|
---|
152 | HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
|
---|
153 | LPDPID lpdpidAllocatedId )
|
---|
154 | {
|
---|
155 | LPVOID lpMsg;
|
---|
156 | LPDPMSG_REQUESTNEWPLAYERID lpMsgBody;
|
---|
157 | DWORD dwMsgSize;
|
---|
158 | DWORD dwWaitReturn;
|
---|
159 | HRESULT hr = DP_OK;
|
---|
160 |
|
---|
161 | dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
|
---|
162 |
|
---|
163 | lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
|
---|
164 |
|
---|
165 | lpMsgBody = (LPDPMSG_REQUESTNEWPLAYERID)( (BYTE*)lpMsg +
|
---|
166 | This->dp2->spData.dwSPHeaderSize );
|
---|
167 |
|
---|
168 | lpMsgBody->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
|
---|
169 | lpMsgBody->envelope.wCommandId = DPMSGCMD_REQUESTNEWPLAYERID;
|
---|
170 | lpMsgBody->envelope.wVersion = DPMSGVER_DP6;
|
---|
171 |
|
---|
172 | lpMsgBody->dwFlags = dwFlags;
|
---|
173 |
|
---|
174 | /* FIXME: Need to have a more advanced queuing system as this needs to
|
---|
175 | * block on send until we get response. Otherwise we need to be
|
---|
176 | * able to ensure we can pick out the exact response. Of course,
|
---|
177 | * with something as non critical as this, would it matter? The
|
---|
178 | * id has been effectively reserved for this session...
|
---|
179 | */
|
---|
180 | {
|
---|
181 | DPSP_SENDDATA data;
|
---|
182 |
|
---|
183 | data.dwFlags = DPSEND_GUARANTEED;
|
---|
184 | data.idPlayerTo = 0; /* Name server */
|
---|
185 | data.idPlayerFrom = 0; /* Sending from DP */
|
---|
186 | data.lpMessage = lpMsg;
|
---|
187 | data.dwMessageSize = dwMsgSize;
|
---|
188 | data.bSystemMessage = TRUE; /* Allow reply to be sent */
|
---|
189 | data.lpISP = This->dp2->spData.lpISP;
|
---|
190 |
|
---|
191 | /* Setup for receipt */
|
---|
192 | This->dp2->hMsgReceipt = CreateEventA( NULL, FALSE, FALSE, NULL );
|
---|
193 |
|
---|
194 | TRACE( "Sending request for player id\n" );
|
---|
195 |
|
---|
196 | hr = (*This->dp2->spData.lpCB->Send)( &data );
|
---|
197 |
|
---|
198 | if( FAILED(hr) )
|
---|
199 | {
|
---|
200 | ERR( "Request for new playerID send failed: %s\n",
|
---|
201 | DPLAYX_HresultToString( hr ) );
|
---|
202 | return DPERR_NOCONNECTION;
|
---|
203 | }
|
---|
204 | }
|
---|
205 |
|
---|
206 | dwWaitReturn = WaitForSingleObject( This->dp2->hMsgReceipt, 30000 );
|
---|
207 | if( dwWaitReturn != WAIT_OBJECT_0 )
|
---|
208 | {
|
---|
209 | ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
|
---|
210 | hr = DPERR_TIMEOUT;
|
---|
211 | }
|
---|
212 |
|
---|
213 | CloseHandle( This->dp2->hMsgReceipt );
|
---|
214 | This->dp2->hMsgReceipt = 0;
|
---|
215 |
|
---|
216 | /* Need to examine the data and extract the new player id */
|
---|
217 | if( !FAILED(hr) )
|
---|
218 | {
|
---|
219 | LPCDPMSG_NEWPLAYERIDREPLY lpcReply;
|
---|
220 |
|
---|
221 | lpcReply = (LPCDPMSG_NEWPLAYERIDREPLY)This->dp2->lpMsgReceived;
|
---|
222 |
|
---|
223 | *lpdpidAllocatedId = lpcReply->dpidNewPlayerId;
|
---|
224 |
|
---|
225 | TRACE( "Received reply for id = 0x%08lx\n", lpcReply->dpidNewPlayerId );
|
---|
226 |
|
---|
227 | /* FIXME: I think that the rest of the message has something to do
|
---|
228 | * with remote data for the player that perhaps I need to setup.
|
---|
229 | */
|
---|
230 | #if 0
|
---|
231 | /* Set the passed service provider data */
|
---|
232 | IDirectPlaySP_SetSPData( This->dp2->spData.lpISP, data,
|
---|
233 | msgsize, DPSET_REMOTE );
|
---|
234 |
|
---|
235 | #endif
|
---|
236 |
|
---|
237 | HeapFree( GetProcessHeap(), 0, This->dp2->lpMsgReceived );
|
---|
238 | This->dp2->lpMsgReceived = NULL;
|
---|
239 | }
|
---|
240 |
|
---|
241 | return hr;
|
---|
242 | }
|
---|
243 |
|
---|
244 |
|
---|
245 | /* This function seems to cause a trap in the SP. It would seem unnecessary */
|
---|
246 | /* FIXME: Remove this method if not required */
|
---|
247 | HRESULT DP_MSG_OpenStream( IDirectPlay2AImpl* This )
|
---|
248 | {
|
---|
249 | HRESULT hr;
|
---|
250 | DPSP_SENDDATA data;
|
---|
251 |
|
---|
252 | data.dwFlags = DPSEND_OPENSTREAM;
|
---|
253 | data.idPlayerTo = 0; /* Name server */
|
---|
254 | data.idPlayerFrom = 0; /* From DP itself */
|
---|
255 | data.lpMessage = NULL;
|
---|
256 | data.dwMessageSize = This->dp2->spData.dwSPHeaderSize;
|
---|
257 | data.bSystemMessage = FALSE; /* FIXME? */
|
---|
258 | data.lpISP = This->dp2->spData.lpISP;
|
---|
259 |
|
---|
260 | hr = (*This->dp2->spData.lpCB->Send)( &data );
|
---|
261 |
|
---|
262 | if( FAILED(hr) )
|
---|
263 | {
|
---|
264 | ERR( "Request for open stream send failed: %s\n",
|
---|
265 | DPLAYX_HresultToString( hr ) );
|
---|
266 | }
|
---|
267 |
|
---|
268 | /* FIXME: hack to give some time for channel to open */
|
---|
269 | SleepEx( 1000 /* 1 sec */, FALSE );
|
---|
270 |
|
---|
271 | return hr;
|
---|
272 | }
|
---|