1 /* Direct Play 2,3,4 Implementation
2 *
3 * Copyright 1998,1999,2000,2001 - Peter Hunnisett
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include "config.h"
21 #include "wine/port.h"
22
23 #include <stdarg.h>
24 #include <string.h>
25
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28 #include "windef.h"
29 #include "winerror.h"
30 #include "winbase.h"
31 #include "winnt.h"
32 #include "winreg.h"
33 #include "winnls.h"
34 #include "wine/unicode.h"
35 #include "wine/debug.h"
36
37 #include "dpinit.h"
38 #include "dplayx_global.h"
39 #include "name_server.h"
40 #include "dplayx_queue.h"
41 #include "wine/dplaysp.h"
42 #include "dplay_global.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
45
46 /* FIXME: Should this be externed? */
47 extern HRESULT DPL_CreateCompoundAddress
48 ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
49 LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
50
51
52 /* Local function prototypes */
53 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid );
54 static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid,
55 LPDPNAME lpName, DWORD dwFlags,
56 HANDLE hEvent, BOOL bAnsi );
57 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi );
58 static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
59 LPVOID lpData, DWORD dwDataSize );
60
61 static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, const DPID *lpid,
62 const DPNAME *lpName, DWORD dwFlags,
63 DPID idParent, BOOL bAnsi );
64 static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
65 LPVOID lpData, DWORD dwDataSize );
66 static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
67 static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid );
68 static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
69 DWORD dwPlayerType,
70 LPCDPNAME lpName,
71 DWORD dwFlags,
72 LPVOID lpContext );
73 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
74 static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType,
75 LPCDPNAME lpName, DWORD dwFlags,
76 LPVOID lpContext );
77 static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
78
79 /* Forward declarations of virtual tables */
80 static const IDirectPlay2Vtbl directPlay2AVT;
81 static const IDirectPlay3Vtbl directPlay3AVT;
82 static const IDirectPlay4Vtbl directPlay4AVT;
83
84 static const IDirectPlay2Vtbl directPlay2WVT;
85 static const IDirectPlay3Vtbl directPlay3WVT;
86 static const IDirectPlay4Vtbl directPlay4WVT;
87
88 /* Helper methods for player/group interfaces */
89 static HRESULT DP_IF_DeletePlayerFromGroup
90 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
91 DPID idPlayer, BOOL bAnsi );
92 static HRESULT 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 DP_IF_DestroyGroup
97 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi );
98 static HRESULT DP_IF_DestroyPlayer
99 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi );
100 static HRESULT DP_IF_EnumGroupPlayers
101 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
102 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
103 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
104 static HRESULT DP_IF_EnumGroups
105 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
106 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
107 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
108 static HRESULT DP_IF_EnumPlayers
109 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
110 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
111 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
112 static HRESULT DP_IF_GetGroupData
113 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
114 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
115 static HRESULT DP_IF_GetGroupName
116 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
117 LPDWORD lpdwDataSize, BOOL bAnsi );
118 static HRESULT DP_IF_GetPlayerData
119 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
120 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
121 static HRESULT DP_IF_GetPlayerName
122 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
123 LPDWORD lpdwDataSize, BOOL bAnsi );
124 static HRESULT DP_IF_SetGroupName
125 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
126 DWORD dwFlags, BOOL bAnsi );
127 static HRESULT DP_IF_SetPlayerData
128 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
129 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
130 static HRESULT DP_IF_SetPlayerName
131 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
132 DWORD dwFlags, BOOL bAnsi );
133 static HRESULT DP_IF_AddGroupToGroup
134 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
135 static HRESULT 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 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 DP_IF_AddPlayerToGroup
144 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
145 DPID idPlayer, BOOL bAnsi );
146 static HRESULT DP_IF_DeleteGroupFromGroup
147 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
148 static HRESULT DP_SetSessionDesc
149 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
150 DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
151 static HRESULT DP_SecureOpen
152 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
153 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
154 BOOL bAnsi );
155 static HRESULT 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 DP_IF_Receive
160 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
161 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
162 static HRESULT DP_IF_GetMessageQueue
163 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
164 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
165 static HRESULT 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 DP_IF_SetGroupData
170 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
171 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
172 static HRESULT DP_IF_GetPlayerCaps
173 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
174 DWORD dwFlags );
175 static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi );
176 static HRESULT DP_IF_CancelMessage
177 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
178 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
179 static HRESULT DP_IF_EnumGroupsInGroup
180 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
181 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
182 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
183 static HRESULT DP_IF_GetGroupParent
184 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
185 BOOL bAnsi );
186 static HRESULT DP_IF_GetCaps
187 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
188 static HRESULT DP_IF_EnumSessions
189 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
190 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
191 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
192 static HRESULT 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 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 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi );
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 = lpDP;
238
239 This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) );
240 if ( This->unk == NULL )
241 {
242 return FALSE;
243 }
244
245 InitializeCriticalSection( &This->unk->DP_lock );
246 This->unk->DP_lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlay2AImpl*->DirectPlayIUnknownData*->DP_lock");
247
248 return TRUE;
249 }
250
251 static BOOL DP_DestroyIUnknown( LPVOID lpDP )
252 {
253 IDirectPlay2AImpl *This = lpDP;
254
255 This->unk->DP_lock.DebugInfo->Spare[0] = 0;
256 DeleteCriticalSection( &This->unk->DP_lock );
257 HeapFree( GetProcessHeap(), 0, This->unk );
258
259 return TRUE;
260 }
261
262 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
263 {
264 IDirectPlay2AImpl *This = lpDP;
265
266 This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
267 if ( This->dp2 == NULL )
268 {
269 return FALSE;
270 }
271
272 This->dp2->bConnectionOpen = FALSE;
273
274 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
275 This->dp2->dwEnumSessionLock = 0;
276
277 This->dp2->bHostInterface = FALSE;
278
279 DPQ_INIT(This->dp2->receiveMsgs);
280 DPQ_INIT(This->dp2->sendMsgs);
281 DPQ_INIT(This->dp2->replysExpected);
282
283 if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
284 {
285 /* FIXME: Memory leak */
286 return FALSE;
287 }
288
289 /* Provide an initial session desc with nothing in it */
290 This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
291 HEAP_ZERO_MEMORY,
292 sizeof( *This->dp2->lpSessionDesc ) );
293 if( This->dp2->lpSessionDesc == NULL )
294 {
295 /* FIXME: Memory leak */
296 return FALSE;
297 }
298 This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
299
300 /* We are emulating a dp 6 implementation */
301 This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
302
303 This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
304 sizeof( *This->dp2->spData.lpCB ) );
305 This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
306 This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
307
308 /* This is the pointer to the service provider */
309 if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
310 (LPVOID*)&This->dp2->spData.lpISP, This ) )
311 )
312 {
313 /* FIXME: Memory leak */
314 return FALSE;
315 }
316
317 /* Setup lobby provider information */
318 This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
319 This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
320 sizeof( *This->dp2->dplspData.lpCB ) );
321 This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB );
322
323 if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
324 (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
325 )
326 {
327 /* FIXME: Memory leak */
328 return FALSE;
329 }
330
331 return TRUE;
332 }
333
334 /* Definition of the global function in dplayx_queue.h. #
335 * FIXME: Would it be better to have a dplayx_queue.c for this function? */
336 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
337 {
338 HeapFree( GetProcessHeap(), 0, elem );
339 }
340
341 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
342 {
343 IDirectPlay2AImpl *This = lpDP;
344
345 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
346 {
347 TerminateThread( This->dp2->hEnumSessionThread, 0 );
348 CloseHandle( This->dp2->hEnumSessionThread );
349 }
350
351 /* Finish with the SP - have it shutdown */
352 if( This->dp2->spData.lpCB->ShutdownEx )
353 {
354 DPSP_SHUTDOWNDATA data;
355
356 TRACE( "Calling SP ShutdownEx\n" );
357
358 data.lpISP = This->dp2->spData.lpISP;
359
360 (*This->dp2->spData.lpCB->ShutdownEx)( &data );
361 }
362 else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
363 {
364 TRACE( "Calling obsolete SP Shutdown\n" );
365 (*This->dp2->spData.lpCB->Shutdown)();
366 }
367
368 /* Unload the SP (if it exists) */
369 if( This->dp2->hServiceProvider != 0 )
370 {
371 FreeLibrary( This->dp2->hServiceProvider );
372 }
373
374 /* Unload the Lobby Provider (if it exists) */
375 if( This->dp2->hDPLobbyProvider != 0 )
376 {
377 FreeLibrary( This->dp2->hDPLobbyProvider );
378 }
379
380 /* FIXME: Need to delete receive and send msgs queue contents */
381
382 NS_DeleteSessionCache( This->dp2->lpNameServerData );
383
384 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
385
386 IDirectPlaySP_Release( This->dp2->spData.lpISP );
387
388 /* Delete the contents */
389 HeapFree( GetProcessHeap(), 0, This->dp2 );
390
391 return TRUE;
392 }
393
394 static BOOL DP_CreateDirectPlay3( LPVOID lpDP )
395 {
396 IDirectPlay3AImpl *This = lpDP;
397
398 This->dp3 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp3) ) );
399 if ( This->dp3 == NULL )
400 {
401 return FALSE;
402 }
403
404 return TRUE;
405 }
406
407 static BOOL DP_DestroyDirectPlay3( LPVOID lpDP )
408 {
409 IDirectPlay3AImpl *This = lpDP;
410
411 /* Delete the contents */
412 HeapFree( GetProcessHeap(), 0, This->dp3 );
413
414 return TRUE;
415 }
416
417 static BOOL DP_CreateDirectPlay4( LPVOID lpDP )
418 {
419 IDirectPlay4AImpl *This = lpDP;
420
421 This->dp4 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp4) ) );
422 if ( This->dp4 == NULL )
423 {
424 return FALSE;
425 }
426
427 return TRUE;
428 }
429
430 static BOOL DP_DestroyDirectPlay4( LPVOID lpDP )
431 {
432 IDirectPlay3AImpl *This = lpDP;
433
434 /* Delete the contents */
435 HeapFree( GetProcessHeap(), 0, This->dp4 );
436
437 return TRUE;
438 }
439
440
441 /* Create a new interface */
442 HRESULT DP_CreateInterface
443 ( REFIID riid, LPVOID* ppvObj )
444 {
445 TRACE( " for %s\n", debugstr_guid( riid ) );
446
447 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
448 sizeof( IDirectPlay2Impl ) );
449
450 if( *ppvObj == NULL )
451 {
452 return DPERR_OUTOFMEMORY;
453 }
454
455 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
456 {
457 IDirectPlay2Impl *This = *ppvObj;
458 This->lpVtbl = &directPlay2WVT;
459 }
460 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
461 {
462 IDirectPlay2AImpl *This = *ppvObj;
463 This->lpVtbl = &directPlay2AVT;
464 }
465 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
466 {
467 IDirectPlay3Impl *This = *ppvObj;
468 This->lpVtbl = &directPlay3WVT;
469 }
470 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
471 {
472 IDirectPlay3AImpl *This = *ppvObj;
473 This->lpVtbl = &directPlay3AVT;
474 }
475 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
476 {
477 IDirectPlay4Impl *This = *ppvObj;
478 This->lpVtbl = &directPlay4WVT;
479 }
480 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
481 {
482 IDirectPlay4AImpl *This = *ppvObj;
483 This->lpVtbl = &directPlay4AVT;
484 }
485 else
486 {
487 /* Unsupported interface */
488 HeapFree( GetProcessHeap(), 0, *ppvObj );
489 *ppvObj = NULL;
490
491 return E_NOINTERFACE;
492 }
493
494 /* Initialize it */
495 if ( DP_CreateIUnknown( *ppvObj ) &&
496 DP_CreateDirectPlay2( *ppvObj ) &&
497 DP_CreateDirectPlay3( *ppvObj ) &&
498 DP_CreateDirectPlay4( *ppvObj )
499 )
500 {
501 IDirectPlayX_AddRef( (LPDIRECTPLAY2A)*ppvObj );
502
503 return S_OK;
504 }
505
506 /* Initialize failed, destroy it */
507 DP_DestroyDirectPlay4( *ppvObj );
508 DP_DestroyDirectPlay3( *ppvObj );
509 DP_DestroyDirectPlay2( *ppvObj );
510 DP_DestroyIUnknown( *ppvObj );
511
512 HeapFree( GetProcessHeap(), 0, *ppvObj );
513
514 *ppvObj = NULL;
515 return DPERR_NOMEMORY;
516 }
517
518
519 /* Direct Play methods */
520
521 /* Shared between all dplay types */
522 static HRESULT WINAPI DP_QueryInterface
523 ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj )
524 {
525 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
526 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
527
528 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
529 sizeof( *This ) );
530
531 if( *ppvObj == NULL )
532 {
533 return DPERR_OUTOFMEMORY;
534 }
535
536 CopyMemory( *ppvObj, This, sizeof( *This ) );
537 (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
538
539 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
540 {
541 IDirectPlay2Impl *This = *ppvObj;
542 This->lpVtbl = &directPlay2WVT;
543 }
544 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
545 {
546 IDirectPlay2AImpl *This = *ppvObj;
547 This->lpVtbl = &directPlay2AVT;
548 }
549 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
550 {
551 IDirectPlay3Impl *This = *ppvObj;
552 This->lpVtbl = &directPlay3WVT;
553 }
554 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
555 {
556 IDirectPlay3AImpl *This = *ppvObj;
557 This->lpVtbl = &directPlay3AVT;
558 }
559 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
560 {
561 IDirectPlay4Impl *This = *ppvObj;
562 This->lpVtbl = &directPlay4WVT;
563 }
564 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
565 {
566 IDirectPlay4AImpl *This = *ppvObj;
567 This->lpVtbl = &directPlay4AVT;
568 }
569 else
570 {
571 /* Unsupported interface */
572 HeapFree( GetProcessHeap(), 0, *ppvObj );
573 *ppvObj = NULL;
574
575 return E_NOINTERFACE;
576 }
577
578 IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj );
579
580 return S_OK;
581 }
582
583 /* Shared between all dplay types */
584 static ULONG WINAPI DP_AddRef
585 ( LPDIRECTPLAY3 iface )
586 {
587 ULONG ulInterfaceRefCount, ulObjRefCount;
588 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
589
590 ulObjRefCount = InterlockedIncrement( &This->unk->ulObjRef );
591 ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
592
593 TRACE( "ref count incremented to %u:%u for %p\n",
594 ulInterfaceRefCount, ulObjRefCount, This );
595
596 return ulObjRefCount;
597 }
598
599 static ULONG WINAPI DP_Release
600 ( LPDIRECTPLAY3 iface )
601 {
602 ULONG ulInterfaceRefCount, ulObjRefCount;
603
604 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
605
606 ulObjRefCount = InterlockedDecrement( &This->unk->ulObjRef );
607 ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
608
609 TRACE( "ref count decremented to %u:%u for %p\n",
610 ulInterfaceRefCount, ulObjRefCount, This );
611
612 /* Deallocate if this is the last reference to the object */
613 if( ulObjRefCount == 0 )
614 {
615 /* If we're destroying the object, this must be the last ref
616 of the last interface */
617 DP_DestroyDirectPlay4( This );
618 DP_DestroyDirectPlay3( This );
619 DP_DestroyDirectPlay2( This );
620 DP_DestroyIUnknown( This );
621 }
622
623 /* Deallocate the interface */
624 if( ulInterfaceRefCount == 0 )
625 {
626 HeapFree( GetProcessHeap(), 0, This );
627 }
628
629 return ulObjRefCount;
630 }
631
632 static inline DPID DP_NextObjectId(void)
633 {
634 return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
635 }
636
637 /* *lplpReply will be non NULL iff there is something to reply */
638 HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
639 DWORD dwMessageBodySize, LPCVOID lpcMessageHeader,
640 WORD wCommandId, WORD wVersion,
641 LPVOID* lplpReply, LPDWORD lpdwMsgSize )
642 {
643 TRACE( "(%p)->(%p,0x%08x,%p,%u,%u)\n",
644 This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
645 wVersion );
646
647 switch( wCommandId )
648 {
649 /* Name server needs to handle this request */
650 case DPMSGCMD_ENUMSESSIONSREQUEST:
651 {
652 /* Reply expected */
653 NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
654
655 break;
656 }
657
658 /* Name server needs to handle this request */
659 case DPMSGCMD_ENUMSESSIONSREPLY:
660 {
661 /* No reply expected */
662 NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
663 This->dp2->spData.dwSPHeaderSize,
664 lpcMessageBody,
665 This->dp2->lpNameServerData );
666 break;
667 }
668
669 case DPMSGCMD_REQUESTNEWPLAYERID:
670 {
671 LPCDPMSG_REQUESTNEWPLAYERID lpcMsg = lpcMessageBody;
672
673 LPDPMSG_NEWPLAYERIDREPLY lpReply;
674
675 *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
676
677 *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
678
679 FIXME( "Ignoring dwFlags 0x%08x in request msg\n",
680 lpcMsg->dwFlags );
681
682 /* Setup the reply */
683 lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
684 This->dp2->spData.dwSPHeaderSize );
685
686 lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
687 lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
688 lpReply->envelope.wVersion = DPMSGVER_DP6;
689
690 lpReply->dpidNewPlayerId = DP_NextObjectId();
691
692 TRACE( "Allocating new playerid 0x%08x from remote request\n",
693 lpReply->dpidNewPlayerId );
694
695 break;
696 }
697
698 case DPMSGCMD_GETNAMETABLEREPLY:
699 case DPMSGCMD_NEWPLAYERIDREPLY:
700 {
701
702 #if 0
703 if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
704 DebugBreak();
705 #endif
706 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
707
708 break;
709 }
710
711 #if 1
712 case DPMSGCMD_JUSTENVELOPE:
713 {
714 TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08x\n", lpcMessageHeader, ((const DWORD *)lpcMessageHeader)[1] );
715 NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
716 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
717 }
718 #endif
719
720 case DPMSGCMD_FORWARDADDPLAYER:
721 {
722 #if 0
723 DebugBreak();
724 #endif
725 #if 1
726 TRACE( "Sending message to self to get my addr\n" );
727 DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
728 #endif
729 break;
730 }
731
732 case DPMSGCMD_FORWARDADDPLAYERNACK:
733 {
734 DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
735 break;
736 }
737
738 default:
739 {
740 FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
741 DebugBreak();
742 break;
743 }
744 }
745
746 /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
747
748 return DP_OK;
749 }
750
751
752 static HRESULT DP_IF_AddPlayerToGroup
753 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
754 DPID idPlayer, BOOL bAnsi )
755 {
756 lpGroupData lpGData;
757 lpPlayerList lpPList;
758 lpPlayerList lpNewPList;
759
760 TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
761 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
762
763 if( This->dp2->connectionInitialized == NO_PROVIDER )
764 {
765 return DPERR_UNINITIALIZED;
766 }
767
768 /* Find the group */
769 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
770 {
771 return DPERR_INVALIDGROUP;
772 }
773
774 /* Find the player */
775 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
776 {
777 return DPERR_INVALIDPLAYER;
778 }
779
780 /* Create a player list (ie "shortcut" ) */
781 lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
782 if( lpNewPList == NULL )
783 {
784 return DPERR_CANTADDPLAYER;
785 }
786
787 /* Add the shortcut */
788 lpPList->lpPData->uRef++;
789 lpNewPList->lpPData = lpPList->lpPData;
790
791 /* Add the player to the list of players for this group */
792 DPQ_INSERT(lpGData->players,lpNewPList,players);
793
794 /* Let the SP know that we've added a player to the group */
795 if( This->dp2->spData.lpCB->AddPlayerToGroup )
796 {
797 DPSP_ADDPLAYERTOGROUPDATA data;
798
799 TRACE( "Calling SP AddPlayerToGroup\n" );
800
801 data.idPlayer = idPlayer;
802 data.idGroup = idGroup;
803 data.lpISP = This->dp2->spData.lpISP;
804
805 (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
806 }
807
808 /* Inform all other peers of the addition of player to the group. If there are
809 * no peers keep this event quiet.
810 * Also, if this event was the result of another machine sending it to us,
811 * don't bother rebroadcasting it.
812 */
813 if( ( lpMsgHdr == NULL ) &&
814 This->dp2->lpSessionDesc &&
815 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
816 {
817 DPMSG_ADDPLAYERTOGROUP msg;
818 msg.dwType = DPSYS_ADDPLAYERTOGROUP;
819
820 msg.dpIdGroup = idGroup;
821 msg.dpIdPlayer = idPlayer;
822
823 /* FIXME: Correct to just use send effectively? */
824 /* FIXME: Should size include data w/ message or just message "header" */
825 /* FIXME: Check return code */
826 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
827 }
828
829 return DP_OK;
830 }
831
832 static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
833 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
834 {
835 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
836 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
837 }
838
839 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
840 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
841 {
842 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
843 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
844 }
845
846 static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
847 {
848 HRESULT hr = DP_OK;
849
850 TRACE("(%p)->(%u)\n", This, bAnsi );
851
852 /* FIXME: Need to find a new host I assume (how?) */
853 /* FIXME: Need to destroy all local groups */
854 /* FIXME: Need to migrate all remotely visible players to the new host */
855
856 /* Invoke the SP callback to inform of session close */
857 if( This->dp2->spData.lpCB->CloseEx )
858 {
859 DPSP_CLOSEDATA data;
860
861 TRACE( "Calling SP CloseEx\n" );
862
863 data.lpISP = This->dp2->spData.lpISP;
864
865 hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
866
867 }
868 else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
869 {
870 TRACE( "Calling SP Close (obsolete interface)\n" );
871
872 hr = (*This->dp2->spData.lpCB->Close)();
873 }
874
875 return hr;
876 }
877
878 static HRESULT WINAPI DirectPlay2AImpl_Close
879 ( LPDIRECTPLAY2A iface )
880 {
881 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
882 return DP_IF_Close( This, TRUE );
883 }
884
885 static HRESULT WINAPI DirectPlay2WImpl_Close
886 ( LPDIRECTPLAY2 iface )
887 {
888 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
889 return DP_IF_Close( This, FALSE );
890 }
891
892 static
893 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, const DPID *lpid,
894 const DPNAME *lpName, DWORD dwFlags,
895 DPID idParent, BOOL bAnsi )
896 {
897 lpGroupData lpGData;
898
899 /* Allocate the new space and add to end of high level group list */
900 lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
901
902 if( lpGData == NULL )
903 {
904 return NULL;
905 }
906
907 DPQ_INIT(lpGData->groups);
908 DPQ_INIT(lpGData->players);
909
910 /* Set the desired player ID - no sanity checking to see if it exists */
911 lpGData->dpid = *lpid;
912
913 DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
914
915 /* FIXME: Should we check that the parent exists? */
916 lpGData->parent = idParent;
917
918 /* FIXME: Should we validate the dwFlags? */
919 lpGData->dwFlags = dwFlags;
920
921 TRACE( "Created group id 0x%08x\n", *lpid );
922
923 return lpGData;
924 }
925
926 /* This method assumes that all links to it are already deleted */
927 static void
928 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
929 {
930 lpGroupList lpGList;
931
932 TRACE( "(%p)->(0x%08x)\n", This, dpid );
933
934 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
935
936 if( lpGList == NULL )
937 {
938 ERR( "DPID 0x%08x not found\n", dpid );
939 return;
940 }
941
942 if( --(lpGList->lpGData->uRef) )
943 {
944 FIXME( "Why is this not the last reference to group?\n" );
945 DebugBreak();
946 }
947
948 /* Delete player */
949 DP_DeleteDPNameStruct( &lpGList->lpGData->name );
950 HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
951
952 /* Remove and Delete Player List object */
953 HeapFree( GetProcessHeap(), 0, lpGList );
954
955 }
956
957 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
958 {
959 lpGroupList lpGroups;
960
961 TRACE( "(%p)->(0x%08x)\n", This, dpid );
962
963 if( dpid == DPID_SYSTEM_GROUP )
964 {
965 return This->dp2->lpSysGroup;
966 }
967 else
968 {
969 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
970 }
971
972 if( lpGroups == NULL )
973 {
974 return NULL;
975 }
976
977 return lpGroups->lpGData;
978 }
979
980 static HRESULT DP_IF_CreateGroup
981 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
982 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
983 DWORD dwFlags, BOOL bAnsi )
984 {
985 lpGroupData lpGData;
986
987 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
988 This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
989 dwFlags, bAnsi );
990
991 if( This->dp2->connectionInitialized == NO_PROVIDER )
992 {
993 return DPERR_UNINITIALIZED;
994 }
995
996 /* If the name is not specified, we must provide one */
997 if( DPID_UNKNOWN == *lpidGroup )
998 {
999 /* If we are the name server, we decide on the group ids. If not, we
1000 * must ask for one before attempting a creation.
1001 */
1002 if( This->dp2->bHostInterface )
1003 {
1004 *lpidGroup = DP_NextObjectId();
1005 }
1006 else
1007 {
1008 *lpidGroup = DP_GetRemoteNextObjectId();
1009 }
1010 }
1011
1012 lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
1013 DPID_NOPARENT_GROUP, bAnsi );
1014
1015 if( lpGData == NULL )
1016 {
1017 return DPERR_CANTADDPLAYER; /* yes player not group */
1018 }
1019
1020 if( DPID_SYSTEM_GROUP == *lpidGroup )
1021 {
1022 This->dp2->lpSysGroup = lpGData;
1023 TRACE( "Inserting system group\n" );
1024 }
1025 else
1026 {
1027 /* Insert into the system group */
1028 lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
1029 lpGroup->lpGData = lpGData;
1030
1031 DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
1032 }
1033
1034 /* Something is now referencing this data */
1035 lpGData->uRef++;
1036
1037 /* Set all the important stuff for the group */
1038 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
1039
1040 /* FIXME: We should only create the system group if GetCaps returns
1041 * DPCAPS_GROUPOPTIMIZED.
1042 */
1043
1044 /* Let the SP know that we've created this group */
1045 if( This->dp2->spData.lpCB->CreateGroup )
1046 {
1047 DPSP_CREATEGROUPDATA data;
1048 DWORD dwCreateFlags = 0;
1049
1050 TRACE( "Calling SP CreateGroup\n" );
1051
1052 if( *lpidGroup == DPID_NOPARENT_GROUP )
1053 dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
1054
1055 if( lpMsgHdr == NULL )
1056 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1057
1058 if( dwFlags & DPGROUP_HIDDEN )
1059 dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
1060
1061 data.idGroup = *lpidGroup;
1062 data.dwFlags = dwCreateFlags;
1063 data.lpSPMessageHeader = lpMsgHdr;
1064 data.lpISP = This->dp2->spData.lpISP;
1065
1066 (*This->dp2->spData.lpCB->CreateGroup)( &data );
1067 }
1068
1069 /* Inform all other peers of the creation of a new group. If there are
1070 * no peers keep this event quiet.
1071 * Also if this message was sent to us, don't rebroadcast.
1072 */
1073 if( ( lpMsgHdr == NULL ) &&
1074 This->dp2->lpSessionDesc &&
1075 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1076 {
1077 DPMSG_CREATEPLAYERORGROUP msg;
1078 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1079
1080 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
1081 msg.dpId = *lpidGroup;
1082 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
1083 msg.lpData = lpData;
1084 msg.dwDataSize = dwDataSize;
1085 msg.dpnName = *lpGroupName;
1086 msg.dpIdParent = DPID_NOPARENT_GROUP;
1087 msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
1088
1089 /* FIXME: Correct to just use send effectively? */
1090 /* FIXME: Should size include data w/ message or just message "header" */
1091 /* FIXME: Check return code */
1092 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
1093 0, 0, NULL, NULL, bAnsi );
1094 }
1095
1096 return DP_OK;
1097 }
1098
1099 static HRESULT WINAPI DirectPlay2AImpl_CreateGroup
1100 ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1101 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1102 {
1103 *lpidGroup = DPID_UNKNOWN;
1104
1105 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1106 lpGroupName, lpData, dwDataSize, dwFlags, TRUE );
1107 }
1108
1109 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
1110 ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1111 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1112 {
1113 *lpidGroup = DPID_UNKNOWN;
1114
1115 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1116 lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
1117 }
1118
1119
1120 static void
1121 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
1122 LPVOID lpData, DWORD dwDataSize )
1123 {
1124 /* Clear out the data with this player */
1125 if( dwFlags & DPSET_LOCAL )
1126 {
1127 if ( lpGData->dwLocalDataSize != 0 )
1128 {
1129 HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
1130 lpGData->lpLocalData = NULL;
1131 lpGData->dwLocalDataSize = 0;
1132 }
1133 }
1134 else
1135 {
1136 if( lpGData->dwRemoteDataSize != 0 )
1137 {
1138 HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
1139 lpGData->lpRemoteData = NULL;
1140 lpGData->dwRemoteDataSize = 0;
1141 }
1142 }
1143
1144 /* Reallocate for new data */
1145 if( lpData != NULL )
1146 {
1147 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1148 sizeof( dwDataSize ) );
1149 CopyMemory( lpNewData, lpData, dwDataSize );
1150
1151 if( dwFlags & DPSET_LOCAL )
1152 {
1153 lpGData->lpLocalData = lpData;
1154 lpGData->dwLocalDataSize = dwDataSize;
1155 }
1156 else
1157 {
1158 lpGData->lpRemoteData = lpNewData;
1159 lpGData->dwRemoteDataSize = dwDataSize;
1160 }
1161 }
1162
1163 }
1164
1165 /* This function will just create the storage for the new player. */
1166 static
1167 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
1168 LPDPNAME lpName, DWORD dwFlags,
1169 HANDLE hEvent, BOOL bAnsi )
1170 {
1171 lpPlayerData lpPData;
1172
1173 TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
1174
1175 /* Allocate the storage for the player and associate it with list element */
1176 lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
1177 if( lpPData == NULL )
1178 {
1179 return NULL;
1180 }
1181
1182 /* Set the desired player ID */
1183 lpPData->dpid = *lpid;
1184
1185 DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1186
1187 lpPData->dwFlags = dwFlags;
1188
1189 /* If we were given an event handle, duplicate it */
1190 if( hEvent != 0 )
1191 {
1192 if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1193 GetCurrentProcess(), &lpPData->hEvent,
1194 0, FALSE, DUPLICATE_SAME_ACCESS )
1195 )
1196 {
1197 /* FIXME: Memory leak */
1198 ERR( "Can't duplicate player msg handle %p\n", hEvent );
1199 }
1200 }
1201
1202 /* Initialize the SP data section */
1203 lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1204
1205 TRACE( "Created player id 0x%08x\n", *lpid );
1206
1207 if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
1208 This->dp2->lpSessionDesc->dwCurrentPlayers++;
1209
1210 return lpPData;
1211 }
1212
1213 /* Delete the contents of the DPNAME struct */
1214 static void
1215 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1216 {
1217 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
1218 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1219 }
1220
1221 /* This method assumes that all links to it are already deleted */
1222 static void
1223 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1224 {
1225 lpPlayerList lpPList;
1226
1227 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1228
1229 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1230
1231 if( lpPList == NULL )
1232 {
1233 ERR( "DPID 0x%08x not found\n", dpid );
1234 return;
1235 }
1236
1237 /* Verify that this is the last reference to the data */
1238 if( --(lpPList->lpPData->uRef) )
1239 {
1240 FIXME( "Why is this not the last reference to player?\n" );
1241 DebugBreak();
1242 }
1243
1244 /* Delete player */
1245 DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1246
1247 CloseHandle( lpPList->lpPData->hEvent );
1248 HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1249
1250 /* Delete Player List object */
1251 HeapFree( GetProcessHeap(), 0, lpPList );
1252 }
1253
1254 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1255 {
1256 lpPlayerList lpPlayers;
1257
1258 TRACE( "(%p)->(0x%08x)\n", This, dpid );
1259
1260 if(This->dp2->lpSysGroup == NULL)
1261 return NULL;
1262
1263 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1264
1265 return lpPlayers;
1266 }
1267
1268 /* Basic area for Dst must already be allocated */
1269 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi )
1270 {
1271 if( lpSrc == NULL )
1272 {
1273 ZeroMemory( lpDst, sizeof( *lpDst ) );
1274 lpDst->dwSize = sizeof( *lpDst );
1275 return TRUE;
1276 }
1277
1278 if( lpSrc->dwSize != sizeof( *lpSrc) )
1279 {
1280 return FALSE;
1281 }
1282
1283 /* Delete any existing pointers */
1284 HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
1285 HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1286
1287 /* Copy as required */
1288 CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1289
1290 if( bAnsi )
1291 {
1292 if( lpSrc->u1.lpszShortNameA )
1293 {
1294 lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1295 strlen(lpSrc->u1.lpszShortNameA)+1 );
1296 strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1297 }
1298 if( lpSrc->u2.lpszLongNameA )
1299 {
1300 lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1301 strlen(lpSrc->u2.lpszLongNameA)+1 );
1302 strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1303 }
1304 }
1305 else
1306 {
1307 if( lpSrc->u1.lpszShortNameA )
1308 {
1309 lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1310 (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
1311 strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1312 }
1313 if( lpSrc->u2.lpszLongNameA )
1314 {
1315 lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1316 (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
1317 strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1318 }
1319 }
1320
1321 return TRUE;
1322 }
1323
1324 static void
1325 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1326 LPVOID lpData, DWORD dwDataSize )
1327 {
1328 /* Clear out the data with this player */
1329 if( dwFlags & DPSET_LOCAL )
1330 {
1331 if ( lpPData->dwLocalDataSize != 0 )
1332 {
1333 HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1334 lpPData->lpLocalData = NULL;
1335 lpPData->dwLocalDataSize = 0;
1336 }
1337 }
1338 else
1339 {
1340 if( lpPData->dwRemoteDataSize != 0 )
1341 {
1342 HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1343 lpPData->lpRemoteData = NULL;
1344 lpPData->dwRemoteDataSize = 0;
1345 }
1346 }
1347
1348 /* Reallocate for new data */
1349 if( lpData != NULL )
1350 {
1351 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1352 sizeof( dwDataSize ) );
1353 CopyMemory( lpNewData, lpData, dwDataSize );
1354
1355 if( dwFlags & DPSET_LOCAL )
1356 {
1357 lpPData->lpLocalData = lpData;
1358 lpPData->dwLocalDataSize = dwDataSize;
1359 }
1360 else
1361 {
1362 lpPData->lpRemoteData = lpNewData;
1363 lpPData->dwRemoteDataSize = dwDataSize;
1364 }
1365 }
1366
1367 }
1368
1369 static HRESULT DP_IF_CreatePlayer
1370 ( IDirectPlay2Impl* This,
1371 LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1372 LPDPID lpidPlayer,
1373 LPDPNAME lpPlayerName,
1374 HANDLE hEvent,
1375 LPVOID lpData,
1376 DWORD dwDataSize,
1377 DWORD dwFlags,
1378 BOOL bAnsi )
1379 {
1380 HRESULT hr = DP_OK;
1381 lpPlayerData lpPData;
1382 lpPlayerList lpPList;
1383 DWORD dwCreateFlags = 0;
1384
1385 TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1386 This, lpidPlayer, lpPlayerName, hEvent, lpData,
1387 dwDataSize, dwFlags, bAnsi );
1388 if( This->dp2->connectionInitialized == NO_PROVIDER )
1389 {
1390 return DPERR_UNINITIALIZED;
1391 }
1392
1393 if( dwFlags == 0 )
1394 {
1395 dwFlags = DPPLAYER_SPECTATOR;
1396 }
1397
1398 if( lpidPlayer == NULL )
1399 {
1400 return DPERR_INVALIDPARAMS;
1401 }
1402
1403
1404 /* Determine the creation flags for the player. These will be passed
1405 * to the name server if requesting a player id and to the SP when
1406 * informing it of the player creation
1407 */
1408 {
1409 if( dwFlags & DPPLAYER_SERVERPLAYER )
1410 {
1411 if( *lpidPlayer == DPID_SERVERPLAYER )
1412 {
1413 /* Server player for the host interface */
1414 dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1415 }
1416 else if( *lpidPlayer == DPID_NAME_SERVER )
1417 {
1418 /* Name server - master of everything */
1419 dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1420 }
1421 else
1422 {
1423 /* Server player for a non host interface */
1424 dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1425 }
1426 }
1427
1428 if( lpMsgHdr == NULL )
1429 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1430 }
1431
1432 /* Verify we know how to handle all the flags */
1433 if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1434 ( dwFlags & DPPLAYER_SPECTATOR )
1435 )
1436 )
1437 {
1438 /* Assume non fatal failure */
1439 ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1440 }
1441
1442 /* If the name is not specified, we must provide one */
1443 if( *lpidPlayer == DPID_UNKNOWN )
1444 {
1445 /* If we are the session master, we dish out the group/player ids */
1446 if( This->dp2->bHostInterface )
1447 {
1448 *lpidPlayer = DP_NextObjectId();
1449 }
1450 else
1451 {
1452 hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1453
1454 if( FAILED(hr) )
1455 {
1456 ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1457 return hr;
1458 }
1459 }
1460 }
1461 else
1462 {
1463 /* FIXME: Would be nice to perhaps verify that we don't already have
1464 * this player.
1465 */
1466 }
1467
1468 /* We pass creation flags, so we can distinguish sysplayers and not count them in the current
1469 player total */
1470 lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwCreateFlags,
1471 hEvent, bAnsi );
1472
1473 if( lpPData == NULL )
1474 {
1475 return DPERR_CANTADDPLAYER;
1476 }
1477
1478 /* Create the list object and link it in */
1479 lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1480 if( lpPList == NULL )
1481 {
1482 FIXME( "Memory leak\n" );
1483 return DPERR_CANTADDPLAYER;
1484 }
1485
1486 lpPData->uRef = 1;
1487 lpPList->lpPData = lpPData;
1488
1489 /* Add the player to the system group */
1490 DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1491
1492 /* Update the information and send it to all players in the session */
1493 DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1494
1495 /* Let the SP know that we've created this player */
1496 if( This->dp2->spData.lpCB->CreatePlayer )
1497 {
1498 DPSP_CREATEPLAYERDATA data;
1499
1500 data.idPlayer = *lpidPlayer;
1501 data.dwFlags = dwCreateFlags;
1502 data.lpSPMessageHeader = lpMsgHdr;
1503 data.lpISP = This->dp2->spData.lpISP;
1504
1505 TRACE( "Calling SP CreatePlayer 0x%08x: dwFlags: 0x%08x lpMsgHdr: %p\n",
1506 *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1507
1508 hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1509 }
1510
1511 if( FAILED(hr) )
1512 {
1513 ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1514 return hr;
1515 }
1516
1517 /* Now let the SP know that this player is a member of the system group */
1518 if( This->dp2->spData.lpCB->AddPlayerToGroup )
1519 {
1520 DPSP_ADDPLAYERTOGROUPDATA data;
1521
1522 data.idPlayer = *lpidPlayer;
1523 data.idGroup = DPID_SYSTEM_GROUP;
1524 data.lpISP = This->dp2->spData.lpISP;
1525
1526 TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1527
1528 hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1529 }
1530
1531 if( FAILED(hr) )
1532 {
1533 ERR( "Failed to add player to sys group with sp: %s\n",
1534 DPLAYX_HresultToString(hr) );
1535 return hr;
1536 }
1537
1538 #if 1
1539 if( This->dp2->bHostInterface == FALSE )
1540 {
1541 /* Let the name server know about the creation of this player */
1542 /* FIXME: Is this only to be done for the creation of a server player or
1543 * is this used for regular players? If only for server players, move
1544 * this call to DP_SecureOpen(...);
1545 */
1546 #if 0
1547 TRACE( "Sending message to self to get my addr\n" );
1548 DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1549 #endif
1550
1551 hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1552 }
1553 #else
1554 /* Inform all other peers of the creation of a new player. If there are
1555 * no peers keep this quiet.
1556 * Also, if this was a remote event, no need to rebroadcast it.
1557 */
1558 if( ( lpMsgHdr == NULL ) &&
1559 This->dp2->lpSessionDesc &&
1560 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1561 {
1562 DPMSG_CREATEPLAYERORGROUP msg;
1563 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1564
1565 msg.dwPlayerType = DPPLAYERTYPE_PLAYER;
1566 msg.dpId = *lpidPlayer;
1567 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1568 msg.lpData = lpData;
1569 msg.dwDataSize = dwDataSize;
1570 msg.dpnName = *lpPlayerName;
1571 msg.dpIdParent = DPID_NOPARENT_GROUP;
1572 msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1573
1574 /* FIXME: Correct to just use send effectively? */
1575 /* FIXME: Should size include data w/ message or just message "header" */
1576 /* FIXME: Check return code */
1577 hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1578 sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1579 }
1580 #endif
1581
1582 return hr;
1583 }
1584
1585 static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
1586 ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1587 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1588 {
1589 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1590
1591 if( lpidPlayer == NULL )
1592 {
1593 return DPERR_INVALIDPARAMS;
1594 }
1595
1596 if( dwFlags & DPPLAYER_SERVERPLAYER )
1597 {
1598 *lpidPlayer = DPID_SERVERPLAYER;
1599 }
1600 else
1601 {
1602 *lpidPlayer = DPID_UNKNOWN;
1603 }
1604
1605 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1606 lpData, dwDataSize, dwFlags, TRUE );
1607 }
1608
1609 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1610 ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1611 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1612 {
1613 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1614
1615 if( lpidPlayer == NULL )
1616 {
1617 return DPERR_INVALIDPARAMS;
1618 }
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 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%08x,0x%08x,%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%08x (type:0x%08x) from element:0x%08x\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%08x from group 0x%08x\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%08x from grp 0x%08x\n",
1753 dpId, lpCtxt->idGroup );
1754 }
1755 }
1756
1757 return TRUE; /* Continue enumeration */
1758 }
1759
1760 static HRESULT 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%08x,%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, &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 DP_IF_DestroyPlayer
1840 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1841 {
1842 DPFAGContext cbContext;
1843
1844 FIXME( "(%p)->(%p,0x%08x,%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 &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 lpContext, DPENUMGROUPS_ALL,
1912 lpCtxt->bAnsi );
1913
1914 }
1915 else
1916 {
1917 ERR( "Group callback has dwPlayerType = 0x%08x\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 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%08x,%p,%p,%p,0x%08x,%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 * consequence 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 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 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 = lpContext;
2122 HANDLE hSuicideRequest = data->hSuicideRequest;
2123 DWORD dwTimeout = data->dwTimeout;
2124
2125 TRACE( "Thread started with timeout = 0x%08x\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 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%08x,%p,%p,0x%08x,%u)\n",
2194 This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
2195 bAnsi );
2196 if( This->dp2->connectionInitialized == NO_PROVIDER )
2197 {
2198 return DPERR_UNINITIALIZED;
2199 }
2200
2201 /* Can't enumerate if the interface is already open */
2202 if( This->dp2->bConnectionOpen )
2203 {
2204 return DPERR_GENERIC;
2205 }
2206
2207 #if 1
2208 /* The loading of a lobby provider _seems_ to require a backdoor loading
2209 * of the service provider to also associate with this DP object. This is
2210 * because the app doesn't seem to have to call EnumConnections and
2211 * InitializeConnection for the SP before calling this method. As such
2212 * we'll do their dirty work for them with a quick hack so as to always
2213 * load the TCP/IP service provider.
2214 *
2215 * The correct solution would seem to involve creating a dialog box which
2216 * contains the possible SPs. These dialog boxes most likely follow SDK
2217 * examples.
2218 */
2219 if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2220 {
2221 LPVOID lpConnection;
2222 DWORD dwSize;
2223
2224 WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2225
2226 if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) )
2227 {
2228 ERR( "Can't build compound addr\n" );
2229 return DPERR_GENERIC;
2230 }
2231
2232 hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
2233 0, bAnsi );
2234 if( FAILED(hr) )
2235 {
2236 return hr;
2237 }
2238
2239 /* Free up the address buffer */
2240 HeapFree( GetProcessHeap(), 0, lpConnection );
2241
2242 /* The SP is now initialized */
2243 This->dp2->bSPInitialized = TRUE;
2244 }
2245 #endif
2246
2247
2248 /* Use the service provider default? */
2249 if( dwTimeout == 0 )
2250 {
2251 DPCAPS spCaps;
2252 spCaps.dwSize = sizeof( spCaps );
2253
2254 DP_IF_GetCaps( This, &spCaps, 0 );
2255 dwTimeout = spCaps.dwTimeout;
2256
2257 /* The service provider doesn't provide one either! */
2258 if( dwTimeout == 0 )
2259 {
2260 /* Provide the TCP/IP default */
2261 dwTimeout = DPMSG_WAIT_5_SECS;
2262 }
2263 }
2264
2265 if( dwFlags & DPENUMSESSIONS_STOPASYNC )
2266 {
2267 DP_KillEnumSessionThread( This );
2268 return hr;
2269 }
2270
2271 if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
2272 {
2273 /* Enumerate everything presently in the local session cache */
2274 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2275 This->dp2->lpNameServerData, dwTimeout,
2276 lpContext );
2277
2278 if( This->dp2->dwEnumSessionLock != 0 )
2279 return DPERR_CONNECTING;
2280
2281 /* See if we've already created a thread to service this interface */
2282 if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
2283 {
2284 DWORD dwThreadId;
2285 This->dp2->dwEnumSessionLock++;
2286
2287 /* Send the first enum request inline since the user may cancel a dialog
2288 * if one is presented. Also, may also have a connecting return code.
2289 */
2290 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2291 dwFlags, &This->dp2->spData );
2292
2293 if( SUCCEEDED(hr) )
2294 {
2295 EnumSessionAsyncCallbackData* lpData
2296 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpData ) );
2297 /* FIXME: need to kill the thread on object deletion */
2298 lpData->lpSpData = &This->dp2->spData;
2299
2300 lpData->requestGuid = lpsd->guidApplication;
2301 lpData->dwEnumSessionFlags = dwFlags;
2302 lpData->dwTimeout = dwTimeout;
2303
2304 This->dp2->hKillEnumSessionThreadEvent =
2305 CreateEventW( NULL, TRUE, FALSE, NULL );
2306
2307 if( !DuplicateHandle( GetCurrentProcess(),
2308 This->dp2->hKillEnumSessionThreadEvent,
2309 GetCurrentProcess(),
2310 &lpData->hSuicideRequest,
2311 0, FALSE, DUPLICATE_SAME_ACCESS )
2312 )
2313 {
2314 ERR( "Can't duplicate thread killing handle\n" );
2315 }
2316
2317 TRACE( ": creating EnumSessionsRequest thread\n" );
2318
2319 This->dp2->hEnumSessionThread = CreateThread( NULL,
2320 0,
2321 DP_EnumSessionsSendAsyncRequestThread,
2322 lpData,
2323 0,
2324 &dwThreadId );
2325 }
2326 This->dp2->dwEnumSessionLock--;
2327 }
2328 }
2329 else
2330 {
2331 /* Invalidate the session cache for the interface */
2332 NS_InvalidateSessionCache( This->dp2->lpNameServerData );
2333
2334 /* Send the broadcast for session enumeration */
2335 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2336 dwFlags,
2337 &This->dp2->spData );
2338
2339
2340 SleepEx( dwTimeout, FALSE );
2341
2342 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2343 This->dp2->lpNameServerData, dwTimeout,
2344 lpContext );
2345 }
2346
2347 return hr;
2348 }
2349
2350 static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
2351 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2352 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2353 LPVOID lpContext, DWORD dwFlags )
2354 {
2355 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2356 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2357 lpContext, dwFlags, TRUE );
2358 }
2359
2360 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
2361 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2362 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2363 LPVOID lpContext, DWORD dwFlags )
2364 {
2365 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2366 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2367 lpContext, dwFlags, FALSE );
2368 }
2369
2370 static HRESULT DP_IF_GetPlayerCaps
2371 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
2372 DWORD dwFlags )
2373 {
2374 DPSP_GETCAPSDATA data;
2375
2376 TRACE("(%p)->(0x%08x,%p,0x%08x)\n", This, idPlayer, lpDPCaps, dwFlags);
2377
2378 if ( This->dp2->connectionInitialized == NO_PROVIDER )
2379 {
2380 return DPERR_UNINITIALIZED;
2381 }
2382
2383 /* Query the service provider */
2384 data.idPlayer = idPlayer;
2385 data.dwFlags = dwFlags;
2386 data.lpCaps = lpDPCaps;
2387 data.lpISP = This->dp2->spData.lpISP;
2388
2389 return (*This->dp2->spData.lpCB->GetCaps)( &data );
2390 }
2391
2392 static HRESULT DP_IF_GetCaps
2393 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
2394 {
2395 return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
2396 }
2397
2398 static HRESULT WINAPI DirectPlay2AImpl_GetCaps
2399 ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2400 {
2401 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2402 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2403 }
2404
2405 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
2406 ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2407 {
2408 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2409 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2410 }
2411
2412 static HRESULT DP_IF_GetGroupData
2413 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2414 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2415 {
2416 lpGroupData lpGData;
2417 DWORD dwRequiredBufferSize;
2418 LPVOID lpCopyDataFrom;
2419
2420 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2421 This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
2422
2423 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2424 {
2425 return DPERR_INVALIDGROUP;
2426 }
2427
2428 /* How much buffer is required? */
2429 if( dwFlags & DPSET_LOCAL )
2430 {
2431 dwRequiredBufferSize = lpGData->dwLocalDataSize;
2432 lpCopyDataFrom = lpGData->lpLocalData;
2433 }
2434 else
2435 {
2436 dwRequiredBufferSize = lpGData->dwRemoteDataSize;
2437 lpCopyDataFrom = lpGData->lpRemoteData;
2438 }
2439
2440 /* Is the user requesting to know how big a buffer is required? */
2441 if( ( lpData == NULL ) ||
2442 ( *lpdwDataSize < dwRequiredBufferSize )
2443 )
2444 {
2445 *lpdwDataSize = dwRequiredBufferSize;
2446 return DPERR_BUFFERTOOSMALL;
2447 }
2448
2449 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2450
2451 return DP_OK;
2452 }
2453
2454 static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
2455 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2456 LPDWORD lpdwDataSize, DWORD dwFlags )
2457 {
2458 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2459 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2460 dwFlags, TRUE );
2461 }
2462
2463 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
2464 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2465 LPDWORD lpdwDataSize, DWORD dwFlags )
2466 {
2467 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2468 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2469 dwFlags, FALSE );
2470 }
2471
2472 static HRESULT DP_IF_GetGroupName
2473 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2474 LPDWORD lpdwDataSize, BOOL bAnsi )
2475 {
2476 lpGroupData lpGData;
2477 LPDPNAME lpName = lpData;
2478 DWORD dwRequiredDataSize;
2479
2480 FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2481 This, idGroup, lpData, lpdwDataSize, bAnsi );
2482
2483 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2484 {
2485 return DPERR_INVALIDGROUP;
2486 }
2487
2488 dwRequiredDataSize = lpGData->name.dwSize;
2489
2490 if( lpGData->name.u1.lpszShortNameA )
2491 {
2492 dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2493 }
2494
2495 if( lpGData->name.u2.lpszLongNameA )
2496 {
2497 dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2498 }
2499
2500 if( ( lpData == NULL ) ||
2501 ( *lpdwDataSize < dwRequiredDataSize )
2502 )
2503 {
2504 *lpdwDataSize = dwRequiredDataSize;
2505 return DPERR_BUFFERTOOSMALL;
2506 }
2507
2508 /* Copy the structure */
2509 CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2510
2511 if( lpGData->name.u1.lpszShortNameA )
2512 {
2513 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2514 lpGData->name.u1.lpszShortNameA );
2515 }
2516 else
2517 {
2518 lpName->u1.lpszShortNameA = NULL;
2519 }
2520
2521 if( lpGData->name.u1.lpszShortNameA )
2522 {
2523 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2524 lpGData->name.u2.lpszLongNameA );
2525 }
2526 else
2527 {
2528 lpName->u2.lpszLongNameA = NULL;
2529 }
2530
2531 return DP_OK;
2532 }
2533
2534 static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
2535 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2536 LPDWORD lpdwDataSize )
2537 {
2538 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2539 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2540 }
2541
2542 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2543 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2544 LPDWORD lpdwDataSize )
2545 {
2546 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2547 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2548 }
2549
2550 static HRESULT DP_IF_GetMessageCount
2551 ( IDirectPlay2Impl* This, DPID idPlayer,
2552 LPDWORD lpdwCount, BOOL bAnsi )
2553 {
2554 FIXME("(%p)->(0x%08x,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi );
2555 return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer,
2556 DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL,
2557 bAnsi );
2558 }
2559
2560 static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
2561 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
2562 {
2563 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2564 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE );
2565 }
2566
2567 static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
2568 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
2569 {
2570 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2571 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE );
2572 }
2573
2574 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
2575 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2576 {
2577 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2578 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2579 return DP_OK;
2580 }
2581
2582 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
2583 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2584 {
2585 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2586 FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2587 return DP_OK;
2588 }
2589
2590 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
2591 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2592 DWORD dwFlags )
2593 {
2594 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2595 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2596 }
2597
2598 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
2599 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2600 DWORD dwFlags )
2601 {
2602 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2603 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2604 }
2605
2606 static HRESULT DP_IF_GetPlayerData
2607 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2608 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2609 {
2610 lpPlayerList lpPList;
2611 DWORD dwRequiredBufferSize;
2612 LPVOID lpCopyDataFrom;
2613
2614 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2615 This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
2616
2617 if( This->dp2->connectionInitialized == NO_PROVIDER )
2618 {
2619 return DPERR_UNINITIALIZED;
2620 }
2621
2622 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2623 {
2624 return DPERR_INVALIDPLAYER;
2625 }
2626
2627 /* How much buffer is required? */
2628 if( dwFlags & DPSET_LOCAL )
2629 {
2630 dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
2631 lpCopyDataFrom = lpPList->lpPData->lpLocalData;
2632 }
2633 else
2634 {
2635 dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
2636 lpCopyDataFrom = lpPList->lpPData->lpRemoteData;
2637 }
2638
2639 /* Is the user requesting to know how big a buffer is required? */
2640 if( ( lpData == NULL ) ||
2641 ( *lpdwDataSize < dwRequiredBufferSize )
2642 )
2643 {
2644 *lpdwDataSize = dwRequiredBufferSize;
2645 return DPERR_BUFFERTOOSMALL;
2646 }
2647
2648 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2649
2650 return DP_OK;
2651 }
2652
2653 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
2654 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2655 LPDWORD lpdwDataSize, DWORD dwFlags )
2656 {
2657 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2658 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2659 dwFlags, TRUE );
2660 }
2661
2662 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
2663 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2664 LPDWORD lpdwDataSize, DWORD dwFlags )
2665 {
2666 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2667 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2668 dwFlags, FALSE );
2669 }
2670
2671 static HRESULT DP_IF_GetPlayerName
2672 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2673 LPDWORD lpdwDataSize, BOOL bAnsi )
2674 {
2675 lpPlayerList lpPList;
2676 LPDPNAME lpName = lpData;
2677 DWORD dwRequiredDataSize;
2678
2679 FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2680 This, idPlayer, lpData, lpdwDataSize, bAnsi );
2681
2682 if( This->dp2->connectionInitialized == NO_PROVIDER )
2683 {
2684 return DPERR_UNINITIALIZED;
2685 }
2686
2687 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2688 {
2689 return DPERR_INVALIDPLAYER;
2690 }
2691
2692 dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2693
2694 if( lpPList->lpPData->name.u1.lpszShortNameA )
2695 {
2696 dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2697 }
2698
2699 if( lpPList->lpPData->name.u2.lpszLongNameA )
2700 {
2701 dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2702 }
2703
2704 if( ( lpData == NULL ) ||
2705 ( *lpdwDataSize < dwRequiredDataSize )
2706 )
2707 {
2708 *lpdwDataSize = dwRequiredDataSize;
2709 return DPERR_BUFFERTOOSMALL;
2710 }
2711
2712 /* Copy the structure */
2713 CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2714
2715 if( lpPList->lpPData->name.u1.lpszShortNameA )
2716 {
2717 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2718 lpPList->lpPData->name.u1.lpszShortNameA );
2719 }
2720 else
2721 {
2722 lpName->u1.lpszShortNameA = NULL;
2723 }
2724
2725 if( lpPList->lpPData->name.u1.lpszShortNameA )
2726 {
2727 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2728 lpPList->lpPData->name.u2.lpszLongNameA );
2729 }
2730 else
2731 {
2732 lpName->u2.lpszLongNameA = NULL;
2733 }
2734
2735 return DP_OK;
2736 }
2737
2738 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
2739 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2740 LPDWORD lpdwDataSize )
2741 {
2742 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2743 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2744 }
2745
2746 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2747 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2748 LPDWORD lpdwDataSize )
2749 {
2750 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2751 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2752 }
2753
2754 static HRESULT DP_GetSessionDesc
2755 ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2756 BOOL bAnsi )
2757 {
2758 DWORD dwRequiredSize;
2759
2760 TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2761
2762 if( This->dp2->connectionInitialized == NO_PROVIDER )
2763 {
2764 return DPERR_UNINITIALIZED;
2765 }
2766
2767 if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
2768 {
2769 return DPERR_INVALIDPARAMS;
2770 }
2771
2772 /* FIXME: Get from This->dp2->lpSessionDesc */
2773 dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2774
2775 if ( ( lpData == NULL ) ||
2776 ( *lpdwDataSize < dwRequiredSize )
2777 )
2778 {
2779 *lpdwDataSize = dwRequiredSize;
2780 return DPERR_BUFFERTOOSMALL;
2781 }
2782
2783 DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2784
2785 return DP_OK;
2786 }
2787
2788 static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
2789 ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
2790 {
2791 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2792 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2793 }
2794
2795 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2796 ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2797 {
2798 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2799 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2800 }
2801
2802 /* Intended only for COM compatibility. Always returns an error. */
2803 static HRESULT WINAPI DirectPlay2AImpl_Initialize
2804 ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
2805 {
2806 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2807 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2808 return DPERR_ALREADYINITIALIZED;
2809 }
2810
2811 /* Intended only for COM compatibility. Always returns an error. */
2812 static HRESULT WINAPI DirectPlay2WImpl_Initialize
2813 ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
2814 {
2815 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2816 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2817 return DPERR_ALREADYINITIALIZED;
2818 }
2819
2820
2821 static HRESULT DP_SecureOpen
2822 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2823 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
2824 BOOL bAnsi )
2825 {
2826 HRESULT hr = DP_OK;
2827
2828 FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
2829 This, lpsd, dwFlags, lpSecurity, lpCredentials );
2830
2831 if( This->dp2->connectionInitialized == NO_PROVIDER )
2832 {
2833 return DPERR_UNINITIALIZED;
2834 }
2835
2836 if( lpsd->dwSize != sizeof(DPSESSIONDESC2) )
2837 {
2838 TRACE( ": rejecting invalid dpsd size (%d).\n", lpsd->dwSize );
2839 return DPERR_INVALIDPARAMS;
2840 }
2841
2842 if( This->dp2->bConnectionOpen )
2843 {
2844 TRACE( ": rejecting already open connection.\n" );
2845 return DPERR_ALREADYINITIALIZED;
2846 }
2847
2848 /* If we're enumerating, kill the thread */
2849 DP_KillEnumSessionThread( This );
2850
2851 if( dwFlags & DPOPEN_CREATE )
2852 {
2853 /* Rightoo - this computer is the host and the local computer needs to be
2854 the name server so that others can join this session */
2855 NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
2856
2857 This->dp2->bHostInterface = TRUE;
2858
2859 hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
2860 if( FAILED( hr ) )
2861 {
2862 ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
2863 return hr;
2864 }
2865 }
2866
2867 /* Invoke the conditional callback for the service provider */
2868 if( This->dp2->spData.lpCB->Open )
2869 {
2870 DPSP_OPENDATA data;
2871
2872 FIXME( "Not all data fields are correct. Need new parameter\n" );
2873
2874 data.bCreate = (dwFlags & DPOPEN_CREATE ) ? TRUE : FALSE;
2875 data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
2876 : NS_GetNSAddr( This->dp2->lpNameServerData );
2877 data.lpISP = This->dp2->spData.lpISP;
2878 data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) ? TRUE : FALSE;
2879 data.dwOpenFlags = dwFlags;
2880 data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
2881
2882 hr = (*This->dp2->spData.lpCB->Open)(&data);
2883 if( FAILED( hr ) )
2884 {
2885 ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
2886 return hr;
2887 }
2888 }
2889
2890 {
2891 /* Create the system group of which everything is a part of */
2892 DPID systemGroup = DPID_SYSTEM_GROUP;
2893
2894 hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
2895 NULL, 0, 0, TRUE );
2896
2897 }
2898
2899 if( dwFlags & DPOPEN_JOIN )
2900 {
2901 DPID dpidServerId = DPID_UNKNOWN;
2902
2903 /* Create the server player for this interface. This way we can receive
2904 * messages for this session.
2905 */
2906 /* FIXME: I suppose that we should be setting an event for a receive
2907 * type of thing. That way the messaging thread could know to wake
2908 * up. DPlay would then trigger the hEvent for the player the
2909 * message is directed to.
2910 */
2911 hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
2912 0,
2913 DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
2914
2915 }
2916 else if( dwFlags & DPOPEN_CREATE )
2917 {
2918 DPID dpidNameServerId = DPID_NAME_SERVER;
2919
2920 hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
2921 0, DPPLAYER_SERVERPLAYER, bAnsi );
2922 }
2923
2924 if( FAILED(hr) )
2925 {
2926 ERR( "Couldn't create name server/system player: %s\n",
2927 DPLAYX_HresultToString(hr) );
2928 }
2929
2930 return hr;
2931 }
2932
2933 static HRESULT WINAPI DirectPlay2AImpl_Open
2934 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2935 {
2936 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2937 TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
2938 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE );
2939 }
2940
2941 static HRESULT WINAPI DirectPlay2WImpl_Open
2942 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2943 {
2944 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2945 TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
2946 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE );
2947 }
2948
2949 static HRESULT DP_IF_Receive
2950 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
2951 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
2952 {
2953 LPDPMSG lpMsg = NULL;
2954
2955 FIXME( "(%p)->(%p,%p,0x%08x,%p,%p,%u): stub\n",
2956 This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
2957
2958 if( This->dp2->connectionInitialized == NO_PROVIDER )
2959 {
2960 return DPERR_UNINITIALIZED;
2961 }
2962
2963 if( dwFlags == 0 )
2964 {
2965 dwFlags = DPRECEIVE_ALL;
2966 }
2967
2968 /* If the lpData is NULL, we must be peeking the message */
2969 if( ( lpData == NULL ) &&
2970 !( dwFlags & DPRECEIVE_PEEK )
2971 )
2972 {
2973 return DPERR_INVALIDPARAMS;
2974 }
2975
2976 if( dwFlags & DPRECEIVE_ALL )
2977 {
2978 lpMsg = This->dp2->receiveMsgs.lpQHFirst;
2979
2980 if( !( dwFlags & DPRECEIVE_PEEK ) )
2981 {
2982 FIXME( "Remove from queue\n" );
2983 }
2984 }
2985 else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
2986 ( dwFlags & DPRECEIVE_FROMPLAYER )
2987 )
2988 {
2989 FIXME( "Find matching message 0x%08x\n", dwFlags );
2990 }
2991 else
2992 {
2993 ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
2994 }
2995
2996 if( lpMsg == NULL )
2997 {
2998 return DPERR_NOMESSAGES;
2999 }
3000
3001 /* Copy into the provided buffer */
3002 if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
3003
3004 return DP_OK;
3005 }
3006
3007 static HRESULT WINAPI DirectPlay2AImpl_Receive
3008 ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
3009 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3010 {
3011 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3012 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3013 lpData, lpdwDataSize, TRUE );
3014 }
3015
3016 static HRESULT WINAPI DirectPlay2WImpl_Receive
3017 ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
3018 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3019 {
3020 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3021 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3022 lpData, lpdwDataSize, FALSE );
3023 }
3024
3025 static HRESULT WINAPI DirectPlay2AImpl_Send
3026 ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3027 {
3028 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3029 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3030 0, 0, NULL, NULL, TRUE );
3031 }
3032
3033 static HRESULT WINAPI DirectPlay2WImpl_Send
3034 ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3035 {
3036 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3037 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3038 0, 0, NULL, NULL, FALSE );
3039 }
3040
3041 static HRESULT DP_IF_SetGroupData
3042 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
3043 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3044 {
3045 lpGroupData lpGData;
3046
3047 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3048 This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
3049
3050 /* Parameter check */
3051 if( ( lpData == NULL ) &&
3052 ( dwDataSize != 0 )
3053 )
3054 {
3055 return DPERR_INVALIDPARAMS;
3056 }
3057
3058 /* Find the pointer to the data for this player */
3059 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3060 {
3061 return DPERR_INVALIDOBJECT;
3062 }
3063
3064 if( !(dwFlags & DPSET_LOCAL) )
3065 {
3066 FIXME( "Was this group created by this interface?\n" );
3067 /* FIXME: If this is a remote update need to allow it but not
3068 * send a message.
3069 */
3070 }
3071
3072 DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
3073
3074 /* FIXME: Only send a message if this group is local to the session otherwise
3075 * it will have been rejected above
3076 */
3077 if( !(dwFlags & DPSET_LOCAL) )
3078 {
3079 FIXME( "Send msg?\n" );
3080 }
3081
3082 return DP_OK;
3083 }
3084
3085 static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
3086 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
3087 DWORD dwDataSize, DWORD dwFlags )
3088 {
3089 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3090 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
3091 }
3092
3093 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
3094 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
3095 DWORD dwDataSize, DWORD dwFlags )
3096 {
3097 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3098 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
3099 }
3100
3101 static HRESULT DP_IF_SetGroupName
3102 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
3103 DWORD dwFlags, BOOL bAnsi )
3104 {
3105 lpGroupData lpGData;
3106
3107 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
3108 lpGroupName, dwFlags, bAnsi );
3109
3110 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3111 {
3112 return DPERR_INVALIDGROUP;
3113 }
3114
3115 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3116
3117 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3118 FIXME( "Message not sent and dwFlags ignored\n" );
3119
3120 return DP_OK;
3121 }
3122
3123 static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
3124 ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
3125 DWORD dwFlags )
3126 {
3127 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3128 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3129 }
3130
3131 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
3132 ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
3133 DWORD dwFlags )
3134 {
3135 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3136 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3137 }
3138
3139 static HRESULT DP_IF_SetPlayerData
3140 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
3141 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3142 {
3143 lpPlayerList lpPList;
3144
3145 TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3146 This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
3147
3148 if( This->dp2->connectionInitialized == NO_PROVIDER )
3149 {
3150 return DPERR_UNINITIALIZED;
3151 }
3152
3153 /* Parameter check */
3154 if( ( lpData == NULL ) &&
3155 ( dwDataSize != 0 )
3156 )
3157 {
3158 return DPERR_INVALIDPARAMS;
3159 }
3160
3161 /* Find the pointer to the data for this player */
3162 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3163 {
3164 return DPERR_INVALIDPLAYER;
3165 }
3166
3167 if( !(dwFlags & DPSET_LOCAL) )
3168 {
3169 FIXME( "Was this group created by this interface?\n" );
3170 /* FIXME: If this is a remote update need to allow it but not
3171 * send a message.
3172 */
3173 }
3174
3175 DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
3176
3177 if( !(dwFlags & DPSET_LOCAL) )
3178 {
3179 FIXME( "Send msg?\n" );
3180 }
3181
3182 return DP_OK;
3183 }
3184
3185 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
3186 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
3187 DWORD dwDataSize, DWORD dwFlags )
3188 {
3189 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3190 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3191 dwFlags, TRUE );
3192 }
3193
3194 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
3195 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
3196 DWORD dwDataSize, DWORD dwFlags )
3197 {
3198 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3199 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3200 dwFlags, FALSE );
3201 }
3202
3203 static HRESULT DP_IF_SetPlayerName
3204 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
3205 DWORD dwFlags, BOOL bAnsi )
3206 {
3207 lpPlayerList lpPList;
3208
3209 TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
3210 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3211
3212 if( This->dp2->connectionInitialized == NO_PROVIDER )
3213 {
3214 return DPERR_UNINITIALIZED;
3215 }
3216
3217 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3218 {
3219 return DPERR_INVALIDGROUP;
3220 }
3221
3222 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3223
3224 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3225 FIXME( "Message not sent and dwFlags ignored\n" );
3226
3227 return DP_OK;
3228 }
3229
3230 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
3231 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
3232 DWORD dwFlags )
3233 {
3234 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3235 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3236 }
3237
3238 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
3239 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
3240 DWORD dwFlags )
3241 {
3242 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3243 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3244 }
3245
3246 static HRESULT DP_SetSessionDesc
3247 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
3248 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
3249 {
3250 DWORD dwRequiredSize;
3251 LPDPSESSIONDESC2 lpTempSessDesc;
3252
3253 TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
3254 This, lpSessDesc, dwFlags, bInitial, bAnsi );
3255
3256 if( This->dp2->connectionInitialized == NO_PROVIDER )
3257 {
3258 return DPERR_UNINITIALIZED;
3259 }
3260
3261 if( dwFlags )
3262 {
3263 return DPERR_INVALIDPARAMS;
3264 }
3265
3266 /* Only the host is allowed to update the session desc */
3267 if( !This->dp2->bHostInterface )
3268 {
3269 return DPERR_ACCESSDENIED;
3270 }
3271
3272 /* FIXME: Copy into This->dp2->lpSessionDesc */
3273 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3274 lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3275
3276 if( lpTempSessDesc == NULL )
3277 {
3278 return DPERR_OUTOFMEMORY;
3279 }
3280
3281 /* Free the old */
3282 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3283
3284 This->dp2->lpSessionDesc = lpTempSessDesc;
3285 /* Set the new */
3286 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3287 if( bInitial )
3288 {
3289 /*Initializing session GUID*/
3290 CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
3291 }
3292 /* If this is an external invocation of the interface, we should be
3293 * letting everyone know that things have changed. Otherwise this is
3294 * just an initialization and it doesn't need to be propagated.
3295 */
3296 if( !bInitial )
3297 {
3298 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3299 }
3300
3301 return DP_OK;
3302 }
3303
3304 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
3305 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3306 {
3307 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3308 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3309 }
3310
3311 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
3312 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3313 {
3314 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3315 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3316 }
3317
3318 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3319 static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3320 {
3321 DWORD dwSize = 0;
3322
3323 if( lpSessDesc == NULL )
3324 {
3325 /* Hmmm..don't need any size? */
3326 ERR( "NULL lpSessDesc\n" );
3327 return dwSize;
3328 }
3329
3330 dwSize += sizeof( *lpSessDesc );
3331
3332 if( bAnsi )
3333 {
3334 if( lpSessDesc->u1.lpszSessionNameA )
3335 {
3336 dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3337 }
3338
3339 if( lpSessDesc->u2.lpszPasswordA )
3340 {
3341 dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3342 }
3343 }
3344 else /* UNICODE */
3345 {
3346 if( lpSessDesc->u1.lpszSessionName )
3347 {
3348 dwSize += sizeof( WCHAR ) *
3349 ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3350 }
3351
3352 if( lpSessDesc->u2.lpszPassword )
3353 {
3354 dwSize += sizeof( WCHAR ) *
3355 ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3356 }
3357 }
3358
3359 return dwSize;
3360 }
3361
3362 /* Assumes that contiguous buffers are already allocated. */
3363 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3364 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3365 {
3366 BYTE* lpStartOfFreeSpace;
3367
3368 if( lpSessionDest == NULL )
3369 {
3370 ERR( "NULL lpSessionDest\n" );
3371 return;
3372 }
3373
3374 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3375
3376 lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3377
3378 if( bAnsi )
3379 {
3380 if( lpSessionSrc->u1.lpszSessionNameA )
3381 {
3382 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3383 lpSessionDest->u1.lpszSessionNameA );
3384 lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3385 lpStartOfFreeSpace +=
3386 lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
3387 }
3388
3389 if( lpSessionSrc->u2.lpszPasswordA )
3390 {
3391 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3392 lpSessionDest->u2.lpszPasswordA );
3393 lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3394 lpStartOfFreeSpace +=
3395 lstrlenA( lpSessionDest->u2.lpszPasswordA ) + 1;
3396 }
3397 }
3398 else /* UNICODE */
3399 {
3400 if( lpSessionSrc->u1.lpszSessionName )
3401 {
3402 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3403 lpSessionDest->u1.lpszSessionName );
3404 lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3405 lpStartOfFreeSpace += sizeof(WCHAR) *
3406 ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3407 }
3408
3409 if( lpSessionSrc->u2.lpszPassword )
3410 {
3411 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3412 lpSessionDest->u2.lpszPassword );
3413 lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3414 lpStartOfFreeSpace += sizeof(WCHAR) *
3415 ( lstrlenW( lpSessionDest->u2.lpszPassword ) + 1 );
3416 }
3417 }
3418 }
3419
3420
3421 static HRESULT DP_IF_AddGroupToGroup
3422 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3423 {
3424 lpGroupData lpGData;
3425 lpGroupList lpNewGList;
3426
3427 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3428
3429 if( This->dp2->connectionInitialized == NO_PROVIDER )
3430 {
3431 return DPERR_UNINITIALIZED;
3432 }
3433
3434 if( DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) == NULL )
3435 {
3436 return DPERR_INVALIDGROUP;
3437 }
3438
3439 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3440 {
3441 return DPERR_INVALIDGROUP;
3442 }
3443
3444 /* Create a player list (ie "shortcut" ) */
3445 lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
3446 if( lpNewGList == NULL )
3447 {
3448 return DPERR_CANTADDPLAYER;
3449 }
3450
3451 /* Add the shortcut */
3452 lpGData->uRef++;
3453 lpNewGList->lpGData = lpGData;
3454
3455 /* Add the player to the list of players for this group */
3456 DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3457
3458 /* Send a ADDGROUPTOGROUP message */
3459 FIXME( "Not sending message\n" );
3460
3461 return DP_OK;
3462 }
3463
3464 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
3465 ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
3466 {
3467 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3468 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3469 }
3470
3471 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3472 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3473 {
3474 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3475 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3476 }
3477
3478 static HRESULT DP_IF_CreateGroupInGroup
3479 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3480 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3481 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3482 {
3483 lpGroupData lpGParentData;
3484 lpGroupList lpGList;
3485 lpGroupData lpGData;
3486
3487 TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
3488 This, idParentGroup, lpidGroup, lpGroupName, lpData,
3489 dwDataSize, dwFlags, bAnsi );
3490
3491 if( This->dp2->connectionInitialized == NO_PROVIDER )
3492 {
3493 return DPERR_UNINITIALIZED;
3494 }
3495
3496 /* Verify that the specified parent is valid */
3497 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3498 idParentGroup ) ) == NULL
3499 )
3500 {
3501 return DPERR_INVALIDGROUP;
3502 }
3503
3504 lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3505 dwFlags, idParentGroup, bAnsi );
3506
3507 if( lpGData == NULL )
3508 {
3509 return DPERR_CANTADDPLAYER; /* yes player not group */
3510 }
3511
3512 /* Something else is referencing this data */
3513 lpGData->uRef++;
3514
3515 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3516
3517 /* The list has now been inserted into the interface group list. We now
3518 need to put a "shortcut" to this group in the parent group */
3519 lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3520 if( lpGList == NULL )
3521 {
3522 FIXME( "Memory leak\n" );
3523 return DPERR_CANTADDPLAYER; /* yes player not group */
3524 }
3525
3526 lpGList->lpGData = lpGData;
3527
3528 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3529
3530 /* Let the SP know that we've created this group */
3531 if( This->dp2->spData.lpCB->CreateGroup )
3532 {
3533 DPSP_CREATEGROUPDATA data;
3534
3535 TRACE( "Calling SP CreateGroup\n" );
3536
3537 data.idGroup = *lpidGroup;
3538 data.dwFlags = dwFlags;
3539 data.lpSPMessageHeader = lpMsgHdr;
3540 data.lpISP = This->dp2->spData.lpISP;
3541
3542 (*This->dp2->spData.lpCB->CreateGroup)( &data );
3543 }
3544
3545 /* Inform all other peers of the creation of a new group. If there are
3546 * no peers keep this quiet.
3547 */
3548 if( This->dp2->lpSessionDesc &&
3549 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3550 {
3551 DPMSG_CREATEPLAYERORGROUP msg;
3552
3553 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3554 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3555 msg.dpId = *lpidGroup;
3556 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3557 msg.lpData = lpData;
3558 msg.dwDataSize = dwDataSize;
3559 msg.dpnName = *lpGroupName;
3560
3561 /* FIXME: Correct to just use send effectively? */
3562 /* FIXME: Should size include data w/ message or just message "header" */
3563 /* FIXME: Check return code */
3564 DP_SendEx( (IDirectPlay2Impl*)This,
3565 DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3566 0, 0, NULL, NULL, bAnsi );
3567 }
3568
3569 return DP_OK;
3570 }
3571
3572 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
3573 ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
3574 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3575 DWORD dwFlags )
3576 {
3577 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3578
3579 *lpidGroup = DPID_UNKNOWN;
3580
3581 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3582 lpGroupName, lpData, dwDataSize, dwFlags,
3583 TRUE );
3584 }
3585
3586 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3587 ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3588 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3589 DWORD dwFlags )
3590 {
3591 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3592
3593 *lpidGroup = DPID_UNKNOWN;
3594
3595 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3596 lpGroupName, lpData, dwDataSize,
3597 dwFlags, FALSE );
3598 }
3599
3600 static HRESULT DP_IF_DeleteGroupFromGroup
3601 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3602 {
3603 lpGroupList lpGList;
3604 lpGroupData lpGParentData;
3605
3606 TRACE("(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3607
3608 /* Is the parent group valid? */
3609 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3610 {
3611 return DPERR_INVALIDGROUP;
3612 }
3613
3614 /* Remove the group from the parent group queue */
3615 DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3616
3617 if( lpGList == NULL )
3618 {
3619 return DPERR_INVALIDGROUP;
3620 }
3621
3622 /* Decrement the ref count */
3623 lpGList->lpGData->uRef--;
3624
3625 /* Free up the list item */
3626 HeapFree( GetProcessHeap(), 0, lpGList );
3627
3628 /* Should send a DELETEGROUPFROMGROUP message */
3629 FIXME( "message not sent\n" );
3630
3631 return DP_OK;
3632 }
3633
3634 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
3635 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3636 {
3637 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3638 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3639 }
3640
3641 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3642 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3643 {
3644 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3645 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3646 }
3647
3648 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3649 LPDWORD lpdwBufSize )
3650 {
3651 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3652 HRESULT hr;
3653
3654 dpCompoundAddress.dwDataSize = sizeof( GUID );
3655 dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
3656 dpCompoundAddress.lpData = lpcSpGuid;
3657
3658 *lplpAddrBuf = NULL;
3659 *lpdwBufSize = 0;
3660
3661 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3662 lpdwBufSize, TRUE );
3663
3664 if( hr != DPERR_BUFFERTOOSMALL )
3665 {
3666 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3667 return FALSE;
3668 }
3669
3670 /* Now allocate the buffer */
3671 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3672 *lpdwBufSize );
3673
3674 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3675 lpdwBufSize, TRUE );
3676 if( FAILED(hr) )
3677 {
3678 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3679 return FALSE;
3680 }
3681
3682 return TRUE;
3683 }
3684
3685 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
3686 ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3687 {
3688 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3689 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3690
3691 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3692 if( dwFlags == 0 )
3693 {
3694 dwFlags = DPCONNECTION_DIRECTPLAY;
3695 }
3696
3697 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3698 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3699 )
3700 {
3701 return DPERR_INVALIDFLAGS;
3702 }
3703
3704 if( !lpEnumCallback )
3705 {
3706 return DPERR_INVALIDPARAMS;
3707 }
3708
3709 /* Enumerate DirectPlay service providers */
3710 if( dwFlags & DPCONNECTION_DIRECTPLAY )
3711 {
3712 HKEY hkResult;
3713 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3714 LPCSTR guidDataSubKey = "Guid";
3715 char subKeyName[51];
3716 DWORD dwIndex, sizeOfSubKeyName=50;
3717 FILETIME filetime;
3718
3719 /* Need to loop over the service providers in the registry */
3720 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3721 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3722 {
3723 /* Hmmm. Does this mean that there are no service providers? */
3724 ERR(": no service providers?\n");
3725 return DP_OK;
3726 }
3727
3728
3729 /* Traverse all the service providers we have available */
3730 for( dwIndex=0;
3731 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3732 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3733 ++dwIndex, sizeOfSubKeyName=51 )
3734 {
3735
3736 HKEY hkServiceProvider;
3737 GUID serviceProviderGUID;
3738 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3739 char returnBuffer[51];
3740 WCHAR buff[51];
3741 DPNAME dpName;
3742 BOOL bBuildPass;
3743
3744 LPVOID lpAddressBuffer = NULL;
3745 DWORD dwAddressBufferSize = 0;
3746
3747 TRACE(" this time through: %s\n", subKeyName );
3748
3749 /* Get a handle for this particular service provider */
3750 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3751 &hkServiceProvider ) != ERROR_SUCCESS )
3752 {
3753 ERR(": what the heck is going on?\n" );
3754 continue;
3755 }
3756
3757 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3758 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3759 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3760 {
3761 ERR(": missing GUID registry data members\n" );
3762 RegCloseKey(hkServiceProvider);
3763 continue;
3764 }
3765 RegCloseKey(hkServiceProvider);
3766
3767 /* FIXME: Check return types to ensure we're interpreting data right */
3768 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3769 CLSIDFromString( buff, &serviceProviderGUID );
3770 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3771
3772 /* Fill in the DPNAME struct for the service provider */
3773 dpName.dwSize = sizeof( dpName );
3774 dpName.dwFlags = 0;
3775 dpName.u1.lpszShortNameA = subKeyName;
3776 dpName.u2.lpszLongNameA = NULL;
3777
3778 /* Create the compound address for the service provider.
3779 * NOTE: This is a gruesome architectural scar right now. DP
3780 * uses DPL and DPL uses DP. Nasty stuff. This may be why the
3781 * native dll just gets around this little bit by allocating an
3782 * 80 byte buffer which isn't even filled with a valid compound
3783 * address. Oh well. Creating a proper compound address is the
3784 * way to go anyways despite this method taking slightly more
3785 * heap space and realtime :) */
3786
3787 bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
3788 &lpAddressBuffer,
3789 &dwAddressBufferSize );
3790 if( !bBuildPass )
3791 {
3792 ERR( "Can't build compound addr\n" );
3793 return DPERR_GENERIC;
3794 }
3795
3796 /* The enumeration will return FALSE if we are not to continue */
3797 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3798 &dpName, dwFlags, lpContext ) )
3799 {
3800 return DP_OK;
3801 }
3802 }
3803 }
3804
3805 /* Enumerate DirectPlayLobby service providers */
3806 if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
3807 {
3808 HKEY hkResult;
3809 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3810 LPCSTR guidDataSubKey = "Guid";
3811 char subKeyName[51];
3812 DWORD dwIndex, sizeOfSubKeyName=50;
3813 FILETIME filetime;
3814
3815 /* Need to loop over the service providers in the registry */
3816 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3817 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3818 {
3819 /* Hmmm. Does this mean that there are no service providers? */
3820 ERR(": no service providers?\n");
3821 return DP_OK;
3822 }
3823
3824
3825 /* Traverse all the lobby providers we have available */
3826 for( dwIndex=0;
3827 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3828 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3829 ++dwIndex, sizeOfSubKeyName=51 )
3830 {
3831
3832 HKEY hkServiceProvider;
3833 GUID serviceProviderGUID;
3834 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3835 char returnBuffer[51];
3836 WCHAR buff[51];
3837 DPNAME dpName;
3838 HRESULT hr;
3839
3840 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3841 LPVOID lpAddressBuffer = NULL;
3842 DWORD dwAddressBufferSize = 0;
3843
3844 TRACE(" this time through: %s\n", subKeyName );
3845
3846 /* Get a handle for this particular service provider */
3847 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3848 &hkServiceProvider ) != ERROR_SUCCESS )
3849 {
3850 ERR(": what the heck is going on?\n" );
3851 continue;
3852 }
3853
3854 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3855 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3856 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3857 {
3858 ERR(": missing GUID registry data members\n" );
3859 RegCloseKey(hkServiceProvider);
3860 continue;
3861 }
3862 RegCloseKey(hkServiceProvider);
3863
3864 /* FIXME: Check return types to ensure we're interpreting data right */
3865 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3866 CLSIDFromString( buff, &serviceProviderGUID );
3867 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3868
3869 /* Fill in the DPNAME struct for the service provider */
3870 dpName.dwSize = sizeof( dpName );
3871 dpName.dwFlags = 0;
3872 dpName.u1.lpszShortNameA = subKeyName;
3873 dpName.u2.lpszLongNameA = NULL;
3874
3875 /* Create the compound address for the service provider.
3876 NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3877 nast stuff. This may be why the native dll just gets around this little bit by
3878 allocating an 80 byte buffer which isn't even a filled with a valid compound
3879 address. Oh well. Creating a proper compound address is the way to go anyways
3880 despite this method taking slightly more heap space and realtime :) */
3881
3882 dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
3883 dpCompoundAddress.dwDataSize = sizeof( GUID );
3884 dpCompoundAddress.lpData = &serviceProviderGUID;
3885
3886 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3887 &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
3888 {
3889 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3890 return hr;
3891 }
3892
3893 /* Now allocate the buffer */
3894 lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
3895
3896 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3897 &dwAddressBufferSize, TRUE ) ) != DP_OK )
3898 {
3899 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3900 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3901 return hr;
3902 }
3903
3904 /* The enumeration will return FALSE if we are not to continue */
3905 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3906 &dpName, dwFlags, lpContext ) )
3907 {
3908 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3909 return DP_OK;
3910 }
3911 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3912 }
3913 }
3914
3915 return DP_OK;
3916 }
3917
3918 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
3919 ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3920 {
3921 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3922 FIXME("(%p)->(%p,%p,%p,0x%08x): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3923 return DP_OK;
3924 }
3925
3926 static HRESULT DP_IF_EnumGroupsInGroup
3927 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
3928 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
3929 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
3930 {
3931 lpGroupList lpGList;
3932 lpGroupData lpGData;
3933
3934 FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
3935 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
3936 lpContext, dwFlags, bAnsi );
3937
3938 if( This->dp2->connectionInitialized == NO_PROVIDER )
3939 {
3940 return DPERR_UNINITIALIZED;
3941 }
3942
3943 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3944 {
3945 return DPERR_INVALIDGROUP;
3946 }
3947
3948 if( DPQ_IS_EMPTY( lpGData->groups ) )
3949 {
3950 return DP_OK;
3951 }
3952
3953 lpGList = DPQ_FIRST( lpGData->groups );
3954
3955 for( ;; )
3956 {
3957 /* FIXME: Should check dwFlags for match here */
3958
3959 if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
3960 &lpGList->lpGData->name, dwFlags,
3961 lpContext ) )
3962 {
3963 return DP_OK; /* User requested break */
3964 }
3965
3966 if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
3967 {
3968 break;
3969 }
3970
3971 lpGList = DPQ_NEXT( lpGList->groups );
3972
3973 }
3974
3975 return DP_OK;
3976 }
3977
3978 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
3979 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3980 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3981 DWORD dwFlags )
3982 {
3983 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3984 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3985 lpEnumPlayersCallback2, lpContext, dwFlags,
3986 TRUE );
3987 }
3988
3989 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
3990 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3991 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3992 DWORD dwFlags )
3993 {
3994 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3995 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3996 lpEnumPlayersCallback2, lpContext, dwFlags,
3997 FALSE );
3998 }
3999
4000 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
4001 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
4002 {
4003 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4004 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4005 return DP_OK;
4006 }
4007
4008 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
4009 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
4010 {
4011 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4012 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4013 return DP_OK;
4014 }
4015
4016 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
4017 REFGUID guidDataType,
4018 DWORD dwDataSize,
4019 LPCVOID lpData,
4020 LPVOID lpContext )
4021 {
4022 /* Looking for the GUID of the provider to load */
4023 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
4024 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
4025 )
4026 {
4027 TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
4028 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
4029
4030 if( dwDataSize != sizeof( GUID ) )
4031 {
4032 ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
4033 }
4034
4035 memcpy( lpContext, lpData, dwDataSize );
4036
4037 /* There shouldn't be more than 1 GUID/compound address */
4038 return FALSE;
4039 }
4040
4041 /* Still waiting for what we want */
4042 return TRUE;
4043 }
4044
4045
4046 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
4047 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
4048 {
4049 UINT i;
4050 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4051 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4052 LPCSTR guidDataSubKey = "Guid";
4053 LPCSTR majVerDataSubKey = "dwReserved1";
4054 LPCSTR minVerDataSubKey = "dwReserved2";
4055 LPCSTR pathSubKey = "Path";
4056
4057 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
4058
4059 /* FIXME: Cloned code with a quick hack. */
4060 for( i=0; i<2; i++ )
4061 {
4062 HKEY hkResult;
4063 LPCSTR searchSubKey;
4064 char subKeyName[51];
4065 DWORD dwIndex, sizeOfSubKeyName=50;
4066 FILETIME filetime;
4067
4068 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4069 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
4070
4071
4072 /* Need to loop over the service providers in the registry */
4073 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4074 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4075 {
4076 /* Hmmm. Does this mean that there are no service providers? */
4077 ERR(": no service providers?\n");
4078 return 0;
4079 }
4080
4081 /* Traverse all the service providers we have available */
4082 for( dwIndex=0;
4083 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4084 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4085 ++dwIndex, sizeOfSubKeyName=51 )
4086 {
4087
4088 HKEY hkServiceProvider;
4089 GUID serviceProviderGUID;
4090 DWORD returnType, sizeOfReturnBuffer = 255;
4091 char returnBuffer[256];
4092 WCHAR buff[51];
4093 DWORD dwTemp, len;
4094
4095 TRACE(" this time through: %s\n", subKeyName );
4096
4097 /* Get a handle for this particular service provider */
4098 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4099 &hkServiceProvider ) != ERROR_SUCCESS )
4100 {
4101 ERR(": what the heck is going on?\n" );
4102 continue;
4103 }
4104
4105 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4106 NULL, &returnType, (LPBYTE)returnBuffer,
4107 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4108 {
4109 ERR(": missing GUID registry data members\n" );
4110 continue;
4111 }
4112
4113 /* FIXME: Check return types to ensure we're interpreting data right */
4114 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4115 CLSIDFromString( buff, &serviceProviderGUID );
4116 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4117
4118 /* Determine if this is the Service Provider that the user asked for */
4119 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4120 {
4121 continue;
4122 }
4123
4124 if( i == 0 ) /* DP SP */
4125 {
4126 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4127 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4128 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4129 }
4130
4131 sizeOfReturnBuffer = 255;
4132
4133 /* Get dwReserved1 */
4134 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4135 NULL, &returnType, (LPBYTE)returnBuffer,
4136 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4137 {
4138 ERR(": missing dwReserved1 registry data members\n") ;
4139 continue;
4140 }
4141
4142 if( i == 0 )
4143 memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
4144
4145 sizeOfReturnBuffer = 255;
4146
4147 /* Get dwReserved2 */
4148 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4149 NULL, &returnType, (LPBYTE)returnBuffer,
4150 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4151 {
4152 ERR(": missing dwReserved1 registry data members\n") ;
4153 continue;
4154 }
4155
4156 if( i == 0 )
4157 memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4158
4159 sizeOfReturnBuffer = 255;
4160
4161 /* Get the path for this service provider */
4162 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4163 NULL, NULL, (LPBYTE)returnBuffer,
4164 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4165 {
4166 ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
4167 continue;
4168 }
4169
4170 TRACE( "Loading %s\n", returnBuffer );
4171 return LoadLibraryA( returnBuffer );
4172 }
4173 }
4174
4175 return 0;
4176 }
4177
4178 static
4179 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
4180 {
4181 HRESULT hr;
4182 LPDPSP_SPINIT SPInit;
4183
4184 /* Initialize the service provider by calling SPInit */
4185 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4186
4187 if( SPInit == NULL )
4188 {
4189 ERR( "Service provider doesn't provide SPInit interface?\n" );
4190 FreeLibrary( hServiceProvider );
4191 return DPERR_UNAVAILABLE;
4192 }
4193
4194 TRACE( "Calling SPInit (DP SP entry point)\n" );
4195
4196 hr = (*SPInit)( &This->dp2->spData );
4197