Wine-0_9_1 vendor import
[reactos.git] / reactos / lib / dplayx / current / dplay.c
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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, LPDPNAME 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, LPDPID lpid,
62 LPDPNAME 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
247 return TRUE;
248 }
249
250 static BOOL DP_DestroyIUnknown( LPVOID lpDP )
251 {
252 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
253
254 DeleteCriticalSection( &This->unk->DP_lock );
255 HeapFree( GetProcessHeap(), 0, This->unk );
256
257 return TRUE;
258 }
259
260 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
261 {
262 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
263
264 This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
265 if ( This->dp2 == NULL )
266 {
267 return FALSE;
268 }
269
270 This->dp2->bConnectionOpen = FALSE;
271
272 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
273
274 This->dp2->bHostInterface = FALSE;
275
276 DPQ_INIT(This->dp2->receiveMsgs);
277 DPQ_INIT(This->dp2->sendMsgs);
278 DPQ_INIT(This->dp2->replysExpected);
279
280 if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
281 {
282 /* FIXME: Memory leak */
283 return FALSE;
284 }
285
286 /* Provide an initial session desc with nothing in it */
287 This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
288 HEAP_ZERO_MEMORY,
289 sizeof( *This->dp2->lpSessionDesc ) );
290 if( This->dp2->lpSessionDesc == NULL )
291 {
292 /* FIXME: Memory leak */
293 return FALSE;
294 }
295 This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
296
297 /* We are emulating a dp 6 implementation */
298 This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
299
300 This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
301 sizeof( *This->dp2->spData.lpCB ) );
302 This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
303 This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
304
305 /* This is the pointer to the service provider */
306 if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
307 (LPVOID*)&This->dp2->spData.lpISP, This ) )
308 )
309 {
310 /* FIXME: Memory leak */
311 return FALSE;
312 }
313
314 /* Setup lobby provider information */
315 This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
316 This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
317 sizeof( *This->dp2->dplspData.lpCB ) );
318 This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB );
319
320 if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
321 (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
322 )
323 {
324 /* FIXME: Memory leak */
325 return FALSE;
326 }
327
328 return TRUE;
329 }
330
331 /* Definition of the global function in dplayx_queue.h. #
332 * FIXME: Would it be better to have a dplayx_queue.c for this function? */
333 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
334 {
335 HeapFree( GetProcessHeap(), 0, elem );
336 }
337
338 /* Function to delete the list of groups with this interface. Needs to
339 * delete the group and player lists associated with this group as well
340 * as the group data associated with this group. It should not delete
341 * player data as that is shared with the top player list and will be
342 * deleted with that.
343 */
344 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList );
345 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList )
346 {
347 DPQ_DELETEQ( elem->lpGData->groups, groups,
348 lpGroupList, cbDeleteElemFromHeap );
349 DPQ_DELETEQ( elem->lpGData->players, players,
350 lpPlayerList, cbDeleteElemFromHeap );
351 HeapFree( GetProcessHeap(), 0, elem->lpGData );
352 HeapFree( GetProcessHeap(), 0, elem );
353 }
354
355 /* Function to delete the list of players with this interface. Needs to
356 * delete the player data for all players as well.
357 */
358 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList );
359 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList )
360 {
361 HeapFree( GetProcessHeap(), 0, elem->lpPData );
362 HeapFree( GetProcessHeap(), 0, elem );
363 }
364
365 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
366 {
367 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
368
369 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
370 {
371 TerminateThread( This->dp2->hEnumSessionThread, 0 );
372 CloseHandle( This->dp2->hEnumSessionThread );
373 }
374
375 /* Finish with the SP - have it shutdown */
376 if( This->dp2->spData.lpCB->ShutdownEx )
377 {
378 DPSP_SHUTDOWNDATA data;
379
380 TRACE( "Calling SP ShutdownEx\n" );
381
382 data.lpISP = This->dp2->spData.lpISP;
383
384 (*This->dp2->spData.lpCB->ShutdownEx)( &data );
385 }
386 else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
387 {
388 TRACE( "Calling obsolete SP Shutdown\n" );
389 (*This->dp2->spData.lpCB->Shutdown)();
390 }
391
392 /* Unload the SP (if it exists) */
393 if( This->dp2->hServiceProvider != 0 )
394 {
395 FreeLibrary( This->dp2->hServiceProvider );
396 }
397
398 /* Unload the Lobby Provider (if it exists) */
399 if( This->dp2->hDPLobbyProvider != 0 )
400 {
401 FreeLibrary( This->dp2->hDPLobbyProvider );
402 }
403
404 #if 0
405 DPQ_DELETEQ( This->dp2->players, players, lpPlayerList, cbDeletePlayerElem );
406 DPQ_DELETEQ( This->dp2->groups, groups, lpGroupList, cbDeleteGroupsElem );
407 #endif
408
409 /* FIXME: Need to delete receive and send msgs queue contents */
410
411 NS_DeleteSessionCache( This->dp2->lpNameServerData );
412
413 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
414
415 IDirectPlaySP_Release( This->dp2->spData.lpISP );
416
417 /* Delete the contents */
418 HeapFree( GetProcessHeap(), 0, This->dp2 );
419
420 return TRUE;
421 }
422
423 static BOOL DP_CreateDirectPlay3( LPVOID lpDP )
424 {
425 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
426
427 This->dp3 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp3) ) );
428 if ( This->dp3 == NULL )
429 {
430 return FALSE;
431 }
432
433 return TRUE;
434 }
435
436 static BOOL DP_DestroyDirectPlay3( LPVOID lpDP )
437 {
438 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
439
440 /* Delete the contents */
441 HeapFree( GetProcessHeap(), 0, This->dp3 );
442
443 return TRUE;
444 }
445
446 static BOOL DP_CreateDirectPlay4( LPVOID lpDP )
447 {
448 IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)lpDP;
449
450 This->dp4 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp4) ) );
451 if ( This->dp4 == NULL )
452 {
453 return FALSE;
454 }
455
456 return TRUE;
457 }
458
459 static BOOL DP_DestroyDirectPlay4( LPVOID lpDP )
460 {
461 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
462
463 /* Delete the contents */
464 HeapFree( GetProcessHeap(), 0, This->dp4 );
465
466 return TRUE;
467 }
468
469
470 /* Create a new interface */
471 extern
472 HRESULT DP_CreateInterface
473 ( REFIID riid, LPVOID* ppvObj )
474 {
475 TRACE( " for %s\n", debugstr_guid( riid ) );
476
477 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
478 sizeof( IDirectPlay2Impl ) );
479
480 if( *ppvObj == NULL )
481 {
482 return DPERR_OUTOFMEMORY;
483 }
484
485 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
486 {
487 IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj;
488 This->lpVtbl = &directPlay2WVT;
489 }
490 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
491 {
492 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj;
493 This->lpVtbl = &directPlay2AVT;
494 }
495 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
496 {
497 IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj;
498 This->lpVtbl = &directPlay3WVT;
499 }
500 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
501 {
502 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj;
503 This->lpVtbl = &directPlay3AVT;
504 }
505 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
506 {
507 IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj;
508 This->lpVtbl = &directPlay4WVT;
509 }
510 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
511 {
512 IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj;
513 This->lpVtbl = &directPlay4AVT;
514 }
515 else
516 {
517 /* Unsupported interface */
518 HeapFree( GetProcessHeap(), 0, *ppvObj );
519 *ppvObj = NULL;
520
521 return E_NOINTERFACE;
522 }
523
524 /* Initialize it */
525 if ( DP_CreateIUnknown( *ppvObj ) &&
526 DP_CreateDirectPlay2( *ppvObj ) &&
527 DP_CreateDirectPlay3( *ppvObj ) &&
528 DP_CreateDirectPlay4( *ppvObj )
529 )
530 {
531 IDirectPlayX_AddRef( (LPDIRECTPLAY2A)*ppvObj );
532
533 return S_OK;
534 }
535
536 /* Initialize failed, destroy it */
537 DP_DestroyDirectPlay4( *ppvObj );
538 DP_DestroyDirectPlay3( *ppvObj );
539 DP_DestroyDirectPlay2( *ppvObj );
540 DP_DestroyIUnknown( *ppvObj );
541
542 HeapFree( GetProcessHeap(), 0, *ppvObj );
543
544 *ppvObj = NULL;
545 return DPERR_NOMEMORY;
546 }
547
548
549 /* Direct Play methods */
550
551 /* Shared between all dplay types */
552 static HRESULT WINAPI DP_QueryInterface
553 ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj )
554 {
555 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
556 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
557
558 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
559 sizeof( *This ) );
560
561 if( *ppvObj == NULL )
562 {
563 return DPERR_OUTOFMEMORY;
564 }
565
566 CopyMemory( *ppvObj, This, sizeof( *This ) );
567 (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
568
569 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
570 {
571 IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj;
572 This->lpVtbl = &directPlay2WVT;
573 }
574 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
575 {
576 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj;
577 This->lpVtbl = &directPlay2AVT;
578 }
579 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
580 {
581 IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj;
582 This->lpVtbl = &directPlay3WVT;
583 }
584 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
585 {
586 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj;
587 This->lpVtbl = &directPlay3AVT;
588 }
589 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
590 {
591 IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj;
592 This->lpVtbl = &directPlay4WVT;
593 }
594 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
595 {
596 IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj;
597 This->lpVtbl = &directPlay4AVT;
598 }
599 else
600 {
601 /* Unsupported interface */
602 HeapFree( GetProcessHeap(), 0, *ppvObj );
603 *ppvObj = NULL;
604
605 return E_NOINTERFACE;
606 }
607
608 IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj );
609
610 return S_OK;
611 }
612
613 /* Shared between all dplay types */
614 static ULONG WINAPI DP_AddRef
615 ( LPDIRECTPLAY3 iface )
616 {
617 ULONG ulInterfaceRefCount, ulObjRefCount;
618 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
619
620 ulObjRefCount = InterlockedIncrement( &This->unk->ulObjRef );
621 ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
622
623 TRACE( "ref count incremented to %lu:%lu for %p\n",
624 ulInterfaceRefCount, ulObjRefCount, This );
625
626 return ulObjRefCount;
627 }
628
629 static ULONG WINAPI DP_Release
630 ( LPDIRECTPLAY3 iface )
631 {
632 ULONG ulInterfaceRefCount, ulObjRefCount;
633
634 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
635
636 ulObjRefCount = InterlockedDecrement( &This->unk->ulObjRef );
637 ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
638
639 TRACE( "ref count decremented to %lu:%lu for %p\n",
640 ulInterfaceRefCount, ulObjRefCount, This );
641
642 /* Deallocate if this is the last reference to the object */
643 if( ulObjRefCount == 0 )
644 {
645 /* If we're destroying the object, this must be the last ref
646 of the last interface */
647 DP_DestroyDirectPlay4( This );
648 DP_DestroyDirectPlay3( This );
649 DP_DestroyDirectPlay2( This );
650 DP_DestroyIUnknown( This );
651 }
652
653 /* Deallocate the interface */
654 if( ulInterfaceRefCount == 0 )
655 {
656 HeapFree( GetProcessHeap(), 0, This );
657 }
658
659 return ulObjRefCount;
660 }
661
662 static inline DPID DP_NextObjectId(void)
663 {
664 return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
665 }
666
667 /* *lplpReply will be non NULL iff there is something to reply */
668 HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
669 DWORD dwMessageBodySize, LPCVOID lpcMessageHeader,
670 WORD wCommandId, WORD wVersion,
671 LPVOID* lplpReply, LPDWORD lpdwMsgSize )
672 {
673 TRACE( "(%p)->(%p,0x%08lx,%p,%u,%u)\n",
674 This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
675 wVersion );
676
677 switch( wCommandId )
678 {
679 /* Name server needs to handle this request */
680 case DPMSGCMD_ENUMSESSIONSREQUEST:
681 {
682 /* Reply expected */
683 NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
684
685 break;
686 }
687
688 /* Name server needs to handle this request */
689 case DPMSGCMD_ENUMSESSIONSREPLY:
690 {
691 /* No reply expected */
692 NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
693 This->dp2->spData.dwSPHeaderSize,
694 (LPDPMSG_ENUMSESSIONSREPLY)lpcMessageBody,
695 This->dp2->lpNameServerData );
696 break;
697 }
698
699 case DPMSGCMD_REQUESTNEWPLAYERID:
700 {
701 LPCDPMSG_REQUESTNEWPLAYERID lpcMsg =
702 (LPCDPMSG_REQUESTNEWPLAYERID)lpcMessageBody;
703
704 LPDPMSG_NEWPLAYERIDREPLY lpReply;
705
706 *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
707
708 *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
709
710 FIXME( "Ignoring dwFlags 0x%08lx in request msg\n",
711 lpcMsg->dwFlags );
712
713 /* Setup the reply */
714 lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
715 This->dp2->spData.dwSPHeaderSize );
716
717 lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
718 lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
719 lpReply->envelope.wVersion = DPMSGVER_DP6;
720
721 lpReply->dpidNewPlayerId = DP_NextObjectId();
722
723 TRACE( "Allocating new playerid 0x%08lx from remote request\n",
724 lpReply->dpidNewPlayerId );
725
726 break;
727 }
728
729 case DPMSGCMD_GETNAMETABLEREPLY:
730 case DPMSGCMD_NEWPLAYERIDREPLY:
731 {
732
733 #if 0
734 if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
735 DebugBreak();
736 #endif
737 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
738
739 break;
740 }
741
742 #if 1
743 case DPMSGCMD_JUSTENVELOPE:
744 {
745 TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08lx\n", lpcMessageHeader, ((LPDWORD)lpcMessageHeader)[1] );
746 NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
747 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
748 }
749 #endif
750
751 case DPMSGCMD_FORWARDADDPLAYER:
752 {
753 #if 0
754 DebugBreak();
755 #endif
756 #if 1
757 TRACE( "Sending message to self to get my addr\n" );
758 DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
759 #endif
760 break;
761 }
762
763 case DPMSGCMD_FORWARDADDPLAYERNACK:
764 {
765 DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
766 break;
767 }
768
769 default:
770 {
771 FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
772 DebugBreak();
773 break;
774 }
775 }
776
777 /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
778
779 return DP_OK;
780 }
781
782
783 static HRESULT WINAPI DP_IF_AddPlayerToGroup
784 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
785 DPID idPlayer, BOOL bAnsi )
786 {
787 lpGroupData lpGData;
788 lpPlayerList lpPList;
789 lpPlayerList lpNewPList;
790
791 TRACE( "(%p)->(%p,0x%08lx,0x%08lx,%u)\n",
792 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
793
794 /* Find the group */
795 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
796 {
797 return DPERR_INVALIDGROUP;
798 }
799
800 /* Find the player */
801 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
802 {
803 return DPERR_INVALIDPLAYER;
804 }
805
806 /* Create a player list (ie "shortcut" ) */
807 lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
808 if( lpNewPList == NULL )
809 {
810 return DPERR_CANTADDPLAYER;
811 }
812
813 /* Add the shortcut */
814 lpPList->lpPData->uRef++;
815 lpNewPList->lpPData = lpPList->lpPData;
816
817 /* Add the player to the list of players for this group */
818 DPQ_INSERT(lpGData->players,lpNewPList,players);
819
820 /* Let the SP know that we've added a player to the group */
821 if( This->dp2->spData.lpCB->AddPlayerToGroup )
822 {
823 DPSP_ADDPLAYERTOGROUPDATA data;
824
825 TRACE( "Calling SP AddPlayerToGroup\n" );
826
827 data.idPlayer = idPlayer;
828 data.idGroup = idGroup;
829 data.lpISP = This->dp2->spData.lpISP;
830
831 (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
832 }
833
834 /* Inform all other peers of the addition of player to the group. If there are
835 * no peers keep this event quiet.
836 * Also, if this event was the result of another machine sending it to us,
837 * don't bother rebroadcasting it.
838 */
839 if( ( lpMsgHdr == NULL ) &&
840 This->dp2->lpSessionDesc &&
841 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
842 {
843 DPMSG_ADDPLAYERTOGROUP msg;
844 msg.dwType = DPSYS_ADDPLAYERTOGROUP;
845
846 msg.dpIdGroup = idGroup;
847 msg.dpIdPlayer = idPlayer;
848
849 /* FIXME: Correct to just use send effectively? */
850 /* FIXME: Should size include data w/ message or just message "header" */
851 /* FIXME: Check return code */
852 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
853 }
854
855 return DP_OK;
856 }
857
858 static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
859 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
860 {
861 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
862 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
863 }
864
865 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
866 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
867 {
868 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
869 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
870 }
871
872 static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
873 {
874 HRESULT hr = DP_OK;
875
876 TRACE("(%p)->(%u)\n", This, bAnsi );
877
878 /* FIXME: Need to find a new host I assume (how?) */
879 /* FIXME: Need to destroy all local groups */
880 /* FIXME: Need to migrate all remotely visible players to the new host */
881
882 /* Invoke the SP callback to inform of session close */
883 if( This->dp2->spData.lpCB->CloseEx )
884 {
885 DPSP_CLOSEDATA data;
886
887 TRACE( "Calling SP CloseEx\n" );
888
889 data.lpISP = This->dp2->spData.lpISP;
890
891 hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
892
893 }
894 else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
895 {
896 TRACE( "Calling SP Close (obsolete interface)\n" );
897
898 hr = (*This->dp2->spData.lpCB->Close)();
899 }
900
901 return hr;
902 }
903
904 static HRESULT WINAPI DirectPlay2AImpl_Close
905 ( LPDIRECTPLAY2A iface )
906 {
907 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
908 return DP_IF_Close( This, TRUE );
909 }
910
911 static HRESULT WINAPI DirectPlay2WImpl_Close
912 ( LPDIRECTPLAY2 iface )
913 {
914 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
915 return DP_IF_Close( This, FALSE );
916 }
917
918 static
919 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, LPDPID lpid,
920 LPDPNAME lpName, DWORD dwFlags,
921 DPID idParent, BOOL bAnsi )
922 {
923 lpGroupData lpGData;
924
925 /* Allocate the new space and add to end of high level group list */
926 lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
927
928 if( lpGData == NULL )
929 {
930 return NULL;
931 }
932
933 DPQ_INIT(lpGData->groups);
934 DPQ_INIT(lpGData->players);
935
936 /* Set the desired player ID - no sanity checking to see if it exists */
937 lpGData->dpid = *lpid;
938
939 DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
940
941 /* FIXME: Should we check that the parent exists? */
942 lpGData->parent = idParent;
943
944 /* FIXME: Should we validate the dwFlags? */
945 lpGData->dwFlags = dwFlags;
946
947 TRACE( "Created group id 0x%08lx\n", *lpid );
948
949 return lpGData;
950 }
951
952 /* This method assumes that all links to it are already deleted */
953 static void
954 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
955 {
956 lpGroupList lpGList;
957
958 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
959
960 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
961
962 if( lpGList == NULL )
963 {
964 ERR( "DPID 0x%08lx not found\n", dpid );
965 return;
966 }
967
968 if( --(lpGList->lpGData->uRef) )
969 {
970 FIXME( "Why is this not the last reference to group?\n" );
971 DebugBreak();
972 }
973
974 /* Delete player */
975 DP_DeleteDPNameStruct( &lpGList->lpGData->name );
976 HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
977
978 /* Remove and Delete Player List object */
979 HeapFree( GetProcessHeap(), 0, lpGList );
980
981 }
982
983 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
984 {
985 lpGroupList lpGroups;
986
987 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
988
989 if( dpid == DPID_SYSTEM_GROUP )
990 {
991 return This->dp2->lpSysGroup;
992 }
993 else
994 {
995 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
996 }
997
998 if( lpGroups == NULL )
999 {
1000 return NULL;
1001 }
1002
1003 return lpGroups->lpGData;
1004 }
1005
1006 static HRESULT WINAPI DP_IF_CreateGroup
1007 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
1008 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
1009 DWORD dwFlags, BOOL bAnsi )
1010 {
1011 lpGroupData lpGData;
1012
1013 TRACE( "(%p)->(%p,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
1014 This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
1015 dwFlags, bAnsi );
1016
1017 /* If the name is not specified, we must provide one */
1018 if( DPID_UNKNOWN == *lpidGroup )
1019 {
1020 /* If we are the name server, we decide on the group ids. If not, we
1021 * must ask for one before attempting a creation.
1022 */
1023 if( This->dp2->bHostInterface )
1024 {
1025 *lpidGroup = DP_NextObjectId();
1026 }
1027 else
1028 {
1029 *lpidGroup = DP_GetRemoteNextObjectId();
1030 }
1031 }
1032
1033 lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
1034 DPID_NOPARENT_GROUP, bAnsi );
1035
1036 if( lpGData == NULL )
1037 {
1038 return DPERR_CANTADDPLAYER; /* yes player not group */
1039 }
1040
1041 if( DPID_SYSTEM_GROUP == *lpidGroup )
1042 {
1043 This->dp2->lpSysGroup = lpGData;
1044 TRACE( "Inserting system group\n" );
1045 }
1046 else
1047 {
1048 /* Insert into the system group */
1049 lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
1050 lpGroup->lpGData = lpGData;
1051
1052 DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
1053 }
1054
1055 /* Something is now referencing this data */
1056 lpGData->uRef++;
1057
1058 /* Set all the important stuff for the group */
1059 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
1060
1061 /* FIXME: We should only create the system group if GetCaps returns
1062 * DPCAPS_GROUPOPTIMIZED.
1063 */
1064
1065 /* Let the SP know that we've created this group */
1066 if( This->dp2->spData.lpCB->CreateGroup )
1067 {
1068 DPSP_CREATEGROUPDATA data;
1069 DWORD dwCreateFlags = 0;
1070
1071 TRACE( "Calling SP CreateGroup\n" );
1072
1073 if( *lpidGroup == DPID_NOPARENT_GROUP )
1074 dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
1075
1076 if( lpMsgHdr == NULL )
1077 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1078
1079 if( dwFlags & DPGROUP_HIDDEN )
1080 dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
1081
1082 data.idGroup = *lpidGroup;
1083 data.dwFlags = dwCreateFlags;
1084 data.lpSPMessageHeader = lpMsgHdr;
1085 data.lpISP = This->dp2->spData.lpISP;
1086
1087 (*This->dp2->spData.lpCB->CreateGroup)( &data );
1088 }
1089
1090 /* Inform all other peers of the creation of a new group. If there are
1091 * no peers keep this event quiet.
1092 * Also if this message was sent to us, don't rebroadcast.
1093 */
1094 if( ( lpMsgHdr == NULL ) &&
1095 This->dp2->lpSessionDesc &&
1096 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1097 {
1098 DPMSG_CREATEPLAYERORGROUP msg;
1099 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1100
1101 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
1102 msg.dpId = *lpidGroup;
1103 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
1104 msg.lpData = lpData;
1105 msg.dwDataSize = dwDataSize;
1106 msg.dpnName = *lpGroupName;
1107 msg.dpIdParent = DPID_NOPARENT_GROUP;
1108 msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
1109
1110 /* FIXME: Correct to just use send effectively? */
1111 /* FIXME: Should size include data w/ message or just message "header" */
1112 /* FIXME: Check return code */
1113 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
1114 0, 0, NULL, NULL, bAnsi );
1115 }
1116
1117 return DP_OK;
1118 }
1119
1120 static HRESULT WINAPI DirectPlay2AImpl_CreateGroup
1121 ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1122 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1123 {
1124 *lpidGroup = DPID_UNKNOWN;
1125
1126 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1127 lpGroupName, lpData, dwDataSize, dwFlags, TRUE );
1128 }
1129
1130 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
1131 ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1132 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1133 {
1134 *lpidGroup = DPID_UNKNOWN;
1135
1136 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1137 lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
1138 }
1139
1140
1141 static void
1142 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
1143 LPVOID lpData, DWORD dwDataSize )
1144 {
1145 /* Clear out the data with this player */
1146 if( dwFlags & DPSET_LOCAL )
1147 {
1148 if ( lpGData->dwLocalDataSize != 0 )
1149 {
1150 HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
1151 lpGData->lpLocalData = NULL;
1152 lpGData->dwLocalDataSize = 0;
1153 }
1154 }
1155 else
1156 {
1157 if( lpGData->dwRemoteDataSize != 0 )
1158 {
1159 HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
1160 lpGData->lpRemoteData = NULL;
1161 lpGData->dwRemoteDataSize = 0;
1162 }
1163 }
1164
1165 /* Reallocate for new data */
1166 if( lpData != NULL )
1167 {
1168 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1169 sizeof( dwDataSize ) );
1170 CopyMemory( lpNewData, lpData, dwDataSize );
1171
1172 if( dwFlags & DPSET_LOCAL )
1173 {
1174 lpGData->lpLocalData = lpData;
1175 lpGData->dwLocalDataSize = dwDataSize;
1176 }
1177 else
1178 {
1179 lpGData->lpRemoteData = lpNewData;
1180 lpGData->dwRemoteDataSize = dwDataSize;
1181 }
1182 }
1183
1184 }
1185
1186 /* This function will just create the storage for the new player. */
1187 static
1188 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
1189 LPDPNAME lpName, DWORD dwFlags,
1190 HANDLE hEvent, BOOL bAnsi )
1191 {
1192 lpPlayerData lpPData;
1193
1194 TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
1195
1196 /* Allocate the storage for the player and associate it with list element */
1197 lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
1198 if( lpPData == NULL )
1199 {
1200 return NULL;
1201 }
1202
1203 /* Set the desired player ID */
1204 lpPData->dpid = *lpid;
1205
1206 DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1207
1208 lpPData->dwFlags = dwFlags;
1209
1210 /* If we were given an event handle, duplicate it */
1211 if( hEvent != 0 )
1212 {
1213 if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1214 GetCurrentProcess(), &lpPData->hEvent,
1215 0, FALSE, DUPLICATE_SAME_ACCESS )
1216 )
1217 {
1218 /* FIXME: Memory leak */
1219 ERR( "Can't duplicate player msg handle %p\n", hEvent );
1220 }
1221 }
1222
1223 /* Initialize the SP data section */
1224 lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1225
1226 TRACE( "Created player id 0x%08lx\n", *lpid );
1227
1228 return lpPData;
1229 }
1230
1231 /* Delete the contents of the DPNAME struct */
1232 static void
1233 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1234 {
1235 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
1236 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1237 }
1238
1239 /* This method assumes that all links to it are already deleted */
1240 static void
1241 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1242 {
1243 lpPlayerList lpPList;
1244
1245 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
1246
1247 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1248
1249 if( lpPList == NULL )
1250 {
1251 ERR( "DPID 0x%08lx not found\n", dpid );
1252 return;
1253 }
1254
1255 /* Verify that this is the last reference to the data */
1256 if( --(lpPList->lpPData->uRef) )
1257 {
1258 FIXME( "Why is this not the last reference to player?\n" );
1259 DebugBreak();
1260 }
1261
1262 /* Delete player */
1263 DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1264
1265 CloseHandle( lpPList->lpPData->hEvent );
1266 HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1267
1268 /* Delete Player List object */
1269 HeapFree( GetProcessHeap(), 0, lpPList );
1270 }
1271
1272 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1273 {
1274 lpPlayerList lpPlayers;
1275
1276 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
1277
1278 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1279
1280 return lpPlayers;
1281 }
1282
1283 /* Basic area for Dst must already be allocated */
1284 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi )
1285 {
1286 if( lpSrc == NULL )
1287 {
1288 ZeroMemory( lpDst, sizeof( *lpDst ) );
1289 lpDst->dwSize = sizeof( *lpDst );
1290 return TRUE;
1291 }
1292
1293 if( lpSrc->dwSize != sizeof( *lpSrc) )
1294 {
1295 return FALSE;
1296 }
1297
1298 /* Delete any existing pointers */
1299 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1300 HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1301
1302 /* Copy as required */
1303 CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1304
1305 if( bAnsi )
1306 {
1307 if( lpSrc->u1.lpszShortNameA )
1308 {
1309 lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1310 strlen(lpSrc->u1.lpszShortNameA)+1 );
1311 strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1312 }
1313 if( lpSrc->u2.lpszLongNameA )
1314 {
1315 lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1316 strlen(lpSrc->u2.lpszLongNameA)+1 );
1317 strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1318 }
1319 }
1320 else
1321 {
1322 if( lpSrc->u1.lpszShortNameA )
1323 {
1324 lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1325 (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1326 strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1327 }
1328 if( lpSrc->u2.lpszLongNameA )
1329 {
1330 lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1331 (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1332 strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1333 }
1334 }
1335
1336 return TRUE;
1337 }
1338
1339 static void
1340 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1341 LPVOID lpData, DWORD dwDataSize )
1342 {
1343 /* Clear out the data with this player */
1344 if( dwFlags & DPSET_LOCAL )
1345 {
1346 if ( lpPData->dwLocalDataSize != 0 )
1347 {
1348 HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1349 lpPData->lpLocalData = NULL;
1350 lpPData->dwLocalDataSize = 0;
1351 }
1352 }
1353 else
1354 {
1355 if( lpPData->dwRemoteDataSize != 0 )
1356 {
1357 HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1358 lpPData->lpRemoteData = NULL;
1359 lpPData->dwRemoteDataSize = 0;
1360 }
1361 }
1362
1363 /* Reallocate for new data */
1364 if( lpData != NULL )
1365 {
1366 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1367 sizeof( dwDataSize ) );
1368 CopyMemory( lpNewData, lpData, dwDataSize );
1369
1370 if( dwFlags & DPSET_LOCAL )
1371 {
1372 lpPData->lpLocalData = lpData;
1373 lpPData->dwLocalDataSize = dwDataSize;
1374 }
1375 else
1376 {
1377 lpPData->lpRemoteData = lpNewData;
1378 lpPData->dwRemoteDataSize = dwDataSize;
1379 }
1380 }
1381
1382 }
1383
1384 static HRESULT WINAPI DP_IF_CreatePlayer
1385 ( IDirectPlay2Impl* This,
1386 LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1387 LPDPID lpidPlayer,
1388 LPDPNAME lpPlayerName,
1389 HANDLE hEvent,
1390 LPVOID lpData,
1391 DWORD dwDataSize,
1392 DWORD dwFlags,
1393 BOOL bAnsi )
1394 {
1395 HRESULT hr = DP_OK;
1396 lpPlayerData lpPData;
1397 lpPlayerList lpPList;
1398 DWORD dwCreateFlags = 0;
1399
1400 TRACE( "(%p)->(%p,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
1401 This, lpidPlayer, lpPlayerName, hEvent, lpData,
1402 dwDataSize, dwFlags, bAnsi );
1403
1404 if( dwFlags == 0 )
1405 {
1406 dwFlags = DPPLAYER_SPECTATOR;
1407 }
1408
1409 if( lpidPlayer == NULL )
1410 {
1411 return DPERR_INVALIDPARAMS;
1412 }
1413
1414
1415 /* Determine the creation flags for the player. These will be passed
1416 * to the name server if requesting a player id and to the SP when
1417 * informing it of the player creation
1418 */
1419 {
1420 if( dwFlags & DPPLAYER_SERVERPLAYER )
1421 {
1422 if( *lpidPlayer == DPID_SERVERPLAYER )
1423 {
1424 /* Server player for the host interface */
1425 dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1426 }
1427 else if( *lpidPlayer == DPID_NAME_SERVER )
1428 {
1429 /* Name server - master of everything */
1430 dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1431 }
1432 else
1433 {
1434 /* Server player for a non host interface */
1435 dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1436 }
1437 }
1438
1439 if( lpMsgHdr == NULL )
1440 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1441 }
1442
1443 /* Verify we know how to handle all the flags */
1444 if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1445 ( dwFlags & DPPLAYER_SPECTATOR )
1446 )
1447 )
1448 {
1449 /* Assume non fatal failure */
1450 ERR( "unknown dwFlags = 0x%08lx\n", dwFlags );
1451 }
1452
1453 /* If the name is not specified, we must provide one */
1454 if( *lpidPlayer == DPID_UNKNOWN )
1455 {
1456 /* If we are the session master, we dish out the group/player ids */
1457 if( This->dp2->bHostInterface )
1458 {
1459 *lpidPlayer = DP_NextObjectId();
1460 }
1461 else
1462 {
1463 hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1464
1465 if( FAILED(hr) )
1466 {
1467 ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1468 return hr;
1469 }
1470 }
1471 }
1472 else
1473 {
1474 /* FIXME: Would be nice to perhaps verify that we don't already have
1475 * this player.
1476 */
1477 }
1478
1479 /* FIXME: Should we be storing these dwFlags or the creation ones? */
1480 lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwFlags,
1481 hEvent, bAnsi );
1482
1483 if( lpPData == NULL )
1484 {
1485 return DPERR_CANTADDPLAYER;
1486 }
1487
1488 /* Create the list object and link it in */
1489 lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1490 if( lpPList == NULL )
1491 {
1492 FIXME( "Memory leak\n" );
1493 return DPERR_CANTADDPLAYER;
1494 }
1495
1496 lpPData->uRef = 1;
1497 lpPList->lpPData = lpPData;
1498
1499 /* Add the player to the system group */
1500 DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1501
1502 /* Update the information and send it to all players in the session */
1503 DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1504
1505 /* Let the SP know that we've created this player */
1506 if( This->dp2->spData.lpCB->CreatePlayer )
1507 {
1508 DPSP_CREATEPLAYERDATA data;
1509
1510 data.idPlayer = *lpidPlayer;
1511 data.dwFlags = dwCreateFlags;
1512 data.lpSPMessageHeader = lpMsgHdr;
1513 data.lpISP = This->dp2->spData.lpISP;
1514
1515 TRACE( "Calling SP CreatePlayer 0x%08lx: dwFlags: 0x%08lx lpMsgHdr: %p\n",
1516 *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1517
1518 hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1519 }
1520
1521 if( FAILED(hr) )
1522 {
1523 ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1524 return hr;
1525 }
1526
1527 /* Now let the SP know that this player is a member of the system group */
1528 if( This->dp2->spData.lpCB->AddPlayerToGroup )
1529 {
1530 DPSP_ADDPLAYERTOGROUPDATA data;
1531
1532 data.idPlayer = *lpidPlayer;
1533 data.idGroup = DPID_SYSTEM_GROUP;
1534 data.lpISP = This->dp2->spData.lpISP;
1535
1536 TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1537
1538 hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1539 }
1540
1541 if( FAILED(hr) )
1542 {
1543 ERR( "Failed to add player to sys group with sp: %s\n",
1544 DPLAYX_HresultToString(hr) );
1545 return hr;
1546 }
1547
1548 #if 1
1549 if( This->dp2->bHostInterface == FALSE )
1550 {
1551 /* Let the name server know about the creation of this player */
1552 /* FIXME: Is this only to be done for the creation of a server player or
1553 * is this used for regular players? If only for server players, move
1554 * this call to DP_SecureOpen(...);
1555 */
1556 #if 0
1557 TRACE( "Sending message to self to get my addr\n" );
1558 DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1559 #endif
1560
1561 hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1562 }
1563 #else
1564 /* Inform all other peers of the creation of a new player. If there are
1565 * no peers keep this quiet.
1566 * Also, if this was a remote event, no need to rebroadcast it.
1567 */
1568 if( ( lpMsgHdr == NULL ) &&
1569 This->dp2->lpSessionDesc &&
1570 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1571 {
1572 DPMSG_CREATEPLAYERORGROUP msg;
1573 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1574
1575 msg.dwPlayerType = DPPLAYERTYPE_PLAYER;
1576 msg.dpId = *lpidPlayer;
1577 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1578 msg.lpData = lpData;
1579 msg.dwDataSize = dwDataSize;
1580 msg.dpnName = *lpPlayerName;
1581 msg.dpIdParent = DPID_NOPARENT_GROUP;
1582 msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1583
1584 /* FIXME: Correct to just use send effectively? */
1585 /* FIXME: Should size include data w/ message or just message "header" */
1586 /* FIXME: Check return code */
1587 hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1588 sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1589 }
1590 #endif
1591
1592 return hr;
1593 }
1594
1595 static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
1596 ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1597 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1598 {
1599 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1600
1601 if( dwFlags & DPPLAYER_SERVERPLAYER )
1602 {
1603 *lpidPlayer = DPID_SERVERPLAYER;
1604 }
1605 else
1606 {
1607 *lpidPlayer = DPID_UNKNOWN;
1608 }
1609
1610 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1611 lpData, dwDataSize, dwFlags, TRUE );
1612 }
1613
1614 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1615 ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1616 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1617 {
1618 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1619
1620 if( dwFlags & DPPLAYER_SERVERPLAYER )
1621 {
1622 *lpidPlayer = DPID_SERVERPLAYER;
1623 }
1624 else
1625 {
1626 *lpidPlayer = DPID_UNKNOWN;
1627 }
1628
1629 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1630 lpData, dwDataSize, dwFlags, FALSE );
1631 }
1632
1633 static DPID DP_GetRemoteNextObjectId(void)
1634 {
1635 FIXME( ":stub\n" );
1636
1637 /* Hack solution */
1638 return DP_NextObjectId();
1639 }
1640
1641 static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
1642 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
1643 DPID idPlayer, BOOL bAnsi )
1644 {
1645 HRESULT hr = DP_OK;
1646
1647 lpGroupData lpGData;
1648 lpPlayerList lpPList;
1649
1650 TRACE( "(%p)->(%p,0x%08lx,0x%08lx,%u)\n",
1651 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
1652
1653 /* Find the group */
1654 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1655 {
1656 return DPERR_INVALIDGROUP;
1657 }
1658
1659 /* Find the player */
1660 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
1661 {
1662 return DPERR_INVALIDPLAYER;
1663 }
1664
1665 /* Remove the player shortcut from the group */
1666 DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
1667
1668 if( lpPList == NULL )
1669 {
1670 return DPERR_INVALIDPLAYER;
1671 }
1672
1673 /* One less reference */
1674 lpPList->lpPData->uRef--;
1675
1676 /* Delete the Player List element */
1677 HeapFree( GetProcessHeap(), 0, lpPList );
1678
1679 /* Inform the SP if they care */
1680 if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1681 {
1682 DPSP_REMOVEPLAYERFROMGROUPDATA data;
1683
1684 TRACE( "Calling SP RemovePlayerFromGroup\n" );
1685
1686 data.idPlayer = idPlayer;
1687 data.idGroup = idGroup;
1688 data.lpISP = This->dp2->spData.lpISP;
1689
1690 hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1691 }
1692
1693 /* Need to send a DELETEPLAYERFROMGROUP message */
1694 FIXME( "Need to send a message\n" );
1695
1696 return hr;
1697 }
1698
1699 static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
1700 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
1701 {
1702 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1703 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
1704 }
1705
1706 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
1707 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
1708 {
1709 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1710 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
1711 }
1712
1713 typedef struct _DPRGOPContext
1714 {
1715 IDirectPlay3Impl* This;
1716 BOOL bAnsi;
1717 DPID idGroup;
1718 } DPRGOPContext, *lpDPRGOPContext;
1719
1720 static BOOL CALLBACK
1721 cbRemoveGroupOrPlayer(
1722 DPID dpId,
1723 DWORD dwPlayerType,
1724 LPCDPNAME lpName,
1725 DWORD dwFlags,
1726 LPVOID lpContext )
1727 {
1728 lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1729
1730 TRACE( "Removing element:0x%08lx (type:0x%08lx) from element:0x%08lx\n",
1731 dpId, dwPlayerType, lpCtxt->idGroup );
1732
1733 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1734 {
1735 if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
1736 dpId )
1737 )
1738 )
1739 {
1740 ERR( "Unable to delete group 0x%08lx from group 0x%08lx\n",
1741 dpId, lpCtxt->idGroup );
1742 }
1743 }
1744 else
1745 {
1746 if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
1747 NULL, lpCtxt->idGroup,
1748 dpId, lpCtxt->bAnsi )
1749 )
1750 )
1751 {
1752 ERR( "Unable to delete player 0x%08lx from grp 0x%08lx\n",
1753 dpId, lpCtxt->idGroup );
1754 }
1755 }
1756
1757 return TRUE; /* Continue enumeration */
1758 }
1759
1760 static HRESULT WINAPI DP_IF_DestroyGroup
1761 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
1762 {
1763 lpGroupData lpGData;
1764 DPRGOPContext context;
1765
1766 FIXME( "(%p)->(%p,0x%08lx,%u): semi stub\n",
1767 This, lpMsgHdr, idGroup, bAnsi );
1768
1769 /* Find the group */
1770 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1771 {
1772 return DPERR_INVALIDPLAYER; /* yes player */
1773 }
1774
1775 context.This = (IDirectPlay3Impl*)This;
1776 context.bAnsi = bAnsi;
1777 context.idGroup = idGroup;
1778
1779 /* Remove all players that this group has */
1780 DP_IF_EnumGroupPlayers( This, idGroup, NULL,
1781 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1782
1783 /* Remove all links to groups that this group has since this is dp3 */
1784 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
1785 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1786
1787 /* Remove this group from the parent group - if it has one */
1788 if( ( idGroup != DPID_SYSTEM_GROUP ) &&
1789 ( lpGData->parent != DPID_SYSTEM_GROUP )
1790 )
1791 {
1792 DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
1793 idGroup );
1794 }
1795
1796 /* Now delete this group data and list from the system group */
1797 DP_DeleteGroup( This, idGroup );
1798
1799 /* Let the SP know that we've destroyed this group */
1800 if( This->dp2->spData.lpCB->DeleteGroup )
1801 {
1802 DPSP_DELETEGROUPDATA data;
1803
1804 FIXME( "data.dwFlags is incorrect\n" );
1805
1806 data.idGroup = idGroup;
1807 data.dwFlags = 0;
1808 data.lpISP = This->dp2->spData.lpISP;
1809
1810 (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1811 }
1812
1813 FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1814
1815 return DP_OK;
1816 }
1817
1818 static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
1819 ( LPDIRECTPLAY2A iface, DPID idGroup )
1820 {
1821 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1822 return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1823 }
1824
1825 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
1826 ( LPDIRECTPLAY2 iface, DPID idGroup )
1827 {
1828 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1829 return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1830 }
1831
1832 typedef struct _DPFAGContext
1833 {
1834 IDirectPlay2Impl* This;
1835 DPID idPlayer;
1836 BOOL bAnsi;
1837 } DPFAGContext, *lpDPFAGContext;
1838
1839 static HRESULT WINAPI DP_IF_DestroyPlayer
1840 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1841 {
1842 DPFAGContext cbContext;
1843
1844 FIXME( "(%p)->(%p,0x%08lx,%u): semi stub\n",
1845 This, lpMsgHdr, idPlayer, bAnsi );
1846
1847 if( This->dp2->connectionInitialized == NO_PROVIDER )
1848 {
1849 return DPERR_UNINITIALIZED;
1850 }
1851
1852 if( DP_FindPlayer( This, idPlayer ) == NULL )
1853 {
1854 return DPERR_INVALIDPLAYER;
1855 }
1856
1857 /* FIXME: If the player is remote, we must be the host to delete this */
1858
1859 cbContext.This = This;
1860 cbContext.idPlayer = idPlayer;
1861 cbContext.bAnsi = bAnsi;
1862
1863 /* Find each group and call DeletePlayerFromGroup if the player is a
1864 member of the group */
1865 DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
1866 (LPVOID)&cbContext, DPENUMGROUPS_ALL, bAnsi );
1867
1868 /* Now delete player and player list from the sys group */
1869 DP_DeletePlayer( This, idPlayer );
1870
1871 /* Let the SP know that we've destroyed this group */
1872 if( This->dp2->spData.lpCB->DeletePlayer )
1873 {
1874 DPSP_DELETEPLAYERDATA data;
1875
1876 FIXME( "data.dwFlags is incorrect\n" );
1877
1878 data.idPlayer = idPlayer;
1879 data.dwFlags = 0;
1880 data.lpISP = This->dp2->spData.lpISP;
1881
1882 (*This->dp2->spData.lpCB->DeletePlayer)( &data );
1883 }
1884
1885 FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
1886
1887 return DP_OK;
1888 }
1889
1890 static BOOL CALLBACK
1891 cbDeletePlayerFromAllGroups(
1892 DPID dpId,
1893 DWORD dwPlayerType,
1894 LPCDPNAME lpName,
1895 DWORD dwFlags,
1896 LPVOID lpContext )
1897 {
1898 lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
1899
1900 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1901 {
1902 DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
1903 lpCtxt->bAnsi );
1904
1905 /* Enumerate all groups in this group since this will normally only
1906 * be called for top level groups
1907 */
1908 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
1909 dpId, NULL,
1910 cbDeletePlayerFromAllGroups,
1911 (LPVOID)lpContext, DPENUMGROUPS_ALL,
1912 lpCtxt->bAnsi );
1913
1914 }
1915 else
1916 {
1917 ERR( "Group callback has dwPlayerType = 0x%08lx\n", dwPlayerType );
1918 }
1919
1920 return TRUE;
1921 }
1922
1923 static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
1924 ( LPDIRECTPLAY2A iface, DPID idPlayer )
1925 {
1926 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1927 return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
1928 }
1929
1930 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
1931 ( LPDIRECTPLAY2 iface, DPID idPlayer )
1932 {
1933 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1934 return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
1935 }
1936
1937 static HRESULT WINAPI DP_IF_EnumGroupPlayers
1938 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
1939 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1940 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1941 {
1942 lpGroupData lpGData;
1943 lpPlayerList lpPList;
1944
1945 FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): semi stub\n",
1946 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
1947 lpContext, dwFlags, bAnsi );
1948
1949 if( This->dp2->connectionInitialized == NO_PROVIDER )
1950 {
1951 return DPERR_UNINITIALIZED;
1952 }
1953
1954 /* Find the group */
1955 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1956 {
1957 return DPERR_INVALIDGROUP;
1958 }
1959
1960 if( DPQ_IS_EMPTY( lpGData->players ) )
1961 {
1962 return DP_OK;
1963 }
1964
1965 lpPList = DPQ_FIRST( lpGData->players );
1966
1967 /* Walk the players in this group */
1968 for( ;; )
1969 {
1970 /* We do not enum the name server or app server as they are of no
1971 * concequence to the end user.
1972 */
1973 if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
1974 ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
1975 )
1976 {
1977
1978 /* FIXME: Need to add stuff for dwFlags checking */
1979
1980 if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
1981 &lpPList->lpPData->name,
1982 lpPList->lpPData->dwFlags,
1983 lpContext )
1984 )
1985 {
1986 /* User requested break */
1987 return DP_OK;
1988 }
1989 }
1990
1991 if( DPQ_IS_ENDOFLIST( lpPList->players ) )
1992 {
1993 break;
1994 }
1995
1996 lpPList = DPQ_NEXT( lpPList->players );
1997 }
1998
1999 return DP_OK;
2000 }
2001
2002 static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
2003 ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance,
2004 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2005 LPVOID lpContext, DWORD dwFlags )
2006 {
2007 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2008 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2009 lpEnumPlayersCallback2, lpContext,
2010 dwFlags, TRUE );
2011 }
2012
2013 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
2014 ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
2015 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2016 LPVOID lpContext, DWORD dwFlags )
2017 {
2018 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2019 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2020 lpEnumPlayersCallback2, lpContext,
2021 dwFlags, FALSE );
2022 }
2023
2024 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
2025 static HRESULT WINAPI DP_IF_EnumGroups
2026 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2027 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2028 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2029 {
2030 return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This,
2031 DPID_SYSTEM_GROUP, lpguidInstance,
2032 lpEnumPlayersCallback2, lpContext,
2033 dwFlags, bAnsi );
2034 }
2035
2036 static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
2037 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2038 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2039 LPVOID lpContext, DWORD dwFlags )
2040 {
2041 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2042 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2043 lpContext, dwFlags, TRUE );
2044 }
2045
2046 static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
2047 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2048 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2049 LPVOID lpContext, DWORD dwFlags )
2050 {
2051 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2052 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2053 lpContext, dwFlags, FALSE );
2054 }
2055
2056 static HRESULT WINAPI DP_IF_EnumPlayers
2057 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2058 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2059 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2060 {
2061 return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance,
2062 lpEnumPlayersCallback2, lpContext,
2063 dwFlags, bAnsi );
2064 }
2065
2066 static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
2067 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2068 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2069 LPVOID lpContext, DWORD dwFlags )
2070 {
2071 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2072 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2073 lpContext, dwFlags, TRUE );
2074 }
2075
2076 static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
2077 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2078 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2079 LPVOID lpContext, DWORD dwFlags )
2080 {
2081 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2082 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2083 lpContext, dwFlags, FALSE );
2084 }
2085
2086 /* This function should call the registered callback function that the user
2087 passed into EnumSessions for each entry available.
2088 */
2089 static void DP_InvokeEnumSessionCallbacks
2090 ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2091 LPVOID lpNSInfo,
2092 DWORD dwTimeout,
2093 LPVOID lpContext )
2094 {
2095 LPDPSESSIONDESC2 lpSessionDesc;
2096
2097 FIXME( ": not checking for conditions\n" );
2098
2099 /* Not sure if this should be pruning but it's convenient */
2100 NS_PruneSessionCache( lpNSInfo );
2101
2102 NS_ResetSessionEnumeration( lpNSInfo );
2103
2104 /* Enumerate all sessions */
2105 /* FIXME: Need to indicate ANSI */
2106 while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
2107 {
2108 TRACE( "EnumSessionsCallback2 invoked\n" );
2109 if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
2110 {
2111 return;
2112 }
2113 }
2114
2115 /* Invoke one last time to indicate that there is no more to come */
2116 lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
2117 }
2118
2119 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
2120 {
2121 EnumSessionAsyncCallbackData* data = (EnumSessionAsyncCallbackData*)lpContext;
2122 HANDLE hSuicideRequest = data->hSuicideRequest;
2123 DWORD dwTimeout = data->dwTimeout;
2124
2125 TRACE( "Thread started with timeout = 0x%08lx\n", dwTimeout );
2126
2127 for( ;; )
2128 {
2129 HRESULT hr;
2130
2131 /* Sleep up to dwTimeout waiting for request to terminate thread */
2132 if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
2133 {
2134 TRACE( "Thread terminating on terminate request\n" );
2135 break;
2136 }
2137
2138 /* Now resend the enum request */
2139 hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
2140 data->dwEnumSessionFlags,
2141 data->lpSpData );
2142
2143 if( FAILED(hr) )
2144 {
2145 ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
2146 /* FIXME: Should we kill this thread? How to inform the main thread? */
2147 }
2148
2149 }
2150
2151 TRACE( "Thread terminating\n" );
2152
2153 /* Clean up the thread data */
2154 CloseHandle( hSuicideRequest );
2155 HeapFree( GetProcessHeap(), 0, lpContext );
2156
2157 /* FIXME: Need to have some notification to main app thread that this is
2158 * dead. It would serve two purposes. 1) allow sync on termination
2159 * so that we don't actually send something to ourselves when we
2160 * become name server (race condition) and 2) so that if we die
2161 * abnormally something else will be able to tell.
2162 */
2163
2164 return 1;
2165 }
2166
2167 static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
2168 {
2169 /* Does a thread exist? If so we were doing an async enum session */
2170 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
2171 {
2172 TRACE( "Killing EnumSession thread %p\n",
2173 This->dp2->hEnumSessionThread );
2174
2175 /* Request that the thread kill itself nicely */
2176 SetEvent( This->dp2->hKillEnumSessionThreadEvent );
2177 CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
2178
2179 /* We no longer need to know about the thread */
2180 CloseHandle( This->dp2->hEnumSessionThread );
2181
2182 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
2183 }
2184 }
2185
2186 static HRESULT WINAPI DP_IF_EnumSessions
2187 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2188 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2189 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2190 {
2191 HRESULT hr = DP_OK;
2192
2193 TRACE( "(%p)->(%p,0x%08lx,%p,%p,0x%08lx,%u)\n",
2194 This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
2195 bAnsi );
2196
2197 /* Can't enumerate if the interface is already open */
2198 if( This->dp2->bConnectionOpen )
2199 {
2200 return DPERR_GENERIC;
2201 }
2202
2203 #if 1
2204 /* The loading of a lobby provider _seems_ to require a backdoor loading
2205 * of the service provider to also associate with this DP object. This is
2206 * because the app doesn't seem to have to call EnumConnections and
2207 * InitializeConnection for the SP before calling this method. As such
2208 * we'll do their dirty work for them with a quick hack so as to always
2209 * load the TCP/IP service provider.
2210 *
2211 * The correct solution would seem to involve creating a dialog box which
2212 * contains the possible SPs. These dialog boxes most likely follow SDK
2213 * examples.
2214 */
2215 if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2216 {
2217 LPVOID lpConnection;
2218 DWORD dwSize;
2219
2220 WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2221
2222 if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) )
2223 {
2224 ERR( "Can't build compound addr\n" );
2225 return DPERR_GENERIC;
2226 }
2227
2228 hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
2229 0, bAnsi );
2230 if( FAILED(hr) )
2231 {
2232 return hr;
2233 }
2234
2235 /* Free up the address buffer */
2236 HeapFree( GetProcessHeap(), 0, lpConnection );
2237
2238 /* The SP is now initialized */
2239 This->dp2->bSPInitialized = TRUE;
2240 }
2241 #endif
2242
2243
2244 /* Use the service provider default? */
2245 if( dwTimeout == 0 )
2246 {
2247 DPCAPS spCaps;
2248 spCaps.dwSize = sizeof( spCaps );
2249
2250 DP_IF_GetCaps( This, &spCaps, 0 );
2251 dwTimeout = spCaps.dwTimeout;
2252
2253 /* The service provider doesn't provide one either! */
2254 if( dwTimeout == 0 )
2255 {
2256 /* Provide the TCP/IP default */
2257 dwTimeout = DPMSG_WAIT_5_SECS;
2258 }
2259 }
2260
2261 if( dwFlags & DPENUMSESSIONS_STOPASYNC )
2262 {
2263 DP_KillEnumSessionThread( This );
2264 return hr;
2265 }
2266
2267 /* FIXME: Interface locking sucks in this method */
2268 if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
2269 {
2270 /* Enumerate everything presently in the local session cache */
2271 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2272 This->dp2->lpNameServerData, dwTimeout,
2273 lpContext );
2274
2275
2276 /* See if we've already created a thread to service this interface */
2277 if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
2278 {
2279 DWORD dwThreadId;
2280
2281 /* Send the first enum request inline since the user may cancel a dialog
2282 * if one is presented. Also, may also have a connecting return code.
2283 */
2284 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2285 dwFlags, &This->dp2->spData );
2286
2287 if( !FAILED(hr) )
2288 {
2289 EnumSessionAsyncCallbackData* lpData
2290 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpData ) );
2291 /* FIXME: need to kill the thread on object deletion */
2292 lpData->lpSpData = &This->dp2->spData;
2293
2294 CopyMemory( &lpData->requestGuid, &lpsd->guidApplication, sizeof(GUID) );
2295 lpData->dwEnumSessionFlags = dwFlags;
2296 lpData->dwTimeout = dwTimeout;
2297
2298 This->dp2->hKillEnumSessionThreadEvent =
2299 CreateEventW( NULL, TRUE, FALSE, NULL );
2300
2301 if( !DuplicateHandle( GetCurrentProcess(),
2302 This->dp2->hKillEnumSessionThreadEvent,
2303 GetCurrentProcess(),
2304 &lpData->hSuicideRequest,
2305 0, FALSE, DUPLICATE_SAME_ACCESS )
2306 )
2307 {
2308 ERR( "Can't duplicate thread killing handle\n" );
2309 }
2310
2311 TRACE( ": creating EnumSessionsRequest thread\n" );
2312
2313 This->dp2->hEnumSessionThread = CreateThread( NULL,
2314 0,
2315 DP_EnumSessionsSendAsyncRequestThread,
2316 lpData,
2317 0,
2318 &dwThreadId );
2319 }
2320 }
2321 }
2322 else
2323 {
2324 /* Invalidate the session cache for the interface */
2325 NS_InvalidateSessionCache( This->dp2->lpNameServerData );
2326
2327 /* Send the broadcast for session enumeration */
2328 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2329 dwFlags,
2330 &This->dp2->spData );
2331
2332
2333 SleepEx( dwTimeout, FALSE );
2334
2335 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2336 This->dp2->lpNameServerData, dwTimeout,
2337 lpContext );
2338 }
2339
2340 return hr;
2341 }
2342
2343 static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
2344 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2345 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2346 LPVOID lpContext, DWORD dwFlags )
2347 {
2348 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2349 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2350 lpContext, dwFlags, TRUE );
2351 }
2352
2353 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
2354 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2355 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2356 LPVOID lpContext, DWORD dwFlags )
2357 {
2358 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2359 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2360 lpContext, dwFlags, FALSE );
2361 }
2362
2363 static HRESULT WINAPI DP_IF_GetPlayerCaps
2364 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
2365 DWORD dwFlags )
2366 {
2367 DPSP_GETCAPSDATA data;
2368
2369 TRACE("(%p)->(0x%08lx,%p,0x%08lx)\n", This, idPlayer, lpDPCaps, dwFlags);
2370
2371 /* Query the service provider */
2372 data.idPlayer = idPlayer;
2373 data.dwFlags = dwFlags;
2374 data.lpCaps = lpDPCaps;
2375 data.lpISP = This->dp2->spData.lpISP;
2376
2377 return (*This->dp2->spData.lpCB->GetCaps)( &data );
2378 }
2379
2380 static HRESULT WINAPI DP_IF_GetCaps
2381 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
2382 {
2383 return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
2384 }
2385
2386 static HRESULT WINAPI DirectPlay2AImpl_GetCaps
2387 ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2388 {
2389 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2390 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2391 }
2392
2393 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
2394 ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2395 {
2396 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2397 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2398 }
2399
2400 static HRESULT WINAPI DP_IF_GetGroupData
2401 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2402 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2403 {
2404 lpGroupData lpGData;
2405 DWORD dwRequiredBufferSize;
2406 LPVOID lpCopyDataFrom;
2407
2408 TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u)\n",
2409 This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
2410
2411 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2412 {
2413 return DPERR_INVALIDGROUP;
2414 }
2415
2416 /* How much buffer is required? */
2417 if( dwFlags & DPSET_LOCAL )
2418 {
2419 dwRequiredBufferSize = lpGData->dwLocalDataSize;
2420 lpCopyDataFrom = lpGData->lpLocalData;
2421 }
2422 else
2423 {
2424 dwRequiredBufferSize = lpGData->dwRemoteDataSize;
2425 lpCopyDataFrom = lpGData->lpRemoteData;
2426 }
2427
2428 /* Is the user requesting to know how big a buffer is required? */
2429 if( ( lpData == NULL ) ||
2430 ( *lpdwDataSize < dwRequiredBufferSize )
2431 )
2432 {
2433 *lpdwDataSize = dwRequiredBufferSize;
2434 return DPERR_BUFFERTOOSMALL;
2435 }
2436
2437 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2438
2439 return DP_OK;
2440 }
2441
2442 static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
2443 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2444 LPDWORD lpdwDataSize, DWORD dwFlags )
2445 {
2446 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2447 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2448 dwFlags, TRUE );
2449 }
2450
2451 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
2452 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2453 LPDWORD lpdwDataSize, DWORD dwFlags )
2454 {
2455 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2456 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2457 dwFlags, FALSE );
2458 }
2459
2460 static HRESULT WINAPI DP_IF_GetGroupName
2461 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2462 LPDWORD lpdwDataSize, BOOL bAnsi )
2463 {
2464 lpGroupData lpGData;
2465 LPDPNAME lpName = (LPDPNAME)lpData;
2466 DWORD dwRequiredDataSize;
2467
2468 FIXME("(%p)->(0x%08lx,%p,%p,%u) ANSI ignored\n",
2469 This, idGroup, lpData, lpdwDataSize, bAnsi );
2470
2471 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2472 {
2473 return DPERR_INVALIDGROUP;
2474 }
2475
2476 dwRequiredDataSize = lpGData->name.dwSize;
2477
2478 if( lpGData->name.u1.lpszShortNameA )
2479 {
2480 dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2481 }
2482
2483 if( lpGData->name.u2.lpszLongNameA )
2484 {
2485 dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2486 }
2487
2488 if( ( lpData == NULL ) ||
2489 ( *lpdwDataSize < dwRequiredDataSize )
2490 )
2491 {
2492 *lpdwDataSize = dwRequiredDataSize;
2493 return DPERR_BUFFERTOOSMALL;
2494 }
2495
2496 /* Copy the structure */
2497 CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2498
2499 if( lpGData->name.u1.lpszShortNameA )
2500 {
2501 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2502 lpGData->name.u1.lpszShortNameA );
2503 }
2504 else
2505 {
2506 lpName->u1.lpszShortNameA = NULL;
2507 }
2508
2509 if( lpGData->name.u1.lpszShortNameA )
2510 {
2511 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2512 lpGData->name.u2.lpszLongNameA );
2513 }
2514 else
2515 {
2516 lpName->u2.lpszLongNameA = NULL;
2517 }
2518
2519 return DP_OK;
2520 }
2521
2522 static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
2523 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2524 LPDWORD lpdwDataSize )
2525 {
2526 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2527 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2528 }
2529
2530 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2531 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2532 LPDWORD lpdwDataSize )
2533 {
2534 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2535 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2536 }
2537
2538 static HRESULT WINAPI DP_IF_GetMessageCount
2539 ( IDirectPlay2Impl* This, DPID idPlayer,
2540 LPDWORD lpdwCount, BOOL bAnsi )
2541 {
2542 FIXME("(%p)->(0x%08lx,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi );
2543 return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer,
2544 DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL,
2545 bAnsi );
2546 }
2547
2548 static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
2549 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
2550 {
2551 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2552 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE );
2553 }
2554
2555 static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
2556 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
2557 {
2558 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2559 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE );
2560 }
2561
2562 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
2563 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2564 {
2565 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2566 FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2567 return DP_OK;
2568 }
2569
2570 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
2571 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2572 {
2573 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2574 FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2575 return DP_OK;
2576 }
2577
2578 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
2579 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2580 DWORD dwFlags )
2581 {
2582 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2583 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2584 }
2585
2586 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
2587 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2588 DWORD dwFlags )
2589 {
2590 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2591 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2592 }
2593
2594 static HRESULT WINAPI DP_IF_GetPlayerData
2595 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2596 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2597 {
2598 lpPlayerList lpPList;
2599 DWORD dwRequiredBufferSize;
2600 LPVOID lpCopyDataFrom;
2601
2602 TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u)\n",
2603 This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
2604
2605 if( This->dp2->connectionInitialized == NO_PROVIDER )
2606 {
2607 return DPERR_UNINITIALIZED;
2608 }
2609
2610 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2611 {
2612 return DPERR_INVALIDPLAYER;
2613 }
2614
2615 /* How much buffer is required? */
2616 if( dwFlags & DPSET_LOCAL )
2617 {
2618 dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
2619 lpCopyDataFrom = lpPList->lpPData->lpLocalData;
2620 }
2621 else
2622 {
2623 dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
2624 lpCopyDataFrom = lpPList->lpPData->lpRemoteData;
2625 }
2626
2627 /* Is the user requesting to know how big a buffer is required? */
2628 if( ( lpData == NULL ) ||
2629 ( *lpdwDataSize < dwRequiredBufferSize )
2630 )
2631 {
2632 *lpdwDataSize = dwRequiredBufferSize;
2633 return DPERR_BUFFERTOOSMALL;
2634 }
2635
2636 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2637
2638 return DP_OK;
2639 }
2640
2641 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
2642 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2643 LPDWORD lpdwDataSize, DWORD dwFlags )
2644 {
2645 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2646 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2647 dwFlags, TRUE );
2648 }
2649
2650 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
2651 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2652 LPDWORD lpdwDataSize, DWORD dwFlags )
2653 {
2654 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2655 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2656 dwFlags, FALSE );
2657 }
2658
2659 static HRESULT WINAPI DP_IF_GetPlayerName
2660 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2661 LPDWORD lpdwDataSize, BOOL bAnsi )
2662 {
2663 lpPlayerList lpPList;
2664 LPDPNAME lpName = (LPDPNAME)lpData;
2665 DWORD dwRequiredDataSize;
2666
2667 FIXME( "(%p)->(0x%08lx,%p,%p,%u): ANSI \n",
2668 This, idPlayer, lpData, lpdwDataSize, bAnsi );
2669
2670 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2671 {
2672 return DPERR_INVALIDPLAYER;
2673 }
2674
2675 dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2676
2677 if( lpPList->lpPData->name.u1.lpszShortNameA )
2678 {
2679 dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2680 }
2681
2682 if( lpPList->lpPData->name.u2.lpszLongNameA )
2683 {
2684 dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2685 }
2686
2687 if( ( lpData == NULL ) ||
2688 ( *lpdwDataSize < dwRequiredDataSize )
2689 )
2690 {
2691 *lpdwDataSize = dwRequiredDataSize;
2692 return DPERR_BUFFERTOOSMALL;
2693 }
2694
2695 /* Copy the structure */
2696 CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2697
2698 if( lpPList->lpPData->name.u1.lpszShortNameA )
2699 {
2700 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2701 lpPList->lpPData->name.u1.lpszShortNameA );
2702 }
2703 else
2704 {
2705 lpName->u1.lpszShortNameA = NULL;
2706 }
2707
2708 if( lpPList->lpPData->name.u1.lpszShortNameA )
2709 {
2710 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2711 lpPList->lpPData->name.u2.lpszLongNameA );
2712 }
2713 else
2714 {
2715 lpName->u2.lpszLongNameA = NULL;
2716 }
2717
2718 return DP_OK;
2719 }
2720
2721 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
2722 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2723 LPDWORD lpdwDataSize )
2724 {
2725 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2726 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2727 }
2728
2729 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2730 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2731 LPDWORD lpdwDataSize )
2732 {
2733 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2734 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2735 }
2736
2737 static HRESULT WINAPI DP_GetSessionDesc
2738 ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2739 BOOL bAnsi )
2740 {
2741 DWORD dwRequiredSize;
2742
2743 TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2744
2745 if( This->dp2->connectionInitialized == NO_PROVIDER )
2746 {
2747 return DPERR_UNINITIALIZED;
2748 }
2749
2750 if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
2751 {
2752 return DPERR_INVALIDPARAMS;
2753 }
2754
2755 /* FIXME: Get from This->dp2->lpSessionDesc */
2756 dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2757
2758 if ( ( lpData == NULL ) ||
2759 ( *lpdwDataSize < dwRequiredSize )
2760 )
2761 {
2762 *lpdwDataSize = dwRequiredSize;
2763 return DPERR_BUFFERTOOSMALL;
2764 }
2765
2766 DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2767
2768 return DP_OK;
2769 }
2770
2771 static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
2772 ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
2773 {
2774 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2775 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2776 }
2777
2778 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2779 ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2780 {
2781 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2782 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2783 }
2784
2785 /* Intended only for COM compatibility. Always returns an error. */
2786 static HRESULT WINAPI DirectPlay2AImpl_Initialize
2787 ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
2788 {
2789 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2790 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2791 return DPERR_ALREADYINITIALIZED;
2792 }
2793
2794 /* Intended only for COM compatibility. Always returns an error. */
2795 static HRESULT WINAPI DirectPlay2WImpl_Initialize
2796 ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
2797 {
2798 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2799 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2800 return DPERR_ALREADYINITIALIZED;
2801 }
2802
2803
2804 static HRESULT WINAPI DP_SecureOpen
2805 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2806 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
2807 BOOL bAnsi )
2808 {
2809 HRESULT hr = DP_OK;
2810
2811 FIXME( "(%p)->(%p,0x%08lx,%p,%p): partial stub\n",
2812 This, lpsd, dwFlags, lpSecurity, lpCredentials );
2813
2814 if( This->dp2->bConnectionOpen )
2815 {
2816 TRACE( ": rejecting already open connection.\n" );
2817 return DPERR_ALREADYINITIALIZED;
2818 }
2819
2820 /* If we're enumerating, kill the thread */
2821 DP_KillEnumSessionThread( This );
2822
2823 if( dwFlags & DPOPEN_CREATE )
2824 {
2825 /* Rightoo - this computer is the host and the local computer needs to be
2826 the name server so that others can join this session */
2827 NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
2828
2829 This->dp2->bHostInterface = TRUE;
2830
2831 hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
2832 if( FAILED( hr ) )
2833 {
2834 ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
2835 return hr;
2836 }
2837 }
2838
2839 /* Invoke the conditional callback for the service provider */
2840 if( This->dp2->spData.lpCB->Open )
2841 {
2842 DPSP_OPENDATA data;
2843
2844 FIXME( "Not all data fields are correct. Need new parameter\n" );
2845
2846 data.bCreate = (dwFlags & DPOPEN_CREATE ) ? TRUE : FALSE;
2847 data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
2848 : NS_GetNSAddr( This->dp2->lpNameServerData );
2849 data.lpISP = This->dp2->spData.lpISP;
2850 data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) ? TRUE : FALSE;
2851 data.dwOpenFlags = dwFlags;
2852 data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
2853
2854 hr = (*This->dp2->spData.lpCB->Open)(&data);
2855 if( FAILED( hr ) )
2856 {
2857 ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
2858 return hr;
2859 }
2860 }
2861
2862 {
2863 /* Create the system group of which everything is a part of */
2864 DPID systemGroup = DPID_SYSTEM_GROUP;
2865
2866 hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
2867 NULL, 0, 0, TRUE );
2868
2869 }
2870
2871 if( dwFlags & DPOPEN_JOIN )
2872 {
2873 DPID dpidServerId = DPID_UNKNOWN;
2874
2875 /* Create the server player for this interface. This way we can receive
2876 * messages for this session.
2877 */
2878 /* FIXME: I suppose that we should be setting an event for a receive
2879 * type of thing. That way the messaging thread could know to wake
2880 * up. DPlay would then trigger the hEvent for the player the
2881 * message is directed to.
2882 */
2883 hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
2884 0,
2885 DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
2886
2887 }
2888 else if( dwFlags & DPOPEN_CREATE )
2889 {
2890 DPID dpidNameServerId = DPID_NAME_SERVER;
2891
2892 hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
2893 0, DPPLAYER_SERVERPLAYER, bAnsi );
2894 }
2895
2896 if( FAILED(hr) )
2897 {
2898 ERR( "Couldn't create name server/system player: %s\n",
2899 DPLAYX_HresultToString(hr) );
2900 }
2901
2902 return hr;
2903 }
2904
2905 static HRESULT WINAPI DirectPlay2AImpl_Open
2906 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2907 {
2908 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2909 TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags );
2910 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE );
2911 }
2912
2913 static HRESULT WINAPI DirectPlay2WImpl_Open
2914 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2915 {
2916 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2917 TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags );
2918 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE );
2919 }
2920
2921 static HRESULT WINAPI DP_IF_Receive
2922 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
2923 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
2924 {
2925 LPDPMSG lpMsg = NULL;
2926
2927 FIXME( "(%p)->(%p,%p,0x%08lx,%p,%p,%u): stub\n",
2928 This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
2929
2930 if( This->dp2->connectionInitialized == NO_PROVIDER )
2931 {
2932 return DPERR_UNINITIALIZED;
2933 }
2934
2935 if( dwFlags == 0 )
2936 {
2937 dwFlags = DPRECEIVE_ALL;
2938 }
2939
2940 /* If the lpData is NULL, we must be peeking the message */
2941 if( ( lpData == NULL ) &&
2942 !( dwFlags & DPRECEIVE_PEEK )
2943 )
2944 {
2945 return DPERR_INVALIDPARAMS;
2946 }
2947
2948 if( dwFlags & DPRECEIVE_ALL )
2949 {
2950 lpMsg = This->dp2->receiveMsgs.lpQHFirst;
2951
2952 if( !( dwFlags & DPRECEIVE_PEEK ) )
2953 {
2954 FIXME( "Remove from queue\n" );
2955 }
2956 }
2957 else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
2958 ( dwFlags & DPRECEIVE_FROMPLAYER )
2959 )
2960 {
2961 FIXME( "Find matching message 0x%08lx\n", dwFlags );
2962 }
2963 else
2964 {
2965 ERR( "Hmmm..dwFlags 0x%08lx\n", dwFlags );
2966 }
2967
2968 if( lpMsg == NULL )
2969 {
2970 return DPERR_NOMESSAGES;
2971 }
2972
2973 /* Copy into the provided buffer */
2974 CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
2975
2976 return DP_OK;
2977 }
2978
2979 static HRESULT WINAPI DirectPlay2AImpl_Receive
2980 ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
2981 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2982 {
2983 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2984 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
2985 lpData, lpdwDataSize, TRUE );
2986 }
2987
2988 static HRESULT WINAPI DirectPlay2WImpl_Receive
2989 ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
2990 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2991 {
2992 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2993 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
2994 lpData, lpdwDataSize, FALSE );
2995 }
2996
2997 static HRESULT WINAPI DirectPlay2AImpl_Send
2998 ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
2999 {
3000 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3001 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3002 0, 0, NULL, NULL, TRUE );
3003 }
3004
3005 static HRESULT WINAPI DirectPlay2WImpl_Send
3006 ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3007 {
3008 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3009 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3010 0, 0, NULL, NULL, FALSE );
3011 }
3012
3013 static HRESULT WINAPI DP_IF_SetGroupData
3014 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
3015 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3016 {
3017 lpGroupData lpGData;
3018
3019 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u)\n",
3020 This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
3021
3022 /* Parameter check */
3023 if( ( lpData == NULL ) &&
3024 ( dwDataSize != 0 )
3025 )
3026 {
3027 return DPERR_INVALIDPARAMS;
3028 }
3029
3030 /* Find the pointer to the data for this player */
3031 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3032 {
3033 return DPERR_INVALIDOBJECT;
3034 }
3035
3036 if( !(dwFlags & DPSET_LOCAL) )
3037 {
3038 FIXME( "Was this group created by this interface?\n" );
3039 /* FIXME: If this is a remote update need to allow it but not
3040 * send a message.
3041 */
3042 }
3043
3044 DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
3045
3046 /* FIXME: Only send a message if this group is local to the session otherwise
3047 * it will have been rejected above
3048 */
3049 if( !(dwFlags & DPSET_LOCAL) )
3050 {
3051 FIXME( "Send msg?\n" );
3052 }
3053
3054 return DP_OK;
3055 }
3056
3057 static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
3058 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
3059 DWORD dwDataSize, DWORD dwFlags )
3060 {
3061 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3062 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
3063 }
3064
3065 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
3066 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
3067 DWORD dwDataSize, DWORD dwFlags )
3068 {
3069 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3070 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
3071 }
3072
3073 static HRESULT WINAPI DP_IF_SetGroupName
3074 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
3075 DWORD dwFlags, BOOL bAnsi )
3076 {
3077 lpGroupData lpGData;
3078
3079 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n", This, idGroup,
3080 lpGroupName, dwFlags, bAnsi );
3081
3082 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3083 {
3084 return DPERR_INVALIDGROUP;
3085 }
3086
3087 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3088
3089 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3090 FIXME( "Message not sent and dwFlags ignored\n" );
3091
3092 return DP_OK;
3093 }
3094
3095 static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
3096 ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
3097 DWORD dwFlags )
3098 {
3099 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3100 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3101 }
3102
3103 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
3104 ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
3105 DWORD dwFlags )
3106 {
3107 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3108 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3109 }
3110
3111 static HRESULT WINAPI DP_IF_SetPlayerData
3112 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
3113 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3114 {
3115 lpPlayerList lpPList;
3116
3117 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u)\n",
3118 This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
3119
3120 /* Parameter check */
3121 if( ( lpData == NULL ) &&
3122 ( dwDataSize != 0 )
3123 )
3124 {
3125 return DPERR_INVALIDPARAMS;
3126 }
3127
3128 /* Find the pointer to the data for this player */
3129 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3130 {
3131 return DPERR_INVALIDPLAYER;
3132 }
3133
3134 if( !(dwFlags & DPSET_LOCAL) )
3135 {
3136 FIXME( "Was this group created by this interface?\n" );
3137 /* FIXME: If this is a remote update need to allow it but not
3138 * send a message.
3139 */
3140 }
3141
3142 DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
3143
3144 if( !(dwFlags & DPSET_LOCAL) )
3145 {
3146 FIXME( "Send msg?\n" );
3147 }
3148
3149 return DP_OK;
3150 }
3151
3152 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
3153 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
3154 DWORD dwDataSize, DWORD dwFlags )
3155 {
3156 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3157 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3158 dwFlags, TRUE );
3159 }
3160
3161 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
3162 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
3163 DWORD dwDataSize, DWORD dwFlags )
3164 {
3165 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3166 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3167 dwFlags, FALSE );
3168 }
3169
3170 static HRESULT WINAPI DP_IF_SetPlayerName
3171 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
3172 DWORD dwFlags, BOOL bAnsi )
3173 {
3174 lpPlayerList lpPList;
3175
3176 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n",
3177 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3178
3179 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3180 {
3181 return DPERR_INVALIDGROUP;
3182 }
3183
3184 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3185
3186 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3187 FIXME( "Message not sent and dwFlags ignored\n" );
3188
3189 return DP_OK;
3190 }
3191
3192 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
3193 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
3194 DWORD dwFlags )
3195 {
3196 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3197 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3198 }
3199
3200 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
3201 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
3202 DWORD dwFlags )
3203 {
3204 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3205 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3206 }
3207
3208 static HRESULT WINAPI DP_SetSessionDesc
3209 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
3210 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
3211 {
3212 DWORD dwRequiredSize;
3213 LPDPSESSIONDESC2 lpTempSessDesc;
3214
3215 TRACE( "(%p)->(%p,0x%08lx,%u,%u)\n",
3216 This, lpSessDesc, dwFlags, bInitial, bAnsi );
3217
3218 if( This->dp2->connectionInitialized == NO_PROVIDER )
3219 {
3220 return DPERR_UNINITIALIZED;
3221 }
3222
3223 if( dwFlags )
3224 {
3225 return DPERR_INVALIDPARAMS;
3226 }
3227
3228 /* Only the host is allowed to update the session desc */
3229 if( !This->dp2->bHostInterface )
3230 {
3231 return DPERR_ACCESSDENIED;
3232 }
3233
3234 /* FIXME: Copy into This->dp2->lpSessionDesc */
3235 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3236 lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3237
3238 if( lpTempSessDesc == NULL )
3239 {
3240 return DPERR_OUTOFMEMORY;
3241 }
3242
3243 /* Free the old */
3244 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3245
3246 This->dp2->lpSessionDesc = lpTempSessDesc;
3247
3248 /* Set the new */
3249 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3250
3251 /* If this is an external invocation of the interface, we should be
3252 * letting everyone know that things have changed. Otherwise this is
3253 * just an initialization and it doesn't need to be propagated.
3254 */
3255 if( !bInitial )
3256 {
3257 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3258 }
3259
3260 return DP_OK;
3261 }
3262
3263 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
3264 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3265 {
3266 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3267 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3268 }
3269
3270 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
3271 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3272 {
3273 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3274 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3275 }
3276
3277 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3278 DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3279 {
3280 DWORD dwSize = 0;
3281
3282 if( lpSessDesc == NULL )
3283 {
3284 /* Hmmm..don't need any size? */
3285 ERR( "NULL lpSessDesc\n" );
3286 return dwSize;
3287 }
3288
3289 dwSize += sizeof( *lpSessDesc );