Gives back the ERROR_FILE_NOT_FOUND to GetFileAttributes.
[wine/gsoc_dplay.git] / dlls / dplayx / dplayx_messages.c
blobcf36b6d783a59f938a0078ff34547a413682cef9
1 /* DirectPlay & DirectPlayLobby messaging implementation
3 * Copyright 2000 - Peter Hunnisett
5 * <presently under construction - contact hunnise@nortelnetworks.com>
7 */
9 #include <string.h>
10 #include "winbase.h"
11 #include "debugtools.h"
13 #include "wingdi.h"
14 #include "winuser.h"
15 #include "winerror.h"
17 #include "dplayx_messages.h"
18 #include "dplay_global.h"
19 #include "dplayx_global.h"
21 DEFAULT_DEBUG_CHANNEL(dplay);
23 typedef struct tagMSGTHREADINFO
25 HANDLE hStart;
26 HANDLE hDeath;
27 HANDLE hSettingRead;
28 HANDLE hNotifyEvent;
29 } MSGTHREADINFO, *LPMSGTHREADINFO;
31 static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext );
32 static LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA data,
33 DWORD dwWaitTime, WORD wReplyCommandId,
34 LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize );
37 /* Create the message reception thread to allow the application to receive
38 * asynchronous message reception
40 DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart,
41 HANDLE hDeath, HANDLE hConnRead )
43 DWORD dwMsgThreadId;
44 LPMSGTHREADINFO lpThreadInfo;
46 lpThreadInfo = HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo ) );
47 if( lpThreadInfo == NULL )
49 return 0;
52 /* The notify event may or may not exist. Depends if async comm or not */
53 if( hNotifyEvent &&
54 !DuplicateHandle( GetCurrentProcess(), hNotifyEvent,
55 GetCurrentProcess(), &lpThreadInfo->hNotifyEvent,
56 0, FALSE, DUPLICATE_SAME_ACCESS ) )
58 ERR( "Unable to duplicate event handle\n" );
59 goto error;
62 /* These 3 handles don't need to be duplicated because we don't keep a
63 * reference to them where they're created. They're created specifically
64 * for the message thread
66 lpThreadInfo->hStart = hStart;
67 lpThreadInfo->hDeath = hDeath;
68 lpThreadInfo->hSettingRead = hConnRead;
70 if( !CreateThread( NULL, /* Security attribs */
71 0, /* Stack */
72 DPL_MSG_ThreadMain, /* Msg reception function */
73 lpThreadInfo, /* Msg reception func parameter */
74 0, /* Flags */
75 &dwMsgThreadId /* Updated with thread id */
79 ERR( "Unable to create msg thread\n" );
80 goto error;
83 /* FIXME: Should I be closing the handle to the thread or does that
84 terminate the thread? */
86 return dwMsgThreadId;
88 error:
90 HeapFree( GetProcessHeap(), 0, lpThreadInfo );
92 return 0;
95 static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext )
97 LPMSGTHREADINFO lpThreadInfo = (LPMSGTHREADINFO)lpContext;
98 DWORD dwWaitResult;
100 TRACE( "Msg thread created. Waiting on app startup\n" );
102 /* Wait to ensure that the lobby application is started w/ 1 min timeout */
103 dwWaitResult = WaitForSingleObject( lpThreadInfo->hStart, 10000 /* 10 sec */ );
104 if( dwWaitResult == WAIT_TIMEOUT )
106 FIXME( "Should signal app/wait creation failure (0x%08lx)\n", dwWaitResult );
107 goto end_of_thread;
110 /* Close this handle as it's not needed anymore */
111 CloseHandle( lpThreadInfo->hStart );
112 lpThreadInfo->hStart = 0;
114 /* Wait until the lobby knows what it is */
115 dwWaitResult = WaitForSingleObject( lpThreadInfo->hSettingRead, INFINITE );
116 if( dwWaitResult == WAIT_TIMEOUT )
118 ERR( "App Read connection setting timeout fail (0x%08lx)\n", dwWaitResult );
121 /* Close this handle as it's not needed anymore */
122 CloseHandle( lpThreadInfo->hSettingRead );
123 lpThreadInfo->hSettingRead = 0;
125 TRACE( "App created && intialized starting main message reception loop\n" );
127 for ( ;; )
129 MSG lobbyMsg;
130 GetMessageW( &lobbyMsg, 0, 0, 0 );
133 end_of_thread:
134 TRACE( "Msg thread exiting!\n" );
135 HeapFree( GetProcessHeap(), 0, lpThreadInfo );
137 return 0;
140 /* DP messageing stuff */
141 static HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This,
142 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
143 WORD wReplyCommandId );
144 static LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
145 LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize );
148 static
149 HANDLE DP_MSG_BuildAndLinkReplyStruct( IDirectPlay2Impl* This,
150 LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList, WORD wReplyCommandId )
152 lpReplyStructList->replyExpected.hReceipt = CreateEventA( NULL, FALSE, FALSE, NULL );
153 lpReplyStructList->replyExpected.wExpectedReply = wReplyCommandId;
154 lpReplyStructList->replyExpected.lpReplyMsg = NULL;
155 lpReplyStructList->replyExpected.dwMsgBodySize = 0;
157 /* Insert into the message queue while locked */
158 EnterCriticalSection( &This->unk->DP_lock );
159 DPQ_INSERT( This->dp2->replysExpected, lpReplyStructList, replysExpected );
160 LeaveCriticalSection( &This->unk->DP_lock );
162 return lpReplyStructList->replyExpected.hReceipt;
165 static
166 LPVOID DP_MSG_CleanReplyStruct( LPDP_MSG_REPLY_STRUCT_LIST lpReplyStructList,
167 LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize )
169 CloseHandle( lpReplyStructList->replyExpected.hReceipt );
171 *lplpReplyMsg = lpReplyStructList->replyExpected.lpReplyMsg;
172 *lpdwMsgBodySize = lpReplyStructList->replyExpected.dwMsgBodySize;
174 return lpReplyStructList->replyExpected.lpReplyMsg;
177 HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
178 LPDPID lpdpidAllocatedId )
180 LPVOID lpMsg;
181 LPDPMSG_REQUESTNEWPLAYERID lpMsgBody;
182 DWORD dwMsgSize;
183 HRESULT hr = DP_OK;
185 dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
187 lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
189 lpMsgBody = (LPDPMSG_REQUESTNEWPLAYERID)( (BYTE*)lpMsg +
190 This->dp2->spData.dwSPHeaderSize );
192 /* Compose dplay message envelope */
193 lpMsgBody->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
194 lpMsgBody->envelope.wCommandId = DPMSGCMD_REQUESTNEWPLAYERID;
195 lpMsgBody->envelope.wVersion = DPMSGVER_DP6;
197 /* Compose the body of the message */
198 lpMsgBody->dwFlags = dwFlags;
200 /* Send the message */
202 DPSP_SENDDATA data;
204 data.dwFlags = DPSEND_GUARANTEED;
205 data.idPlayerTo = 0; /* Name server */
206 data.idPlayerFrom = 0; /* Sending from DP */
207 data.lpMessage = lpMsg;
208 data.dwMessageSize = dwMsgSize;
209 data.bSystemMessage = TRUE; /* Allow reply to be sent */
210 data.lpISP = This->dp2->spData.lpISP;
212 TRACE( "Asking for player id w/ dwFlags 0x%08lx\n",
213 lpMsgBody->dwFlags );
216 DP_MSG_ExpectReply( This, &data, DPMSG_DEFAULT_WAIT_TIME, DPMSGCMD_NEWPLAYERIDREPLY,
217 &lpMsg, &dwMsgSize );
220 /* Need to examine the data and extract the new player id */
221 if( !FAILED(hr) )
223 LPCDPMSG_NEWPLAYERIDREPLY lpcReply;
225 lpcReply = (LPCDPMSG_NEWPLAYERIDREPLY)lpMsg;
227 *lpdpidAllocatedId = lpcReply->dpidNewPlayerId;
229 TRACE( "Received reply for id = 0x%08lx\n", lpcReply->dpidNewPlayerId );
231 /* FIXME: I think that the rest of the message has something to do
232 * with remote data for the player that perhaps I need to setup.
233 * However, with the information that is passed, all that it could
234 * be used for is a standardized intialization value, which I'm
235 * guessing we can do without. Unless the message content is the same
236 * for several different messages?
239 HeapFree( GetProcessHeap(), 0, lpMsg );
242 return hr;
245 HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlay2AImpl* This, DPID dpidServer )
247 LPVOID lpMsg;
248 LPDPMSG_FORWARDADDPLAYER lpMsgBody;
249 DWORD dwMsgSize;
250 HRESULT hr = DP_OK;
252 dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
254 lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
256 lpMsgBody = (LPDPMSG_FORWARDADDPLAYER)( (BYTE*)lpMsg +
257 This->dp2->spData.dwSPHeaderSize );
259 /* Compose dplay message envelope */
260 lpMsgBody->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
261 lpMsgBody->envelope.wCommandId = DPMSGCMD_FORWARDADDPLAYER;
262 lpMsgBody->envelope.wVersion = DPMSGVER_DP6;
264 #if 0
266 LPBYTE lpPData;
267 DWORD dwDataSize;
269 /* SP Player remote data needs to be propagated at some point - is this the point? */
270 IDirectPlaySP_GetSPPlayerData( This->dp2->spData.lpISP, dpidServer, (LPVOID*)&lpPData, &dwDataSize, DPSET_REMOTE );
272 ERR( "Player Data size is 0x%08lx\n"
273 "[%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x]\n"
274 "[%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x]\n",
276 dwDataSize,
277 lpPData[0], lpPData[1], lpPData[2], lpPData[3], lpPData[4],
278 lpPData[5], lpPData[6], lpPData[7], lpPData[8], lpPData[9],
279 lpPData[10], lpPData[11], lpPData[12], lpPData[13], lpPData[14],
280 lpPData[15], lpPData[16], lpPData[17], lpPData[18], lpPData[19],
281 lpPData[20], lpPData[21], lpPData[22], lpPData[23], lpPData[24],
282 lpPData[25], lpPData[26], lpPData[27], lpPData[28], lpPData[29],
283 lpPData[30], lpPData[31]
285 DebugBreak();
287 #endif
289 /* Compose body of message */
290 lpMsgBody->dpidAppServer = dpidServer;
291 lpMsgBody->unknown2[0] = 0x0;
292 lpMsgBody->unknown2[1] = 0x1c;
293 lpMsgBody->unknown2[2] = 0x6c;
294 lpMsgBody->unknown2[3] = 0x50;
295 lpMsgBody->unknown2[4] = 0x9;
297 lpMsgBody->dpidAppServer2 = dpidServer;
298 lpMsgBody->unknown3[0] = 0x0;
299 lpMsgBody->unknown3[0] = 0x0;
300 lpMsgBody->unknown3[0] = 0x20;
301 lpMsgBody->unknown3[0] = 0x0;
302 lpMsgBody->unknown3[0] = 0x0;
304 lpMsgBody->dpidAppServer3 = dpidServer;
305 lpMsgBody->unknown4[0] = 0x30;
306 lpMsgBody->unknown4[1] = 0xb;
307 lpMsgBody->unknown4[2] = 0x0;
308 lpMsgBody->unknown4[3] = 0x1e090002;
309 lpMsgBody->unknown4[4] = 0x0;
310 lpMsgBody->unknown4[5] = 0x0;
311 lpMsgBody->unknown4[6] = 0x0;
312 lpMsgBody->unknown4[7] = 0x32090002;
313 lpMsgBody->unknown4[8] = 0x0;
314 lpMsgBody->unknown4[9] = 0x0;
315 lpMsgBody->unknown4[10] = 0x0;
316 lpMsgBody->unknown4[11] = 0x0;
317 lpMsgBody->unknown4[12] = 0x0;
319 lpMsgBody->unknown5[0] = 0x0;
320 lpMsgBody->unknown5[1] = 0x0;
322 /* Send the message */
324 DPSP_SENDDATA data;
326 data.dwFlags = DPSEND_GUARANTEED;
327 data.idPlayerTo = 0; /* Name server */
328 data.idPlayerFrom = dpidServer; /* Sending from session server */
329 data.lpMessage = lpMsg;
330 data.dwMessageSize = dwMsgSize;
331 data.bSystemMessage = TRUE; /* Allow reply to be sent */
332 data.lpISP = This->dp2->spData.lpISP;
334 lpMsg = DP_MSG_ExpectReply( This, &data,
335 DPMSG_WAIT_60_SECS,
336 DPMSGCMD_GETNAMETABLEREPLY,
337 &lpMsg, &dwMsgSize );
340 /* Need to examine the data and extract the new player id */
341 if( lpMsg != NULL )
343 FIXME( "Name Table reply received: stub\n" );
346 return hr;
349 /* Queue up a structure indicating that we want a reply of type wReplyCommandId. DPlay does
350 * not seem to offer any way of uniquely differentiating between replies of the same type
351 * relative to the request sent. There is an implicit assumption that there will be no
352 * ordering issues on sends and receives from the opposite machine. No wonder MS is not
353 * a networking company.
355 static
356 LPVOID DP_MSG_ExpectReply( IDirectPlay2AImpl* This, LPDPSP_SENDDATA lpData,
357 DWORD dwWaitTime, WORD wReplyCommandId,
358 LPVOID* lplpReplyMsg, LPDWORD lpdwMsgBodySize )
360 HRESULT hr;
361 HANDLE hMsgReceipt;
362 DP_MSG_REPLY_STRUCT_LIST replyStructList;
363 DWORD dwWaitReturn;
365 /* Setup for receipt */
366 hMsgReceipt = DP_MSG_BuildAndLinkReplyStruct( This, &replyStructList,
367 wReplyCommandId );
369 TRACE( "Sending msg and expecting cmd %u in reply within %lu ticks\n",
370 wReplyCommandId, dwWaitTime );
371 hr = (*This->dp2->spData.lpCB->Send)( lpData );
373 if( FAILED(hr) )
375 ERR( "Request for new playerID send failed: %s\n",
376 DPLAYX_HresultToString( hr ) );
377 return NULL;
380 dwWaitReturn = WaitForSingleObject( hMsgReceipt, dwWaitTime );
381 if( dwWaitReturn != WAIT_OBJECT_0 )
383 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
384 return NULL;
387 /* Clean Up */
388 return DP_MSG_CleanReplyStruct( &replyStructList, lplpReplyMsg, lpdwMsgBodySize );
391 /* Determine if there is a matching request for this incomming message and then copy
392 * all important data. It is quite silly to have to copy the message, but the documents
393 * indicate that a copy is taken. Silly really.
395 void DP_MSG_ReplyReceived( IDirectPlay2AImpl* This, WORD wCommandId,
396 LPCVOID lpcMsgBody, DWORD dwMsgBodySize )
398 LPDP_MSG_REPLY_STRUCT_LIST lpReplyList;
400 #if 0
401 if( wCommandId == DPMSGCMD_FORWARDADDPLAYER )
403 DebugBreak();
405 #endif
407 /* Find, and immediately remove (to avoid double triggering), the appropriate entry. Call locked to
408 * avoid problems.
410 EnterCriticalSection( &This->unk->DP_lock );
411 DPQ_REMOVE_ENTRY( This->dp2->replysExpected, replysExpected, replyExpected.wExpectedReply,\
412 ==, wCommandId, lpReplyList );
413 LeaveCriticalSection( &This->unk->DP_lock );
415 if( lpReplyList != NULL )
417 lpReplyList->replyExpected.dwMsgBodySize = dwMsgBodySize;
418 lpReplyList->replyExpected.lpReplyMsg = HeapAlloc( GetProcessHeap(),
419 HEAP_ZERO_MEMORY,
420 dwMsgBodySize );
421 CopyMemory( lpReplyList->replyExpected.lpReplyMsg,
422 lpcMsgBody, dwMsgBodySize );
424 /* Signal the thread which sent the message that it has a reply */
425 SetEvent( lpReplyList->replyExpected.hReceipt );
427 else
429 ERR( "No receipt event set - only expecting in reply mode\n" );
430 DebugBreak();
435 void DP_MSG_ErrorReceived( IDirectPlay2AImpl* This, WORD wCommandId,
436 LPCVOID lpMsgBody, DWORD dwMsgBodySize )
438 LPCDPMSG_FORWARDADDPLAYERNACK lpcErrorMsg;
440 lpcErrorMsg = (LPCDPMSG_FORWARDADDPLAYERNACK)lpMsgBody;
442 ERR( "Received error message %u. Error is %s\n",
443 wCommandId, DPLAYX_HresultToString( lpcErrorMsg->errorCode) );
444 DebugBreak();