1 /* Direct Play 2,3,4 Implementation
2 *
3 * Copyright 1998,1999,2000,2001 - Peter Hunnisett
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include "config.h"
21 #include "wine/port.h"
22
23 #include <stdarg.h>
24 #include <string.h>
25
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28 #include "windef.h"
29 #include "winerror.h"
30 #include "winbase.h"
31 #include "winnt.h"
32 #include "winreg.h"
33 #include "winnls.h"
34 #include "wine/unicode.h"
35 #include "wine/debug.h"
36
37 #include "dpinit.h"
38 #include "dplayx_global.h"
39 #include "name_server.h"
40 #include "dplayx_queue.h"
41 #include "dplaysp.h"
42 #include "dplay_global.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
45
46 /* FIXME: Should this be externed? */
47 extern HRESULT DPL_CreateCompoundAddress
48 ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
49 LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
50
51
52 /* Local function prototypes */
53 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid );
54 static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid,
55 LPDPNAME lpName, DWORD dwFlags,
56 HANDLE hEvent, BOOL bAnsi );
57 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi );
58 static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
59 LPVOID lpData, DWORD dwDataSize );
60
61 static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, const DPID *lpid,
62 const DPNAME *lpName, DWORD dwFlags,
63 DPID idParent, BOOL bAnsi );
64 static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
65 LPVOID lpData, DWORD dwDataSize );
66 static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
67 static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid );
68 static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
69 DWORD dwPlayerType,
70 LPCDPNAME lpName,
71 DWORD dwFlags,
72 LPVOID lpContext );
73 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
74 static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType,
75 LPCDPNAME lpName, DWORD dwFlags,
76 LPVOID lpContext );
77 static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
78
79 /* Forward declarations of virtual tables */
80 static const IDirectPlay2Vtbl directPlay2AVT;
81 static const IDirectPlay3Vtbl directPlay3AVT;
82 static const IDirectPlay4Vtbl directPlay4AVT;
83
84 static const IDirectPlay2Vtbl directPlay2WVT;
85 static const IDirectPlay3Vtbl directPlay3WVT;
86 static const IDirectPlay4Vtbl directPlay4WVT;
87
88 /* Helper methods for player/group interfaces */
89 static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
90 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
91 DPID idPlayer, BOOL bAnsi );
92 static HRESULT WINAPI DP_IF_CreatePlayer
93 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, LPDPID lpidPlayer,
94 LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData,
95 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
96 static HRESULT WINAPI DP_IF_DestroyGroup
97 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi );
98 static HRESULT WINAPI DP_IF_DestroyPlayer
99 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi );
100 static HRESULT WINAPI DP_IF_EnumGroupPlayers
101 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
102 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
103 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
104 static HRESULT WINAPI DP_IF_EnumGroups
105 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
106 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
107 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
108 static HRESULT WINAPI DP_IF_EnumPlayers
109 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
110 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
111 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
112 static HRESULT WINAPI DP_IF_GetGroupData
113 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
114 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
115 static HRESULT WINAPI DP_IF_GetGroupName
116 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
117 LPDWORD lpdwDataSize, BOOL bAnsi );
118 static HRESULT WINAPI DP_IF_GetPlayerData
119 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
120 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
121 static HRESULT WINAPI DP_IF_GetPlayerName
122 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
123 LPDWORD lpdwDataSize, BOOL bAnsi );
124 static HRESULT WINAPI DP_IF_SetGroupName
125 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
126 DWORD dwFlags, BOOL bAnsi );
127 static HRESULT WINAPI DP_IF_SetPlayerData
128 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
129 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
130 static HRESULT WINAPI DP_IF_SetPlayerName
131 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
132 DWORD dwFlags, BOOL bAnsi );
133 static HRESULT WINAPI DP_IF_AddGroupToGroup
134 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
135 static HRESULT WINAPI DP_IF_CreateGroup
136 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
137 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
138 DWORD dwFlags, BOOL bAnsi );
139 static HRESULT WINAPI DP_IF_CreateGroupInGroup
140 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
141 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
142 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
143 static HRESULT WINAPI DP_IF_AddPlayerToGroup
144 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
145 DPID idPlayer, BOOL bAnsi );
146 static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
147 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
148 static HRESULT WINAPI DP_SetSessionDesc
149 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
150 DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
151 static HRESULT WINAPI DP_SecureOpen
152 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
153 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
154 BOOL bAnsi );
155 static HRESULT WINAPI DP_SendEx
156 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
157 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
158 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi );
159 static HRESULT WINAPI DP_IF_Receive
160 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
161 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
162 static HRESULT WINAPI DP_IF_GetMessageQueue
163 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
164 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
165 static HRESULT WINAPI DP_SP_SendEx
166 ( IDirectPlay2Impl* This, DWORD dwFlags,
167 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
168 LPVOID lpContext, LPDWORD lpdwMsgID );
169 static HRESULT WINAPI DP_IF_SetGroupData
170 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
171 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
172 static HRESULT WINAPI DP_IF_GetPlayerCaps
173 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
174 DWORD dwFlags );
175 static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi );
176 static HRESULT WINAPI DP_IF_CancelMessage
177 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
178 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
179 static HRESULT WINAPI DP_IF_EnumGroupsInGroup
180 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
181 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
182 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
183 static HRESULT WINAPI DP_IF_GetGroupParent
184 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
185 BOOL bAnsi );
186 static HRESULT WINAPI DP_IF_GetCaps
187 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
188 static HRESULT WINAPI DP_IF_EnumSessions
189 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
190 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
191 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
192 static HRESULT WINAPI DP_IF_InitializeConnection
193 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi );
194 static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
195 LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
196 DWORD dwFlags, LPVOID lpContext );
197 static BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
198 LPDWORD lpdwBufSize );
199
200
201
202 static inline DPID DP_NextObjectId(void);
203 static DPID DP_GetRemoteNextObjectId(void);
204
205
206 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
207 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
208
209
210 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
211 static HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
212 static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
213
214
215
216
217
218
219 #define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
220 #define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
221 we don't have to change much */
222 #define DPID_NAME_SERVER 0x19a9d65b /* Don't ask me why */
223
224 /* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
225 #define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )
226
227 /* Strip out all dwFlags values for CREATEPLAYER msg */
228 #define DPMSG_CREATEPLAYER_DWFLAGS(x) 0
229
230 static LONG kludgePlayerGroupId = 1000;
231
232 /* ------------------------------------------------------------------ */
233
234
235 static BOOL DP_CreateIUnknown( LPVOID lpDP )
236 {
237 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
238
239 This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) );
240 if ( This->unk == NULL )
241 {
242 return FALSE;
243 }
244
245 InitializeCriticalSection( &This->unk->DP_lock );
246 This->unk->DP_lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlay2AImpl*->DirectPlayIUnknownData*->DP_lock");
247
248 return TRUE;
249 }
250
251 static BOOL DP_DestroyIUnknown( LPVOID lpDP )
252 {
253 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
254
255 This->unk->DP_lock.DebugInfo->Spare[0] = 0;
256 DeleteCriticalSection( &This->unk->DP_lock );
257 HeapFree( GetProcessHeap(), 0, This->unk );
258
259 return TRUE;
260 }
261
262 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
263 {
264 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
265
266 This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
267 if ( This->dp2 == NULL )
268 {
269 return FALSE;
270 }
271
272 This->dp2->bConnectionOpen = FALSE;
273
274 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
275 This->dp2->dwEnumSessionLock = 0;
276
277 This->dp2->bHostInterface = FALSE;
278
279 DPQ_INIT(This->dp2->receiveMsgs);
280 DPQ_INIT(This->dp2->sendMsgs);
281 DPQ_INIT(This->dp2->replysExpected);
282
283 if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
284 {
285 /* FIXME: Memory leak */
286 return FALSE;
287 }
288
289 /* Provide an initial session desc with nothing in it */
290 This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
291 HEAP_ZERO_MEMORY,
292 sizeof( *This->dp2->lpSessionDesc ) );
293 if( This->dp2->lpSessionDesc == NULL )
294 {
295 /* FIXME: Memory leak */
296 return FALSE;
297 }
298 This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
299
300 /* We are emulating a dp 6 implementation */
301 This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
302
303 This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
304 sizeof( *This->dp2->spData.lpCB ) );
305 This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
306 This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
307
308 /* This is the pointer to the service provider */
309 if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
310 (LPVOID*)&This->dp2->spData.lpISP, This ) )
311 )
312 {
313 /* FIXME: Memory leak */
314 return FALSE;
315 }
316
317 /* Setup lobby provider information */
318 This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
319 This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
320 sizeof( *This->dp2->dplspData.lpCB ) );
321 This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB );
322
323 if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
324 (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
325 )
326 {
327 /* FIXME: Memory leak */
328 return FALSE;
329 }
330
331 return TRUE;
332 }
333
334 /* Definition of the global function in dplayx_queue.h. #
335 * FIXME: Would it be better to have a dplayx_queue.c for this function? */
336 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
337 {
338 HeapFree( GetProcessHeap(), 0, elem );
339 }
340
341 /* Function to delete the list of groups with this interface. Needs to
342 * delete the group and player lists associated with this group as well
343 * as the group data associated with this group. It should not delete
344 * player data as that is shared with the top player list and will be
345 * deleted with that.
346 */
347 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList );
348 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList )
349 {
350 DPQ_DELETEQ( elem->lpGData->groups, groups,
351 lpGroupList, cbDeleteElemFromHeap );
352 DPQ_DELETEQ( elem->lpGData->players, players,
353 lpPlayerList, cbDeleteElemFromHeap );
354 HeapFree( GetProcessHeap(), 0, elem->lpGData );
355 HeapFree( GetProcessHeap(), 0, elem );
356 }
357
358 /* Function to delete the list of players with this interface. Needs to
359 * delete the player data for all players as well.
360 */
361 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList );
362 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList )
363 {
364 HeapFree( GetProcessHeap(), 0, elem->lpPData );
365 HeapFree( GetProcessHeap(), 0, elem );
366 }
367
368 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
369 {
370 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
371
372 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
373 {
374 TerminateThread( This->dp2->hEnumSessionThread, 0 );
375 CloseHandle( This->dp2->hEnumSessionThread );
376 }
377
378 /* Finish with the SP - have it shutdown */
379 if( This->dp2->spData.lpCB->ShutdownEx )
380 {
381 DPSP_SHUTDOWNDATA data;
382
383 TRACE( "Calling SP ShutdownEx\n" );
384
385 data.lpISP = This->dp2->spData.lpISP;
386
387 (*This->dp2->spData.lpCB->ShutdownEx)( &data );
388 }
389 else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
390 {
391 TRACE( "Calling obsolete SP Shutdown\n" );
392 (*This->dp2->spData.lpCB->Shutdown)();
393 }
394
395 /* Unload the SP (if it exists) */
396 if( This->dp2->hServiceProvider != 0 )
397 {
398 FreeLibrary( This->dp2->hServiceProvider );
399 }
400
401 /* Unload the Lobby Provider (if it exists) */
402 if( This->dp2->hDPLobbyProvider != 0 )
403 {
404 FreeLibrary( This->dp2->hDPLobbyProvider );
405 }
406
407 #if 0
408 DPQ_DELETEQ( This->dp2->players, players, lpPlayerList, cbDeletePlayerElem );
409 DPQ_DELETEQ( This->dp2->groups, groups, lpGroupList, cbDeleteGroupsElem );
410 #endif
411
412 /* FIXME: Need to delete receive and send msgs queue contents */
413
414 NS_DeleteSessionCache( This->dp2->lpNameServerData );
415
416 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
417
418 IDirectPlaySP_Release( This->dp2->spData.lpISP );
419
420 /* Delete the contents */
421 HeapFree( GetProcessHeap(), 0, This->dp2 );
422
423 return TRUE;
424 }
425
426 static BOOL DP_CreateDirectPlay3( LPVOID lpDP )
427 {
428 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
429
430 This->dp3 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp3) ) );
431 if ( This->dp3 == NULL )
432 {
433 return FALSE;
434 }
435
436 return TRUE;
437 }
438
439 static BOOL DP_DestroyDirectPlay3( LPVOID lpDP )
440 {
441 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
442
443 /* Delete the contents */
444 HeapFree( GetProcessHeap(), 0, This->dp3 );
445
446 return TRUE;
447 }
448
449 static BOOL DP_CreateDirectPlay4( LPVOID lpDP )
450 {
451 IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)lpDP;
452
453 This->dp4 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp4) ) );
454 if ( This->dp4 == NULL )
455 {
456 return FALSE;
457 }
458
459 return TRUE;
460 }
461
462 static BOOL DP_DestroyDirectPlay4( LPVOID lpDP )
463 {
464 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
465
466 /* Delete the contents */
467 HeapFree( GetProcessHeap(), 0, This->dp4 );
468
469 return TRUE;
470 }
471
472
473 /* Create a new interface */
474 HRESULT DP_CreateInterface
475 ( REFIID riid, LPVOID* ppvObj )
476 {
477 TRACE( " for %s\n", debugstr_guid( riid ) );
478
479 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
480 sizeof( IDirectPlay2Impl ) );
481
482 if( *ppvObj == NULL )
483 {
484 return DPERR_OUTOFMEMORY;
485 }
486
487 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
488 {
489 IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj;
490 This->lpVtbl = &directPlay2WVT;
491 }
492 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
493 {
494 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj;
495 This->lpVtbl = &directPlay2AVT;
496 }
497 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
498 {
499 IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj;
500 This->lpVtbl = &directPlay3WVT;
501 }
502 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
503 {
504 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj;
505 This->lpVtbl = &directPlay3AVT;
506 }
507 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
508 {
509 IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj;
510 This->lpVtbl = &directPlay4WVT;
511 }
512 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
513 {
514 IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj;
515 This->lpVtbl = &directPlay4AVT;
516 }
517 else
518 {
519 /* Unsupported interface */
520 HeapFree( GetProcessHeap(), 0, *ppvObj );
521 *ppvObj = NULL;
522
523 return E_NOINTERFACE;
524 }
525
526 /* Initialize it */
527 if ( DP_CreateIUnknown( *ppvObj ) &&
528 DP_CreateDirectPlay2( *ppvObj ) &&
529 DP_CreateDirectPlay3( *ppvObj ) &&
530 DP_CreateDirectPlay4( *ppvObj )
531 )
532 {
533 IDirectPlayX_AddRef( (LPDIRECTPLAY2A)*ppvObj );
534
535 return S_OK;
536 }
537
538 /* Initialize failed, destroy it */
539 DP_DestroyDirectPlay4( *ppvObj );
540 DP_DestroyDirectPlay3( *ppvObj );
541 DP_DestroyDirectPlay2( *ppvObj );
542 DP_DestroyIUnknown( *ppvObj );
543
544 HeapFree( GetProcessHeap(), 0, *ppvObj );
545
546 *ppvObj = NULL;
547 return DPERR_NOMEMORY;
548 }
549
550
551 /* Direct Play methods */
552
553 /* Shared between all dplay types */
554 static HRESULT WINAPI DP_QueryInterface
555 ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj )
556 {
557 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
558 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
559
560 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
561 sizeof( *This ) );
562
563 if( *ppvObj == NULL )
564 {
565 return DPERR_OUTOFMEMORY;
566 }
567
568 CopyMemory( *ppvObj, This, sizeof( *This ) );
569 (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
570
571 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
572 {
573 IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj;
574 This->lpVtbl = &directPlay2WVT;
575 }
576 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
577 {
578 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj;
579 This->lpVtbl = &directPlay2AVT;
580 }
581 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
582 {
583 IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj;
584 This->lpVtbl = &directPlay3WVT;
585 }
586 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
587 {
588 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj;
589 This->lpVtbl = &directPlay3AVT;
590 }
591 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
592 {
593 IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj;
594 This->lpVtbl = &directPlay4WVT;
595 }
596 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
597 {
598 IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj;
599 This->lpVtbl = &directPlay4AVT;
600 }
601 else
602 {
603 /* Unsupported interface */
604 HeapFree( GetProcessHeap(), 0, *ppvObj );
605 *ppvObj = NULL;
606
607 return E_NOINTERFACE;
608 }
609
610 IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj );
611
612 return S_OK;
613 }
614
615 /* Shared between all dplay types */
616 static ULONG WINAPI DP_AddRef
617 ( LPDIRECTPLAY3 iface )
618 {
619 ULONG ulInterfaceRefCount, ulObjRefCount;
620 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
621
622 ulObjRefCount = InterlockedIncrement( &This->unk->ulObjRef );
623 ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
624
625 TRACE( "ref count incremented to %u:%u for %p\n",
626 ulInterfaceRefCount, ulObjRefCount, This );
627
628 return ulObjRefCount;
629 }
630
631 static ULONG WINAPI DP_Release
632 ( LPDIRECTPLAY3 iface )
633 {
634 ULONG ulInterfaceRefCount, ulObjRefCount;
635
636 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
637
638 ulObjRefCount = InterlockedDecrement( &This->unk->ulObjRef );
639 ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
640
641 TRACE( "ref count decremented to %u:%u for %p\n",
642 ulInterfaceRefCount, ulObjRefCount, This );
643
644 /* Deallocate if this is the last reference to the object */
645 if( ulObjRefCount == 0 )
646 {
647 /* If we're destroying the object, this must be the last ref
648 of the last interface */
649 DP_DestroyDirectPlay4( This );
650 DP_DestroyDirectPlay3( This );
651 DP_DestroyDirectPlay2( This );
652 DP_DestroyIUnknown( This );
653 }
654
655 /* Deallocate the interface */
656 if( ulInterfaceRefCount == 0 )
657 {
658 HeapFree( GetProcessHeap(), 0, This );
659 }
660
661 return ulObjRefCount;
662 }
663
664 static inline DPID DP_NextObjectId(void)
665 {
666 return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
667 }
668
669 /* *lplpReply will be non NULL iff there is something to reply */
670 HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
671 DWORD dwMessageBodySize, LPCVOID lpcMessageHeader,
672 WORD wCommandId, WORD wVersion,
673 LPVOID* lplpReply, LPDWORD lpdwMsgSize )
674 {
675 TRACE( "(%p)->(%p,0x%08x,%p,%u,%u)\n",
676 This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
677 wVersion );
678
679 switch( wCommandId )
680 {
681 /* Name server needs to handle this request */
682 case DPMSGCMD_ENUMSESSIONSREQUEST:
683 {
684 /* Reply expected */
685 NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
686
687 break;
688 }
689
690 /* Name server needs to handle this request */
691 case DPMSGCMD_ENUMSESSIONSREPLY:
692 {
693 /* No reply expected */
694 NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
695 This->dp2->spData.dwSPHeaderSize,
696 lpcMessageBody,
697 This->dp2->lpNameServerData );
698 break;
699 }
700
701 case DPMSGCMD_REQUESTNEWPLAYERID:
702 {
703 LPCDPMSG_REQUESTNEWPLAYERID lpcMsg =
704 (LPCDPMSG_REQUESTNEWPLAYERID)lpcMessageBody;
705
706 LPDPMSG_NEWPLAYERIDREPLY lpReply;
707
708 *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
709
710 *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
711
712 FIXME( "Ignoring dwFlags 0x%08x in request msg\n",
713 lpcMsg->dwFlags );
714
715 /* Setup the reply */
716 lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
717 This->dp2->spData.dwSPHeaderSize );
718
719 lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
720 lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
721 lpReply->envelope.wVersion = DPMSGVER_DP6;
722
723 lpReply->dpidNewPlayerId = DP_NextObjectId();
724
725 TRACE( "Allocating new playerid 0x%08x from remote request\n",
726 lpReply->dpidNewPlayerId );
727
728 break;
729 }
730
731 case DPMSGCMD_GETNAMETABLEREPLY:
732 case DPMSGCMD_NEWPLAYERIDREPLY:
733 {
734
735 #if 0
736 if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
737 DebugBreak();
738 #endif
739 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
740
741 break;
742 }
743
744 #if 1
745 case DPMSGCMD_JUSTENVELOPE:
746 {
747 TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08x\n", lpcMessageHeader, ((const DWORD *)lpcMessageHeader)[1] );
748 NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
749 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
750 }
751 #endif
752
753 case DPMSGCMD_FORWARDADDPLAYER:
754 {
755 #if 0
756 DebugBreak();
757 #endif
758 #if 1
759 TRACE( "Sending message to self to get my addr\n" );
760 DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
761 #endif
762 break;
763 }
764
765 case DPMSGCMD_FORWARDADDPLAYERNACK:
766 {
767 DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
768 break;
769 }
770
771 default:
772 {
773 FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
774 DebugBreak();
775 break;
776 }
777 }
778
779 /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
780
781 return DP_OK;
782 }
783
784
785 static HRESULT WINAPI DP_IF_AddPlayerToGroup
786 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
787 DPID idPlayer, BOOL bAnsi )
788 {
789 lpGroupData lpGData;
790 lpPlayerList lpPList;
791 lpPlayerList lpNewPList;
792
793 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
794 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
795
796 /* Find the group */
797 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
798 {
799 return DPERR_INVALIDGROUP;
800 }
801
802 /* Find the player */
803 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
804 {
805 return DPERR_INVALIDPLAYER;
806 }
807
808 /* Create a player list (ie "shortcut" ) */
809 lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
810 if( lpNewPList == NULL )
811 {
812 return DPERR_CANTADDPLAYER;
813 }
814
815 /* Add the shortcut */
816 lpPList->lpPData->uRef++;
817 lpNewPList->lpPData = lpPList->lpPData;
818
819 /* Add the player to the list of players for this group */
820 DPQ_INSERT(lpGData->players,lpNewPList,players);
821
822 /* Let the SP know that we've added a player to the group */
823 if( This->dp2->spData.lpCB->AddPlayerToGroup )
824 {
825 DPSP_ADDPLAYERTOGROUPDATA data;
826
827 TRACE( "Calling SP AddPlayerToGroup\n" );
828
829 data.idPlayer = idPlayer;
830 data.idGroup = idGroup;
831 data.lpISP = This->dp2->spData.lpISP;
832
833 (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
834 }
835
836 /* Inform all other peers of the addition of player to the group. If there are
837 * no peers keep this event quiet.
838 * Also, if this event was the result of another machine sending it to us,
839 * don't bother rebroadcasting it.
840 */
841 if( ( lpMsgHdr == NULL ) &&
842 This->dp2->lpSessionDesc &&
843 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
844 {
845 DPMSG_ADDPLAYERTOGROUP msg;
846 msg.dwType = DPSYS_ADDPLAYERTOGROUP;
847
848 msg.dpIdGroup = idGroup;
849 msg.dpIdPlayer = idPlayer;
850
851 /* FIXME: Correct to just use send effectively? */
852 /* FIXME: Should size include data w/ message or just message "header" */
853 /* FIXME: Check return code */
854 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
855 }
856
857 return DP_OK;
858 }
859
860 static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
861 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
862 {
863 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
864 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
865 }
866
867 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
868 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
869 {
870 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
871 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
872 }
873
874 static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
875 {
876 HRESULT hr = DP_OK;
877
878 TRACE("(%p)->(%u)\n", This, bAnsi );
879
880 /* FIXME: Need to find a new host I assume (how?) */
881 /* FIXME: Need to destroy all local groups */
882 /* FIXME: Need to migrate all remotely visible players to the new host */
883