7748156ec8d64ab69c669316ba0ecea349eab35d
[reactos.git] / reactos / dll / dplayx / dplay.c
1 /* Direct Play 2,3,4 Implementation
2 *
3 * Copyright 1998,1999,2000,2001 - Peter Hunnisett
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include "config.h"
21 #include "wine/port.h"
22
23 #include <stdarg.h>
24 #include <string.h>
25
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28 #include "windef.h"
29 #include "winerror.h"
30 #include "winbase.h"
31 #include "winnt.h"
32 #include "winreg.h"
33 #include "winnls.h"
34 #include "wine/unicode.h"
35 #include "wine/debug.h"
36
37 #include "dpinit.h"
38 #include "dplayx_global.h"
39 #include "name_server.h"
40 #include "dplayx_queue.h"
41 #include "dplaysp.h"
42 #include "dplay_global.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
45
46 /* FIXME: Should this be externed? */
47 extern HRESULT DPL_CreateCompoundAddress
48 ( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
49 LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
50
51
52 /* Local function prototypes */
53 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid );
54 static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid,
55 LPDPNAME lpName, DWORD dwFlags,
56 HANDLE hEvent, BOOL bAnsi );
57 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi );
58 static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
59 LPVOID lpData, DWORD dwDataSize );
60
61 static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, LPDPID lpid,
62 LPDPNAME lpName, DWORD dwFlags,
63 DPID idParent, BOOL bAnsi );
64 static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
65 LPVOID lpData, DWORD dwDataSize );
66 static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
67 static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid );
68 static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
69 DWORD dwPlayerType,
70 LPCDPNAME lpName,
71 DWORD dwFlags,
72 LPVOID lpContext );
73 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
74 static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType,
75 LPCDPNAME lpName, DWORD dwFlags,
76 LPVOID lpContext );
77 static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
78
79 /* Forward declarations of virtual tables */
80 static const IDirectPlay2Vtbl directPlay2AVT;
81 static const IDirectPlay3Vtbl directPlay3AVT;
82 static const IDirectPlay4Vtbl directPlay4AVT;
83
84 static const IDirectPlay2Vtbl directPlay2WVT;
85 static const IDirectPlay3Vtbl directPlay3WVT;
86 static const IDirectPlay4Vtbl directPlay4WVT;
87
88 /* Helper methods for player/group interfaces */
89 static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
90 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
91 DPID idPlayer, BOOL bAnsi );
92 static HRESULT WINAPI DP_IF_CreatePlayer
93 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, LPDPID lpidPlayer,
94 LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData,
95 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
96 static HRESULT WINAPI DP_IF_DestroyGroup
97 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi );
98 static HRESULT WINAPI DP_IF_DestroyPlayer
99 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi );
100 static HRESULT WINAPI DP_IF_EnumGroupPlayers
101 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
102 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
103 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
104 static HRESULT WINAPI DP_IF_EnumGroups
105 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
106 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
107 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
108 static HRESULT WINAPI DP_IF_EnumPlayers
109 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
110 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
111 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
112 static HRESULT WINAPI DP_IF_GetGroupData
113 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
114 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
115 static HRESULT WINAPI DP_IF_GetGroupName
116 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
117 LPDWORD lpdwDataSize, BOOL bAnsi );
118 static HRESULT WINAPI DP_IF_GetPlayerData
119 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
120 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
121 static HRESULT WINAPI DP_IF_GetPlayerName
122 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
123 LPDWORD lpdwDataSize, BOOL bAnsi );
124 static HRESULT WINAPI DP_IF_SetGroupName
125 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
126 DWORD dwFlags, BOOL bAnsi );
127 static HRESULT WINAPI DP_IF_SetPlayerData
128 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
129 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
130 static HRESULT WINAPI DP_IF_SetPlayerName
131 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
132 DWORD dwFlags, BOOL bAnsi );
133 static HRESULT WINAPI DP_IF_AddGroupToGroup
134 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
135 static HRESULT WINAPI DP_IF_CreateGroup
136 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
137 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
138 DWORD dwFlags, BOOL bAnsi );
139 static HRESULT WINAPI DP_IF_CreateGroupInGroup
140 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
141 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
142 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
143 static HRESULT WINAPI DP_IF_AddPlayerToGroup
144 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
145 DPID idPlayer, BOOL bAnsi );
146 static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
147 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
148 static HRESULT WINAPI DP_SetSessionDesc
149 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
150 DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
151 static HRESULT WINAPI DP_SecureOpen
152 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
153 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
154 BOOL bAnsi );
155 static HRESULT WINAPI DP_SendEx
156 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
157 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
158 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi );
159 static HRESULT WINAPI DP_IF_Receive
160 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
161 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
162 static HRESULT WINAPI DP_IF_GetMessageQueue
163 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
164 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
165 static HRESULT WINAPI DP_SP_SendEx
166 ( IDirectPlay2Impl* This, DWORD dwFlags,
167 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
168 LPVOID lpContext, LPDWORD lpdwMsgID );
169 static HRESULT WINAPI DP_IF_SetGroupData
170 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
171 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
172 static HRESULT WINAPI DP_IF_GetPlayerCaps
173 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
174 DWORD dwFlags );
175 static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi );
176 static HRESULT WINAPI DP_IF_CancelMessage
177 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
178 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
179 static HRESULT WINAPI DP_IF_EnumGroupsInGroup
180 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
181 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
182 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
183 static HRESULT WINAPI DP_IF_GetGroupParent
184 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
185 BOOL bAnsi );
186 static HRESULT WINAPI DP_IF_GetCaps
187 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
188 static HRESULT WINAPI DP_IF_EnumSessions
189 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
190 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
191 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
192 static HRESULT WINAPI DP_IF_InitializeConnection
193 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi );
194 static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
195 LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
196 DWORD dwFlags, LPVOID lpContext );
197 static BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
198 LPDWORD lpdwBufSize );
199
200
201
202 static inline DPID DP_NextObjectId(void);
203 static DPID DP_GetRemoteNextObjectId(void);
204
205
206 static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
207 LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
208
209
210 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
211 static HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
212 static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
213
214
215
216
217
218
219 #define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
220 #define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
221 we don't have to change much */
222 #define DPID_NAME_SERVER 0x19a9d65b /* Don't ask me why */
223
224 /* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
225 #define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )
226
227 /* Strip out all dwFlags values for CREATEPLAYER msg */
228 #define DPMSG_CREATEPLAYER_DWFLAGS(x) 0
229
230 static LONG kludgePlayerGroupId = 1000;
231
232 /* ------------------------------------------------------------------ */
233
234
235 static BOOL DP_CreateIUnknown( LPVOID lpDP )
236 {
237 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
238
239 This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) );
240 if ( This->unk == NULL )
241 {
242 return FALSE;
243 }
244
245 InitializeCriticalSection( &This->unk->DP_lock );
246
247 return TRUE;
248 }
249
250 static BOOL DP_DestroyIUnknown( LPVOID lpDP )
251 {
252 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
253
254 DeleteCriticalSection( &This->unk->DP_lock );
255 HeapFree( GetProcessHeap(), 0, This->unk );
256
257 return TRUE;
258 }
259
260 static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
261 {
262 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
263
264 This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
265 if ( This->dp2 == NULL )
266 {
267 return FALSE;
268 }
269
270 This->dp2->bConnectionOpen = FALSE;
271
272 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
273
274 This->dp2->bHostInterface = FALSE;
275
276 DPQ_INIT(This->dp2->receiveMsgs);
277 DPQ_INIT(This->dp2->sendMsgs);
278 DPQ_INIT(This->dp2->replysExpected);
279
280 if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
281 {
282 /* FIXME: Memory leak */
283 return FALSE;
284 }
285
286 /* Provide an initial session desc with nothing in it */
287 This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
288 HEAP_ZERO_MEMORY,
289 sizeof( *This->dp2->lpSessionDesc ) );
290 if( This->dp2->lpSessionDesc == NULL )
291 {
292 /* FIXME: Memory leak */
293 return FALSE;
294 }
295 This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
296
297 /* We are emulating a dp 6 implementation */
298 This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;
299
300 This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
301 sizeof( *This->dp2->spData.lpCB ) );
302 This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
303 This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
304
305 /* This is the pointer to the service provider */
306 if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
307 (LPVOID*)&This->dp2->spData.lpISP, This ) )
308 )
309 {
310 /* FIXME: Memory leak */
311 return FALSE;
312 }
313
314 /* Setup lobby provider information */
315 This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
316 This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
317 sizeof( *This->dp2->dplspData.lpCB ) );
318 This->dp2->dplspData.lpCB->dwSize = sizeof( *This->dp2->dplspData.lpCB );
319
320 if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
321 (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
322 )
323 {
324 /* FIXME: Memory leak */
325 return FALSE;
326 }
327
328 return TRUE;
329 }
330
331 /* Definition of the global function in dplayx_queue.h. #
332 * FIXME: Would it be better to have a dplayx_queue.c for this function? */
333 DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
334 {
335 HeapFree( GetProcessHeap(), 0, elem );
336 }
337
338 /* Function to delete the list of groups with this interface. Needs to
339 * delete the group and player lists associated with this group as well
340 * as the group data associated with this group. It should not delete
341 * player data as that is shared with the top player list and will be
342 * deleted with that.
343 */
344 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList );
345 DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList )
346 {
347 DPQ_DELETEQ( elem->lpGData->groups, groups,
348 lpGroupList, cbDeleteElemFromHeap );
349 DPQ_DELETEQ( elem->lpGData->players, players,
350 lpPlayerList, cbDeleteElemFromHeap );
351 HeapFree( GetProcessHeap(), 0, elem->lpGData );
352 HeapFree( GetProcessHeap(), 0, elem );
353 }
354
355 /* Function to delete the list of players with this interface. Needs to
356 * delete the player data for all players as well.
357 */
358 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList );
359 DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList )
360 {
361 HeapFree( GetProcessHeap(), 0, elem->lpPData );
362 HeapFree( GetProcessHeap(), 0, elem );
363 }
364
365 static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
366 {
367 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
368
369 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
370 {
371 TerminateThread( This->dp2->hEnumSessionThread, 0 );
372 CloseHandle( This->dp2->hEnumSessionThread );
373 }
374
375 /* Finish with the SP - have it shutdown */
376 if( This->dp2->spData.lpCB->ShutdownEx )
377 {
378 DPSP_SHUTDOWNDATA data;
379
380 TRACE( "Calling SP ShutdownEx\n" );
381
382 data.lpISP = This->dp2->spData.lpISP;
383
384 (*This->dp2->spData.lpCB->ShutdownEx)( &data );
385 }
386 else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
387 {
388 TRACE( "Calling obsolete SP Shutdown\n" );
389 (*This->dp2->spData.lpCB->Shutdown)();
390 }
391
392 /* Unload the SP (if it exists) */
393 if( This->dp2->hServiceProvider != 0 )
394 {
395 FreeLibrary( This->dp2->hServiceProvider );
396 }
397
398 /* Unload the Lobby Provider (if it exists) */
399 if( This->dp2->hDPLobbyProvider != 0 )
400 {
401 FreeLibrary( This->dp2->hDPLobbyProvider );
402 }
403
404 #if 0
405 DPQ_DELETEQ( This->dp2->players, players, lpPlayerList, cbDeletePlayerElem );
406 DPQ_DELETEQ( This->dp2->groups, groups, lpGroupList, cbDeleteGroupsElem );
407 #endif
408
409 /* FIXME: Need to delete receive and send msgs queue contents */
410
411 NS_DeleteSessionCache( This->dp2->lpNameServerData );
412
413 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
414
415 IDirectPlaySP_Release( This->dp2->spData.lpISP );
416
417 /* Delete the contents */
418 HeapFree( GetProcessHeap(), 0, This->dp2 );
419
420 return TRUE;
421 }
422
423 static BOOL DP_CreateDirectPlay3( LPVOID lpDP )
424 {
425 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
426
427 This->dp3 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp3) ) );
428 if ( This->dp3 == NULL )
429 {
430 return FALSE;
431 }
432
433 return TRUE;
434 }
435
436 static BOOL DP_DestroyDirectPlay3( LPVOID lpDP )
437 {
438 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
439
440 /* Delete the contents */
441 HeapFree( GetProcessHeap(), 0, This->dp3 );
442
443 return TRUE;
444 }
445
446 static BOOL DP_CreateDirectPlay4( LPVOID lpDP )
447 {
448 IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)lpDP;
449
450 This->dp4 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp4) ) );
451 if ( This->dp4 == NULL )
452 {
453 return FALSE;
454 }
455
456 return TRUE;
457 }
458
459 static BOOL DP_DestroyDirectPlay4( LPVOID lpDP )
460 {
461 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
462
463 /* Delete the contents */
464 HeapFree( GetProcessHeap(), 0, This->dp4 );
465
466 return TRUE;
467 }
468
469
470 /* Create a new interface */
471 extern
472 HRESULT DP_CreateInterface
473 ( REFIID riid, LPVOID* ppvObj )
474 {
475 TRACE( " for %s\n", debugstr_guid( riid ) );
476
477 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
478 sizeof( IDirectPlay2Impl ) );
479
480 if( *ppvObj == NULL )
481 {
482 return DPERR_OUTOFMEMORY;
483 }
484
485 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
486 {
487 IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj;
488 This->lpVtbl = &directPlay2WVT;
489 }
490 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
491 {
492 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj;
493 This->lpVtbl = &directPlay2AVT;
494 }
495 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
496 {
497 IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj;
498 This->lpVtbl = &directPlay3WVT;
499 }
500 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
501 {
502 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj;
503 This->lpVtbl = &directPlay3AVT;
504 }
505 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
506 {
507 IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj;
508 This->lpVtbl = &directPlay4WVT;
509 }
510 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
511 {
512 IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj;
513 This->lpVtbl = &directPlay4AVT;
514 }
515 else
516 {
517 /* Unsupported interface */
518 HeapFree( GetProcessHeap(), 0, *ppvObj );
519 *ppvObj = NULL;
520
521 return E_NOINTERFACE;
522 }
523
524 /* Initialize it */
525 if ( DP_CreateIUnknown( *ppvObj ) &&
526 DP_CreateDirectPlay2( *ppvObj ) &&
527 DP_CreateDirectPlay3( *ppvObj ) &&
528 DP_CreateDirectPlay4( *ppvObj )
529 )
530 {
531 IDirectPlayX_AddRef( (LPDIRECTPLAY2A)*ppvObj );
532
533 return S_OK;
534 }
535
536 /* Initialize failed, destroy it */
537 DP_DestroyDirectPlay4( *ppvObj );
538 DP_DestroyDirectPlay3( *ppvObj );
539 DP_DestroyDirectPlay2( *ppvObj );
540 DP_DestroyIUnknown( *ppvObj );
541
542 HeapFree( GetProcessHeap(), 0, *ppvObj );
543
544 *ppvObj = NULL;
545 return DPERR_NOMEMORY;
546 }
547
548
549 /* Direct Play methods */
550
551 /* Shared between all dplay types */
552 static HRESULT WINAPI DP_QueryInterface
553 ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj )
554 {
555 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
556 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
557
558 *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
559 sizeof( *This ) );
560
561 if( *ppvObj == NULL )
562 {
563 return DPERR_OUTOFMEMORY;
564 }
565
566 CopyMemory( *ppvObj, This, sizeof( *This ) );
567 (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
568
569 if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
570 {
571 IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj;
572 This->lpVtbl = &directPlay2WVT;
573 }
574 else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
575 {
576 IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj;
577 This->lpVtbl = &directPlay2AVT;
578 }
579 else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
580 {
581 IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj;
582 This->lpVtbl = &directPlay3WVT;
583 }
584 else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
585 {
586 IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj;
587 This->lpVtbl = &directPlay3AVT;
588 }
589 else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
590 {
591 IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj;
592 This->lpVtbl = &directPlay4WVT;
593 }
594 else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
595 {
596 IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj;
597 This->lpVtbl = &directPlay4AVT;
598 }
599 else
600 {
601 /* Unsupported interface */
602 HeapFree( GetProcessHeap(), 0, *ppvObj );
603 *ppvObj = NULL;
604
605 return E_NOINTERFACE;
606 }
607
608 IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj );
609
610 return S_OK;
611 }
612
613 /* Shared between all dplay types */
614 static ULONG WINAPI DP_AddRef
615 ( LPDIRECTPLAY3 iface )
616 {
617 ULONG ulInterfaceRefCount, ulObjRefCount;
618 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
619
620 ulObjRefCount = InterlockedIncrement( &This->unk->ulObjRef );
621 ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
622
623 TRACE( "ref count incremented to %lu:%lu for %p\n",
624 ulInterfaceRefCount, ulObjRefCount, This );
625
626 return ulObjRefCount;
627 }
628
629 static ULONG WINAPI DP_Release
630 ( LPDIRECTPLAY3 iface )
631 {
632 ULONG ulInterfaceRefCount, ulObjRefCount;
633
634 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
635
636 ulObjRefCount = InterlockedDecrement( &This->unk->ulObjRef );
637 ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
638
639 TRACE( "ref count decremented to %lu:%lu for %p\n",
640 ulInterfaceRefCount, ulObjRefCount, This );
641
642 /* Deallocate if this is the last reference to the object */
643 if( ulObjRefCount == 0 )
644 {
645 /* If we're destroying the object, this must be the last ref
646 of the last interface */
647 DP_DestroyDirectPlay4( This );
648 DP_DestroyDirectPlay3( This );
649 DP_DestroyDirectPlay2( This );
650 DP_DestroyIUnknown( This );
651 }
652
653 /* Deallocate the interface */
654 if( ulInterfaceRefCount == 0 )
655 {
656 HeapFree( GetProcessHeap(), 0, This );
657 }
658
659 return ulObjRefCount;
660 }
661
662 static inline DPID DP_NextObjectId(void)
663 {
664 return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
665 }
666
667 /* *lplpReply will be non NULL iff there is something to reply */
668 HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
669 DWORD dwMessageBodySize, LPCVOID lpcMessageHeader,
670 WORD wCommandId, WORD wVersion,
671 LPVOID* lplpReply, LPDWORD lpdwMsgSize )
672 {
673 TRACE( "(%p)->(%p,0x%08lx,%p,%u,%u)\n",
674 This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
675 wVersion );
676
677 switch( wCommandId )
678 {
679 /* Name server needs to handle this request */
680 case DPMSGCMD_ENUMSESSIONSREQUEST:
681 {
682 /* Reply expected */
683 NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
684
685 break;
686 }
687
688 /* Name server needs to handle this request */
689 case DPMSGCMD_ENUMSESSIONSREPLY:
690 {
691 /* No reply expected */
692 NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
693 This->dp2->spData.dwSPHeaderSize,
694 (LPDPMSG_ENUMSESSIONSREPLY)lpcMessageBody,
695 This->dp2->lpNameServerData );
696 break;
697 }
698
699 case DPMSGCMD_REQUESTNEWPLAYERID:
700 {
701 LPCDPMSG_REQUESTNEWPLAYERID lpcMsg =
702 (LPCDPMSG_REQUESTNEWPLAYERID)lpcMessageBody;
703
704 LPDPMSG_NEWPLAYERIDREPLY lpReply;
705
706 *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
707
708 *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
709
710 FIXME( "Ignoring dwFlags 0x%08lx in request msg\n",
711 lpcMsg->dwFlags );
712
713 /* Setup the reply */
714 lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
715 This->dp2->spData.dwSPHeaderSize );
716
717 lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
718 lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
719 lpReply->envelope.wVersion = DPMSGVER_DP6;
720
721 lpReply->dpidNewPlayerId = DP_NextObjectId();
722
723 TRACE( "Allocating new playerid 0x%08lx from remote request\n",
724 lpReply->dpidNewPlayerId );
725
726 break;
727 }
728
729 case DPMSGCMD_GETNAMETABLEREPLY:
730 case DPMSGCMD_NEWPLAYERIDREPLY:
731 {
732
733 #if 0
734 if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
735 DebugBreak();
736 #endif
737 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
738
739 break;
740 }
741
742 #if 1
743 case DPMSGCMD_JUSTENVELOPE:
744 {
745 TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08lx\n", lpcMessageHeader, ((LPDWORD)lpcMessageHeader)[1] );
746 NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
747 DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
748 }
749 #endif
750
751 case DPMSGCMD_FORWARDADDPLAYER:
752 {
753 #if 0
754 DebugBreak();
755 #endif
756 #if 1
757 TRACE( "Sending message to self to get my addr\n" );
758 DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
759 #endif
760 break;
761 }
762
763 case DPMSGCMD_FORWARDADDPLAYERNACK:
764 {
765 DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
766 break;
767 }
768
769 default:
770 {
771 FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
772 DebugBreak();
773 break;
774 }
775 }
776
777 /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
778
779 return DP_OK;
780 }
781
782
783 static HRESULT WINAPI DP_IF_AddPlayerToGroup
784 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
785 DPID idPlayer, BOOL bAnsi )
786 {
787 lpGroupData lpGData;
788 lpPlayerList lpPList;
789 lpPlayerList lpNewPList;
790
791 TRACE( "(%p)->(%p,0x%08lx,0x%08lx,%u)\n",
792 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
793
794 /* Find the group */
795 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
796 {
797 return DPERR_INVALIDGROUP;
798 }
799
800 /* Find the player */
801 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
802 {
803 return DPERR_INVALIDPLAYER;
804 }
805
806 /* Create a player list (ie "shortcut" ) */
807 lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
808 if( lpNewPList == NULL )
809 {
810 return DPERR_CANTADDPLAYER;
811 }
812
813 /* Add the shortcut */
814 lpPList->lpPData->uRef++;
815 lpNewPList->lpPData = lpPList->lpPData;
816
817 /* Add the player to the list of players for this group */
818 DPQ_INSERT(lpGData->players,lpNewPList,players);
819
820 /* Let the SP know that we've added a player to the group */
821 if( This->dp2->spData.lpCB->AddPlayerToGroup )
822 {
823 DPSP_ADDPLAYERTOGROUPDATA data;
824
825 TRACE( "Calling SP AddPlayerToGroup\n" );
826
827 data.idPlayer = idPlayer;
828 data.idGroup = idGroup;
829 data.lpISP = This->dp2->spData.lpISP;
830
831 (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
832 }
833
834 /* Inform all other peers of the addition of player to the group. If there are
835 * no peers keep this event quiet.
836 * Also, if this event was the result of another machine sending it to us,
837 * don't bother rebroadcasting it.
838 */
839 if( ( lpMsgHdr == NULL ) &&
840 This->dp2->lpSessionDesc &&
841 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
842 {
843 DPMSG_ADDPLAYERTOGROUP msg;
844 msg.dwType = DPSYS_ADDPLAYERTOGROUP;
845
846 msg.dpIdGroup = idGroup;
847 msg.dpIdPlayer = idPlayer;
848
849 /* FIXME: Correct to just use send effectively? */
850 /* FIXME: Should size include data w/ message or just message "header" */
851 /* FIXME: Check return code */
852 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
853 }
854
855 return DP_OK;
856 }
857
858 static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
859 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
860 {
861 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
862 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
863 }
864
865 static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
866 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
867 {
868 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
869 return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
870 }
871
872 static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
873 {
874 HRESULT hr = DP_OK;
875
876 TRACE("(%p)->(%u)\n", This, bAnsi );
877
878 /* FIXME: Need to find a new host I assume (how?) */
879 /* FIXME: Need to destroy all local groups */
880 /* FIXME: Need to migrate all remotely visible players to the new host */
881
882 /* Invoke the SP callback to inform of session close */
883 if( This->dp2->spData.lpCB->CloseEx )
884 {
885 DPSP_CLOSEDATA data;
886
887 TRACE( "Calling SP CloseEx\n" );
888
889 data.lpISP = This->dp2->spData.lpISP;
890
891 hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
892
893 }
894 else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
895 {
896 TRACE( "Calling SP Close (obsolete interface)\n" );
897
898 hr = (*This->dp2->spData.lpCB->Close)();
899 }
900
901 return hr;
902 }
903
904 static HRESULT WINAPI DirectPlay2AImpl_Close
905 ( LPDIRECTPLAY2A iface )
906 {
907 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
908 return DP_IF_Close( This, TRUE );
909 }
910
911 static HRESULT WINAPI DirectPlay2WImpl_Close
912 ( LPDIRECTPLAY2 iface )
913 {
914 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
915 return DP_IF_Close( This, FALSE );
916 }
917
918 static
919 lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, LPDPID lpid,
920 LPDPNAME lpName, DWORD dwFlags,
921 DPID idParent, BOOL bAnsi )
922 {
923 lpGroupData lpGData;
924
925 /* Allocate the new space and add to end of high level group list */
926 lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
927
928 if( lpGData == NULL )
929 {
930 return NULL;
931 }
932
933 DPQ_INIT(lpGData->groups);
934 DPQ_INIT(lpGData->players);
935
936 /* Set the desired player ID - no sanity checking to see if it exists */
937 lpGData->dpid = *lpid;
938
939 DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
940
941 /* FIXME: Should we check that the parent exists? */
942 lpGData->parent = idParent;
943
944 /* FIXME: Should we validate the dwFlags? */
945 lpGData->dwFlags = dwFlags;
946
947 TRACE( "Created group id 0x%08lx\n", *lpid );
948
949 return lpGData;
950 }
951
952 /* This method assumes that all links to it are already deleted */
953 static void
954 DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
955 {
956 lpGroupList lpGList;
957
958 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
959
960 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
961
962 if( lpGList == NULL )
963 {
964 ERR( "DPID 0x%08lx not found\n", dpid );
965 return;
966 }
967
968 if( --(lpGList->lpGData->uRef) )
969 {
970 FIXME( "Why is this not the last reference to group?\n" );
971 DebugBreak();
972 }
973
974 /* Delete player */
975 DP_DeleteDPNameStruct( &lpGList->lpGData->name );
976 HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
977
978 /* Remove and Delete Player List object */
979 HeapFree( GetProcessHeap(), 0, lpGList );
980
981 }
982
983 static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
984 {
985 lpGroupList lpGroups;
986
987 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
988
989 if( dpid == DPID_SYSTEM_GROUP )
990 {
991 return This->dp2->lpSysGroup;
992 }
993 else
994 {
995 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
996 }
997
998 if( lpGroups == NULL )
999 {
1000 return NULL;
1001 }
1002
1003 return lpGroups->lpGData;
1004 }
1005
1006 static HRESULT WINAPI DP_IF_CreateGroup
1007 ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
1008 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
1009 DWORD dwFlags, BOOL bAnsi )
1010 {
1011 lpGroupData lpGData;
1012
1013 TRACE( "(%p)->(%p,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
1014 This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
1015 dwFlags, bAnsi );
1016
1017 /* If the name is not specified, we must provide one */
1018 if( DPID_UNKNOWN == *lpidGroup )
1019 {
1020 /* If we are the name server, we decide on the group ids. If not, we
1021 * must ask for one before attempting a creation.
1022 */
1023 if( This->dp2->bHostInterface )
1024 {
1025 *lpidGroup = DP_NextObjectId();
1026 }
1027 else
1028 {
1029 *lpidGroup = DP_GetRemoteNextObjectId();
1030 }
1031 }
1032
1033 lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
1034 DPID_NOPARENT_GROUP, bAnsi );
1035
1036 if( lpGData == NULL )
1037 {
1038 return DPERR_CANTADDPLAYER; /* yes player not group */
1039 }
1040
1041 if( DPID_SYSTEM_GROUP == *lpidGroup )
1042 {
1043 This->dp2->lpSysGroup = lpGData;
1044 TRACE( "Inserting system group\n" );
1045 }
1046 else
1047 {
1048 /* Insert into the system group */
1049 lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
1050 lpGroup->lpGData = lpGData;
1051
1052 DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
1053 }
1054
1055 /* Something is now referencing this data */
1056 lpGData->uRef++;
1057
1058 /* Set all the important stuff for the group */
1059 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
1060
1061 /* FIXME: We should only create the system group if GetCaps returns
1062 * DPCAPS_GROUPOPTIMIZED.
1063 */
1064
1065 /* Let the SP know that we've created this group */
1066 if( This->dp2->spData.lpCB->CreateGroup )
1067 {
1068 DPSP_CREATEGROUPDATA data;
1069 DWORD dwCreateFlags = 0;
1070
1071 TRACE( "Calling SP CreateGroup\n" );
1072
1073 if( *lpidGroup == DPID_NOPARENT_GROUP )
1074 dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;
1075
1076 if( lpMsgHdr == NULL )
1077 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1078
1079 if( dwFlags & DPGROUP_HIDDEN )
1080 dwCreateFlags |= DPLAYI_GROUP_HIDDEN;
1081
1082 data.idGroup = *lpidGroup;
1083 data.dwFlags = dwCreateFlags;
1084 data.lpSPMessageHeader = lpMsgHdr;
1085 data.lpISP = This->dp2->spData.lpISP;
1086
1087 (*This->dp2->spData.lpCB->CreateGroup)( &data );
1088 }
1089
1090 /* Inform all other peers of the creation of a new group. If there are
1091 * no peers keep this event quiet.
1092 * Also if this message was sent to us, don't rebroadcast.
1093 */
1094 if( ( lpMsgHdr == NULL ) &&
1095 This->dp2->lpSessionDesc &&
1096 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1097 {
1098 DPMSG_CREATEPLAYERORGROUP msg;
1099 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1100
1101 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
1102 msg.dpId = *lpidGroup;
1103 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
1104 msg.lpData = lpData;
1105 msg.dwDataSize = dwDataSize;
1106 msg.dpnName = *lpGroupName;
1107 msg.dpIdParent = DPID_NOPARENT_GROUP;
1108 msg.dwFlags = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );
1109
1110 /* FIXME: Correct to just use send effectively? */
1111 /* FIXME: Should size include data w/ message or just message "header" */
1112 /* FIXME: Check return code */
1113 DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
1114 0, 0, NULL, NULL, bAnsi );
1115 }
1116
1117 return DP_OK;
1118 }
1119
1120 static HRESULT WINAPI DirectPlay2AImpl_CreateGroup
1121 ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1122 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1123 {
1124 *lpidGroup = DPID_UNKNOWN;
1125
1126 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1127 lpGroupName, lpData, dwDataSize, dwFlags, TRUE );
1128 }
1129
1130 static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
1131 ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1132 LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1133 {
1134 *lpidGroup = DPID_UNKNOWN;
1135
1136 return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1137 lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
1138 }
1139
1140
1141 static void
1142 DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
1143 LPVOID lpData, DWORD dwDataSize )
1144 {
1145 /* Clear out the data with this player */
1146 if( dwFlags & DPSET_LOCAL )
1147 {
1148 if ( lpGData->dwLocalDataSize != 0 )
1149 {
1150 HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
1151 lpGData->lpLocalData = NULL;
1152 lpGData->dwLocalDataSize = 0;
1153 }
1154 }
1155 else
1156 {
1157 if( lpGData->dwRemoteDataSize != 0 )
1158 {
1159 HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
1160 lpGData->lpRemoteData = NULL;
1161 lpGData->dwRemoteDataSize = 0;
1162 }
1163 }
1164
1165 /* Reallocate for new data */
1166 if( lpData != NULL )
1167 {
1168 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1169 sizeof( dwDataSize ) );
1170 CopyMemory( lpNewData, lpData, dwDataSize );
1171
1172 if( dwFlags & DPSET_LOCAL )
1173 {
1174 lpGData->lpLocalData = lpData;
1175 lpGData->dwLocalDataSize = dwDataSize;
1176 }
1177 else
1178 {
1179 lpGData->lpRemoteData = lpNewData;
1180 lpGData->dwRemoteDataSize = dwDataSize;
1181 }
1182 }
1183
1184 }
1185
1186 /* This function will just create the storage for the new player. */
1187 static
1188 lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
1189 LPDPNAME lpName, DWORD dwFlags,
1190 HANDLE hEvent, BOOL bAnsi )
1191 {
1192 lpPlayerData lpPData;
1193
1194 TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );
1195
1196 /* Allocate the storage for the player and associate it with list element */
1197 lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
1198 if( lpPData == NULL )
1199 {
1200 return NULL;
1201 }
1202
1203 /* Set the desired player ID */
1204 lpPData->dpid = *lpid;
1205
1206 DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1207
1208 lpPData->dwFlags = dwFlags;
1209
1210 /* If we were given an event handle, duplicate it */
1211 if( hEvent != 0 )
1212 {
1213 if( !DuplicateHandle( GetCurrentProcess(), hEvent,
1214 GetCurrentProcess(), &lpPData->hEvent,
1215 0, FALSE, DUPLICATE_SAME_ACCESS )
1216 )
1217 {
1218 /* FIXME: Memory leak */
1219 ERR( "Can't duplicate player msg handle %p\n", hEvent );
1220 }
1221 }
1222
1223 /* Initialize the SP data section */
1224 lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();
1225
1226 TRACE( "Created player id 0x%08lx\n", *lpid );
1227
1228 return lpPData;
1229 }
1230
1231 /* Delete the contents of the DPNAME struct */
1232 static void
1233 DP_DeleteDPNameStruct( LPDPNAME lpDPName )
1234 {
1235 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->lpszShortNameA );
1236 HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->lpszLongNameA );
1237 }
1238
1239 /* This method assumes that all links to it are already deleted */
1240 static void
1241 DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1242 {
1243 lpPlayerList lpPList;
1244
1245 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
1246
1247 DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1248
1249 if( lpPList == NULL )
1250 {
1251 ERR( "DPID 0x%08lx not found\n", dpid );
1252 return;
1253 }
1254
1255 /* Verify that this is the last reference to the data */
1256 if( --(lpPList->lpPData->uRef) )
1257 {
1258 FIXME( "Why is this not the last reference to player?\n" );
1259 DebugBreak();
1260 }
1261
1262 /* Delete player */
1263 DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1264
1265 CloseHandle( lpPList->lpPData->hEvent );
1266 HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1267
1268 /* Delete Player List object */
1269 HeapFree( GetProcessHeap(), 0, lpPList );
1270 }
1271
1272 static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
1273 {
1274 lpPlayerList lpPlayers;
1275
1276 TRACE( "(%p)->(0x%08lx)\n", This, dpid );
1277
1278 DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1279
1280 return lpPlayers;
1281 }
1282
1283 /* Basic area for Dst must already be allocated */
1284 static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi )
1285 {
1286 if( lpSrc == NULL )
1287 {
1288 ZeroMemory( lpDst, sizeof( *lpDst ) );
1289 lpDst->dwSize = sizeof( *lpDst );
1290 return TRUE;
1291 }
1292
1293 if( lpSrc->dwSize != sizeof( *lpSrc) )
1294 {
1295 return FALSE;
1296 }
1297
1298 /* Delete any existing pointers */
1299 HeapFree( GetProcessHeap(), 0, lpDst->lpszShortNameA );
1300 HeapFree( GetProcessHeap(), 0, lpDst->lpszLongNameA );
1301
1302 /* Copy as required */
1303 CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1304
1305 if( bAnsi )
1306 {
1307 if( lpSrc->lpszShortNameA )
1308 {
1309 lpDst->lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
1310 strlen(lpSrc->lpszShortNameA)+1 );
1311 strcpy( lpDst->lpszShortNameA, lpSrc->lpszShortNameA );
1312 }
1313 if( lpSrc->lpszLongNameA )
1314 {
1315 lpDst->lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
1316 strlen(lpSrc->lpszLongNameA)+1 );
1317 strcpy( lpDst->lpszLongNameA, lpSrc->lpszLongNameA );
1318 }
1319 }
1320 else
1321 {
1322 if( lpSrc->lpszShortNameA )
1323 {
1324 lpDst->lpszShortName = HeapAlloc( GetProcessHeap(), 0,
1325 (strlenW(lpSrc->lpszShortName)+1)*sizeof(WCHAR) );
1326 strcpyW( lpDst->lpszShortName, lpSrc->lpszShortName );
1327 }
1328 if( lpSrc->lpszLongNameA )
1329 {
1330 lpDst->lpszLongName = HeapAlloc( GetProcessHeap(), 0,
1331 (strlenW(lpSrc->lpszLongName)+1)*sizeof(WCHAR) );
1332 strcpyW( lpDst->lpszLongName, lpSrc->lpszLongName );
1333 }
1334 }
1335
1336 return TRUE;
1337 }
1338
1339 static void
1340 DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1341 LPVOID lpData, DWORD dwDataSize )
1342 {
1343 /* Clear out the data with this player */
1344 if( dwFlags & DPSET_LOCAL )
1345 {
1346 if ( lpPData->dwLocalDataSize != 0 )
1347 {
1348 HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
1349 lpPData->lpLocalData = NULL;
1350 lpPData->dwLocalDataSize = 0;
1351 }
1352 }
1353 else
1354 {
1355 if( lpPData->dwRemoteDataSize != 0 )
1356 {
1357 HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
1358 lpPData->lpRemoteData = NULL;
1359 lpPData->dwRemoteDataSize = 0;
1360 }
1361 }
1362
1363 /* Reallocate for new data */
1364 if( lpData != NULL )
1365 {
1366 LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1367 sizeof( dwDataSize ) );
1368 CopyMemory( lpNewData, lpData, dwDataSize );
1369
1370 if( dwFlags & DPSET_LOCAL )
1371 {
1372 lpPData->lpLocalData = lpData;
1373 lpPData->dwLocalDataSize = dwDataSize;
1374 }
1375 else
1376 {
1377 lpPData->lpRemoteData = lpNewData;
1378 lpPData->dwRemoteDataSize = dwDataSize;
1379 }
1380 }
1381
1382 }
1383
1384 static HRESULT WINAPI DP_IF_CreatePlayer
1385 ( IDirectPlay2Impl* This,
1386 LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1387 LPDPID lpidPlayer,
1388 LPDPNAME lpPlayerName,
1389 HANDLE hEvent,
1390 LPVOID lpData,
1391 DWORD dwDataSize,
1392 DWORD dwFlags,
1393 BOOL bAnsi )
1394 {
1395 HRESULT hr = DP_OK;
1396 lpPlayerData lpPData;
1397 lpPlayerList lpPList;
1398 DWORD dwCreateFlags = 0;
1399
1400 TRACE( "(%p)->(%p,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
1401 This, lpidPlayer, lpPlayerName, hEvent, lpData,
1402 dwDataSize, dwFlags, bAnsi );
1403
1404 if( dwFlags == 0 )
1405 {
1406 dwFlags = DPPLAYER_SPECTATOR;
1407 }
1408
1409 if( lpidPlayer == NULL )
1410 {
1411 return DPERR_INVALIDPARAMS;
1412 }
1413
1414
1415 /* Determine the creation flags for the player. These will be passed
1416 * to the name server if requesting a player id and to the SP when
1417 * informing it of the player creation
1418 */
1419 {
1420 if( dwFlags & DPPLAYER_SERVERPLAYER )
1421 {
1422 if( *lpidPlayer == DPID_SERVERPLAYER )
1423 {
1424 /* Server player for the host interface */
1425 dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
1426 }
1427 else if( *lpidPlayer == DPID_NAME_SERVER )
1428 {
1429 /* Name server - master of everything */
1430 dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
1431 }
1432 else
1433 {
1434 /* Server player for a non host interface */
1435 dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
1436 }
1437 }
1438
1439 if( lpMsgHdr == NULL )
1440 dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
1441 }
1442
1443 /* Verify we know how to handle all the flags */
1444 if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
1445 ( dwFlags & DPPLAYER_SPECTATOR )
1446 )
1447 )
1448 {
1449 /* Assume non fatal failure */
1450 ERR( "unknown dwFlags = 0x%08lx\n", dwFlags );
1451 }
1452
1453 /* If the name is not specified, we must provide one */
1454 if( *lpidPlayer == DPID_UNKNOWN )
1455 {
1456 /* If we are the session master, we dish out the group/player ids */
1457 if( This->dp2->bHostInterface )
1458 {
1459 *lpidPlayer = DP_NextObjectId();
1460 }
1461 else
1462 {
1463 hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1464
1465 if( FAILED(hr) )
1466 {
1467 ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
1468 return hr;
1469 }
1470 }
1471 }
1472 else
1473 {
1474 /* FIXME: Would be nice to perhaps verify that we don't already have
1475 * this player.
1476 */
1477 }
1478
1479 /* FIXME: Should we be storing these dwFlags or the creation ones? */
1480 lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwFlags,
1481 hEvent, bAnsi );
1482
1483 if( lpPData == NULL )
1484 {
1485 return DPERR_CANTADDPLAYER;
1486 }
1487
1488 /* Create the list object and link it in */
1489 lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1490 if( lpPList == NULL )
1491 {
1492 FIXME( "Memory leak\n" );
1493 return DPERR_CANTADDPLAYER;
1494 }
1495
1496 lpPData->uRef = 1;
1497 lpPList->lpPData = lpPData;
1498
1499 /* Add the player to the system group */
1500 DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1501
1502 /* Update the information and send it to all players in the session */
1503 DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1504
1505 /* Let the SP know that we've created this player */
1506 if( This->dp2->spData.lpCB->CreatePlayer )
1507 {
1508 DPSP_CREATEPLAYERDATA data;
1509
1510 data.idPlayer = *lpidPlayer;
1511 data.dwFlags = dwCreateFlags;
1512 data.lpSPMessageHeader = lpMsgHdr;
1513 data.lpISP = This->dp2->spData.lpISP;
1514
1515 TRACE( "Calling SP CreatePlayer 0x%08lx: dwFlags: 0x%08lx lpMsgHdr: %p\n",
1516 *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );
1517
1518 hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
1519 }
1520
1521 if( FAILED(hr) )
1522 {
1523 ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
1524 return hr;
1525 }
1526
1527 /* Now let the SP know that this player is a member of the system group */
1528 if( This->dp2->spData.lpCB->AddPlayerToGroup )
1529 {
1530 DPSP_ADDPLAYERTOGROUPDATA data;
1531
1532 data.idPlayer = *lpidPlayer;
1533 data.idGroup = DPID_SYSTEM_GROUP;
1534 data.lpISP = This->dp2->spData.lpISP;
1535
1536 TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );
1537
1538 hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
1539 }
1540
1541 if( FAILED(hr) )
1542 {
1543 ERR( "Failed to add player to sys group with sp: %s\n",
1544 DPLAYX_HresultToString(hr) );
1545 return hr;
1546 }
1547
1548 #if 1
1549 if( This->dp2->bHostInterface == FALSE )
1550 {
1551 /* Let the name server know about the creation of this player */
1552 /* FIXME: Is this only to be done for the creation of a server player or
1553 * is this used for regular players? If only for server players, move
1554 * this call to DP_SecureOpen(...);
1555 */
1556 #if 0
1557 TRACE( "Sending message to self to get my addr\n" );
1558 DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
1559 #endif
1560
1561 hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
1562 }
1563 #else
1564 /* Inform all other peers of the creation of a new player. If there are
1565 * no peers keep this quiet.
1566 * Also, if this was a remote event, no need to rebroadcast it.
1567 */
1568 if( ( lpMsgHdr == NULL ) &&
1569 This->dp2->lpSessionDesc &&
1570 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
1571 {
1572 DPMSG_CREATEPLAYERORGROUP msg;
1573 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
1574
1575 msg.dwPlayerType = DPPLAYERTYPE_PLAYER;
1576 msg.dpId = *lpidPlayer;
1577 msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
1578 msg.lpData = lpData;
1579 msg.dwDataSize = dwDataSize;
1580 msg.dpnName = *lpPlayerName;
1581 msg.dpIdParent = DPID_NOPARENT_GROUP;
1582 msg.dwFlags = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );
1583
1584 /* FIXME: Correct to just use send effectively? */
1585 /* FIXME: Should size include data w/ message or just message "header" */
1586 /* FIXME: Check return code */
1587 hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1588 sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1589 }
1590 #endif
1591
1592 return hr;
1593 }
1594
1595 static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
1596 ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1597 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1598 {
1599 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1600
1601 if( dwFlags & DPPLAYER_SERVERPLAYER )
1602 {
1603 *lpidPlayer = DPID_SERVERPLAYER;
1604 }
1605 else
1606 {
1607 *lpidPlayer = DPID_UNKNOWN;
1608 }
1609
1610 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1611 lpData, dwDataSize, dwFlags, TRUE );
1612 }
1613
1614 static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1615 ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
1616 HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1617 {
1618 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1619
1620 if( dwFlags & DPPLAYER_SERVERPLAYER )
1621 {
1622 *lpidPlayer = DPID_SERVERPLAYER;
1623 }
1624 else
1625 {
1626 *lpidPlayer = DPID_UNKNOWN;
1627 }
1628
1629 return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1630 lpData, dwDataSize, dwFlags, FALSE );
1631 }
1632
1633 static DPID DP_GetRemoteNextObjectId(void)
1634 {
1635 FIXME( ":stub\n" );
1636
1637 /* Hack solution */
1638 return DP_NextObjectId();
1639 }
1640
1641 static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
1642 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
1643 DPID idPlayer, BOOL bAnsi )
1644 {
1645 HRESULT hr = DP_OK;
1646
1647 lpGroupData lpGData;
1648 lpPlayerList lpPList;
1649
1650 TRACE( "(%p)->(%p,0x%08lx,0x%08lx,%u)\n",
1651 This, lpMsgHdr, idGroup, idPlayer, bAnsi );
1652
1653 /* Find the group */
1654 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1655 {
1656 return DPERR_INVALIDGROUP;
1657 }
1658
1659 /* Find the player */
1660 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
1661 {
1662 return DPERR_INVALIDPLAYER;
1663 }
1664
1665 /* Remove the player shortcut from the group */
1666 DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
1667
1668 if( lpPList == NULL )
1669 {
1670 return DPERR_INVALIDPLAYER;
1671 }
1672
1673 /* One less reference */
1674 lpPList->lpPData->uRef--;
1675
1676 /* Delete the Player List element */
1677 HeapFree( GetProcessHeap(), 0, lpPList );
1678
1679 /* Inform the SP if they care */
1680 if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
1681 {
1682 DPSP_REMOVEPLAYERFROMGROUPDATA data;
1683
1684 TRACE( "Calling SP RemovePlayerFromGroup\n" );
1685
1686 data.idPlayer = idPlayer;
1687 data.idGroup = idGroup;
1688 data.lpISP = This->dp2->spData.lpISP;
1689
1690 hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1691 }
1692
1693 /* Need to send a DELETEPLAYERFROMGROUP message */
1694 FIXME( "Need to send a message\n" );
1695
1696 return hr;
1697 }
1698
1699 static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
1700 ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
1701 {
1702 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1703 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
1704 }
1705
1706 static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
1707 ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
1708 {
1709 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1710 return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
1711 }
1712
1713 typedef struct _DPRGOPContext
1714 {
1715 IDirectPlay3Impl* This;
1716 BOOL bAnsi;
1717 DPID idGroup;
1718 } DPRGOPContext, *lpDPRGOPContext;
1719
1720 static BOOL CALLBACK
1721 cbRemoveGroupOrPlayer(
1722 DPID dpId,
1723 DWORD dwPlayerType,
1724 LPCDPNAME lpName,
1725 DWORD dwFlags,
1726 LPVOID lpContext )
1727 {
1728 lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1729
1730 TRACE( "Removing element:0x%08lx (type:0x%08lx) from element:0x%08lx\n",
1731 dpId, dwPlayerType, lpCtxt->idGroup );
1732
1733 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1734 {
1735 if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
1736 dpId )
1737 )
1738 )
1739 {
1740 ERR( "Unable to delete group 0x%08lx from group 0x%08lx\n",
1741 dpId, lpCtxt->idGroup );
1742 }
1743 }
1744 else
1745 {
1746 if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
1747 NULL, lpCtxt->idGroup,
1748 dpId, lpCtxt->bAnsi )
1749 )
1750 )
1751 {
1752 ERR( "Unable to delete player 0x%08lx from grp 0x%08lx\n",
1753 dpId, lpCtxt->idGroup );
1754 }
1755 }
1756
1757 return TRUE; /* Continue enumeration */
1758 }
1759
1760 static HRESULT WINAPI DP_IF_DestroyGroup
1761 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
1762 {
1763 lpGroupData lpGData;
1764 DPRGOPContext context;
1765
1766 FIXME( "(%p)->(%p,0x%08lx,%u): semi stub\n",
1767 This, lpMsgHdr, idGroup, bAnsi );
1768
1769 /* Find the group */
1770 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1771 {
1772 return DPERR_INVALIDPLAYER; /* yes player */
1773 }
1774
1775 context.This = (IDirectPlay3Impl*)This;
1776 context.bAnsi = bAnsi;
1777 context.idGroup = idGroup;
1778
1779 /* Remove all players that this group has */
1780 DP_IF_EnumGroupPlayers( This, idGroup, NULL,
1781 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1782
1783 /* Remove all links to groups that this group has since this is dp3 */
1784 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
1785 cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1786
1787 /* Remove this group from the parent group - if it has one */
1788 if( ( idGroup != DPID_SYSTEM_GROUP ) &&
1789 ( lpGData->parent != DPID_SYSTEM_GROUP )
1790 )
1791 {
1792 DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
1793 idGroup );
1794 }
1795
1796 /* Now delete this group data and list from the system group */
1797 DP_DeleteGroup( This, idGroup );
1798
1799 /* Let the SP know that we've destroyed this group */
1800 if( This->dp2->spData.lpCB->DeleteGroup )
1801 {
1802 DPSP_DELETEGROUPDATA data;
1803
1804 FIXME( "data.dwFlags is incorrect\n" );
1805
1806 data.idGroup = idGroup;
1807 data.dwFlags = 0;
1808 data.lpISP = This->dp2->spData.lpISP;
1809
1810 (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1811 }
1812
1813 FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1814
1815 return DP_OK;
1816 }
1817
1818 static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
1819 ( LPDIRECTPLAY2A iface, DPID idGroup )
1820 {
1821 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1822 return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1823 }
1824
1825 static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
1826 ( LPDIRECTPLAY2 iface, DPID idGroup )
1827 {
1828 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1829 return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1830 }
1831
1832 typedef struct _DPFAGContext
1833 {
1834 IDirectPlay2Impl* This;
1835 DPID idPlayer;
1836 BOOL bAnsi;
1837 } DPFAGContext, *lpDPFAGContext;
1838
1839 static HRESULT WINAPI DP_IF_DestroyPlayer
1840 ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1841 {
1842 DPFAGContext cbContext;
1843
1844 FIXME( "(%p)->(%p,0x%08lx,%u): semi stub\n",
1845 This, lpMsgHdr, idPlayer, bAnsi );
1846
1847 if( This->dp2->connectionInitialized == NO_PROVIDER )
1848 {
1849 return DPERR_UNINITIALIZED;
1850 }
1851
1852 if( DP_FindPlayer( This, idPlayer ) == NULL )
1853 {
1854 return DPERR_INVALIDPLAYER;
1855 }
1856
1857 /* FIXME: If the player is remote, we must be the host to delete this */
1858
1859 cbContext.This = This;
1860 cbContext.idPlayer = idPlayer;
1861 cbContext.bAnsi = bAnsi;
1862
1863 /* Find each group and call DeletePlayerFromGroup if the player is a
1864 member of the group */
1865 DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
1866 (LPVOID)&cbContext, DPENUMGROUPS_ALL, bAnsi );
1867
1868 /* Now delete player and player list from the sys group */
1869 DP_DeletePlayer( This, idPlayer );
1870
1871 /* Let the SP know that we've destroyed this group */
1872 if( This->dp2->spData.lpCB->DeletePlayer )
1873 {
1874 DPSP_DELETEPLAYERDATA data;
1875
1876 FIXME( "data.dwFlags is incorrect\n" );
1877
1878 data.idPlayer = idPlayer;
1879 data.dwFlags = 0;
1880 data.lpISP = This->dp2->spData.lpISP;
1881
1882 (*This->dp2->spData.lpCB->DeletePlayer)( &data );
1883 }
1884
1885 FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
1886
1887 return DP_OK;
1888 }
1889
1890 static BOOL CALLBACK
1891 cbDeletePlayerFromAllGroups(
1892 DPID dpId,
1893 DWORD dwPlayerType,
1894 LPCDPNAME lpName,
1895 DWORD dwFlags,
1896 LPVOID lpContext )
1897 {
1898 lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;
1899
1900 if( dwPlayerType == DPPLAYERTYPE_GROUP )
1901 {
1902 DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
1903 lpCtxt->bAnsi );
1904
1905 /* Enumerate all groups in this group since this will normally only
1906 * be called for top level groups
1907 */
1908 DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
1909 dpId, NULL,
1910 cbDeletePlayerFromAllGroups,
1911 (LPVOID)lpContext, DPENUMGROUPS_ALL,
1912 lpCtxt->bAnsi );
1913
1914 }
1915 else
1916 {
1917 ERR( "Group callback has dwPlayerType = 0x%08lx\n", dwPlayerType );
1918 }
1919
1920 return TRUE;
1921 }
1922
1923 static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
1924 ( LPDIRECTPLAY2A iface, DPID idPlayer )
1925 {
1926 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1927 return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
1928 }
1929
1930 static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
1931 ( LPDIRECTPLAY2 iface, DPID idPlayer )
1932 {
1933 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1934 return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
1935 }
1936
1937 static HRESULT WINAPI DP_IF_EnumGroupPlayers
1938 ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
1939 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
1940 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
1941 {
1942 lpGroupData lpGData;
1943 lpPlayerList lpPList;
1944
1945 FIXME("(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): semi stub\n",
1946 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
1947 lpContext, dwFlags, bAnsi );
1948
1949 if( This->dp2->connectionInitialized == NO_PROVIDER )
1950 {
1951 return DPERR_UNINITIALIZED;
1952 }
1953
1954 /* Find the group */
1955 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1956 {
1957 return DPERR_INVALIDGROUP;
1958 }
1959
1960 if( DPQ_IS_EMPTY( lpGData->players ) )
1961 {
1962 return DP_OK;
1963 }
1964
1965 lpPList = DPQ_FIRST( lpGData->players );
1966
1967 /* Walk the players in this group */
1968 for( ;; )
1969 {
1970 /* We do not enum the name server or app server as they are of no
1971 * concequence to the end user.
1972 */
1973 if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
1974 ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
1975 )
1976 {
1977
1978 /* FIXME: Need to add stuff for dwFlags checking */
1979
1980 if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
1981 &lpPList->lpPData->name,
1982 lpPList->lpPData->dwFlags,
1983 lpContext )
1984 )
1985 {
1986 /* User requested break */
1987 return DP_OK;
1988 }
1989 }
1990
1991 if( DPQ_IS_ENDOFLIST( lpPList->players ) )
1992 {
1993 break;
1994 }
1995
1996 lpPList = DPQ_NEXT( lpPList->players );
1997 }
1998
1999 return DP_OK;
2000 }
2001
2002 static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
2003 ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance,
2004 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2005 LPVOID lpContext, DWORD dwFlags )
2006 {
2007 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2008 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2009 lpEnumPlayersCallback2, lpContext,
2010 dwFlags, TRUE );
2011 }
2012
2013 static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
2014 ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
2015 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2016 LPVOID lpContext, DWORD dwFlags )
2017 {
2018 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2019 return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
2020 lpEnumPlayersCallback2, lpContext,
2021 dwFlags, FALSE );
2022 }
2023
2024 /* NOTE: This only enumerates top level groups (created with CreateGroup) */
2025 static HRESULT WINAPI DP_IF_EnumGroups
2026 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2027 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2028 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2029 {
2030 return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This,
2031 DPID_SYSTEM_GROUP, lpguidInstance,
2032 lpEnumPlayersCallback2, lpContext,
2033 dwFlags, bAnsi );
2034 }
2035
2036 static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
2037 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2038 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2039 LPVOID lpContext, DWORD dwFlags )
2040 {
2041 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2042 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2043 lpContext, dwFlags, TRUE );
2044 }
2045
2046 static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
2047 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2048 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2049 LPVOID lpContext, DWORD dwFlags )
2050 {
2051 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2052 return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
2053 lpContext, dwFlags, FALSE );
2054 }
2055
2056 static HRESULT WINAPI DP_IF_EnumPlayers
2057 ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
2058 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2059 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2060 {
2061 return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance,
2062 lpEnumPlayersCallback2, lpContext,
2063 dwFlags, bAnsi );
2064 }
2065
2066 static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
2067 ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
2068 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2069 LPVOID lpContext, DWORD dwFlags )
2070 {
2071 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2072 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2073 lpContext, dwFlags, TRUE );
2074 }
2075
2076 static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
2077 ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
2078 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2079 LPVOID lpContext, DWORD dwFlags )
2080 {
2081 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2082 return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
2083 lpContext, dwFlags, FALSE );
2084 }
2085
2086 /* This function should call the registered callback function that the user
2087 passed into EnumSessions for each entry available.
2088 */
2089 static void DP_InvokeEnumSessionCallbacks
2090 ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2091 LPVOID lpNSInfo,
2092 DWORD dwTimeout,
2093 LPVOID lpContext )
2094 {
2095 LPDPSESSIONDESC2 lpSessionDesc;
2096
2097 FIXME( ": not checking for conditions\n" );
2098
2099 /* Not sure if this should be pruning but it's convenient */
2100 NS_PruneSessionCache( lpNSInfo );
2101
2102 NS_ResetSessionEnumeration( lpNSInfo );
2103
2104 /* Enumerate all sessions */
2105 /* FIXME: Need to indicate ANSI */
2106 while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
2107 {
2108 TRACE( "EnumSessionsCallback2 invoked\n" );
2109 if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
2110 {
2111 return;
2112 }
2113 }
2114
2115 /* Invoke one last time to indicate that there is no more to come */
2116 lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
2117 }
2118
2119 static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
2120 {
2121 EnumSessionAsyncCallbackData* data = (EnumSessionAsyncCallbackData*)lpContext;
2122 HANDLE hSuicideRequest = data->hSuicideRequest;
2123 DWORD dwTimeout = data->dwTimeout;
2124
2125 TRACE( "Thread started with timeout = 0x%08lx\n", dwTimeout );
2126
2127 for( ;; )
2128 {
2129 HRESULT hr;
2130
2131 /* Sleep up to dwTimeout waiting for request to terminate thread */
2132 if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
2133 {
2134 TRACE( "Thread terminating on terminate request\n" );
2135 break;
2136 }
2137
2138 /* Now resend the enum request */
2139 hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
2140 data->dwEnumSessionFlags,
2141 data->lpSpData );
2142
2143 if( FAILED(hr) )
2144 {
2145 ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
2146 /* FIXME: Should we kill this thread? How to inform the main thread? */
2147 }
2148
2149 }
2150
2151 TRACE( "Thread terminating\n" );
2152
2153 /* Clean up the thread data */
2154 CloseHandle( hSuicideRequest );
2155 HeapFree( GetProcessHeap(), 0, lpContext );
2156
2157 /* FIXME: Need to have some notification to main app thread that this is
2158 * dead. It would serve two purposes. 1) allow sync on termination
2159 * so that we don't actually send something to ourselves when we
2160 * become name server (race condition) and 2) so that if we die
2161 * abnormally something else will be able to tell.
2162 */
2163
2164 return 1;
2165 }
2166
2167 static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
2168 {
2169 /* Does a thread exist? If so we were doing an async enum session */
2170 if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
2171 {
2172 TRACE( "Killing EnumSession thread %p\n",
2173 This->dp2->hEnumSessionThread );
2174
2175 /* Request that the thread kill itself nicely */
2176 SetEvent( This->dp2->hKillEnumSessionThreadEvent );
2177 CloseHandle( This->dp2->hKillEnumSessionThreadEvent );
2178
2179 /* We no longer need to know about the thread */
2180 CloseHandle( This->dp2->hEnumSessionThread );
2181
2182 This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
2183 }
2184 }
2185
2186 static HRESULT WINAPI DP_IF_EnumSessions
2187 ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2188 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2189 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2190 {
2191 HRESULT hr = DP_OK;
2192
2193 TRACE( "(%p)->(%p,0x%08lx,%p,%p,0x%08lx,%u)\n",
2194 This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
2195 bAnsi );
2196
2197 /* Can't enumerate if the interface is already open */
2198 if( This->dp2->bConnectionOpen )
2199 {
2200 return DPERR_GENERIC;
2201 }
2202
2203 #if 1
2204 /* The loading of a lobby provider _seems_ to require a backdoor loading
2205 * of the service provider to also associate with this DP object. This is
2206 * because the app doesn't seem to have to call EnumConnections and
2207 * InitializeConnection for the SP before calling this method. As such
2208 * we'll do their dirty work for them with a quick hack so as to always
2209 * load the TCP/IP service provider.
2210 *
2211 * The correct solution would seem to involve creating a dialog box which
2212 * contains the possible SPs. These dialog boxes most likely follow SDK
2213 * examples.
2214 */
2215 if( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2216 {
2217 LPVOID lpConnection;
2218 DWORD dwSize;
2219
2220 WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
2221
2222 if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) )
2223 {
2224 ERR( "Can't build compound addr\n" );
2225 return DPERR_GENERIC;
2226 }
2227
2228 hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
2229 0, bAnsi );
2230 if( FAILED(hr) )
2231 {
2232 return hr;
2233 }
2234
2235 /* Free up the address buffer */
2236 HeapFree( GetProcessHeap(), 0, lpConnection );
2237
2238 /* The SP is now initialized */
2239 This->dp2->bSPInitialized = TRUE;
2240 }
2241 #endif
2242
2243
2244 /* Use the service provider default? */
2245 if( dwTimeout == 0 )
2246 {
2247 DPCAPS spCaps;
2248 spCaps.dwSize = sizeof( spCaps );
2249
2250 DP_IF_GetCaps( This, &spCaps, 0 );
2251 dwTimeout = spCaps.dwTimeout;
2252
2253 /* The service provider doesn't provide one either! */
2254 if( dwTimeout == 0 )
2255 {
2256 /* Provide the TCP/IP default */
2257 dwTimeout = DPMSG_WAIT_5_SECS;
2258 }
2259 }
2260
2261 if( dwFlags & DPENUMSESSIONS_STOPASYNC )
2262 {
2263 DP_KillEnumSessionThread( This );
2264 return hr;
2265 }
2266
2267 /* FIXME: Interface locking sucks in this method */
2268 if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
2269 {
2270 /* Enumerate everything presently in the local session cache */
2271 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2272 This->dp2->lpNameServerData, dwTimeout,
2273 lpContext );
2274
2275
2276 /* See if we've already created a thread to service this interface */
2277 if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
2278 {
2279 DWORD dwThreadId;
2280
2281 /* Send the first enum request inline since the user may cancel a dialog
2282 * if one is presented. Also, may also have a connecting return code.
2283 */
2284 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2285 dwFlags, &This->dp2->spData );
2286
2287 if( !FAILED(hr) )
2288 {
2289 EnumSessionAsyncCallbackData* lpData
2290 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpData ) );
2291 /* FIXME: need to kill the thread on object deletion */
2292 lpData->lpSpData = &This->dp2->spData;
2293
2294 CopyMemory( &lpData->requestGuid, &lpsd->guidApplication, sizeof(GUID) );
2295 lpData->dwEnumSessionFlags = dwFlags;
2296 lpData->dwTimeout = dwTimeout;
2297
2298 This->dp2->hKillEnumSessionThreadEvent =
2299 CreateEventW( NULL, TRUE, FALSE, NULL );
2300
2301 if( !DuplicateHandle( GetCurrentProcess(),
2302 This->dp2->hKillEnumSessionThreadEvent,
2303 GetCurrentProcess(),
2304 &lpData->hSuicideRequest,
2305 0, FALSE, DUPLICATE_SAME_ACCESS )
2306 )
2307 {
2308 ERR( "Can't duplicate thread killing handle\n" );
2309 }
2310
2311 TRACE( ": creating EnumSessionsRequest thread\n" );
2312
2313 This->dp2->hEnumSessionThread = CreateThread( NULL,
2314 0,
2315 DP_EnumSessionsSendAsyncRequestThread,
2316 lpData,
2317 0,
2318 &dwThreadId );
2319 }
2320 }
2321 }
2322 else
2323 {
2324 /* Invalidate the session cache for the interface */
2325 NS_InvalidateSessionCache( This->dp2->lpNameServerData );
2326
2327 /* Send the broadcast for session enumeration */
2328 hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
2329 dwFlags,
2330 &This->dp2->spData );
2331
2332
2333 SleepEx( dwTimeout, FALSE );
2334
2335 DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
2336 This->dp2->lpNameServerData, dwTimeout,
2337 lpContext );
2338 }
2339
2340 return hr;
2341 }
2342
2343 static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
2344 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2345 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2346 LPVOID lpContext, DWORD dwFlags )
2347 {
2348 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2349 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2350 lpContext, dwFlags, TRUE );
2351 }
2352
2353 static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
2354 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2355 LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
2356 LPVOID lpContext, DWORD dwFlags )
2357 {
2358 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2359 return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
2360 lpContext, dwFlags, FALSE );
2361 }
2362
2363 static HRESULT WINAPI DP_IF_GetPlayerCaps
2364 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
2365 DWORD dwFlags )
2366 {
2367 DPSP_GETCAPSDATA data;
2368
2369 TRACE("(%p)->(0x%08lx,%p,0x%08lx)\n", This, idPlayer, lpDPCaps, dwFlags);
2370
2371 /* Query the service provider */
2372 data.idPlayer = idPlayer;
2373 data.dwFlags = dwFlags;
2374 data.lpCaps = lpDPCaps;
2375 data.lpISP = This->dp2->spData.lpISP;
2376
2377 return (*This->dp2->spData.lpCB->GetCaps)( &data );
2378 }
2379
2380 static HRESULT WINAPI DP_IF_GetCaps
2381 ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
2382 {
2383 return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
2384 }
2385
2386 static HRESULT WINAPI DirectPlay2AImpl_GetCaps
2387 ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2388 {
2389 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2390 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2391 }
2392
2393 static HRESULT WINAPI DirectPlay2WImpl_GetCaps
2394 ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
2395 {
2396 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2397 return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2398 }
2399
2400 static HRESULT WINAPI DP_IF_GetGroupData
2401 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2402 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2403 {
2404 lpGroupData lpGData;
2405 DWORD dwRequiredBufferSize;
2406 LPVOID lpCopyDataFrom;
2407
2408 TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u)\n",
2409 This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
2410
2411 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2412 {
2413 return DPERR_INVALIDGROUP;
2414 }
2415
2416 /* How much buffer is required? */
2417 if( dwFlags & DPSET_LOCAL )
2418 {
2419 dwRequiredBufferSize = lpGData->dwLocalDataSize;
2420 lpCopyDataFrom = lpGData->lpLocalData;
2421 }
2422 else
2423 {
2424 dwRequiredBufferSize = lpGData->dwRemoteDataSize;
2425 lpCopyDataFrom = lpGData->lpRemoteData;
2426 }
2427
2428 /* Is the user requesting to know how big a buffer is required? */
2429 if( ( lpData == NULL ) ||
2430 ( *lpdwDataSize < dwRequiredBufferSize )
2431 )
2432 {
2433 *lpdwDataSize = dwRequiredBufferSize;
2434 return DPERR_BUFFERTOOSMALL;
2435 }
2436
2437 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2438
2439 return DP_OK;
2440 }
2441
2442 static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
2443 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2444 LPDWORD lpdwDataSize, DWORD dwFlags )
2445 {
2446 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2447 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2448 dwFlags, TRUE );
2449 }
2450
2451 static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
2452 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2453 LPDWORD lpdwDataSize, DWORD dwFlags )
2454 {
2455 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2456 return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2457 dwFlags, FALSE );
2458 }
2459
2460 static HRESULT WINAPI DP_IF_GetGroupName
2461 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2462 LPDWORD lpdwDataSize, BOOL bAnsi )
2463 {
2464 lpGroupData lpGData;
2465 LPDPNAME lpName = (LPDPNAME)lpData;
2466 DWORD dwRequiredDataSize;
2467
2468 FIXME("(%p)->(0x%08lx,%p,%p,%u) ANSI ignored\n",
2469 This, idGroup, lpData, lpdwDataSize, bAnsi );
2470
2471 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2472 {
2473 return DPERR_INVALIDGROUP;
2474 }
2475
2476 dwRequiredDataSize = lpGData->name.dwSize;
2477
2478 if( lpGData->name.lpszShortNameA )
2479 {
2480 dwRequiredDataSize += strlen( lpGData->name.lpszShortNameA ) + 1;
2481 }
2482
2483 if( lpGData->name.lpszLongNameA )
2484 {
2485 dwRequiredDataSize += strlen( lpGData->name.lpszLongNameA ) + 1;
2486 }
2487
2488 if( ( lpData == NULL ) ||
2489 ( *lpdwDataSize < dwRequiredDataSize )
2490 )
2491 {
2492 *lpdwDataSize = dwRequiredDataSize;
2493 return DPERR_BUFFERTOOSMALL;
2494 }
2495
2496 /* Copy the structure */
2497 CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2498
2499 if( lpGData->name.lpszShortNameA )
2500 {
2501 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2502 lpGData->name.lpszShortNameA );
2503 }
2504 else
2505 {
2506 lpName->lpszShortNameA = NULL;
2507 }
2508
2509 if( lpGData->name.lpszShortNameA )
2510 {
2511 strcpy( ((char*)lpName)+lpGData->name.dwSize,
2512 lpGData->name.lpszLongNameA );
2513 }
2514 else
2515 {
2516 lpName->lpszLongNameA = NULL;
2517 }
2518
2519 return DP_OK;
2520 }
2521
2522 static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
2523 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2524 LPDWORD lpdwDataSize )
2525 {
2526 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2527 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2528 }
2529
2530 static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2531 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2532 LPDWORD lpdwDataSize )
2533 {
2534 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2535 return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2536 }
2537
2538 static HRESULT WINAPI DP_IF_GetMessageCount
2539 ( IDirectPlay2Impl* This, DPID idPlayer,
2540 LPDWORD lpdwCount, BOOL bAnsi )
2541 {
2542 FIXME("(%p)->(0x%08lx,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi );
2543 return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer,
2544 DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL,
2545 bAnsi );
2546 }
2547
2548 static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
2549 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
2550 {
2551 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2552 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE );
2553 }
2554
2555 static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
2556 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
2557 {
2558 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2559 return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE );
2560 }
2561
2562 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
2563 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2564 {
2565 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2566 FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2567 return DP_OK;
2568 }
2569
2570 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
2571 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
2572 {
2573 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2574 FIXME("(%p)->(0x%08lx,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2575 return DP_OK;
2576 }
2577
2578 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
2579 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2580 DWORD dwFlags )
2581 {
2582 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2583 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2584 }
2585
2586 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
2587 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2588 DWORD dwFlags )
2589 {
2590 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2591 return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2592 }
2593
2594 static HRESULT WINAPI DP_IF_GetPlayerData
2595 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2596 LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2597 {
2598 lpPlayerList lpPList;
2599 DWORD dwRequiredBufferSize;
2600 LPVOID lpCopyDataFrom;
2601
2602 TRACE( "(%p)->(0x%08lx,%p,%p,0x%08lx,%u)\n",
2603 This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
2604
2605 if( This->dp2->connectionInitialized == NO_PROVIDER )
2606 {
2607 return DPERR_UNINITIALIZED;
2608 }
2609
2610 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2611 {
2612 return DPERR_INVALIDPLAYER;
2613 }
2614
2615 /* How much buffer is required? */
2616 if( dwFlags & DPSET_LOCAL )
2617 {
2618 dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
2619 lpCopyDataFrom = lpPList->lpPData->lpLocalData;
2620 }
2621 else
2622 {
2623 dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
2624 lpCopyDataFrom = lpPList->lpPData->lpRemoteData;
2625 }
2626
2627 /* Is the user requesting to know how big a buffer is required? */
2628 if( ( lpData == NULL ) ||
2629 ( *lpdwDataSize < dwRequiredBufferSize )
2630 )
2631 {
2632 *lpdwDataSize = dwRequiredBufferSize;
2633 return DPERR_BUFFERTOOSMALL;
2634 }
2635
2636 CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2637
2638 return DP_OK;
2639 }
2640
2641 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
2642 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2643 LPDWORD lpdwDataSize, DWORD dwFlags )
2644 {
2645 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2646 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2647 dwFlags, TRUE );
2648 }
2649
2650 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
2651 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2652 LPDWORD lpdwDataSize, DWORD dwFlags )
2653 {
2654 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2655 return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2656 dwFlags, FALSE );
2657 }
2658
2659 static HRESULT WINAPI DP_IF_GetPlayerName
2660 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2661 LPDWORD lpdwDataSize, BOOL bAnsi )
2662 {
2663 lpPlayerList lpPList;
2664 LPDPNAME lpName = (LPDPNAME)lpData;
2665 DWORD dwRequiredDataSize;
2666
2667 FIXME( "(%p)->(0x%08lx,%p,%p,%u): ANSI\n",
2668 This, idPlayer, lpData, lpdwDataSize, bAnsi );
2669
2670 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
2671 {
2672 return DPERR_INVALIDPLAYER;
2673 }
2674
2675 dwRequiredDataSize = lpPList->lpPData->name.dwSize;
2676
2677 if( lpPList->lpPData->name.lpszShortNameA )
2678 {
2679 dwRequiredDataSize += strlen( lpPList->lpPData->name.lpszShortNameA ) + 1;
2680 }
2681
2682 if( lpPList->lpPData->name.lpszLongNameA )
2683 {
2684 dwRequiredDataSize += strlen( lpPList->lpPData->name.lpszLongNameA ) + 1;
2685 }
2686
2687 if( ( lpData == NULL ) ||
2688 ( *lpdwDataSize < dwRequiredDataSize )
2689 )
2690 {
2691 *lpdwDataSize = dwRequiredDataSize;
2692 return DPERR_BUFFERTOOSMALL;
2693 }
2694
2695 /* Copy the structure */
2696 CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
2697
2698 if( lpPList->lpPData->name.lpszShortNameA )
2699 {
2700 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2701 lpPList->lpPData->name.lpszShortNameA );
2702 }
2703 else
2704 {
2705 lpName->lpszShortNameA = NULL;
2706 }
2707
2708 if( lpPList->lpPData->name.lpszShortNameA )
2709 {
2710 strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2711 lpPList->lpPData->name.lpszLongNameA );
2712 }
2713 else
2714 {
2715 lpName->lpszLongNameA = NULL;
2716 }
2717
2718 return DP_OK;
2719 }
2720
2721 static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
2722 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2723 LPDWORD lpdwDataSize )
2724 {
2725 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2726 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
2727 }
2728
2729 static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2730 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2731 LPDWORD lpdwDataSize )
2732 {
2733 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2734 return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2735 }
2736
2737 static HRESULT WINAPI DP_GetSessionDesc
2738 ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2739 BOOL bAnsi )
2740 {
2741 DWORD dwRequiredSize;
2742
2743 TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );
2744
2745 if( This->dp2->connectionInitialized == NO_PROVIDER )
2746 {
2747 return DPERR_UNINITIALIZED;
2748 }
2749
2750 if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
2751 {
2752 return DPERR_INVALIDPARAMS;
2753 }
2754
2755 /* FIXME: Get from This->dp2->lpSessionDesc */
2756 dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );
2757
2758 if ( ( lpData == NULL ) ||
2759 ( *lpdwDataSize < dwRequiredSize )
2760 )
2761 {
2762 *lpdwDataSize = dwRequiredSize;
2763 return DPERR_BUFFERTOOSMALL;
2764 }
2765
2766 DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );
2767
2768 return DP_OK;
2769 }
2770
2771 static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
2772 ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
2773 {
2774 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2775 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2776 }
2777
2778 static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
2779 ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
2780 {
2781 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2782 return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2783 }
2784
2785 /* Intended only for COM compatibility. Always returns an error. */
2786 static HRESULT WINAPI DirectPlay2AImpl_Initialize
2787 ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
2788 {
2789 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2790 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2791 return DPERR_ALREADYINITIALIZED;
2792 }
2793
2794 /* Intended only for COM compatibility. Always returns an error. */
2795 static HRESULT WINAPI DirectPlay2WImpl_Initialize
2796 ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
2797 {
2798 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2799 TRACE("(%p)->(%p): stub\n", This, lpGUID );
2800 return DPERR_ALREADYINITIALIZED;
2801 }
2802
2803
2804 static HRESULT WINAPI DP_SecureOpen
2805 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2806 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
2807 BOOL bAnsi )
2808 {
2809 HRESULT hr = DP_OK;
2810
2811 FIXME( "(%p)->(%p,0x%08lx,%p,%p): partial stub\n",
2812 This, lpsd, dwFlags, lpSecurity, lpCredentials );
2813
2814 if( This->dp2->bConnectionOpen )
2815 {
2816 TRACE( ": rejecting already open connection.\n" );
2817 return DPERR_ALREADYINITIALIZED;
2818 }
2819
2820 /* If we're enumerating, kill the thread */
2821 DP_KillEnumSessionThread( This );
2822
2823 if( dwFlags & DPOPEN_CREATE )
2824 {
2825 /* Rightoo - this computer is the host and the local computer needs to be
2826 the name server so that others can join this session */
2827 NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
2828
2829 This->dp2->bHostInterface = TRUE;
2830
2831 hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
2832 if( FAILED( hr ) )
2833 {
2834 ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
2835 return hr;
2836 }
2837 }
2838
2839 /* Invoke the conditional callback for the service provider */
2840 if( This->dp2->spData.lpCB->Open )
2841 {
2842 DPSP_OPENDATA data;
2843
2844 FIXME( "Not all data fields are correct. Need new parameter\n" );
2845
2846 data.bCreate = (dwFlags & DPOPEN_CREATE ) ? TRUE : FALSE;
2847 data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
2848 : NS_GetNSAddr( This->dp2->lpNameServerData );
2849 data.lpISP = This->dp2->spData.lpISP;
2850 data.bReturnStatus = (dwFlags & DPOPEN_RETURNSTATUS) ? TRUE : FALSE;
2851 data.dwOpenFlags = dwFlags;
2852 data.dwSessionFlags = This->dp2->lpSessionDesc->dwFlags;
2853
2854 hr = (*This->dp2->spData.lpCB->Open)(&data);
2855 if( FAILED( hr ) )
2856 {
2857 ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
2858 return hr;
2859 }
2860 }
2861
2862 {
2863 /* Create the system group of which everything is a part of */
2864 DPID systemGroup = DPID_SYSTEM_GROUP;
2865
2866 hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
2867 NULL, 0, 0, TRUE );
2868
2869 }
2870
2871 if( dwFlags & DPOPEN_JOIN )
2872 {
2873 DPID dpidServerId = DPID_UNKNOWN;
2874
2875 /* Create the server player for this interface. This way we can receive
2876 * messages for this session.
2877 */
2878 /* FIXME: I suppose that we should be setting an event for a receive
2879 * type of thing. That way the messaging thread could know to wake
2880 * up. DPlay would then trigger the hEvent for the player the
2881 * message is directed to.
2882 */
2883 hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
2884 0,
2885 DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
2886
2887 }
2888 else if( dwFlags & DPOPEN_CREATE )
2889 {
2890 DPID dpidNameServerId = DPID_NAME_SERVER;
2891
2892 hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
2893 0, DPPLAYER_SERVERPLAYER, bAnsi );
2894 }
2895
2896 if( FAILED(hr) )
2897 {
2898 ERR( "Couldn't create name server/system player: %s\n",
2899 DPLAYX_HresultToString(hr) );
2900 }
2901
2902 return hr;
2903 }
2904
2905 static HRESULT WINAPI DirectPlay2AImpl_Open
2906 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2907 {
2908 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2909 TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags );
2910 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE );
2911 }
2912
2913 static HRESULT WINAPI DirectPlay2WImpl_Open
2914 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
2915 {
2916 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2917 TRACE("(%p)->(%p,0x%08lx)\n", This, lpsd, dwFlags );
2918 return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE );
2919 }
2920
2921 static HRESULT WINAPI DP_IF_Receive
2922 ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
2923 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
2924 {
2925 LPDPMSG lpMsg = NULL;
2926
2927 FIXME( "(%p)->(%p,%p,0x%08lx,%p,%p,%u): stub\n",
2928 This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );
2929
2930 if( This->dp2->connectionInitialized == NO_PROVIDER )
2931 {
2932 return DPERR_UNINITIALIZED;
2933 }
2934
2935 if( dwFlags == 0 )
2936 {
2937 dwFlags = DPRECEIVE_ALL;
2938 }
2939
2940 /* If the lpData is NULL, we must be peeking the message */
2941 if( ( lpData == NULL ) &&
2942 !( dwFlags & DPRECEIVE_PEEK )
2943 )
2944 {
2945 return DPERR_INVALIDPARAMS;
2946 }
2947
2948 if( dwFlags & DPRECEIVE_ALL )
2949 {
2950 lpMsg = This->dp2->receiveMsgs.lpQHFirst;
2951
2952 if( !( dwFlags & DPRECEIVE_PEEK ) )
2953 {
2954 FIXME( "Remove from queue\n" );
2955 }
2956 }
2957 else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
2958 ( dwFlags & DPRECEIVE_FROMPLAYER )
2959 )
2960 {
2961 FIXME( "Find matching message 0x%08lx\n", dwFlags );
2962 }
2963 else
2964 {
2965 ERR( "Hmmm..dwFlags 0x%08lx\n", dwFlags );
2966 }
2967
2968 if( lpMsg == NULL )
2969 {
2970 return DPERR_NOMESSAGES;
2971 }
2972
2973 /* Copy into the provided buffer */
2974 CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
2975
2976 return DP_OK;
2977 }
2978
2979 static HRESULT WINAPI DirectPlay2AImpl_Receive
2980 ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
2981 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2982 {
2983 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2984 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
2985 lpData, lpdwDataSize, TRUE );
2986 }
2987
2988 static HRESULT WINAPI DirectPlay2WImpl_Receive
2989 ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
2990 DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
2991 {
2992 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2993 return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
2994 lpData, lpdwDataSize, FALSE );
2995 }
2996
2997 static HRESULT WINAPI DirectPlay2AImpl_Send
2998 ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
2999 {
3000 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3001 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3002 0, 0, NULL, NULL, TRUE );
3003 }
3004
3005 static HRESULT WINAPI DirectPlay2WImpl_Send
3006 ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
3007 {
3008 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3009 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3010 0, 0, NULL, NULL, FALSE );
3011 }
3012
3013 static HRESULT WINAPI DP_IF_SetGroupData
3014 ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
3015 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3016 {
3017 lpGroupData lpGData;
3018
3019 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u)\n",
3020 This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
3021
3022 /* Parameter check */
3023 if( ( lpData == NULL ) &&
3024 ( dwDataSize != 0 )
3025 )
3026 {
3027 return DPERR_INVALIDPARAMS;
3028 }
3029
3030 /* Find the pointer to the data for this player */
3031 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3032 {
3033 return DPERR_INVALIDOBJECT;
3034 }
3035
3036 if( !(dwFlags & DPSET_LOCAL) )
3037 {
3038 FIXME( "Was this group created by this interface?\n" );
3039 /* FIXME: If this is a remote update need to allow it but not
3040 * send a message.
3041 */
3042 }
3043
3044 DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );
3045
3046 /* FIXME: Only send a message if this group is local to the session otherwise
3047 * it will have been rejected above
3048 */
3049 if( !(dwFlags & DPSET_LOCAL) )
3050 {
3051 FIXME( "Send msg?\n" );
3052 }
3053
3054 return DP_OK;
3055 }
3056
3057 static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
3058 ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
3059 DWORD dwDataSize, DWORD dwFlags )
3060 {
3061 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3062 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
3063 }
3064
3065 static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
3066 ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
3067 DWORD dwDataSize, DWORD dwFlags )
3068 {
3069 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3070 return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
3071 }
3072
3073 static HRESULT WINAPI DP_IF_SetGroupName
3074 ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
3075 DWORD dwFlags, BOOL bAnsi )
3076 {
3077 lpGroupData lpGData;
3078
3079 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n", This, idGroup,
3080 lpGroupName, dwFlags, bAnsi );
3081
3082 if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3083 {
3084 return DPERR_INVALIDGROUP;
3085 }
3086
3087 DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3088
3089 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3090 FIXME( "Message not sent and dwFlags ignored\n" );
3091
3092 return DP_OK;
3093 }
3094
3095 static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
3096 ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
3097 DWORD dwFlags )
3098 {
3099 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3100 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3101 }
3102
3103 static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
3104 ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
3105 DWORD dwFlags )
3106 {
3107 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3108 return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3109 }
3110
3111 static HRESULT WINAPI DP_IF_SetPlayerData
3112 ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
3113 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3114 {
3115 lpPlayerList lpPList;
3116
3117 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,0x%08lx,%u)\n",
3118 This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
3119
3120 /* Parameter check */
3121 if( ( lpData == NULL ) &&
3122 ( dwDataSize != 0 )
3123 )
3124 {
3125 return DPERR_INVALIDPARAMS;
3126 }
3127
3128 /* Find the pointer to the data for this player */
3129 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3130 {
3131 return DPERR_INVALIDPLAYER;
3132 }
3133
3134 if( !(dwFlags & DPSET_LOCAL) )
3135 {
3136 FIXME( "Was this group created by this interface?\n" );
3137 /* FIXME: If this is a remote update need to allow it but not
3138 * send a message.
3139 */
3140 }
3141
3142 DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
3143
3144 if( !(dwFlags & DPSET_LOCAL) )
3145 {
3146 FIXME( "Send msg?\n" );
3147 }
3148
3149 return DP_OK;
3150 }
3151
3152 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
3153 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
3154 DWORD dwDataSize, DWORD dwFlags )
3155 {
3156 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3157 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3158 dwFlags, TRUE );
3159 }
3160
3161 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
3162 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
3163 DWORD dwDataSize, DWORD dwFlags )
3164 {
3165 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3166 return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3167 dwFlags, FALSE );
3168 }
3169
3170 static HRESULT WINAPI DP_IF_SetPlayerName
3171 ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
3172 DWORD dwFlags, BOOL bAnsi )
3173 {
3174 lpPlayerList lpPList;
3175
3176 TRACE( "(%p)->(0x%08lx,%p,0x%08lx,%u)\n",
3177 This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3178
3179 if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3180 {
3181 return DPERR_INVALIDGROUP;
3182 }
3183
3184 DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3185
3186 /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
3187 FIXME( "Message not sent and dwFlags ignored\n" );
3188
3189 return DP_OK;
3190 }
3191
3192 static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
3193 ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
3194 DWORD dwFlags )
3195 {
3196 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3197 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3198 }
3199
3200 static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
3201 ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
3202 DWORD dwFlags )
3203 {
3204 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3205 return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3206 }
3207
3208 static HRESULT WINAPI DP_SetSessionDesc
3209 ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
3210 DWORD dwFlags, BOOL bInitial, BOOL bAnsi )
3211 {
3212 DWORD dwRequiredSize;
3213 LPDPSESSIONDESC2 lpTempSessDesc;
3214
3215 TRACE( "(%p)->(%p,0x%08lx,%u,%u)\n",
3216 This, lpSessDesc, dwFlags, bInitial, bAnsi );
3217
3218 if( This->dp2->connectionInitialized == NO_PROVIDER )
3219 {
3220 return DPERR_UNINITIALIZED;
3221 }
3222
3223 if( dwFlags )
3224 {
3225 return DPERR_INVALIDPARAMS;
3226 }
3227
3228 /* Only the host is allowed to update the session desc */
3229 if( !This->dp2->bHostInterface )
3230 {
3231 return DPERR_ACCESSDENIED;
3232 }
3233
3234 /* FIXME: Copy into This->dp2->lpSessionDesc */
3235 dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3236 lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3237
3238 if( lpTempSessDesc == NULL )
3239 {
3240 return DPERR_OUTOFMEMORY;
3241 }
3242
3243 /* Free the old */
3244 HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
3245
3246 This->dp2->lpSessionDesc = lpTempSessDesc;
3247
3248 /* Set the new */
3249 DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3250
3251 /* If this is an external invocation of the interface, we should be
3252 * letting everyone know that things have changed. Otherwise this is
3253 * just an initialization and it doesn't need to be propagated.
3254 */
3255 if( !bInitial )
3256 {
3257 FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3258 }
3259
3260 return DP_OK;
3261 }
3262
3263 static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
3264 ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3265 {
3266 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3267 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3268 }
3269
3270 static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
3271 ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
3272 {
3273 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3274 return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3275 }
3276
3277 /* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3278 DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3279 {
3280 DWORD dwSize = 0;
3281
3282 if( lpSessDesc == NULL )
3283 {
3284 /* Hmmm..don't need any size? */
3285 ERR( "NULL lpSessDesc\n" );
3286 return dwSize;
3287 }
3288
3289 dwSize += sizeof( *lpSessDesc );
3290
3291 if( bAnsi )
3292 {
3293 if( lpSessDesc->lpszSessionNameA )
3294 {
3295 dwSize += lstrlenA( lpSessDesc->lpszSessionNameA ) + 1;
3296 }
3297
3298 if( lpSessDesc->lpszPasswordA )
3299 {
3300 dwSize += lstrlenA( lpSessDesc->lpszPasswordA ) + 1;
3301 }
3302 }
3303 else /* UNICODE */
3304 {
3305 if( lpSessDesc->lpszSessionName )
3306 {
3307 dwSize += sizeof( WCHAR ) *
3308 ( lstrlenW( lpSessDesc->lpszSessionName ) + 1 );
3309 }
3310
3311 if( lpSessDesc->lpszPassword )
3312 {
3313 dwSize += sizeof( WCHAR ) *
3314 ( lstrlenW( lpSessDesc->lpszPassword ) + 1 );
3315 }
3316 }
3317
3318 return dwSize;
3319 }
3320
3321 /* Assumes that contugous buffers are already allocated. */
3322 static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3323 LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
3324 {
3325 BYTE* lpStartOfFreeSpace;
3326
3327 if( lpSessionDest == NULL )
3328 {
3329 ERR( "NULL lpSessionDest\n" );
3330 return;
3331 }
3332
3333 CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
3334
3335 lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );
3336
3337 if( bAnsi )
3338 {
3339 if( lpSessionSrc->lpszSessionNameA )
3340 {
3341 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3342 lpSessionDest->lpszSessionNameA );
3343 lpSessionDest->lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3344 lpStartOfFreeSpace +=
3345 lstrlenA( (LPSTR)lpSessionDest->lpszSessionNameA ) + 1;
3346 }
3347
3348 if( lpSessionSrc->lpszPasswordA )
3349 {
3350 lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3351 lpSessionDest->lpszPasswordA );
3352 lpSessionDest->lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3353 lpStartOfFreeSpace +=
3354 lstrlenA( (LPSTR)lpSessionDest->lpszPasswordA ) + 1;
3355 }
3356 }
3357 else /* UNICODE */
3358 {
3359 if( lpSessionSrc->lpszSessionName )
3360 {
3361 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3362 lpSessionDest->lpszSessionName );
3363 lpSessionDest->lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3364 lpStartOfFreeSpace += sizeof(WCHAR) *
3365 ( lstrlenW( (LPWSTR)lpSessionDest->lpszSessionName ) + 1 );
3366 }
3367
3368 if( lpSessionSrc->lpszPassword )
3369 {
3370 lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3371 lpSessionDest->lpszPassword );
3372 lpSessionDest->lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3373 lpStartOfFreeSpace += sizeof(WCHAR) *
3374 ( lstrlenW( (LPWSTR)lpSessionDest->lpszPassword ) + 1 );
3375 }
3376 }
3377 }
3378
3379
3380 static HRESULT WINAPI DP_IF_AddGroupToGroup
3381 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3382 {
3383 lpGroupData lpGParentData;
3384 lpGroupData lpGData;
3385 lpGroupList lpNewGList;
3386
3387 TRACE( "(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup );
3388
3389 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3390 {
3391 return DPERR_INVALIDGROUP;
3392 }
3393
3394 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3395 {
3396 return DPERR_INVALIDGROUP;
3397 }
3398
3399 /* Create a player list (ie "shortcut" ) */
3400 lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
3401 if( lpNewGList == NULL )
3402 {
3403 return DPERR_CANTADDPLAYER;
3404 }
3405
3406 /* Add the shortcut */
3407 lpGData->uRef++;
3408 lpNewGList->lpGData = lpGData;
3409
3410 /* Add the player to the list of players for this group */
3411 DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3412
3413 /* Send a ADDGROUPTOGROUP message */
3414 FIXME( "Not sending message\n" );
3415
3416 return DP_OK;
3417 }
3418
3419 static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
3420 ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
3421 {
3422 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3423 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3424 }
3425
3426 static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
3427 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3428 {
3429 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3430 return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3431 }
3432
3433 static HRESULT WINAPI DP_IF_CreateGroupInGroup
3434 ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
3435 LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3436 DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3437 {
3438 lpGroupData lpGParentData;
3439 lpGroupList lpGList;
3440 lpGroupData lpGData;
3441
3442 TRACE( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,0x%08lx,%u)\n",
3443 This, idParentGroup, lpidGroup, lpGroupName, lpData,
3444 dwDataSize, dwFlags, bAnsi );
3445
3446 /* Verify that the specified parent is valid */
3447 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
3448 idParentGroup ) ) == NULL
3449 )
3450 {
3451 return DPERR_INVALIDGROUP;
3452 }
3453
3454 lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3455 dwFlags, idParentGroup, bAnsi );
3456
3457 if( lpGData == NULL )
3458 {
3459 return DPERR_CANTADDPLAYER; /* yes player not group */
3460 }
3461
3462 /* Something else is referencing this data */
3463 lpGData->uRef++;
3464
3465 DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3466
3467 /* The list has now been inserted into the interface group list. We now
3468 need to put a "shortcut" to this group in the parent group */
3469 lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3470 if( lpGList == NULL )
3471 {
3472 FIXME( "Memory leak\n" );
3473 return DPERR_CANTADDPLAYER; /* yes player not group */
3474 }
3475
3476 lpGList->lpGData = lpGData;
3477
3478 DPQ_INSERT( lpGParentData->groups, lpGList, groups );
3479
3480 /* Let the SP know that we've created this group */
3481 if( This->dp2->spData.lpCB->CreateGroup )
3482 {
3483 DPSP_CREATEGROUPDATA data;
3484
3485 TRACE( "Calling SP CreateGroup\n" );
3486
3487 data.idGroup = *lpidGroup;
3488 data.dwFlags = dwFlags;
3489 data.lpSPMessageHeader = lpMsgHdr;
3490 data.lpISP = This->dp2->spData.lpISP;
3491
3492 (*This->dp2->spData.lpCB->CreateGroup)( &data );
3493 }
3494
3495 /* Inform all other peers of the creation of a new group. If there are
3496 * no peers keep this quiet.
3497 */
3498 if( This->dp2->lpSessionDesc &&
3499 ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
3500 {
3501 DPMSG_CREATEPLAYERORGROUP msg;
3502
3503 msg.dwType = DPSYS_CREATEPLAYERORGROUP;
3504 msg.dwPlayerType = DPPLAYERTYPE_GROUP;
3505 msg.dpId = *lpidGroup;
3506 msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
3507 msg.lpData = lpData;
3508 msg.dwDataSize = dwDataSize;
3509 msg.dpnName = *lpGroupName;
3510
3511 /* FIXME: Correct to just use send effectively? */
3512 /* FIXME: Should size include data w/ message or just message "header" */
3513 /* FIXME: Check return code */
3514 DP_SendEx( (IDirectPlay2Impl*)This,
3515 DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
3516 0, 0, NULL, NULL, bAnsi );
3517 }
3518
3519 return DP_OK;
3520 }
3521
3522 static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
3523 ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
3524 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3525 DWORD dwFlags )
3526 {
3527 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3528
3529 *lpidGroup = DPID_UNKNOWN;
3530
3531 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3532 lpGroupName, lpData, dwDataSize, dwFlags,
3533 TRUE );
3534 }
3535
3536 static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3537 ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
3538 LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3539 DWORD dwFlags )
3540 {
3541 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3542
3543 *lpidGroup = DPID_UNKNOWN;
3544
3545 return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
3546 lpGroupName, lpData, dwDataSize,
3547 dwFlags, FALSE );
3548 }
3549
3550 static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
3551 ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3552 {
3553 lpGroupList lpGList;
3554 lpGroupData lpGParentData;
3555
3556 TRACE("(%p)->(0x%08lx,0x%08lx)\n", This, idParentGroup, idGroup );
3557
3558 /* Is the parent group valid? */
3559 if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3560 {
3561 return DPERR_INVALIDGROUP;
3562 }
3563
3564 /* Remove the group from the parent group queue */
3565 DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3566
3567 if( lpGList == NULL )
3568 {
3569 return DPERR_INVALIDGROUP;
3570 }
3571
3572 /* Decrement the ref count */
3573 lpGList->lpGData->uRef--;
3574
3575 /* Free up the list item */
3576 HeapFree( GetProcessHeap(), 0, lpGList );
3577
3578 /* Should send a DELETEGROUPFROMGROUP message */
3579 FIXME( "message not sent\n" );
3580
3581 return DP_OK;
3582 }
3583
3584 static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
3585 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3586 {
3587 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3588 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3589 }
3590
3591 static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
3592 ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
3593 {
3594 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3595 return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3596 }
3597
3598 static
3599 BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3600 LPDWORD lpdwBufSize )
3601 {
3602 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3603 HRESULT hr;
3604
3605 dpCompoundAddress.dwDataSize = sizeof( GUID );
3606 memcpy( &dpCompoundAddress.guidDataType, &DPAID_ServiceProvider,
3607 sizeof( GUID ) ) ;
3608 dpCompoundAddress.lpData = lpcSpGuid;
3609
3610 *lplpAddrBuf = NULL;
3611 *lpdwBufSize = 0;
3612
3613 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3614 lpdwBufSize, TRUE );
3615
3616 if( hr != DPERR_BUFFERTOOSMALL )
3617 {
3618 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3619 return FALSE;
3620 }
3621
3622 /* Now allocate the buffer */
3623 *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3624 *lpdwBufSize );
3625
3626 hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
3627 lpdwBufSize, TRUE );
3628 if( FAILED(hr) )
3629 {
3630 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3631 return FALSE;
3632 }
3633
3634 return TRUE;
3635 }
3636
3637 static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
3638 ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3639 {
3640 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3641 TRACE("(%p)->(%p,%p,%p,0x%08lx)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3642
3643 /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
3644 if( dwFlags == 0 )
3645 {
3646 dwFlags = DPCONNECTION_DIRECTPLAY;
3647 }
3648
3649 if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
3650 ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3651 )
3652 {
3653 return DPERR_INVALIDFLAGS;
3654 }
3655
3656 if( !lpEnumCallback || !*lpEnumCallback )
3657 {
3658 return DPERR_INVALIDPARAMS;
3659 }
3660
3661 /* Enumerate DirectPlay service providers */
3662 if( dwFlags & DPCONNECTION_DIRECTPLAY )
3663 {
3664 HKEY hkResult;
3665 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3666 LPCSTR guidDataSubKey = "Guid";
3667 char subKeyName[51];
3668 DWORD dwIndex, sizeOfSubKeyName=50;
3669 FILETIME filetime;
3670
3671 /* Need to loop over the service providers in the registry */
3672 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3673 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3674 {
3675 /* Hmmm. Does this mean that there are no service providers? */
3676 ERR(": no service providers?\n");
3677 return DP_OK;
3678 }
3679
3680
3681 /* Traverse all the service providers we have available */
3682 for( dwIndex=0;
3683 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3684 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3685 ++dwIndex, sizeOfSubKeyName=51 )
3686 {
3687
3688 HKEY hkServiceProvider;
3689 GUID serviceProviderGUID;
3690 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3691 char returnBuffer[51];
3692 WCHAR buff[51];
3693 DPNAME dpName;
3694 BOOL bBuildPass;
3695
3696 LPVOID lpAddressBuffer = NULL;
3697 DWORD dwAddressBufferSize = 0;
3698
3699 TRACE(" this time through: %s\n", subKeyName );
3700
3701 /* Get a handle for this particular service provider */
3702 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3703 &hkServiceProvider ) != ERROR_SUCCESS )
3704 {
3705 ERR(": what the heck is going on?\n" );
3706 continue;
3707 }
3708
3709 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3710 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3711 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3712 {
3713 ERR(": missing GUID registry data members\n" );
3714 continue;
3715 }
3716
3717 /* FIXME: Check return types to ensure we're interpreting data right */
3718 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3719 CLSIDFromString( buff, &serviceProviderGUID );
3720 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3721
3722 /* Fill in the DPNAME struct for the service provider */
3723 dpName.dwSize = sizeof( dpName );
3724 dpName.dwFlags = 0;
3725 dpName.lpszShortNameA = subKeyName;
3726 dpName.lpszLongNameA = NULL;
3727
3728 /* Create the compound address for the service provider.
3729 * NOTE: This is a gruesome architectural scar right now. DP
3730 * uses DPL and DPL uses DP. Nasty stuff. This may be why the
3731 * native dll just gets around this little bit by allocating an
3732 * 80 byte buffer which isn't even filled with a valid compound
3733 * address. Oh well. Creating a proper compound address is the
3734 * way to go anyways despite this method taking slightly more
3735 * heap space and realtime :) */
3736
3737 bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
3738 &lpAddressBuffer,
3739 &dwAddressBufferSize );
3740 if( !bBuildPass )
3741 {
3742 ERR( "Can't build compound addr\n" );
3743 return DPERR_GENERIC;
3744 }
3745
3746 /* The enumeration will return FALSE if we are not to continue */
3747 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3748 &dpName, DPCONNECTION_DIRECTPLAY, lpContext ) )
3749 {
3750 return DP_OK;
3751 }
3752 }
3753 }
3754
3755 /* Enumerate DirectPlayLobby service providers */
3756 if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
3757 {
3758 HKEY hkResult;
3759 LPCSTR searchSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3760 LPCSTR guidDataSubKey = "Guid";
3761 char subKeyName[51];
3762 DWORD dwIndex, sizeOfSubKeyName=50;
3763 FILETIME filetime;
3764
3765 /* Need to loop over the service providers in the registry */
3766 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3767 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3768 {
3769 /* Hmmm. Does this mean that there are no service providers? */
3770 ERR(": no service providers?\n");
3771 return DP_OK;
3772 }
3773
3774
3775 /* Traverse all the lobby providers we have available */
3776 for( dwIndex=0;
3777 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3778 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
3779 ++dwIndex, sizeOfSubKeyName=51 )
3780 {
3781
3782 HKEY hkServiceProvider;
3783 GUID serviceProviderGUID;
3784 DWORD returnTypeGUID, sizeOfReturnBuffer = 50;
3785 char returnBuffer[51];
3786 WCHAR buff[51];
3787 DPNAME dpName;
3788 HRESULT hr;
3789
3790 DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
3791 LPVOID lpAddressBuffer = NULL;
3792 DWORD dwAddressBufferSize = 0;
3793
3794 TRACE(" this time through: %s\n", subKeyName );
3795
3796 /* Get a handle for this particular service provider */
3797 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
3798 &hkServiceProvider ) != ERROR_SUCCESS )
3799 {
3800 ERR(": what the heck is going on?\n" );
3801 continue;
3802 }
3803
3804 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3805 NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3806 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
3807 {
3808 ERR(": missing GUID registry data members\n" );
3809 continue;
3810 }
3811
3812 /* FIXME: Check return types to ensure we're interpreting data right */
3813 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3814 CLSIDFromString( buff, &serviceProviderGUID );
3815 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
3816
3817 /* Fill in the DPNAME struct for the service provider */
3818 dpName.dwSize = sizeof( dpName );
3819 dpName.dwFlags = 0;
3820 dpName.lpszShortNameA = subKeyName;
3821 dpName.lpszLongNameA = NULL;
3822
3823 /* Create the compound address for the service provider.
3824 NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
3825 nast stuff. This may be why the native dll just gets around this little bit by
3826 allocating an 80 byte buffer which isn't even a filled with a valid compound
3827 address. Oh well. Creating a proper compound address is the way to go anyways
3828 despite this method taking slightly more heap space and realtime :) */
3829
3830 dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
3831 dpCompoundAddress.dwDataSize = sizeof( GUID );
3832 dpCompoundAddress.lpData = &serviceProviderGUID;
3833
3834 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3835 &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
3836 {
3837 ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
3838 return hr;
3839 }
3840
3841 /* Now allocate the buffer */
3842 lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );
3843
3844 if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
3845 &dwAddressBufferSize, TRUE ) ) != DP_OK )
3846 {
3847 ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
3848 return hr;
3849 }
3850
3851 /* The enumeration will return FALSE if we are not to continue */
3852 if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3853 &dpName, DPCONNECTION_DIRECTPLAYLOBBY, lpContext ) )
3854 {
3855 return DP_OK;
3856 }
3857 }
3858 }
3859
3860 return DP_OK;
3861 }
3862
3863 static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
3864 ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3865 {
3866 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3867 FIXME("(%p)->(%p,%p,%p,0x%08lx): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3868 return DP_OK;
3869 }
3870
3871 static HRESULT WINAPI DP_IF_EnumGroupsInGroup
3872 ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
3873 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
3874 LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
3875 {
3876 lpGroupList lpGList;
3877 lpGroupData lpGData;
3878
3879 FIXME( "(%p)->(0x%08lx,%p,%p,%p,0x%08lx,%u): semi stub\n",
3880 This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
3881 lpContext, dwFlags, bAnsi );
3882
3883 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3884 {
3885 return DPERR_INVALIDGROUP;
3886 }
3887
3888 if( DPQ_IS_EMPTY( lpGData->groups ) )
3889 {
3890 return DP_OK;
3891 }
3892
3893 lpGList = DPQ_FIRST( lpGData->groups );
3894
3895 for( ;; )
3896 {
3897 /* FIXME: Should check dwFlags for match here */
3898
3899 if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
3900 &lpGList->lpGData->name, dwFlags,
3901 lpContext ) )
3902 {
3903 return DP_OK; /* User requested break */
3904 }
3905
3906 if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
3907 {
3908 break;
3909 }
3910
3911 lpGList = DPQ_NEXT( lpGList->groups );
3912
3913 }
3914
3915 return DP_OK;
3916 }
3917
3918 static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
3919 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3920 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3921 DWORD dwFlags )
3922 {
3923 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3924 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3925 lpEnumPlayersCallback2, lpContext, dwFlags,
3926 TRUE );
3927 }
3928
3929 static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
3930 ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
3931 LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3932 DWORD dwFlags )
3933 {
3934 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3935 return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3936 lpEnumPlayersCallback2, lpContext, dwFlags,
3937 FALSE );
3938 }
3939
3940 static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
3941 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3942 {
3943 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3944 FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
3945 return DP_OK;
3946 }
3947
3948 static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
3949 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
3950 {
3951 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3952 FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
3953 return DP_OK;
3954 }
3955
3956 static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
3957 REFGUID guidDataType,
3958 DWORD dwDataSize,
3959 LPCVOID lpData,
3960 LPVOID lpContext )
3961 {
3962 /* Looking for the GUID of the provider to load */
3963 if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
3964 ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
3965 )
3966 {
3967 TRACE( "Found SP/LP (%s) %s (data size = 0x%08lx)\n",
3968 debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );
3969
3970 if( dwDataSize != sizeof( GUID ) )
3971 {
3972 ERR( "Invalid sp/lp guid size 0x%08lx\n", dwDataSize );
3973 }
3974
3975 memcpy( lpContext, lpData, dwDataSize );
3976
3977 /* There shouldn't be more than 1 GUID/compound address */
3978 return FALSE;
3979 }
3980
3981 /* Still waiting for what we want */
3982 return TRUE;
3983 }
3984
3985
3986 /* Find and perform a LoadLibrary on the requested SP or LP GUID */
3987 static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
3988 {
3989 UINT i;
3990 LPCSTR spSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3991 LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3992 LPCSTR guidDataSubKey = "Guid";
3993 LPCSTR majVerDataSubKey = "dwReserved1";
3994 LPCSTR minVerDataSubKey = "dwReserved2";
3995 LPCSTR pathSubKey = "Path";
3996
3997 TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );
3998
3999 /* FIXME: Cloned code with a quick hack. */
4000 for( i=0; i<2; i++ )
4001 {
4002 HKEY hkResult;
4003 LPCSTR searchSubKey;
4004 char subKeyName[51];
4005 DWORD dwIndex, sizeOfSubKeyName=50;
4006 FILETIME filetime;
4007
4008 (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4009 *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
4010
4011
4012 /* Need to loop over the service providers in the registry */
4013 if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4014 0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4015 {
4016 /* Hmmm. Does this mean that there are no service providers? */
4017 ERR(": no service providers?\n");
4018 return 0;
4019 }
4020
4021 /* Traverse all the service providers we have available */
4022 for( dwIndex=0;
4023 RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4024 NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
4025 ++dwIndex, sizeOfSubKeyName=51 )
4026 {
4027
4028 HKEY hkServiceProvider;
4029 GUID serviceProviderGUID;
4030 DWORD returnType, sizeOfReturnBuffer = 255;
4031 char returnBuffer[256];
4032 WCHAR buff[51];
4033 DWORD dwTemp, len;
4034
4035 TRACE(" this time through: %s\n", subKeyName );
4036
4037 /* Get a handle for this particular service provider */
4038 if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4039 &hkServiceProvider ) != ERROR_SUCCESS )
4040 {
4041 ERR(": what the heck is going on?\n" );
4042 continue;
4043 }
4044
4045 if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4046 NULL, &returnType, (LPBYTE)returnBuffer,
4047 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4048 {
4049 ERR(": missing GUID registry data members\n" );
4050 continue;
4051 }
4052
4053 /* FIXME: Check return types to ensure we're interpreting data right */
4054 MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4055 CLSIDFromString( buff, &serviceProviderGUID );
4056 /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4057
4058 /* Determine if this is the Service Provider that the user asked for */
4059 if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
4060 {
4061 continue;
4062 }
4063
4064 if( i == 0 ) /* DP SP */
4065 {
4066 len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
4067 lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
4068 MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
4069 }
4070
4071 sizeOfReturnBuffer = 255;
4072
4073 /* Get dwReserved1 */
4074 if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4075 NULL, &returnType, (LPBYTE)returnBuffer,
4076 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4077 {
4078 ERR(": missing dwReserved1 registry data members\n") ;
4079 continue;
4080 }
4081
4082 if( i == 0 )
4083 memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );
4084
4085 sizeOfReturnBuffer = 255;
4086
4087 /* Get dwReserved2 */
4088 if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4089 NULL, &returnType, (LPBYTE)returnBuffer,
4090 &sizeOfReturnBuffer ) != ERROR_SUCCESS )
4091 {
4092 ERR(": missing dwReserved1 registry data members\n") ;
4093 continue;
4094 }
4095
4096 if( i == 0 )
4097 memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4098
4099 sizeOfReturnBuffer = 255;
4100
4101 /* Get the path for this service provider */
4102 if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4103 NULL, NULL, (LPBYTE)returnBuffer,
4104 &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
4105 {
4106 ERR(": missing PATH registry data members: 0x%08lx\n", dwTemp );
4107 continue;
4108 }
4109
4110 TRACE( "Loading %s\n", returnBuffer );
4111 return LoadLibraryA( returnBuffer );
4112 }
4113 }
4114
4115 return 0;
4116 }
4117
4118 static
4119 HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
4120 {
4121 HRESULT hr;
4122 LPDPSP_SPINIT SPInit;
4123
4124 /* Initialize the service provider by calling SPInit */
4125 SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4126
4127 if( SPInit == NULL )
4128 {
4129 ERR( "Service provider doesn't provide SPInit interface?\n" );
4130 FreeLibrary( hServiceProvider );
4131 return DPERR_UNAVAILABLE;
4132 }
4133
4134 TRACE( "Calling SPInit (DP SP entry point)\n" );
4135
4136 hr = (*SPInit)( &This->dp2->spData );
4137
4138 if( FAILED(hr) )
4139 {
4140 ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4141 FreeLibrary( hServiceProvider );
4142 return hr;
4143 }
4144
4145 /* FIXME: Need to verify the sanity of the returned callback table
4146 * using IsBadCodePtr */
4147 This->dp2->bSPInitialized = TRUE;
4148
4149 /* This interface is now initialized as a DP object */
4150 This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;
4151
4152 /* Store the handle of the module so that we can unload it later */
4153 This->dp2->hServiceProvider = hServiceProvider;
4154
4155 return hr;
4156 }
4157
4158 static
4159 HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
4160 {
4161 HRESULT hr;
4162 LPSP_INIT DPLSPInit;
4163
4164 /* Initialize the service provider by calling SPInit */
4165 DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4166
4167 if( DPLSPInit == NULL )
4168 {
4169 ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
4170 FreeLibrary( hLobbyProvider );
4171 return DPERR_UNAVAILABLE;
4172 }
4173
4174 TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4175
4176 hr = (*DPLSPInit)( &This->dp2->dplspData );
4177
4178 if( FAILED(hr) )
4179 {
4180 ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
4181 FreeLibrary( hLobbyProvider );
4182 return hr;
4183 }
4184
4185 /* FIXME: Need to verify the sanity of the returned callback table
4186 * using IsBadCodePtr */
4187
4188 This->dp2->bDPLSPInitialized = TRUE;
4189
4190 /* This interface is now initialized as a lobby object */
4191 This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;
4192
4193 /* Store the handle of the module so that we can unload it later */
4194 This->dp2->hDPLobbyProvider = hLobbyProvider;
4195
4196 return hr;
4197 }
4198
4199 static HRESULT WINAPI DP_IF_InitializeConnection
4200 ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4201 {
4202 HMODULE hServiceProvider;
4203 HRESULT hr;
4204 GUID guidSP;
4205 const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
4206 BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4207
4208 TRACE("(%p)->(%p,0x%08lx,%u)\n", This, lpConnection, dwFlags, bAnsi );
4209
4210 if( dwFlags != 0 )
4211 {
4212 return DPERR_INVALIDFLAGS;
4213 }
4214
4215 /* Find out what the requested SP is and how large this buffer is */
4216 hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4217 dwAddrSize, &guidSP );
4218
4219 if( FAILED(hr) )
4220 {
4221 ERR( "Invalid compound address?\n" );
4222 return DPERR_UNAVAILABLE;
4223 }
4224
4225 /* Load the service provider */
4226 hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4227
4228 if( hServiceProvider == 0 )
4229 {
4230 ERR( "Unable to load service provider\n" );
4231 return DPERR_UNAVAILABLE;
4232 }
4233
4234 if( bIsDpSp )
4235 {
4236 /* Fill in what we can of the Service Provider required information.
4237 * The rest was be done in DP_LoadSP
4238 */
4239 This->dp2->spData.lpAddress = lpConnection;
4240 This->dp2->spData.dwAddressSize = dwAddrSize;
4241 This->dp2->spData.lpGuid = &guidSP;
4242
4243 hr = DP_InitializeDPSP( This, hServiceProvider );
4244 }
4245 else
4246 {
4247 This->dp2->dplspData.lpAddress = lpConnection;
4248
4249 hr = DP_InitializeDPLSP( This, hServiceProvider );
4250 }
4251
4252 if( FAILED(hr) )
4253 {
4254 return hr;
4255 }
4256
4257 return DP_OK;
4258 }
4259
4260 static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
4261 ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
4262 {
4263 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4264
4265 /* This may not be externally invoked once either an SP or LP is initialized */
4266 if( This->dp2->connectionInitialized != NO_PROVIDER )
4267 {
4268 return DPERR_ALREADYINITIALIZED;
4269 }
4270
4271 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4272 }
4273
4274 static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
4275 ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
4276 {
4277 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4278
4279 /* This may not be externally invoked once either an SP or LP is initialized */
4280 if( This->dp2->connectionInitialized != NO_PROVIDER )
4281 {
4282 return DPERR_ALREADYINITIALIZED;
4283 }
4284
4285 return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4286 }
4287
4288 static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
4289 ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4290 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4291 {
4292 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4293 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4294 }
4295
4296 static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4297 ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4298 LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4299 {
4300 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4301 return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4302 }
4303
4304 static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
4305 ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4306 {
4307 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4308 FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4309 return DP_OK;
4310 }
4311
4312 static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
4313 ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
4314 {
4315 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4316 FIXME("(%p)->(0x%08lx,0x%08lx,0x%08lx,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4317 return DP_OK;
4318 }
4319
4320 static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
4321 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4322 {
4323 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4324 FIXME("(%p)->(0x%08lx,0x%08lx,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4325 return DP_OK;
4326 }
4327
4328 static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
4329 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
4330 {
4331 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4332 FIXME("(%p)->(0x%08lx,0x%08lx,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4333 return DP_OK;
4334 }
4335
4336 static HRESULT WINAPI DirectPlay3AImpl_StartSession
4337 ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
4338 {
4339 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4340 FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwFlags, idGroup );
4341 return DP_OK;
4342 }
4343
4344 static HRESULT WINAPI DirectPlay3WImpl_StartSession
4345 ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
4346 {
4347 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4348 FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, dwFlags, idGroup );
4349 return DP_OK;
4350 }
4351
4352 static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
4353 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
4354 {
4355 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4356 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpdwFlags );
4357 return DP_OK;
4358 }
4359
4360 static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
4361 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
4362 {
4363 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4364 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpdwFlags );
4365 return DP_OK;
4366 }
4367
4368 static HRESULT WINAPI DP_IF_GetGroupParent
4369 ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4370 BOOL bAnsi )
4371 {
4372 lpGroupData lpGData;
4373
4374 TRACE("(%p)->(0x%08lx,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4375
4376 if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4377 {
4378 return DPERR_INVALIDGROUP;
4379 }
4380
4381 *lpidGroup = lpGData->dpid;
4382
4383 return DP_OK;
4384 }
4385
4386 static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
4387 ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
4388 {
4389 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4390 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4391 }
4392 static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
4393 ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
4394 {
4395 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4396 return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4397 }
4398
4399 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
4400 ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4401 {
4402 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4403 FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4404 return DP_OK;
4405 }
4406
4407 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
4408 ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
4409 {
4410 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4411 FIXME("(%p)->(0x%08lx,0x%08lx,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4412 return DP_OK;
4413 }
4414
4415 static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
4416 ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
4417 {
4418 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4419 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwFlags );
4420 return DP_OK;
4421 }
4422
4423 static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
4424 ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
4425 {
4426 IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4427 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idPlayer, lpdwFlags );
4428 return DP_OK;
4429 }
4430
4431 static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
4432 ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
4433 {
4434 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4435 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpidGroupOwner );
4436 return DP_OK;
4437 }
4438
4439 static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
4440 ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
4441 {
4442 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4443 FIXME("(%p)->(0x%08lx,%p): stub\n", This, idGroup, lpidGroupOwner );
4444 return DP_OK;
4445 }
4446
4447 static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
4448 ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
4449 {
4450 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4451 FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idGroup, idGroupOwner );
4452 return DP_OK;
4453 }
4454
4455 static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
4456 ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
4457 {
4458 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4459 FIXME("(%p)->(0x%08lx,0x%08lx): stub\n", This, idGroup, idGroupOwner );
4460 return DP_OK;
4461 }
4462
4463 static HRESULT WINAPI DP_SendEx
4464 ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4465 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4466 LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
4467 {
4468 lpPlayerList lpPList;
4469 lpGroupData lpGData;
4470 BOOL bValidDestination = FALSE;
4471
4472 FIXME( "(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,0x%08lx,0x%08lx,0x%08lx,%p,%p,%u)"
4473 ": stub\n",
4474 This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
4475 dwTimeout, lpContext, lpdwMsgID, bAnsi );
4476
4477 /* FIXME: Add parameter checking */
4478 /* FIXME: First call to this needs to aquire a message id which will be
4479 * used for multiple sends
4480 */
4481
4482 /* NOTE: Can't send messages to yourself - this will be trapped in receive */
4483
4484 /* Verify that the message is being sent from a valid local player. The
4485 * from player may be anonymous DPID_UNKNOWN
4486 */
4487 if( idFrom != DPID_UNKNOWN )
4488 {
4489 if( ( lpPList = DP_FindPlayer( This, idFrom ) ) == NULL )
4490 {
4491 WARN( "INFO: Invalid from player 0x%08lx\n", idFrom );
4492 return DPERR_INVALIDPLAYER;
4493 }
4494 }
4495
4496 /* Verify that the message is being sent to a valid player, group or to
4497 * everyone. If it's valid, send it to those players.
4498 */
4499 if( idTo == DPID_ALLPLAYERS )
4500 {
4501 bValidDestination = TRUE;
4502
4503 /* See if SP has the ability to multicast. If so, use it */
4504 if( This->dp2->spData.lpCB->SendToGroupEx )
4505 {
4506 FIXME( "Use group sendex to group 0\n" );
4507 }
4508 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4509 {
4510 FIXME( "Use obsolete group send to group 0\n" );
4511 }
4512 else /* No multicast, multiplicate */
4513 {
4514 /* Send to all players we know about */
4515 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4516 }
4517 }
4518
4519 if( ( !bValidDestination ) &&
4520 ( DP_FindPlayer( This, idTo ) != NULL )
4521 )
4522 {
4523 bValidDestination = TRUE;
4524
4525 /* Have the service provider send this message */
4526 /* FIXME: Could optimize for local interface sends */
4527 return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
4528 dwTimeout, lpContext, lpdwMsgID );
4529 }
4530
4531 if( ( !bValidDestination ) &&
4532 ( ( lpGData = DP_FindAnyGroup( This, idTo ) ) != NULL )
4533 )
4534 {
4535 bValidDestination = TRUE;
4536
4537 /* See if SP has the ability to multicast. If so, use it */
4538 if( This->dp2->spData.lpCB->SendToGroupEx )
4539 {
4540 FIXME( "Use group sendex\n" );
4541 }
4542 else if( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
4543 {
4544 FIXME( "Use obsolete group send to group\n" );
4545 }
4546 else /* No multicast, multiplicate */
4547 {
4548 FIXME( "Send to all players using EnumPlayersInGroup\n" );
4549 }
4550
4551 #if 0
4552 if( bExpectReply )
4553 {
4554 DWORD dwWaitReturn;
4555
4556 This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
4557
4558 dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
4559 if( dwWaitReturn != WAIT_OBJECT_0 )
4560 {
4561 ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
4562 }
4563 }
4564 #endif
4565 }
4566
4567 if( !bValidDestination )
4568 {
4569 return DPERR_INVALIDPLAYER;
4570 }
4571 else
4572 {
4573 /* FIXME: Should return what the send returned */
4574 return DP_OK;
4575 }
4576 }
4577
4578
4579 static HRESULT WINAPI DirectPlay4AImpl_SendEx
4580 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4581 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4582 LPVOID lpContext, LPDWORD lpdwMsgID )
4583 {
4584 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4585 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4586 dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4587 }
4588
4589 static HRESULT WINAPI DirectPlay4WImpl_SendEx
4590 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4591 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4592 LPVOID lpContext, LPDWORD lpdwMsgID )
4593 {
4594 IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4595 return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4596 dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
4597 }
4598
4599 static HRESULT WINAPI DP_SP_SendEx
4600 ( IDirectPlay2Impl* This, DWORD dwFlags,
4601 LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
4602 LPVOID lpContext, LPDWORD lpdwMsgID )
4603 {
4604 LPDPMSG lpMElem;
4605
4606 FIXME( ": stub\n" );
4607
4608 /* FIXME: This queuing should only be for async messages */
4609
4610 lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
4611 lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4612
4613 CopyMemory( lpMElem->msg, lpData, dwDataSize );
4614
4615 /* FIXME: Need to queue based on priority */
4616 DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );
4617
4618 return DP_OK;
4619 }
4620
4621 static HRESULT WINAPI DP_IF_GetMessageQueue
4622 ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4623 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
4624 {
4625 HRESULT hr = DP_OK;
4626
4627 FIXME( "(%p)->(0x%08lx,0x%08lx,0x%08lx,%p,%p,%u): semi stub\n",
4628 This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );
4629
4630 /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
4631 /* FIXME: What about sends which are not immediate? */
4632
4633 if( This->dp2->spData.lpCB->GetMessageQueue )
4634 {
4635 DPSP_GETMESSAGEQUEUEDATA data;
4636
4637 FIXME( "Calling SP GetMessageQueue - is it right?\n" );
4638
4639 /* FIXME: None of this is documented :( */
4640
4641 data.lpISP = This->dp2->spData.lpISP;
4642 data.dwFlags = dwFlags;
4643 data.idFrom = idFrom;
4644 data.idTo = idTo;
4645 data.lpdwNumMsgs = lpdwNumMsgs;
4646 data.lpdwNumBytes = lpdwNumBytes;
4647
4648 hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4649 }
4650 else
4651 {
4652 FIXME( "No SP for GetMessageQueue - fake some data\n" );
4653 }
4654
4655 return hr;
4656 }
4657
4658 static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4659 ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4660 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4661 {
4662 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4663 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4664 lpdwNumBytes, TRUE );
4665 }
4666
4667 static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4668 ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4669 LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4670 {
4671 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4672 return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
4673 lpdwNumBytes, FALSE );
4674 }
4675
4676 static HRESULT WINAPI DP_IF_CancelMessage
4677 ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4678 DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
4679 {
4680 HRESULT hr = DP_OK;
4681
4682 FIXME( "(%p)->(0x%08lx,0x%08lx,%u): semi stub\n",
4683 This, dwMsgID, dwFlags, bAnsi );
4684
4685 if( This->dp2->spData.lpCB->Cancel )
4686 {
4687 DPSP_CANCELDATA data;
4688
4689 TRACE( "Calling SP Cancel\n" );
4690
4691 /* FIXME: Undocumented callback */
4692
4693 data.lpISP = This->dp2->spData.lpISP;
4694 data.dwFlags = dwFlags;
4695 data.lprglpvSPMsgID = NULL;
4696 data.cSPMsgID = dwMsgID;
4697 data.dwMinPriority = dwMinPriority;
4698 data.dwMaxPriority = dwMaxPriority;
4699
4700 hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4701 }
4702 else
4703 {
4704 FIXME( "SP doesn't implement Cancel\n" );
4705 }
4706
4707 return hr;
4708 }
4709
4710 static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
4711 ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
4712 {
4713 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4714
4715 if( dwFlags != 0 )
4716 {
4717 return DPERR_INVALIDFLAGS;
4718 }
4719
4720 if( dwMsgID == 0 )
4721 {
4722 dwFlags |= DPCANCELSEND_ALL;
4723 }
4724
4725 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4726 }
4727
4728 static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
4729 ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
4730 {
4731 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4732
4733 if( dwFlags != 0 )
4734 {
4735 return DPERR_INVALIDFLAGS;
4736 }
4737
4738 if( dwMsgID == 0 )
4739 {
4740 dwFlags |= DPCANCELSEND_ALL;
4741 }
4742
4743 return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4744 }
4745
4746 static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4747 ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4748 DWORD dwFlags )
4749 {
4750 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4751
4752 if( dwFlags != 0 )
4753 {
4754 return DPERR_INVALIDFLAGS;
4755 }
4756
4757 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4758 dwMaxPriority, TRUE );
4759 }
4760
4761 static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4762 ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4763 DWORD dwFlags )
4764 {
4765 IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4766
4767 if( dwFlags != 0 )
4768 {
4769 return DPERR_INVALIDFLAGS;
4770 }
4771
4772 return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4773 dwMaxPriority, FALSE );
4774 }
4775
4776 /* Note: Hack so we can reuse the old functions without compiler warnings */
4777 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4778 # define XCAST(fun) (typeof(directPlay2WVT.fun))
4779 #else
4780 # define XCAST(fun) (void*)
4781 #endif
4782
4783 static const IDirectPlay2Vtbl directPlay2WVT =
4784 {
4785 XCAST(QueryInterface)DP_QueryInterface,
4786 XCAST(AddRef)DP_AddRef,
4787 XCAST(Release)DP_Release,
4788
4789 DirectPlay2WImpl_AddPlayerToGroup,
4790 DirectPlay2WImpl_Close,
4791 DirectPlay2WImpl_CreateGroup,
4792 DirectPlay2WImpl_CreatePlayer,
4793 DirectPlay2WImpl_DeletePlayerFromGroup,
4794 DirectPlay2WImpl_DestroyGroup,
4795 DirectPlay2WImpl_DestroyPlayer,
4796 DirectPlay2WImpl_EnumGroupPlayers,
4797 DirectPlay2WImpl_EnumGroups,
4798 DirectPlay2WImpl_EnumPlayers,
4799 DirectPlay2WImpl_EnumSessions,
4800 DirectPlay2WImpl_GetCaps,
4801 DirectPlay2WImpl_GetGroupData,
4802 DirectPlay2WImpl_GetGroupName,
4803 DirectPlay2WImpl_GetMessageCount,
4804 DirectPlay2WImpl_GetPlayerAddress,
4805 DirectPlay2WImpl_GetPlayerCaps,
4806 DirectPlay2WImpl_GetPlayerData,
4807 DirectPlay2WImpl_GetPlayerName,
4808 DirectPlay2WImpl_GetSessionDesc,
4809 DirectPlay2WImpl_Initialize,
4810 DirectPlay2WImpl_Open,
4811 DirectPlay2WImpl_Receive,
4812 DirectPlay2WImpl_Send,
4813 DirectPlay2WImpl_SetGroupData,
4814 DirectPlay2WImpl_SetGroupName,
4815 DirectPlay2WImpl_SetPlayerData,
4816 DirectPlay2WImpl_SetPlayerName,
4817 DirectPlay2WImpl_SetSessionDesc
4818 };
4819 #undef XCAST
4820
4821 /* Note: Hack so we can reuse the old functions without compiler warnings */
4822 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4823 # define XCAST(fun) (typeof(directPlay2AVT.fun))
4824 #else
4825 # define XCAST(fun) (void*)
4826 #endif
4827
4828 static const IDirectPlay2Vtbl directPlay2AVT =
4829 {
4830 XCAST(QueryInterface)DP_QueryInterface,
4831 XCAST(AddRef)DP_AddRef,
4832 XCAST(Release)DP_Release,
4833
4834 DirectPlay2AImpl_AddPlayerToGroup,
4835 DirectPlay2AImpl_Close,
4836 DirectPlay2AImpl_CreateGroup,
4837 DirectPlay2AImpl_CreatePlayer,
4838 DirectPlay2AImpl_DeletePlayerFromGroup,
4839 DirectPlay2AImpl_DestroyGroup,
4840 DirectPlay2AImpl_DestroyPlayer,
4841 DirectPlay2AImpl_EnumGroupPlayers,
4842 DirectPlay2AImpl_EnumGroups,
4843 DirectPlay2AImpl_EnumPlayers,
4844 DirectPlay2AImpl_EnumSessions,
4845 DirectPlay2AImpl_GetCaps,
4846 DirectPlay2AImpl_GetGroupData,
4847 DirectPlay2AImpl_GetGroupName,
4848 DirectPlay2AImpl_GetMessageCount,
4849 DirectPlay2AImpl_GetPlayerAddress,
4850 DirectPlay2AImpl_GetPlayerCaps,
4851 DirectPlay2AImpl_GetPlayerData,
4852 DirectPlay2AImpl_GetPlayerName,
4853 DirectPlay2AImpl_GetSessionDesc,
4854 DirectPlay2AImpl_Initialize,
4855 DirectPlay2AImpl_Open,
4856 DirectPlay2AImpl_Receive,
4857 DirectPlay2AImpl_Send,
4858 DirectPlay2AImpl_SetGroupData,
4859 DirectPlay2AImpl_SetGroupName,
4860 DirectPlay2AImpl_SetPlayerData,
4861 DirectPlay2AImpl_SetPlayerName,
4862 DirectPlay2AImpl_SetSessionDesc
4863 };
4864 #undef XCAST
4865
4866
4867 /* Note: Hack so we can reuse the old functions without compiler warnings */
4868 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4869 # define XCAST(fun) (typeof(directPlay3AVT.fun))
4870 #else
4871 # define XCAST(fun) (void*)
4872 #endif
4873
4874 static const IDirectPlay3Vtbl directPlay3AVT =
4875 {
4876 XCAST(QueryInterface)DP_QueryInterface,
4877 XCAST(AddRef)DP_AddRef,
4878 XCAST(Release)DP_Release,
4879
4880 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
4881 XCAST(Close)DirectPlay2AImpl_Close,
4882 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
4883 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
4884 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
4885 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
4886 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
4887 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
4888 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
4889 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
4890 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
4891 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
4892 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
4893 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
4894 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
4895 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
4896 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
4897 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
4898 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
4899 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
4900 XCAST(Initialize)DirectPlay2AImpl_Initialize,
4901 XCAST(Open)DirectPlay2AImpl_Open,
4902 XCAST(Receive)DirectPlay2AImpl_Receive,
4903 XCAST(Send)DirectPlay2AImpl_Send,
4904 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
4905 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
4906 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
4907 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
4908 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
4909
4910 DirectPlay3AImpl_AddGroupToGroup,
4911 DirectPlay3AImpl_CreateGroupInGroup,
4912 DirectPlay3AImpl_DeleteGroupFromGroup,
4913 DirectPlay3AImpl_EnumConnections,
4914 DirectPlay3AImpl_EnumGroupsInGroup,
4915 DirectPlay3AImpl_GetGroupConnectionSettings,
4916 DirectPlay3AImpl_InitializeConnection,
4917 DirectPlay3AImpl_SecureOpen,
4918 DirectPlay3AImpl_SendChatMessage,
4919 DirectPlay3AImpl_SetGroupConnectionSettings,
4920 DirectPlay3AImpl_StartSession,
4921 DirectPlay3AImpl_GetGroupFlags,
4922 DirectPlay3AImpl_GetGroupParent,
4923 DirectPlay3AImpl_GetPlayerAccount,
4924 DirectPlay3AImpl_GetPlayerFlags
4925 };
4926 #undef XCAST
4927
4928 /* Note: Hack so we can reuse the old functions without compiler warnings */
4929 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4930 # define XCAST(fun) (typeof(directPlay3WVT.fun))
4931 #else
4932 # define XCAST(fun) (void*)
4933 #endif
4934 static const IDirectPlay3Vtbl directPlay3WVT =
4935 {
4936 XCAST(QueryInterface)DP_QueryInterface,
4937 XCAST(AddRef)DP_AddRef,
4938 XCAST(Release)DP_Release,
4939
4940 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
4941 XCAST(Close)DirectPlay2WImpl_Close,
4942 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
4943 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
4944 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
4945 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
4946 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
4947 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
4948 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
4949 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
4950 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
4951 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
4952 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
4953 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
4954 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
4955 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
4956 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
4957 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
4958 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
4959 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
4960 XCAST(Initialize)DirectPlay2WImpl_Initialize,
4961 XCAST(Open)DirectPlay2WImpl_Open,
4962 XCAST(Receive)DirectPlay2WImpl_Receive,
4963 XCAST(Send)DirectPlay2WImpl_Send,
4964 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
4965 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
4966 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
4967 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
4968 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
4969
4970 DirectPlay3WImpl_AddGroupToGroup,
4971 DirectPlay3WImpl_CreateGroupInGroup,
4972 DirectPlay3WImpl_DeleteGroupFromGroup,
4973 DirectPlay3WImpl_EnumConnections,
4974 DirectPlay3WImpl_EnumGroupsInGroup,
4975 DirectPlay3WImpl_GetGroupConnectionSettings,
4976 DirectPlay3WImpl_InitializeConnection,
4977 DirectPlay3WImpl_SecureOpen,
4978 DirectPlay3WImpl_SendChatMessage,
4979 DirectPlay3WImpl_SetGroupConnectionSettings,
4980 DirectPlay3WImpl_StartSession,
4981 DirectPlay3WImpl_GetGroupFlags,
4982 DirectPlay3WImpl_GetGroupParent,
4983 DirectPlay3WImpl_GetPlayerAccount,
4984 DirectPlay3WImpl_GetPlayerFlags
4985 };
4986 #undef XCAST
4987
4988 /* Note: Hack so we can reuse the old functions without compiler warnings */
4989 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4990 # define XCAST(fun) (typeof(directPlay4WVT.fun))
4991 #else
4992 # define XCAST(fun) (void*)
4993 #endif
4994 static const IDirectPlay4Vtbl directPlay4WVT =
4995 {
4996 XCAST(QueryInterface)DP_QueryInterface,
4997 XCAST(AddRef)DP_AddRef,
4998 XCAST(Release)DP_Release,
4999
5000 XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
5001 XCAST(Close)DirectPlay2WImpl_Close,
5002 XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
5003 XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
5004 XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
5005 XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
5006 XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
5007 XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
5008 XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
5009 XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
5010 XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
5011 XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
5012 XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
5013 XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
5014 XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
5015 XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
5016 XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
5017 XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
5018 XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
5019 XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
5020 XCAST(Initialize)DirectPlay2WImpl_Initialize,
5021 XCAST(Open)DirectPlay2WImpl_Open,
5022 XCAST(Receive)DirectPlay2WImpl_Receive,
5023 XCAST(Send)DirectPlay2WImpl_Send,
5024 XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
5025 XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
5026 XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
5027 XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
5028 XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,
5029
5030 XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
5031 XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
5032 XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
5033 XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
5034 XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
5035 XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
5036 XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
5037 XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
5038 XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
5039 XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
5040 XCAST(StartSession)DirectPlay3WImpl_StartSession,
5041 XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
5042 XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
5043 XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
5044 XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,
5045
5046 DirectPlay4WImpl_GetGroupOwner,
5047 DirectPlay4WImpl_SetGroupOwner,
5048 DirectPlay4WImpl_SendEx,
5049 DirectPlay4WImpl_GetMessageQueue,
5050 DirectPlay4WImpl_CancelMessage,
5051 DirectPlay4WImpl_CancelPriority
5052 };
5053 #undef XCAST
5054
5055
5056 /* Note: Hack so we can reuse the old functions without compiler warnings */
5057 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5058 # define XCAST(fun) (typeof(directPlay4AVT.fun))
5059 #else
5060 # define XCAST(fun) (void*)
5061 #endif
5062 static const IDirectPlay4Vtbl directPlay4AVT =
5063 {
5064 XCAST(QueryInterface)DP_QueryInterface,
5065 XCAST(AddRef)DP_AddRef,
5066 XCAST(Release)DP_Release,
5067
5068 XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
5069 XCAST(Close)DirectPlay2AImpl_Close,
5070 XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
5071 XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
5072 XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
5073 XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
5074 XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
5075 XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
5076 XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
5077 XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
5078 XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
5079 XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
5080 XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
5081 XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
5082 XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
5083 XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
5084 XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
5085 XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
5086 XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
5087 XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
5088 XCAST(Initialize)DirectPlay2AImpl_Initialize,
5089 XCAST(Open)DirectPlay2AImpl_Open,
5090 XCAST(Receive)DirectPlay2AImpl_Receive,
5091 XCAST(Send)DirectPlay2AImpl_Send,
5092 XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
5093 XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
5094 XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
5095 XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
5096 XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,
5097
5098 XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
5099 XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
5100 XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
5101 XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
5102 XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
5103 XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
5104 XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
5105 XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
5106 XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
5107 XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
5108 XCAST(StartSession)DirectPlay3AImpl_StartSession,
5109 XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
5110 XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
5111 XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
5112 XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,
5113
5114 DirectPlay4AImpl_GetGroupOwner,
5115 DirectPlay4AImpl_SetGroupOwner,
5116 DirectPlay4AImpl_SendEx,
5117 DirectPlay4AImpl_GetMessageQueue,
5118 DirectPlay4AImpl_CancelMessage,
5119 DirectPlay4AImpl_CancelPriority
5120 };
5121 #undef XCAST
5122
5123 extern
5124 HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
5125 DPID idPlayer,
5126 LPVOID* lplpData )
5127 {
5128 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5129
5130 if( lpPlayer == NULL )
5131 {
5132 return DPERR_INVALIDPLAYER;
5133 }
5134
5135 *lplpData = lpPlayer->lpPData->lpSPPlayerData;
5136
5137 return DP_OK;
5138 }
5139
5140 extern
5141 HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
5142 DPID idPlayer,
5143 LPVOID lpData )
5144 {
5145 lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );
5146
5147 if( lpPlayer == NULL )
5148 {
5149 return DPERR_INVALIDPLAYER;
5150 }
5151
5152 lpPlayer->lpPData->lpSPPlayerData = lpData;
5153
5154 return DP_OK;
5155 }
5156
5157 /***************************************************************************
5158 * DirectPlayEnumerateAW
5159 *
5160 * The pointer to the structure lpContext will be filled with the
5161 * appropriate data for each service offered by the OS. These services are
5162 * not necessarily available on this particular machine but are defined
5163 * as simple service providers under the "Service Providers" registry key.
5164 * This structure is then passed to lpEnumCallback for each of the different
5165 * services.
5166 *
5167 * This API is useful only for applications written using DirectX3 or
5168 * worse. It is superseded by IDirectPlay3::EnumConnections which also
5169 * gives information on the actual connections.
5170 *
5171 * defn of a service provider:
5172 * A dynamic-link library used by DirectPlay to communicate over a network.
5173 * The service provider contains all the network-specific code required
5174 * to send and receive messages. Online services and network operators can
5175 * supply service providers to use specialized hardware, protocols, communications
5176 * media, and network resources.
5177 *
5178 */
5179 static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
5180 LPDPENUMDPCALLBACKW lpEnumCallbackW,
5181 LPVOID lpContext)
5182 {
5183 HKEY hkResult;
5184 static const WCHAR searchSubKey[] = {
5185 'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
5186 'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
5187 'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
5188 'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
5189 static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
5190 static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
5191
5192 DWORD dwIndex;
5193 FILETIME filetime;
5194
5195 char *descriptionA = NULL;
5196 DWORD max_sizeOfDescriptionA = 0;
5197 WCHAR *descriptionW = NULL;
5198 DWORD max_sizeOfDescriptionW = 0;
5199
5200 if (!lpEnumCallbackA && !lpEnumCallbackW)
5201 {
5202 return DPERR_INVALIDPARAMS;
5203 }
5204
5205 /* Need to loop over the service providers in the registry */
5206 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
5207 0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5208 {
5209 /* Hmmm. Does this mean that there are no service providers? */
5210 ERR(": no service provider key in the registry - check your Wine installation !!!\n");
5211 return DPERR_GENERIC;
5212 }
5213
5214 /* Traverse all the service providers we have available */
5215 dwIndex = 0;
5216 while (1)
5217 {
5218 WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
5219 DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
5220 HKEY hkServiceProvider;
5221 GUID serviceProviderGUID;
5222 WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
5223 DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
5224 LONG ret_value;
5225
5226 ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
5227 NULL, NULL, NULL, &filetime);
5228 if (ret_value == ERROR_NO_MORE_ITEMS)
5229 break;
5230 else if (ret_value != ERROR_SUCCESS)
5231 {
5232 ERR(": could not enumerate on service provider key.\n");
5233 return DPERR_EXCEPTION;
5234 }
5235 TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
5236
5237 /* Open the key for this service provider */
5238 if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
5239 {
5240 ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
5241 continue;
5242 }
5243
5244 /* Get the GUID from the registry */
5245 if (RegQueryValueExW(hkServiceProvider, guidKey,
5246 NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
5247 {
5248 ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
5249 continue;
5250 }
5251 if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
5252 {
5253 ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
5254 continue;
5255 }
5256 CLSIDFromString(guidKeyContent, &serviceProviderGUID );
5257
5258 /* The enumeration will return FALSE if we are not to continue.
5259 *
5260 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
5261 * and have no relations to any of the two dwReserved1 and dwReserved2 keys.
5262 * I think that it simply means that they are in-line with DirectX 6.0
5263 */
5264 if (lpEnumCallbackA)
5265 {
5266 DWORD sizeOfDescription = 0;
5267
5268 /* Note that this the the A case of this function, so use the A variant to get the description string */
5269 if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
5270 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5271 {
5272 ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5273 continue;
5274 }
5275 if (sizeOfDescription > max_sizeOfDescriptionA)
5276 {
5277 HeapFree(GetProcessHeap(), 0, descriptionA);
5278 max_sizeOfDescriptionA = sizeOfDescription;
5279 descriptionA = HeapAlloc(GetProcessHeap(), 0, max_sizeOfDescriptionA);
5280 }
5281 descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5282 RegQueryValueExA(hkServiceProvider, "DescriptionA",
5283 NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
5284
5285 if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
5286 goto end;
5287 }
5288 else
5289 {
5290 DWORD sizeOfDescription = 0;
5291
5292 if (RegQueryValueExW(hkServiceProvider, descW,
5293 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
5294 {
5295 ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
5296 continue;
5297 }
5298 if (sizeOfDescription > max_sizeOfDescriptionW)
5299 {
5300 HeapFree(GetProcessHeap(), 0, descriptionW);
5301 max_sizeOfDescriptionW = sizeOfDescription;
5302 descriptionW = HeapAlloc(GetProcessHeap(), 0, max_sizeOfDescriptionW);
5303 }
5304 descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
5305 RegQueryValueExW(hkServiceProvider, descW,
5306 NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);
5307
5308 if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
5309 goto end;
5310 }
5311
5312 dwIndex++;
5313 }
5314
5315 end:
5316 HeapFree(GetProcessHeap(), 0, descriptionA);
5317 HeapFree(GetProcessHeap(), 0, descriptionW);
5318
5319 return DP_OK;
5320 }
5321
5322 /***************************************************************************
5323 * DirectPlayEnumerate [DPLAYX.9]
5324 * DirectPlayEnumerateA [DPLAYX.2]
5325 */
5326 HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
5327 {
5328 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5329
5330 return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5331 }
5332
5333 /***************************************************************************
5334 * DirectPlayEnumerateW [DPLAYX.3]
5335 */
5336 HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5337 {
5338 TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
5339
5340 return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5341 }
5342
5343 typedef struct tagCreateEnum
5344 {
5345 LPVOID lpConn;
5346 LPCGUID lpGuid;
5347 } CreateEnumData, *lpCreateEnumData;
5348
5349 /* Find and copy the matching connection for the SP guid */
5350 static BOOL CALLBACK cbDPCreateEnumConnections(
5351 LPCGUID lpguidSP,
5352 LPVOID lpConnection,
5353 DWORD dwConnectionSize,
5354 LPCDPNAME lpName,
5355 DWORD dwFlags,
5356 LPVOID lpContext)
5357 {
5358 lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5359
5360 if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
5361 {
5362 TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );
5363
5364 lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
5365 dwConnectionSize );
5366 CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );
5367
5368 /* Found the record that we were looking for */
5369 return FALSE;
5370 }
5371
5372 /* Haven't found what were looking for yet */
5373 return TRUE;
5374 }
5375
5376
5377 /***************************************************************************
5378 * DirectPlayCreate [DPLAYX.1]
5379 *
5380 */
5381 HRESULT WINAPI DirectPlayCreate
5382 ( LPGUID lpGUID, LPDIRECTPLAY2 *lplpDP, IUnknown *pUnk)
5383 {
5384 HRESULT hr;
5385 LPDIRECTPLAY3A lpDP3A;
5386 CreateEnumData cbData;
5387
5388 TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5389
5390 if( pUnk != NULL )
5391 {
5392 return CLASS_E_NOAGGREGATION;
5393 }
5394
5395 /* Create an IDirectPlay object. We don't support that so we'll cheat and
5396 give them an IDirectPlay2A object and hope that doesn't cause problems */
5397 if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
5398 {
5399 return DPERR_UNAVAILABLE;
5400 }
5401
5402 if( IsEqualGUID( &GUID_NULL, lpGUID ) )
5403 {
5404 /* The GUID_NULL means don't bind a service provider. Just return the
5405 interface as is */
5406 return DP_OK;
5407 }
5408
5409 /* Bind the desired service provider since lpGUID is non NULL */
5410 TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5411
5412 /* We're going to use a DP3 interface */
5413 hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5414 (LPVOID*)&lpDP3A );
5415 if( FAILED(hr) )
5416 {
5417 ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5418 return hr;
5419 }
5420
5421 cbData.lpConn = NULL;
5422 cbData.lpGuid = lpGUID;
5423
5424 /* We were given a service provider, find info about it... */
5425 hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5426 &cbData, DPCONNECTION_DIRECTPLAY );
5427 if( ( FAILED(hr) ) ||
5428 ( cbData.lpConn == NULL )
5429 )
5430 {
5431 ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5432 IDirectPlayX_Release( lpDP3A );
5433 return DPERR_UNAVAILABLE;
5434 }
5435
5436 /* Initialize the service provider */
5437 hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5438 if( FAILED(hr) )
5439 {
5440 ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
5441 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5442 IDirectPlayX_Release( lpDP3A );
5443 return hr;
5444 }
5445
5446 /* Release our version of the interface now that we're done with it */
5447 IDirectPlayX_Release( lpDP3A );
5448 HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5449
5450 return DP_OK;
5451 }