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 }
3395 }
3396 else /* UNICODE */
3397 {
3398 if( lpSessionSrc->u1.lpszSessionName )
3399 {
3400 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3401 lpSessionDest->u1.lpszSessionName );
3402 lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3403 lpStartOfFreeSpace += sizeof(WCHAR) *
3404 ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3405 }
3406
3407 if( lpSessionSrc->u2.lpszPassword )
3408 {
3409 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3410 lpSessionDest->u2.lpszPassword );
3411 lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3412 }
3413 }
3414 }
3415
3416
3417 static HRESULT DP_IF_AddGroupToGroup
3418 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3419 {
3420 lpGroupData lpGData;
3421 lpGroupList lpNewGList;
3422
3423 TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3424
3425 if( This->dp2->connectionInitialized == NO_PROVIDER )
3426 {
3427 return DPERR_UNINITIALIZED;
3428 }
3429
3430 if( DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) == NULL )
3431 {
3432 return DPERR_INVALIDGROUP;
3433 }
3434
3435 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3436 {
3437 return DPERR_INVALIDGROUP;
3438 }
3439
3440 /* Create a player list (ie "shortcut" ) */
3441 lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
3442 if( lpNewGList == NULL )
3443 {
3444 return DPERR_CANTADDPLAYER;
3445 }
3446
3447 /* Add the shortcut */
3448 lpGData->uRef++;
3449 lpNewGList->lpGData = lpGData;
3450
3451 /* Add the player to the list of players for this group */
3452 DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3453
3454 /* Send a ADDGROUPTOGROUP message */
3455 FIXME( "Not sending message\n" );
3456
3457 return DP_OK;
3458 }
3459
3460 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
3461 ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
3462 {
3463 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3464 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3465 }
3466
3467 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3468 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3469 {
3470 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3471 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3472 }
3473
3474 static HRESULT DP_IF_CreateGroupInGroup
3475 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3476 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3477 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3478 {
3479 lpGroupData lpGParentData;
3480 lpGroupList lpGList;
3481 lpGroupData lpGData;
3482
3483 TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
3484 This, idParentGroup, lpidGroup, lpGroupName, lpData,
3485 dwDataSize, dwFlags, bAnsi );
3486
3487 if( This->dp2->connectionInitialized == NO_PROVIDER )
3488 {
3489 return DPERR_UNINITIALIZED;
3490 }
3491
3492 /* Verify that the specified parent is valid */
3493 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3494 idParentGroup ) ) == NULL
3495 )
3496 {
3497 return DPERR_INVALIDGROUP;
3498 }
3499
3500 lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3501 dwFlags, idParentGroup, bAnsi );
3502
3503 if( lpGData == NULL )
3504 {
3505 return DPERR_CANTADDPLAYER; /* yes player not group */
3506 }
3507
3508 /* Something else is referencing this data */
3509 lpGData->uRef++;
3510
3511 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3512
3513 /* The list has now been inserted into the interface group list. We now
3514 need to put a "shortcut" to this group in the parent group */
3515 lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3516 if( lpGList == NULL )
3517 {
3518 FIXME( "Memory leak\n" );
3519 return DPERR_CANTADDPLAYER; /* yes player not group */
3520 }
3521
3522 lpGList->lpGData = lpGData;
3523
3524 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3525
3526 /* Let the SP know that we've created this group */
3527 if( This->dp2->spData.lpCB->CreateGroup )
3528 {
3529 DPSP_CREATEGROUPDATA data;
3530
3531 TRACE( "Calling SP CreateGroup\n" );
3532
3533 data.idGroup = *lpidGroup;
3534 data.dwFlags = dwFlags;
3535 data.lpSPMessageHeader = lpMsgHdr;
3536 data.lpISP = This->dp2->spData.lpISP;
3537
3538 (*This->dp2->spData.lpCB->CreateGroup)( &data );
3539 }
3540
3541 /* Inform all other peers of the creation of a new group. If there are
3542 * no peers keep this quiet.
3543 */
3544 if( This->dp2->lpSessionDesc &&
3545 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3546 {
3547 DPMSG_CREATEPLAYERORGROUP msg;
3548
3549 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3550 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3551 msg.dpId = *lpidGroup;
3552 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3553 msg.lpData = lpData;
3554 msg.dwDataSize = dwDataSize;
3555 msg.dpnName = *lpGroupName;
3556
3557 /* FIXME: Correct to just use send effectively? */
3558 /* FIXME: Should size include data w/ message or just message "header" */
3559 /* FIXME: Check return code */
3560 DP_SendEx( (IDirectPlay2Impl*)This,
3561 DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3562 0, 0, NULL, NULL, bAnsi );
3563 }
3564
3565 return DP_OK;
3566 }
3567
3568 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
3569 ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
3570 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3571 DWORD dwFlags )
3572 {
3573 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3574
3575 *lpidGroup = DPID_UNKNOWN;
3576
3577 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3578 lpGroupName, lpData, dwDataSize, dwFlags,
3579 TRUE );
3580 }
3581
3582 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3583 ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3584 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3585 DWORD dwFlags )
3586 {
3587 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3588
3589 *lpidGroup = DPID_UNKNOWN;
3590
3591 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3592 lpGroupName, lpData, dwDataSize,
3593 dwFlags, FALSE );
3594 }
3595
3596 static HRESULT DP_IF_DeleteGroupFromGroup
3597 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3598 {
3599 lpGroupList lpGList;
3600 lpGroupData lpGParentData;
3601
3602 TRACE("(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3603
3604 /* Is the parent group valid? */
3605 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3606 {
3607 return DPERR_INVALIDGROUP;
3608 }
3609
3610 /* Remove the group from the parent group queue */
3611 DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3612
3613 if( lpGList == NULL )
3614 {
3615 return DPERR_INVALIDGROUP;
3616 }
3617
3618 /* Decrement the ref count */
3619 lpGList->lpGData->uRef--;
3620
3621 /* Free up the list item */
3622 HeapFree( GetProcessHeap(), 0, lpGList );
3623
3624 /* Should send a DELETEGROUPFROMGROUP message */
3625 FIXME( "message not sent\n" );
3626
3627 return DP_OK;
3628 }
3629
3630 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
3631 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3632 {
3633 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3634 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3635 }
3636
3637 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3638 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3639 {
3640 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3641 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3642 }
3643
3644 static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3645 LPDWORD lpdwBufSize )
3646 {
3647 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3648 HRESULT hr;
3649
3650 dpCompoundAddress.dwDataSize = sizeof( GUID );
3651 dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
3652 dpCompoundAddress.lpData = lpcSpGuid;
3653
3654 *lplpAddrBuf = NULL;
3655 *lpdwBufSize = 0;
3656
3657 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3658 lpdwBufSize, TRUE );
3659
3660 if( hr != DPERR_BUFFERTOOSMALL )
3661 {
3662 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3663 return FALSE;
3664 }
3665
3666 /* Now allocate the buffer */
3667 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3668 *lpdwBufSize );
3669
3670 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3671 lpdwBufSize, TRUE );
3672 if( FAILED(hr) )
3673 {
3674 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3675 return FALSE;
3676 }
3677
3678 return TRUE;
3679 }
3680
3681 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
3682 ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3683 {
3684 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3685 TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3686
3687 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3688 if( dwFlags == 0 )
3689 {
3690 dwFlags = DPCONNECTION_DIRECTPLAY;
3691 }
3692
3693 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3694 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3695 )
3696 {
3697 return DPERR_INVALIDFLAGS;
3698 }
3699
3700 if( !lpEnumCallback )
3701 {
3702 return DPERR_INVALIDPARAMS;
3703 }
3704
3705 /* Enumerate DirectPlay service providers */
3706 if( dwFlags & DPCONNECTION_DIRECTPLAY )
3707 {
3708 HKEY hkResult;
3709 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3710 LPCSTR guidDataSubKey = "Guid";
3711 char subKeyName[51];
3712 DWORD dwIndex, sizeOfSubKeyName=50;
3713 FILETIME filetime;
3714
3715 /* Need to loop over the service providers in the registry */
3716 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3717 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3718 {
3719 /* Hmmm. Does this mean that there are no service providers? */
3720 ERR(": no service providers?\n");
3721 return DP_OK;
3722 }
3723
3724
3725 /* Traverse all the service providers we have available */
3726 for( dwIndex=0;
3727 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3728 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3729 ++dwIndex, sizeOfSubKeyName=51 )
3730 {
3731
3732 HKEY hkServiceProvider;
3733 GUID serviceProviderGUID;
3734 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3735 char returnBuffer[51];
3736 WCHAR buff[51];
3737 DPNAME dpName;
3738 BOOL bBuildPass;
3739
3740 LPVOID lpAddressBuffer = NULL;
3741 DWORD dwAddressBufferSize = 0;
3742
3743 TRACE(" this time through: %s\n", subKeyName );
3744
3745 /* Get a handle for this particular service provider */
3746 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3747 &hkServiceProvider ) != ERROR_SUCCESS )
3748 {
3749 ERR(": what the heck is going on?\n" );
3750 continue;
3751 }
3752
3753 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3754 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3755 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3756 {
3757 ERR(": missing GUID registry data members\n" );
3758 RegCloseKey(hkServiceProvider);
3759 continue;
3760 }
3761 RegCloseKey(hkServiceProvider);
3762
3763 /* FIXME: Check return types to ensure we're interpreting data right */
3764 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3765 CLSIDFromString( buff, &serviceProviderGUID );
3766 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3767
3768 /* Fill in the DPNAME struct for the service provider */
3769 dpName.dwSize = sizeof( dpName );
3770 dpName.dwFlags = 0;
3771 dpName.u1.lpszShortNameA = subKeyName;
3772 dpName.u2.lpszLongNameA = NULL;
3773
3774 /* Create the compound address for the service provider.
3775 * NOTE: This is a gruesome architectural scar right now. DP
3776 * uses DPL and DPL uses DP. Nasty stuff. This may be why the
3777 * native dll just gets around this little bit by allocating an
3778 * 80 byte buffer which isn't even filled with a valid compound
3779 * address. Oh well. Creating a proper compound address is the
3780 * way to go anyways despite this method taking slightly more
3781 * heap space and realtime :) */
3782
3783 bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
3784 &lpAddressBuffer,
3785 &dwAddressBufferSize );
3786 if( !bBuildPass )
3787 {
3788 ERR( "Can't build compound addr\n" );
3789 return DPERR_GENERIC;
3790 }
3791
3792 /* The enumeration will return FALSE if we are not to continue */
3793 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3794 &dpName, dwFlags, lpContext ) )
3795 {
3796 return DP_OK;
3797 }
3798 }
3799 }
3800
3801 /* Enumerate DirectPlayLobby service providers */
3802 if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
3803 {
3804 HKEY hkResult;
3805 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3806 LPCSTR guidDataSubKey = "Guid";
3807 char subKeyName[51];
3808 DWORD dwIndex, sizeOfSubKeyName=50;
3809 FILETIME filetime;
3810
3811 /* Need to loop over the service providers in the registry */
3812 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3813 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3814 {
3815 /* Hmmm. Does this mean that there are no service providers? */
3816 ERR(": no service providers?\n");
3817 return DP_OK;
3818 }
3819
3820
3821 /* Traverse all the lobby providers we have available */
3822 for( dwIndex=0;
3823 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3824 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3825 ++dwIndex, sizeOfSubKeyName=51 )
3826 {
3827
3828 HKEY hkServiceProvider;
3829 GUID serviceProviderGUID;
3830 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3831 char returnBuffer[51];
3832 WCHAR buff[51];
3833 DPNAME dpName;
3834 HRESULT hr;
3835
3836 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3837 LPVOID lpAddressBuffer = NULL;
3838 DWORD dwAddressBufferSize = 0;
3839
3840 TRACE(" this time through: %s\n", subKeyName );
3841
3842 /* Get a handle for this particular service provider */
3843 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3844 &hkServiceProvider ) != ERROR_SUCCESS )
3845 {
3846 ERR(": what the heck is going on?\n" );
3847 continue;
3848 }
3849
3850 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3851 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3852 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3853 {
3854 ERR(": missing GUID registry data members\n" );
3855 RegCloseKey(hkServiceProvider);
3856 continue;
3857 }
3858 RegCloseKey(hkServiceProvider);
3859
3860 /* FIXME: Check return types to ensure we're interpreting data right */
3861 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3862 CLSIDFromString( buff, &serviceProviderGUID );
3863 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3864
3865 /* Fill in the DPNAME struct for the service provider */
3866 dpName.dwSize = sizeof( dpName );
3867 dpName.dwFlags = 0;
3868 dpName.u1.lpszShortNameA = subKeyName;
3869 dpName.u2.lpszLongNameA = NULL;
3870
3871 /* Create the compound address for the service provider.
3872 NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3873 nast stuff. This may be why the native dll just gets around this little bit by
3874 allocating an 80 byte buffer which isn't even a filled with a valid compound
3875 address. Oh well. Creating a proper compound address is the way to go anyways
3876 despite this method taking slightly more heap space and realtime :) */
3877
3878 dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
3879 dpCompoundAddress.dwDataSize = sizeof( GUID );
3880 dpCompoundAddress.lpData = &serviceProviderGUID;
3881
3882 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3883 &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
3884 {
3885 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3886 return hr;
3887 }
3888
3889 /* Now allocate the buffer */
3890 lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
3891
3892 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3893 &dwAddressBufferSize, TRUE ) ) != DP_OK )
3894 {
3895 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3896 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3897 return hr;
3898 }
3899
3900 /* The enumeration will return FALSE if we are not to continue */
3901 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3902 &dpName, dwFlags, lpContext ) )
3903 {
3904 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3905 return DP_OK;
3906 }
3907 HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3908 }
3909 }
3910
3911 return DP_OK;
3912 }
3913
3914 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
3915 ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3916 {
3917 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3918 FIXME("(%p)->(%p,%p,%p,0x%08x): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3919 return DP_OK;
3920 }
3921
3922 static HRESULT DP_IF_EnumGroupsInGroup
3923 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
3924 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
3925 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
3926 {
3927 lpGroupList lpGList;
3928 lpGroupData lpGData;
3929
3930 FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
3931 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
3932 lpContext, dwFlags, bAnsi );
3933
3934 if( This->dp2->connectionInitialized == NO_PROVIDER )
3935 {
3936 return DPERR_UNINITIALIZED;
3937 }
3938
3939 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3940 {
3941 return DPERR_INVALIDGROUP;
3942 }
3943
3944 if( DPQ_IS_EMPTY( lpGData->groups ) )
3945 {
3946 return DP_OK;
3947 }
3948
3949 lpGList = DPQ_FIRST( lpGData->groups );
3950
3951 for( ;; )
3952 {
3953 /* FIXME: Should check dwFlags for match here */
3954
3955 if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
3956 &lpGList->lpGData->name, dwFlags,
3957 lpContext ) )
3958 {
3959 return DP_OK; /* User requested break */
3960 }
3961
3962 if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
3963 {
3964 break;
3965 }
3966
3967 lpGList = DPQ_NEXT( lpGList->groups );
3968
3969 }
3970
3971 return DP_OK;
3972 }
3973
3974 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
3975 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3976 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3977 DWORD dwFlags )
3978 {
3979 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3980 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3981 lpEnumPlayersCallback2, lpContext, dwFlags,
3982 TRUE );
3983 }
3984
3985 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
3986 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3987 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3988 DWORD dwFlags )
3989 {
3990 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3991 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3992 lpEnumPlayersCallback2, lpContext, dwFlags,
3993 FALSE );
3994 }
3995
3996 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
3997 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3998 {
3999 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4000 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4001 return DP_OK;
4002 }
4003
4004 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
4005 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
4006 {
4007 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4008 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4009 return DP_OK;
4010 }
4011
4012 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
4013 REFGUID guidDataType,
4014 DWORD dwDataSize,
4015 LPCVOID lpData,
4016 LPVOID lpContext )
4017 {
4018 /* Looking for the GUID of the provider to load */
4019 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
4020 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
4021 )
4022 {
4023 TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
4024 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
4025
4026 if( dwDataSize != sizeof( GUID ) )
4027 {
4028 ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
4029 }
4030
4031 memcpy( lpContext, lpData, dwDataSize );
4032
4033 /* There shouldn't be more than 1 GUID/compound address */
4034 return FALSE;
4035 }
4036
4037 /* Still waiting for what we want */
4038 return TRUE;
4039 }
4040
4041
4042 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
4043 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
4044 {
4045 UINT i;
4046 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4047 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4048 LPCSTR guidDataSubKey = "Guid";
4049 LPCSTR majVerDataSubKey = "dwReserved1";
4050 LPCSTR minVerDataSubKey = "dwReserved2";
4051 LPCSTR pathSubKey = "Path";
4052
4053 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
4054
4055 /* FIXME: Cloned code with a quick hack. */
4056 for( i=0; i<2; i++ )
4057 {
4058 HKEY hkResult;
4059 LPCSTR searchSubKey;
4060 char subKeyName[51];
4061 DWORD dwIndex, sizeOfSubKeyName=50;
4062 FILETIME filetime;
4063
4064 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4065 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
4066
4067
4068 /* Need to loop over the service providers in the registry */
4069 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4070 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4071 {
4072 /* Hmmm. Does this mean that there are no service providers? */
4073 ERR(": no service providers?\n");
4074 return 0;
4075 }
4076
4077 /* Traverse all the service providers we have available */
4078 for( dwIndex=0;
4079 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4080 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4081 ++dwIndex, sizeOfSubKeyName=51 )
4082 {
4083
4084 HKEY hkServiceProvider;
4085 GUID serviceProviderGUID;
4086 DWORD returnType, sizeOfReturnBuffer = 255;
4087 char returnBuffer[256];
4088 WCHAR buff[51];
4089 DWORD dwTemp, len;
4090
4091 TRACE(" this time through: %s\n", subKeyName );
4092
4093 /* Get a handle for this particular service provider */
4094 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4095 &hkServiceProvider ) != ERROR_SUCCESS )
4096 {
4097 ERR(": what the heck is going on?\n" );
4098 continue;
4099 }
4100
4101 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4102 NULL, &returnType, (LPBYTE)returnBuffer,
4103 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4104 {
4105 ERR(": missing GUID registry data members\n" );
4106 continue;
4107 }
4108
4109 /* FIXME: Check return types to ensure we're interpreting data right */
4110 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4111 CLSIDFromString( buff, &serviceProviderGUID );
4112 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4113
4114 /* Determine if this is the Service Provider that the user asked for */
4115 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4116 {
4117 continue;
4118 }
4119
4120 if( i == 0 ) /* DP SP */
4121 {
4122 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4123 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4124 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4125 }
4126
4127 sizeOfReturnBuffer = 255;
4128
4129 /* Get dwReserved1 */
4130 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4131 NULL, &returnType, (LPBYTE)returnBuffer,
4132 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4133 {
4134 ERR(": missing dwReserved1 registry data members\n") ;
4135 continue;
4136 }
4137
4138 if( i == 0 )
4139 memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
4140
4141 sizeOfReturnBuffer = 255;
4142
4143 /* Get dwReserved2 */
4144 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4145 NULL, &returnType, (LPBYTE)returnBuffer,
4146 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4147 {
4148 ERR(": missing dwReserved1 registry data members\n") ;
4149 continue;
4150 }
4151
4152 if( i == 0 )
4153 memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4154
4155 sizeOfReturnBuffer = 255;
4156
4157 /* Get the path for this service provider */
4158 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4159 NULL, NULL, (LPBYTE)returnBuffer,
4160 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4161 {
4162 ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
4163 continue;
4164 }
4165
4166 TRACE( "Loading %s\n", returnBuffer );
4167 return LoadLibraryA( returnBuffer );
4168 }
4169 }
4170
4171 return 0;
4172 }
4173
4174 static
4175 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
4176 {
4177 HRESULT hr;
4178 LPDPSP_SPINIT SPInit;
4179
4180 /* Initialize the service provider by calling SPInit */
4181 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4182
4183 if( SPInit == NULL )
4184 {
4185 ERR( "Service provider doesn't provide SPInit interface?\n" );
4186 FreeLibrary( hServiceProvider );
4187 return DPERR_UNAVAILABLE;
4188 }
4189
4190 TRACE( "Calling SPInit (DP SP entry point)\n" );
4191
4192 hr = (*SPInit)( &This->dp2->spData );
4193
4194 if( FAILED(hr) )
4195 {
4196 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4197 FreeLibrary( hServiceProvider );
4198 return hr;
4199 }
4200
4201 /* FIXME: Need to verify the sanity of the returned callback table
4202 * using IsBadCodePtr */
4203 This->dp2->bSPInitialized = TRUE;
4204
4205 /* This interface is now initialized as a DP object */
4206 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4207
4208 /* Store the handle of the module so that we can unload it later */
4209 This->dp2->hServiceProvider = hServiceProvider;
4210
4211 return hr;
4212 }
4213
4214 static
4215 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
4216 {
4217 HRESULT hr;
4218 LPSP_INIT DPLSPInit;
4219
4220 /* Initialize the service provider by calling SPInit */
4221 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4222
4223 if( DPLSPInit == NULL )
4224 {
4225 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4226 FreeLibrary( hLobbyProvider );
4227 return DPERR_UNAVAILABLE;
4228 }
4229
4230 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4231
4232 hr = (*DPLSPInit)( &This->dp2->dplspData );
4233
4234 if( FAILED(hr) )
4235 {
4236 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4237 FreeLibrary( hLobbyProvider );
4238 return hr;
4239 }
4240
4241 /* FIXME: Need to verify the sanity of the returned callback table
4242 * using IsBadCodePtr */
4243
4244 This->dp2->bDPLSPInitialized = TRUE;
4245
4246 /* This interface is now initialized as a lobby object */
4247 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4248
4249 /* Store the handle of the module so that we can unload it later */
4250 This->dp2->hDPLobbyProvider = hLobbyProvider;
4251
4252 return hr;
4253 }
4254
4255 static HRESULT DP_IF_InitializeConnection
4256 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4257 {
4258 HMODULE hServiceProvider;
4259 HRESULT hr;
4260 GUID guidSP;
4261 const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
4262 BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4263
4264 TRACE("(%p)->(%p,0x%08x,%u)\n", This, lpConnection, dwFlags, bAnsi );
4265
4266 if ( lpConnection == NULL )
4267 {
4268 return DPERR_INVALIDPARAMS;
4269 }
4270
4271 if( dwFlags != 0 )
4272 {
4273 return DPERR_INVALIDFLAGS;
4274 }
4275
4276 if( This->dp2->connectionInitialized != NO_PROVIDER )
4277 {
4278 return DPERR_ALREADYINITIALIZED;
4279 }
4280
4281 /* Find out what the requested SP is and how large this buffer is */
4282 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4283 dwAddrSize, &guidSP );
4284
4285 if( FAILED(hr) )
4286 {
4287 ERR( "Invalid compound address?\n" );
4288 return DPERR_UNAVAILABLE;
4289 }
4290
4291 /* Load the service provider */
4292 hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4293
4294 if( hServiceProvider == 0 )
4295 {
4296 ERR( "Unable to load service provider %s\n", debugstr_guid(&guidSP) );
4297 return DPERR_UNAVAILABLE;
4298 }
4299
4300 if( bIsDpSp )
4301 {
4302 /* Fill in what we can of the Service Provider required information.
4303 * The rest was be done in DP_LoadSP
4304 */
4305 This->dp2->spData.lpAddress = lpConnection;
4306 This->dp2->spData.dwAddressSize = dwAddrSize;
4307 This->dp2->spData.lpGuid = &guidSP;
4308
4309 hr = DP_InitializeDPSP( This, hServiceProvider );
4310 }
4311 else
4312 {
4313 This->dp2->dplspData.lpAddress = lpConnection;
4314
4315 hr = DP_InitializeDPLSP( This, hServiceProvider );
4316 }
4317
4318 if( FAILED(hr) )
4319 {
4320 return hr;
4321 }
4322
4323 return DP_OK;
4324 }
4325
4326 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
4327 ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
4328 {
4329 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4330
4331 /* This may not be externally invoked once either an SP or LP is initialized */
4332 if( This->dp2->connectionInitialized != NO_PROVIDER )
4333 {
4334 return DPERR_ALREADYINITIALIZED;
4335 }
4336
4337 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4338 }
4339
4340 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4341 ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4342 {
4343 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4344
4345 /* This may not be externally invoked once either an SP or LP is initialized */
4346 if( This->dp2->connectionInitialized != NO_PROVIDER )
4347 {
4348 return DPERR_ALREADYINITIALIZED;
4349 }
4350
4351 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4352 }
4353
4354 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
4355 ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4356 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4357 {
4358 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4359 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4360 }
4361
4362 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4363 ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4364 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4365 {
4366 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4367 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4368 }
4369
4370 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
4371 ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4372 {
4373 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4374 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4375 return DP_OK;
4376 }
4377
4378 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
4379 ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4380 {
4381 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4382 FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4383 return DP_OK;
4384 }
4385
4386 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
4387 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4388 {
4389 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4390 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4391 return DP_OK;
4392 }
4393
4394 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
4395 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4396 {
4397 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4398 FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4399 return DP_OK;
4400 }
4401
4402 static HRESULT WINAPI DirectPlay3AImpl_StartSession
4403 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
4404 {
4405 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4406 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4407 return DP_OK;
4408 }
4409
4410 static HRESULT WINAPI DirectPlay3WImpl_StartSession
4411 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
4412 {
4413 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4414 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4415 return DP_OK;
4416 }
4417
4418 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
4419 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
4420 {
4421 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4422 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4423 return DP_OK;
4424 }
4425
4426 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
4427 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
4428 {
4429 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4430 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4431 return DP_OK;
4432 }
4433
4434 static HRESULT DP_IF_GetGroupParent
4435 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4436 BOOL bAnsi )
4437 {
4438 lpGroupData lpGData;
4439
4440 TRACE("(%p)->(0x%08x,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4441
4442 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4443 {
4444 return DPERR_INVALIDGROUP;
4445 }
4446
4447 *lpidGroup = lpGData->dpid;
4448
4449 return DP_OK;
4450 }
4451
4452 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
4453 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
4454 {
4455 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4456 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4457 }
4458 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4459 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4460 {
4461 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4462 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4463 }
4464
4465 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
4466 ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4467 {
4468 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4469 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4470 return DP_OK;
4471 }
4472
4473 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
4474 ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4475 {
4476 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4477 FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4478 return DP_OK;
4479 }
4480
4481 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
4482 ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
4483 {
4484 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4485 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4486 return DP_OK;
4487 }
4488
4489 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
4490 ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
4491 {
4492 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4493 FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4494 return DP_OK;
4495 }
4496
4497 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4498 ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4499 {
4500 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4501 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4502 return DP_OK;
4503 }
4504
4505 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
4506 ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
4507 {
4508 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4509 FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4510 return DP_OK;
4511 }
4512
4513 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4514 ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4515 {
4516 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4517 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4518 return DP_OK;
4519 }
4520
4521 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
4522 ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
4523 {
4524 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4525 FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4526 return DP_OK;
4527 }
4528
4529 static HRESULT DP_SendEx
4530 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4531 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4532 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4533 {
4534 BOOL bValidDestination = FALSE;
4535
4536 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
4537 ": stub\n",
4538 This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4539 dwTimeout, lpContext, lpdwMsgID, bAnsi );
4540
4541 if( This->dp2->connectionInitialized == NO_PROVIDER )
4542 {
4543 return DPERR_UNINITIALIZED;
4544 }
4545
4546 /* FIXME: Add parameter checking */
4547 /* FIXME: First call to this needs to acquire a message id which will be
4548 * used for multiple sends
4549 */
4550
4551 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4552
4553 /* Verify that the message is being sent from a valid local player. The
4554 * from player may be anonymous DPID_UNKNOWN
4555 */
4556 if( idFrom != DPID_UNKNOWN )
4557 {
4558 if( DP_FindPlayer( This, idFrom ) == NULL )
4559 {
4560 WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
4561 return DPERR_INVALIDPLAYER;
4562 }
4563 }
4564
4565 /* Verify that the message is being sent to a valid player, group or to
4566 * everyone. If it's valid, send it to those players.
4567 */
4568 if( idTo == DPID_ALLPLAYERS )
4569 {
4570 bValidDestination = TRUE;
4571
4572 /* See if SP has the ability to multicast. If so, use it */
4573 if( This->dp2->spData.lpCB->SendToGroupEx )
4574 {
4575 FIXME( "Use group sendex to group 0\n" );
4576 }
4577 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4578 {
4579 FIXME( "Use obsolete group send to group 0\n" );
4580 }
4581 else /* No multicast, multiplicate */
4582 {
4583 /* Send to all players we know about */
4584 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4585 }
4586 }
4587
4588 if( ( !bValidDestination ) &&
4589 ( DP_FindPlayer( This, idTo ) != NULL )
4590 )
4591 {
4592 /* Have the service provider send this message */
4593 /* FIXME: Could optimize for local interface sends */
4594 return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4595 dwTimeout, lpContext, lpdwMsgID );
4596 }
4597
4598 if( ( !bValidDestination ) &&
4599 ( DP_FindAnyGroup( This, idTo ) != NULL )
4600 )
4601 {
4602 bValidDestination = TRUE;
4603
4604 /* See if SP has the ability to multicast. If so, use it */
4605 if( This->dp2->spData.lpCB->SendToGroupEx )
4606 {
4607 FIXME( "Use group sendex\n" );
4608 }
4609 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4610 {
4611 FIXME( "Use obsolete group send to group\n" );
4612 }
4613 else /* No multicast, multiplicate */
4614 {
4615 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4616 }
4617
4618 #if 0
4619 if( bExpectReply )
4620 {
4621 DWORD dwWaitReturn;
4622
4623 This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
4624
4625 dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4626 if( dwWaitReturn != WAIT_OBJECT_0 )
4627 {
4628 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4629 }
4630 }
4631 #endif
4632 }
4633
4634 if( !bValidDestination )
4635 {
4636 return DPERR_INVALIDPLAYER;
4637 }
4638 else
4639 {
4640 /* FIXME: Should return what the send returned */
4641 return DP_OK;
4642 }
4643 }
4644
4645
4646 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4647 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4648 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4649 LPVOID lpContext, LPDWORD lpdwMsgID )
4650 {
4651 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4652 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4653 dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4654 }
4655
4656 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4657 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4658 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4659 LPVOID lpContext, LPDWORD lpdwMsgID )
4660 {
4661 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4662 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4663 dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4664 }
4665
4666 static HRESULT DP_SP_SendEx
4667 ( IDirectPlay2Impl* This, DWORD dwFlags,
4668 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4669 LPVOID lpContext, LPDWORD lpdwMsgID )
4670 {
4671 LPDPMSG lpMElem;
4672
4673 FIXME( ": stub\n" );
4674
4675 /* FIXME: This queuing should only be for async messages */
4676
4677 lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4678 lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4679
4680 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4681
4682 /* FIXME: Need to queue based on priority */
4683 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4684
4685 return DP_OK;
4686 }
4687
4688 static HRESULT DP_IF_GetMessageQueue
4689 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4690 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4691 {
4692 HRESULT hr = DP_OK;
4693
4694 FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p,%u): semi stub\n",
4695 This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4696
4697 /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4698 /* FIXME: What about sends which are not immediate? */
4699
4700 if( This->dp2->spData.lpCB->GetMessageQueue )
4701 {
4702 DPSP_GETMESSAGEQUEUEDATA data;
4703
4704 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4705
4706 /* FIXME: None of this is documented :( */
4707
4708 data.lpISP = This->dp2->spData.lpISP;
4709 data.dwFlags = dwFlags;
4710 data.idFrom = idFrom;
4711 data.idTo = idTo;
4712 data.lpdwNumMsgs = lpdwNumMsgs;
4713 data.lpdwNumBytes = lpdwNumBytes;
4714
4715 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4716 }
4717 else
4718 {
4719 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4720 }
4721
4722 return hr;
4723 }
4724
4725 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4726 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4727 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4728 {
4729 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4730 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4731 lpdwNumBytes, TRUE );
4732 }
4733
4734 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4735 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4736 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4737 {
4738 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4739 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4740 lpdwNumBytes, FALSE );
4741 }
4742
4743 static HRESULT DP_IF_CancelMessage
4744 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4745 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4746 {
4747 HRESULT hr = DP_OK;
4748
4749 FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
4750 This, dwMsgID, dwFlags, bAnsi );
4751
4752 if( This->dp2->spData.lpCB->Cancel )
4753 {
4754 DPSP_CANCELDATA data;
4755
4756 TRACE( "Calling SP Cancel\n" );
4757
4758 /* FIXME: Undocumented callback */
4759
4760 data.lpISP = This->dp2->spData.lpISP;
4761 data.dwFlags = dwFlags;
4762 data.lprglpvSPMsgID = NULL;
4763 data.cSPMsgID = dwMsgID;
4764 data.dwMinPriority = dwMinPriority;
4765 data.dwMaxPriority = dwMaxPriority;
4766
4767 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4768 }
4769 else
4770 {
4771 FIXME( "SP doesn't implement Cancel\n" );
4772 }
4773
4774 return hr;
4775 }
4776
4777 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4778 ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4779 {
4780 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4781
4782 if( dwFlags != 0 )
4783 {
4784 return DPERR_INVALIDFLAGS;
4785 }
4786
4787 if( dwMsgID == 0 )
4788 {
4789 dwFlags |= DPCANCELSEND_ALL;
4790 }
4791
4792 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4793 }
4794
4795 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4796 ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4797 {
4798 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4799
4800 if( dwFlags != 0 )
4801 {
4802 return DPERR_INVALIDFLAGS;
4803 }
4804
4805 if( dwMsgID == 0 )
4806 {
4807 dwFlags |= DPCANCELSEND_ALL;
4808 }
4809
4810 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4811 }
4812
4813 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4814 ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4815 DWORD dwFlags )
4816 {
4817 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4818
4819 if( dwFlags != 0 )
4820 {
4821 return DPERR_INVALIDFLAGS;
4822 }
4823
4824 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4825 dwMaxPriority, TRUE );
4826 }
4827
4828 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4829 ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4830 DWORD dwFlags )
4831 {
4832 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4833
4834 if( dwFlags != 0 )
4835 {
4836 return DPERR_INVALIDFLAGS;
4837 }
4838
4839 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4840 dwMaxPriority, FALSE );
4841 }
4842
4843 /* Note: Hack so we can reuse the old functions without compiler warnings */
4844 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4845 # define XCAST(fun) (typeof(directPlay2WVT.fun))
4846 #else
4847 # define XCAST(fun) (void*)
4848 #endif
4849
4850 static const IDirectPlay2Vtbl directPlay2WVT =
4851 {
4852 XCAST(QueryInterface)DP_QueryInterface,
4853 XCAST(AddRef)DP_AddRef,
4854 XCAST(Release)DP_Release,
4855
4856 DirectPlay2WImpl_AddPlayerToGroup,
4857 DirectPlay2WImpl_Close,
4858 DirectPlay2WImpl_CreateGroup,
4859 DirectPlay2WImpl_CreatePlayer,
4860 DirectPlay2WImpl_DeletePlayerFromGroup,
4861 DirectPlay2WImpl_DestroyGroup,
4862 DirectPlay2WImpl_DestroyPlayer,
4863 DirectPlay2WImpl_EnumGroupPlayers,
4864 DirectPlay2WImpl_EnumGroups,
4865 DirectPlay2WImpl_EnumPlayers,
4866 DirectPlay2WImpl_EnumSessions,
4867 DirectPlay2WImpl_GetCaps,
4868 DirectPlay2WImpl_GetGroupData,
4869 DirectPlay2WImpl_GetGroupName,
4870 DirectPlay2WImpl_GetMessageCount,
4871 DirectPlay2WImpl_GetPlayerAddress,
4872 DirectPlay2WImpl_GetPlayerCaps,
4873 DirectPlay2WImpl_GetPlayerData,
4874 DirectPlay2WImpl_GetPlayerName,
4875 DirectPlay2WImpl_GetSessionDesc,
4876 DirectPlay2WImpl_Initialize,
4877 DirectPlay2WImpl_Open,
4878 DirectPlay2WImpl_Receive,
4879 DirectPlay2WImpl_Send,
4880 DirectPlay2WImpl_SetGroupData,
4881 DirectPlay2WImpl_SetGroupName,
4882 DirectPlay2WImpl_SetPlayerData,
4883 DirectPlay2WImpl_SetPlayerName,
4884 DirectPlay2WImpl_SetSessionDesc
4885 };
4886 #undef XCAST
4887
4888 /* Note: Hack so we can reuse the old functions without compiler warnings */
4889 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4890 # define XCAST(fun) (typeof(directPlay2AVT.fun))
4891 #else
4892 # define XCAST(fun) (void*)
4893 #endif
4894
4895 static const IDirectPlay2Vtbl directPlay2AVT =
4896 {
4897 XCAST(QueryInterface)DP_QueryInterface,
4898 XCAST(AddRef)DP_AddRef,
4899 XCAST(Release)DP_Release,
4900
4901 DirectPlay2AImpl_AddPlayerToGroup,
4902 DirectPlay2AImpl_Close,
4903 DirectPlay2AImpl_CreateGroup,
4904 DirectPlay2AImpl_CreatePlayer,
4905 DirectPlay2AImpl_DeletePlayerFromGroup,
4906 DirectPlay2AImpl_DestroyGroup,
4907 DirectPlay2AImpl_DestroyPlayer,
4908 DirectPlay2AImpl_EnumGroupPlayers,
4909 DirectPlay2AImpl_EnumGroups,
4910 DirectPlay2AImpl_EnumPlayers,
4911 DirectPlay2AImpl_EnumSessions,
4912 DirectPlay2AImpl_GetCaps,
4913 DirectPlay2AImpl_GetGroupData,
4914 DirectPlay2AImpl_GetGroupName,
4915 DirectPlay2AImpl_GetMessageCount,
4916 DirectPlay2AImpl_GetPlayerAddress,
4917 DirectPlay2AImpl_GetPlayerCaps,
4918 DirectPlay2AImpl_GetPlayerData,
4919 DirectPlay2AImpl_GetPlayerName,
4920 DirectPlay2AImpl_GetSessionDesc,
4921 DirectPlay2AImpl_Initialize,
4922 DirectPlay2AImpl_Open,
4923 DirectPlay2AImpl_Receive,
4924 DirectPlay2AImpl_Send,
4925 DirectPlay2AImpl_SetGroupData,
4926 DirectPlay2AImpl_SetGroupName,
4927 DirectPlay2AImpl_SetPlayerData,
4928 DirectPlay2AImpl_SetPlayerName,
4929 DirectPlay2AImpl_SetSessionDesc
4930 };
4931 #undef XCAST
4932
4933
4934 /* Note: Hack so we can reuse the old functions without compiler warnings */
4935 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4936 # define XCAST(fun) (typeof(directPlay3AVT.fun))
4937 #else
4938 # define XCAST(fun) (void*)
4939 #endif
4940
4941 static const IDirectPlay3Vtbl directPlay3AVT =
4942 {
4943 XCAST(QueryInterface)DP_QueryInterface,
4944 XCAST(AddRef)DP_AddRef,
4945 XCAST(Release)DP_Release,
4946
4947 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
4948 XCAST(Close)DirectPlay2AImpl_Close,
4949 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
4950 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
4951 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
4952 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
4953 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
4954 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
4955 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
4956 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
4957 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
4958 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
4959 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
4960 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
4961 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
4962 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
4963 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
4964 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
4965 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
4966 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
4967 XCAST(Initialize)DirectPlay2AImpl_Initialize,
4968 XCAST(Open)DirectPlay2AImpl_Open,
4969 XCAST(Receive)DirectPlay2AImpl_Receive,
4970 XCAST(Send)DirectPlay2AImpl_Send,
4971 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
4972 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
4973 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
4974 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
4975 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
4976
4977 DirectPlay3AImpl_AddGroupToGroup,
4978 DirectPlay3AImpl_CreateGroupInGroup,
4979 DirectPlay3AImpl_DeleteGroupFromGroup,
4980 DirectPlay3AImpl_EnumConnections,
4981 DirectPlay3AImpl_EnumGroupsInGroup,
4982 DirectPlay3AImpl_GetGroupConnectionSettings,
4983 DirectPlay3AImpl_InitializeConnection,
4984 DirectPlay3AImpl_SecureOpen,
4985 DirectPlay3AImpl_SendChatMessage,
4986 DirectPlay3AImpl_SetGroupConnectionSettings,
4987 DirectPlay3AImpl_StartSession,
4988 DirectPlay3AImpl_GetGroupFlags,
4989 DirectPlay3AImpl_GetGroupParent,
4990 DirectPlay3AImpl_GetPlayerAccount,
4991 DirectPlay3AImpl_GetPlayerFlags
4992 };
4993 #undef XCAST
4994
4995 /* Note: Hack so we can reuse the old functions without compiler warnings */
4996 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4997 # define XCAST(fun) (typeof(directPlay3WVT.fun))
4998 #else
4999 # define XCAST(fun) (void*)
5000 #endif
5001 static const IDirectPlay3Vtbl directPlay3WVT =
5002 {
5003 XCAST(QueryInterface)DP_QueryInterface,
5004 XCAST(AddRef)DP_AddRef,
5005 XCAST(Release)DP_Release,
5006
5007 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5008 XCAST(Close)DirectPlay2WImpl_Close,
5009 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5010 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5011 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5012 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5013 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5014 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5015 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5016 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5017 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5018 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5019 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5020 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5021 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5022 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5023 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5024 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5025 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5026 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5027 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5028 XCAST(Open)DirectPlay2WImpl_Open,
5029 XCAST(Receive)DirectPlay2WImpl_Receive,
5030 XCAST(Send)DirectPlay2WImpl_Send,
5031 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5032 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5033 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5034 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5035 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5036
5037 DirectPlay3WImpl_AddGroupToGroup,
5038 DirectPlay3WImpl_CreateGroupInGroup,
5039 DirectPlay3WImpl_DeleteGroupFromGroup,
5040 DirectPlay3WImpl_EnumConnections,
5041 DirectPlay3WImpl_EnumGroupsInGroup,
5042 DirectPlay3WImpl_GetGroupConnectionSettings,
5043 DirectPlay3WImpl_InitializeConnection,
5044 DirectPlay3WImpl_SecureOpen,
5045 DirectPlay3WImpl_SendChatMessage,
5046 DirectPlay3WImpl_SetGroupConnectionSettings,
5047 DirectPlay3WImpl_StartSession,
5048 DirectPlay3WImpl_GetGroupFlags,
5049 DirectPlay3WImpl_GetGroupParent,
5050 DirectPlay3WImpl_GetPlayerAccount,
5051 DirectPlay3WImpl_GetPlayerFlags
5052 };
5053 #undef XCAST
5054
5055 /* Note: Hack so we can reuse the old functions without compiler warnings */
5056 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5057 # define XCAST(fun) (typeof(directPlay4WVT.fun))
5058 #else
5059 # define XCAST(fun) (void*)
5060 #endif
5061 static const IDirectPlay4Vtbl directPlay4WVT =
5062 {
5063 XCAST(QueryInterface)DP_QueryInterface,
5064 XCAST(AddRef)DP_AddRef,
5065 XCAST(Release)DP_Release,
5066
5067 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5068 XCAST(Close)DirectPlay2WImpl_Close,
5069 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5070 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5071 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5072 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5073 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5074 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5075 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5076 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5077 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5078 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5079 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5080 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5081 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5082 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5083 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5084 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5085 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5086 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5087 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5088 XCAST(Open)DirectPlay2WImpl_Open,
5089 XCAST(Receive)DirectPlay2WImpl_Receive,
5090 XCAST(Send)DirectPlay2WImpl_Send,
5091 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5092 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5093 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5094 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5095 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5096
5097 XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
5098 XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
5099 XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
5100 XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
5101 XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
5102 XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
5103 XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
5104 XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
5105 XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
5106 XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
5107 XCAST(StartSession)DirectPlay3WImpl_StartSession,
5108 XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
5109 XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
5110 XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
5111 XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
5112
5113 DirectPlay4WImpl_GetGroupOwner,
5114 DirectPlay4WImpl_SetGroupOwner,
5115 DirectPlay4WImpl_SendEx,
5116 DirectPlay4WImpl_GetMessageQueue,
5117 DirectPlay4WImpl_CancelMessage,
5118 DirectPlay4WImpl_CancelPriority
5119 };
5120 #undef XCAST
5121
5122
5123 /* Note: Hack so we can reuse the old functions without compiler warnings */
5124 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5125 # define XCAST(fun) (typeof(directPlay4AVT.fun))
5126 #else
5127 # define XCAST(fun) (void*)
5128 #endif
5129 static const IDirectPlay4Vtbl directPlay4AVT =
5130 {
5131 XCAST(QueryInterface)DP_QueryInterface,
5132 XCAST(AddRef)DP_AddRef,
5133 XCAST(Release)DP_Release,
5134
5135 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5136 XCAST(Close)DirectPlay2AImpl_Close,
5137 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5138 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5139 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5140 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5141 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5142 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5143 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5144 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5145 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5146 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5147 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5148 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5149 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5150 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5151 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5152 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5153 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5154 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5155 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5156 XCAST(Open)DirectPlay2AImpl_Open,
5157 XCAST(Receive)DirectPlay2AImpl_Receive,
5158 XCAST(Send)DirectPlay2AImpl_Send,
5159 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5160 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5161 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5162 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5163 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5164
5165 XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
5166 XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
5167 XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
5168 XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
5169 XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
5170 XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
5171 XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
5172 XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
5173 XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
5174 XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
5175 XCAST(StartSession)DirectPlay3AImpl_StartSession,
5176 XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
5177 XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
5178 XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
5179 XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
5180
5181 DirectPlay4AImpl_GetGroupOwner,
5182 DirectPlay4AImpl_SetGroupOwner,
5183 DirectPlay4AImpl_SendEx,
5184 DirectPlay4AImpl_GetMessageQueue,
5185 DirectPlay4AImpl_CancelMessage,
5186 DirectPlay4AImpl_CancelPriority
5187 };
5188 #undef XCAST
5189
5190 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
5191 DPID idPlayer,
5192 LPVOID* lplpData )
5193 {
5194 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5195
5196 if( lpPlayer == NULL )
5197 {
5198 return DPERR_INVALIDPLAYER;
5199 }
5200
5201 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5202
5203 return DP_OK;
5204 }
5205
5206 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
5207 DPID idPlayer,
5208 LPVOID lpData )
5209 {
5210 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5211
5212 if( lpPlayer == NULL )
5213 {
5214 return DPERR_INVALIDPLAYER;
5215 }
5216
5217 lpPlayer->lpPData->lpSPPlayerData = lpData;
5218
5219 return DP_OK;
5220 }
5221
5222 /***************************************************************************
5223 * DirectPlayEnumerateAW
5224 *
5225 * The pointer to the structure lpContext will be filled with the
5226 * appropriate data for each service offered by the OS. These services are
5227 * not necessarily available on this particular machine but are defined
5228 * as simple service providers under the "Service Providers" registry key.
5229 * This structure is then passed to lpEnumCallback for each of the different
5230 * services.
5231 *
5232 * This API is useful only for applications written using DirectX3 or
5233 * worse. It is superseded by IDirectPlay3::EnumConnections which also
5234 * gives information on the actual connections.
5235 *
5236 * defn of a service provider:
5237 * A dynamic-link library used by DirectPlay to communicate over a network.
5238 * The service provider contains all the network-specific code required
5239 * to send and receive messages. Online services and network operators can
5240 * supply service providers to use specialized hardware, protocols, communications
5241 * media, and network resources.
5242 *
5243 */
5244 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
5245 LPDPENUMDPCALLBACKW lpEnumCallbackW,
5246 LPVOID lpContext)
5247 {
5248 HKEY hkResult;
5249 static const WCHAR searchSubKey[] = {
5250 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
5251 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
5252 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
5253 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
5254 static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
5255 static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
5256
5257 DWORD dwIndex;
5258 FILETIME filetime;
5259
5260 char *descriptionA = NULL;
5261 DWORD max_sizeOfDescriptionA = 0;
5262 WCHAR *descriptionW = NULL;
5263 DWORD max_sizeOfDescriptionW = 0;
5264
5265 if (!lpEnumCallbackA && !lpEnumCallbackW)
5266 {
5267 return DPERR_INVALIDPARAMS;
5268 }
5269
5270 /* Need to loop over the service providers in the registry */
5271 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
5272 0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5273 {
5274 /* Hmmm. Does this mean that there are no service providers? */
5275 ERR(": no service provider key in the registry - check your Wine installation !!!\n");
5276 return DPERR_GENERIC;
5277 }
5278
5279 /* Traverse all the service providers we have available */
5280 dwIndex = 0;
5281 while (1)
5282 {
5283 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
5284 DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
5285 HKEY hkServiceProvider;
5286 GUID serviceProviderGUID;
5287 WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
5288 DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
5289 LONG ret_value;
5290
5291 ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5292 NULL, NULL, NULL, &filetime);
5293 if (ret_value == ERROR_NO_MORE_ITEMS)
5294 break;
5295 else if (ret_value != ERROR_SUCCESS)
5296 {
5297 ERR(": could not enumerate on service provider key.\n");
5298 return DPERR_EXCEPTION;
5299 }
5300 TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
5301
5302 /* Open the key for this service provider */
5303 if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
5304 {
5305 ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
5306 continue;
5307 }
5308
5309 /* Get the GUID from the registry */
5310 if (RegQueryValueExW(hkServiceProvider, guidKey,
5311 NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
5312 {
5313 ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
5314 continue;
5315 }
5316 if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
5317 {
5318 ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
5319 continue;
5320 }
5321 CLSIDFromString(guidKeyContent, &serviceProviderGUID );
5322
5323 /* The enumeration will return FALSE if we are not to continue.
5324 *
5325 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
5326 * and have no relation to any of the two dwReserved1 and dwReserved2 keys.
5327 * I think that it simply means that they are in-line with DirectX 6.0
5328 */
5329 if (lpEnumCallbackA)
5330 {
5331 DWORD sizeOfDescription = 0;
5332
5333 /* Note that this is the A case of this function, so use the A variant to get the description string */
5334 if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
5335 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5336 {
5337 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5338 continue;
5339 }
5340 if (sizeOfDescription > max_sizeOfDescriptionA)
5341 {
5342 HeapFree(GetProcessHeap(), 0, descriptionA);
5343 max_sizeOfDescriptionA = sizeOfDescription;
5344 }
5345 descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5346 RegQueryValueExA(hkServiceProvider, "DescriptionA",
5347 NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
5348
5349 if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
5350 goto end;
5351 }
5352 else
5353 {
5354 DWORD sizeOfDescription = 0;
5355
5356 if (RegQueryValueExW(hkServiceProvider, descW,
5357 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5358 {
5359 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5360 continue;
5361 }
5362 if (sizeOfDescription > max_sizeOfDescriptionW)
5363 {
5364 HeapFree(GetProcessHeap(), 0, descriptionW);
5365 max_sizeOfDescriptionW = sizeOfDescription;
5366 }
5367 descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5368 RegQueryValueExW(hkServiceProvider, descW,
5369 NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
5370
5371 if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
5372 goto end;
5373 }
5374
5375 dwIndex++;
5376 }
5377
5378 end:
5379 HeapFree(GetProcessHeap(), 0, descriptionA);
5380 HeapFree(GetProcessHeap(), 0, descriptionW);
5381
5382 return DP_OK;
5383 }
5384
5385 /***************************************************************************
5386 * DirectPlayEnumerate [DPLAYX.9]
5387 * DirectPlayEnumerateA [DPLAYX.2]
5388 */
5389 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
5390 {
5391 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5392
5393 return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5394 }
5395
5396 /***************************************************************************
5397 * DirectPlayEnumerateW [DPLAYX.3]
5398 */
5399 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5400 {
5401 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5402
5403 return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5404 }
5405
5406 typedef struct tagCreateEnum
5407 {
5408 LPVOID lpConn;
5409 LPCGUID lpGuid;
5410 } CreateEnumData, *lpCreateEnumData;
5411
5412 /* Find and copy the matching connection for the SP guid */
5413 static BOOL CALLBACK cbDPCreateEnumConnections(
5414 LPCGUID lpguidSP,
5415 LPVOID lpConnection,
5416 DWORD dwConnectionSize,
5417 LPCDPNAME lpName,
5418 DWORD dwFlags,
5419 LPVOID lpContext)
5420 {
5421 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5422
5423 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5424 {
5425 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5426
5427 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5428 dwConnectionSize );
5429 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5430
5431 /* Found the record that we were looking for */
5432 return FALSE;
5433 }
5434
5435 /* Haven't found what were looking for yet */
5436 return TRUE;
5437 }
5438
5439
5440 /***************************************************************************
5441 * DirectPlayCreate [DPLAYX.1]
5442 *
5443 */
5444 HRESULT WINAPI DirectPlayCreate
5445 ( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
5446 {
5447 HRESULT hr;
5448 LPDIRECTPLAY3A lpDP3A;
5449 CreateEnumData cbData;
5450
5451 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5452
5453 if( pUnk != NULL )
5454 {
5455 return CLASS_E_NOAGGREGATION;
5456 }
5457
5458 if( (lplpDP == NULL) || (lpGUID == NULL) )
5459 {
5460 return DPERR_INVALIDPARAMS;
5461 }
5462
5463
5464 /* Create an IDirectPlay object. We don't support that so we'll cheat and
5465 give them an IDirectPlay2A object and hope that doesn't cause problems */
5466 if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
5467 {
5468 return DPERR_UNAVAILABLE;
5469 }
5470
5471 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5472 {
5473 /* The GUID_NULL means don't bind a service provider. Just return the
5474 interface as is */
5475 return DP_OK;
5476 }
5477
5478 /* Bind the desired service provider since lpGUID is non NULL */
5479 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5480
5481 /* We're going to use a DP3 interface */
5482 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5483 (LPVOID*)&lpDP3A );
5484 if( FAILED(hr) )
5485 {
5486 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5487 return hr;
5488 }
5489
5490 cbData.lpConn = NULL;
5491 cbData.lpGuid = lpGUID;
5492
5493 /* We were given a service provider, find info about it... */
5494 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5495 &cbData, DPCONNECTION_DIRECTPLAY );
5496 if( ( FAILED(hr) ) ||
5497 ( cbData.lpConn == NULL )
5498 )
5499 {
5500 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5501 IDirectPlayX_Release( lpDP3A );
5502 return DPERR_UNAVAILABLE;
5503 }
5504
5505 /* Initialize the service provider */
5506 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5507 if( FAILED(hr) )
5508 {
5509 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5510 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5511 IDirectPlayX_Release( lpDP3A );
5512 return hr;
5513 }
5514
5515 /* Release our version of the interface now that we're done with it */
5516 IDirectPlayX_Release( lpDP3A );
5517 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5518
5519 return DP_OK;
5520 }
5521
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.