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
4198 if( FAILED(hr) )
4199 {
4200 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4201 FreeLibrary( hServiceProvider );
4202 return hr;
4203 }
4204
4205 /* FIXME: Need to verify the sanity of the returned callback table
4206 * using IsBadCodePtr */
4207 This->dp2->bSPInitialized = TRUE;
4208
4209 /* This interface is now initialized as a DP object */
4210 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4211
4212 /* Store the handle of the module so that we can unload it later */
4213 This->dp2->hServiceProvider = hServiceProvider;
4214
4215 return hr;
4216 }
4217
4218 static
4219 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
4220 {
4221 HRESULT hr;
4222 LPSP_INIT DPLSPInit;
4223
4224 /* Initialize the service provider by calling SPInit */
4225 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4226
4227 if( DPLSPInit == NULL )
4228 {
4229 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4230 FreeLibrary( hLobbyProvider );
4231 return DPERR_UNAVAILABLE;
4232 }
4233
4234 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4235
4236 hr = (*DPLSPInit)( &This->dp2->dplspData );
4237
4238 if( FAILED(hr) )
4239 {
4240 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4241 FreeLibrary( hLobbyProvider );
4242 return hr;
4243 }
4244
4245 /* FIXME: Need to verify the sanity of the returned callback table
4246 * using IsBadCodePtr */
4247
4248 This->dp2->bDPLSPInitialized = TRUE;
4249
4250 /* This interface is now initialized as a lobby object */
4251 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4252
4253 /* Store the handle of the module so that we can unload it later */
4254 This->dp2->hDPLobbyProvider = hLobbyProvider;
4255
4256 return hr;
4257 }
4258
4259 static HRESULT DP_IF_InitializeConnection
4260 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4261 {
4262 HMODULE hServiceProvider;
4263 HRESULT hr;
4264 GUID guidSP;
4265 const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
4266 BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4267
4268 TRACE("(%p)->(%p,0x%08x,%u)\n", This, lpConnection, dwFlags, bAnsi );
4269
4270 if ( lpConnection == NULL )
4271 {
4272 return DPERR_INVALIDPARAMS;
4273 }
4274
4275 if( dwFlags != 0 )
4276 {
4277 return DPERR_INVALIDFLAGS;
4278 }
4279
4280 if( This->dp2->connectionInitialized != NO_PROVIDER )
4281 {
4282 return DPERR_ALREADYINITIALIZED;
4283 }
4284
4285 /* Find out what the requested SP is and how large this buffer is */
4286 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4287 dwAddrSize, &guidSP );
4288
4289 if( FAILED(hr) )
4290 {
4291 ERR( "Invalid compound address?\n" );
4292 return DPERR_UNAVAILABLE;
4293 }
4294
4295 /* Load the service provider */
4296 hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4297
4298 if( hServiceProvider == 0 )
4299 {
4300 ERR( "Unable to load service provider %s\n", debugstr_guid(&guidSP) );
4301 return DPERR_UNAVAILABLE;
4302 }
4303
4304 if( bIsDpSp )
4305 {
4306 /* Fill in what we can of the Service Provider required information.
4307 * The rest was be done in DP_LoadSP
4308 */
4309 This->dp2->spData.lpAddress = lpConnection;
4310 This->dp2->spData.dwAddressSize = dwAddrSize;
4311 This->dp2->spData.lpGuid = &guidSP;
4312
4313 hr = DP_InitializeDPSP( This, hServiceProvider );
4314 }
4315 else
4316 {
4317 This->dp2->dplspData.lpAddress = lpConnection;
4318
4319 hr = DP_InitializeDPLSP( This, hServiceProvider );
4320 }
4321
4322 if( FAILED(hr) )
4323 {
4324 return hr;
4325 }
4326
4327 return DP_OK;
4328 }
4329
4330 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
4331 ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
4332 {
4333 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4334
4335 /* This may not be externally invoked once either an SP or LP is initialized */
4336 if( This->dp2->connectionInitialized != NO_PROVIDER )
4337 {
4338 return DPERR_ALREADYINITIALIZED;
4339 }
4340
4341 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4342 }
4343
4344 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4345 ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4346 {
4347 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4348
4349 /* This may not be externally invoked once either an SP or LP is initialized */
4350 if( This->dp2->connectionInitialized != NO_PROVIDER )
4351 {
4352 return DPERR_ALREADYINITIALIZED;
4353 }
4354
4355 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4356 }
4357
4358 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
4359 ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4360 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4361 {
4362 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4363 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4364 }
4365
4366 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4367 ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4368 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4369 {
4370 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4371 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4372 }
4373
4374 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
4375 ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4376 {
4377 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4378 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4379 return DP_OK;
4380 }
4381
4382 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
4383 ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4384 {
4385 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4386 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4387 return DP_OK;
4388 }
4389
4390 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
4391 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4392 {
4393 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4394 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4395 return DP_OK;
4396 }
4397
4398 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
4399 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4400 {
4401 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4402 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4403 return DP_OK;
4404 }
4405
4406 static HRESULT WINAPI DirectPlay3AImpl_StartSession
4407 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
4408 {
4409 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4410 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4411 return DP_OK;
4412 }
4413
4414 static HRESULT WINAPI DirectPlay3WImpl_StartSession
4415 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
4416 {
4417 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4418 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4419 return DP_OK;
4420 }
4421
4422 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
4423 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
4424 {
4425 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4426 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4427 return DP_OK;
4428 }
4429
4430 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
4431 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
4432 {
4433 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4434 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4435 return DP_OK;
4436 }
4437
4438 static HRESULT DP_IF_GetGroupParent
4439 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4440 BOOL bAnsi )
4441 {
4442 lpGroupData lpGData;
4443
4444 TRACE("(%p)->(0x%08x,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4445
4446 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4447 {
4448 return DPERR_INVALIDGROUP;
4449 }
4450
4451 *lpidGroup = lpGData->dpid;
4452
4453 return DP_OK;
4454 }
4455
4456 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
4457 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
4458 {
4459 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4460 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4461 }
4462 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4463 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4464 {
4465 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4466 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4467 }
4468
4469 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
4470 ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4471 {
4472 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4473 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4474 return DP_OK;
4475 }
4476
4477 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
4478 ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4479 {
4480 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4481 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4482 return DP_OK;
4483 }
4484
4485 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
4486 ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
4487 {
4488 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4489 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4490 return DP_OK;
4491 }
4492
4493 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
4494 ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
4495 {
4496 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4497 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4498 return DP_OK;
4499 }
4500
4501 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4502 ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4503 {
4504 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4505 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4506 return DP_OK;
4507 }
4508
4509 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
4510 ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
4511 {
4512 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4513 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4514 return DP_OK;
4515 }
4516
4517 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4518 ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4519 {
4520 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4521 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4522 return DP_OK;
4523 }
4524
4525 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
4526 ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
4527 {
4528 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4529 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4530 return DP_OK;
4531 }
4532
4533 static HRESULT DP_SendEx
4534 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4535 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4536 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4537 {
4538 BOOL bValidDestination = FALSE;
4539
4540 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
4541 ": stub\n",
4542 This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4543 dwTimeout, lpContext, lpdwMsgID, bAnsi );
4544
4545 if( This->dp2->connectionInitialized == NO_PROVIDER )
4546 {
4547 return DPERR_UNINITIALIZED;
4548 }
4549
4550 /* FIXME: Add parameter checking */
4551 /* FIXME: First call to this needs to acquire a message id which will be
4552 * used for multiple sends
4553 */
4554
4555 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4556
4557 /* Verify that the message is being sent from a valid local player. The
4558 * from player may be anonymous DPID_UNKNOWN
4559 */
4560 if( idFrom != DPID_UNKNOWN )
4561 {
4562 if( DP_FindPlayer( This, idFrom ) == NULL )
4563 {
4564 WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
4565 return DPERR_INVALIDPLAYER;
4566 }
4567 }
4568
4569 /* Verify that the message is being sent to a valid player, group or to
4570 * everyone. If it's valid, send it to those players.
4571 */
4572 if( idTo == DPID_ALLPLAYERS )
4573 {
4574 bValidDestination = TRUE;
4575
4576 /* See if SP has the ability to multicast. If so, use it */
4577 if( This->dp2->spData.lpCB->SendToGroupEx )
4578 {
4579 FIXME( "Use group sendex to group 0\n" );
4580 }
4581 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4582 {
4583 FIXME( "Use obsolete group send to group 0\n" );
4584 }
4585 else /* No multicast, multiplicate */
4586 {
4587 /* Send to all players we know about */
4588 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4589 }
4590 }
4591
4592 if( ( !bValidDestination ) &&
4593 ( DP_FindPlayer( This, idTo ) != NULL )
4594 )
4595 {
4596 bValidDestination = TRUE;
4597
4598 /* Have the service provider send this message */
4599 /* FIXME: Could optimize for local interface sends */
4600 return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4601 dwTimeout, lpContext, lpdwMsgID );
4602 }
4603
4604 if( ( !bValidDestination ) &&
4605 ( DP_FindAnyGroup( This, idTo ) != NULL )
4606 )
4607 {
4608 bValidDestination = TRUE;
4609
4610 /* See if SP has the ability to multicast. If so, use it */
4611 if( This->dp2->spData.lpCB->SendToGroupEx )
4612 {
4613 FIXME( "Use group sendex\n" );
4614 }
4615 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4616 {
4617 FIXME( "Use obsolete group send to group\n" );
4618 }
4619 else /* No multicast, multiplicate */
4620 {
4621 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4622 }
4623
4624 #if 0
4625 if( bExpectReply )
4626 {
4627 DWORD dwWaitReturn;
4628
4629 This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
4630
4631 dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4632 if( dwWaitReturn != WAIT_OBJECT_0 )
4633 {
4634 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4635 }
4636 }
4637 #endif
4638 }
4639
4640 if( !bValidDestination )
4641 {
4642 return DPERR_INVALIDPLAYER;
4643 }
4644 else
4645 {
4646 /* FIXME: Should return what the send returned */
4647 return DP_OK;
4648 }
4649 }
4650
4651
4652 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4653 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4654 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4655 LPVOID lpContext, LPDWORD lpdwMsgID )
4656 {
4657 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4658 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4659 dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4660 }
4661
4662 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4663 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4664 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4665 LPVOID lpContext, LPDWORD lpdwMsgID )
4666 {
4667 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4668 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4669 dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4670 }
4671
4672 static HRESULT DP_SP_SendEx
4673 ( IDirectPlay2Impl* This, DWORD dwFlags,
4674 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4675 LPVOID lpContext, LPDWORD lpdwMsgID )
4676 {
4677 LPDPMSG lpMElem;
4678
4679 FIXME( ": stub\n" );
4680
4681 /* FIXME: This queuing should only be for async messages */
4682
4683 lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4684 lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4685
4686 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4687
4688 /* FIXME: Need to queue based on priority */
4689 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4690
4691 return DP_OK;
4692 }
4693
4694 static HRESULT DP_IF_GetMessageQueue
4695 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4696 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4697 {
4698 HRESULT hr = DP_OK;
4699
4700 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p,%u): semi stub\n",
4701 This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4702
4703 /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4704 /* FIXME: What about sends which are not immediate? */
4705
4706 if( This->dp2->spData.lpCB->GetMessageQueue )
4707 {
4708 DPSP_GETMESSAGEQUEUEDATA data;
4709
4710 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4711
4712 /* FIXME: None of this is documented :( */
4713
4714 data.lpISP = This->dp2->spData.lpISP;
4715 data.dwFlags = dwFlags;
4716 data.idFrom = idFrom;
4717 data.idTo = idTo;
4718 data.lpdwNumMsgs = lpdwNumMsgs;
4719 data.lpdwNumBytes = lpdwNumBytes;
4720
4721 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4722 }
4723 else
4724 {
4725 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4726 }
4727
4728 return hr;
4729 }
4730
4731 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4732 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4733 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4734 {
4735 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4736 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4737 lpdwNumBytes, TRUE );
4738 }
4739
4740 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4741 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4742 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4743 {
4744 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4745 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4746 lpdwNumBytes, FALSE );
4747 }
4748
4749 static HRESULT DP_IF_CancelMessage
4750 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4751 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4752 {
4753 HRESULT hr = DP_OK;
4754
4755 FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
4756 This, dwMsgID, dwFlags, bAnsi );
4757
4758 if( This->dp2->spData.lpCB->Cancel )
4759 {
4760 DPSP_CANCELDATA data;
4761
4762 TRACE( "Calling SP Cancel\n" );
4763
4764 /* FIXME: Undocumented callback */
4765
4766 data.lpISP = This->dp2->spData.lpISP;
4767 data.dwFlags = dwFlags;
4768 data.lprglpvSPMsgID = NULL;
4769 data.cSPMsgID = dwMsgID;
4770 data.dwMinPriority = dwMinPriority;
4771 data.dwMaxPriority = dwMaxPriority;
4772
4773 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4774 }
4775 else
4776 {
4777 FIXME( "SP doesn't implement Cancel\n" );
4778 }
4779
4780 return hr;
4781 }
4782
4783 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4784 ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4785 {
4786 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4787
4788 if( dwFlags != 0 )
4789 {
4790 return DPERR_INVALIDFLAGS;
4791 }
4792
4793 if( dwMsgID == 0 )
4794 {
4795 dwFlags |= DPCANCELSEND_ALL;
4796 }
4797
4798 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4799 }
4800
4801 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4802 ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4803 {
4804 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4805
4806 if( dwFlags != 0 )
4807 {
4808 return DPERR_INVALIDFLAGS;
4809 }
4810
4811 if( dwMsgID == 0 )
4812 {
4813 dwFlags |= DPCANCELSEND_ALL;
4814 }
4815
4816 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4817 }
4818
4819 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4820 ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4821 DWORD dwFlags )
4822 {
4823 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4824
4825 if( dwFlags != 0 )
4826 {
4827 return DPERR_INVALIDFLAGS;
4828 }
4829
4830 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4831 dwMaxPriority, TRUE );
4832 }
4833
4834 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4835 ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4836 DWORD dwFlags )
4837 {
4838 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4839
4840 if( dwFlags != 0 )
4841 {
4842 return DPERR_INVALIDFLAGS;
4843 }
4844
4845 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4846 dwMaxPriority, FALSE );
4847 }
4848
4849 /* Note: Hack so we can reuse the old functions without compiler warnings */
4850 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4851 # define XCAST(fun) (typeof(directPlay2WVT.fun))
4852 #else
4853 # define XCAST(fun) (void*)
4854 #endif
4855
4856 static const IDirectPlay2Vtbl directPlay2WVT =
4857 {
4858 XCAST(QueryInterface)DP_QueryInterface,
4859 XCAST(AddRef)DP_AddRef,
4860 XCAST(Release)DP_Release,
4861
4862 DirectPlay2WImpl_AddPlayerToGroup,
4863 DirectPlay2WImpl_Close,
4864 DirectPlay2WImpl_CreateGroup,
4865 DirectPlay2WImpl_CreatePlayer,
4866 DirectPlay2WImpl_DeletePlayerFromGroup,
4867 DirectPlay2WImpl_DestroyGroup,
4868 DirectPlay2WImpl_DestroyPlayer,
4869 DirectPlay2WImpl_EnumGroupPlayers,
4870 DirectPlay2WImpl_EnumGroups,
4871 DirectPlay2WImpl_EnumPlayers,
4872 DirectPlay2WImpl_EnumSessions,
4873 DirectPlay2WImpl_GetCaps,
4874 DirectPlay2WImpl_GetGroupData,
4875 DirectPlay2WImpl_GetGroupName,
4876 DirectPlay2WImpl_GetMessageCount,
4877 DirectPlay2WImpl_GetPlayerAddress,
4878 DirectPlay2WImpl_GetPlayerCaps,
4879 DirectPlay2WImpl_GetPlayerData,
4880 DirectPlay2WImpl_GetPlayerName,
4881 DirectPlay2WImpl_GetSessionDesc,
4882 DirectPlay2WImpl_Initialize,
4883 DirectPlay2WImpl_Open,
4884 DirectPlay2WImpl_Receive,
4885 DirectPlay2WImpl_Send,
4886 DirectPlay2WImpl_SetGroupData,
4887 DirectPlay2WImpl_SetGroupName,
4888 DirectPlay2WImpl_SetPlayerData,
4889 DirectPlay2WImpl_SetPlayerName,
4890 DirectPlay2WImpl_SetSessionDesc
4891 };
4892 #undef XCAST
4893
4894 /* Note: Hack so we can reuse the old functions without compiler warnings */
4895 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4896 # define XCAST(fun) (typeof(directPlay2AVT.fun))
4897 #else
4898 # define XCAST(fun) (void*)
4899 #endif
4900
4901 static const IDirectPlay2Vtbl directPlay2AVT =
4902 {
4903 XCAST(QueryInterface)DP_QueryInterface,
4904 XCAST(AddRef)DP_AddRef,
4905 XCAST(Release)DP_Release,
4906
4907 DirectPlay2AImpl_AddPlayerToGroup,
4908 DirectPlay2AImpl_Close,
4909 DirectPlay2AImpl_CreateGroup,
4910 DirectPlay2AImpl_CreatePlayer,
4911 DirectPlay2AImpl_DeletePlayerFromGroup,
4912 DirectPlay2AImpl_DestroyGroup,
4913 DirectPlay2AImpl_DestroyPlayer,
4914 DirectPlay2AImpl_EnumGroupPlayers,
4915 DirectPlay2AImpl_EnumGroups,
4916 DirectPlay2AImpl_EnumPlayers,
4917 DirectPlay2AImpl_EnumSessions,
4918 DirectPlay2AImpl_GetCaps,
4919 DirectPlay2AImpl_GetGroupData,
4920 DirectPlay2AImpl_GetGroupName,
4921 DirectPlay2AImpl_GetMessageCount,
4922 DirectPlay2AImpl_GetPlayerAddress,
4923 DirectPlay2AImpl_GetPlayerCaps,
4924 DirectPlay2AImpl_GetPlayerData,
4925 DirectPlay2AImpl_GetPlayerName,
4926 DirectPlay2AImpl_GetSessionDesc,
4927 DirectPlay2AImpl_Initialize,
4928 DirectPlay2AImpl_Open,
4929 DirectPlay2AImpl_Receive,
4930 DirectPlay2AImpl_Send,
4931 DirectPlay2AImpl_SetGroupData,
4932 DirectPlay2AImpl_SetGroupName,
4933 DirectPlay2AImpl_SetPlayerData,
4934 DirectPlay2AImpl_SetPlayerName,
4935 DirectPlay2AImpl_SetSessionDesc
4936 };
4937 #undef XCAST
4938
4939
4940 /* Note: Hack so we can reuse the old functions without compiler warnings */
4941 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4942 # define XCAST(fun) (typeof(directPlay3AVT.fun))
4943 #else
4944 # define XCAST(fun) (void*)
4945 #endif
4946
4947 static const IDirectPlay3Vtbl directPlay3AVT =
4948 {
4949 XCAST(QueryInterface)DP_QueryInterface,
4950 XCAST(AddRef)DP_AddRef,
4951 XCAST(Release)DP_Release,
4952
4953 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
4954 XCAST(Close)DirectPlay2AImpl_Close,
4955 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
4956 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
4957 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
4958 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
4959 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
4960 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
4961 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
4962 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
4963 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
4964 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
4965 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
4966 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
4967 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
4968 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
4969 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
4970 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
4971 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
4972 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
4973 XCAST(Initialize)DirectPlay2AImpl_Initialize,
4974 XCAST(Open)DirectPlay2AImpl_Open,
4975 XCAST(Receive)DirectPlay2AImpl_Receive,
4976 XCAST(Send)DirectPlay2AImpl_Send,
4977 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
4978 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
4979 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
4980 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
4981 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
4982
4983 DirectPlay3AImpl_AddGroupToGroup,
4984 DirectPlay3AImpl_CreateGroupInGroup,
4985 DirectPlay3AImpl_DeleteGroupFromGroup,
4986 DirectPlay3AImpl_EnumConnections,
4987 DirectPlay3AImpl_EnumGroupsInGroup,
4988 DirectPlay3AImpl_GetGroupConnectionSettings,
4989 DirectPlay3AImpl_InitializeConnection,
4990 DirectPlay3AImpl_SecureOpen,
4991 DirectPlay3AImpl_SendChatMessage,
4992 DirectPlay3AImpl_SetGroupConnectionSettings,
4993 DirectPlay3AImpl_StartSession,
4994 DirectPlay3AImpl_GetGroupFlags,
4995 DirectPlay3AImpl_GetGroupParent,
4996 DirectPlay3AImpl_GetPlayerAccount,
4997 DirectPlay3AImpl_GetPlayerFlags
4998 };
4999 #undef XCAST
5000
5001 /* Note: Hack so we can reuse the old functions without compiler warnings */
5002 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5003 # define XCAST(fun) (typeof(directPlay3WVT.fun))
5004 #else
5005 # define XCAST(fun) (void*)
5006 #endif
5007 static const IDirectPlay3Vtbl directPlay3WVT =
5008 {
5009 XCAST(QueryInterface)DP_QueryInterface,
5010 XCAST(AddRef)DP_AddRef,
5011 XCAST(Release)DP_Release,
5012
5013 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5014 XCAST(Close)DirectPlay2WImpl_Close,
5015 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5016 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5017 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5018 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5019 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5020 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5021 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5022 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5023 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5024 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5025 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5026 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5027 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5028 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5029 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5030 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5031 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5032 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5033 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5034 XCAST(Open)DirectPlay2WImpl_Open,
5035 XCAST(Receive)DirectPlay2WImpl_Receive,
5036 XCAST(Send)DirectPlay2WImpl_Send,
5037 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5038 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5039 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5040 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5041 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5042
5043 DirectPlay3WImpl_AddGroupToGroup,
5044 DirectPlay3WImpl_CreateGroupInGroup,
5045 DirectPlay3WImpl_DeleteGroupFromGroup,
5046 DirectPlay3WImpl_EnumConnections,
5047 DirectPlay3WImpl_EnumGroupsInGroup,
5048 DirectPlay3WImpl_GetGroupConnectionSettings,
5049 DirectPlay3WImpl_InitializeConnection,
5050 DirectPlay3WImpl_SecureOpen,
5051 DirectPlay3WImpl_SendChatMessage,
5052 DirectPlay3WImpl_SetGroupConnectionSettings,
5053 DirectPlay3WImpl_StartSession,
5054 DirectPlay3WImpl_GetGroupFlags,
5055 DirectPlay3WImpl_GetGroupParent,
5056 DirectPlay3WImpl_GetPlayerAccount,
5057 DirectPlay3WImpl_GetPlayerFlags
5058 };
5059 #undef XCAST
5060
5061 /* Note: Hack so we can reuse the old functions without compiler warnings */
5062 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5063 # define XCAST(fun) (typeof(directPlay4WVT.fun))
5064 #else
5065 # define XCAST(fun) (void*)
5066 #endif
5067 static const IDirectPlay4Vtbl directPlay4WVT =
5068 {
5069 XCAST(QueryInterface)DP_QueryInterface,
5070 XCAST(AddRef)DP_AddRef,
5071 XCAST(Release)DP_Release,
5072
5073 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5074 XCAST(Close)DirectPlay2WImpl_Close,
5075 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5076 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5077 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5078 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5079 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5080 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5081 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5082 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5083 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5084 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5085 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5086 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5087 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5088 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5089 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5090 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5091 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5092 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5093 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5094 XCAST(Open)DirectPlay2WImpl_Open,
5095 XCAST(Receive)DirectPlay2WImpl_Receive,
5096 XCAST(Send)DirectPlay2WImpl_Send,
5097 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5098 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5099 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5100 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5101 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5102
5103 XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
5104 XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
5105 XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
5106 XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
5107 XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
5108 XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
5109 XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
5110 XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
5111 XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
5112 XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
5113 XCAST(StartSession)DirectPlay3WImpl_StartSession,
5114 XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
5115 XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
5116 XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
5117 XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
5118
5119 DirectPlay4WImpl_GetGroupOwner,
5120 DirectPlay4WImpl_SetGroupOwner,
5121 DirectPlay4WImpl_SendEx,
5122 DirectPlay4WImpl_GetMessageQueue,
5123 DirectPlay4WImpl_CancelMessage,
5124 DirectPlay4WImpl_CancelPriority
5125 };
5126 #undef XCAST
5127
5128
5129 /* Note: Hack so we can reuse the old functions without compiler warnings */
5130 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5131 # define XCAST(fun) (typeof(directPlay4AVT.fun))
5132 #else
5133 # define XCAST(fun) (void*)
5134 #endif
5135 static const IDirectPlay4Vtbl directPlay4AVT =
5136 {
5137 XCAST(QueryInterface)DP_QueryInterface,
5138 XCAST(AddRef)DP_AddRef,
5139 XCAST(Release)DP_Release,
5140
5141 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5142 XCAST(Close)DirectPlay2AImpl_Close,
5143 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5144 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5145 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5146 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5147 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5148 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5149 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5150 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5151 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5152 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5153 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5154 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5155 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5156 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5157 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5158 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5159 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5160 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5161 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5162 XCAST(Open)DirectPlay2AImpl_Open,
5163 XCAST(Receive)DirectPlay2AImpl_Receive,
5164 XCAST(Send)DirectPlay2AImpl_Send,
5165 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5166 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5167 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5168 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5169 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5170
5171 XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
5172 XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
5173 XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
5174 XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
5175 XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
5176 XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
5177 XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
5178 XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
5179 XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
5180 XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
5181 XCAST(StartSession)DirectPlay3AImpl_StartSession,
5182 XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
5183 XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
5184 XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
5185 XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
5186
5187 DirectPlay4AImpl_GetGroupOwner,
5188 DirectPlay4AImpl_SetGroupOwner,
5189 DirectPlay4AImpl_SendEx,
5190 DirectPlay4AImpl_GetMessageQueue,
5191 DirectPlay4AImpl_CancelMessage,
5192 DirectPlay4AImpl_CancelPriority
5193 };
5194 #undef XCAST
5195
5196 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
5197 DPID idPlayer,
5198 LPVOID* lplpData )
5199 {
5200 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5201
5202 if( lpPlayer == NULL )
5203 {
5204 return DPERR_INVALIDPLAYER;
5205 }
5206
5207 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5208
5209 return DP_OK;
5210 }
5211
5212 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
5213 DPID idPlayer,
5214 LPVOID lpData )
5215 {
5216 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5217
5218 if( lpPlayer == NULL )
5219 {
5220 return DPERR_INVALIDPLAYER;
5221 }
5222
5223 lpPlayer->lpPData->lpSPPlayerData = lpData;
5224
5225 return DP_OK;
5226 }
5227
5228 /***************************************************************************
5229 * DirectPlayEnumerateAW
5230 *
5231 * The pointer to the structure lpContext will be filled with the
5232 * appropriate data for each service offered by the OS. These services are
5233 * not necessarily available on this particular machine but are defined
5234 * as simple service providers under the "Service Providers" registry key.
5235 * This structure is then passed to lpEnumCallback for each of the different
5236 * services.
5237 *
5238 * This API is useful only for applications written using DirectX3 or
5239 * worse. It is superseded by IDirectPlay3::EnumConnections which also
5240 * gives information on the actual connections.
5241 *
5242 * defn of a service provider:
5243 * A dynamic-link library used by DirectPlay to communicate over a network.
5244 * The service provider contains all the network-specific code required
5245 * to send and receive messages. Online services and network operators can
5246 * supply service providers to use specialized hardware, protocols, communications
5247 * media, and network resources.
5248 *
5249 */
5250 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
5251 LPDPENUMDPCALLBACKW lpEnumCallbackW,
5252 LPVOID lpContext)
5253 {
5254 HKEY hkResult;
5255 static const WCHAR searchSubKey[] = {
5256 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
5257 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
5258 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
5259 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
5260 static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
5261 static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
5262
5263 DWORD dwIndex;
5264 FILETIME filetime;
5265
5266 char *descriptionA = NULL;
5267 DWORD max_sizeOfDescriptionA = 0;
5268 WCHAR *descriptionW = NULL;
5269 DWORD max_sizeOfDescriptionW = 0;
5270
5271 if (!lpEnumCallbackA && !lpEnumCallbackW)
5272 {
5273 return DPERR_INVALIDPARAMS;
5274 }
5275
5276 /* Need to loop over the service providers in the registry */
5277 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
5278 0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5279 {
5280 /* Hmmm. Does this mean that there are no service providers? */
5281 ERR(": no service provider key in the registry - check your Wine installation !!!\n");
5282 return DPERR_GENERIC;
5283 }
5284
5285 /* Traverse all the service providers we have available */
5286 dwIndex = 0;
5287 while (1)
5288 {
5289 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
5290 DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
5291 HKEY hkServiceProvider;
5292 GUID serviceProviderGUID;
5293 WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
5294 DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
5295 LONG ret_value;
5296
5297 ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5298 NULL, NULL, NULL, &filetime);
5299 if (ret_value == ERROR_NO_MORE_ITEMS)
5300 break;
5301 else if (ret_value != ERROR_SUCCESS)
5302 {
5303 ERR(": could not enumerate on service provider key.\n");
5304 return DPERR_EXCEPTION;
5305 }
5306 TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
5307
5308 /* Open the key for this service provider */
5309 if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
5310 {
5311 ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
5312 continue;
5313 }
5314
5315 /* Get the GUID from the registry */
5316 if (RegQueryValueExW(hkServiceProvider, guidKey,
5317 NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
5318 {
5319 ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
5320 continue;
5321 }
5322 if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
5323 {
5324 ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
5325 continue;
5326 }
5327 CLSIDFromString(guidKeyContent, &serviceProviderGUID );
5328
5329 /* The enumeration will return FALSE if we are not to continue.
5330 *
5331 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
5332 * and have no relation to any of the two dwReserved1 and dwReserved2 keys.
5333 * I think that it simply means that they are in-line with DirectX 6.0
5334 */
5335 if (lpEnumCallbackA)
5336 {
5337 DWORD sizeOfDescription = 0;
5338
5339 /* Note that this is the A case of this function, so use the A variant to get the description string */
5340 if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
5341 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5342 {
5343 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5344 continue;
5345 }
5346 if (sizeOfDescription > max_sizeOfDescriptionA)
5347 {
5348 HeapFree(GetProcessHeap(), 0, descriptionA);
5349 max_sizeOfDescriptionA = sizeOfDescription;
5350 }
5351 descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5352 RegQueryValueExA(hkServiceProvider, "DescriptionA",
5353 NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
5354
5355 if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
5356 goto end;
5357 }
5358 else
5359 {
5360 DWORD sizeOfDescription = 0;
5361
5362 if (RegQueryValueExW(hkServiceProvider, descW,
5363 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5364 {
5365 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5366 continue;
5367 }
5368 if (sizeOfDescription > max_sizeOfDescriptionW)
5369 {
5370 HeapFree(GetProcessHeap(), 0, descriptionW);
5371 max_sizeOfDescriptionW = sizeOfDescription;
5372 }
5373 descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5374 RegQueryValueExW(hkServiceProvider, descW,
5375 NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
5376
5377 if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
5378 goto end;
5379 }
5380
5381 dwIndex++;
5382 }
5383
5384 end:
5385 HeapFree(GetProcessHeap(), 0, descriptionA);
5386 HeapFree(GetProcessHeap(), 0, descriptionW);
5387
5388 return DP_OK;
5389 }
5390
5391 /***************************************************************************
5392 * DirectPlayEnumerate [DPLAYX.9]
5393 * DirectPlayEnumerateA [DPLAYX.2]
5394 */
5395 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
5396 {
5397 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5398
5399 return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5400 }
5401
5402 /***************************************************************************
5403 * DirectPlayEnumerateW [DPLAYX.3]
5404 */
5405 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5406 {
5407 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5408
5409 return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5410 }
5411
5412 typedef struct tagCreateEnum
5413 {
5414 LPVOID lpConn;
5415 LPCGUID lpGuid;
5416 } CreateEnumData, *lpCreateEnumData;
5417
5418 /* Find and copy the matching connection for the SP guid */
5419 static BOOL CALLBACK cbDPCreateEnumConnections(
5420 LPCGUID lpguidSP,
5421 LPVOID lpConnection,
5422 DWORD dwConnectionSize,
5423 LPCDPNAME lpName,
5424 DWORD dwFlags,
5425 LPVOID lpContext)
5426 {
5427 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5428
5429 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5430 {
5431 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5432
5433 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5434 dwConnectionSize );
5435 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5436
5437 /* Found the record that we were looking for */
5438 return FALSE;
5439 }
5440
5441 /* Haven't found what were looking for yet */
5442 return TRUE;
5443 }
5444
5445
5446 /***************************************************************************
5447 * DirectPlayCreate [DPLAYX.1]
5448 *
5449 */
5450 HRESULT WINAPI DirectPlayCreate
5451 ( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
5452 {
5453 HRESULT hr;
5454 LPDIRECTPLAY3A lpDP3A;
5455 CreateEnumData cbData;
5456
5457 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5458
5459 if( pUnk != NULL )
5460 {
5461 return CLASS_E_NOAGGREGATION;
5462 }
5463
5464 if( (lplpDP == NULL) || (lpGUID == NULL) )
5465 {
5466 return DPERR_INVALIDPARAMS;
5467 }
5468
5469
5470 /* Create an IDirectPlay object. We don't support that so we'll cheat and
5471 give them an IDirectPlay2A object and hope that doesn't cause problems */
5472 if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
5473 {
5474 return DPERR_UNAVAILABLE;
5475 }
5476
5477 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5478 {
5479 /* The GUID_NULL means don't bind a service provider. Just return the
5480 interface as is */
5481 return DP_OK;
5482 }
5483
5484 /* Bind the desired service provider since lpGUID is non NULL */
5485 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5486
5487 /* We're going to use a DP3 interface */
5488 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5489 (LPVOID*)&lpDP3A );
5490 if( FAILED(hr) )
5491 {
5492 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5493 return hr;
5494 }
5495
5496 cbData.lpConn = NULL;
5497 cbData.lpGuid = lpGUID;
5498
5499 /* We were given a service provider, find info about it... */
5500 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5501 &cbData, DPCONNECTION_DIRECTPLAY );
5502 if( ( FAILED(hr) ) ||
5503 ( cbData.lpConn == NULL )
5504 )
5505 {
5506 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5507 IDirectPlayX_Release( lpDP3A );
5508 return DPERR_UNAVAILABLE;
5509 }
5510
5511 /* Initialize the service provider */
5512 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5513 if( FAILED(hr) )
5514 {
5515 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5516 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5517 IDirectPlayX_Release( lpDP3A );
5518 return hr;
5519 }
5520
5521 /* Release our version of the interface now that we're done with it */
5522 IDirectPlayX_Release( lpDP3A );
5523 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5524
5525 return DP_OK;
5526 }
5527
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.