dplay.c 196 KB
Newer Older
1 2
/* Direct Play 2,3,4 Implementation
 *
3
 * Copyright 1998,1999,2000,2001 - Peter Hunnisett
4
 *
5 6 7 8 9 10 11 12 13 14 15 16
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18
 */
19

20
#define COBJMACROS
21
#include "config.h"
22
#include "wine/port.h"
23

24
#include <stdarg.h>
25 26
#include <string.h>

27
#define NONAMELESSUNION
28

29
#include "windef.h"
30
#include "winerror.h"
31
#include "winbase.h"
32 33
#include "winnt.h"
#include "winreg.h"
34
#include "winnls.h"
35
#include "wine/unicode.h"
36
#include "wine/debug.h"
37

38
#include "dplayx_global.h"
39
#include "name_server.h"
40
#include "dplayx_queue.h"
41
#include "wine/dplaysp.h"
42
#include "dplay_global.h"
43

44
WINE_DEFAULT_DEBUG_CHANNEL(dplay);
45

46
/* FIXME: Should this be externed? */
47
extern HRESULT DPL_CreateCompoundAddress
48 49
( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
  LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
50

51 52

/* Local function prototypes */
53
static lpPlayerList DP_FindPlayer( IDirectPlayImpl *This, DPID dpid );
54
static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi );
55 56
static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
                             LPVOID lpData, DWORD dwDataSize );
57
static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
58 59 60 61
static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
                                                  DWORD dwPlayerType,
                                                  LPCDPNAME lpName,
                                                  DWORD dwFlags,
Peter Hunnisett's avatar
Peter Hunnisett committed
62
                                                  LPVOID lpContext );
63
static lpGroupData DP_FindAnyGroup( IDirectPlayImpl *This, DPID dpid );
64

65
/* Helper methods for player/group interfaces */
66 67 68 69
static HRESULT DP_SetSessionDesc( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpSessDesc,
        DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
static HRESULT DP_SP_SendEx( IDirectPlayImpl *This, DWORD dwFlags, void *lpData, DWORD dwDataSize,
        DWORD dwPriority, DWORD dwTimeout, void *lpContext, DWORD *lpdwMsgID );
70 71
static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
                                    LPDWORD lpdwBufSize );
Peter Hunnisett's avatar
Peter Hunnisett committed
72 73 74

static DPID DP_GetRemoteNextObjectId(void);

75
static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi );
76
static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
77 78
                                LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );

79

80
#define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
81
#define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
82 83 84 85 86 87 88 89 90
                                                 we don't have to change much */
#define DPID_NAME_SERVER 0x19a9d65b  /* Don't ask me why */

/* Strip out dwFlag values which cannot be sent in the CREATEGROUP msg */
#define DPMSG_CREATEGROUP_DWFLAGS(x) ( (x) & DPGROUP_HIDDEN )

/* Strip out all dwFlags values for CREATEPLAYER msg */
#define DPMSG_CREATEPLAYER_DWFLAGS(x) 0

91
static LONG kludgePlayerGroupId = 1000;
92 93


94 95 96 97 98
static inline IDirectPlayImpl *impl_from_IDirectPlay( IDirectPlay *iface )
{
    return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay_iface );
}

99 100 101 102 103
static inline IDirectPlayImpl *impl_from_IDirectPlay2( IDirectPlay2 *iface )
{
    return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay2_iface );
}

104 105 106 107 108
static inline IDirectPlayImpl *impl_from_IDirectPlay2A( IDirectPlay2A *iface )
{
    return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay2A_iface );
}

109 110 111 112 113
static inline IDirectPlayImpl *impl_from_IDirectPlay3A( IDirectPlay3A *iface )
{
    return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay3A_iface );
}

114 115 116 117 118
static inline IDirectPlayImpl *impl_from_IDirectPlay3( IDirectPlay3 *iface )
{
    return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay3_iface );
}

119 120
static inline IDirectPlayImpl *impl_from_IDirectPlay4A( IDirectPlay4A *iface )
{
121
    return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4A_iface );
122
}
123

124 125
static inline IDirectPlayImpl *impl_from_IDirectPlay4( IDirectPlay4 *iface )
{
126
    return CONTAINING_RECORD( iface, IDirectPlayImpl, IDirectPlay4_iface );
127 128
}

129
static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
130
{
131
  IDirectPlayImpl *This = lpDP;
132

133
  This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
134 135 136 137 138
  if ( This->dp2 == NULL )
  {
    return FALSE;
  }

139 140 141
  This->dp2->bConnectionOpen = FALSE;

  This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
142
  This->dp2->dwEnumSessionLock = 0;
143

144 145
  This->dp2->bHostInterface = FALSE;

146 147
  DPQ_INIT(This->dp2->receiveMsgs);
  DPQ_INIT(This->dp2->sendMsgs);
148
  DPQ_INIT(This->dp2->repliesExpected);
149

150 151
  if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
  {
152 153 154 155 156
    /* FIXME: Memory leak */
    return FALSE;
  }

  /* Provide an initial session desc with nothing in it */
157 158 159
  This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
                                        HEAP_ZERO_MEMORY,
                                        sizeof( *This->dp2->lpSessionDesc ) );
160 161 162 163 164 165 166
  if( This->dp2->lpSessionDesc == NULL )
  {
    /* FIXME: Memory leak */
    return FALSE;
  }
  This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );

167
  /* We are emulating a dp 6 implementation */
168 169 170 171 172 173
  This->dp2->spData.dwSPVersion = DPSP_MAJORVERSION;

  This->dp2->spData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                      sizeof( *This->dp2->spData.lpCB ) );
  This->dp2->spData.lpCB->dwSize = sizeof( *This->dp2->spData.lpCB );
  This->dp2->spData.lpCB->dwVersion = DPSP_MAJORVERSION;
174

175
  /* This is the pointer to the service provider */
176
  if ( FAILED( dplaysp_create( &IID_IDirectPlaySP, (void**)&This->dp2->spData.lpISP, This ) ) )
177 178
  {
    /* FIXME: Memory leak */
179 180 181
    return FALSE;
  }

182 183 184 185 186 187
  /* Setup lobby provider information */
  This->dp2->dplspData.dwSPVersion = DPSP_MAJORVERSION;
  This->dp2->dplspData.lpCB = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                         sizeof( *This->dp2->dplspData.lpCB ) );
  This->dp2->dplspData.lpCB->dwSize = sizeof(  *This->dp2->dplspData.lpCB );

188
  if( FAILED( dplobbysp_create( &IID_IDPLobbySP, (void**)&This->dp2->dplspData.lpISP, This ) )
189 190 191 192 193 194
    )
  {
    /* FIXME: Memory leak */
    return FALSE;
  }

195 196 197
  return TRUE;
}

198 199 200
/* Definition of the global function in dplayx_queue.h. #
 * FIXME: Would it be better to have a dplayx_queue.c for this function? */
DPQ_DECL_DELETECB( cbDeleteElemFromHeap, LPVOID )
201
{
202 203 204 205 206
  HeapFree( GetProcessHeap(), 0, elem );
}

static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
{
207
  IDirectPlayImpl *This = lpDP;
208

209 210 211 212 213
  if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
  {
    TerminateThread( This->dp2->hEnumSessionThread, 0 );
    CloseHandle( This->dp2->hEnumSessionThread );
  }
214

Peter Hunnisett's avatar
Peter Hunnisett committed
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
  /* Finish with the SP - have it shutdown */
  if( This->dp2->spData.lpCB->ShutdownEx )
  {
    DPSP_SHUTDOWNDATA data;

    TRACE( "Calling SP ShutdownEx\n" );

    data.lpISP = This->dp2->spData.lpISP;

    (*This->dp2->spData.lpCB->ShutdownEx)( &data );
  }
  else if (This->dp2->spData.lpCB->Shutdown ) /* obsolete interface */
  {
    TRACE( "Calling obsolete SP Shutdown\n" );
    (*This->dp2->spData.lpCB->Shutdown)();
  }

232
  /* Unload the SP (if it exists) */
Peter Hunnisett's avatar
Peter Hunnisett committed
233 234 235 236 237
  if( This->dp2->hServiceProvider != 0 )
  {
    FreeLibrary( This->dp2->hServiceProvider );
  }

238 239 240 241 242
  /* Unload the Lobby Provider (if it exists) */
  if( This->dp2->hDPLobbyProvider != 0 )
  {
    FreeLibrary( This->dp2->hDPLobbyProvider );
  }
Peter Hunnisett's avatar
Peter Hunnisett committed
243

244
  /* FIXME: Need to delete receive and send msgs queue contents */
245

246
  NS_DeleteSessionCache( This->dp2->lpNameServerData );
247

248
  HeapFree( GetProcessHeap(), 0, This->dp2->dplspData.lpCB);
249 250 251 252
  HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );

  IDirectPlaySP_Release( This->dp2->spData.lpISP );

253 254 255 256 257 258
  /* Delete the contents */
  HeapFree( GetProcessHeap(), 0, This->dp2 );

  return TRUE;
}

259 260 261 262 263 264 265
static void dplay_destroy(IDirectPlayImpl *obj)
{
     DP_DestroyDirectPlay2( obj );
     obj->lock.DebugInfo->Spare[0] = 0;
     DeleteCriticalSection( &obj->lock );
     HeapFree( GetProcessHeap(), 0, obj );
}
266

267
static inline DPID DP_NextObjectId(void)
268
{
269 270 271
  return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
}

Peter Hunnisett's avatar
Peter Hunnisett committed
272
/* *lplpReply will be non NULL iff there is something to reply */
273 274 275
HRESULT DP_HandleMessage( IDirectPlayImpl *This, const void *lpcMessageBody,
        DWORD dwMessageBodySize, const void *lpcMessageHeader, WORD wCommandId, WORD wVersion,
        void **lplpReply, DWORD *lpdwMsgSize )
Peter Hunnisett's avatar
Peter Hunnisett committed
276
{
277
  TRACE( "(%p)->(%p,0x%08x,%p,%u,%u)\n",
278
         This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
Peter Hunnisett's avatar
Peter Hunnisett committed
279 280 281 282
         wVersion );

  switch( wCommandId )
  {
283 284 285 286 287 288 289 290 291 292 293
    /* Name server needs to handle this request */
    case DPMSGCMD_ENUMSESSIONSREQUEST:
      /* Reply expected */
      NS_ReplyToEnumSessionsRequest( lpcMessageBody, lplpReply, lpdwMsgSize, This );
      break;

    /* Name server needs to handle this request */
    case DPMSGCMD_ENUMSESSIONSREPLY:
      /* No reply expected */
      NS_AddRemoteComputerAsNameServer( lpcMessageHeader,
                                        This->dp2->spData.dwSPHeaderSize,
294
                                        lpcMessageBody,
295 296 297
                                        This->dp2->lpNameServerData );
      break;

Peter Hunnisett's avatar
Peter Hunnisett committed
298 299
    case DPMSGCMD_REQUESTNEWPLAYERID:
    {
300
      LPCDPMSG_REQUESTNEWPLAYERID lpcMsg = lpcMessageBody;
301

Peter Hunnisett's avatar
Peter Hunnisett committed
302 303 304 305
      LPDPMSG_NEWPLAYERIDREPLY lpReply;

      *lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );

306
      *lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
Peter Hunnisett's avatar
Peter Hunnisett committed
307

308
      FIXME( "Ignoring dwFlags 0x%08x in request msg\n",
309
             lpcMsg->dwFlags );
Peter Hunnisett's avatar
Peter Hunnisett committed
310 311

      /* Setup the reply */
312
      lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
Peter Hunnisett's avatar
Peter Hunnisett committed
313 314 315
                                            This->dp2->spData.dwSPHeaderSize );

      lpReply->envelope.dwMagic    = DPMSGMAGIC_DPLAYMSG;
316 317
      lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
      lpReply->envelope.wVersion   = DPMSGVER_DP6;
Peter Hunnisett's avatar
Peter Hunnisett committed
318 319

      lpReply->dpidNewPlayerId = DP_NextObjectId();
320

321
      TRACE( "Allocating new playerid 0x%08x from remote request\n",
322
             lpReply->dpidNewPlayerId );
Peter Hunnisett's avatar
Peter Hunnisett committed
323 324 325
      break;
    }

326
    case DPMSGCMD_GETNAMETABLEREPLY:
Peter Hunnisett's avatar
Peter Hunnisett committed
327
    case DPMSGCMD_NEWPLAYERIDREPLY:
328
      DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
Peter Hunnisett's avatar
Peter Hunnisett committed
329
      break;
330

331
    case DPMSGCMD_JUSTENVELOPE:
332
      TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08x\n", lpcMessageHeader, ((const DWORD *)lpcMessageHeader)[1] );
333 334 335 336
      NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
      DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );

    case DPMSGCMD_FORWARDADDPLAYER:
337 338
      TRACE( "Sending message to self to get my addr\n" );
      DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
339 340
      break;

341 342 343
    case DPMSGCMD_FORWARDADDPLAYERNACK:
      DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
      break;
Peter Hunnisett's avatar
Peter Hunnisett committed
344 345 346

    default:
      FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
347
      DebugBreak();
Peter Hunnisett's avatar
Peter Hunnisett committed
348 349 350
      break;
  }

351 352
  /* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */

Peter Hunnisett's avatar
Peter Hunnisett committed
353 354 355
  return DP_OK;
}

356

357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
static HRESULT WINAPI IDirectPlayImpl_QueryInterface( IDirectPlay *iface, REFIID riid, void **ppv )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
}

static ULONG WINAPI IDirectPlayImpl_AddRef( IDirectPlay *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    ULONG ref = InterlockedIncrement( &This->ref );

    TRACE( "(%p) ref=%d\n", This, ref );

    if ( ref == 1 )
        InterlockedIncrement( &This->numIfaces );

    return ref;
}

static ULONG WINAPI IDirectPlayImpl_Release( IDirectPlay *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    ULONG ref = InterlockedDecrement( &This->ref );

    TRACE( "(%p) ref=%d\n", This, ref );

    if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
        dplay_destroy( This );

    return ref;
}

static HRESULT WINAPI IDirectPlayImpl_AddPlayerToGroup( IDirectPlay *iface, DPID group,
        DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, group, player );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_Close( IDirectPlay *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p): stub\n", This );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_CreatePlayer( IDirectPlay *iface, DPID *player,
        LPSTR name, LPSTR fullname, HANDLE *event )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(%p,%s,%s,%p): stub\n", This, player, debugstr_a( name ), debugstr_a( fullname ),
            event );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_CreateGroup( IDirectPlay *iface, DPID *group, LPSTR name,
        LPSTR fullname )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(%p,%s,%s): stub\n", This, group, debugstr_a( name ), debugstr_a( fullname ) );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_DeletePlayerFromGroup( IDirectPlay *iface, DPID group,
        DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, group, player );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_DestroyPlayer( IDirectPlay *iface, DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(0x%08x): stub\n", This, player );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_DestroyGroup( IDirectPlay *iface, DPID group )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(0x%08x): stub\n", This, group );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_EnableNewPlayers( IDirectPlay *iface, BOOL enable )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(%d): stub\n", This, enable );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_EnumGroupPlayers( IDirectPlay *iface, DPID group,
        LPDPENUMPLAYERSCALLBACK enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(0x%08x,%p,%p,0x%08x): stub\n", This, group, enumplayercb, context, flags );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_EnumGroups( IDirectPlay *iface, DWORD session,
        LPDPENUMPLAYERSCALLBACK enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(0x%08x,%p,%p,0x%08x): stub\n", This, session, enumplayercb, context, flags );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_EnumPlayers( IDirectPlay *iface, DWORD session,
        LPDPENUMPLAYERSCALLBACK enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(0x%08x,%p,%p,0x%08x): stub\n", This, session, enumplayercb, context, flags );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_EnumSessions( IDirectPlay *iface, DPSESSIONDESC *sdesc,
        DWORD timeout, LPDPENUMSESSIONSCALLBACK enumsessioncb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(%p,%u,%p,%p,0x%08x): stub\n", This, sdesc, timeout, enumsessioncb, context,
            flags );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_GetCaps( IDirectPlay *iface, DPCAPS *caps )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(%p): stub\n", This, caps );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_GetMessageCount( IDirectPlay *iface, DPID player,
        DWORD *count )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(0x%08x,%p): stub\n", This, player, count );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_GetPlayerCaps( IDirectPlay *iface, DPID player, DPCAPS *caps )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(0x%08x,%p): stub\n", This, player, caps );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_GetPlayerName( IDirectPlay *iface, DPID player, LPSTR name,
        DWORD *size_name, LPSTR fullname, DWORD *size_fullname )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(0x%08x,%p,%p,%p,%p): stub\n", This, player, name, size_name, fullname,
            size_fullname );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_Initialize( IDirectPlay *iface, GUID *guid )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(%p): stub\n", This, guid );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_Open( IDirectPlay *iface, DPSESSIONDESC *sdesc )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(%p): stub\n", This, sdesc );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_Receive( IDirectPlay *iface, DPID *from, DPID *to,
        DWORD flags, void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(%p,%p,0x%08x,%p,%p): stub\n", This, from, to, flags, data, size );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_SaveSession( IDirectPlay *iface, LPSTR reserved )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(%p): stub\n", This, reserved );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_Send( IDirectPlay *iface, DPID from, DPID to, DWORD flags,
        void *data, DWORD size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%u): stub\n", This, from, to, flags, data, size );
    return E_NOTIMPL;
}

static HRESULT WINAPI IDirectPlayImpl_SetPlayerName( IDirectPlay *iface, DPID player, LPSTR name,
        LPSTR fullname )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay( iface );
    FIXME( "(%p)->(0x%08x,%s,%s): stub\n", This, player, debugstr_a( name ),
            debugstr_a ( fullname ) );
    return E_NOTIMPL;
}

static const IDirectPlayVtbl dp_vt =
{
    IDirectPlayImpl_QueryInterface,
    IDirectPlayImpl_AddRef,
    IDirectPlayImpl_Release,
    IDirectPlayImpl_AddPlayerToGroup,
    IDirectPlayImpl_Close,
    IDirectPlayImpl_CreatePlayer,
    IDirectPlayImpl_CreateGroup,
    IDirectPlayImpl_DeletePlayerFromGroup,
    IDirectPlayImpl_DestroyPlayer,
    IDirectPlayImpl_DestroyGroup,
    IDirectPlayImpl_EnableNewPlayers,
    IDirectPlayImpl_EnumGroupPlayers,
    IDirectPlayImpl_EnumGroups,
    IDirectPlayImpl_EnumPlayers,
    IDirectPlayImpl_EnumSessions,
    IDirectPlayImpl_GetCaps,
    IDirectPlayImpl_GetMessageCount,
    IDirectPlayImpl_GetPlayerCaps,
    IDirectPlayImpl_GetPlayerName,
    IDirectPlayImpl_Initialize,
    IDirectPlayImpl_Open,
    IDirectPlayImpl_Receive,
    IDirectPlayImpl_SaveSession,
    IDirectPlayImpl_Send,
    IDirectPlayImpl_SetPlayerName,
};


590 591 592 593
static HRESULT WINAPI IDirectPlay2AImpl_QueryInterface( IDirectPlay2A *iface, REFIID riid,
        void **ppv )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
594
    return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
595 596
}

597 598 599 600 601 602 603
static HRESULT WINAPI IDirectPlay2Impl_QueryInterface( IDirectPlay2 *iface, REFIID riid,
        void **ppv )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
}

604 605 606 607 608 609 610
static HRESULT WINAPI IDirectPlay3AImpl_QueryInterface( IDirectPlay3A *iface, REFIID riid,
        void **ppv )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
}

611 612 613 614 615 616 617
static HRESULT WINAPI IDirectPlay3Impl_QueryInterface( IDirectPlay3 *iface, REFIID riid,
        void **ppv )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
}

618 619 620 621
static HRESULT WINAPI IDirectPlay4AImpl_QueryInterface( IDirectPlay4A *iface, REFIID riid,
        void **ppv )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
622
    return IDirectPlayX_QueryInterface( &This->IDirectPlay4_iface, riid, ppv );
623 624 625 626 627 628
}

static HRESULT WINAPI IDirectPlay4Impl_QueryInterface( IDirectPlay4 *iface, REFIID riid,
        void **ppv )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
629 630 631 632

    if ( IsEqualGUID( &IID_IUnknown, riid ) )
    {
        TRACE( "(%p)->(IID_IUnknown %p)\n", This, ppv );
633
        *ppv = &This->IDirectPlay_iface;
634
    }
635 636 637 638 639
    else if ( IsEqualGUID( &IID_IDirectPlay, riid ) )
    {
        TRACE( "(%p)->(IID_IDirectPlay %p)\n", This, ppv );
        *ppv = &This->IDirectPlay_iface;
    }
640 641 642
    else if ( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
    {
        TRACE( "(%p)->(IID_IDirectPlay2A %p)\n", This, ppv );
643
        *ppv = &This->IDirectPlay2A_iface;
644 645 646 647
    }
    else if ( IsEqualGUID( &IID_IDirectPlay2, riid ) )
    {
        TRACE( "(%p)->(IID_IDirectPlay2 %p)\n", This, ppv );
648
        *ppv = &This->IDirectPlay2_iface;
649 650 651 652
    }
    else if ( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
    {
        TRACE( "(%p)->(IID_IDirectPlay3A %p)\n", This, ppv );
653
        *ppv = &This->IDirectPlay3A_iface;
654 655 656 657
    }
    else if ( IsEqualGUID( &IID_IDirectPlay3, riid ) )
    {
        TRACE( "(%p)->(IID_IDirectPlay3 %p)\n", This, ppv );
658
        *ppv = &This->IDirectPlay3_iface;
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
    }
    else if ( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
    {
        TRACE( "(%p)->(IID_IDirectPlay4A %p)\n", This, ppv );
        *ppv = &This->IDirectPlay4A_iface;
    }
    else if ( IsEqualGUID( &IID_IDirectPlay4, riid ) )
    {
        TRACE( "(%p)->(IID_IDirectPlay4 %p)\n", This, ppv );
        *ppv = &This->IDirectPlay4_iface;
    }
    else
    {
        WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
        *ppv = NULL;
        return E_NOINTERFACE;
    }

    IUnknown_AddRef((IUnknown*)*ppv);
    return S_OK;
679 680
}

681 682 683 684 685 686 687 688 689 690 691 692 693
static ULONG WINAPI IDirectPlay2AImpl_AddRef( IDirectPlay2A *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    ULONG ref = InterlockedIncrement( &This->ref2A );

    TRACE( "(%p) ref2A=%d\n", This, ref );

    if ( ref == 1 )
        InterlockedIncrement( &This->numIfaces );

    return ref;
}

694 695 696 697 698 699 700 701 702 703 704 705 706
static ULONG WINAPI IDirectPlay2Impl_AddRef( IDirectPlay2 *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    ULONG ref = InterlockedIncrement( &This->ref2 );

    TRACE( "(%p) ref2=%d\n", This, ref );

    if ( ref == 1 )
        InterlockedIncrement( &This->numIfaces );

    return ref;
}

707 708 709 710 711 712 713 714 715 716 717 718 719
static ULONG WINAPI IDirectPlay3AImpl_AddRef( IDirectPlay3A *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    ULONG ref = InterlockedIncrement( &This->ref3A );

    TRACE( "(%p) ref3A=%d\n", This, ref );

    if ( ref == 1 )
        InterlockedIncrement( &This->numIfaces );

    return ref;
}

720 721 722 723 724 725 726 727 728 729 730 731 732
static ULONG WINAPI IDirectPlay3Impl_AddRef( IDirectPlay3 *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    ULONG ref = InterlockedIncrement( &This->ref3 );

    TRACE( "(%p) ref3=%d\n", This, ref );

    if ( ref == 1 )
        InterlockedIncrement( &This->numIfaces );

    return ref;
}

733 734 735
static ULONG WINAPI IDirectPlay4AImpl_AddRef(IDirectPlay4A *iface)
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
736 737 738 739 740 741 742 743
    ULONG ref = InterlockedIncrement( &This->ref4A );

    TRACE( "(%p) ref4A=%d\n", This, ref );

    if ( ref == 1 )
        InterlockedIncrement( &This->numIfaces );

    return ref;
744 745 746 747 748
}

static ULONG WINAPI IDirectPlay4Impl_AddRef(IDirectPlay4 *iface)
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
749 750 751 752 753 754 755 756
    ULONG ref = InterlockedIncrement( &This->ref4 );

    TRACE( "(%p) ref4=%d\n", This, ref );

    if ( ref == 1 )
        InterlockedIncrement( &This->numIfaces );

    return ref;
757 758
}

759 760 761 762 763 764 765 766 767 768 769 770 771
static ULONG WINAPI IDirectPlay2AImpl_Release( IDirectPlay2A *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    ULONG ref = InterlockedDecrement( &This->ref2A );

    TRACE( "(%p) ref2A=%d\n", This, ref );

    if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
        dplay_destroy( This );

    return ref;
}

772 773 774 775 776 777 778 779 780 781 782 783 784
static ULONG WINAPI IDirectPlay2Impl_Release( IDirectPlay2 *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    ULONG ref = InterlockedDecrement( &This->ref2 );

    TRACE( "(%p) ref2=%d\n", This, ref );

    if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
        dplay_destroy( This );

    return ref;
}

785 786 787 788 789 790 791 792 793 794 795 796 797
static ULONG WINAPI IDirectPlay3AImpl_Release( IDirectPlay3A *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    ULONG ref = InterlockedDecrement( &This->ref3A );

    TRACE( "(%p) ref3A=%d\n", This, ref );

    if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
        dplay_destroy( This );

    return ref;
}

798 799 800 801 802 803 804 805 806 807 808 809 810
static ULONG WINAPI IDirectPlay3Impl_Release( IDirectPlay3 *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    ULONG ref = InterlockedDecrement( &This->ref3 );

    TRACE( "(%p) ref3=%d\n", This, ref );

    if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
        dplay_destroy( This );

    return ref;
}

811 812 813
static ULONG WINAPI IDirectPlay4AImpl_Release(IDirectPlay4A *iface)
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
814 815 816 817 818 819 820 821
    ULONG ref = InterlockedDecrement( &This->ref4A );

    TRACE( "(%p) ref4A=%d\n", This, ref );

    if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
        dplay_destroy( This );

    return ref;
822 823 824 825 826
}

static ULONG WINAPI IDirectPlay4Impl_Release(IDirectPlay4 *iface)
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
827 828 829 830 831 832 833 834
    ULONG ref = InterlockedDecrement( &This->ref4 );

    TRACE( "(%p) ref4=%d\n", This, ref );

    if ( !ref && !InterlockedDecrement( &This->numIfaces ) )
        dplay_destroy( This );

    return ref;
835 836
}

837 838 839 840 841 842 843
static HRESULT WINAPI IDirectPlay2AImpl_AddPlayerToGroup( IDirectPlay2A *iface, DPID group,
        DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4A_iface, group, player );
}

844 845 846 847 848 849 850
static HRESULT WINAPI IDirectPlay2Impl_AddPlayerToGroup( IDirectPlay2 *iface, DPID group,
        DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
}

851 852 853 854 855 856 857
static HRESULT WINAPI IDirectPlay3AImpl_AddPlayerToGroup( IDirectPlay3A *iface, DPID group,
        DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
}

858 859 860 861 862 863 864
static HRESULT WINAPI IDirectPlay3Impl_AddPlayerToGroup( IDirectPlay3 *iface, DPID group,
        DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
}

865 866
static HRESULT WINAPI IDirectPlay4AImpl_AddPlayerToGroup( IDirectPlay4A *iface, DPID group,
        DPID player )
867
{
868 869
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_AddPlayerToGroup( &This->IDirectPlay4_iface, group, player );
870 871
}

872 873
static HRESULT WINAPI IDirectPlay4Impl_AddPlayerToGroup( IDirectPlay4 *iface, DPID group,
        DPID player )
874
{
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    lpGroupData  gdata;
    lpPlayerList plist;
    lpPlayerList newplist;

    TRACE( "(%p)->(0x%08x,0x%08x)\n", This, group, player );

    if ( This->dp2->connectionInitialized == NO_PROVIDER )
        return DPERR_UNINITIALIZED;

    /* Find the group */
    if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
        return DPERR_INVALIDGROUP;

    /* Find the player */
    if ( ( plist = DP_FindPlayer( This, player ) ) == NULL )
        return DPERR_INVALIDPLAYER;

    /* Create a player list (ie "shortcut" ) */
    newplist = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *newplist ) );
    if ( !newplist )
        return DPERR_CANTADDPLAYER;

    /* Add the shortcut */
    plist->lpPData->uRef++;
    newplist->lpPData = plist->lpPData;

    /* Add the player to the list of players for this group */
    DPQ_INSERT(gdata->players, newplist, players);

    /* Let the SP know that we've added a player to the group */
    if ( This->dp2->spData.lpCB->AddPlayerToGroup )
    {
        DPSP_ADDPLAYERTOGROUPDATA data;

        TRACE( "Calling SP AddPlayerToGroup\n" );

        data.idPlayer = player;
        data.idGroup  = group;
        data.lpISP    = This->dp2->spData.lpISP;

        (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
    }

    /* Inform all other peers of the addition of player to the group. If there are
     * no peers keep this event quiet.
     * Also, if this event was the result of another machine sending it to us,
     * don't bother rebroadcasting it.
     */
    if ( This->dp2->lpSessionDesc &&
            ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
    {
        DPMSG_ADDPLAYERTOGROUP msg;
        msg.dwType = DPSYS_ADDPLAYERTOGROUP;

        msg.dpIdGroup  = group;
        msg.dpIdPlayer = player;

        /* FIXME: Correct to just use send effectively? */
        /* FIXME: Should size include data w/ message or just message "header" */
        /* FIXME: Check return code */
        IDirectPlayX_SendEx( iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
                0, 0, NULL, NULL );
    }

    return DP_OK;
941 942
}

943 944 945 946 947 948
static HRESULT WINAPI IDirectPlay2AImpl_Close( IDirectPlay2A *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_Close( &This->IDirectPlay4A_iface );
}

949 950 951 952 953 954
static HRESULT WINAPI IDirectPlay2Impl_Close( IDirectPlay2 *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_Close( &This->IDirectPlay4_iface );
}

955 956 957 958 959 960
static HRESULT WINAPI IDirectPlay3AImpl_Close( IDirectPlay3A *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_Close( &This->IDirectPlay4_iface );
}

961 962 963 964 965 966
static HRESULT WINAPI IDirectPlay3Impl_Close( IDirectPlay3 *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_Close( &This->IDirectPlay4_iface );
}

967
static HRESULT WINAPI IDirectPlay4AImpl_Close( IDirectPlay4A *iface )
968
{
969 970 971
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_Close( &This->IDirectPlay4_iface);
}
972

973 974 975 976
static HRESULT WINAPI IDirectPlay4Impl_Close( IDirectPlay4 *iface )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    HRESULT hr = DP_OK;
977

978
    TRACE( "(%p)\n", This );
979

980 981 982
    /* FIXME: Need to find a new host I assume (how?) */
    /* FIXME: Need to destroy all local groups */
    /* FIXME: Need to migrate all remotely visible players to the new host */
983

984 985 986 987
    /* Invoke the SP callback to inform of session close */
    if( This->dp2->spData.lpCB->CloseEx )
    {
        DPSP_CLOSEDATA data;
988

989 990 991 992 993 994 995 996 997
        TRACE( "Calling SP CloseEx\n" );
        data.lpISP = This->dp2->spData.lpISP;
        hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
    }
    else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
    {
        TRACE( "Calling SP Close (obsolete interface)\n" );
        hr = (*This->dp2->spData.lpCB->Close)();
    }
998

999
    return hr;
1000 1001
}

1002 1003
static lpGroupData DP_CreateGroup( IDirectPlayImpl *This, const DPID *lpid, const DPNAME *lpName,
        DWORD dwFlags, DPID idParent, BOOL bAnsi )
1004
{
1005
  lpGroupData lpGData;
1006

1007
  /* Allocate the new space and add to end of high level group list */
1008
  lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
1009

1010
  if( lpGData == NULL )
1011 1012 1013 1014
  {
    return NULL;
  }

1015 1016
  DPQ_INIT(lpGData->groups);
  DPQ_INIT(lpGData->players);
1017

1018 1019
  /* Set the desired player ID - no sanity checking to see if it exists */
  lpGData->dpid = *lpid;
1020

1021
  DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
1022

1023 1024
  /* FIXME: Should we check that the parent exists? */
  lpGData->parent  = idParent;
1025

1026 1027 1028
  /* FIXME: Should we validate the dwFlags? */
  lpGData->dwFlags = dwFlags;

1029
  TRACE( "Created group id 0x%08x\n", *lpid );
1030

1031
  return lpGData;
1032 1033
}

1034
/* This method assumes that all links to it are already deleted */
1035
static void DP_DeleteGroup( IDirectPlayImpl *This, DPID dpid )
1036 1037 1038
{
  lpGroupList lpGList;

1039
  TRACE( "(%p)->(0x%08x)\n", This, dpid );
1040

1041
  DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
1042 1043 1044

  if( lpGList == NULL )
  {
1045
    ERR( "DPID 0x%08x not found\n", dpid );
1046 1047 1048
    return;
  }

Peter Hunnisett's avatar
Peter Hunnisett committed
1049 1050 1051 1052 1053 1054
  if( --(lpGList->lpGData->uRef) )
  {
    FIXME( "Why is this not the last reference to group?\n" );
    DebugBreak();
  }

1055 1056 1057 1058 1059 1060
  /* Delete player */
  DP_DeleteDPNameStruct( &lpGList->lpGData->name );
  HeapFree( GetProcessHeap(), 0, lpGList->lpGData );

  /* Remove and Delete Player List object */
  HeapFree( GetProcessHeap(), 0, lpGList );
1061

1062 1063
}

1064
static lpGroupData DP_FindAnyGroup( IDirectPlayImpl *This, DPID dpid )
1065 1066 1067
{
  lpGroupList lpGroups;

1068
  TRACE( "(%p)->(0x%08x)\n", This, dpid );
1069

1070
  if( dpid == DPID_SYSTEM_GROUP )
1071
  {
1072
    return This->dp2->lpSysGroup;
1073 1074 1075
  }
  else
  {
1076
    DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
1077
  }
1078

Peter Hunnisett's avatar
Peter Hunnisett committed
1079 1080 1081 1082
  if( lpGroups == NULL )
  {
    return NULL;
  }
1083

1084
  return lpGroups->lpGData;
1085
}
1086

1087 1088
static HRESULT DP_IF_CreateGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID *lpidGroup,
        DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
1089
{
1090 1091
  lpGroupData lpGData;

1092
  TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1093
         This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
1094
         dwFlags, bAnsi );
1095

1096 1097 1098 1099 1100
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
  /* If the name is not specified, we must provide one */
  if( DPID_UNKNOWN == *lpidGroup )
  {
    /* If we are the name server, we decide on the group ids. If not, we
     * must ask for one before attempting a creation.
     */
    if( This->dp2->bHostInterface )
    {
      *lpidGroup = DP_NextObjectId();
    }
    else
    {
Peter Hunnisett's avatar
Peter Hunnisett committed
1113
      *lpidGroup = DP_GetRemoteNextObjectId();
1114 1115
    }
  }
1116

1117 1118
  lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
                            DPID_NOPARENT_GROUP, bAnsi );
1119 1120 1121 1122 1123

  if( lpGData == NULL )
  {
    return DPERR_CANTADDPLAYER; /* yes player not group */
  }
1124

1125 1126
  if( DPID_SYSTEM_GROUP == *lpidGroup )
  {
1127
    This->dp2->lpSysGroup = lpGData;
1128
    TRACE( "Inserting system group\n" );
1129 1130 1131 1132
  }
  else
  {
    /* Insert into the system group */
1133
    lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
1134 1135 1136 1137 1138
    lpGroup->lpGData = lpGData;

    DPQ_INSERT( This->dp2->lpSysGroup->groups, lpGroup, groups );
  }

Peter Hunnisett's avatar
Peter Hunnisett committed
1139 1140 1141
  /* Something is now referencing this data */
  lpGData->uRef++;

1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169
  /* Set all the important stuff for the group */
  DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );

  /* FIXME: We should only create the system group if GetCaps returns
   *        DPCAPS_GROUPOPTIMIZED.
   */

  /* Let the SP know that we've created this group */
  if( This->dp2->spData.lpCB->CreateGroup )
  {
    DPSP_CREATEGROUPDATA data;
    DWORD dwCreateFlags = 0;

    TRACE( "Calling SP CreateGroup\n" );

    if( *lpidGroup == DPID_NOPARENT_GROUP )
      dwCreateFlags |= DPLAYI_GROUP_SYSGROUP;

    if( lpMsgHdr == NULL )
      dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;

    if( dwFlags & DPGROUP_HIDDEN )
      dwCreateFlags |= DPLAYI_GROUP_HIDDEN;

    data.idGroup           = *lpidGroup;
    data.dwFlags           = dwCreateFlags;
    data.lpSPMessageHeader = lpMsgHdr;
    data.lpISP             = This->dp2->spData.lpISP;
1170

Peter Hunnisett's avatar
Peter Hunnisett committed
1171
    (*This->dp2->spData.lpCB->CreateGroup)( &data );
1172 1173
  }

1174 1175
  /* Inform all other peers of the creation of a new group. If there are
   * no peers keep this event quiet.
1176 1177 1178
   * Also if this message was sent to us, don't rebroadcast.
   */
  if( ( lpMsgHdr == NULL ) &&
1179
      This->dp2->lpSessionDesc &&
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
      ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
  {
    DPMSG_CREATEPLAYERORGROUP msg;
    msg.dwType = DPSYS_CREATEPLAYERORGROUP;

    msg.dwPlayerType     = DPPLAYERTYPE_GROUP;
    msg.dpId             = *lpidGroup;
    msg.dwCurrentPlayers = 0; /* FIXME: Incorrect? */
    msg.lpData           = lpData;
    msg.dwDataSize       = dwDataSize;
    msg.dpnName          = *lpGroupName;
    msg.dpIdParent       = DPID_NOPARENT_GROUP;
    msg.dwFlags          = DPMSG_CREATEGROUP_DWFLAGS( dwFlags );

    /* FIXME: Correct to just use send effectively? */
    /* FIXME: Should size include data w/ message or just message "header" */
    /* FIXME: Check return code */
1197 1198
    IDirectPlayX_SendEx( &This->IDirectPlay4_iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
            sizeof( msg ), 0, 0, NULL, NULL );
1199
  }
1200

1201 1202 1203
  return DP_OK;
}

1204 1205 1206 1207 1208 1209 1210 1211
static HRESULT WINAPI IDirectPlay2AImpl_CreateGroup( IDirectPlay2A *iface, DPID *lpidGroup,
        DPNAME *name, void *data, DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_CreateGroup( &This->IDirectPlay4A_iface, lpidGroup, name, data, size,
            flags );
}

1212 1213 1214 1215 1216 1217 1218 1219
static HRESULT WINAPI IDirectPlay2Impl_CreateGroup( IDirectPlay2 *iface, DPID *lpidGroup,
        DPNAME *name, void *data, DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_CreateGroup( &This->IDirectPlay4_iface, lpidGroup, name, data, size,
            flags );
}

1220 1221 1222 1223 1224 1225 1226 1227
static HRESULT WINAPI IDirectPlay3AImpl_CreateGroup( IDirectPlay3A *iface, DPID *group,
        DPNAME *name, void *data, DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_CreateGroup( &This->IDirectPlay4_iface, group, name, data, size,
            flags );
}

1228 1229 1230 1231 1232 1233 1234 1235
static HRESULT WINAPI IDirectPlay3Impl_CreateGroup( IDirectPlay3 *iface, DPID *lpidGroup,
        DPNAME *name, void *data, DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_CreateGroup( &This->IDirectPlay4_iface, lpidGroup, name, data, size,
            flags );
}

1236 1237
static HRESULT WINAPI IDirectPlay4AImpl_CreateGroup( IDirectPlay4A *iface, DPID *lpidGroup,
        DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1238
{
1239
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1240

1241 1242 1243 1244
    *lpidGroup = DPID_UNKNOWN;

    return DP_IF_CreateGroup( This, NULL, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
            TRUE );
1245 1246
}

1247 1248
static HRESULT WINAPI IDirectPlay4Impl_CreateGroup( IDirectPlay4 *iface, DPID *lpidGroup,
        DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1249
{
1250 1251 1252
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );

    *lpidGroup = DPID_UNKNOWN;
1253

1254 1255
    return DP_IF_CreateGroup( This, NULL, lpidGroup, lpGroupName, lpData, dwDataSize, dwFlags,
            FALSE );
1256 1257 1258
}


1259
static void
1260
DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
1261
                 LPVOID lpData, DWORD dwDataSize )
1262 1263
{
  /* Clear out the data with this player */
1264
  if( dwFlags & DPSET_LOCAL )
1265
  {
1266 1267 1268 1269 1270 1271
    if ( lpGData->dwLocalDataSize != 0 )
    {
      HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
      lpGData->lpLocalData = NULL;
      lpGData->dwLocalDataSize = 0;
    }
1272
  }
1273
  else
1274
  {
1275 1276 1277 1278 1279 1280
    if( lpGData->dwRemoteDataSize != 0 )
    {
      HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
      lpGData->lpRemoteData = NULL;
      lpGData->dwRemoteDataSize = 0;
    }
1281 1282 1283
  }

  /* Reallocate for new data */
1284
  if( lpData != NULL )
1285
  {
1286 1287 1288 1289 1290
    if( dwFlags & DPSET_LOCAL )
    {
      lpGData->lpLocalData     = lpData;
      lpGData->dwLocalDataSize = dwDataSize;
    }
1291 1292
    else
    {
1293 1294
      lpGData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
      CopyMemory( lpGData->lpRemoteData, lpData, dwDataSize );
1295 1296
      lpGData->dwRemoteDataSize = dwDataSize;
    }
1297
  }
1298

1299 1300
}

Peter Hunnisett's avatar
Peter Hunnisett committed
1301
/* This function will just create the storage for the new player.  */
1302 1303
static lpPlayerData DP_CreatePlayer( IDirectPlayImpl *This, DPID *lpid, DPNAME *lpName,
        DWORD dwFlags, HANDLE hEvent, BOOL bAnsi )
1304
{
1305
  lpPlayerData lpPData;
1306 1307 1308

  TRACE( "(%p)->(%p,%p,%u)\n", This, lpid, lpName, bAnsi );

1309
  /* Allocate the storage for the player and associate it with list element */
1310
  lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
1311
  if( lpPData == NULL )
1312 1313 1314 1315
  {
    return NULL;
  }

1316 1317
  /* Set the desired player ID */
  lpPData->dpid = *lpid;
1318

1319
  DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1320

1321
  lpPData->dwFlags = dwFlags;
1322

1323 1324 1325 1326 1327 1328 1329 1330 1331
  /* If we were given an event handle, duplicate it */
  if( hEvent != 0 )
  {
    if( !DuplicateHandle( GetCurrentProcess(), hEvent,
                          GetCurrentProcess(), &lpPData->hEvent,
                          0, FALSE, DUPLICATE_SAME_ACCESS )
      )
    {
      /* FIXME: Memory leak */
1332
      ERR( "Can't duplicate player msg handle %p\n", hEvent );
1333 1334
    }
  }
1335

1336 1337 1338
  /* Initialize the SP data section */
  lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();

1339
  TRACE( "Created player id 0x%08x\n", *lpid );
1340

1341 1342 1343
  if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
    This->dp2->lpSessionDesc->dwCurrentPlayers++;

1344
  return lpPData;
1345 1346 1347 1348 1349 1350
}

/* Delete the contents of the DPNAME struct */
static void
DP_DeleteDPNameStruct( LPDPNAME lpDPName )
{
1351 1352
  HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
  HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1353 1354
}

1355
/* This method assumes that all links to it are already deleted */
1356
static void DP_DeletePlayer( IDirectPlayImpl *This, DPID dpid )
1357
{
Peter Hunnisett's avatar
Peter Hunnisett committed
1358
  lpPlayerList lpPList;
1359

1360
  TRACE( "(%p)->(0x%08x)\n", This, dpid );
1361

Peter Hunnisett's avatar
Peter Hunnisett committed
1362
  DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPList );
1363

Peter Hunnisett's avatar
Peter Hunnisett committed
1364
  if( lpPList == NULL )
1365
  {
1366
    ERR( "DPID 0x%08x not found\n", dpid );
1367
    return;
1368
  }
Peter Hunnisett's avatar
Peter Hunnisett committed
1369 1370 1371 1372 1373

  /* Verify that this is the last reference to the data */
  if( --(lpPList->lpPData->uRef) )
  {
    FIXME( "Why is this not the last reference to player?\n" );
1374
    DebugBreak();
Peter Hunnisett's avatar
Peter Hunnisett committed
1375
  }
1376

1377
  /* Delete player */
Peter Hunnisett's avatar
Peter Hunnisett committed
1378
  DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1379

Peter Hunnisett's avatar
Peter Hunnisett committed
1380 1381
  CloseHandle( lpPList->lpPData->hEvent );
  HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1382 1383

  /* Delete Player List object */
Peter Hunnisett's avatar
Peter Hunnisett committed
1384
  HeapFree( GetProcessHeap(), 0, lpPList );
1385 1386
}

1387
static lpPlayerList DP_FindPlayer( IDirectPlayImpl *This, DPID dpid )
1388 1389 1390
{
  lpPlayerList lpPlayers;

1391
  TRACE( "(%p)->(0x%08x)\n", This, dpid );
1392

1393 1394 1395
  if(This->dp2->lpSysGroup == NULL)
    return NULL;

1396
  DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1397 1398

  return lpPlayers;
1399 1400 1401
}

/* Basic area for Dst must already be allocated */
1402
static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi )
1403 1404 1405 1406 1407 1408 1409 1410
{
  if( lpSrc == NULL )
  {
    ZeroMemory( lpDst, sizeof( *lpDst ) );
    lpDst->dwSize = sizeof( *lpDst );
    return TRUE;
  }

1411
  if( lpSrc->dwSize != sizeof( *lpSrc) )
1412 1413 1414 1415 1416
  {
    return FALSE;
  }

  /* Delete any existing pointers */
1417 1418
  HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
  HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1419 1420

  /* Copy as required */
1421
  CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1422 1423 1424

  if( bAnsi )
  {
1425
    if( lpSrc->u1.lpszShortNameA )
1426
    {
1427 1428 1429
        lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
                                             strlen(lpSrc->u1.lpszShortNameA)+1 );
        strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1430
    }
1431
    if( lpSrc->u2.lpszLongNameA )
1432
    {
1433 1434 1435
        lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
                                              strlen(lpSrc->u2.lpszLongNameA)+1 );
        strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1436 1437 1438 1439
    }
  }
  else
  {
1440
    if( lpSrc->u1.lpszShortNameA )
1441
    {
1442 1443 1444
        lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
                                              (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
        strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1445
    }
1446
    if( lpSrc->u2.lpszLongNameA )
1447
    {
1448 1449 1450
        lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
                                             (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
        strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1451 1452 1453 1454 1455 1456
    }
  }

  return TRUE;
}

1457 1458
static void
DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1459
                  LPVOID lpData, DWORD dwDataSize )
1460 1461
{
  /* Clear out the data with this player */
1462
  if( dwFlags & DPSET_LOCAL )
1463
  {
1464 1465 1466 1467 1468 1469
    if ( lpPData->dwLocalDataSize != 0 )
    {
      HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
      lpPData->lpLocalData = NULL;
      lpPData->dwLocalDataSize = 0;
    }
1470
  }
1471
  else
1472
  {
1473 1474 1475 1476 1477 1478
    if( lpPData->dwRemoteDataSize != 0 )
    {
      HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
      lpPData->lpRemoteData = NULL;
      lpPData->dwRemoteDataSize = 0;
    }
1479 1480 1481
  }

  /* Reallocate for new data */
1482
  if( lpData != NULL )
1483
  {
1484 1485 1486 1487 1488 1489

    if( dwFlags & DPSET_LOCAL )
    {
      lpPData->lpLocalData     = lpData;
      lpPData->dwLocalDataSize = dwDataSize;
    }
1490 1491
    else
    {
1492 1493
      lpPData->lpRemoteData = HeapAlloc( GetProcessHeap(), 0, dwDataSize );
      CopyMemory( lpPData->lpRemoteData, lpData, dwDataSize );
1494 1495
      lpPData->dwRemoteDataSize = dwDataSize;
    }
1496
  }
1497

1498 1499
}

1500 1501 1502 1503
/* Note: lpMsgHdr is NULL for local creation, non NULL for remote creation */
static HRESULT DP_IF_CreatePlayer( IDirectPlayImpl *This, void *lpMsgHdr, DPID *lpidPlayer,
        DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags,
        BOOL bAnsi )
1504
{
1505
  HRESULT hr = DP_OK;
1506
  lpPlayerData lpPData;
1507
  lpPlayerList lpPList;
1508
  DWORD dwCreateFlags = 0;
1509

1510
  TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1511
         This, lpidPlayer, lpPlayerName, hEvent, lpData,
1512
         dwDataSize, dwFlags, bAnsi );
1513 1514 1515 1516
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }
1517

1518
  if( dwFlags == 0 )
1519 1520 1521 1522
  {
    dwFlags = DPPLAYER_SPECTATOR;
  }

1523 1524 1525 1526 1527
  if( lpidPlayer == NULL )
  {
    return DPERR_INVALIDPARAMS;
  }

1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556

  /* Determine the creation flags for the player. These will be passed
   * to the name server if requesting a player id and to the SP when
   * informing it of the player creation
   */
  {
    if( dwFlags & DPPLAYER_SERVERPLAYER )
    {
      if( *lpidPlayer == DPID_SERVERPLAYER )
      {
        /* Server player for the host interface */
        dwCreateFlags |= DPLAYI_PLAYER_APPSERVER;
      }
      else if( *lpidPlayer == DPID_NAME_SERVER )
      {
        /* Name server - master of everything */
        dwCreateFlags |= (DPLAYI_PLAYER_NAMESRVR|DPLAYI_PLAYER_SYSPLAYER);
      }
      else
      {
        /* Server player for a non host interface */
        dwCreateFlags |= DPLAYI_PLAYER_SYSPLAYER;
      }
    }

    if( lpMsgHdr == NULL )
      dwCreateFlags |= DPLAYI_PLAYER_PLAYERLOCAL;
  }

1557 1558 1559 1560 1561 1562 1563
  /* Verify we know how to handle all the flags */
  if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
         ( dwFlags & DPPLAYER_SPECTATOR )
       )
    )
  {
    /* Assume non fatal failure */
1564
    ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1565 1566
  }

1567 1568
  /* If the name is not specified, we must provide one */
  if( *lpidPlayer == DPID_UNKNOWN )
1569
  {
1570 1571
    /* If we are the session master, we dish out the group/player ids */
    if( This->dp2->bHostInterface )
1572
    {
1573
      *lpidPlayer = DP_NextObjectId();
1574
    }
1575 1576
    else
    {
1577
      hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1578

Peter Hunnisett's avatar
Peter Hunnisett committed
1579 1580 1581 1582 1583
      if( FAILED(hr) )
      {
        ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
        return hr;
      }
1584
    }
1585 1586 1587
  }
  else
  {
1588 1589 1590
    /* FIXME: Would be nice to perhaps verify that we don't already have
     *        this player.
     */
1591 1592
  }

1593 1594 1595
  /* We pass creation flags, so we can distinguish sysplayers and not count them in the current
     player total */
  lpPData = DP_CreatePlayer( This, lpidPlayer, lpPlayerName, dwCreateFlags,
1596 1597
                             hEvent, bAnsi );
  /* Create the list object and link it in */
1598
  lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1599
  if( !lpPData || !lpPList )
1600
  {
1601 1602
    HeapFree( GetProcessHeap(), 0, lpPData );
    HeapFree( GetProcessHeap(), 0, lpPList );
1603 1604 1605
    return DPERR_CANTADDPLAYER;
  }

Peter Hunnisett's avatar
Peter Hunnisett committed
1606
  lpPData->uRef = 1;
1607
  lpPList->lpPData = lpPData;
1608

Peter Hunnisett's avatar
Peter Hunnisett committed
1609
  /* Add the player to the system group */
1610
  DPQ_INSERT( This->dp2->lpSysGroup->players, lpPList, players );
1611

Peter Hunnisett's avatar
Peter Hunnisett committed
1612
  /* Update the information and send it to all players in the session */
1613
  DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624

  /* Let the SP know that we've created this player */
  if( This->dp2->spData.lpCB->CreatePlayer )
  {
    DPSP_CREATEPLAYERDATA data;

    data.idPlayer          = *lpidPlayer;
    data.dwFlags           = dwCreateFlags;
    data.lpSPMessageHeader = lpMsgHdr;
    data.lpISP             = This->dp2->spData.lpISP;

1625
    TRACE( "Calling SP CreatePlayer 0x%08x: dwFlags: 0x%08x lpMsgHdr: %p\n",
1626 1627
           *lpidPlayer, data.dwFlags, data.lpSPMessageHeader );

1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642
    hr = (*This->dp2->spData.lpCB->CreatePlayer)( &data );
  }

  if( FAILED(hr) )
  {
    ERR( "Failed to create player with sp: %s\n", DPLAYX_HresultToString(hr) );
    return hr;
  }

  /* Now let the SP know that this player is a member of the system group */
  if( This->dp2->spData.lpCB->AddPlayerToGroup )
  {
    DPSP_ADDPLAYERTOGROUPDATA data;

    data.idPlayer = *lpidPlayer;
1643
    data.idGroup  = DPID_SYSTEM_GROUP;
1644 1645 1646 1647 1648 1649 1650 1651 1652
    data.lpISP    = This->dp2->spData.lpISP;

    TRACE( "Calling SP AddPlayerToGroup (sys group)\n" );

    hr = (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
  }

  if( FAILED(hr) )
  {
1653
    ERR( "Failed to add player to sys group with sp: %s\n",
1654 1655
         DPLAYX_HresultToString(hr) );
    return hr;
1656 1657
  }

1658
#if 1
1659
  if( !This->dp2->bHostInterface )
1660 1661 1662 1663 1664 1665
  {
    /* Let the name server know about the creation of this player */
    /* FIXME: Is this only to be done for the creation of a server player or
     *        is this used for regular players? If only for server players, move
     *        this call to DP_SecureOpen(...);
     */
1666 1667 1668 1669 1670
#if 0
    TRACE( "Sending message to self to get my addr\n" );
    DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
#endif

1671 1672 1673
    hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
  }
#else
1674
  /* Inform all other peers of the creation of a new player. If there are
1675
   * no peers keep this quiet.
1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696
   * Also, if this was a remote event, no need to rebroadcast it.
   */
  if( ( lpMsgHdr == NULL ) &&
      This->dp2->lpSessionDesc &&
      ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
  {
    DPMSG_CREATEPLAYERORGROUP msg;
    msg.dwType = DPSYS_CREATEPLAYERORGROUP;

    msg.dwPlayerType     = DPPLAYERTYPE_PLAYER;
    msg.dpId             = *lpidPlayer;
    msg.dwCurrentPlayers = 0; /* FIXME: Incorrect */
    msg.lpData           = lpData;
    msg.dwDataSize       = dwDataSize;
    msg.dpnName          = *lpPlayerName;
    msg.dpIdParent       = DPID_NOPARENT_GROUP;
    msg.dwFlags          = DPMSG_CREATEPLAYER_DWFLAGS( dwFlags );

    /* FIXME: Correct to just use send effectively? */
    /* FIXME: Should size include data w/ message or just message "header" */
    /* FIXME: Check return code */
1697 1698
    hr = IDirectPlayX_SendEx( &This->IDirectPlay4_iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0,
            &msg, sizeof( msg ), 0, 0, NULL, NULL );
1699
  }
1700
#endif
1701

1702
  return hr;
1703 1704
}

1705 1706 1707 1708 1709 1710 1711 1712
static HRESULT WINAPI IDirectPlay2AImpl_CreatePlayer( IDirectPlay2A *iface, DPID *lpidPlayer,
        DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_CreatePlayer( &This->IDirectPlay4A_iface, lpidPlayer, name, event, data,
            size, flags );
}

1713 1714 1715 1716 1717 1718 1719 1720
static HRESULT WINAPI IDirectPlay2Impl_CreatePlayer( IDirectPlay2 *iface, DPID *lpidPlayer,
        DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_CreatePlayer( &This->IDirectPlay4_iface, lpidPlayer, name, event, data,
            size, flags );
}

1721 1722 1723 1724 1725 1726 1727 1728
static HRESULT WINAPI IDirectPlay3AImpl_CreatePlayer( IDirectPlay3A *iface, DPID *lpidPlayer,
        DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_CreatePlayer( &This->IDirectPlay4_iface, lpidPlayer, name, event, data,
            size, flags );
}

1729 1730 1731 1732 1733 1734 1735 1736
static HRESULT WINAPI IDirectPlay3Impl_CreatePlayer( IDirectPlay3 *iface, DPID *lpidPlayer,
        DPNAME *name, HANDLE event, void *data, DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_CreatePlayer( &This->IDirectPlay4_iface, lpidPlayer, name, event, data,
            size, flags );
}

1737 1738
static HRESULT WINAPI IDirectPlay4AImpl_CreatePlayer( IDirectPlay4A *iface, DPID *lpidPlayer,
        DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1739
{
1740
  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
1741

1742 1743 1744 1745 1746
  if( lpidPlayer == NULL )
  {
    return DPERR_INVALIDPARAMS;
  }

1747 1748 1749 1750 1751 1752 1753 1754 1755
  if( dwFlags & DPPLAYER_SERVERPLAYER )
  {
    *lpidPlayer = DPID_SERVERPLAYER;
  }
  else
  {
    *lpidPlayer = DPID_UNKNOWN;
  }

1756
  return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1757 1758 1759
                           lpData, dwDataSize, dwFlags, TRUE );
}

1760 1761
static HRESULT WINAPI IDirectPlay4Impl_CreatePlayer( IDirectPlay4 *iface, DPID *lpidPlayer,
        DPNAME *lpPlayerName, HANDLE hEvent, void *lpData, DWORD dwDataSize, DWORD dwFlags )
1762
{
1763
  IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
1764

1765 1766 1767 1768 1769
  if( lpidPlayer == NULL )
  {
    return DPERR_INVALIDPARAMS;
  }

1770 1771 1772 1773 1774 1775 1776 1777 1778
  if( dwFlags & DPPLAYER_SERVERPLAYER )
  {
    *lpidPlayer = DPID_SERVERPLAYER;
  }
  else
  {
    *lpidPlayer = DPID_UNKNOWN;
  }

1779
  return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1780
                           lpData, dwDataSize, dwFlags, FALSE );
1781 1782
}

Peter Hunnisett's avatar
Peter Hunnisett committed
1783 1784 1785 1786 1787 1788 1789 1790
static DPID DP_GetRemoteNextObjectId(void)
{
  FIXME( ":stub\n" );

  /* Hack solution */
  return DP_NextObjectId();
}

1791 1792 1793 1794 1795 1796 1797
static HRESULT WINAPI IDirectPlay2AImpl_DeletePlayerFromGroup( IDirectPlay2A *iface, DPID group,
        DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4A_iface, group, player );
}

1798 1799 1800 1801 1802 1803 1804
static HRESULT WINAPI IDirectPlay2Impl_DeletePlayerFromGroup( IDirectPlay2 *iface, DPID group,
        DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
}

1805 1806 1807 1808 1809 1810 1811
static HRESULT WINAPI IDirectPlay3AImpl_DeletePlayerFromGroup( IDirectPlay3A *iface, DPID group,
        DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
}

1812 1813 1814 1815 1816 1817 1818
static HRESULT WINAPI IDirectPlay3Impl_DeletePlayerFromGroup( IDirectPlay3 *iface, DPID group,
        DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
}

1819 1820
static HRESULT WINAPI IDirectPlay4AImpl_DeletePlayerFromGroup( IDirectPlay4A *iface, DPID group,
        DPID player )
1821
{
1822 1823 1824
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_DeletePlayerFromGroup( &This->IDirectPlay4_iface, group, player );
}
1825

1826 1827 1828 1829 1830
static HRESULT WINAPI IDirectPlay4Impl_DeletePlayerFromGroup( IDirectPlay4 *iface, DPID group,
        DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    HRESULT hr = DP_OK;
1831

1832 1833
    lpGroupData  gdata;
    lpPlayerList plist;
1834

1835
    TRACE( "(%p)->(0x%08x,0x%08x)\n", This, group, player );
1836

1837 1838 1839
    /* Find the group */
    if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
        return DPERR_INVALIDGROUP;
Peter Hunnisett's avatar
Peter Hunnisett committed
1840

1841
    /* Find the player */
1842
    if ( DP_FindPlayer( This, player ) == NULL )
1843
        return DPERR_INVALIDPLAYER;
1844

1845 1846
    /* Remove the player shortcut from the group */
    DPQ_REMOVE_ENTRY( gdata->players, players, lpPData->dpid, ==, player, plist );
1847

1848 1849
    if ( !plist )
        return DPERR_INVALIDPLAYER;
1850

1851 1852
    /* One less reference */
    plist->lpPData->uRef--;
1853

1854 1855
    /* Delete the Player List element */
    HeapFree( GetProcessHeap(), 0, plist );
1856

1857 1858 1859 1860
    /* Inform the SP if they care */
    if ( This->dp2->spData.lpCB->RemovePlayerFromGroup )
    {
        DPSP_REMOVEPLAYERFROMGROUPDATA data;
1861

1862 1863 1864 1865 1866 1867
        TRACE( "Calling SP RemovePlayerFromGroup\n" );
        data.idPlayer = player;
        data.idGroup = group;
        data.lpISP = This->dp2->spData.lpISP;
        hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
    }
1868

1869 1870
    /* Need to send a DELETEPLAYERFROMGROUP message */
    FIXME( "Need to send a message\n" );
1871

1872
    return hr;
1873 1874
}

1875 1876
typedef struct _DPRGOPContext
{
1877
  IDirectPlayImpl   *This;
Peter Hunnisett's avatar
Peter Hunnisett committed
1878 1879
  BOOL              bAnsi;
  DPID              idGroup;
1880 1881
} DPRGOPContext, *lpDPRGOPContext;

Peter Hunnisett's avatar
Peter Hunnisett committed
1882
static BOOL CALLBACK
1883 1884 1885 1886 1887 1888 1889 1890
cbRemoveGroupOrPlayer(
    DPID            dpId,
    DWORD           dwPlayerType,
    LPCDPNAME       lpName,
    DWORD           dwFlags,
    LPVOID          lpContext )
{
  lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1891

1892
  TRACE( "Removing element:0x%08x (type:0x%08x) from element:0x%08x\n",
1893 1894 1895 1896
           dpId, dwPlayerType, lpCtxt->idGroup );

  if( dwPlayerType == DPPLAYERTYPE_GROUP )
  {
1897 1898 1899
    if ( FAILED( IDirectPlayX_DeleteGroupFromGroup( &lpCtxt->This->IDirectPlay4_iface,
                    lpCtxt->idGroup, dpId ) ) )
      ERR( "Unable to delete group 0x%08x from group 0x%08x\n", dpId, lpCtxt->idGroup );
1900
  }
1901 1902 1903
  else if ( FAILED( IDirectPlayX_DeletePlayerFromGroup( &lpCtxt->This->IDirectPlay4_iface,
                                                        lpCtxt->idGroup, dpId ) ) )
      ERR( "Unable to delete player 0x%08x from grp 0x%08x\n", dpId, lpCtxt->idGroup );
1904

1905 1906 1907
  return TRUE; /* Continue enumeration */
}

1908
static HRESULT DP_IF_DestroyGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID idGroup, BOOL bAnsi )
1909
{
1910
  lpGroupData lpGData;
1911 1912
  DPRGOPContext context;

1913
  FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1914
         This, lpMsgHdr, idGroup, bAnsi );
1915 1916

  /* Find the group */
1917
  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1918 1919 1920 1921
  {
    return DPERR_INVALIDPLAYER; /* yes player */
  }

1922
  context.This    = This;
1923
  context.bAnsi   = bAnsi;
1924 1925
  context.idGroup = idGroup;

Peter Hunnisett's avatar
Peter Hunnisett committed
1926
  /* Remove all players that this group has */
1927 1928
  IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, idGroup, NULL, cbRemoveGroupOrPlayer,
          &context, 0 );
Peter Hunnisett's avatar
Peter Hunnisett committed
1929

1930
  /* Remove all links to groups that this group has since this is dp3 */
1931 1932
  IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4_iface, idGroup, NULL, cbRemoveGroupOrPlayer,
          (void*)&context, 0 );
1933

Peter Hunnisett's avatar
Peter Hunnisett committed
1934
  /* Remove this group from the parent group - if it has one */
1935 1936
  if( ( idGroup != DPID_SYSTEM_GROUP ) && ( lpGData->parent != DPID_SYSTEM_GROUP ) )
    IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, lpGData->parent, idGroup );
1937

Peter Hunnisett's avatar
Peter Hunnisett committed
1938
  /* Now delete this group data and list from the system group */
1939
  DP_DeleteGroup( This, idGroup );
1940

1941 1942 1943 1944 1945 1946 1947 1948
  /* Let the SP know that we've destroyed this group */
  if( This->dp2->spData.lpCB->DeleteGroup )
  {
    DPSP_DELETEGROUPDATA data;

    FIXME( "data.dwFlags is incorrect\n" );

    data.idGroup = idGroup;
1949
    data.dwFlags = 0;
1950 1951
    data.lpISP   = This->dp2->spData.lpISP;

Peter Hunnisett's avatar
Peter Hunnisett committed
1952
    (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1953 1954 1955
  }

  FIXME( "Send out a DESTORYPLAYERORGROUP message\n" );
1956

1957 1958 1959
  return DP_OK;
}

1960 1961 1962 1963 1964 1965
static HRESULT WINAPI IDirectPlay2AImpl_DestroyGroup( IDirectPlay2A *iface, DPID group )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_DestroyGroup( &This->IDirectPlay4A_iface, group );
}

1966 1967 1968 1969 1970 1971
static HRESULT WINAPI IDirectPlay2Impl_DestroyGroup( IDirectPlay2 *iface, DPID group )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_DestroyGroup( &This->IDirectPlay4_iface, group );
}

1972 1973 1974 1975 1976 1977
static HRESULT WINAPI IDirectPlay3AImpl_DestroyGroup( IDirectPlay3A *iface, DPID group )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_DestroyGroup( &This->IDirectPlay4_iface, group );
}

1978 1979 1980 1981 1982 1983
static HRESULT WINAPI IDirectPlay3Impl_DestroyGroup( IDirectPlay3 *iface, DPID group )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_DestroyGroup( &This->IDirectPlay4_iface, group );
}

1984
static HRESULT WINAPI IDirectPlay4AImpl_DestroyGroup( IDirectPlay4A *iface, DPID idGroup )
1985
{
1986 1987
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1988 1989
}

1990
static HRESULT WINAPI IDirectPlay4Impl_DestroyGroup( IDirectPlay4 *iface, DPID idGroup )
1991
{
1992 1993
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1994 1995
}

1996 1997
typedef struct _DPFAGContext
{
1998
  IDirectPlayImpl   *This;
Peter Hunnisett's avatar
Peter Hunnisett committed
1999 2000
  DPID              idPlayer;
  BOOL              bAnsi;
2001 2002
} DPFAGContext, *lpDPFAGContext;

2003 2004
static HRESULT DP_IF_DestroyPlayer( IDirectPlayImpl *This, void *lpMsgHdr, DPID idPlayer,
        BOOL bAnsi )
2005
{
2006 2007
  DPFAGContext cbContext;

2008
  FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
2009
         This, lpMsgHdr, idPlayer, bAnsi );
2010

2011 2012 2013 2014 2015
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

2016
  if( DP_FindPlayer( This, idPlayer ) == NULL )
2017 2018 2019 2020 2021 2022
  {
    return DPERR_INVALIDPLAYER;
  }

  /* FIXME: If the player is remote, we must be the host to delete this */

Peter Hunnisett's avatar
Peter Hunnisett committed
2023
  cbContext.This     = This;
2024
  cbContext.idPlayer = idPlayer;
Peter Hunnisett's avatar
Peter Hunnisett committed
2025
  cbContext.bAnsi    = bAnsi;
2026 2027 2028

  /* Find each group and call DeletePlayerFromGroup if the player is a
     member of the group */
2029
  IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, NULL, cbDeletePlayerFromAllGroups, &cbContext,
2030
          DPENUMGROUPS_ALL );
2031

Peter Hunnisett's avatar
Peter Hunnisett committed
2032
  /* Now delete player and player list from the sys group */
2033 2034
  DP_DeletePlayer( This, idPlayer );

2035 2036 2037 2038 2039 2040 2041 2042
  /* Let the SP know that we've destroyed this group */
  if( This->dp2->spData.lpCB->DeletePlayer )
  {
    DPSP_DELETEPLAYERDATA data;

    FIXME( "data.dwFlags is incorrect\n" );

    data.idPlayer = idPlayer;
2043
    data.dwFlags = 0;
2044 2045
    data.lpISP   = This->dp2->spData.lpISP;

Peter Hunnisett's avatar
Peter Hunnisett committed
2046
    (*This->dp2->spData.lpCB->DeletePlayer)( &data );
2047 2048 2049
  }

  FIXME( "Send a DELETEPLAYERORGROUP msg\n" );
2050

2051 2052 2053
  return DP_OK;
}

Peter Hunnisett's avatar
Peter Hunnisett committed
2054
static BOOL CALLBACK
2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065
cbDeletePlayerFromAllGroups(
    DPID            dpId,
    DWORD           dwPlayerType,
    LPCDPNAME       lpName,
    DWORD           dwFlags,
    LPVOID          lpContext )
{
  lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;

  if( dwPlayerType == DPPLAYERTYPE_GROUP )
  {
2066
    IDirectPlayX_DeletePlayerFromGroup( &lpCtxt->This->IDirectPlay4_iface, dpId, lpCtxt->idPlayer );
Peter Hunnisett's avatar
Peter Hunnisett committed
2067 2068 2069 2070

    /* Enumerate all groups in this group since this will normally only
     * be called for top level groups
     */
2071 2072
    IDirectPlayX_EnumGroupsInGroup( &lpCtxt->This->IDirectPlay4_iface, dpId, NULL,
            cbDeletePlayerFromAllGroups, lpContext, DPENUMGROUPS_ALL);
2073 2074 2075 2076

  }
  else
  {
2077
    ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
2078 2079 2080 2081 2082
  }

  return TRUE;
}

2083 2084 2085 2086 2087 2088
static HRESULT WINAPI IDirectPlay2AImpl_DestroyPlayer( IDirectPlay2A *iface, DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4A_iface, player );
}

2089 2090 2091 2092 2093 2094
static HRESULT WINAPI IDirectPlay2Impl_DestroyPlayer( IDirectPlay2 *iface, DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4_iface, player );
}

2095 2096 2097 2098 2099 2100
static HRESULT WINAPI IDirectPlay3AImpl_DestroyPlayer( IDirectPlay3A *iface, DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4_iface, player );
}

2101 2102 2103 2104 2105 2106
static HRESULT WINAPI IDirectPlay3Impl_DestroyPlayer( IDirectPlay3 *iface, DPID player )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_DestroyPlayer( &This->IDirectPlay4_iface, player );
}

2107
static HRESULT WINAPI IDirectPlay4AImpl_DestroyPlayer( IDirectPlay4A *iface, DPID idPlayer )
2108
{
2109 2110
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
2111
}
2112

2113
static HRESULT WINAPI IDirectPlay4Impl_DestroyPlayer( IDirectPlay4 *iface, DPID idPlayer )
2114
{
2115 2116
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
2117 2118
}

2119 2120 2121 2122 2123 2124 2125 2126
static HRESULT WINAPI IDirectPlay2AImpl_EnumGroupPlayers( IDirectPlay2A *iface, DPID group,
        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4A_iface, group, instance,
            enumplayercb, context, flags );
}

2127 2128 2129 2130 2131 2132 2133 2134
static HRESULT WINAPI IDirectPlay2Impl_EnumGroupPlayers( IDirectPlay2 *iface, DPID group,
        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance,
            enumplayercb, context, flags );
}

2135 2136 2137 2138 2139 2140 2141 2142
static HRESULT WINAPI IDirectPlay3AImpl_EnumGroupPlayers( IDirectPlay3A *iface, DPID group,
        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance,
            enumplayercb, context, flags );
}

2143 2144 2145 2146 2147 2148 2149 2150
static HRESULT WINAPI IDirectPlay3Impl_EnumGroupPlayers( IDirectPlay3 *iface, DPID group,
        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance,
            enumplayercb, context, flags );
}

2151 2152
static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupPlayers( IDirectPlay4A *iface, DPID group,
        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2153
{
2154 2155 2156 2157
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_EnumGroupPlayers( &This->IDirectPlay4_iface, group, instance, enumplayercb,
            context, flags );
}
2158

2159 2160 2161 2162 2163 2164
static HRESULT WINAPI IDirectPlay4Impl_EnumGroupPlayers( IDirectPlay4 *iface, DPID group,
        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    lpGroupData  gdata;
    lpPlayerList plist;
2165

2166 2167
    FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x): semi stub\n", This, group, instance, enumplayercb,
           context, flags );
2168

2169 2170
    if ( This->dp2->connectionInitialized == NO_PROVIDER )
        return DPERR_UNINITIALIZED;
2171

2172 2173 2174
    /* Find the group */
    if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
        return DPERR_INVALIDGROUP;
2175

2176
    if ( DPQ_IS_EMPTY( gdata->players ) )
2177 2178
        return DP_OK;

2179 2180
    /* Walk the players in this group */
    for( plist = DPQ_FIRST( gdata->players ); ; plist = DPQ_NEXT( plist->players ) )
2181
    {
2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193
        /* We do not enum the name server or app server as they are of no
         * consequence to the end user.
         */
        if ( ( plist->lpPData->dpid != DPID_NAME_SERVER ) &&
                ( plist->lpPData->dpid != DPID_SERVERPLAYER ) )
        {
            /* FIXME: Need to add stuff for flags checking */
            if ( !enumplayercb( plist->lpPData->dpid, DPPLAYERTYPE_PLAYER,
                        &plist->lpPData->name, plist->lpPData->dwFlags, context ) )
              /* User requested break */
              return DP_OK;
        }
2194

2195 2196 2197 2198
        if ( DPQ_IS_ENDOFLIST( plist->players ) )
            break;
    }
    return DP_OK;
2199 2200
}

2201
/* NOTE: This only enumerates top level groups (created with CreateGroup) */
2202 2203 2204 2205 2206 2207 2208 2209
static HRESULT WINAPI IDirectPlay2AImpl_EnumGroups( IDirectPlay2A *iface, GUID *instance,
        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_EnumGroups( &This->IDirectPlay4A_iface, instance, enumplayercb, context,
            flags );
}

2210 2211 2212 2213 2214 2215 2216 2217
static HRESULT WINAPI IDirectPlay2Impl_EnumGroups( IDirectPlay2 *iface, GUID *instance,
        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, instance, enumplayercb, context,
            flags );
}

2218 2219 2220 2221 2222 2223 2224 2225
static HRESULT WINAPI IDirectPlay3AImpl_EnumGroups( IDirectPlay3A *iface, GUID *instance,
        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, instance, enumplayercb, context,
            flags );
}

2226 2227 2228 2229 2230 2231 2232 2233
static HRESULT WINAPI IDirectPlay3Impl_EnumGroups( IDirectPlay3 *iface, GUID *instance,
        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_EnumGroups( &This->IDirectPlay4_iface, instance, enumplayercb, context,
            flags );
}

2234 2235
static HRESULT WINAPI IDirectPlay4AImpl_EnumGroups( IDirectPlay4A *iface, GUID *instance,
        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2236
{
2237 2238
    return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
            context, flags );
2239 2240
}

2241 2242
static HRESULT WINAPI IDirectPlay4Impl_EnumGroups ( IDirectPlay4 *iface, GUID *instance,
        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2243
{
2244 2245
    return IDirectPlayX_EnumGroupsInGroup( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
            context, flags );
2246 2247
}

2248 2249 2250 2251 2252 2253 2254 2255
static HRESULT WINAPI IDirectPlay2AImpl_EnumPlayers( IDirectPlay2A *iface, GUID *instance,
        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_EnumPlayers( &This->IDirectPlay4A_iface, instance, enumplayercb, context,
            flags );
}

2256 2257 2258 2259 2260 2261 2262 2263
static HRESULT WINAPI IDirectPlay2Impl_EnumPlayers( IDirectPlay2 *iface, GUID *instance,
        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_EnumPlayers( &This->IDirectPlay4_iface, instance, enumplayercb, context,
            flags );
}

2264 2265 2266 2267 2268 2269 2270 2271
static HRESULT WINAPI IDirectPlay3AImpl_EnumPlayers( IDirectPlay3A *iface, GUID *instance,
        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_EnumPlayers( &This->IDirectPlay4_iface, instance, enumplayercb, context,
            flags );
}

2272 2273 2274 2275 2276 2277 2278 2279
static HRESULT WINAPI IDirectPlay3Impl_EnumPlayers( IDirectPlay3 *iface, GUID *instance,
        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_EnumPlayers( &This->IDirectPlay4_iface, instance, enumplayercb, context,
            flags );
}

2280 2281
static HRESULT WINAPI IDirectPlay4AImpl_EnumPlayers( IDirectPlay4A *iface, GUID *instance,
        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2282
{
2283 2284
    return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
            context, flags );
2285 2286
}

2287 2288
static HRESULT WINAPI IDirectPlay4Impl_EnumPlayers( IDirectPlay4 *iface, GUID *instance,
        LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
2289
{
2290 2291
    return IDirectPlayX_EnumGroupPlayers( iface, DPID_SYSTEM_GROUP, instance, enumplayercb,
            context, flags );
2292 2293
}

Peter Hunnisett's avatar
Peter Hunnisett committed
2294
/* This function should call the registered callback function that the user
2295
   passed into EnumSessions for each entry available.
Peter Hunnisett's avatar
Peter Hunnisett committed
2296
 */
Peter Hunnisett's avatar
Peter Hunnisett committed
2297 2298 2299 2300 2301
static void DP_InvokeEnumSessionCallbacks
       ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
         LPVOID lpNSInfo,
         DWORD dwTimeout,
         LPVOID lpContext )
2302
{
2303 2304 2305 2306
  LPDPSESSIONDESC2 lpSessionDesc;

  FIXME( ": not checking for conditions\n" );

2307 2308 2309
  /* Not sure if this should be pruning but it's convenient */
  NS_PruneSessionCache( lpNSInfo );

2310 2311 2312
  NS_ResetSessionEnumeration( lpNSInfo );

  /* Enumerate all sessions */
2313
  /* FIXME: Need to indicate ANSI */
2314 2315 2316 2317 2318 2319 2320 2321 2322
  while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
  {
    TRACE( "EnumSessionsCallback2 invoked\n" );
    if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
    {
      return;
    }
  }

2323 2324
  /* Invoke one last time to indicate that there is no more to come */
  lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
2325 2326
}

2327 2328
static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
{
2329
  EnumSessionAsyncCallbackData* data = lpContext;
2330 2331 2332
  HANDLE hSuicideRequest = data->hSuicideRequest;
  DWORD dwTimeout = data->dwTimeout;

2333
  TRACE( "Thread started with timeout = 0x%08x\n", dwTimeout );
2334 2335 2336

  for( ;; )
  {
Peter Hunnisett's avatar
Peter Hunnisett committed
2337
    HRESULT hr;
2338 2339 2340

    /* Sleep up to dwTimeout waiting for request to terminate thread */
    if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
2341
    {
2342 2343
      TRACE( "Thread terminating on terminate request\n" );
      break;
2344
    }
Peter Hunnisett's avatar
Peter Hunnisett committed
2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356

    /* Now resend the enum request */
    hr = NS_SendSessionRequestBroadcast( &data->requestGuid,
                                         data->dwEnumSessionFlags,
                                         data->lpSpData );

    if( FAILED(hr) )
    {
      ERR( "Enum broadcase request failed: %s\n", DPLAYX_HresultToString(hr) );
      /* FIXME: Should we kill this thread? How to inform the main thread? */
    }

2357 2358
  }

2359 2360 2361 2362 2363 2364
  TRACE( "Thread terminating\n" );

  /* Clean up the thread data */
  CloseHandle( hSuicideRequest );
  HeapFree( GetProcessHeap(), 0, lpContext );

Peter Hunnisett's avatar
Peter Hunnisett committed
2365 2366 2367 2368 2369 2370 2371
  /* FIXME: Need to have some notification to main app thread that this is
   *        dead. It would serve two purposes. 1) allow sync on termination
   *        so that we don't actually send something to ourselves when we
   *        become name server (race condition) and 2) so that if we die
   *        abnormally something else will be able to tell.
   */

2372
  return 1;
2373 2374
}

2375
static void DP_KillEnumSessionThread( IDirectPlayImpl *This )
2376 2377 2378 2379
{
  /* Does a thread exist? If so we were doing an async enum session */
  if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
  {
2380
    TRACE( "Killing EnumSession thread %p\n",
2381
           This->dp2->hEnumSessionThread );
2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393

    /* Request that the thread kill itself nicely */
    SetEvent( This->dp2->hKillEnumSessionThreadEvent );
    CloseHandle( This->dp2->hKillEnumSessionThreadEvent );

    /* We no longer need to know about the thread */
    CloseHandle( This->dp2->hEnumSessionThread );

    This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
  }
}

2394 2395 2396 2397 2398 2399 2400 2401
static HRESULT WINAPI IDirectPlay2AImpl_EnumSessions( IDirectPlay2A *iface, DPSESSIONDESC2 *sdesc,
        DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_EnumSessions( &This->IDirectPlay4A_iface, sdesc, timeout, enumsessioncb,
            context, flags );
}

2402 2403 2404 2405 2406 2407 2408 2409
static HRESULT WINAPI IDirectPlay2Impl_EnumSessions( IDirectPlay2 *iface, DPSESSIONDESC2 *sdesc,
        DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
            context, flags );
}

2410 2411 2412 2413 2414 2415 2416 2417
static HRESULT WINAPI IDirectPlay3AImpl_EnumSessions( IDirectPlay3A *iface, DPSESSIONDESC2 *sdesc,
        DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
            context, flags );
}

2418 2419 2420 2421 2422 2423 2424 2425
static HRESULT WINAPI IDirectPlay3Impl_EnumSessions( IDirectPlay3 *iface, DPSESSIONDESC2 *sdesc,
        DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
            context, flags );
}

2426 2427
static HRESULT WINAPI IDirectPlay4AImpl_EnumSessions( IDirectPlay4A *iface, DPSESSIONDESC2 *sdesc,
        DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
2428
{
2429 2430 2431 2432
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_EnumSessions( &This->IDirectPlay4_iface, sdesc, timeout, enumsessioncb,
            context, flags );
}
2433

2434 2435 2436 2437 2438 2439 2440
static HRESULT WINAPI IDirectPlay4Impl_EnumSessions( IDirectPlay4 *iface, DPSESSIONDESC2 *sdesc,
        DWORD timeout, LPDPENUMSESSIONSCALLBACK2 enumsessioncb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    void *connection;
    DWORD  size;
    HRESULT hr = DP_OK;
2441

2442 2443
    TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x)\n", This, sdesc, timeout, enumsessioncb,
            context, flags );
2444

2445 2446
    if ( This->dp2->connectionInitialized == NO_PROVIDER )
        return DPERR_UNINITIALIZED;
2447

2448 2449 2450
    /* Can't enumerate if the interface is already open */
    if ( This->dp2->bConnectionOpen )
        return DPERR_GENERIC;
2451

2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463
    /* The loading of a lobby provider _seems_ to require a backdoor loading
     * of the service provider to also associate with this DP object. This is
     * because the app doesn't seem to have to call EnumConnections and
     * InitializeConnection for the SP before calling this method. As such
     * we'll do their dirty work for them with a quick hack so as to always
     * load the TCP/IP service provider.
     *
     * The correct solution would seem to involve creating a dialog box which
     * contains the possible SPs. These dialog boxes most likely follow SDK
     * examples.
     */
    if ( This->dp2->bDPLSPInitialized && !This->dp2->bSPInitialized )
2464
    {
2465
        WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );
Peter Hunnisett's avatar
Peter Hunnisett committed
2466

2467
        if ( !DP_BuildSPCompoundAddr( (GUID*)&DPSPGUID_TCPIP, &connection, &size ) )
Peter Hunnisett's avatar
Peter Hunnisett committed
2468
        {
2469 2470
            ERR( "Can't build compound addr\n" );
            return DPERR_GENERIC;
Peter Hunnisett's avatar
Peter Hunnisett committed
2471
        }
2472

2473 2474 2475
        hr = IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, 0 );
        if ( FAILED(hr) )
            return hr;
2476

2477 2478
        HeapFree( GetProcessHeap(), 0, connection );
        This->dp2->bSPInitialized = TRUE;
2479
    }
2480 2481


2482 2483 2484 2485 2486
    /* Use the service provider default? */
    if ( !timeout )
    {
        DPCAPS caps;
        caps.dwSize = sizeof( caps );
2487

2488 2489 2490 2491 2492
        IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, &caps, 0 );
        timeout = caps.dwTimeout;
        if ( !timeout )
            timeout = DPMSG_WAIT_5_SECS; /* Provide the TCP/IP default */
    }
2493

2494 2495 2496 2497 2498
    if ( flags & DPENUMSESSIONS_STOPASYNC )
    {
        DP_KillEnumSessionThread( This );
        return hr;
    }
2499

2500 2501 2502 2503 2504
    if ( flags & DPENUMSESSIONS_ASYNC )
    {
        /* Enumerate everything presently in the local session cache */
        DP_InvokeEnumSessionCallbacks( enumsessioncb, This->dp2->lpNameServerData, timeout,
                context );
2505

2506 2507
        if ( This->dp2->dwEnumSessionLock )
            return DPERR_CONNECTING;
Peter Hunnisett's avatar
Peter Hunnisett committed
2508

2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555
        /* See if we've already created a thread to service this interface */
        if ( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
        {
            DWORD tid;
            This->dp2->dwEnumSessionLock++;

            /* Send the first enum request inline since the user may cancel a dialog
             * if one is presented. Also, may also have a connecting return code.
             */
            hr = NS_SendSessionRequestBroadcast( &sdesc->guidApplication, flags,
                    &This->dp2->spData );

            if ( SUCCEEDED(hr) )
            {
                EnumSessionAsyncCallbackData* data = HeapAlloc( GetProcessHeap(),
                        HEAP_ZERO_MEMORY, sizeof( *data ) );
                /* FIXME: need to kill the thread on object deletion */
                data->lpSpData  = &This->dp2->spData;
                data->requestGuid = sdesc->guidApplication;
                data->dwEnumSessionFlags = flags;
                data->dwTimeout = timeout;

                This->dp2->hKillEnumSessionThreadEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
                if ( !DuplicateHandle( GetCurrentProcess(), This->dp2->hKillEnumSessionThreadEvent,
                            GetCurrentProcess(), &data->hSuicideRequest, 0, FALSE,
                            DUPLICATE_SAME_ACCESS ) )
                    ERR( "Can't duplicate thread killing handle\n" );

                TRACE( ": creating EnumSessionsRequest thread\n" );
                This->dp2->hEnumSessionThread = CreateThread( NULL, 0,
                        DP_EnumSessionsSendAsyncRequestThread, data, 0, &tid );
            }
            This->dp2->dwEnumSessionLock--;
        }
    }
    else
    {
        /* Invalidate the session cache for the interface */
        NS_InvalidateSessionCache( This->dp2->lpNameServerData );
        /* Send the broadcast for session enumeration */
        hr = NS_SendSessionRequestBroadcast( &sdesc->guidApplication, flags, &This->dp2->spData );
        SleepEx( timeout, FALSE );
        DP_InvokeEnumSessionCallbacks( enumsessioncb, This->dp2->lpNameServerData, timeout,
                context );
    }

    return hr;
2556 2557
}

2558 2559 2560 2561 2562 2563
static HRESULT WINAPI IDirectPlay2AImpl_GetCaps( IDirectPlay2A *iface, DPCAPS *caps, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_GetCaps( &This->IDirectPlay4A_iface, caps, flags );
}

2564 2565 2566 2567 2568 2569
static HRESULT WINAPI IDirectPlay2Impl_GetCaps( IDirectPlay2 *iface, DPCAPS *caps, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, caps, flags );
}

2570 2571 2572 2573 2574 2575
static HRESULT WINAPI IDirectPlay3AImpl_GetCaps( IDirectPlay3A *iface, DPCAPS *caps, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, caps, flags );
}

2576 2577 2578 2579 2580 2581
static HRESULT WINAPI IDirectPlay3Impl_GetCaps( IDirectPlay3 *iface, DPCAPS *caps, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_GetCaps( &This->IDirectPlay4_iface, caps, flags );
}

2582
static HRESULT WINAPI IDirectPlay4AImpl_GetCaps( IDirectPlay4A *iface, DPCAPS *caps, DWORD flags )
Peter Hunnisett's avatar
Peter Hunnisett committed
2583
{
2584
    return IDirectPlayX_GetPlayerCaps( iface, DPID_ALLPLAYERS, caps, flags );
Peter Hunnisett's avatar
Peter Hunnisett committed
2585
}
2586

2587
static HRESULT WINAPI IDirectPlay4Impl_GetCaps( IDirectPlay4 *iface, DPCAPS *caps, DWORD flags )
2588
{
2589
    return IDirectPlayX_GetPlayerCaps( iface, DPID_ALLPLAYERS, caps, flags );
2590 2591
}

2592 2593 2594 2595 2596 2597 2598
static HRESULT WINAPI IDirectPlay2AImpl_GetGroupData( IDirectPlay2A *iface, DPID group, void *data,
        DWORD *size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_GetGroupData( &This->IDirectPlay4A_iface, group, data, size, flags );
}

2599 2600 2601 2602 2603 2604 2605
static HRESULT WINAPI IDirectPlay2Impl_GetGroupData( IDirectPlay2 *iface, DPID group, void *data,
        DWORD *size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
}

2606 2607 2608 2609 2610 2611 2612
static HRESULT WINAPI IDirectPlay3AImpl_GetGroupData( IDirectPlay3A *iface, DPID group, void *data,
        DWORD *size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
}

2613 2614 2615 2616 2617 2618 2619
static HRESULT WINAPI IDirectPlay3Impl_GetGroupData( IDirectPlay3 *iface, DPID group, void *data,
        DWORD *size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
}

2620 2621
static HRESULT WINAPI IDirectPlay4AImpl_GetGroupData( IDirectPlay4A *iface, DPID group,
        void *data, DWORD *size, DWORD flags )
2622
{
2623 2624 2625
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_GetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
}
2626

2627 2628 2629 2630 2631 2632 2633
static HRESULT WINAPI IDirectPlay4Impl_GetGroupData( IDirectPlay4 *iface, DPID group,
        void *data, DWORD *size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    lpGroupData gdata;
    DWORD bufsize;
    void *src;
2634

2635
    TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n", This, group, data, size, flags );
2636

2637 2638
    if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
        return DPERR_INVALIDGROUP;
2639

2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650
    /* How much buffer is required? */
    if ( flags & DPSET_LOCAL )
    {
        bufsize = gdata->dwLocalDataSize;
        src = gdata->lpLocalData;
    }
    else
    {
        bufsize = gdata->dwRemoteDataSize;
        src = gdata->lpRemoteData;
    }
2651

2652 2653 2654 2655 2656 2657
    /* Is the user requesting to know how big a buffer is required? */
    if ( !data || *size < bufsize )
    {
        *size = bufsize;
        return DPERR_BUFFERTOOSMALL;
    }
2658

2659
    CopyMemory( data, src, bufsize );
2660

2661
    return DP_OK;
2662 2663
}

2664 2665
static HRESULT DP_IF_GetGroupName( IDirectPlayImpl *This, DPID idGroup, void *lpData,
        DWORD *lpdwDataSize, BOOL bAnsi )
2666
{
2667
  lpGroupData lpGData;
2668
  LPDPNAME    lpName = lpData;
2669 2670
  DWORD       dwRequiredDataSize;

2671
  FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2672
          This, idGroup, lpData, lpdwDataSize, bAnsi );
2673

2674
  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2675 2676 2677 2678
  {
    return DPERR_INVALIDGROUP;
  }

2679
  dwRequiredDataSize = lpGData->name.dwSize;
2680

2681
  if( lpGData->name.u1.lpszShortNameA )
2682
  {
2683
    dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2684 2685
  }

2686
  if( lpGData->name.u2.lpszLongNameA )
2687
  {
2688
    dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2689
  }
2690

2691 2692 2693 2694 2695 2696 2697 2698 2699
  if( ( lpData == NULL ) ||
      ( *lpdwDataSize < dwRequiredDataSize )
    )
  {
    *lpdwDataSize = dwRequiredDataSize;
    return DPERR_BUFFERTOOSMALL;
  }

  /* Copy the structure */
2700
  CopyMemory( lpName, &lpGData->name, lpGData->name.dwSize );
2701

2702
  if( lpGData->name.u1.lpszShortNameA )
2703
  {
2704
    strcpy( ((char*)lpName)+lpGData->name.dwSize,
2705
            lpGData->name.u1.lpszShortNameA );
2706 2707 2708
  }
  else
  {
2709
    lpName->u1.lpszShortNameA = NULL;
2710 2711
  }

2712
  if( lpGData->name.u1.lpszShortNameA )
2713
  {
2714
    strcpy( ((char*)lpName)+lpGData->name.dwSize,
2715
            lpGData->name.u2.lpszLongNameA );
2716 2717 2718
  }
  else
  {
2719
    lpName->u2.lpszLongNameA = NULL;
2720 2721
  }

2722 2723 2724
  return DP_OK;
}

2725 2726 2727 2728 2729 2730 2731
static HRESULT WINAPI IDirectPlay2AImpl_GetGroupName( IDirectPlay2A *iface, DPID group, void *data,
        DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_GetGroupName( &This->IDirectPlay4A_iface, group, data, size );
}

2732 2733 2734 2735 2736 2737 2738
static HRESULT WINAPI IDirectPlay2Impl_GetGroupName( IDirectPlay2 *iface, DPID group, void *data,
        DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_GetGroupName( &This->IDirectPlay4_iface, group, data, size );
}

2739 2740 2741 2742 2743 2744 2745
static HRESULT WINAPI IDirectPlay3AImpl_GetGroupName( IDirectPlay3A *iface, DPID group, void *data,
        DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_GetGroupName( &This->IDirectPlay4_iface, group, data, size );
}

2746 2747 2748 2749 2750 2751 2752
static HRESULT WINAPI IDirectPlay3Impl_GetGroupName( IDirectPlay3 *iface, DPID group, void *data,
        DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_GetGroupName( &This->IDirectPlay4_iface, group, data, size );
}

2753 2754
static HRESULT WINAPI IDirectPlay4AImpl_GetGroupName( IDirectPlay4A *iface, DPID idGroup,
        void *lpData, DWORD *lpdwDataSize )
2755
{
2756 2757
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
2758 2759
}

2760 2761
static HRESULT WINAPI IDirectPlay4Impl_GetGroupName( IDirectPlay4 *iface, DPID idGroup,
        void *lpData, DWORD *lpdwDataSize )
2762
{
2763 2764
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2765 2766
}

2767 2768 2769 2770 2771 2772 2773
static HRESULT WINAPI IDirectPlay2AImpl_GetMessageCount( IDirectPlay2A *iface, DPID player,
        DWORD *count )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_GetMessageCount( &This->IDirectPlay4A_iface, player, count );
}

2774 2775 2776 2777 2778 2779 2780
static HRESULT WINAPI IDirectPlay2Impl_GetMessageCount( IDirectPlay2 *iface, DPID player,
        DWORD *count )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_GetMessageCount( &This->IDirectPlay4_iface, player, count );
}

2781 2782 2783 2784 2785 2786 2787
static HRESULT WINAPI IDirectPlay3AImpl_GetMessageCount( IDirectPlay3A *iface, DPID player,
        DWORD *count )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_GetMessageCount( &This->IDirectPlay4_iface, player, count );
}

2788 2789 2790 2791 2792 2793 2794
static HRESULT WINAPI IDirectPlay3Impl_GetMessageCount( IDirectPlay3 *iface, DPID player,
        DWORD *count )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_GetMessageCount( &This->IDirectPlay4_iface, player, count );
}

2795 2796
static HRESULT WINAPI IDirectPlay4AImpl_GetMessageCount( IDirectPlay4A *iface, DPID player,
        DWORD *count )
2797
{
2798
    return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
2799 2800
}

2801 2802
static HRESULT WINAPI IDirectPlay4Impl_GetMessageCount( IDirectPlay4 *iface, DPID player,
        DWORD *count )
2803
{
2804
    return IDirectPlayX_GetMessageQueue( iface, 0, player, DPMESSAGEQUEUE_RECEIVE, count, NULL );
2805 2806
}

2807 2808 2809 2810 2811 2812 2813
static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerAddress( IDirectPlay2A *iface, DPID player,
        void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4A_iface, player, data, size );
}

2814 2815 2816 2817 2818 2819 2820
static HRESULT WINAPI IDirectPlay2Impl_GetPlayerAddress( IDirectPlay2 *iface, DPID player,
        void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4_iface, player, data, size );
}

2821 2822 2823 2824 2825 2826 2827
static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerAddress( IDirectPlay3A *iface, DPID player,
        void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4_iface, player, data, size );
}

2828 2829 2830 2831 2832 2833 2834
static HRESULT WINAPI IDirectPlay3Impl_GetPlayerAddress( IDirectPlay3 *iface, DPID player,
        void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_GetPlayerAddress( &This->IDirectPlay4_iface, player, data, size );
}

2835 2836
static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAddress( IDirectPlay4A *iface, DPID player,
        void *data, DWORD *size )
2837
{
2838
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
2839 2840
    FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
    return DP_OK;
2841 2842
}

2843 2844
static HRESULT WINAPI IDirectPlay4Impl_GetPlayerAddress( IDirectPlay4 *iface, DPID player,
        void *data, DWORD *size )
2845
{
2846 2847 2848
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    FIXME( "(%p)->(0x%08x,%p,%p): stub\n", This, player, data, size );
    return DP_OK;
2849 2850
}

2851 2852 2853 2854 2855 2856 2857
static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerCaps( IDirectPlay2A *iface, DPID player,
        DPCAPS *caps, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4A_iface, player, caps, flags );
}

2858 2859 2860 2861 2862 2863 2864
static HRESULT WINAPI IDirectPlay2Impl_GetPlayerCaps( IDirectPlay2 *iface, DPID player,
        DPCAPS *caps, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
}

2865 2866 2867 2868 2869 2870 2871
static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerCaps( IDirectPlay3A *iface, DPID player,
        DPCAPS *caps, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
}

2872 2873 2874 2875 2876 2877 2878
static HRESULT WINAPI IDirectPlay3Impl_GetPlayerCaps( IDirectPlay3 *iface, DPID player,
        DPCAPS *caps, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
}

2879 2880
static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerCaps( IDirectPlay4A *iface, DPID player,
        DPCAPS *caps, DWORD flags )
2881
{
2882 2883
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_GetPlayerCaps( &This->IDirectPlay4_iface, player, caps, flags );
2884 2885
}

2886 2887
static HRESULT WINAPI IDirectPlay4Impl_GetPlayerCaps( IDirectPlay4 *iface, DPID player,
        DPCAPS *caps, DWORD flags )
2888
{
2889 2890 2891 2892 2893
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    DPSP_GETCAPSDATA data;

    TRACE( "(%p)->(0x%08x,%p,0x%08x)\n", This, player, caps, flags);

2894 2895 2896
    if ( !caps )
        return DPERR_INVALIDPARAMS;

2897 2898 2899
    if ( This->dp2->connectionInitialized == NO_PROVIDER )
        return DPERR_UNINITIALIZED;

2900 2901 2902
    if( caps->dwSize != sizeof(DPCAPS) )
        return DPERR_INVALIDPARAMS;

2903 2904 2905 2906 2907 2908 2909
    /* Query the service provider */
    data.idPlayer = player;
    data.dwFlags = flags;
    data.lpCaps = caps;
    data.lpISP = This->dp2->spData.lpISP;

    return (*This->dp2->spData.lpCB->GetCaps)( &data );
2910 2911
}

2912 2913 2914 2915 2916 2917 2918
static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerData( IDirectPlay2A *iface, DPID player,
        void *data, DWORD *size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_GetPlayerData( &This->IDirectPlay4A_iface, player, data, size, flags );
}

2919 2920 2921 2922 2923 2924 2925
static HRESULT WINAPI IDirectPlay2Impl_GetPlayerData( IDirectPlay2 *iface, DPID player,
        void *data, DWORD *size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
}

2926 2927 2928 2929 2930 2931 2932
static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerData( IDirectPlay3A *iface, DPID player,
        void *data, DWORD *size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
}

2933 2934 2935 2936 2937 2938 2939
static HRESULT WINAPI IDirectPlay3Impl_GetPlayerData( IDirectPlay3 *iface, DPID player,
        void *data, DWORD *size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
}

2940 2941
static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerData( IDirectPlay4A *iface, DPID player,
        void *data, DWORD *size, DWORD flags )
2942
{
2943 2944 2945
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_GetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
}
2946

2947 2948 2949 2950 2951 2952 2953
static HRESULT WINAPI IDirectPlay4Impl_GetPlayerData( IDirectPlay4 *iface, DPID player,
        void *data, DWORD *size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    lpPlayerList plist;
    DWORD bufsize;
    void *src;
2954

2955
    TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n", This, player, data, size, flags );
2956

2957 2958
    if ( This->dp2->connectionInitialized == NO_PROVIDER )
        return DPERR_UNINITIALIZED;
2959

2960 2961
    if ( ( plist = DP_FindPlayer( This, player ) ) == NULL )
        return DPERR_INVALIDPLAYER;
2962

2963 2964 2965 2966 2967 2968 2969 2970 2971 2972
    if ( flags & DPSET_LOCAL )
    {
        bufsize = plist->lpPData->dwLocalDataSize;
        src = plist->lpPData->lpLocalData;
    }
    else
    {
        bufsize = plist->lpPData->dwRemoteDataSize;
        src = plist->lpPData->lpRemoteData;
    }
2973

2974 2975 2976 2977 2978 2979
    /* Is the user requesting to know how big a buffer is required? */
    if ( !data || *size < bufsize )
    {
        *size = bufsize;
        return DPERR_BUFFERTOOSMALL;
    }
2980

2981
    CopyMemory( data, src, bufsize );
2982

2983
    return DP_OK;
2984 2985
}

2986 2987
static HRESULT DP_IF_GetPlayerName( IDirectPlayImpl *This, DPID idPlayer, void *lpData,
        DWORD *lpdwDataSize, BOOL bAnsi )
2988
{
2989
  lpPlayerList lpPList;
2990
  LPDPNAME    lpName = lpData;
2991 2992
  DWORD       dwRequiredDataSize;

2993
  FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2994
         This, idPlayer, lpData, lpdwDataSize, bAnsi );
2995

2996 2997 2998 2999 3000
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

3001 3002 3003 3004 3005 3006 3007
  if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
  {
    return DPERR_INVALIDPLAYER;
  }

  dwRequiredDataSize = lpPList->lpPData->name.dwSize;

3008
  if( lpPList->lpPData->name.u1.lpszShortNameA )
3009
  {
3010
    dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
3011 3012
  }

3013
  if( lpPList->lpPData->name.u2.lpszLongNameA )
3014
  {
3015
    dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026
  }

  if( ( lpData == NULL ) ||
      ( *lpdwDataSize < dwRequiredDataSize )
    )
  {
    *lpdwDataSize = dwRequiredDataSize;
    return DPERR_BUFFERTOOSMALL;
  }

  /* Copy the structure */
3027
  CopyMemory( lpName, &lpPList->lpPData->name, lpPList->lpPData->name.dwSize );
3028

3029
  if( lpPList->lpPData->name.u1.lpszShortNameA )
3030
  {
3031
    strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
3032
            lpPList->lpPData->name.u1.lpszShortNameA );
3033 3034 3035
  }
  else
  {
3036
    lpName->u1.lpszShortNameA = NULL;
3037 3038
  }

3039
  if( lpPList->lpPData->name.u1.lpszShortNameA )
3040
  {
3041
    strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
3042
            lpPList->lpPData->name.u2.lpszLongNameA );
3043 3044 3045
  }
  else
  {
3046
    lpName->u2.lpszLongNameA = NULL;
3047 3048
  }

3049 3050 3051
  return DP_OK;
}

3052 3053 3054 3055 3056 3057 3058
static HRESULT WINAPI IDirectPlay2AImpl_GetPlayerName( IDirectPlay2A *iface, DPID player,
        void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_GetPlayerName( &This->IDirectPlay4A_iface, player, data, size );
}

3059 3060 3061 3062 3063 3064 3065
static HRESULT WINAPI IDirectPlay2Impl_GetPlayerName( IDirectPlay2 *iface, DPID player,
        void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_GetPlayerName( &This->IDirectPlay4_iface, player, data, size );
}

3066 3067 3068 3069 3070 3071 3072
static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerName( IDirectPlay3A *iface, DPID player,
        void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_GetPlayerName( &This->IDirectPlay4_iface, player, data, size );
}

3073 3074 3075 3076 3077 3078 3079
static HRESULT WINAPI IDirectPlay3Impl_GetPlayerName( IDirectPlay3 *iface, DPID player,
        void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_GetPlayerName( &This->IDirectPlay4_iface, player, data, size );
}

3080 3081
static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
        void *lpData, DWORD *lpdwDataSize )
3082
{
3083 3084
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
3085 3086
}

3087 3088
static HRESULT WINAPI IDirectPlay4Impl_GetPlayerName( IDirectPlay4 *iface, DPID idPlayer,
        void *lpData, DWORD *lpdwDataSize )
3089
{
3090 3091
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
3092 3093
}

3094 3095
static HRESULT DP_GetSessionDesc( IDirectPlayImpl *This, void *lpData, DWORD *lpdwDataSize,
        BOOL bAnsi )
3096 3097 3098 3099 3100
{
  DWORD dwRequiredSize;

  TRACE( "(%p)->(%p,%p,%u)\n", This, lpData, lpdwDataSize, bAnsi );

3101 3102 3103 3104 3105
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

3106
  if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120
  {
    return DPERR_INVALIDPARAMS;
  }

  /* FIXME: Get from This->dp2->lpSessionDesc */
  dwRequiredSize = DP_CalcSessionDescSize( This->dp2->lpSessionDesc, bAnsi );

  if ( ( lpData == NULL ) ||
       ( *lpdwDataSize < dwRequiredSize )
     )
  {
    *lpdwDataSize = dwRequiredSize;
    return DPERR_BUFFERTOOSMALL;
  }
3121

3122 3123
  DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );

3124
  return DP_OK;
3125 3126
}

3127 3128 3129 3130 3131 3132 3133
static HRESULT WINAPI IDirectPlay2AImpl_GetSessionDesc( IDirectPlay2A *iface, void *data,
        DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4A_iface, data, size );
}

3134 3135 3136 3137 3138 3139 3140
static HRESULT WINAPI IDirectPlay2Impl_GetSessionDesc( IDirectPlay2 *iface, void *data,
        DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4_iface, data, size );
}

3141 3142 3143 3144 3145 3146 3147
static HRESULT WINAPI IDirectPlay3AImpl_GetSessionDesc( IDirectPlay3A *iface, void *data,
        DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4_iface, data, size );
}

3148 3149 3150 3151 3152 3153 3154
static HRESULT WINAPI IDirectPlay3Impl_GetSessionDesc( IDirectPlay3 *iface, void *data,
        DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_GetSessionDesc( &This->IDirectPlay4_iface, data, size );
}

3155 3156
static HRESULT WINAPI IDirectPlay4AImpl_GetSessionDesc( IDirectPlay4A *iface, void *lpData,
        DWORD *lpdwDataSize )
3157
{
3158 3159
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
3160 3161
}

3162 3163
static HRESULT WINAPI IDirectPlay4Impl_GetSessionDesc( IDirectPlay4 *iface, void *lpData,
        DWORD *lpdwDataSize )
3164
{
3165 3166
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
3167 3168
}

3169 3170 3171 3172 3173 3174
static HRESULT WINAPI IDirectPlay2AImpl_Initialize( IDirectPlay2A *iface, GUID *guid )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_Initialize( &This->IDirectPlay4A_iface, guid );
}

3175 3176 3177 3178 3179 3180
static HRESULT WINAPI IDirectPlay2Impl_Initialize( IDirectPlay2 *iface, GUID *guid )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_Initialize( &This->IDirectPlay4_iface, guid );
}

3181 3182 3183 3184 3185 3186
static HRESULT WINAPI IDirectPlay3AImpl_Initialize( IDirectPlay3A *iface, GUID *guid )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_Initialize( &This->IDirectPlay4_iface, guid );
}

3187 3188 3189 3190 3191 3192
static HRESULT WINAPI IDirectPlay3Impl_Initialize( IDirectPlay3 *iface, GUID *guid )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_Initialize( &This->IDirectPlay4_iface, guid );
}

3193
/* Intended only for COM compatibility. Always returns an error. */
3194
static HRESULT WINAPI IDirectPlay4AImpl_Initialize( IDirectPlay4A *iface, GUID *guid )
3195
{
3196
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
3197 3198
    TRACE("(%p)->(%p): no-op\n", This, guid );
    return DPERR_ALREADYINITIALIZED;
3199 3200
}

3201
static HRESULT WINAPI IDirectPlay4Impl_Initialize( IDirectPlay4 *iface, GUID *guid )
3202
{
3203 3204 3205
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    TRACE( "(%p)->(%p): no-op\n", This, guid );
    return DPERR_ALREADYINITIALIZED;
3206 3207 3208
}


3209 3210
static HRESULT DP_SecureOpen( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpsd, DWORD dwFlags,
        const DPSECURITYDESC *lpSecurity, const DPCREDENTIALS *lpCredentials, BOOL bAnsi )
3211
{
3212 3213
  HRESULT hr = DP_OK;

3214
  FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
3215
         This, lpsd, dwFlags, lpSecurity, lpCredentials );
3216

Ismael Barros's avatar
Ismael Barros committed
3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

  if( lpsd->dwSize != sizeof(DPSESSIONDESC2) )
  {
    TRACE( ": rejecting invalid dpsd size (%d).\n", lpsd->dwSize );
    return DPERR_INVALIDPARAMS;
  }

3228 3229 3230 3231 3232 3233
  if( This->dp2->bConnectionOpen )
  {
    TRACE( ": rejecting already open connection.\n" );
    return DPERR_ALREADYINITIALIZED;
  }

3234 3235
  /* If we're enumerating, kill the thread */
  DP_KillEnumSessionThread( This );
3236 3237 3238 3239 3240

  if( dwFlags & DPOPEN_CREATE )
  {
    /* Rightoo - this computer is the host and the local computer needs to be
       the name server so that others can join this session */
3241
    NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
3242

3243
    This->dp2->bHostInterface = TRUE;
3244 3245 3246 3247

    hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
    if( FAILED( hr ) )
    {
3248
      ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
3249 3250
      return hr;
    }
3251 3252
  }

3253 3254 3255 3256 3257 3258 3259
  /* Invoke the conditional callback for the service provider */
  if( This->dp2->spData.lpCB->Open )
  {
    DPSP_OPENDATA data;

    FIXME( "Not all data fields are correct. Need new parameter\n" );

3260
    data.bCreate           = (dwFlags & DPOPEN_CREATE ) != 0;
3261
    data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
3262 3263
                                                        : NS_GetNSAddr( This->dp2->lpNameServerData );
    data.lpISP             = This->dp2->spData.lpISP;
3264
    data.bReturnStatus     = (dwFlags & DPOPEN_RETURNSTATUS) != 0;
3265 3266 3267
    data.dwOpenFlags       = dwFlags;
    data.dwSessionFlags    = This->dp2->lpSessionDesc->dwFlags;

Peter Hunnisett's avatar
Peter Hunnisett committed
3268 3269 3270
    hr = (*This->dp2->spData.lpCB->Open)(&data);
    if( FAILED( hr ) )
    {
3271
      ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
Peter Hunnisett's avatar
Peter Hunnisett committed
3272 3273
      return hr;
    }
3274
  }
Peter Hunnisett's avatar
Peter Hunnisett committed
3275

3276
  {
Peter Hunnisett's avatar
Peter Hunnisett committed
3277
    /* Create the system group of which everything is a part of */
3278 3279 3280 3281
    DPID systemGroup = DPID_SYSTEM_GROUP;

    hr = DP_IF_CreateGroup( This, NULL, &systemGroup, NULL,
                            NULL, 0, 0, TRUE );
3282

3283 3284
  }

3285 3286
  if( dwFlags & DPOPEN_JOIN )
  {
3287
    DPID dpidServerId = DPID_UNKNOWN;
3288

3289 3290 3291
    /* Create the server player for this interface. This way we can receive
     * messages for this session.
     */
3292
    /* FIXME: I suppose that we should be setting an event for a receive
3293 3294 3295 3296
     *        type of thing. That way the messaging thread could know to wake
     *        up. DPlay would then trigger the hEvent for the player the
     *        message is directed to.
     */
3297 3298
    hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
                             0,
Peter Hunnisett's avatar
Peter Hunnisett committed
3299
                             DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
3300

3301 3302 3303 3304 3305 3306 3307 3308 3309
  }
  else if( dwFlags & DPOPEN_CREATE )
  {
    DPID dpidNameServerId = DPID_NAME_SERVER;

    hr = DP_IF_CreatePlayer( This, NULL, &dpidNameServerId, NULL, 0, NULL,
                             0, DPPLAYER_SERVERPLAYER, bAnsi );
  }

3310 3311 3312 3313 3314 3315
  if( FAILED(hr) )
  {
    ERR( "Couldn't create name server/system player: %s\n",
         DPLAYX_HresultToString(hr) );
  }

3316
  return hr;
3317 3318
}

3319 3320 3321 3322 3323 3324 3325
static HRESULT WINAPI IDirectPlay2AImpl_Open( IDirectPlay2A *iface, DPSESSIONDESC2 *sdesc,
        DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_Open( &This->IDirectPlay4A_iface, sdesc, flags );
}

3326 3327 3328 3329 3330 3331 3332
static HRESULT WINAPI IDirectPlay2Impl_Open( IDirectPlay2 *iface, DPSESSIONDESC2 *sdesc,
        DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_Open( &This->IDirectPlay4_iface, sdesc, flags );
}

3333 3334 3335 3336 3337 3338 3339
static HRESULT WINAPI IDirectPlay3AImpl_Open( IDirectPlay3A *iface, DPSESSIONDESC2 *sdesc,
        DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_Open( &This->IDirectPlay4_iface, sdesc, flags );
}

3340 3341 3342 3343 3344 3345 3346
static HRESULT WINAPI IDirectPlay3Impl_Open( IDirectPlay3 *iface, DPSESSIONDESC2 *sdesc,
        DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_Open( &This->IDirectPlay4_iface, sdesc, flags );
}

3347 3348
static HRESULT WINAPI IDirectPlay4AImpl_Open( IDirectPlay4A *iface, DPSESSIONDESC2 *sdesc,
        DWORD flags )
3349
{
3350
    return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
3351 3352
}

3353 3354
static HRESULT WINAPI IDirectPlay4Impl_Open( IDirectPlay4 *iface, DPSESSIONDESC2 *sdesc,
        DWORD flags )
3355
{
3356
    return IDirectPlayX_SecureOpen( iface, sdesc, flags, NULL, NULL );
3357 3358
}

3359 3360
static HRESULT DP_IF_Receive( IDirectPlayImpl *This, DPID *lpidFrom, DPID *lpidTo, DWORD dwFlags,
        void *lpData, DWORD *lpdwDataSize, BOOL bAnsi )
3361 3362 3363
{
  LPDPMSG lpMsg = NULL;

3364
  FIXME( "(%p)->(%p,%p,0x%08x,%p,%p,%u): stub\n",
3365 3366
         This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, bAnsi );

3367 3368 3369 3370 3371
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391
  if( dwFlags == 0 )
  {
    dwFlags = DPRECEIVE_ALL;
  }

  /* If the lpData is NULL, we must be peeking the message */
  if(  ( lpData == NULL ) &&
      !( dwFlags & DPRECEIVE_PEEK )
    )
  {
    return DPERR_INVALIDPARAMS;
  }

  if( dwFlags & DPRECEIVE_ALL )
  {
    lpMsg = This->dp2->receiveMsgs.lpQHFirst;

    if( !( dwFlags & DPRECEIVE_PEEK ) )
    {
      FIXME( "Remove from queue\n" );
3392
    }
3393 3394 3395 3396 3397
  }
  else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
           ( dwFlags & DPRECEIVE_FROMPLAYER )
         )
  {
3398
    FIXME( "Find matching message 0x%08x\n", dwFlags );
3399 3400 3401
  }
  else
  {
3402
    ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
3403 3404 3405 3406 3407 3408 3409 3410
  }

  if( lpMsg == NULL )
  {
    return DPERR_NOMESSAGES;
  }

  /* Copy into the provided buffer */
3411
  if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
3412 3413

  return DP_OK;
3414 3415
}

3416 3417 3418 3419 3420 3421 3422
static HRESULT WINAPI IDirectPlay2AImpl_Receive( IDirectPlay2A *iface, DPID *from, DPID *to,
        DWORD flags, void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_Receive( &This->IDirectPlay4A_iface, from, to, flags, data, size );
}

3423 3424 3425 3426 3427 3428 3429
static HRESULT WINAPI IDirectPlay2Impl_Receive( IDirectPlay2 *iface, DPID *from, DPID *to,
        DWORD flags, void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_Receive( &This->IDirectPlay4_iface, from, to, flags, data, size );
}

3430 3431 3432 3433 3434 3435 3436
static HRESULT WINAPI IDirectPlay3AImpl_Receive( IDirectPlay3A *iface, DPID *from, DPID *to,
        DWORD flags, void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_Receive( &This->IDirectPlay4_iface, from, to, flags, data, size );
}

3437 3438 3439 3440 3441 3442 3443
static HRESULT WINAPI IDirectPlay3Impl_Receive( IDirectPlay3 *iface, DPID *from, DPID *to,
        DWORD flags, void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_Receive( &This->IDirectPlay4_iface, from, to, flags, data, size );
}

3444 3445
static HRESULT WINAPI IDirectPlay4AImpl_Receive( IDirectPlay4A *iface, DPID *lpidFrom,
        DPID *lpidTo, DWORD dwFlags, void *lpData, DWORD *lpdwDataSize )
3446
{
3447 3448
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, TRUE );
3449 3450
}

3451 3452
static HRESULT WINAPI IDirectPlay4Impl_Receive( IDirectPlay4 *iface, DPID *lpidFrom,
        DPID *lpidTo, DWORD dwFlags, void *lpData, DWORD *lpdwDataSize )
3453
{
3454 3455
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags, lpData, lpdwDataSize, FALSE );
3456 3457
}

3458 3459 3460 3461 3462 3463 3464
static HRESULT WINAPI IDirectPlay2AImpl_Send( IDirectPlay2A *iface, DPID from, DPID to,
        DWORD flags, void *data, DWORD size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_Send( &This->IDirectPlay4A_iface, from, to, flags, data, size );
}

3465 3466 3467 3468 3469 3470 3471
static HRESULT WINAPI IDirectPlay2Impl_Send( IDirectPlay2 *iface, DPID from, DPID to,
        DWORD flags, void *data, DWORD size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_Send( &This->IDirectPlay4_iface, from, to, flags, data, size );
}

3472 3473 3474 3475 3476 3477 3478
static HRESULT WINAPI IDirectPlay3AImpl_Send( IDirectPlay3A *iface, DPID from, DPID to,
        DWORD flags, void *data, DWORD size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_Send( &This->IDirectPlay4_iface, from, to, flags, data, size );
}

3479 3480 3481 3482 3483 3484 3485
static HRESULT WINAPI IDirectPlay3Impl_Send( IDirectPlay3 *iface, DPID from, DPID to,
        DWORD flags, void *data, DWORD size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_Send( &This->IDirectPlay4_iface, from, to, flags, data, size );
}

3486 3487
static HRESULT WINAPI IDirectPlay4AImpl_Send( IDirectPlay4A *iface, DPID from, DPID to,
        DWORD flags, void *data, DWORD size )
3488
{
3489
    return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
3490 3491
}

3492 3493
static HRESULT WINAPI IDirectPlay4Impl_Send( IDirectPlay4 *iface, DPID from, DPID to,
        DWORD flags, void *data, DWORD size )
3494
{
3495
    return IDirectPlayX_SendEx( iface, from, to, flags, data, size, 0, 0, NULL, NULL );
3496 3497
}

3498 3499 3500 3501 3502 3503 3504
static HRESULT WINAPI IDirectPlay2AImpl_SetGroupData( IDirectPlay2A *iface, DPID group, void *data,
        DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_SetGroupData( &This->IDirectPlay4A_iface, group, data, size, flags );
}

3505 3506 3507 3508 3509 3510 3511
static HRESULT WINAPI IDirectPlay2Impl_SetGroupData( IDirectPlay2 *iface, DPID group, void *data,
        DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
}

3512 3513 3514 3515 3516 3517 3518
static HRESULT WINAPI IDirectPlay3AImpl_SetGroupData( IDirectPlay3A *iface, DPID group, void *data,
        DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
}

3519 3520 3521 3522 3523 3524 3525
static HRESULT WINAPI IDirectPlay3Impl_SetGroupData( IDirectPlay3 *iface, DPID group, void *data,
        DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
}

3526 3527
static HRESULT WINAPI IDirectPlay4AImpl_SetGroupData( IDirectPlay4A *iface, DPID group, void *data,
        DWORD size, DWORD flags )
3528
{
3529 3530 3531
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_SetGroupData( &This->IDirectPlay4_iface, group, data, size, flags );
}
3532

3533 3534 3535 3536 3537
static HRESULT WINAPI IDirectPlay4Impl_SetGroupData( IDirectPlay4 *iface, DPID group, void *data,
        DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    lpGroupData gdata;
3538

3539
    TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n", This, group, data, size, flags );
3540

3541 3542 3543
    /* Parameter check */
    if ( !data && size )
        return DPERR_INVALIDPARAMS;
3544

3545 3546 3547
    /* Find the pointer to the data for this player */
    if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
        return DPERR_INVALIDOBJECT;
3548

3549 3550 3551 3552 3553 3554 3555
    if ( !(flags & DPSET_LOCAL) )
    {
        FIXME( "Was this group created by this interface?\n" );
        /* FIXME: If this is a remote update need to allow it but not
         *        send a message.
         */
    }
3556

3557
    DP_SetGroupData( gdata, flags, data, size );
3558

3559 3560 3561 3562 3563
    /* FIXME: Only send a message if this group is local to the session otherwise
     * it will have been rejected above
     */
    if ( !(flags & DPSET_LOCAL) )
        FIXME( "Send msg?\n" );
3564

3565
    return DP_OK;
3566 3567
}

3568 3569
static HRESULT DP_IF_SetGroupName( IDirectPlayImpl *This, DPID idGroup, DPNAME *lpGroupName,
        DWORD dwFlags, BOOL bAnsi )
3570
{
3571
  lpGroupData lpGData;
3572

3573
  TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
3574
         lpGroupName, dwFlags, bAnsi );
3575

3576
  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3577 3578 3579 3580
  {
    return DPERR_INVALIDGROUP;
  }

3581
  DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3582 3583 3584 3585

  /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
  FIXME( "Message not sent and dwFlags ignored\n" );

3586 3587 3588
  return DP_OK;
}

3589 3590 3591 3592 3593 3594 3595
static HRESULT WINAPI IDirectPlay2AImpl_SetGroupName( IDirectPlay2A *iface, DPID group,
        DPNAME *name, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_SetGroupName( &This->IDirectPlay4A_iface, group, name, flags );
}

3596 3597 3598 3599 3600 3601 3602
static HRESULT WINAPI IDirectPlay2Impl_SetGroupName( IDirectPlay2 *iface, DPID group,
        DPNAME *name, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_SetGroupName( &This->IDirectPlay4_iface, group, name, flags );
}

3603 3604 3605 3606 3607 3608 3609
static HRESULT WINAPI IDirectPlay3AImpl_SetGroupName( IDirectPlay3A *iface, DPID group,
        DPNAME *name, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_SetGroupName( &This->IDirectPlay4_iface, group, name, flags );
}

3610 3611 3612 3613 3614 3615 3616
static HRESULT WINAPI IDirectPlay3Impl_SetGroupName( IDirectPlay3 *iface, DPID group,
        DPNAME *name, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_SetGroupName( &This->IDirectPlay4_iface, group, name, flags );
}

3617 3618
static HRESULT WINAPI IDirectPlay4AImpl_SetGroupName( IDirectPlay4A *iface, DPID idGroup,
        DPNAME *lpGroupName, DWORD dwFlags )
3619
{
3620 3621
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
3622 3623
}

3624 3625
static HRESULT WINAPI IDirectPlay4Impl_SetGroupName( IDirectPlay4 *iface, DPID idGroup,
        DPNAME *lpGroupName, DWORD dwFlags )
3626
{
3627 3628
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3629 3630
}

3631 3632 3633 3634 3635 3636 3637
static HRESULT WINAPI IDirectPlay2AImpl_SetPlayerData( IDirectPlay2A *iface, DPID player,
        void *data, DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_SetPlayerData( &This->IDirectPlay4A_iface, player, data, size, flags );
}

3638 3639 3640 3641 3642 3643 3644
static HRESULT WINAPI IDirectPlay2Impl_SetPlayerData( IDirectPlay2 *iface, DPID player,
        void *data, DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
}

3645 3646 3647 3648 3649 3650 3651
static HRESULT WINAPI IDirectPlay3AImpl_SetPlayerData( IDirectPlay3A *iface, DPID player,
        void *data, DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
}

3652 3653 3654 3655 3656 3657 3658
static HRESULT WINAPI IDirectPlay3Impl_SetPlayerData( IDirectPlay3 *iface, DPID player,
        void *data, DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
}

3659 3660
static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerData( IDirectPlay4A *iface, DPID player,
        void *data, DWORD size, DWORD flags )
3661
{
3662 3663 3664
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_SetPlayerData( &This->IDirectPlay4_iface, player, data, size, flags );
}
3665

3666 3667 3668 3669 3670
static HRESULT WINAPI IDirectPlay4Impl_SetPlayerData( IDirectPlay4 *iface, DPID player,
        void *data, DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    lpPlayerList plist;
3671

3672
    TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n", This, player, data, size, flags );
3673

3674 3675
    if ( This->dp2->connectionInitialized == NO_PROVIDER )
        return DPERR_UNINITIALIZED;
3676

3677 3678 3679
    /* Parameter check */
    if ( !data && size )
        return DPERR_INVALIDPARAMS;
3680

3681 3682 3683
    /* Find the pointer to the data for this player */
    if ( (plist = DP_FindPlayer( This, player )) == NULL )
        return DPERR_INVALIDPLAYER;
3684

3685 3686 3687 3688 3689 3690 3691
    if ( !(flags & DPSET_LOCAL) )
    {
        FIXME( "Was this group created by this interface?\n" );
        /* FIXME: If this is a remote update need to allow it but not
         *        send a message.
         */
    }
3692

3693
    DP_SetPlayerData( plist->lpPData, flags, data, size );
3694

3695 3696
    if ( !(flags & DPSET_LOCAL) )
        FIXME( "Send msg?\n" );
3697

3698
    return DP_OK;
3699 3700
}

3701 3702
static HRESULT DP_IF_SetPlayerName( IDirectPlayImpl *This, DPID idPlayer, DPNAME *lpPlayerName,
        DWORD dwFlags, BOOL bAnsi )
3703
{
3704
  lpPlayerList lpPList;
3705

3706
  TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
3707
         This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3708

3709 3710 3711 3712 3713
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

3714 3715 3716 3717 3718
  if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
  {
    return DPERR_INVALIDGROUP;
  }

3719
  DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3720 3721 3722

  /* Should send a DPMSG_SETPLAYERORGROUPNAME message */
  FIXME( "Message not sent and dwFlags ignored\n" );
3723

3724 3725 3726
  return DP_OK;
}

3727 3728 3729 3730 3731 3732 3733
static HRESULT WINAPI IDirectPlay2AImpl_SetPlayerName( IDirectPlay2A *iface, DPID player,
        DPNAME *name, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_SetPlayerName( &This->IDirectPlay4A_iface, player, name, flags );
}

3734 3735 3736 3737 3738 3739 3740
static HRESULT WINAPI IDirectPlay2Impl_SetPlayerName( IDirectPlay2 *iface, DPID player,
        DPNAME *name, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_SetPlayerName( &This->IDirectPlay4_iface, player, name, flags );
}

3741 3742 3743 3744 3745 3746 3747
static HRESULT WINAPI IDirectPlay3AImpl_SetPlayerName( IDirectPlay3A *iface, DPID player,
        DPNAME *name, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_SetPlayerName( &This->IDirectPlay4_iface, player, name, flags );
}

3748 3749 3750 3751 3752 3753 3754
static HRESULT WINAPI IDirectPlay3Impl_SetPlayerName( IDirectPlay3 *iface, DPID player,
        DPNAME *name, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_SetPlayerName( &This->IDirectPlay4_iface, player, name, flags );
}

3755 3756
static HRESULT WINAPI IDirectPlay4AImpl_SetPlayerName( IDirectPlay4A *iface, DPID idPlayer,
        DPNAME *lpPlayerName, DWORD dwFlags )
3757
{
3758 3759
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
3760 3761
}

3762 3763
static HRESULT WINAPI IDirectPlay4Impl_SetPlayerName( IDirectPlay4 *iface, DPID idPlayer,
        DPNAME *lpPlayerName, DWORD dwFlags )
3764
{
3765 3766
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3767 3768
}

3769 3770
static HRESULT DP_SetSessionDesc( IDirectPlayImpl *This, const DPSESSIONDESC2 *lpSessDesc,
        DWORD dwFlags, BOOL bInitial, BOOL bAnsi  )
3771 3772 3773 3774
{
  DWORD            dwRequiredSize;
  LPDPSESSIONDESC2 lpTempSessDesc;

3775
  TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
3776 3777
         This, lpSessDesc, dwFlags, bInitial, bAnsi );

3778 3779 3780 3781 3782
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795
  if( dwFlags )
  {
    return DPERR_INVALIDPARAMS;
  }

  /* Only the host is allowed to update the session desc */
  if( !This->dp2->bHostInterface )
  {
    return DPERR_ACCESSDENIED;
  }

  /* FIXME: Copy into This->dp2->lpSessionDesc */
  dwRequiredSize = DP_CalcSessionDescSize( lpSessDesc, bAnsi );
3796
  lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3797 3798 3799 3800 3801 3802 3803 3804 3805 3806

  if( lpTempSessDesc == NULL )
  {
    return DPERR_OUTOFMEMORY;
  }

  /* Free the old */
  HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );

  This->dp2->lpSessionDesc = lpTempSessDesc;
3807 3808
  /* Set the new */
  DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3809 3810 3811 3812 3813
  if( bInitial )
  {
    /*Initializing session GUID*/
    CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
  }
3814
  /* If this is an external invocation of the interface, we should be
3815 3816 3817 3818 3819
   * letting everyone know that things have changed. Otherwise this is
   * just an initialization and it doesn't need to be propagated.
   */
  if( !bInitial )
  {
3820
    FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3821 3822 3823 3824 3825
  }

  return DP_OK;
}

3826 3827 3828 3829 3830 3831 3832
static HRESULT WINAPI IDirectPlay2AImpl_SetSessionDesc( IDirectPlay2A *iface, DPSESSIONDESC2 *sdesc,
        DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2A( iface );
    return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4A_iface, sdesc, flags );
}

3833 3834 3835 3836 3837 3838 3839
static HRESULT WINAPI IDirectPlay2Impl_SetSessionDesc( IDirectPlay2 *iface, DPSESSIONDESC2 *sdesc,
        DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay2( iface );
    return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4_iface, sdesc, flags );
}

3840 3841 3842 3843 3844 3845 3846
static HRESULT WINAPI IDirectPlay3AImpl_SetSessionDesc( IDirectPlay3A *iface, DPSESSIONDESC2 *sdesc,
        DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4_iface, sdesc, flags );
}

3847 3848 3849 3850 3851 3852 3853
static HRESULT WINAPI IDirectPlay3Impl_SetSessionDesc( IDirectPlay3 *iface, DPSESSIONDESC2 *sdesc,
        DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_SetSessionDesc( &This->IDirectPlay4_iface, sdesc, flags );
}

3854 3855
static HRESULT WINAPI IDirectPlay4AImpl_SetSessionDesc( IDirectPlay4A *iface,
        DPSESSIONDESC2 *lpSessDesc, DWORD dwFlags )
3856
{
3857 3858
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3859 3860
}

3861 3862
static HRESULT WINAPI IDirectPlay4Impl_SetSessionDesc( IDirectPlay4 *iface,
        DPSESSIONDESC2 *lpSessDesc, DWORD dwFlags )
3863
{
3864 3865
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3866 3867 3868
}

/* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3869
static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883
{
  DWORD dwSize = 0;

  if( lpSessDesc == NULL )
  {
    /* Hmmm..don't need any size? */
    ERR( "NULL lpSessDesc\n" );
    return dwSize;
  }

  dwSize += sizeof( *lpSessDesc );

  if( bAnsi )
  {
3884
    if( lpSessDesc->u1.lpszSessionNameA )
3885
    {
3886
      dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3887 3888
    }

3889
    if( lpSessDesc->u2.lpszPasswordA )
3890
    {
3891
      dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3892 3893 3894 3895
    }
  }
  else /* UNICODE */
  {
3896
    if( lpSessDesc->u1.lpszSessionName )
3897 3898
    {
      dwSize += sizeof( WCHAR ) *
3899
        ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3900 3901
    }

3902
    if( lpSessDesc->u2.lpszPassword )
3903 3904
    {
      dwSize += sizeof( WCHAR ) *
3905
        ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3906 3907 3908 3909 3910 3911
    }
  }

  return dwSize;
}

Austin English's avatar
Austin English committed
3912
/* Assumes that contiguous buffers are already allocated. */
3913
static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929
                                LPCDPSESSIONDESC2 lpSessionSrc, BOOL bAnsi )
{
  BYTE* lpStartOfFreeSpace;

  if( lpSessionDest == NULL )
  {
    ERR( "NULL lpSessionDest\n" );
    return;
  }

  CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );

  lpStartOfFreeSpace = ((BYTE*)lpSessionDest) + sizeof( *lpSessionSrc );

  if( bAnsi )
  {
3930
    if( lpSessionSrc->u1.lpszSessionNameA )
3931
    {
3932
      lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3933 3934
                lpSessionDest->u1.lpszSessionNameA );
      lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3935
      lpStartOfFreeSpace +=
3936
        lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
3937
    }
3938

3939
    if( lpSessionSrc->u2.lpszPasswordA )
3940
    {
3941
      lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3942 3943
                lpSessionDest->u2.lpszPasswordA );
      lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3944
    }
3945 3946 3947
  }
  else /* UNICODE */
  {
3948
    if( lpSessionSrc->u1.lpszSessionName )
3949 3950
    {
      lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3951 3952
                lpSessionDest->u1.lpszSessionName );
      lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3953
      lpStartOfFreeSpace += sizeof(WCHAR) *
3954
        ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3955 3956
    }

3957
    if( lpSessionSrc->u2.lpszPassword )
3958 3959
    {
      lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3960 3961
                lpSessionDest->u2.lpszPassword );
      lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3962
    }
3963
  }
3964 3965
}

3966 3967 3968 3969 3970 3971 3972
static HRESULT WINAPI IDirectPlay3AImpl_AddGroupToGroup( IDirectPlay3A *iface, DPID parent,
        DPID group )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4A_iface, parent, group );
}

3973 3974 3975 3976 3977 3978 3979
static HRESULT WINAPI IDirectPlay3Impl_AddGroupToGroup( IDirectPlay3 *iface, DPID parent,
        DPID group )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4_iface, parent, group );
}

3980 3981
static HRESULT WINAPI IDirectPlay4AImpl_AddGroupToGroup( IDirectPlay4A *iface, DPID parent,
        DPID group )
3982
{
3983 3984 3985
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_AddGroupToGroup( &This->IDirectPlay4_iface, parent, group );
}
3986

3987 3988 3989 3990 3991 3992
static HRESULT WINAPI IDirectPlay4Impl_AddGroupToGroup( IDirectPlay4 *iface, DPID parent,
        DPID group )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    lpGroupData gdata;
    lpGroupList glist;
3993

3994
    TRACE( "(%p)->(0x%08x,0x%08x)\n", This, parent, group );
3995

3996 3997
    if ( This->dp2->connectionInitialized == NO_PROVIDER )
        return DPERR_UNINITIALIZED;
3998

3999 4000
    if ( !DP_FindAnyGroup(This, parent ) )
        return DPERR_INVALIDGROUP;
4001

4002 4003
    if ( ( gdata = DP_FindAnyGroup(This, group ) ) == NULL )
        return DPERR_INVALIDGROUP;
4004

4005 4006 4007 4008
    /* Create a player list (ie "shortcut" ) */
    glist = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *glist ) );
    if ( !glist )
        return DPERR_CANTADDPLAYER;
4009

4010 4011 4012
    /* Add the shortcut */
    gdata->uRef++;
    glist->lpGData = gdata;
4013

4014 4015
    /* Add the player to the list of players for this group */
    DPQ_INSERT( gdata->groups, glist, groups );
4016

4017 4018
    /* Send a ADDGROUPTOGROUP message */
    FIXME( "Not sending message\n" );
4019

4020
    return DP_OK;
4021 4022
}

4023 4024 4025
static HRESULT DP_IF_CreateGroupInGroup( IDirectPlayImpl *This, void *lpMsgHdr, DPID idParentGroup,
        DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags,
        BOOL bAnsi )
4026
{
4027
  lpGroupData lpGParentData;
4028 4029 4030
  lpGroupList lpGList;
  lpGroupData lpGData;

4031
  TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
4032
         This, idParentGroup, lpidGroup, lpGroupName, lpData,
4033
         dwDataSize, dwFlags, bAnsi );
4034

4035 4036 4037 4038 4039
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

4040
  /* Verify that the specified parent is valid */
4041
  if( ( lpGParentData = DP_FindAnyGroup(This, idParentGroup ) ) == NULL )
4042 4043
    return DPERR_INVALIDGROUP;

4044
  lpGData = DP_CreateGroup(This, lpidGroup, lpGroupName, dwFlags, idParentGroup, bAnsi );
4045 4046 4047 4048 4049

  if( lpGData == NULL )
  {
    return DPERR_CANTADDPLAYER; /* yes player not group */
  }
Peter Hunnisett's avatar
Peter Hunnisett committed
4050 4051 4052

  /* Something else is referencing this data */
  lpGData->uRef++;
4053

4054
  DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
4055 4056 4057

  /* The list has now been inserted into the interface group list. We now
     need to put a "shortcut" to this group in the parent group */
4058
  lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
4059 4060 4061 4062 4063 4064
  if( lpGList == NULL )
  {
    FIXME( "Memory leak\n" );
    return DPERR_CANTADDPLAYER; /* yes player not group */
  }

4065
  lpGList->lpGData = lpGData;
4066

4067 4068 4069 4070 4071 4072 4073 4074
  DPQ_INSERT( lpGParentData->groups, lpGList, groups );

  /* Let the SP know that we've created this group */
  if( This->dp2->spData.lpCB->CreateGroup )
  {
    DPSP_CREATEGROUPDATA data;

    TRACE( "Calling SP CreateGroup\n" );
4075

4076 4077 4078 4079 4080
    data.idGroup           = *lpidGroup;
    data.dwFlags           = dwFlags;
    data.lpSPMessageHeader = lpMsgHdr;
    data.lpISP             = This->dp2->spData.lpISP;

Peter Hunnisett's avatar
Peter Hunnisett committed
4081
    (*This->dp2->spData.lpCB->CreateGroup)( &data );
4082 4083
  }

4084 4085
  /* Inform all other peers of the creation of a new group. If there are
   * no peers keep this quiet.
4086
   */
4087
  if( This->dp2->lpSessionDesc &&
4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102
      ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
  {
    DPMSG_CREATEPLAYERORGROUP msg;

    msg.dwType = DPSYS_CREATEPLAYERORGROUP;
    msg.dwPlayerType = DPPLAYERTYPE_GROUP;
    msg.dpId = *lpidGroup;
    msg.dwCurrentPlayers = idParentGroup; /* FIXME: Incorrect? */
    msg.lpData = lpData;
    msg.dwDataSize = dwDataSize;
    msg.dpnName = *lpGroupName;

    /* FIXME: Correct to just use send effectively? */
    /* FIXME: Should size include data w/ message or just message "header" */
    /* FIXME: Check return code */
4103 4104
    IDirectPlayX_SendEx( &This->IDirectPlay4_iface, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
            sizeof( msg ), 0, 0, NULL, NULL );
4105
  }
4106 4107

  return DP_OK;
4108
}
4109

4110 4111 4112 4113 4114 4115 4116 4117
static HRESULT WINAPI IDirectPlay3AImpl_CreateGroupInGroup( IDirectPlay3A *iface, DPID parent,
        DPID *group, DPNAME *name, void *data, DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_CreateGroupInGroup( &This->IDirectPlay4A_iface, parent, group, name,
            data, size, flags );
}

4118 4119 4120 4121 4122 4123 4124 4125
static HRESULT WINAPI IDirectPlay3Impl_CreateGroupInGroup( IDirectPlay3 *iface, DPID parent,
        DPID *group, DPNAME *name, void *data, DWORD size, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_CreateGroupInGroup( &This->IDirectPlay4_iface, parent, group, name,
            data, size, flags );
}

4126 4127 4128
static HRESULT WINAPI IDirectPlay4AImpl_CreateGroupInGroup( IDirectPlay4A *iface,
        DPID idParentGroup, DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize,
        DWORD dwFlags )
4129
{
4130
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4131

4132
    *lpidGroup = DPID_UNKNOWN;
4133

4134 4135
    return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, lpGroupName, lpData,
            dwDataSize, dwFlags, TRUE );
4136 4137
}

4138 4139
static HRESULT WINAPI IDirectPlay4Impl_CreateGroupInGroup( IDirectPlay4 *iface, DPID idParentGroup,
        DPID *lpidGroup, DPNAME *lpGroupName, void *lpData, DWORD dwDataSize, DWORD dwFlags )
4140
{
4141
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
4142

4143
    *lpidGroup = DPID_UNKNOWN;
4144

4145 4146
    return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup, lpGroupName, lpData,
            dwDataSize, dwFlags, FALSE );
4147 4148
}

4149 4150 4151 4152 4153 4154 4155
static HRESULT WINAPI IDirectPlay3AImpl_DeleteGroupFromGroup( IDirectPlay3A *iface, DPID parent,
        DPID group )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4A_iface, parent, group );
}

4156 4157 4158 4159 4160 4161 4162
static HRESULT WINAPI IDirectPlay3Impl_DeleteGroupFromGroup( IDirectPlay3 *iface, DPID parent,
        DPID group )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, parent, group );
}

4163 4164
static HRESULT WINAPI IDirectPlay4AImpl_DeleteGroupFromGroup( IDirectPlay4A *iface, DPID parent,
        DPID group )
4165
{
4166 4167 4168
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_DeleteGroupFromGroup( &This->IDirectPlay4_iface, parent, group );
}
4169

4170 4171 4172 4173 4174 4175
static HRESULT WINAPI IDirectPlay4Impl_DeleteGroupFromGroup( IDirectPlay4 *iface, DPID parent,
        DPID group )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    lpGroupList glist;
    lpGroupData parentdata;
4176

4177
    TRACE("(%p)->(0x%08x,0x%08x)\n", This, parent, group );
4178

4179 4180 4181
    /* Is the parent group valid? */
    if ( ( parentdata = DP_FindAnyGroup(This, parent ) ) == NULL )
        return DPERR_INVALIDGROUP;
4182

4183 4184
    /* Remove the group from the parent group queue */
    DPQ_REMOVE_ENTRY( parentdata->groups, groups, lpGData->dpid, ==, group, glist );
Peter Hunnisett's avatar
Peter Hunnisett committed
4185

4186 4187
    if ( glist == NULL )
        return DPERR_INVALIDGROUP;
4188

4189 4190
    /* Decrement the ref count */
    glist->lpGData->uRef--;
4191

4192 4193
    /* Free up the list item */
    HeapFree( GetProcessHeap(), 0, glist );
4194

4195 4196
    /* Should send a DELETEGROUPFROMGROUP message */
    FIXME( "message not sent\n" );
4197

4198
    return DP_OK;
4199 4200
}

4201
static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
4202 4203 4204 4205 4206 4207
                                    LPDWORD lpdwBufSize )
{
  DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
  HRESULT                  hr;

  dpCompoundAddress.dwDataSize = sizeof( GUID );
4208
  dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237
  dpCompoundAddress.lpData = lpcSpGuid;

  *lplpAddrBuf = NULL;
  *lpdwBufSize = 0;

  hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
                                  lpdwBufSize, TRUE );

  if( hr != DPERR_BUFFERTOOSMALL )
  {
    ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
    return FALSE;
  }

  /* Now allocate the buffer */
  *lplpAddrBuf = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                            *lpdwBufSize );

  hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, *lplpAddrBuf,
                                  lpdwBufSize, TRUE );
  if( FAILED(hr) )
  {
    ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
    return FALSE;
  }

  return TRUE;
}

4238 4239 4240 4241 4242 4243 4244 4245
static HRESULT WINAPI IDirectPlay3AImpl_EnumConnections( IDirectPlay3A *iface,
        const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_EnumConnections( &This->IDirectPlay4A_iface, application, enumcb, context,
            flags );
}

4246 4247 4248 4249 4250 4251 4252 4253
static HRESULT WINAPI IDirectPlay3Impl_EnumConnections( IDirectPlay3 *iface,
        const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_EnumConnections( &This->IDirectPlay4_iface, application, enumcb, context,
            flags );
}

4254 4255 4256
static HRESULT WINAPI IDirectPlay4AImpl_EnumConnections( IDirectPlay4A *iface,
        const GUID *lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, void *lpContext,
        DWORD dwFlags )
4257
{
4258
  IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4259
  TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
4260 4261 4262 4263 4264 4265 4266 4267 4268

  /* A default dwFlags (0) is backwards compatible -- DPCONNECTION_DIRECTPLAY */
  if( dwFlags == 0 )
  {
    dwFlags = DPCONNECTION_DIRECTPLAY;
  }

  if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
          ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
4269
    )
4270 4271 4272 4273
  {
    return DPERR_INVALIDFLAGS;
  }

4274
  if( !lpEnumCallback )
4275
  {
4276
     return DPERR_INVALIDPARAMS;
4277 4278 4279 4280 4281
  }

  /* Enumerate DirectPlay service providers */
  if( dwFlags & DPCONNECTION_DIRECTPLAY )
  {
4282 4283
    HKEY hkResult;
    LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4284
    LPCSTR guidDataSubKey  = "Guid";
4285
    char subKeyName[51];
4286 4287
    DWORD dwIndex, sizeOfSubKeyName=50;
    FILETIME filetime;
4288 4289 4290

    /* Need to loop over the service providers in the registry */
    if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
4291
                         0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
4292 4293 4294 4295 4296 4297 4298 4299 4300
    {
      /* Hmmm. Does this mean that there are no service providers? */
      ERR(": no service providers?\n");
      return DP_OK;
    }


    /* Traverse all the service providers we have available */
    for( dwIndex=0;
4301
         RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
4302 4303
                        NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
         ++dwIndex, sizeOfSubKeyName=51 )
4304 4305 4306 4307 4308 4309
    {

      HKEY     hkServiceProvider;
      GUID     serviceProviderGUID;
      DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
      char     returnBuffer[51];
4310
      WCHAR    buff[51];
4311
      DPNAME   dpName;
4312
      BOOL     bBuildPass;
4313 4314 4315

      LPVOID                   lpAddressBuffer = NULL;
      DWORD                    dwAddressBufferSize = 0;
4316 4317

      TRACE(" this time through: %s\n", subKeyName );
4318

4319
      /* Get a handle for this particular service provider */
4320
      if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
4321 4322 4323 4324 4325 4326 4327
                         &hkServiceProvider ) != ERROR_SUCCESS )
      {
         ERR(": what the heck is going on?\n" );
         continue;
      }

      if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4328
                            NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
4329 4330 4331
                            &sizeOfReturnBuffer ) != ERROR_SUCCESS )
      {
        ERR(": missing GUID registry data members\n" );
4332
        RegCloseKey(hkServiceProvider);
4333 4334
        continue;
      }
4335
      RegCloseKey(hkServiceProvider);
4336 4337

      /* FIXME: Check return types to ensure we're interpreting data right */
4338
      MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4339
      CLSIDFromString( buff, &serviceProviderGUID );
4340 4341
      /* FIXME: Have I got a memory leak on the serviceProviderGUID? */

4342
      /* Fill in the DPNAME struct for the service provider */
4343 4344
      dpName.dwSize             = sizeof( dpName );
      dpName.dwFlags            = 0;
4345 4346
      dpName.u1.lpszShortNameA = subKeyName;
      dpName.u2.lpszLongNameA  = NULL;
4347

4348
      /* Create the compound address for the service provider.
Andreas Mohr's avatar
Andreas Mohr committed
4349 4350 4351 4352 4353 4354 4355
       * NOTE: This is a gruesome architectural scar right now.  DP
       * uses DPL and DPL uses DP.  Nasty stuff. This may be why the
       * native dll just gets around this little bit by allocating an
       * 80 byte buffer which isn't even filled with a valid compound
       * address. Oh well. Creating a proper compound address is the
       * way to go anyways despite this method taking slightly more
       * heap space and realtime :) */
4356 4357 4358 4359 4360

      bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
                                           &lpAddressBuffer,
                                           &dwAddressBufferSize );
      if( !bBuildPass )
4361
      {
4362 4363
        ERR( "Can't build compound addr\n" );
        return DPERR_GENERIC;
4364
      }
4365 4366

      /* The enumeration will return FALSE if we are not to continue */
4367
      if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
4368
                           &dpName, dwFlags, lpContext ) )
4369
      {
4370
         HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4371
         return DP_OK;
4372
      }
4373
      HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4374
    }
4375 4376 4377 4378 4379
  }

  /* Enumerate DirectPlayLobby service providers */
  if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
  {
Peter Hunnisett's avatar
Peter Hunnisett committed
4380 4381
    HKEY hkResult;
    LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4382
    LPCSTR guidDataSubKey  = "Guid";
4383
    char subKeyName[51];
Peter Hunnisett's avatar
Peter Hunnisett committed
4384 4385 4386 4387 4388 4389 4390
    DWORD dwIndex, sizeOfSubKeyName=50;
    FILETIME filetime;

    /* Need to loop over the service providers in the registry */
    if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
                         0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
    {
4391
      TRACE("No Lobby Providers have been registered.\n");
Peter Hunnisett's avatar
Peter Hunnisett committed
4392 4393 4394 4395
      return DP_OK;
    }


4396
    /* Traverse all the lobby providers we have available */
Peter Hunnisett's avatar
Peter Hunnisett committed
4397
    for( dwIndex=0;
4398
         RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
Peter Hunnisett's avatar
Peter Hunnisett committed
4399 4400 4401 4402 4403 4404 4405 4406
                        NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
         ++dwIndex, sizeOfSubKeyName=51 )
    {

      HKEY     hkServiceProvider;
      GUID     serviceProviderGUID;
      DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
      char     returnBuffer[51];
4407
      WCHAR    buff[51];
Peter Hunnisett's avatar
Peter Hunnisett committed
4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425
      DPNAME   dpName;
      HRESULT  hr;

      DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
      LPVOID                   lpAddressBuffer = NULL;
      DWORD                    dwAddressBufferSize = 0;

      TRACE(" this time through: %s\n", subKeyName );

      /* Get a handle for this particular service provider */
      if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
                         &hkServiceProvider ) != ERROR_SUCCESS )
      {
         ERR(": what the heck is going on?\n" );
         continue;
      }

      if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4426
                            NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
Peter Hunnisett's avatar
Peter Hunnisett committed
4427 4428 4429
                            &sizeOfReturnBuffer ) != ERROR_SUCCESS )
      {
        ERR(": missing GUID registry data members\n" );
4430
        RegCloseKey(hkServiceProvider);
Peter Hunnisett's avatar
Peter Hunnisett committed
4431 4432
        continue;
      }
4433
      RegCloseKey(hkServiceProvider);
Peter Hunnisett's avatar
Peter Hunnisett committed
4434 4435

      /* FIXME: Check return types to ensure we're interpreting data right */
4436
      MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4437
      CLSIDFromString( buff, &serviceProviderGUID );
Peter Hunnisett's avatar
Peter Hunnisett committed
4438 4439 4440 4441 4442
      /* FIXME: Have I got a memory leak on the serviceProviderGUID? */

      /* Fill in the DPNAME struct for the service provider */
      dpName.dwSize             = sizeof( dpName );
      dpName.dwFlags            = 0;
4443 4444
      dpName.u1.lpszShortNameA = subKeyName;
      dpName.u2.lpszLongNameA  = NULL;
Peter Hunnisett's avatar
Peter Hunnisett committed
4445

4446
      /* Create the compound address for the service provider.
4447 4448 4449 4450
         NOTE: This is a gruesome architectural scar right now. DP uses DPL and DPL uses DP
               nast stuff. This may be why the native dll just gets around this little bit by
               allocating an 80 byte buffer which isn't even a filled with a valid compound
               address. Oh well. Creating a proper compound address is the way to go anyways
Peter Hunnisett's avatar
Peter Hunnisett committed
4451
               despite this method taking slightly more heap space and realtime :) */
4452

4453
      dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
Peter Hunnisett's avatar
Peter Hunnisett committed
4454
      dpCompoundAddress.dwDataSize   = sizeof( GUID );
4455
      dpCompoundAddress.lpData       = &serviceProviderGUID;
Peter Hunnisett's avatar
Peter Hunnisett committed
4456

4457
      if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
Peter Hunnisett's avatar
Peter Hunnisett committed
4458 4459 4460 4461 4462 4463
                                     &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
      {
        ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
        return hr;
      }

4464 4465 4466 4467 4468 4469 4470
      /* Now allocate the buffer */
      lpAddressBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAddressBufferSize );

      if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
                                     &dwAddressBufferSize, TRUE ) ) != DP_OK )
      {
        ERR( "can't create address: %s\n", DPLAYX_HresultToString( hr ) );
4471
        HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4472 4473 4474 4475 4476
        return hr;
      }

      /* The enumeration will return FALSE if we are not to continue */
      if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
4477
                           &dpName, dwFlags, lpContext ) )
4478
      {
4479
         HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4480 4481
         return DP_OK;
      }
4482
      HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
4483 4484 4485 4486 4487 4488
    }
  }

  return DP_OK;
}

4489 4490
static HRESULT WINAPI IDirectPlay4Impl_EnumConnections( IDirectPlay4 *iface,
        const GUID *application, LPDPENUMCONNECTIONSCALLBACK enumcb, void *context, DWORD flags )
4491
{
4492 4493 4494
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    FIXME( "(%p)->(%p,%p,%p,0x%08x): stub\n", This, application, enumcb, context, flags );
    return DP_OK;
4495 4496
}

4497 4498 4499 4500 4501 4502 4503 4504
static HRESULT WINAPI IDirectPlay3AImpl_EnumGroupsInGroup( IDirectPlay3A *iface, DPID group,
        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4A_iface, group, instance,
            enumplayercb, context, flags );
}

4505 4506 4507 4508 4509 4510 4511 4512
static HRESULT WINAPI IDirectPlay3Impl_EnumGroupsInGroup( IDirectPlay3 *iface, DPID group,
        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4_iface, group, instance,
            enumplayercb, context, flags );
}

4513 4514
static HRESULT WINAPI IDirectPlay4AImpl_EnumGroupsInGroup( IDirectPlay4A *iface, DPID group,
        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
4515
{
4516 4517 4518 4519
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_EnumGroupsInGroup( &This->IDirectPlay4_iface, group, instance,
            enumplayercb, context, flags );
}
4520

4521 4522 4523 4524 4525 4526
static HRESULT WINAPI IDirectPlay4Impl_EnumGroupsInGroup( IDirectPlay4 *iface, DPID group,
        GUID *instance, LPDPENUMPLAYERSCALLBACK2 enumplayercb, void *context, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    lpGroupList glist;
    lpGroupData gdata;
4527

4528 4529
    FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x): semi stub\n", This, group, instance, enumplayercb,
            context, flags );
4530

4531 4532
    if ( This->dp2->connectionInitialized == NO_PROVIDER )
        return DPERR_UNINITIALIZED;
4533

4534 4535
    if ( ( gdata = DP_FindAnyGroup(This, group ) ) == NULL )
        return DPERR_INVALIDGROUP;
4536

4537 4538
    if ( DPQ_IS_EMPTY( gdata->groups ) )
        return DP_OK;
4539 4540


4541
    for( glist = DPQ_FIRST( gdata->groups ); ; glist = DPQ_NEXT( glist->groups ) )
4542
    {
4543 4544 4545 4546
        /* FIXME: Should check flags for match here */
        if ( !(*enumplayercb)( glist->lpGData->dpid, DPPLAYERTYPE_GROUP, &glist->lpGData->name,
                    flags, context ) )
            return DP_OK; /* User requested break */
4547

4548 4549
        if ( DPQ_IS_ENDOFLIST( glist->groups ) )
            break;
4550 4551
    }

4552
    return DP_OK;
4553 4554
}

4555 4556 4557 4558 4559 4560 4561 4562
static HRESULT WINAPI IDirectPlay3AImpl_GetGroupConnectionSettings( IDirectPlay3A *iface,
        DWORD flags, DPID group, void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_GetGroupConnectionSettings( &This->IDirectPlay4A_iface, flags, group,
            data, size );
}

4563 4564 4565 4566 4567 4568 4569 4570
static HRESULT WINAPI IDirectPlay3Impl_GetGroupConnectionSettings( IDirectPlay3 *iface,
        DWORD flags, DPID group, void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_GetGroupConnectionSettings( &This->IDirectPlay4_iface, flags, group,
            data, size );
}

4571 4572
static HRESULT WINAPI IDirectPlay4AImpl_GetGroupConnectionSettings( IDirectPlay4A *iface,
        DWORD flags, DPID group, void *data, DWORD *size )
4573
{
4574
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4575 4576
    FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, flags, group, data, size );
    return DP_OK;
4577 4578
}

4579 4580
static HRESULT WINAPI IDirectPlay4Impl_GetGroupConnectionSettings( IDirectPlay4 *iface, DWORD flags,
        DPID group, void *data, DWORD *size )
4581
{
4582 4583 4584
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    FIXME( "(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, flags, group, data, size );
    return DP_OK;
4585 4586
}

4587
static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
4588 4589 4590 4591 4592 4593 4594 4595 4596 4597
    REFGUID         guidDataType,
    DWORD           dwDataSize,
    LPCVOID         lpData,
    LPVOID          lpContext )
{
  /* Looking for the GUID of the provider to load */
  if( ( IsEqualGUID( guidDataType, &DPAID_ServiceProvider ) ) ||
      ( IsEqualGUID( guidDataType, &DPAID_LobbyProvider ) )
    )
  {
4598
    TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
4599 4600 4601 4602
           debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );

    if( dwDataSize != sizeof( GUID ) )
    {
4603
      ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
4604 4605 4606 4607 4608 4609 4610
    }

    memcpy( lpContext, lpData, dwDataSize );

    /* There shouldn't be more than 1 GUID/compound address */
    return FALSE;
  }
4611

4612 4613 4614 4615 4616 4617
  /* Still waiting for what we want */
  return TRUE;
}


/* Find and perform a LoadLibrary on the requested SP or LP GUID */
4618
static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
4619
{
4620
  UINT i;
4621
  LPCSTR spSubKey         = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4622
  LPCSTR lpSubKey         = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639
  LPCSTR guidDataSubKey   = "Guid";
  LPCSTR majVerDataSubKey = "dwReserved1";
  LPCSTR minVerDataSubKey = "dwReserved2";
  LPCSTR pathSubKey       = "Path";

  TRACE( " request to load %s\n", debugstr_guid( lpcGuid ) );

  /* FIXME: Cloned code with a quick hack. */
  for( i=0; i<2; i++ )
  {
    HKEY hkResult;
    LPCSTR searchSubKey;
    char subKeyName[51];
    DWORD dwIndex, sizeOfSubKeyName=50;
    FILETIME filetime;

    (i == 0) ? (searchSubKey = spSubKey ) : (searchSubKey = lpSubKey );
4640
    *lpbIsDpSp = (i == 0);
4641

4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662

    /* Need to loop over the service providers in the registry */
    if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
                         0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
    {
      /* Hmmm. Does this mean that there are no service providers? */
      ERR(": no service providers?\n");
      return 0;
    }

    /* Traverse all the service providers we have available */
    for( dwIndex=0;
         RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
                        NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
         ++dwIndex, sizeOfSubKeyName=51 )
    {

      HKEY     hkServiceProvider;
      GUID     serviceProviderGUID;
      DWORD    returnType, sizeOfReturnBuffer = 255;
      char     returnBuffer[256];
4663 4664
      WCHAR    buff[51];
      DWORD    dwTemp, len;
4665 4666

      TRACE(" this time through: %s\n", subKeyName );
Peter Hunnisett's avatar
Peter Hunnisett committed
4667

4668 4669 4670
      /* Get a handle for this particular service provider */
      if( RegOpenKeyExA( hkResult, subKeyName, 0, KEY_READ,
                         &hkServiceProvider ) != ERROR_SUCCESS )
Peter Hunnisett's avatar
Peter Hunnisett committed
4671
      {
4672 4673
         ERR(": what the heck is going on?\n" );
         continue;
Peter Hunnisett's avatar
Peter Hunnisett committed
4674 4675
      }

4676
      if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4677
                            NULL, &returnType, (LPBYTE)returnBuffer,
4678
                            &sizeOfReturnBuffer ) != ERROR_SUCCESS )
Peter Hunnisett's avatar
Peter Hunnisett committed
4679
      {
4680 4681
        ERR(": missing GUID registry data members\n" );
        continue;
Peter Hunnisett's avatar
Peter Hunnisett committed
4682
      }
4683

4684
      /* FIXME: Check return types to ensure we're interpreting data right */
4685
      MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
4686
      CLSIDFromString( buff, &serviceProviderGUID );
4687
      /* FIXME: Have I got a memory leak on the serviceProviderGUID? */
4688

4689 4690 4691 4692 4693
      /* Determine if this is the Service Provider that the user asked for */
      if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
      {
        continue;
      }
4694

4695 4696 4697 4698 4699 4700
      if( i == 0 ) /* DP SP */
      {
        len = MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, NULL, 0 );
        lpSpData->lpszName = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
        MultiByteToWideChar( CP_ACP, 0, subKeyName, -1, lpSpData->lpszName, len );
      }
4701

4702
      sizeOfReturnBuffer = 255;
4703

4704 4705
      /* Get dwReserved1 */
      if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4706
                            NULL, &returnType, (LPBYTE)returnBuffer,
4707 4708 4709 4710 4711
                            &sizeOfReturnBuffer ) != ERROR_SUCCESS )
      {
         ERR(": missing dwReserved1 registry data members\n") ;
         continue;
      }
4712

4713
      if( i == 0 )
4714 4715
          memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );

4716
      sizeOfReturnBuffer = 255;
4717

4718 4719
      /* Get dwReserved2 */
      if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4720
                            NULL, &returnType, (LPBYTE)returnBuffer,
4721 4722 4723 4724 4725
                            &sizeOfReturnBuffer ) != ERROR_SUCCESS )
      {
         ERR(": missing dwReserved1 registry data members\n") ;
         continue;
      }
4726

4727
      if( i == 0 )
4728
          memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4729

4730
      sizeOfReturnBuffer = 255;
4731

4732 4733
      /* Get the path for this service provider */
      if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4734
                            NULL, NULL, (LPBYTE)returnBuffer,
4735 4736
                            &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
      {
4737
        ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
4738 4739
        continue;
      }
4740

4741
      TRACE( "Loading %s\n", returnBuffer );
4742 4743 4744
      return LoadLibraryA( returnBuffer );
    }
  }
4745

4746
  return 0;
4747 4748
}

4749
static HRESULT DP_InitializeDPSP( IDirectPlayImpl *This, HMODULE hServiceProvider )
4750 4751 4752 4753 4754 4755
{
  HRESULT hr;
  LPDPSP_SPINIT SPInit;

  /* Initialize the service provider by calling SPInit */
  SPInit = (LPDPSP_SPINIT)GetProcAddress( hServiceProvider, "SPInit" );
4756

4757 4758 4759 4760 4761
  if( SPInit == NULL )
  {
    ERR( "Service provider doesn't provide SPInit interface?\n" );
    FreeLibrary( hServiceProvider );
    return DPERR_UNAVAILABLE;
4762
  }
4763 4764

  TRACE( "Calling SPInit (DP SP entry point)\n" );
4765

4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783
  hr = (*SPInit)( &This->dp2->spData );

  if( FAILED(hr) )
  {
    ERR( "DP SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
    FreeLibrary( hServiceProvider );
    return hr;
  }

  /* FIXME: Need to verify the sanity of the returned callback table
   *        using IsBadCodePtr */
  This->dp2->bSPInitialized = TRUE;

  /* This interface is now initialized as a DP object */
  This->dp2->connectionInitialized = DP_SERVICE_PROVIDER;

  /* Store the handle of the module so that we can unload it later */
  This->dp2->hServiceProvider = hServiceProvider;
4784

4785 4786 4787
  return hr;
}

4788
static HRESULT DP_InitializeDPLSP( IDirectPlayImpl *This, HMODULE hLobbyProvider )
4789 4790 4791
{
  HRESULT hr;
  LPSP_INIT DPLSPInit;
4792

4793 4794
  /* Initialize the service provider by calling SPInit */
  DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4795

4796 4797 4798 4799 4800
  if( DPLSPInit == NULL )
  {
    ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
    FreeLibrary( hLobbyProvider );
    return DPERR_UNAVAILABLE;
4801
  }
4802 4803

  TRACE( "Calling DPLSPInit (DPL SP entry point)\n" );
4804

4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817
  hr = (*DPLSPInit)( &This->dp2->dplspData );

  if( FAILED(hr) )
  {
    ERR( "DPL SP Initialization failed: %s\n", DPLAYX_HresultToString(hr) );
    FreeLibrary( hLobbyProvider );
    return hr;
  }

  /* FIXME: Need to verify the sanity of the returned callback table
   *        using IsBadCodePtr */

  This->dp2->bDPLSPInitialized = TRUE;
4818

4819 4820 4821 4822 4823
  /* This interface is now initialized as a lobby object */
  This->dp2->connectionInitialized = DP_LOBBY_PROVIDER;

  /* Store the handle of the module so that we can unload it later */
  This->dp2->hDPLobbyProvider = hLobbyProvider;
4824

4825 4826 4827
  return hr;
}

4828 4829 4830 4831 4832 4833 4834
static HRESULT WINAPI IDirectPlay3AImpl_InitializeConnection( IDirectPlay3A *iface,
        void *connection, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_InitializeConnection( &This->IDirectPlay4A_iface, connection, flags );
}

4835 4836 4837 4838 4839 4840 4841
static HRESULT WINAPI IDirectPlay3Impl_InitializeConnection( IDirectPlay3 *iface,
        void *connection, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, flags );
}

4842 4843
static HRESULT WINAPI IDirectPlay4AImpl_InitializeConnection( IDirectPlay4A *iface,
        void *connection, DWORD flags )
4844
{
4845 4846 4847
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_InitializeConnection( &This->IDirectPlay4_iface, connection, flags );
}
4848

4849 4850 4851 4852 4853 4854 4855 4856 4857
static HRESULT WINAPI IDirectPlay4Impl_InitializeConnection( IDirectPlay4 *iface,
        void *connection, DWORD flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    HMODULE servprov;
    GUID sp;
    const DWORD size = 80; /* FIXME: Need to calculate it correctly */
    BOOL is_dp_sp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
    HRESULT hr;
4858

4859
    TRACE( "(%p)->(%p,0x%08x)\n", This, connection, flags );
4860

4861 4862
    if ( !connection )
        return DPERR_INVALIDPARAMS;
4863

4864 4865
    if ( flags )
        return DPERR_INVALIDFLAGS;
4866

4867 4868
    if ( This->dp2->connectionInitialized != NO_PROVIDER )
        return DPERR_ALREADYINITIALIZED;
4869

4870 4871
    /* Find out what the requested SP is and how large this buffer is */
    hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, connection, size, &sp );
4872

4873 4874 4875 4876 4877
    if ( FAILED(hr) )
    {
        ERR( "Invalid compound address?\n" );
        return DPERR_UNAVAILABLE;
    }
4878

4879 4880
    /* Load the service provider */
    servprov = DP_LoadSP( &sp, &This->dp2->spData, &is_dp_sp );
4881

4882 4883 4884 4885 4886
    if ( !servprov )
    {
        ERR( "Unable to load service provider %s\n", debugstr_guid(&sp) );
        return DPERR_UNAVAILABLE;
    }
4887

4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902
    if ( is_dp_sp )
    {
         /* Fill in what we can of the Service Provider required information.
          * The rest was be done in DP_LoadSP
          */
         This->dp2->spData.lpAddress = connection;
         This->dp2->spData.dwAddressSize = size;
         This->dp2->spData.lpGuid = &sp;
         hr = DP_InitializeDPSP( This, servprov );
    }
    else
    {
         This->dp2->dplspData.lpAddress = connection;
         hr = DP_InitializeDPLSP( This, servprov );
    }
4903

4904 4905
    if ( FAILED(hr) )
        return hr;
4906

4907
    return DP_OK;
4908 4909
}

4910 4911 4912 4913 4914 4915 4916 4917 4918
static HRESULT WINAPI IDirectPlay3AImpl_SecureOpen( IDirectPlay3A *iface,
        const DPSESSIONDESC2 *sdesc, DWORD flags, const DPSECURITYDESC *security,
        const DPCREDENTIALS *credentials )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_SecureOpen( &This->IDirectPlay4A_iface, sdesc, flags, security,
            credentials );
}

4919 4920 4921 4922 4923 4924 4925 4926 4927
static HRESULT WINAPI IDirectPlay3Impl_SecureOpen( IDirectPlay3 *iface,
        const DPSESSIONDESC2 *sdesc, DWORD flags, const DPSECURITYDESC *security,
        const DPCREDENTIALS *credentials )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_SecureOpen( &This->IDirectPlay4_iface, sdesc, flags, security,
            credentials );
}

4928 4929 4930
static HRESULT WINAPI IDirectPlay4AImpl_SecureOpen( IDirectPlay4A *iface,
        const DPSESSIONDESC2 *lpsd, DWORD dwFlags, const DPSECURITYDESC *lpSecurity,
        const DPCREDENTIALS *lpCredentials )
4931
{
4932 4933
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4934 4935
}

4936 4937 4938
static HRESULT WINAPI IDirectPlay4Impl_SecureOpen( IDirectPlay4 *iface,
        const DPSESSIONDESC2 *lpsd, DWORD dwFlags, const DPSECURITYDESC *lpSecurity,
        const DPCREDENTIALS *lpCredentials )
4939
{
4940 4941
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4942 4943
}

4944 4945 4946 4947 4948 4949 4950
static HRESULT WINAPI IDirectPlay3AImpl_SendChatMessage( IDirectPlay3A *iface, DPID from, DPID to,
        DWORD flags, DPCHAT *chatmsg )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_SendChatMessage( &This->IDirectPlay4A_iface, from, to, flags, chatmsg );
}

4951 4952 4953 4954 4955 4956 4957
static HRESULT WINAPI IDirectPlay3Impl_SendChatMessage( IDirectPlay3 *iface, DPID from, DPID to,
        DWORD flags, DPCHAT *chatmsg )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_SendChatMessage( &This->IDirectPlay4_iface, from, to, flags, chatmsg );
}

4958 4959
static HRESULT WINAPI IDirectPlay4AImpl_SendChatMessage( IDirectPlay4A *iface, DPID from,
        DPID to, DWORD flags, DPCHAT *chatmsg )
4960
{
4961
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4962 4963
    FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, from, to, flags, chatmsg );
    return DP_OK;
4964 4965
}

4966 4967
static HRESULT WINAPI IDirectPlay4Impl_SendChatMessage( IDirectPlay4 *iface, DPID from, DPID to,
        DWORD flags, DPCHAT *chatmsg )
4968
{
4969 4970 4971
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, from, to, flags, chatmsg );
    return DP_OK;
4972 4973
}

4974 4975 4976 4977 4978 4979 4980 4981
static HRESULT WINAPI IDirectPlay3AImpl_SetGroupConnectionSettings( IDirectPlay3A *iface,
        DWORD flags, DPID group, DPLCONNECTION *connection )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_SetGroupConnectionSettings( &This->IDirectPlay4A_iface, flags, group,
            connection );
}

4982 4983 4984 4985 4986 4987 4988 4989
static HRESULT WINAPI IDirectPlay3Impl_SetGroupConnectionSettings( IDirectPlay3 *iface,
        DWORD flags, DPID group, DPLCONNECTION *connection )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_SetGroupConnectionSettings( &This->IDirectPlay4_iface, flags, group,
            connection );
}

4990 4991
static HRESULT WINAPI IDirectPlay4AImpl_SetGroupConnectionSettings( IDirectPlay4A *iface,
        DWORD flags, DPID group, DPLCONNECTION *connection )
4992
{
4993
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
4994 4995
    FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, flags, group, connection );
    return DP_OK;
4996 4997
}

4998 4999
static HRESULT WINAPI IDirectPlay4Impl_SetGroupConnectionSettings( IDirectPlay4 *iface, DWORD flags,
        DPID group, DPLCONNECTION *connection )
5000
{
5001 5002 5003
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    FIXME( "(%p)->(0x%08x,0x%08x,%p): stub\n", This, flags, group, connection );
    return DP_OK;
5004 5005
}

5006 5007 5008 5009 5010 5011 5012
static HRESULT WINAPI IDirectPlay3AImpl_StartSession( IDirectPlay3A *iface, DWORD flags,
        DPID group )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_StartSession( &This->IDirectPlay4A_iface, flags, group );
}

5013 5014 5015 5016 5017 5018 5019
static HRESULT WINAPI IDirectPlay3Impl_StartSession( IDirectPlay3 *iface, DWORD flags,
        DPID group )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_StartSession( &This->IDirectPlay4_iface, flags, group );
}

5020 5021
static HRESULT WINAPI IDirectPlay4AImpl_StartSession( IDirectPlay4A *iface, DWORD flags,
        DPID group )
5022
{
5023 5024
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_StartSession( &This->IDirectPlay4_iface, flags, group );
5025 5026
}

5027
static HRESULT WINAPI IDirectPlay4Impl_StartSession( IDirectPlay4 *iface, DWORD flags, DPID group )
5028
{
5029 5030 5031
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, flags, group );
    return DP_OK;
5032
}
5033

5034 5035 5036 5037 5038 5039 5040
static HRESULT WINAPI IDirectPlay3AImpl_GetGroupFlags( IDirectPlay3A *iface, DPID group,
        DWORD *flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_GetGroupFlags( &This->IDirectPlay4A_iface, group, flags );
}

5041 5042 5043 5044 5045 5046 5047
static HRESULT WINAPI IDirectPlay3Impl_GetGroupFlags( IDirectPlay3 *iface, DPID group,
        DWORD *flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_GetGroupFlags( &This->IDirectPlay4_iface, group, flags );
}

5048 5049
static HRESULT WINAPI IDirectPlay4AImpl_GetGroupFlags( IDirectPlay4A *iface, DPID group,
        DWORD *flags )
5050
{
5051 5052
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_GetGroupFlags( &This->IDirectPlay4_iface, group, flags );
5053 5054
}

5055 5056
static HRESULT WINAPI IDirectPlay4Impl_GetGroupFlags( IDirectPlay4 *iface, DPID group,
        DWORD *flags )
5057
{
5058 5059 5060
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    FIXME( "(%p)->(0x%08x,%p): stub\n", This, group, flags );
    return DP_OK;
5061 5062
}

5063 5064 5065 5066 5067 5068 5069
static HRESULT WINAPI IDirectPlay3AImpl_GetGroupParent( IDirectPlay3A *iface, DPID group,
        DPID *parent )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_GetGroupParent( &This->IDirectPlay4A_iface, group, parent );
}

5070 5071 5072 5073 5074 5075 5076
static HRESULT WINAPI IDirectPlay3Impl_GetGroupParent( IDirectPlay3 *iface, DPID group,
        DPID *parent )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_GetGroupParent( &This->IDirectPlay4_iface, group, parent );
}

5077 5078
static HRESULT WINAPI IDirectPlay4AImpl_GetGroupParent( IDirectPlay4A *iface, DPID group,
        DPID *parent )
5079
{
5080 5081 5082
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_GetGroupParent( &This->IDirectPlay4_iface, group, parent );
}
5083

5084 5085 5086 5087 5088
static HRESULT WINAPI IDirectPlay4Impl_GetGroupParent( IDirectPlay4 *iface, DPID group,
        DPID *parent )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    lpGroupData gdata;
5089

5090
    TRACE( "(%p)->(0x%08x,%p)\n", This, group, parent );
5091

5092 5093
    if ( ( gdata = DP_FindAnyGroup( This, group ) ) == NULL )
        return DPERR_INVALIDGROUP;
5094

5095
    *parent = gdata->dpid;
5096

5097
    return DP_OK;
5098 5099
}

5100 5101 5102 5103 5104 5105 5106
static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerAccount( IDirectPlay3A *iface, DPID player,
        DWORD flags, void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_GetPlayerAccount( &This->IDirectPlay4A_iface, player, flags, data, size );
}

5107 5108 5109 5110 5111 5112 5113
static HRESULT WINAPI IDirectPlay3Impl_GetPlayerAccount( IDirectPlay3 *iface, DPID player,
        DWORD flags, void *data, DWORD *size )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_GetPlayerAccount( &This->IDirectPlay4_iface, player, flags, data, size );
}

5114 5115
static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerAccount( IDirectPlay4A *iface, DPID player,
        DWORD flags, void *data, DWORD *size )
5116
{
5117
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
5118 5119
    FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, player, flags, data, size );
    return DP_OK;
5120 5121
}

5122 5123
static HRESULT WINAPI IDirectPlay4Impl_GetPlayerAccount( IDirectPlay4 *iface, DPID player,
        DWORD flags, void *data, DWORD *size )
5124
{
5125 5126 5127
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    FIXME( "(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, player, flags, data, size );
    return DP_OK;
5128 5129
}

5130 5131 5132 5133 5134 5135 5136
static HRESULT WINAPI IDirectPlay3AImpl_GetPlayerFlags( IDirectPlay3A *iface, DPID player,
        DWORD *flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3A( iface );
    return IDirectPlayX_GetPlayerFlags( &This->IDirectPlay4A_iface, player, flags );
}

5137 5138 5139 5140 5141 5142 5143
static HRESULT WINAPI IDirectPlay3Impl_GetPlayerFlags( IDirectPlay3 *iface, DPID player,
        DWORD *flags )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay3( iface );
    return IDirectPlayX_GetPlayerFlags( &This->IDirectPlay4_iface, player, flags );
}

5144 5145
static HRESULT WINAPI IDirectPlay4AImpl_GetPlayerFlags( IDirectPlay4A *iface, DPID player,
        DWORD *flags )
5146
{
5147 5148
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_GetPlayerFlags( &This->IDirectPlay4_iface, player, flags );
5149 5150
}

5151 5152
static HRESULT WINAPI IDirectPlay4Impl_GetPlayerFlags( IDirectPlay4 *iface, DPID player,
        DWORD *flags )
5153
{
5154 5155 5156
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    FIXME( "(%p)->(0x%08x,%p): stub\n", This, player, flags );
    return DP_OK;
5157 5158
}

5159 5160
static HRESULT WINAPI IDirectPlay4AImpl_GetGroupOwner( IDirectPlay4A *iface, DPID group,
        DPID *owner )
5161
{
5162 5163
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_GetGroupOwner( &This->IDirectPlay4_iface, group, owner );
5164 5165
}

5166 5167
static HRESULT WINAPI IDirectPlay4Impl_GetGroupOwner( IDirectPlay4 *iface, DPID group,
        DPID *owner )
5168
{
5169 5170 5171
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    FIXME( "(%p)->(0x%08x,%p): stub\n", This, group, owner );
    return DP_OK;
5172 5173
}

5174 5175
static HRESULT WINAPI IDirectPlay4AImpl_SetGroupOwner( IDirectPlay4A *iface, DPID group,
        DPID owner )
5176
{
5177 5178
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_SetGroupOwner( &This->IDirectPlay4_iface, group, owner );
5179 5180
}

5181 5182
static HRESULT WINAPI IDirectPlay4Impl_SetGroupOwner( IDirectPlay4 *iface, DPID group ,
        DPID owner )
5183
{
5184 5185 5186
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    FIXME( "(%p)->(0x%08x,0x%08x): stub\n", This, group, owner );
    return DP_OK;
5187 5188
}

5189 5190 5191
static HRESULT WINAPI IDirectPlay4AImpl_SendEx( IDirectPlay4A *iface, DPID from, DPID to,
        DWORD flags, void *data, DWORD size, DWORD priority, DWORD timeout, void *context,
        DWORD *msgid )
5192
{
5193 5194 5195 5196
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_SendEx( &This->IDirectPlay4_iface, from, to, flags, data, size, priority,
            timeout, context, msgid );
}
5197

5198 5199 5200 5201 5202
static HRESULT WINAPI IDirectPlay4Impl_SendEx( IDirectPlay4 *iface, DPID from, DPID to,
        DWORD flags, void *data, DWORD size, DWORD priority, DWORD timeout, void *context,
        DWORD *msgid )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5203

5204 5205
    FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p): semi-stub\n",
            This, from, to, flags, data, size, priority, timeout, context, msgid );
5206

5207 5208
    if ( This->dp2->connectionInitialized == NO_PROVIDER )
        return DPERR_UNINITIALIZED;
5209

5210 5211 5212 5213
    /* FIXME: Add parameter checking */
    /* FIXME: First call to this needs to acquire a message id which will be
     *        used for multiple sends
     */
5214

5215
    /* NOTE: Can't send messages to yourself - this will be trapped in receive */
5216

5217 5218 5219 5220
    /* Verify that the message is being sent from a valid local player. The
     * from player may be anonymous DPID_UNKNOWN
     */
    if ( from != DPID_UNKNOWN && !DP_FindPlayer( This, from ) )
5221
    {
5222 5223
        WARN( "INFO: Invalid from player 0x%08x\n", from );
        return DPERR_INVALIDPLAYER;
5224 5225
    }

5226 5227 5228 5229
    /* Verify that the message is being sent to a valid player, group or to
     * everyone. If it's valid, send it to those players.
     */
    if ( to == DPID_ALLPLAYERS )
5230
    {
5231 5232 5233 5234 5235 5236 5237
        /* See if SP has the ability to multicast. If so, use it */
        if ( This->dp2->spData.lpCB->SendToGroupEx )
            FIXME( "Use group sendex to group 0\n" );
        else if ( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
            FIXME( "Use obsolete group send to group 0\n" );
        else /* No multicast, multiplicate */
            FIXME( "Send to all players using EnumPlayersInGroup\n" );
5238
    }
5239
    else if ( DP_FindPlayer( This, to ) )
5240
    {
5241 5242 5243
        /* Have the service provider send this message */
        /* FIXME: Could optimize for local interface sends */
        return DP_SP_SendEx( This, flags, data, size, priority, timeout, context, msgid );
5244
    }
5245
    else if ( DP_FindAnyGroup( This, to ) )
5246
    {
5247 5248 5249 5250 5251 5252 5253
        /* See if SP has the ability to multicast. If so, use it */
        if ( This->dp2->spData.lpCB->SendToGroupEx )
            FIXME( "Use group sendex\n" );
        else if ( This->dp2->spData.lpCB->SendToGroup ) /* obsolete interface */
            FIXME( "Use obsolete group send to group\n" );
        else /* No multicast, multiplicate */
            FIXME( "Send to all players using EnumPlayersInGroup\n" );
Peter Hunnisett's avatar
Peter Hunnisett committed
5254 5255

    }
5256 5257
    else
        return DPERR_INVALIDPLAYER;
5258 5259 5260 5261 5262

    /* FIXME: Should return what the send returned */
    return DP_OK;
}

5263 5264
static HRESULT DP_SP_SendEx( IDirectPlayImpl *This, DWORD dwFlags, void *lpData, DWORD dwDataSize,
        DWORD dwPriority, DWORD dwTimeout, void *lpContext, DWORD *lpdwMsgID )
5265 5266 5267
{
  LPDPMSG lpMElem;

Peter Hunnisett's avatar
Peter Hunnisett committed
5268
  FIXME( ": stub\n" );
5269

Peter Hunnisett's avatar
Peter Hunnisett committed
5270
  /* FIXME: This queuing should only be for async messages */
5271

5272 5273
  lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
  lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
5274 5275 5276

  CopyMemory( lpMElem->msg, lpData, dwDataSize );

Peter Hunnisett's avatar
Peter Hunnisett committed
5277
  /* FIXME: Need to queue based on priority */
5278 5279
  DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );

5280 5281 5282
  return DP_OK;
}

5283 5284
static HRESULT WINAPI IDirectPlay4AImpl_GetMessageQueue( IDirectPlay4A *iface, DPID from, DPID to,
        DWORD flags, DWORD *msgs, DWORD *bytes )
5285
{
5286 5287 5288
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_GetMessageQueue( &This->IDirectPlay4_iface, from, to, flags, msgs, bytes );
}
5289

5290 5291 5292 5293 5294
static HRESULT WINAPI IDirectPlay4Impl_GetMessageQueue( IDirectPlay4 *iface, DPID from, DPID to,
        DWORD flags, DWORD *msgs, DWORD *bytes )
{
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
    HRESULT hr = DP_OK;
5295

5296
    FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p): semi-stub\n", This, from, to, flags, msgs, bytes );
5297

5298 5299
    /* FIXME: Do we need to do from and to sanity checking here? */
    /* FIXME: What about sends which are not immediate? */
5300

5301 5302 5303
    if ( This->dp2->spData.lpCB->GetMessageQueue )
    {
        DPSP_GETMESSAGEQUEUEDATA data;
5304

5305
        FIXME( "Calling SP GetMessageQueue - is it right?\n" );
5306

5307 5308 5309 5310 5311 5312 5313
        /* FIXME: None of this is documented :( */
        data.lpISP        = This->dp2->spData.lpISP;
        data.dwFlags      = flags;
        data.idFrom       = from;
        data.idTo         = to;
        data.lpdwNumMsgs  = msgs;
        data.lpdwNumBytes = bytes;
5314

5315 5316 5317 5318
        hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
    }
    else
        FIXME( "No SP for GetMessageQueue - fake some data\n" );
5319

5320
    return hr;
5321 5322
}

5323 5324
static HRESULT dplay_cancelmsg ( IDirectPlayImpl* This, DWORD msgid, DWORD flags, DWORD minprio,
        DWORD maxprio )
5325
{
5326
    HRESULT hr = DP_OK;
5327

5328
    FIXME( "(%p)->(0x%08x,0x%08x): semi stub\n", This, msgid, flags );
5329

5330 5331 5332
    if ( This->dp2->spData.lpCB->Cancel )
    {
        DPSP_CANCELDATA data;
5333

5334
        TRACE( "Calling SP Cancel\n" );
5335

5336
        /* FIXME: Undocumented callback */
5337

5338 5339 5340 5341 5342 5343
        data.lpISP          = This->dp2->spData.lpISP;
        data.dwFlags        = flags;
        data.lprglpvSPMsgID = NULL;
        data.cSPMsgID       = msgid;
        data.dwMinPriority  = minprio;
        data.dwMaxPriority  = maxprio;
5344

5345 5346 5347 5348
        hr = (*This->dp2->spData.lpCB->Cancel)( &data );
    }
    else
        FIXME( "SP doesn't implement Cancel\n" );
5349

5350
    return hr;
5351 5352
}

5353 5354
static HRESULT WINAPI IDirectPlay4AImpl_CancelMessage( IDirectPlay4A *iface, DWORD msgid,
        DWORD flags )
5355
{
5356 5357
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_CancelMessage( &This->IDirectPlay4_iface, msgid, flags );
5358 5359
}

5360 5361
static HRESULT WINAPI IDirectPlay4Impl_CancelMessage( IDirectPlay4 *iface, DWORD msgid,
        DWORD flags )
5362
{
5363
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5364

5365 5366
    if ( flags != 0 )
      return DPERR_INVALIDFLAGS;
5367

5368 5369
    if ( msgid == 0 )
      flags |= DPCANCELSEND_ALL;
5370

5371
    return dplay_cancelmsg( This, msgid, flags, 0, 0 );
5372 5373
}

5374 5375
static HRESULT WINAPI IDirectPlay4AImpl_CancelPriority( IDirectPlay4A *iface, DWORD minprio,
        DWORD maxprio, DWORD flags )
5376
{
5377 5378
    IDirectPlayImpl *This = impl_from_IDirectPlay4A( iface );
    return IDirectPlayX_CancelPriority( &This->IDirectPlay4_iface, minprio, maxprio, flags );
5379 5380
}

5381 5382
static HRESULT WINAPI IDirectPlay4Impl_CancelPriority( IDirectPlay4 *iface, DWORD minprio,
        DWORD maxprio, DWORD flags )
5383
{
5384
    IDirectPlayImpl *This = impl_from_IDirectPlay4( iface );
5385

5386 5387
    if ( flags != 0 )
        return DPERR_INVALIDFLAGS;
5388

5389
    return dplay_cancelmsg( This, 0, DPCANCELSEND_PRIORITY, minprio, maxprio );
5390 5391
}

5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427
static const IDirectPlay2Vtbl dp2_vt =
{
    IDirectPlay2Impl_QueryInterface,
    IDirectPlay2Impl_AddRef,
    IDirectPlay2Impl_Release,
    IDirectPlay2Impl_AddPlayerToGroup,
    IDirectPlay2Impl_Close,
    IDirectPlay2Impl_CreateGroup,
    IDirectPlay2Impl_CreatePlayer,
    IDirectPlay2Impl_DeletePlayerFromGroup,
    IDirectPlay2Impl_DestroyGroup,
    IDirectPlay2Impl_DestroyPlayer,
    IDirectPlay2Impl_EnumGroupPlayers,
    IDirectPlay2Impl_EnumGroups,
    IDirectPlay2Impl_EnumPlayers,
    IDirectPlay2Impl_EnumSessions,
    IDirectPlay2Impl_GetCaps,
    IDirectPlay2Impl_GetGroupData,
    IDirectPlay2Impl_GetGroupName,
    IDirectPlay2Impl_GetMessageCount,
    IDirectPlay2Impl_GetPlayerAddress,
    IDirectPlay2Impl_GetPlayerCaps,
    IDirectPlay2Impl_GetPlayerData,
    IDirectPlay2Impl_GetPlayerName,
    IDirectPlay2Impl_GetSessionDesc,
    IDirectPlay2Impl_Initialize,
    IDirectPlay2Impl_Open,
    IDirectPlay2Impl_Receive,
    IDirectPlay2Impl_Send,
    IDirectPlay2Impl_SetGroupData,
    IDirectPlay2Impl_SetGroupName,
    IDirectPlay2Impl_SetPlayerData,
    IDirectPlay2Impl_SetPlayerName,
    IDirectPlay2Impl_SetSessionDesc
};

5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463
static const IDirectPlay2Vtbl dp2A_vt =
{
    IDirectPlay2AImpl_QueryInterface,
    IDirectPlay2AImpl_AddRef,
    IDirectPlay2AImpl_Release,
    IDirectPlay2AImpl_AddPlayerToGroup,
    IDirectPlay2AImpl_Close,
    IDirectPlay2AImpl_CreateGroup,
    IDirectPlay2AImpl_CreatePlayer,
    IDirectPlay2AImpl_DeletePlayerFromGroup,
    IDirectPlay2AImpl_DestroyGroup,
    IDirectPlay2AImpl_DestroyPlayer,
    IDirectPlay2AImpl_EnumGroupPlayers,
    IDirectPlay2AImpl_EnumGroups,
    IDirectPlay2AImpl_EnumPlayers,
    IDirectPlay2AImpl_EnumSessions,
    IDirectPlay2AImpl_GetCaps,
    IDirectPlay2AImpl_GetGroupData,
    IDirectPlay2AImpl_GetGroupName,
    IDirectPlay2AImpl_GetMessageCount,
    IDirectPlay2AImpl_GetPlayerAddress,
    IDirectPlay2AImpl_GetPlayerCaps,
    IDirectPlay2AImpl_GetPlayerData,
    IDirectPlay2AImpl_GetPlayerName,
    IDirectPlay2AImpl_GetSessionDesc,
    IDirectPlay2AImpl_Initialize,
    IDirectPlay2AImpl_Open,
    IDirectPlay2AImpl_Receive,
    IDirectPlay2AImpl_Send,
    IDirectPlay2AImpl_SetGroupData,
    IDirectPlay2AImpl_SetGroupName,
    IDirectPlay2AImpl_SetPlayerData,
    IDirectPlay2AImpl_SetPlayerName,
    IDirectPlay2AImpl_SetSessionDesc
};

5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514
static const IDirectPlay3Vtbl dp3_vt =
{
    IDirectPlay3Impl_QueryInterface,
    IDirectPlay3Impl_AddRef,
    IDirectPlay3Impl_Release,
    IDirectPlay3Impl_AddPlayerToGroup,
    IDirectPlay3Impl_Close,
    IDirectPlay3Impl_CreateGroup,
    IDirectPlay3Impl_CreatePlayer,
    IDirectPlay3Impl_DeletePlayerFromGroup,
    IDirectPlay3Impl_DestroyGroup,
    IDirectPlay3Impl_DestroyPlayer,
    IDirectPlay3Impl_EnumGroupPlayers,
    IDirectPlay3Impl_EnumGroups,
    IDirectPlay3Impl_EnumPlayers,
    IDirectPlay3Impl_EnumSessions,
    IDirectPlay3Impl_GetCaps,
    IDirectPlay3Impl_GetGroupData,
    IDirectPlay3Impl_GetGroupName,
    IDirectPlay3Impl_GetMessageCount,
    IDirectPlay3Impl_GetPlayerAddress,
    IDirectPlay3Impl_GetPlayerCaps,
    IDirectPlay3Impl_GetPlayerData,
    IDirectPlay3Impl_GetPlayerName,
    IDirectPlay3Impl_GetSessionDesc,
    IDirectPlay3Impl_Initialize,
    IDirectPlay3Impl_Open,
    IDirectPlay3Impl_Receive,
    IDirectPlay3Impl_Send,
    IDirectPlay3Impl_SetGroupData,
    IDirectPlay3Impl_SetGroupName,
    IDirectPlay3Impl_SetPlayerData,
    IDirectPlay3Impl_SetPlayerName,
    IDirectPlay3Impl_SetSessionDesc,
    IDirectPlay3Impl_AddGroupToGroup,
    IDirectPlay3Impl_CreateGroupInGroup,
    IDirectPlay3Impl_DeleteGroupFromGroup,
    IDirectPlay3Impl_EnumConnections,
    IDirectPlay3Impl_EnumGroupsInGroup,
    IDirectPlay3Impl_GetGroupConnectionSettings,
    IDirectPlay3Impl_InitializeConnection,
    IDirectPlay3Impl_SecureOpen,
    IDirectPlay3Impl_SendChatMessage,
    IDirectPlay3Impl_SetGroupConnectionSettings,
    IDirectPlay3Impl_StartSession,
    IDirectPlay3Impl_GetGroupFlags,
    IDirectPlay3Impl_GetGroupParent,
    IDirectPlay3Impl_GetPlayerAccount,
    IDirectPlay3Impl_GetPlayerFlags
};

5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565
static const IDirectPlay3Vtbl dp3A_vt =
{
    IDirectPlay3AImpl_QueryInterface,
    IDirectPlay3AImpl_AddRef,
    IDirectPlay3AImpl_Release,
    IDirectPlay3AImpl_AddPlayerToGroup,
    IDirectPlay3AImpl_Close,
    IDirectPlay3AImpl_CreateGroup,
    IDirectPlay3AImpl_CreatePlayer,
    IDirectPlay3AImpl_DeletePlayerFromGroup,
    IDirectPlay3AImpl_DestroyGroup,
    IDirectPlay3AImpl_DestroyPlayer,
    IDirectPlay3AImpl_EnumGroupPlayers,
    IDirectPlay3AImpl_EnumGroups,
    IDirectPlay3AImpl_EnumPlayers,
    IDirectPlay3AImpl_EnumSessions,
    IDirectPlay3AImpl_GetCaps,
    IDirectPlay3AImpl_GetGroupData,
    IDirectPlay3AImpl_GetGroupName,
    IDirectPlay3AImpl_GetMessageCount,
    IDirectPlay3AImpl_GetPlayerAddress,
    IDirectPlay3AImpl_GetPlayerCaps,
    IDirectPlay3AImpl_GetPlayerData,
    IDirectPlay3AImpl_GetPlayerName,
    IDirectPlay3AImpl_GetSessionDesc,
    IDirectPlay3AImpl_Initialize,
    IDirectPlay3AImpl_Open,
    IDirectPlay3AImpl_Receive,
    IDirectPlay3AImpl_Send,
    IDirectPlay3AImpl_SetGroupData,
    IDirectPlay3AImpl_SetGroupName,
    IDirectPlay3AImpl_SetPlayerData,
    IDirectPlay3AImpl_SetPlayerName,
    IDirectPlay3AImpl_SetSessionDesc,
    IDirectPlay3AImpl_AddGroupToGroup,
    IDirectPlay3AImpl_CreateGroupInGroup,
    IDirectPlay3AImpl_DeleteGroupFromGroup,
    IDirectPlay3AImpl_EnumConnections,
    IDirectPlay3AImpl_EnumGroupsInGroup,
    IDirectPlay3AImpl_GetGroupConnectionSettings,
    IDirectPlay3AImpl_InitializeConnection,
    IDirectPlay3AImpl_SecureOpen,
    IDirectPlay3AImpl_SendChatMessage,
    IDirectPlay3AImpl_SetGroupConnectionSettings,
    IDirectPlay3AImpl_StartSession,
    IDirectPlay3AImpl_GetGroupFlags,
    IDirectPlay3AImpl_GetGroupParent,
    IDirectPlay3AImpl_GetPlayerAccount,
    IDirectPlay3AImpl_GetPlayerFlags
};

5566
static const IDirectPlay4Vtbl dp4_vt =
5567
{
5568 5569 5570
    IDirectPlay4Impl_QueryInterface,
    IDirectPlay4Impl_AddRef,
    IDirectPlay4Impl_Release,
5571
    IDirectPlay4Impl_AddPlayerToGroup,
5572
    IDirectPlay4Impl_Close,
5573 5574
    IDirectPlay4Impl_CreateGroup,
    IDirectPlay4Impl_CreatePlayer,
5575
    IDirectPlay4Impl_DeletePlayerFromGroup,
5576 5577
    IDirectPlay4Impl_DestroyGroup,
    IDirectPlay4Impl_DestroyPlayer,
5578
    IDirectPlay4Impl_EnumGroupPlayers,
5579
    IDirectPlay4Impl_EnumGroups,
5580
    IDirectPlay4Impl_EnumPlayers,
5581
    IDirectPlay4Impl_EnumSessions,
5582
    IDirectPlay4Impl_GetCaps,
5583
    IDirectPlay4Impl_GetGroupData,
5584
    IDirectPlay4Impl_GetGroupName,
5585
    IDirectPlay4Impl_GetMessageCount,
5586
    IDirectPlay4Impl_GetPlayerAddress,
5587
    IDirectPlay4Impl_GetPlayerCaps,
5588
    IDirectPlay4Impl_GetPlayerData,
5589 5590
    IDirectPlay4Impl_GetPlayerName,
    IDirectPlay4Impl_GetSessionDesc,
5591
    IDirectPlay4Impl_Initialize,
5592
    IDirectPlay4Impl_Open,
5593
    IDirectPlay4Impl_Receive,
5594
    IDirectPlay4Impl_Send,
5595
    IDirectPlay4Impl_SetGroupData,
5596
    IDirectPlay4Impl_SetGroupName,
5597
    IDirectPlay4Impl_SetPlayerData,
5598 5599
    IDirectPlay4Impl_SetPlayerName,
    IDirectPlay4Impl_SetSessionDesc,
5600
    IDirectPlay4Impl_AddGroupToGroup,
5601
    IDirectPlay4Impl_CreateGroupInGroup,
5602
    IDirectPlay4Impl_DeleteGroupFromGroup,
5603
    IDirectPlay4Impl_EnumConnections,
5604
    IDirectPlay4Impl_EnumGroupsInGroup,
5605
    IDirectPlay4Impl_GetGroupConnectionSettings,
5606
    IDirectPlay4Impl_InitializeConnection,
5607
    IDirectPlay4Impl_SecureOpen,
5608 5609 5610 5611
    IDirectPlay4Impl_SendChatMessage,
    IDirectPlay4Impl_SetGroupConnectionSettings,
    IDirectPlay4Impl_StartSession,
    IDirectPlay4Impl_GetGroupFlags,
5612
    IDirectPlay4Impl_GetGroupParent,
5613 5614 5615 5616
    IDirectPlay4Impl_GetPlayerAccount,
    IDirectPlay4Impl_GetPlayerFlags,
    IDirectPlay4Impl_GetGroupOwner,
    IDirectPlay4Impl_SetGroupOwner,
5617
    IDirectPlay4Impl_SendEx,
5618
    IDirectPlay4Impl_GetMessageQueue,
5619 5620
    IDirectPlay4Impl_CancelMessage,
    IDirectPlay4Impl_CancelPriority
5621 5622
};

5623
static const IDirectPlay4Vtbl dp4A_vt =
5624
{
5625 5626 5627
    IDirectPlay4AImpl_QueryInterface,
    IDirectPlay4AImpl_AddRef,
    IDirectPlay4AImpl_Release,
5628 5629 5630 5631 5632 5633 5634 5635
    IDirectPlay4AImpl_AddPlayerToGroup,
    IDirectPlay4AImpl_Close,
    IDirectPlay4AImpl_CreateGroup,
    IDirectPlay4AImpl_CreatePlayer,
    IDirectPlay4AImpl_DeletePlayerFromGroup,
    IDirectPlay4AImpl_DestroyGroup,
    IDirectPlay4AImpl_DestroyPlayer,
    IDirectPlay4AImpl_EnumGroupPlayers,
5636
    IDirectPlay4AImpl_EnumGroups,
5637
    IDirectPlay4AImpl_EnumPlayers,
5638 5639 5640 5641
    IDirectPlay4AImpl_EnumSessions,
    IDirectPlay4AImpl_GetCaps,
    IDirectPlay4AImpl_GetGroupData,
    IDirectPlay4AImpl_GetGroupName,
5642
    IDirectPlay4AImpl_GetMessageCount,
5643 5644 5645 5646 5647 5648
    IDirectPlay4AImpl_GetPlayerAddress,
    IDirectPlay4AImpl_GetPlayerCaps,
    IDirectPlay4AImpl_GetPlayerData,
    IDirectPlay4AImpl_GetPlayerName,
    IDirectPlay4AImpl_GetSessionDesc,
    IDirectPlay4AImpl_Initialize,
5649
    IDirectPlay4AImpl_Open,
5650
    IDirectPlay4AImpl_Receive,
5651
    IDirectPlay4AImpl_Send,
5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671
    IDirectPlay4AImpl_SetGroupData,
    IDirectPlay4AImpl_SetGroupName,
    IDirectPlay4AImpl_SetPlayerData,
    IDirectPlay4AImpl_SetPlayerName,
    IDirectPlay4AImpl_SetSessionDesc,
    IDirectPlay4AImpl_AddGroupToGroup,
    IDirectPlay4AImpl_CreateGroupInGroup,
    IDirectPlay4AImpl_DeleteGroupFromGroup,
    IDirectPlay4AImpl_EnumConnections,
    IDirectPlay4AImpl_EnumGroupsInGroup,
    IDirectPlay4AImpl_GetGroupConnectionSettings,
    IDirectPlay4AImpl_InitializeConnection,
    IDirectPlay4AImpl_SecureOpen,
    IDirectPlay4AImpl_SendChatMessage,
    IDirectPlay4AImpl_SetGroupConnectionSettings,
    IDirectPlay4AImpl_StartSession,
    IDirectPlay4AImpl_GetGroupFlags,
    IDirectPlay4AImpl_GetGroupParent,
    IDirectPlay4AImpl_GetPlayerAccount,
    IDirectPlay4AImpl_GetPlayerFlags,
5672 5673
    IDirectPlay4AImpl_GetGroupOwner,
    IDirectPlay4AImpl_SetGroupOwner,
5674
    IDirectPlay4AImpl_SendEx,
5675
    IDirectPlay4AImpl_GetMessageQueue,
5676 5677
    IDirectPlay4AImpl_CancelMessage,
    IDirectPlay4AImpl_CancelPriority
5678 5679
};

5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691
HRESULT dplay_create( REFIID riid, void **ppv )
{
    IDirectPlayImpl *obj;
    HRESULT hr;

    TRACE( "(%s, %p)\n", debugstr_guid( riid ), ppv );

    *ppv = NULL;
    obj = HeapAlloc( GetProcessHeap(), 0, sizeof( *obj ) );
    if ( !obj )
        return DPERR_OUTOFMEMORY;

5692
    obj->IDirectPlay_iface.lpVtbl = &dp_vt;
5693
    obj->IDirectPlay2A_iface.lpVtbl = &dp2A_vt;
5694
    obj->IDirectPlay2_iface.lpVtbl = &dp2_vt;
5695
    obj->IDirectPlay3A_iface.lpVtbl = &dp3A_vt;
5696
    obj->IDirectPlay3_iface.lpVtbl = &dp3_vt;
5697 5698
    obj->IDirectPlay4A_iface.lpVtbl = &dp4A_vt;
    obj->IDirectPlay4_iface.lpVtbl = &dp4_vt;
5699
    obj->numIfaces = 1;
5700
    obj->ref = 0;
5701
    obj->ref2A = 0;
5702
    obj->ref2 = 0;
5703
    obj->ref3A = 0;
5704
    obj->ref3 = 0;
5705 5706
    obj->ref4A = 0;
    obj->ref4 = 1;
5707 5708 5709 5710 5711

    InitializeCriticalSection( &obj->lock );
    obj->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlayImpl.lock");

    if ( DP_CreateDirectPlay2( obj ) )
5712
        hr = IDirectPlayX_QueryInterface( &obj->IDirectPlay4_iface, riid, ppv );
5713 5714
    else
        hr = DPERR_NOMEMORY;
5715
    IDirectPlayX_Release( &obj->IDirectPlay4_iface );
5716 5717 5718 5719 5720

    return hr;
}


5721
HRESULT DP_GetSPPlayerData( IDirectPlayImpl *lpDP, DPID idPlayer, void **lplpData )
5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734
{
  lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );

  if( lpPlayer == NULL )
  {
    return DPERR_INVALIDPLAYER;
  }

  *lplpData = lpPlayer->lpPData->lpSPPlayerData;

  return DP_OK;
}

5735
HRESULT DP_SetSPPlayerData( IDirectPlayImpl *lpDP, DPID idPlayer, void *lpData )
5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747
{
  lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );

  if( lpPlayer == NULL )
  {
    return DPERR_INVALIDPLAYER;
  }

  lpPlayer->lpPData->lpSPPlayerData = lpData;

  return DP_OK;
}
5748 5749

/***************************************************************************
5750
 *  DirectPlayEnumerateAW
5751
 *
5752
 *  The pointer to the structure lpContext will be filled with the
5753 5754 5755
 *  appropriate data for each service offered by the OS. These services are
 *  not necessarily available on this particular machine but are defined
 *  as simple service providers under the "Service Providers" registry key.
5756 5757
 *  This structure is then passed to lpEnumCallback for each of the different
 *  services.
5758 5759
 *
 *  This API is useful only for applications written using DirectX3 or
Francois Gouget's avatar
Francois Gouget committed
5760
 *  worse. It is superseded by IDirectPlay3::EnumConnections which also
5761 5762 5763
 *  gives information on the actual connections.
 *
 * defn of a service provider:
5764
 * A dynamic-link library used by DirectPlay to communicate over a network.
5765 5766 5767
 * The service provider contains all the network-specific code required
 * to send and receive messages. Online services and network operators can
 * supply service providers to use specialized hardware, protocols, communications
5768
 * media, and network resources.
5769 5770
 *
 */
5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785
static HRESULT DirectPlayEnumerateAW(LPDPENUMDPCALLBACKA lpEnumCallbackA,
                                     LPDPENUMDPCALLBACKW lpEnumCallbackW,
                                     LPVOID lpContext)
{
    HKEY   hkResult;
    static const WCHAR searchSubKey[] = {
	'S', 'O', 'F', 'T', 'W', 'A', 'R', 'E', '\\',
	'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', '\\',
	'D', 'i', 'r', 'e', 'c', 't', 'P', 'l', 'a', 'y', '\\',
	'S', 'e', 'r', 'v', 'i', 'c', 'e', ' ', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r', 's', 0 };
    static const WCHAR guidKey[] = { 'G', 'u', 'i', 'd', 0 };
    static const WCHAR descW[] = { 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 'W', 0 };
    
    DWORD  dwIndex;
    FILETIME filetime;
5786

5787 5788 5789 5790
    char  *descriptionA = NULL;
    DWORD max_sizeOfDescriptionA = 0;
    WCHAR *descriptionW = NULL;
    DWORD max_sizeOfDescriptionW = 0;
5791 5792 5793 5794 5795
    DWORD sizeOfSubKeyName;
    WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
    LONG  ret_value;
    static GUID *guid_cache;
    static int cache_count;
5796 5797
    
    if (!lpEnumCallbackA && !lpEnumCallbackW)
5798
    {
5799
	return DPERR_INVALIDPARAMS;
5800
    }
5801 5802 5803 5804
    
    /* Need to loop over the service providers in the registry */
    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
		      0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5805
    {
5806 5807 5808
	/* Hmmm. Does this mean that there are no service providers? */
	ERR(": no service provider key in the registry - check your Wine installation !!!\n");
	return DPERR_GENERIC;
5809
    }
5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826

    dwIndex = 0;
    do
    {
	sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
	ret_value = RegEnumKeyW(hkResult, dwIndex, subKeyName, sizeOfSubKeyName);
	dwIndex++;
    }
    while (ret_value == ERROR_SUCCESS);
    /* The game Swing from bug 37185 expects GUID values to persist after
     * the end of the enumeration. */
    if (cache_count < dwIndex)
    {
	HeapFree(GetProcessHeap(), 0, guid_cache);
	guid_cache = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID) * dwIndex);
	if (!guid_cache)
	{
5827
	    ERR(": failed to allocate required memory.\n");
5828 5829 5830 5831
	    return DPERR_EXCEPTION;
	}
	cache_count = dwIndex;
    }
5832 5833 5834
    /* Traverse all the service providers we have available */
    dwIndex = 0;
    while (1)
5835
    {
5836 5837 5838 5839
	HKEY  hkServiceProvider;
	WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
	DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
	
5840
	sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870
	ret_value = RegEnumKeyExW(hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
				  NULL, NULL, NULL, &filetime);
	if (ret_value == ERROR_NO_MORE_ITEMS)
	    break;
	else if (ret_value != ERROR_SUCCESS)
	{
	    ERR(": could not enumerate on service provider key.\n");
	    return DPERR_EXCEPTION;
	}
	TRACE(" this time through sub-key %s.\n", debugstr_w(subKeyName));
	
	/* Open the key for this service provider */
	if (RegOpenKeyExW(hkResult, subKeyName, 0, KEY_READ, &hkServiceProvider) != ERROR_SUCCESS)
	{
	    ERR(": could not open registry key for service provider %s.\n", debugstr_w(subKeyName));
	    continue;
	}
	
	/* Get the GUID from the registry */
	if (RegQueryValueExW(hkServiceProvider, guidKey,
			     NULL, NULL, (LPBYTE) guidKeyContent, &sizeOfGuidKeyContent) != ERROR_SUCCESS)
	{
	    ERR(": missing GUID registry data member for service provider %s.\n", debugstr_w(subKeyName));
	    continue;
	}
	if (sizeOfGuidKeyContent != sizeof(guidKeyContent))
	{
	    ERR(": invalid format for the GUID registry data member for service provider %s (%s).\n", debugstr_w(subKeyName), debugstr_w(guidKeyContent));
	    continue;
	}
5871
	CLSIDFromString(guidKeyContent, &guid_cache[dwIndex]);
5872 5873 5874 5875
	
	/* The enumeration will return FALSE if we are not to continue.
	 *
	 * Note: on my windows box, major / minor version is 6 / 0 for all service providers
5876
	 *       and have no relation to any of the two dwReserved1 and dwReserved2 keys.
5877 5878 5879 5880 5881 5882
	 *       I think that it simply means that they are in-line with DirectX 6.0
	 */
	if (lpEnumCallbackA)
	{
	    DWORD sizeOfDescription = 0;
	    
5883
	    /* Note that this is the A case of this function, so use the A variant to get the description string */
5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898
	    if (RegQueryValueExA(hkServiceProvider, "DescriptionA",
				 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
	    {
		ERR(": missing 'DescriptionA' registry data member for service provider %s.\n", debugstr_w(subKeyName));
		continue;
	    }
	    if (sizeOfDescription > max_sizeOfDescriptionA)
	    {
		HeapFree(GetProcessHeap(), 0, descriptionA);
		max_sizeOfDescriptionA = sizeOfDescription;
	    }
	    descriptionA = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
	    RegQueryValueExA(hkServiceProvider, "DescriptionA",
			     NULL, NULL, (LPBYTE) descriptionA, &sizeOfDescription);
	    
5899
	    if (!lpEnumCallbackA(&guid_cache[dwIndex], descriptionA, 6, 0, lpContext))
5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920
		goto end;
	}
	else
	{
	    DWORD sizeOfDescription = 0;
	    
	    if (RegQueryValueExW(hkServiceProvider, descW,
				 NULL, NULL, NULL, &sizeOfDescription) != ERROR_SUCCESS)
	    {
		ERR(": missing 'DescriptionW' registry data member for service provider %s.\n", debugstr_w(subKeyName));
		continue;
	    }
	    if (sizeOfDescription > max_sizeOfDescriptionW)
	    {
		HeapFree(GetProcessHeap(), 0, descriptionW);
		max_sizeOfDescriptionW = sizeOfDescription;
	    }
	    descriptionW = HeapAlloc(GetProcessHeap(), 0, sizeOfDescription);
	    RegQueryValueExW(hkServiceProvider, descW,
			     NULL, NULL, (LPBYTE) descriptionW, &sizeOfDescription);

5921
	    if (!lpEnumCallbackW(&guid_cache[dwIndex], descriptionW, 6, 0, lpContext))
5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933
		goto end;
	}
      
      dwIndex++;
  }

 end:
    HeapFree(GetProcessHeap(), 0, descriptionA);
    HeapFree(GetProcessHeap(), 0, descriptionW);
    
    return DP_OK;
}
5934

5935 5936 5937 5938 5939 5940 5941 5942 5943
/***************************************************************************
 *  DirectPlayEnumerate  [DPLAYX.9]
 *  DirectPlayEnumerateA [DPLAYX.2]
 */
HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
{
    TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
    
    return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5944 5945 5946
}

/***************************************************************************
5947
 *  DirectPlayEnumerateW [DPLAYX.3]
5948
 */
5949
HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5950
{
5951 5952 5953
    TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
    
    return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5954 5955
}

5956 5957 5958
typedef struct tagCreateEnum
{
  LPVOID  lpConn;
5959
  LPCGUID lpGuid;
5960 5961 5962
} CreateEnumData, *lpCreateEnumData;

/* Find and copy the matching connection for the SP guid */
5963
static BOOL CALLBACK cbDPCreateEnumConnections(
5964 5965 5966 5967 5968 5969 5970
    LPCGUID     lpguidSP,
    LPVOID      lpConnection,
    DWORD       dwConnectionSize,
    LPCDPNAME   lpName,
    DWORD       dwFlags,
    LPVOID      lpContext)
{
5971
  lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989

  if( IsEqualGUID( lpguidSP, lpData->lpGuid ) )
  {
    TRACE( "Found SP entry with guid %s\n", debugstr_guid(lpData->lpGuid) );

    lpData->lpConn = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                dwConnectionSize );
    CopyMemory( lpData->lpConn, lpConnection, dwConnectionSize );

    /* Found the record that we were looking for */
    return FALSE;
  }

  /* Haven't found what were looking for yet */
  return TRUE;
}


5990
/***************************************************************************
5991
 *  DirectPlayCreate [DPLAYX.1]
5992 5993 5994
 *
 */
HRESULT WINAPI DirectPlayCreate
5995
( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
5996
{
5997 5998 5999
  HRESULT hr;
  LPDIRECTPLAY3A lpDP3A;
  CreateEnumData cbData;
6000

6001
  TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
6002 6003 6004

  if( pUnk != NULL )
  {
6005
    return CLASS_E_NOAGGREGATION;
6006 6007
  }

6008 6009 6010 6011 6012
  if( (lplpDP == NULL) || (lpGUID == NULL) )
  {
    return DPERR_INVALIDPARAMS;
  }

6013
  if ( dplay_create( &IID_IDirectPlay, (void**)lplpDP ) != DP_OK )
6014 6015
    return DPERR_UNAVAILABLE;

6016 6017 6018
  if( IsEqualGUID( &GUID_NULL, lpGUID ) )
  {
    /* The GUID_NULL means don't bind a service provider. Just return the
6019
       interface as is */
6020 6021 6022
    return DP_OK;
  }

6023 6024
  /* Bind the desired service provider since lpGUID is non NULL */
  TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
6025

6026
  /* We're going to use a DP3 interface */
6027
  hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
6028 6029 6030
                                    (LPVOID*)&lpDP3A );
  if( FAILED(hr) )
  {
6031
    ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
6032 6033 6034 6035 6036 6037 6038
    return hr;
  }

  cbData.lpConn = NULL;
  cbData.lpGuid = lpGUID;

  /* We were given a service provider, find info about it... */
6039
  hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
6040 6041
                                     &cbData, DPCONNECTION_DIRECTPLAY );
  if( ( FAILED(hr) ) ||
6042
      ( cbData.lpConn == NULL )
6043
    )
6044
  {
6045
    ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
6046 6047
    IDirectPlayX_Release( lpDP3A );
    return DPERR_UNAVAILABLE;
6048 6049
  }

6050 6051
  /* Initialize the service provider */
  hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
6052
  if( FAILED(hr) )
6053 6054 6055 6056 6057 6058
  {
    ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
    HeapFree( GetProcessHeap(), 0, cbData.lpConn );
    IDirectPlayX_Release( lpDP3A );
    return hr;
  }
6059

6060 6061 6062
  /* Release our version of the interface now that we're done with it */
  IDirectPlayX_Release( lpDP3A );
  HeapFree( GetProcessHeap(), 0, cbData.lpConn );
6063

6064
  return DP_OK;
6065
}