dplay.c 167 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
#include "config.h"
21
#include "wine/port.h"
22

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

26 27
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
28
#include "windef.h"
29
#include "winerror.h"
30
#include "winbase.h"
31 32
#include "winnt.h"
#include "winreg.h"
33
#include "winnls.h"
34
#include "wine/unicode.h"
35
#include "wine/debug.h"
36

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

44
WINE_DEFAULT_DEBUG_CHANNEL(dplay);
45

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

51 52

/* Local function prototypes */
53
static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid );
54
static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid,
55 56
                                     LPDPNAME lpName, DWORD dwFlags,
                                     HANDLE hEvent, BOOL bAnsi );
57
static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi );
58 59
static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
                              LPVOID lpData, DWORD dwDataSize );
60

61 62
static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, const DPID *lpid,
                                   const DPNAME *lpName, DWORD dwFlags,
63 64 65
                                   DPID idParent, BOOL bAnsi );
static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
                             LPVOID lpData, DWORD dwDataSize );
66 67
static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid );
68 69 70 71
static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
                                                  DWORD dwPlayerType,
                                                  LPCDPNAME lpName,
                                                  DWORD dwFlags,
Peter Hunnisett's avatar
Peter Hunnisett committed
72
                                                  LPVOID lpContext );
73
static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
74 75
static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType,
                                            LPCDPNAME lpName, DWORD dwFlags,
Peter Hunnisett's avatar
Peter Hunnisett committed
76
                                            LPVOID lpContext );
77
static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
78

79
/* Forward declarations of virtual tables */
80 81 82
static const IDirectPlay2Vtbl directPlay2AVT;
static const IDirectPlay3Vtbl directPlay3AVT;
static const IDirectPlay4Vtbl directPlay4AVT;
83

84 85 86
static const IDirectPlay2Vtbl directPlay2WVT;
static const IDirectPlay3Vtbl directPlay3WVT;
static const IDirectPlay4Vtbl directPlay4WVT;
87

88
/* Helper methods for player/group interfaces */
89
static HRESULT DP_IF_DeletePlayerFromGroup
90
          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
91
            DPID idPlayer, BOOL bAnsi );
92
static HRESULT DP_IF_CreatePlayer
93 94
          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, LPDPID lpidPlayer,
            LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData,
95
            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
96
static HRESULT DP_IF_DestroyGroup
97
          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi );
98
static HRESULT DP_IF_DestroyPlayer
99
          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi );
100
static HRESULT DP_IF_EnumGroupPlayers
101
          ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
102 103
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
104
static HRESULT DP_IF_EnumGroups
105 106
          ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
107
            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
108
static HRESULT DP_IF_EnumPlayers
109 110
          ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
111
            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
112
static HRESULT DP_IF_GetGroupData
113
          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
114
            LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
115
static HRESULT DP_IF_GetGroupName
116
          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
117
            LPDWORD lpdwDataSize, BOOL bAnsi );
118
static HRESULT DP_IF_GetPlayerData
119 120
          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
            LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
121
static HRESULT DP_IF_GetPlayerName
122 123
          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
            LPDWORD lpdwDataSize, BOOL bAnsi );
124
static HRESULT DP_IF_SetGroupName
125
          ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
126
            DWORD dwFlags, BOOL bAnsi );
127
static HRESULT DP_IF_SetPlayerData
128
          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
129
            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
130
static HRESULT DP_IF_SetPlayerName
131
          ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
132
            DWORD dwFlags, BOOL bAnsi );
133
static HRESULT DP_IF_AddGroupToGroup
134
          ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
135
static HRESULT DP_IF_CreateGroup
136 137
          ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
            LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
138
            DWORD dwFlags, BOOL bAnsi );
139
static HRESULT DP_IF_CreateGroupInGroup
140 141
          ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
            LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
142
            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
143
static HRESULT DP_IF_AddPlayerToGroup
144
          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
145
            DPID idPlayer, BOOL bAnsi );
146
static HRESULT DP_IF_DeleteGroupFromGroup
147
          ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
148
static HRESULT DP_SetSessionDesc
149
          ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
150
            DWORD dwFlags, BOOL bInitial, BOOL bAnsi  );
151
static HRESULT DP_SecureOpen
152
          ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
153 154
            LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
            BOOL bAnsi );
155
static HRESULT DP_SendEx
156 157 158
          ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
            LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
            LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi );
159
static HRESULT DP_IF_Receive
160 161
          ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
            DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
162
static HRESULT DP_IF_GetMessageQueue
163 164
          ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
            LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
165
static HRESULT DP_SP_SendEx
166 167 168
          ( IDirectPlay2Impl* This, DWORD dwFlags,
            LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
            LPVOID lpContext, LPDWORD lpdwMsgID );
169
static HRESULT DP_IF_SetGroupData
170 171
          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
172
static HRESULT DP_IF_GetPlayerCaps
173 174
          ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
            DWORD dwFlags );
175 176
static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi );
static HRESULT DP_IF_CancelMessage
177 178
          ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
            DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
179
static HRESULT DP_IF_EnumGroupsInGroup
180
          ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
181
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
182
            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
183
static HRESULT DP_IF_GetGroupParent
184 185
          ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
            BOOL bAnsi );
186
static HRESULT DP_IF_GetCaps
Peter Hunnisett's avatar
Peter Hunnisett committed
187
          ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
188
static HRESULT DP_IF_EnumSessions
Peter Hunnisett's avatar
Peter Hunnisett committed
189 190 191
          ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
            LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
192
static HRESULT DP_IF_InitializeConnection
193
          ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi );
Peter Hunnisett's avatar
Peter Hunnisett committed
194 195 196
static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
    LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
    DWORD dwFlags, LPVOID lpContext );
197 198
static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
                                    LPDWORD lpdwBufSize );
Peter Hunnisett's avatar
Peter Hunnisett committed
199

200 201 202


static inline DPID DP_NextObjectId(void);
Peter Hunnisett's avatar
Peter Hunnisett committed
203 204
static DPID DP_GetRemoteNextObjectId(void);

205
static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi );
206
static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
207 208
                                LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );

209

210
static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
211 212 213
static HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );

214 215 216



217

218 219

#define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
220
#define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
221 222 223 224 225 226 227 228 229
                                                 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

230
static LONG kludgePlayerGroupId = 1000;
231 232 233 234

/* ------------------------------------------------------------------ */


235
static BOOL DP_CreateIUnknown( LPVOID lpDP )
236
{
237
  IDirectPlay2AImpl *This = lpDP;
238

239
  This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) );
240 241 242 243 244 245
  if ( This->unk == NULL )
  {
    return FALSE;
  }

  InitializeCriticalSection( &This->unk->DP_lock );
246
  This->unk->DP_lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectPlay2AImpl*->DirectPlayIUnknownData*->DP_lock");
247 248 249 250

  return TRUE;
}

251
static BOOL DP_DestroyIUnknown( LPVOID lpDP )
252
{
253
  IDirectPlay2AImpl *This = lpDP;
254

255
  This->unk->DP_lock.DebugInfo->Spare[0] = 0;
256 257 258 259 260 261
  DeleteCriticalSection( &This->unk->DP_lock );
  HeapFree( GetProcessHeap(), 0, This->unk );

  return TRUE;
}

262
static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
263
{
264
  IDirectPlay2AImpl *This = lpDP;
265

266
  This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
267 268 269 270 271
  if ( This->dp2 == NULL )
  {
    return FALSE;
  }

272 273 274
  This->dp2->bConnectionOpen = FALSE;

  This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
275
  This->dp2->dwEnumSessionLock = 0;
276

277 278
  This->dp2->bHostInterface = FALSE;

279 280
  DPQ_INIT(This->dp2->receiveMsgs);
  DPQ_INIT(This->dp2->sendMsgs);
281
  DPQ_INIT(This->dp2->replysExpected);
282

283 284
  if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
  {
285 286 287 288 289
    /* FIXME: Memory leak */
    return FALSE;
  }

  /* Provide an initial session desc with nothing in it */
290 291 292
  This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
                                        HEAP_ZERO_MEMORY,
                                        sizeof( *This->dp2->lpSessionDesc ) );
293 294 295 296 297 298 299
  if( This->dp2->lpSessionDesc == NULL )
  {
    /* FIXME: Memory leak */
    return FALSE;
  }
  This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );

300
  /* We are emulating a dp 6 implementation */
301 302 303 304 305 306
  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;
307

308
  /* This is the pointer to the service provider */
309
  if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
310 311 312 313
                                    (LPVOID*)&This->dp2->spData.lpISP, This ) )
    )
  {
    /* FIXME: Memory leak */
314 315 316
    return FALSE;
  }

317 318 319 320 321 322 323 324 325 326 327 328 329 330
  /* 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 );

  if( FAILED( DPLSP_CreateInterface( &IID_IDPLobbySP,
                                     (LPVOID*)&This->dp2->dplspData.lpISP, This ) )
    )
  {
    /* FIXME: Memory leak */
    return FALSE;
  }

331 332 333
  return TRUE;
}

334 335 336
/* 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 )
337
{
338 339 340 341 342
  HeapFree( GetProcessHeap(), 0, elem );
}

static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
{
343
  IDirectPlay2AImpl *This = lpDP;
344

345 346 347 348 349
  if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
  {
    TerminateThread( This->dp2->hEnumSessionThread, 0 );
    CloseHandle( This->dp2->hEnumSessionThread );
  }
350

Peter Hunnisett's avatar
Peter Hunnisett committed
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
  /* 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)();
  }

368
  /* Unload the SP (if it exists) */
Peter Hunnisett's avatar
Peter Hunnisett committed
369 370 371 372 373
  if( This->dp2->hServiceProvider != 0 )
  {
    FreeLibrary( This->dp2->hServiceProvider );
  }

374 375 376 377 378
  /* Unload the Lobby Provider (if it exists) */
  if( This->dp2->hDPLobbyProvider != 0 )
  {
    FreeLibrary( This->dp2->hDPLobbyProvider );
  }
Peter Hunnisett's avatar
Peter Hunnisett committed
379

380
  /* FIXME: Need to delete receive and send msgs queue contents */
381

382
  NS_DeleteSessionCache( This->dp2->lpNameServerData );
383 384 385 386 387

  HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );

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

388 389 390 391 392 393
  /* Delete the contents */
  HeapFree( GetProcessHeap(), 0, This->dp2 );

  return TRUE;
}

394
static BOOL DP_CreateDirectPlay3( LPVOID lpDP )
395
{
396
  IDirectPlay3AImpl *This = lpDP;
397

398
  This->dp3 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp3) ) );
399 400 401 402 403 404 405 406
  if ( This->dp3 == NULL )
  {
    return FALSE;
  }

  return TRUE;
}

407
static BOOL DP_DestroyDirectPlay3( LPVOID lpDP )
408
{
409
  IDirectPlay3AImpl *This = lpDP;
410 411 412 413 414 415 416

  /* Delete the contents */
  HeapFree( GetProcessHeap(), 0, This->dp3 );

  return TRUE;
}

417
static BOOL DP_CreateDirectPlay4( LPVOID lpDP )
418
{
419
  IDirectPlay4AImpl *This = lpDP;
420

421
  This->dp4 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp4) ) );
422 423 424 425 426 427 428 429
  if ( This->dp4 == NULL )
  {
    return FALSE;
  }

  return TRUE;
}

430
static BOOL DP_DestroyDirectPlay4( LPVOID lpDP )
431
{
432
  IDirectPlay3AImpl *This = lpDP;
433 434 435 436 437 438

  /* Delete the contents */
  HeapFree( GetProcessHeap(), 0, This->dp4 );

  return TRUE;
}
439

440

441 442
/* Create a new interface */
HRESULT DP_CreateInterface
443 444
         ( REFIID riid, LPVOID* ppvObj )
{
445
  TRACE( " for %s\n", debugstr_guid( riid ) );
446

447 448
  *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                       sizeof( IDirectPlay2Impl ) );
449

450 451 452 453
  if( *ppvObj == NULL )
  {
    return DPERR_OUTOFMEMORY;
  }
454

455 456
  if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
  {
457
    IDirectPlay2Impl *This = *ppvObj;
458
    This->lpVtbl = &directPlay2WVT;
459
  }
460 461
  else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
  {
462
    IDirectPlay2AImpl *This = *ppvObj;
463
    This->lpVtbl = &directPlay2AVT;
464 465 466
  }
  else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
  {
467
    IDirectPlay3Impl *This = *ppvObj;
468
    This->lpVtbl = &directPlay3WVT;
469 470 471
  }
  else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
  {
472
    IDirectPlay3AImpl *This = *ppvObj;
473
    This->lpVtbl = &directPlay3AVT;
474 475 476
  }
  else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
  {
477
    IDirectPlay4Impl *This = *ppvObj;
478
    This->lpVtbl = &directPlay4WVT;
479 480 481
  }
  else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
  {
482
    IDirectPlay4AImpl *This = *ppvObj;
483
    This->lpVtbl = &directPlay4AVT;
484 485 486 487 488 489
  }
  else
  {
    /* Unsupported interface */
    HeapFree( GetProcessHeap(), 0, *ppvObj );
    *ppvObj = NULL;
490

491
    return E_NOINTERFACE;
492 493
  }

494 495 496 497 498 499 500 501
  /* Initialize it */
  if ( DP_CreateIUnknown( *ppvObj ) &&
       DP_CreateDirectPlay2( *ppvObj ) &&
       DP_CreateDirectPlay3( *ppvObj ) &&
       DP_CreateDirectPlay4( *ppvObj )
     )
  {
    IDirectPlayX_AddRef( (LPDIRECTPLAY2A)*ppvObj );
502

503 504
    return S_OK;
  }
505

506 507 508 509 510
  /* Initialize failed, destroy it */
  DP_DestroyDirectPlay4( *ppvObj );
  DP_DestroyDirectPlay3( *ppvObj );
  DP_DestroyDirectPlay2( *ppvObj );
  DP_DestroyIUnknown( *ppvObj );
511

512
  HeapFree( GetProcessHeap(), 0, *ppvObj );
513

514 515
  *ppvObj = NULL;
  return DPERR_NOMEMORY;
516 517 518 519
}


/* Direct Play methods */
520 521 522

/* Shared between all dplay types */
static HRESULT WINAPI DP_QueryInterface
523 524
         ( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj )
{
525
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
526
  TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
527

528
  *ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
529
                       sizeof( *This ) );
530 531

  if( *ppvObj == NULL )
532
  {
533
    return DPERR_OUTOFMEMORY;
534 535
  }

536
  CopyMemory( *ppvObj, This, sizeof( *This )  );
537
  (*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
538

539
  if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
540
  {
541
    IDirectPlay2Impl *This = *ppvObj;
542
    This->lpVtbl = &directPlay2WVT;
543
  }
544
  else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
545
  {
546
    IDirectPlay2AImpl *This = *ppvObj;
547
    This->lpVtbl = &directPlay2AVT;
548
  }
549
  else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
550
  {
551
    IDirectPlay3Impl *This = *ppvObj;
552
    This->lpVtbl = &directPlay3WVT;
553
  }
554
  else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
555
  {
556
    IDirectPlay3AImpl *This = *ppvObj;
557
    This->lpVtbl = &directPlay3AVT;
558
  }
559
  else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
560
  {
561
    IDirectPlay4Impl *This = *ppvObj;
562
    This->lpVtbl = &directPlay4WVT;
563 564 565
  }
  else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
  {
566
    IDirectPlay4AImpl *This = *ppvObj;
567
    This->lpVtbl = &directPlay4AVT;
568 569 570 571 572 573 574 575
  }
  else
  {
    /* Unsupported interface */
    HeapFree( GetProcessHeap(), 0, *ppvObj );
    *ppvObj = NULL;

    return E_NOINTERFACE;
576 577
  }

578
  IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj );
579

580 581
  return S_OK;
}
582 583

/* Shared between all dplay types */
584
static ULONG WINAPI DP_AddRef
585 586
         ( LPDIRECTPLAY3 iface )
{
587
  ULONG ulInterfaceRefCount, ulObjRefCount;
588
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
589

590 591
  ulObjRefCount       = InterlockedIncrement( &This->unk->ulObjRef );
  ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
592

593
  TRACE( "ref count incremented to %u:%u for %p\n",
594
         ulInterfaceRefCount, ulObjRefCount, This );
595

596
  return ulObjRefCount;
597 598
}

599
static ULONG WINAPI DP_Release
600 601
( LPDIRECTPLAY3 iface )
{
602
  ULONG ulInterfaceRefCount, ulObjRefCount;
603

604
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
605

606 607
  ulObjRefCount       = InterlockedDecrement( &This->unk->ulObjRef );
  ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
608

609
  TRACE( "ref count decremented to %u:%u for %p\n",
610
         ulInterfaceRefCount, ulObjRefCount, This );
611 612

  /* Deallocate if this is the last reference to the object */
613
  if( ulObjRefCount == 0 )
614
  {
615 616
     /* If we're destroying the object, this must be the last ref
        of the last interface */
617 618 619 620
     DP_DestroyDirectPlay4( This );
     DP_DestroyDirectPlay3( This );
     DP_DestroyDirectPlay2( This );
     DP_DestroyIUnknown( This );
621
  }
622

623 624 625 626
  /* Deallocate the interface */
  if( ulInterfaceRefCount == 0 )
  {
    HeapFree( GetProcessHeap(), 0, This );
627 628
  }

629
  return ulObjRefCount;
630 631
}

632
static inline DPID DP_NextObjectId(void)
633
{
634 635 636
  return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
}

Peter Hunnisett's avatar
Peter Hunnisett committed
637
/* *lplpReply will be non NULL iff there is something to reply */
638 639
HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
                          DWORD  dwMessageBodySize, LPCVOID lpcMessageHeader,
640
                          WORD wCommandId, WORD wVersion,
Peter Hunnisett's avatar
Peter Hunnisett committed
641 642
                          LPVOID* lplpReply, LPDWORD lpdwMsgSize )
{
643
  TRACE( "(%p)->(%p,0x%08x,%p,%u,%u)\n",
644
         This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
Peter Hunnisett's avatar
Peter Hunnisett committed
645 646 647 648
         wVersion );

  switch( wCommandId )
  {
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
    /* 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,
664
                                        lpcMessageBody,
665 666 667 668
                                        This->dp2->lpNameServerData );
      break;
    }

Peter Hunnisett's avatar
Peter Hunnisett committed
669 670
    case DPMSGCMD_REQUESTNEWPLAYERID:
    {
671
      LPCDPMSG_REQUESTNEWPLAYERID lpcMsg = lpcMessageBody;
672

Peter Hunnisett's avatar
Peter Hunnisett committed
673 674 675 676
      LPDPMSG_NEWPLAYERIDREPLY lpReply;

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

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

679
      FIXME( "Ignoring dwFlags 0x%08x in request msg\n",
680
             lpcMsg->dwFlags );
Peter Hunnisett's avatar
Peter Hunnisett committed
681 682

      /* Setup the reply */
683
      lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
Peter Hunnisett's avatar
Peter Hunnisett committed
684 685 686
                                            This->dp2->spData.dwSPHeaderSize );

      lpReply->envelope.dwMagic    = DPMSGMAGIC_DPLAYMSG;
687 688
      lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
      lpReply->envelope.wVersion   = DPMSGVER_DP6;
Peter Hunnisett's avatar
Peter Hunnisett committed
689 690

      lpReply->dpidNewPlayerId = DP_NextObjectId();
691

692
      TRACE( "Allocating new playerid 0x%08x from remote request\n",
693
             lpReply->dpidNewPlayerId );
Peter Hunnisett's avatar
Peter Hunnisett committed
694 695 696 697

      break;
    }

698
    case DPMSGCMD_GETNAMETABLEREPLY:
Peter Hunnisett's avatar
Peter Hunnisett committed
699 700 701
    case DPMSGCMD_NEWPLAYERIDREPLY:
    {

702 703 704 705
#if 0
      if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
        DebugBreak();
#endif
706
      DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
707

Peter Hunnisett's avatar
Peter Hunnisett committed
708 709
      break;
    }
710

711 712 713
#if 1
    case DPMSGCMD_JUSTENVELOPE:
    {
714
      TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08x\n", lpcMessageHeader, ((const DWORD *)lpcMessageHeader)[1] );
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
      NS_SetLocalAddr( This->dp2->lpNameServerData, lpcMessageHeader, 20 );
      DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
    }
#endif

    case DPMSGCMD_FORWARDADDPLAYER:
    {
#if 0
      DebugBreak();
#endif
#if 1
    TRACE( "Sending message to self to get my addr\n" );
    DP_MSG_ToSelf( This, 1 ); /* This is a hack right now */
#endif
      break;
    }

732 733 734 735 736
    case DPMSGCMD_FORWARDADDPLAYERNACK:
    {
      DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
      break;
    }
Peter Hunnisett's avatar
Peter Hunnisett committed
737 738 739 740

    default:
    {
      FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
741
      DebugBreak();
Peter Hunnisett's avatar
Peter Hunnisett committed
742 743 744 745
      break;
    }
  }

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

Peter Hunnisett's avatar
Peter Hunnisett committed
748 749 750
  return DP_OK;
}

751

752
static HRESULT DP_IF_AddPlayerToGroup
753
          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
754 755 756
            DPID idPlayer, BOOL bAnsi )
{
  lpGroupData  lpGData;
757 758 759
  lpPlayerList lpPList;
  lpPlayerList lpNewPList;

760
  TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
761
         This, lpMsgHdr, idGroup, idPlayer, bAnsi );
762

763 764 765 766 767
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

768
  /* Find the group */
769
  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
770 771 772 773 774 775 776 777 778 779
  {
    return DPERR_INVALIDGROUP;
  }

  /* Find the player */
  if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
  {
    return DPERR_INVALIDPLAYER;
  }

780
  /* Create a player list (ie "shortcut" ) */
781
  lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
782
  if( lpNewPList == NULL )
783 784
  {
    return DPERR_CANTADDPLAYER;
785
  }
786 787

  /* Add the shortcut */
Peter Hunnisett's avatar
Peter Hunnisett committed
788
  lpPList->lpPData->uRef++;
789 790 791 792 793 794 795 796 797
  lpNewPList->lpPData = lpPList->lpPData;

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

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

799 800 801 802 803 804
    TRACE( "Calling SP AddPlayerToGroup\n" );

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

Peter Hunnisett's avatar
Peter Hunnisett committed
805
    (*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
806 807 808 809 810 811 812 813 814 815 816 817
  }

  /* 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( ( lpMsgHdr == NULL ) &&
      This->dp2->lpSessionDesc &&
      ( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
  {
    DPMSG_ADDPLAYERTOGROUP msg;
818
    msg.dwType = DPSYS_ADDPLAYERTOGROUP;
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834

    msg.dpIdGroup  = idGroup;
    msg.dpIdPlayer = idPlayer;

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

  return DP_OK;
}

static HRESULT WINAPI DirectPlay2AImpl_AddPlayerToGroup
          ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
{
835
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
836 837 838 839 840 841
  return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
}

static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
          ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
{
842
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
843 844 845
  return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
}

846
static HRESULT DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
847 848 849
{
  HRESULT hr = DP_OK;

Peter Hunnisett's avatar
Peter Hunnisett committed
850
  TRACE("(%p)->(%u)\n", This, bAnsi );
851 852 853 854 855 856 857 858 859 860 861 862 863

  /* 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 */

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

    TRACE( "Calling SP CloseEx\n" );

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

Peter Hunnisett's avatar
Peter Hunnisett committed
865
    hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
866

867 868 869 870 871
  }
  else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
  {
    TRACE( "Calling SP Close (obsolete interface)\n" );

Peter Hunnisett's avatar
Peter Hunnisett committed
872
    hr = (*This->dp2->spData.lpCB->Close)();
873
  }
874

875
  return hr;
876 877 878 879 880
}

static HRESULT WINAPI DirectPlay2AImpl_Close
          ( LPDIRECTPLAY2A iface )
{
881
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
882
  return DP_IF_Close( This, TRUE );
883 884 885 886 887
}

static HRESULT WINAPI DirectPlay2WImpl_Close
          ( LPDIRECTPLAY2 iface )
{
888
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
889
  return DP_IF_Close( This, FALSE );
890 891
}

892
static
893 894
lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, const DPID *lpid,
                            const DPNAME *lpName, DWORD dwFlags,
895
                            DPID idParent, BOOL bAnsi )
896
{
897
  lpGroupData lpGData;
898

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

902
  if( lpGData == NULL )
903 904 905 906
  {
    return NULL;
  }

907 908
  DPQ_INIT(lpGData->groups);
  DPQ_INIT(lpGData->players);
909

910 911
  /* Set the desired player ID - no sanity checking to see if it exists */
  lpGData->dpid = *lpid;
912

913
  DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
914

915 916
  /* FIXME: Should we check that the parent exists? */
  lpGData->parent  = idParent;
917

918 919 920
  /* FIXME: Should we validate the dwFlags? */
  lpGData->dwFlags = dwFlags;

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

923
  return lpGData;
924 925
}

926
/* This method assumes that all links to it are already deleted */
927
static void
928 929 930 931
DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
{
  lpGroupList lpGList;

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

934
  DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
935 936 937

  if( lpGList == NULL )
  {
938
    ERR( "DPID 0x%08x not found\n", dpid );
939 940 941
    return;
  }

Peter Hunnisett's avatar
Peter Hunnisett committed
942 943 944 945 946 947
  if( --(lpGList->lpGData->uRef) )
  {
    FIXME( "Why is this not the last reference to group?\n" );
    DebugBreak();
  }

948 949 950 951 952 953
  /* Delete player */
  DP_DeleteDPNameStruct( &lpGList->lpGData->name );
  HeapFree( GetProcessHeap(), 0, lpGList->lpGData );

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

955 956
}

957
static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
958 959 960
{
  lpGroupList lpGroups;

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

963
  if( dpid == DPID_SYSTEM_GROUP )
964
  {
965
    return This->dp2->lpSysGroup;
966 967 968
  }
  else
  {
969
    DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
970
  }
971

Peter Hunnisett's avatar
Peter Hunnisett committed
972 973 974 975
  if( lpGroups == NULL )
  {
    return NULL;
  }
976

977
  return lpGroups->lpGData;
978
}
979

980
static HRESULT DP_IF_CreateGroup
981 982
          ( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
            LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
983
            DWORD dwFlags, BOOL bAnsi )
984
{
985 986
  lpGroupData lpGData;

987
  TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
988
         This, lpMsgHdr, lpidGroup, lpGroupName, lpData, dwDataSize,
989
         dwFlags, bAnsi );
990

991 992 993 994 995
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
  /* 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
1008
      *lpidGroup = DP_GetRemoteNextObjectId();
1009 1010
    }
  }
1011

1012 1013
  lpGData = DP_CreateGroup( This, lpidGroup, lpGroupName, dwFlags,
                            DPID_NOPARENT_GROUP, bAnsi );
1014 1015 1016 1017 1018

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

1020 1021
  if( DPID_SYSTEM_GROUP == *lpidGroup )
  {
1022
    This->dp2->lpSysGroup = lpGData;
1023
    TRACE( "Inserting system group\n" );
1024 1025 1026 1027
  }
  else
  {
    /* Insert into the system group */
1028
    lpGroupList lpGroup = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGroup ) );
1029 1030 1031 1032 1033
    lpGroup->lpGData = lpGData;

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

Peter Hunnisett's avatar
Peter Hunnisett committed
1034 1035 1036
  /* Something is now referencing this data */
  lpGData->uRef++;

1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
  /* 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;
1065

Peter Hunnisett's avatar
Peter Hunnisett committed
1066
    (*This->dp2->spData.lpCB->CreateGroup)( &data );
1067 1068
  }

1069 1070
  /* Inform all other peers of the creation of a new group. If there are
   * no peers keep this event quiet.
1071 1072 1073
   * Also if this message was sent to us, don't rebroadcast.
   */
  if( ( lpMsgHdr == NULL ) &&
1074
      This->dp2->lpSessionDesc &&
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
      ( 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 */
    DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
               0, 0, NULL, NULL, bAnsi );
  }
1095

1096 1097 1098
  return DP_OK;
}

1099 1100 1101 1102 1103 1104
static HRESULT WINAPI DirectPlay2AImpl_CreateGroup
          ( LPDIRECTPLAY2A iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
            LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
{
  *lpidGroup = DPID_UNKNOWN;

1105
  return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1106 1107 1108 1109
                            lpGroupName, lpData, dwDataSize, dwFlags, TRUE );
}

static HRESULT WINAPI DirectPlay2WImpl_CreateGroup
1110
          ( LPDIRECTPLAY2 iface, LPDPID lpidGroup, LPDPNAME lpGroupName,
1111 1112 1113 1114
            LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
{
  *lpidGroup = DPID_UNKNOWN;

1115
  return DP_IF_CreateGroup( (IDirectPlay2AImpl*)iface, NULL, lpidGroup,
1116 1117 1118 1119
                            lpGroupName, lpData, dwDataSize, dwFlags, FALSE );
}


1120
static void
1121
DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
1122
                 LPVOID lpData, DWORD dwDataSize )
1123 1124
{
  /* Clear out the data with this player */
1125
  if( dwFlags & DPSET_LOCAL )
1126
  {
1127 1128 1129 1130 1131 1132
    if ( lpGData->dwLocalDataSize != 0 )
    {
      HeapFree( GetProcessHeap(), 0, lpGData->lpLocalData );
      lpGData->lpLocalData = NULL;
      lpGData->dwLocalDataSize = 0;
    }
1133
  }
1134
  else
1135
  {
1136 1137 1138 1139 1140 1141
    if( lpGData->dwRemoteDataSize != 0 )
    {
      HeapFree( GetProcessHeap(), 0, lpGData->lpRemoteData );
      lpGData->lpRemoteData = NULL;
      lpGData->dwRemoteDataSize = 0;
    }
1142 1143 1144
  }

  /* Reallocate for new data */
1145
  if( lpData != NULL )
1146
  {
1147 1148 1149
    LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                  sizeof( dwDataSize ) );
    CopyMemory( lpNewData, lpData, dwDataSize );
1150

1151 1152 1153 1154 1155
    if( dwFlags & DPSET_LOCAL )
    {
      lpGData->lpLocalData     = lpData;
      lpGData->dwLocalDataSize = dwDataSize;
    }
1156 1157 1158 1159 1160
    else
    {
      lpGData->lpRemoteData     = lpNewData;
      lpGData->dwRemoteDataSize = dwDataSize;
    }
1161
  }
1162

1163 1164
}

Peter Hunnisett's avatar
Peter Hunnisett committed
1165
/* This function will just create the storage for the new player.  */
1166 1167 1168
static
lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* This, LPDPID lpid,
                              LPDPNAME lpName, DWORD dwFlags,
1169
                              HANDLE hEvent, BOOL bAnsi )
1170
{
1171
  lpPlayerData lpPData;
1172 1173 1174

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

1175
  /* Allocate the storage for the player and associate it with list element */
1176
  lpPData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPData ) );
1177
  if( lpPData == NULL )
1178 1179 1180 1181
  {
    return NULL;
  }

1182 1183
  /* Set the desired player ID */
  lpPData->dpid = *lpid;
1184

1185
  DP_CopyDPNAMEStruct( &lpPData->name, lpName, bAnsi );
1186

1187
  lpPData->dwFlags = dwFlags;
1188

1189 1190 1191 1192 1193 1194 1195 1196 1197
  /* 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 */
1198
      ERR( "Can't duplicate player msg handle %p\n", hEvent );
1199 1200
    }
  }
1201

1202 1203 1204
  /* Initialize the SP data section */
  lpPData->lpSPPlayerData = DPSP_CreateSPPlayerData();

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

1207 1208 1209
  if( ~dwFlags & DPLAYI_PLAYER_SYSPLAYER )
    This->dp2->lpSessionDesc->dwCurrentPlayers++;

1210
  return lpPData;
1211 1212 1213 1214 1215 1216
}

/* Delete the contents of the DPNAME struct */
static void
DP_DeleteDPNameStruct( LPDPNAME lpDPName )
{
1217 1218
  HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u1.lpszShortNameA );
  HeapFree( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDPName->u2.lpszLongNameA );
1219 1220
}

1221 1222 1223
/* This method assumes that all links to it are already deleted */
static void
DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid )
1224
{
Peter Hunnisett's avatar
Peter Hunnisett committed
1225
  lpPlayerList lpPList;
1226

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

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

Peter Hunnisett's avatar
Peter Hunnisett committed
1231
  if( lpPList == NULL )
1232
  {
1233
    ERR( "DPID 0x%08x not found\n", dpid );
1234
    return;
1235
  }
Peter Hunnisett's avatar
Peter Hunnisett committed
1236 1237 1238 1239 1240

  /* 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" );
1241
    DebugBreak();
Peter Hunnisett's avatar
Peter Hunnisett committed
1242
  }
1243

1244
  /* Delete player */
Peter Hunnisett's avatar
Peter Hunnisett committed
1245
  DP_DeleteDPNameStruct( &lpPList->lpPData->name );
1246

Peter Hunnisett's avatar
Peter Hunnisett committed
1247 1248
  CloseHandle( lpPList->lpPData->hEvent );
  HeapFree( GetProcessHeap(), 0, lpPList->lpPData );
1249 1250

  /* Delete Player List object */
Peter Hunnisett's avatar
Peter Hunnisett committed
1251
  HeapFree( GetProcessHeap(), 0, lpPList );
1252 1253 1254 1255 1256 1257
}

static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid )
{
  lpPlayerList lpPlayers;

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

1260 1261 1262
  if(This->dp2->lpSysGroup == NULL)
    return NULL;

1263
  DPQ_FIND_ENTRY( This->dp2->lpSysGroup->players, players, lpPData->dpid, ==, dpid, lpPlayers );
1264 1265

  return lpPlayers;
1266 1267 1268
}

/* Basic area for Dst must already be allocated */
1269
static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, const DPNAME *lpSrc, BOOL bAnsi )
1270 1271 1272 1273 1274 1275 1276 1277
{
  if( lpSrc == NULL )
  {
    ZeroMemory( lpDst, sizeof( *lpDst ) );
    lpDst->dwSize = sizeof( *lpDst );
    return TRUE;
  }

1278
  if( lpSrc->dwSize != sizeof( *lpSrc) )
1279 1280 1281 1282 1283
  {
    return FALSE;
  }

  /* Delete any existing pointers */
1284 1285
  HeapFree( GetProcessHeap(), 0, lpDst->u1.lpszShortNameA );
  HeapFree( GetProcessHeap(), 0, lpDst->u2.lpszLongNameA );
1286 1287

  /* Copy as required */
1288
  CopyMemory( lpDst, lpSrc, lpSrc->dwSize );
1289 1290 1291

  if( bAnsi )
  {
1292
    if( lpSrc->u1.lpszShortNameA )
1293
    {
1294 1295 1296
        lpDst->u1.lpszShortNameA = HeapAlloc( GetProcessHeap(), 0,
                                             strlen(lpSrc->u1.lpszShortNameA)+1 );
        strcpy( lpDst->u1.lpszShortNameA, lpSrc->u1.lpszShortNameA );
1297
    }
1298
    if( lpSrc->u2.lpszLongNameA )
1299
    {
1300 1301 1302
        lpDst->u2.lpszLongNameA = HeapAlloc( GetProcessHeap(), 0,
                                              strlen(lpSrc->u2.lpszLongNameA)+1 );
        strcpy( lpDst->u2.lpszLongNameA, lpSrc->u2.lpszLongNameA );
1303 1304 1305 1306
    }
  }
  else
  {
1307
    if( lpSrc->u1.lpszShortNameA )
1308
    {
1309 1310 1311
        lpDst->u1.lpszShortName = HeapAlloc( GetProcessHeap(), 0,
                                              (strlenW(lpSrc->u1.lpszShortName)+1)*sizeof(WCHAR) );
        strcpyW( lpDst->u1.lpszShortName, lpSrc->u1.lpszShortName );
1312
    }
1313
    if( lpSrc->u2.lpszLongNameA )
1314
    {
1315 1316 1317
        lpDst->u2.lpszLongName = HeapAlloc( GetProcessHeap(), 0,
                                             (strlenW(lpSrc->u2.lpszLongName)+1)*sizeof(WCHAR) );
        strcpyW( lpDst->u2.lpszLongName, lpSrc->u2.lpszLongName );
1318 1319 1320 1321 1322 1323
    }
  }

  return TRUE;
}

1324 1325
static void
DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
1326
                  LPVOID lpData, DWORD dwDataSize )
1327 1328
{
  /* Clear out the data with this player */
1329
  if( dwFlags & DPSET_LOCAL )
1330
  {
1331 1332 1333 1334 1335 1336
    if ( lpPData->dwLocalDataSize != 0 )
    {
      HeapFree( GetProcessHeap(), 0, lpPData->lpLocalData );
      lpPData->lpLocalData = NULL;
      lpPData->dwLocalDataSize = 0;
    }
1337
  }
1338
  else
1339
  {
1340 1341 1342 1343 1344 1345
    if( lpPData->dwRemoteDataSize != 0 )
    {
      HeapFree( GetProcessHeap(), 0, lpPData->lpRemoteData );
      lpPData->lpRemoteData = NULL;
      lpPData->dwRemoteDataSize = 0;
    }
1346 1347 1348
  }

  /* Reallocate for new data */
1349
  if( lpData != NULL )
1350
  {
1351 1352 1353 1354 1355 1356 1357 1358 1359
    LPVOID lpNewData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                  sizeof( dwDataSize ) );
    CopyMemory( lpNewData, lpData, dwDataSize );

    if( dwFlags & DPSET_LOCAL )
    {
      lpPData->lpLocalData     = lpData;
      lpPData->dwLocalDataSize = dwDataSize;
    }
1360 1361 1362 1363 1364
    else
    {
      lpPData->lpRemoteData     = lpNewData;
      lpPData->dwRemoteDataSize = dwDataSize;
    }
1365
  }
1366

1367 1368
}

1369
static HRESULT DP_IF_CreatePlayer
1370
( IDirectPlay2Impl* This,
1371
  LPVOID lpMsgHdr, /* NULL for local creation, non NULL for remote creation */
1372 1373 1374 1375 1376
  LPDPID lpidPlayer,
  LPDPNAME lpPlayerName,
  HANDLE hEvent,
  LPVOID lpData,
  DWORD dwDataSize,
1377 1378
  DWORD dwFlags,
  BOOL bAnsi )
1379
{
1380
  HRESULT hr = DP_OK;
1381
  lpPlayerData lpPData;
1382
  lpPlayerList lpPList;
1383
  DWORD dwCreateFlags = 0;
1384

1385
  TRACE( "(%p)->(%p,%p,%p,%p,0x%08x,0x%08x,%u)\n",
1386
         This, lpidPlayer, lpPlayerName, hEvent, lpData,
1387
         dwDataSize, dwFlags, bAnsi );
1388 1389 1390 1391
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }
1392

1393
  if( dwFlags == 0 )
1394 1395 1396 1397
  {
    dwFlags = DPPLAYER_SPECTATOR;
  }

1398 1399 1400 1401 1402
  if( lpidPlayer == NULL )
  {
    return DPERR_INVALIDPARAMS;
  }

1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431

  /* 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;
  }

1432 1433 1434 1435 1436 1437 1438
  /* Verify we know how to handle all the flags */
  if( !( ( dwFlags & DPPLAYER_SERVERPLAYER ) ||
         ( dwFlags & DPPLAYER_SPECTATOR )
       )
    )
  {
    /* Assume non fatal failure */
1439
    ERR( "unknown dwFlags = 0x%08x\n", dwFlags );
1440 1441
  }

1442 1443
  /* If the name is not specified, we must provide one */
  if( *lpidPlayer == DPID_UNKNOWN )
1444
  {
1445 1446
    /* If we are the session master, we dish out the group/player ids */
    if( This->dp2->bHostInterface )
1447
    {
1448
      *lpidPlayer = DP_NextObjectId();
1449
    }
1450 1451
    else
    {
1452
      hr = DP_MSG_SendRequestPlayerId( This, dwCreateFlags, lpidPlayer );
1453

Peter Hunnisett's avatar
Peter Hunnisett committed
1454 1455 1456 1457 1458
      if( FAILED(hr) )
      {
        ERR( "Request for ID failed: %s\n", DPLAYX_HresultToString( hr ) );
        return hr;
      }
1459
    }
1460 1461 1462
  }
  else
  {
1463 1464 1465
    /* FIXME: Would be nice to perhaps verify that we don't already have
     *        this player.
     */
1466 1467
  }

1468 1469 1470
  /* 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,
1471
                             hEvent, bAnsi );
1472 1473 1474 1475 1476 1477

  if( lpPData == NULL )
  {
    return DPERR_CANTADDPLAYER;
  }

1478
  /* Create the list object and link it in */
1479
  lpPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpPList ) );
1480 1481 1482 1483 1484 1485
  if( lpPList == NULL )
  {
    FIXME( "Memory leak\n" );
    return DPERR_CANTADDPLAYER;
  }

Peter Hunnisett's avatar
Peter Hunnisett committed
1486
  lpPData->uRef = 1;
1487
  lpPList->lpPData = lpPData;
1488

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

Peter Hunnisett's avatar
Peter Hunnisett committed
1492
  /* Update the information and send it to all players in the session */
1493
  DP_SetPlayerData( lpPData, DPSET_REMOTE, lpData, dwDataSize );
1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504

  /* 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;

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

1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522
    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;
1523
    data.idGroup  = DPID_SYSTEM_GROUP;
1524 1525 1526 1527 1528 1529 1530 1531 1532
    data.lpISP    = This->dp2->spData.lpISP;

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

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

  if( FAILED(hr) )
  {
1533
    ERR( "Failed to add player to sys group with sp: %s\n",
1534 1535
         DPLAYX_HresultToString(hr) );
    return hr;
1536 1537
  }

1538 1539 1540 1541 1542 1543 1544 1545
#if 1
  if( This->dp2->bHostInterface == FALSE )
  {
    /* 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(...);
     */
1546 1547 1548 1549 1550
#if 0
    TRACE( "Sending message to self to get my addr\n" );
    DP_MSG_ToSelf( This, *lpidPlayer ); /* This is a hack right now */
#endif

1551 1552 1553
    hr = DP_MSG_ForwardPlayerCreation( This, *lpidPlayer);
  }
#else
1554
  /* Inform all other peers of the creation of a new player. If there are
1555
   * no peers keep this quiet.
1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576
   * 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 */
1577
    hr = DP_SendEx( This, DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg,
1578
                    sizeof( msg ), 0, 0, NULL, NULL, bAnsi );
1579
  }
1580
#endif
1581

1582
  return hr;
1583 1584
}

1585
static HRESULT WINAPI DirectPlay2AImpl_CreatePlayer
1586
          ( LPDIRECTPLAY2A iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
Peter Hunnisett's avatar
Peter Hunnisett committed
1587
            HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1588
{
1589
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1590

1591 1592 1593 1594 1595
  if( lpidPlayer == NULL )
  {
    return DPERR_INVALIDPARAMS;
  }

1596 1597 1598 1599 1600 1601 1602 1603 1604
  if( dwFlags & DPPLAYER_SERVERPLAYER )
  {
    *lpidPlayer = DPID_SERVERPLAYER;
  }
  else
  {
    *lpidPlayer = DPID_UNKNOWN;
  }

1605
  return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1606 1607 1608
                           lpData, dwDataSize, dwFlags, TRUE );
}

1609
static HRESULT WINAPI DirectPlay2WImpl_CreatePlayer
1610
          ( LPDIRECTPLAY2 iface, LPDPID lpidPlayer, LPDPNAME lpPlayerName,
Peter Hunnisett's avatar
Peter Hunnisett committed
1611
            HANDLE hEvent, LPVOID lpData, DWORD dwDataSize, DWORD dwFlags )
1612
{
1613
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1614

1615 1616 1617 1618 1619
  if( lpidPlayer == NULL )
  {
    return DPERR_INVALIDPARAMS;
  }

1620 1621 1622 1623 1624 1625 1626 1627 1628
  if( dwFlags & DPPLAYER_SERVERPLAYER )
  {
    *lpidPlayer = DPID_SERVERPLAYER;
  }
  else
  {
    *lpidPlayer = DPID_UNKNOWN;
  }

1629
  return DP_IF_CreatePlayer( This, NULL, lpidPlayer, lpPlayerName, hEvent,
1630
                           lpData, dwDataSize, dwFlags, FALSE );
1631 1632
}

Peter Hunnisett's avatar
Peter Hunnisett committed
1633 1634 1635 1636 1637 1638 1639 1640
static DPID DP_GetRemoteNextObjectId(void)
{
  FIXME( ":stub\n" );

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

1641
static HRESULT DP_IF_DeletePlayerFromGroup
1642
          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
1643
            DPID idPlayer, BOOL bAnsi )
1644
{
1645 1646 1647
  HRESULT hr = DP_OK;

  lpGroupData  lpGData;
1648
  lpPlayerList lpPList;
1649

1650
  TRACE( "(%p)->(%p,0x%08x,0x%08x,%u)\n",
1651
         This, lpMsgHdr, idGroup, idPlayer, bAnsi );
1652 1653

  /* Find the group */
1654
  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665
  {
    return DPERR_INVALIDGROUP;
  }

  /* Find the player */
  if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
  {
    return DPERR_INVALIDPLAYER;
  }

  /* Remove the player shortcut from the group */
1666
  DPQ_REMOVE_ENTRY( lpGData->players, players, lpPData->dpid, ==, idPlayer, lpPList );
1667 1668 1669

  if( lpPList == NULL )
  {
1670
    return DPERR_INVALIDPLAYER;
1671 1672
  }

Peter Hunnisett's avatar
Peter Hunnisett committed
1673 1674 1675
  /* One less reference */
  lpPList->lpPData->uRef--;

1676 1677 1678
  /* Delete the Player List element */
  HeapFree( GetProcessHeap(), 0, lpPList );

1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689
  /* Inform the SP if they care */
  if( This->dp2->spData.lpCB->RemovePlayerFromGroup )
  {
    DPSP_REMOVEPLAYERFROMGROUPDATA data;

    TRACE( "Calling SP RemovePlayerFromGroup\n" );

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

Peter Hunnisett's avatar
Peter Hunnisett committed
1690
    hr = (*This->dp2->spData.lpCB->RemovePlayerFromGroup)( &data );
1691 1692
  }

1693 1694 1695
  /* Need to send a DELETEPLAYERFROMGROUP message */
  FIXME( "Need to send a message\n" );

1696
  return hr;
1697 1698
}

1699 1700 1701
static HRESULT WINAPI DirectPlay2AImpl_DeletePlayerFromGroup
          ( LPDIRECTPLAY2A iface, DPID idGroup, DPID idPlayer )
{
1702
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1703
  return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, TRUE );
1704 1705
}

1706 1707 1708
static HRESULT WINAPI DirectPlay2WImpl_DeletePlayerFromGroup
          ( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
{
1709
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1710
  return DP_IF_DeletePlayerFromGroup( This, NULL, idGroup, idPlayer, FALSE );
1711 1712
}

1713 1714
typedef struct _DPRGOPContext
{
Peter Hunnisett's avatar
Peter Hunnisett committed
1715 1716 1717
  IDirectPlay3Impl* This;
  BOOL              bAnsi;
  DPID              idGroup;
1718 1719
} DPRGOPContext, *lpDPRGOPContext;

Peter Hunnisett's avatar
Peter Hunnisett committed
1720
static BOOL CALLBACK
1721 1722 1723 1724 1725 1726 1727 1728
cbRemoveGroupOrPlayer(
    DPID            dpId,
    DWORD           dwPlayerType,
    LPCDPNAME       lpName,
    DWORD           dwFlags,
    LPVOID          lpContext )
{
  lpDPRGOPContext lpCtxt = (lpDPRGOPContext)lpContext;
1729

1730
  TRACE( "Removing element:0x%08x (type:0x%08x) from element:0x%08x\n",
1731 1732 1733 1734
           dpId, dwPlayerType, lpCtxt->idGroup );

  if( dwPlayerType == DPPLAYERTYPE_GROUP )
  {
1735 1736 1737
    if( FAILED( DP_IF_DeleteGroupFromGroup( lpCtxt->This, lpCtxt->idGroup,
                                            dpId )
              )
1738 1739
      )
    {
1740
      ERR( "Unable to delete group 0x%08x from group 0x%08x\n",
1741 1742 1743 1744 1745
             dpId, lpCtxt->idGroup );
    }
  }
  else
  {
1746 1747
    if( FAILED( DP_IF_DeletePlayerFromGroup( (IDirectPlay2Impl*)lpCtxt->This,
                                             NULL, lpCtxt->idGroup,
Peter Hunnisett's avatar
Peter Hunnisett committed
1748
                                             dpId, lpCtxt->bAnsi )
1749 1750 1751
              )
      )
    {
1752
      ERR( "Unable to delete player 0x%08x from grp 0x%08x\n",
1753 1754 1755
             dpId, lpCtxt->idGroup );
    }
  }
1756

1757 1758 1759
  return TRUE; /* Continue enumeration */
}

1760
static HRESULT DP_IF_DestroyGroup
1761
          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi )
1762
{
1763
  lpGroupData lpGData;
1764 1765
  DPRGOPContext context;

1766
  FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1767
         This, lpMsgHdr, idGroup, bAnsi );
1768 1769

  /* Find the group */
1770
  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
1771 1772 1773 1774
  {
    return DPERR_INVALIDPLAYER; /* yes player */
  }

Peter Hunnisett's avatar
Peter Hunnisett committed
1775
  context.This    = (IDirectPlay3Impl*)This;
1776
  context.bAnsi   = bAnsi;
1777 1778
  context.idGroup = idGroup;

Peter Hunnisett's avatar
Peter Hunnisett committed
1779
  /* Remove all players that this group has */
1780
  DP_IF_EnumGroupPlayers( This, idGroup, NULL,
1781
                          cbRemoveGroupOrPlayer, &context, 0, bAnsi );
Peter Hunnisett's avatar
Peter Hunnisett committed
1782

1783
  /* Remove all links to groups that this group has since this is dp3 */
1784
  DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This, idGroup, NULL,
Peter Hunnisett's avatar
Peter Hunnisett committed
1785
                           cbRemoveGroupOrPlayer, (LPVOID)&context, 0, bAnsi );
1786

Peter Hunnisett's avatar
Peter Hunnisett committed
1787 1788 1789 1790
  /* Remove this group from the parent group - if it has one */
  if( ( idGroup != DPID_SYSTEM_GROUP ) &&
      ( lpGData->parent != DPID_SYSTEM_GROUP )
    )
1791
  {
1792 1793
    DP_IF_DeleteGroupFromGroup( (IDirectPlay3Impl*)This, lpGData->parent,
                                idGroup );
Peter Hunnisett's avatar
Peter Hunnisett committed
1794
  }
1795

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

1799 1800 1801 1802 1803 1804 1805 1806
  /* 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;
1807
    data.dwFlags = 0;
1808 1809
    data.lpISP   = This->dp2->spData.lpISP;

Peter Hunnisett's avatar
Peter Hunnisett committed
1810
    (*This->dp2->spData.lpCB->DeleteGroup)( &data );
1811 1812 1813
  }

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

1815 1816 1817
  return DP_OK;
}

1818 1819 1820
static HRESULT WINAPI DirectPlay2AImpl_DestroyGroup
          ( LPDIRECTPLAY2A iface, DPID idGroup )
{
1821
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1822
  return DP_IF_DestroyGroup( This, NULL, idGroup, TRUE );
1823 1824
}

1825 1826 1827
static HRESULT WINAPI DirectPlay2WImpl_DestroyGroup
          ( LPDIRECTPLAY2 iface, DPID idGroup )
{
1828
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1829
  return DP_IF_DestroyGroup( This, NULL, idGroup, FALSE );
1830 1831
}

1832 1833
typedef struct _DPFAGContext
{
Peter Hunnisett's avatar
Peter Hunnisett committed
1834 1835 1836
  IDirectPlay2Impl* This;
  DPID              idPlayer;
  BOOL              bAnsi;
1837 1838
} DPFAGContext, *lpDPFAGContext;

1839
static HRESULT DP_IF_DestroyPlayer
1840
          ( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi )
1841
{
1842 1843
  DPFAGContext cbContext;

1844
  FIXME( "(%p)->(%p,0x%08x,%u): semi stub\n",
1845
         This, lpMsgHdr, idPlayer, bAnsi );
1846

1847 1848 1849 1850 1851
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

1852
  if( DP_FindPlayer( This, idPlayer ) == NULL )
1853 1854 1855 1856 1857 1858
  {
    return DPERR_INVALIDPLAYER;
  }

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

Peter Hunnisett's avatar
Peter Hunnisett committed
1859
  cbContext.This     = This;
1860
  cbContext.idPlayer = idPlayer;
Peter Hunnisett's avatar
Peter Hunnisett committed
1861
  cbContext.bAnsi    = bAnsi;
1862 1863 1864

  /* Find each group and call DeletePlayerFromGroup if the player is a
     member of the group */
Peter Hunnisett's avatar
Peter Hunnisett committed
1865
  DP_IF_EnumGroups( This, NULL, cbDeletePlayerFromAllGroups,
1866
                    &cbContext, DPENUMGROUPS_ALL, bAnsi );
1867

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

1871 1872 1873 1874 1875 1876 1877 1878
  /* 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;
1879
    data.dwFlags = 0;
1880 1881
    data.lpISP   = This->dp2->spData.lpISP;

Peter Hunnisett's avatar
Peter Hunnisett committed
1882
    (*This->dp2->spData.lpCB->DeletePlayer)( &data );
1883 1884 1885
  }

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

1887 1888 1889
  return DP_OK;
}

Peter Hunnisett's avatar
Peter Hunnisett committed
1890
static BOOL CALLBACK
1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901
cbDeletePlayerFromAllGroups(
    DPID            dpId,
    DWORD           dwPlayerType,
    LPCDPNAME       lpName,
    DWORD           dwFlags,
    LPVOID          lpContext )
{
  lpDPFAGContext lpCtxt = (lpDPFAGContext)lpContext;

  if( dwPlayerType == DPPLAYERTYPE_GROUP )
  {
Peter Hunnisett's avatar
Peter Hunnisett committed
1902 1903 1904 1905 1906 1907 1908 1909 1910
    DP_IF_DeletePlayerFromGroup( lpCtxt->This, NULL, dpId, lpCtxt->idPlayer,
                                 lpCtxt->bAnsi );

    /* Enumerate all groups in this group since this will normally only
     * be called for top level groups
     */
    DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)lpCtxt->This,
                             dpId, NULL,
                             cbDeletePlayerFromAllGroups,
1911
                             lpContext, DPENUMGROUPS_ALL,
Peter Hunnisett's avatar
Peter Hunnisett committed
1912
                             lpCtxt->bAnsi );
1913 1914 1915 1916

  }
  else
  {
1917
    ERR( "Group callback has dwPlayerType = 0x%08x\n", dwPlayerType );
1918 1919 1920 1921 1922
  }

  return TRUE;
}

1923 1924 1925
static HRESULT WINAPI DirectPlay2AImpl_DestroyPlayer
          ( LPDIRECTPLAY2A iface, DPID idPlayer )
{
1926
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1927
  return DP_IF_DestroyPlayer( This, NULL, idPlayer, TRUE );
1928
}
1929

1930 1931 1932
static HRESULT WINAPI DirectPlay2WImpl_DestroyPlayer
          ( LPDIRECTPLAY2 iface, DPID idPlayer )
{
1933
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
1934
  return DP_IF_DestroyPlayer( This, NULL, idPlayer, FALSE );
1935 1936
}

1937
static HRESULT DP_IF_EnumGroupPlayers
1938
          ( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
1939 1940 1941 1942 1943 1944
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
{
  lpGroupData  lpGData;
  lpPlayerList lpPList;

1945
  FIXME("(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
1946
          This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
1947 1948
          lpContext, dwFlags, bAnsi );

1949 1950 1951 1952 1953
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

1954 1955 1956 1957 1958 1959 1960 1961 1962 1963
  /* Find the group */
  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
  {
    return DPERR_INVALIDGROUP;
  }

  if( DPQ_IS_EMPTY( lpGData->players ) )
  {
    return DP_OK;
  }
1964

1965 1966 1967 1968 1969 1970
  lpPList = DPQ_FIRST( lpGData->players );

  /* Walk the players in this group */
  for( ;; )
  {
    /* We do not enum the name server or app server as they are of no
Austin English's avatar
Austin English committed
1971
     * consequence to the end user.
1972 1973
     */
    if( ( lpPList->lpPData->dpid != DPID_NAME_SERVER ) &&
1974
        ( lpPList->lpPData->dpid != DPID_SERVERPLAYER )
1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992
      )
    {

      /* FIXME: Need to add stuff for dwFlags checking */

      if( !lpEnumPlayersCallback2( lpPList->lpPData->dpid, DPPLAYERTYPE_PLAYER,
                                   &lpPList->lpPData->name,
                                   lpPList->lpPData->dwFlags,
                                   lpContext )
        )
      {
        /* User requested break */
        return DP_OK;
      }
    }

    if( DPQ_IS_ENDOFLIST( lpPList->players ) )
    {
1993
      break;
1994 1995 1996 1997 1998
    }

    lpPList = DPQ_NEXT( lpPList->players );
  }

1999 2000 2001 2002
  return DP_OK;
}

static HRESULT WINAPI DirectPlay2AImpl_EnumGroupPlayers
2003
          ( LPDIRECTPLAY2A iface, DPID idGroup, LPGUID lpguidInstance,
2004
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2005 2006
            LPVOID lpContext, DWORD dwFlags )
{
2007
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2008 2009 2010
  return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
                               lpEnumPlayersCallback2, lpContext,
                               dwFlags, TRUE );
2011 2012 2013
}

static HRESULT WINAPI DirectPlay2WImpl_EnumGroupPlayers
2014
          ( LPDIRECTPLAY2 iface, DPID idGroup, LPGUID lpguidInstance,
2015
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2016 2017
            LPVOID lpContext, DWORD dwFlags )
{
2018
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2019 2020 2021
  return DP_IF_EnumGroupPlayers( This, idGroup, lpguidInstance,
                               lpEnumPlayersCallback2, lpContext,
                               dwFlags, FALSE );
2022 2023
}

2024
/* NOTE: This only enumerates top level groups (created with CreateGroup) */
2025
static HRESULT DP_IF_EnumGroups
2026 2027
          ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2028
            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2029
{
2030
  return DP_IF_EnumGroupsInGroup( (IDirectPlay3Impl*)This,
2031 2032 2033
                                  DPID_SYSTEM_GROUP, lpguidInstance,
                                  lpEnumPlayersCallback2, lpContext,
                                  dwFlags, bAnsi );
2034 2035
}

2036
static HRESULT WINAPI DirectPlay2AImpl_EnumGroups
2037 2038
          ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2039
            LPVOID lpContext, DWORD dwFlags )
2040
{
2041
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2042 2043
  return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
                         lpContext, dwFlags, TRUE );
2044 2045
}

2046
static HRESULT WINAPI DirectPlay2WImpl_EnumGroups
2047 2048
          ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2049
            LPVOID lpContext, DWORD dwFlags )
2050
{
2051
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2052 2053 2054 2055
  return DP_IF_EnumGroups( This, lpguidInstance, lpEnumPlayersCallback2,
                         lpContext, dwFlags, FALSE );
}

2056
static HRESULT DP_IF_EnumPlayers
2057 2058
          ( IDirectPlay2Impl* This, LPGUID lpguidInstance,
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2059 2060
            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
{
2061 2062 2063
  return DP_IF_EnumGroupPlayers( This, DPID_SYSTEM_GROUP, lpguidInstance,
                                 lpEnumPlayersCallback2, lpContext,
                                 dwFlags, bAnsi );
2064 2065
}

2066
static HRESULT WINAPI DirectPlay2AImpl_EnumPlayers
2067 2068
          ( LPDIRECTPLAY2A iface, LPGUID lpguidInstance,
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2069 2070
            LPVOID lpContext, DWORD dwFlags )
{
2071
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2072 2073 2074 2075
  return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
                          lpContext, dwFlags, TRUE );
}

2076
static HRESULT WINAPI DirectPlay2WImpl_EnumPlayers
2077 2078
          ( LPDIRECTPLAY2 iface, LPGUID lpguidInstance,
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
2079
            LPVOID lpContext, DWORD dwFlags )
2080
{
2081
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2082 2083
  return DP_IF_EnumPlayers( This, lpguidInstance, lpEnumPlayersCallback2,
                          lpContext, dwFlags, FALSE );
2084 2085
}

Peter Hunnisett's avatar
Peter Hunnisett committed
2086
/* This function should call the registered callback function that the user
2087
   passed into EnumSessions for each entry available.
Peter Hunnisett's avatar
Peter Hunnisett committed
2088
 */
Peter Hunnisett's avatar
Peter Hunnisett committed
2089 2090 2091 2092 2093
static void DP_InvokeEnumSessionCallbacks
       ( LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
         LPVOID lpNSInfo,
         DWORD dwTimeout,
         LPVOID lpContext )
2094
{
2095 2096 2097 2098
  LPDPSESSIONDESC2 lpSessionDesc;

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

2099 2100 2101
  /* Not sure if this should be pruning but it's convenient */
  NS_PruneSessionCache( lpNSInfo );

2102 2103 2104
  NS_ResetSessionEnumeration( lpNSInfo );

  /* Enumerate all sessions */
2105
  /* FIXME: Need to indicate ANSI */
2106 2107 2108 2109 2110 2111 2112 2113 2114
  while( (lpSessionDesc = NS_WalkSessions( lpNSInfo ) ) != NULL )
  {
    TRACE( "EnumSessionsCallback2 invoked\n" );
    if( !lpEnumSessionsCallback2( lpSessionDesc, &dwTimeout, 0, lpContext ) )
    {
      return;
    }
  }

2115 2116
  /* Invoke one last time to indicate that there is no more to come */
  lpEnumSessionsCallback2( NULL, &dwTimeout, DPESC_TIMEDOUT, lpContext );
2117 2118
}

2119 2120
static DWORD CALLBACK DP_EnumSessionsSendAsyncRequestThread( LPVOID lpContext )
{
2121
  EnumSessionAsyncCallbackData* data = lpContext;
2122 2123 2124
  HANDLE hSuicideRequest = data->hSuicideRequest;
  DWORD dwTimeout = data->dwTimeout;

2125
  TRACE( "Thread started with timeout = 0x%08x\n", dwTimeout );
2126 2127 2128

  for( ;; )
  {
Peter Hunnisett's avatar
Peter Hunnisett committed
2129
    HRESULT hr;
2130 2131 2132

    /* Sleep up to dwTimeout waiting for request to terminate thread */
    if( WaitForSingleObject( hSuicideRequest, dwTimeout ) == WAIT_OBJECT_0 )
2133
    {
2134 2135
      TRACE( "Thread terminating on terminate request\n" );
      break;
2136
    }
Peter Hunnisett's avatar
Peter Hunnisett committed
2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148

    /* 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? */
    }

2149 2150
  }

2151 2152 2153 2154 2155 2156
  TRACE( "Thread terminating\n" );

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

Peter Hunnisett's avatar
Peter Hunnisett committed
2157 2158 2159 2160 2161 2162 2163
  /* 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.
   */

2164
  return 1;
2165 2166
}

2167 2168 2169 2170 2171
static void DP_KillEnumSessionThread( IDirectPlay2Impl* This )
{
  /* Does a thread exist? If so we were doing an async enum session */
  if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
  {
2172
    TRACE( "Killing EnumSession thread %p\n",
2173
           This->dp2->hEnumSessionThread );
2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185

    /* 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;
  }
}

2186
static HRESULT DP_IF_EnumSessions
2187
          ( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2188
            LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
Peter Hunnisett's avatar
Peter Hunnisett committed
2189
            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
2190
{
2191 2192
  HRESULT hr = DP_OK;

2193
  TRACE( "(%p)->(%p,0x%08x,%p,%p,0x%08x,%u)\n",
Peter Hunnisett's avatar
Peter Hunnisett committed
2194 2195
         This, lpsd, dwTimeout, lpEnumSessionsCallback2, lpContext, dwFlags,
         bAnsi );
Ismael Barros's avatar
Ismael Barros committed
2196 2197 2198 2199
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }
2200 2201 2202 2203 2204 2205

  /* Can't enumerate if the interface is already open */
  if( This->dp2->bConnectionOpen )
  {
    return DPERR_GENERIC;
  }
2206

2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247
#if 1
  /* 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 )
   {
     LPVOID lpConnection;
     DWORD  dwSize;

     WARN( "Hack providing TCP/IP SP for lobby provider activated\n" );

     if( !DP_BuildSPCompoundAddr( (LPGUID)&DPSPGUID_TCPIP, &lpConnection, &dwSize ) )
     {
       ERR( "Can't build compound addr\n" );
       return DPERR_GENERIC;
     }

     hr = DP_IF_InitializeConnection( (IDirectPlay3Impl*)This, lpConnection,
                                      0, bAnsi );
     if( FAILED(hr) )
     {
       return hr;
     }

     /* Free up the address buffer */
     HeapFree( GetProcessHeap(), 0, lpConnection );

     /* The SP is now initialized */
     This->dp2->bSPInitialized = TRUE;
   }
#endif


2248
  /* Use the service provider default? */
2249 2250
  if( dwTimeout == 0 )
  {
2251 2252 2253
    DPCAPS spCaps;
    spCaps.dwSize = sizeof( spCaps );

Peter Hunnisett's avatar
Peter Hunnisett committed
2254
    DP_IF_GetCaps( This, &spCaps, 0 );
2255 2256
    dwTimeout = spCaps.dwTimeout;

2257 2258 2259 2260 2261 2262
    /* The service provider doesn't provide one either! */
    if( dwTimeout == 0 )
    {
      /* Provide the TCP/IP default */
      dwTimeout = DPMSG_WAIT_5_SECS;
    }
2263 2264 2265 2266
  }

  if( dwFlags & DPENUMSESSIONS_STOPASYNC )
  {
2267 2268 2269
    DP_KillEnumSessionThread( This );
    return hr;
  }
2270

2271 2272 2273
  if( ( dwFlags & DPENUMSESSIONS_ASYNC ) )
  {
    /* Enumerate everything presently in the local session cache */
2274 2275
    DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
                                   This->dp2->lpNameServerData, dwTimeout,
Peter Hunnisett's avatar
Peter Hunnisett committed
2276
                                   lpContext );
2277

2278 2279
    if( This->dp2->dwEnumSessionLock != 0 )
      return DPERR_CONNECTING;
2280

2281 2282 2283 2284
    /* See if we've already created a thread to service this interface */
    if( This->dp2->hEnumSessionThread == INVALID_HANDLE_VALUE )
    {
      DWORD dwThreadId;
2285
      This->dp2->dwEnumSessionLock++;
Peter Hunnisett's avatar
Peter Hunnisett committed
2286 2287 2288 2289 2290 2291 2292

      /* 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( &lpsd->guidApplication,
                                           dwFlags, &This->dp2->spData );

2293
      if( SUCCEEDED(hr) )
2294
      {
2295
        EnumSessionAsyncCallbackData* lpData
2296
          = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpData ) );
Peter Hunnisett's avatar
Peter Hunnisett committed
2297 2298
        /* FIXME: need to kill the thread on object deletion */
        lpData->lpSpData  = &This->dp2->spData;
2299

2300
        lpData->requestGuid = lpsd->guidApplication;
Peter Hunnisett's avatar
Peter Hunnisett committed
2301 2302
        lpData->dwEnumSessionFlags = dwFlags;
        lpData->dwTimeout = dwTimeout;
2303 2304

        This->dp2->hKillEnumSessionThreadEvent =
2305
          CreateEventW( NULL, TRUE, FALSE, NULL );
2306 2307

        if( !DuplicateHandle( GetCurrentProcess(),
Peter Hunnisett's avatar
Peter Hunnisett committed
2308 2309 2310 2311 2312 2313 2314 2315
                              This->dp2->hKillEnumSessionThreadEvent,
                              GetCurrentProcess(),
                              &lpData->hSuicideRequest,
                              0, FALSE, DUPLICATE_SAME_ACCESS )
          )
        {
          ERR( "Can't duplicate thread killing handle\n" );
        }
2316

Peter Hunnisett's avatar
Peter Hunnisett committed
2317
        TRACE( ": creating EnumSessionsRequest thread\n" );
2318

Peter Hunnisett's avatar
Peter Hunnisett committed
2319 2320 2321 2322 2323 2324
        This->dp2->hEnumSessionThread = CreateThread( NULL,
                                                      0,
                                                      DP_EnumSessionsSendAsyncRequestThread,
                                                      lpData,
                                                      0,
                                                      &dwThreadId );
2325
      }
2326
      This->dp2->dwEnumSessionLock--;
2327
    }
2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341
  }
  else
  {
    /* Invalidate the session cache for the interface */
    NS_InvalidateSessionCache( This->dp2->lpNameServerData );

    /* Send the broadcast for session enumeration */
    hr = NS_SendSessionRequestBroadcast( &lpsd->guidApplication,
                                         dwFlags,
                                         &This->dp2->spData );


    SleepEx( dwTimeout, FALSE );

2342 2343
    DP_InvokeEnumSessionCallbacks( lpEnumSessionsCallback2,
                                   This->dp2->lpNameServerData, dwTimeout,
Peter Hunnisett's avatar
Peter Hunnisett committed
2344
                                   lpContext );
2345 2346 2347 2348 2349
  }

  return hr;
}

Peter Hunnisett's avatar
Peter Hunnisett committed
2350
static HRESULT WINAPI DirectPlay2AImpl_EnumSessions
2351
          ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
Peter Hunnisett's avatar
Peter Hunnisett committed
2352 2353 2354
            LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
            LPVOID lpContext, DWORD dwFlags )
{
2355
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
Peter Hunnisett's avatar
Peter Hunnisett committed
2356 2357 2358 2359
  return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
                             lpContext, dwFlags, TRUE );
}

2360
static HRESULT WINAPI DirectPlay2WImpl_EnumSessions
2361
          ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
2362 2363 2364
            LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
            LPVOID lpContext, DWORD dwFlags )
{
2365
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
Peter Hunnisett's avatar
Peter Hunnisett committed
2366 2367
  return DP_IF_EnumSessions( This, lpsd, dwTimeout, lpEnumSessionsCallback2,
                             lpContext, dwFlags, FALSE );
2368 2369
}

2370
static HRESULT DP_IF_GetPlayerCaps
2371
          ( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
2372
            DWORD dwFlags )
2373
{
2374 2375
  DPSP_GETCAPSDATA data;

2376
  TRACE("(%p)->(0x%08x,%p,0x%08x)\n", This, idPlayer, lpDPCaps, dwFlags);
2377

2378 2379 2380 2381 2382
  if ( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

2383 2384 2385 2386 2387 2388
  /* Query the service provider */
  data.idPlayer = idPlayer;
  data.dwFlags  = dwFlags;
  data.lpCaps   = lpDPCaps;
  data.lpISP    = This->dp2->spData.lpISP;

Peter Hunnisett's avatar
Peter Hunnisett committed
2389
  return (*This->dp2->spData.lpCB->GetCaps)( &data );
2390 2391
}

2392
static HRESULT DP_IF_GetCaps
Peter Hunnisett's avatar
Peter Hunnisett committed
2393 2394 2395 2396
          ( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags )
{
  return DP_IF_GetPlayerCaps( This, DPID_ALLPLAYERS, lpDPCaps, dwFlags );
}
2397

2398 2399 2400
static HRESULT WINAPI DirectPlay2AImpl_GetCaps
          ( LPDIRECTPLAY2A iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
{
2401
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
Peter Hunnisett's avatar
Peter Hunnisett committed
2402
  return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2403 2404 2405 2406 2407
}

static HRESULT WINAPI DirectPlay2WImpl_GetCaps
          ( LPDIRECTPLAY2 iface, LPDPCAPS lpDPCaps, DWORD dwFlags )
{
2408
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
Peter Hunnisett's avatar
Peter Hunnisett committed
2409
  return DP_IF_GetCaps( This, lpDPCaps, dwFlags );
2410 2411
}

2412
static HRESULT DP_IF_GetGroupData
2413
          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2414
            LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2415
{
2416 2417 2418
  lpGroupData lpGData;
  DWORD dwRequiredBufferSize;
  LPVOID lpCopyDataFrom;
2419

2420
  TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2421
         This, idGroup, lpData, lpdwDataSize, dwFlags, bAnsi );
2422

2423
  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2424 2425 2426 2427
  {
    return DPERR_INVALIDGROUP;
  }

2428
  /* How much buffer is required? */
2429
  if( dwFlags & DPSET_LOCAL )
2430 2431 2432 2433 2434 2435
  {
    dwRequiredBufferSize = lpGData->dwLocalDataSize;
    lpCopyDataFrom       = lpGData->lpLocalData;
  }
  else
  {
2436 2437
    dwRequiredBufferSize = lpGData->dwRemoteDataSize;
    lpCopyDataFrom       = lpGData->lpRemoteData;
2438 2439
  }

2440 2441
  /* Is the user requesting to know how big a buffer is required? */
  if( ( lpData == NULL ) ||
2442
      ( *lpdwDataSize < dwRequiredBufferSize )
2443 2444
    )
  {
2445
    *lpdwDataSize = dwRequiredBufferSize;
2446
    return DPERR_BUFFERTOOSMALL;
2447 2448
  }

2449
  CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2450

2451 2452 2453
  return DP_OK;
}

2454
static HRESULT WINAPI DirectPlay2AImpl_GetGroupData
2455
          ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2456 2457
            LPDWORD lpdwDataSize, DWORD dwFlags )
{
2458
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2459
  return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2460 2461 2462
                           dwFlags, TRUE );
}

2463
static HRESULT WINAPI DirectPlay2WImpl_GetGroupData
2464
          ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2465
            LPDWORD lpdwDataSize, DWORD dwFlags )
2466
{
2467
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2468
  return DP_IF_GetGroupData( This, idGroup, lpData, lpdwDataSize,
2469
                           dwFlags, FALSE );
2470 2471
}

2472
static HRESULT DP_IF_GetGroupName
2473
          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
2474
            LPDWORD lpdwDataSize, BOOL bAnsi )
2475
{
2476
  lpGroupData lpGData;
2477
  LPDPNAME    lpName = lpData;
2478 2479
  DWORD       dwRequiredDataSize;

2480
  FIXME("(%p)->(0x%08x,%p,%p,%u) ANSI ignored\n",
2481
          This, idGroup, lpData, lpdwDataSize, bAnsi );
2482

2483
  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
2484 2485 2486 2487
  {
    return DPERR_INVALIDGROUP;
  }

2488
  dwRequiredDataSize = lpGData->name.dwSize;
2489

2490
  if( lpGData->name.u1.lpszShortNameA )
2491
  {
2492
    dwRequiredDataSize += strlen( lpGData->name.u1.lpszShortNameA ) + 1;
2493 2494
  }

2495
  if( lpGData->name.u2.lpszLongNameA )
2496
  {
2497
    dwRequiredDataSize += strlen( lpGData->name.u2.lpszLongNameA ) + 1;
2498
  }
2499

2500 2501 2502 2503 2504 2505 2506 2507 2508
  if( ( lpData == NULL ) ||
      ( *lpdwDataSize < dwRequiredDataSize )
    )
  {
    *lpdwDataSize = dwRequiredDataSize;
    return DPERR_BUFFERTOOSMALL;
  }

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

2511
  if( lpGData->name.u1.lpszShortNameA )
2512
  {
2513
    strcpy( ((char*)lpName)+lpGData->name.dwSize,
2514
            lpGData->name.u1.lpszShortNameA );
2515 2516 2517
  }
  else
  {
2518
    lpName->u1.lpszShortNameA = NULL;
2519 2520
  }

2521
  if( lpGData->name.u1.lpszShortNameA )
2522
  {
2523
    strcpy( ((char*)lpName)+lpGData->name.dwSize,
2524
            lpGData->name.u2.lpszLongNameA );
2525 2526 2527
  }
  else
  {
2528
    lpName->u2.lpszLongNameA = NULL;
2529 2530
  }

2531 2532 2533
  return DP_OK;
}

2534
static HRESULT WINAPI DirectPlay2AImpl_GetGroupName
2535
          ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
2536 2537
            LPDWORD lpdwDataSize )
{
2538
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2539 2540 2541
  return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, TRUE );
}

2542
static HRESULT WINAPI DirectPlay2WImpl_GetGroupName
2543
          ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
2544
            LPDWORD lpdwDataSize )
2545
{
2546
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2547
  return DP_IF_GetGroupName( This, idGroup, lpData, lpdwDataSize, FALSE );
2548 2549
}

2550
static HRESULT DP_IF_GetMessageCount
2551
          ( IDirectPlay2Impl* This, DPID idPlayer,
2552 2553
            LPDWORD lpdwCount, BOOL bAnsi )
{
2554
  FIXME("(%p)->(0x%08x,%p,%u): stub\n", This, idPlayer, lpdwCount, bAnsi );
2555 2556
  return DP_IF_GetMessageQueue( (IDirectPlay4Impl*)This, 0, idPlayer,
                                DPMESSAGEQUEUE_RECEIVE, lpdwCount, NULL,
2557 2558 2559
                                bAnsi );
}

2560 2561 2562
static HRESULT WINAPI DirectPlay2AImpl_GetMessageCount
          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDWORD lpdwCount )
{
2563
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2564
  return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, TRUE );
2565 2566 2567 2568 2569
}

static HRESULT WINAPI DirectPlay2WImpl_GetMessageCount
          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDWORD lpdwCount )
{
2570
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2571
  return DP_IF_GetMessageCount( This, idPlayer, lpdwCount, FALSE );
2572 2573 2574 2575 2576
}

static HRESULT WINAPI DirectPlay2AImpl_GetPlayerAddress
          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
{
2577
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2578
  FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2579 2580 2581 2582 2583 2584
  return DP_OK;
}

static HRESULT WINAPI DirectPlay2WImpl_GetPlayerAddress
          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData, LPDWORD lpdwDataSize )
{
2585
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2586
  FIXME("(%p)->(0x%08x,%p,%p): stub\n", This, idPlayer, lpData, lpdwDataSize );
2587 2588 2589 2590
  return DP_OK;
}

static HRESULT WINAPI DirectPlay2AImpl_GetPlayerCaps
2591
          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2592
            DWORD dwFlags )
2593
{
2594
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2595
  return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2596 2597 2598
}

static HRESULT WINAPI DirectPlay2WImpl_GetPlayerCaps
2599
          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPCAPS lpPlayerCaps,
2600
            DWORD dwFlags )
2601
{
2602
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2603
  return DP_IF_GetPlayerCaps( This, idPlayer, lpPlayerCaps, dwFlags );
2604 2605
}

2606
static HRESULT DP_IF_GetPlayerData
2607
          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2608
            LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi )
2609
{
2610
  lpPlayerList lpPList;
2611 2612
  DWORD dwRequiredBufferSize;
  LPVOID lpCopyDataFrom;
2613

2614
  TRACE( "(%p)->(0x%08x,%p,%p,0x%08x,%u)\n",
2615
         This, idPlayer, lpData, lpdwDataSize, dwFlags, bAnsi );
2616

2617 2618 2619 2620 2621
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

2622 2623 2624 2625 2626
  if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
  {
    return DPERR_INVALIDPLAYER;
  }

2627
  /* How much buffer is required? */
2628
  if( dwFlags & DPSET_LOCAL )
2629 2630 2631 2632 2633 2634
  {
    dwRequiredBufferSize = lpPList->lpPData->dwLocalDataSize;
    lpCopyDataFrom       = lpPList->lpPData->lpLocalData;
  }
  else
  {
2635 2636
    dwRequiredBufferSize = lpPList->lpPData->dwRemoteDataSize;
    lpCopyDataFrom       = lpPList->lpPData->lpRemoteData;
2637 2638
  }

2639 2640
  /* Is the user requesting to know how big a buffer is required? */
  if( ( lpData == NULL ) ||
2641
      ( *lpdwDataSize < dwRequiredBufferSize )
2642 2643
    )
  {
2644
    *lpdwDataSize = dwRequiredBufferSize;
2645 2646 2647
    return DPERR_BUFFERTOOSMALL;
  }

2648
  CopyMemory( lpData, lpCopyDataFrom, dwRequiredBufferSize );
2649

2650 2651 2652
  return DP_OK;
}

2653
static HRESULT WINAPI DirectPlay2AImpl_GetPlayerData
2654
          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2655 2656
            LPDWORD lpdwDataSize, DWORD dwFlags )
{
2657
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2658
  return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2659 2660 2661
                            dwFlags, TRUE );
}

2662
static HRESULT WINAPI DirectPlay2WImpl_GetPlayerData
2663
          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2664
            LPDWORD lpdwDataSize, DWORD dwFlags )
2665
{
2666
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2667
  return DP_IF_GetPlayerData( This, idPlayer, lpData, lpdwDataSize,
2668
                            dwFlags, FALSE );
2669 2670
}

2671
static HRESULT DP_IF_GetPlayerName
2672
          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
2673
            LPDWORD lpdwDataSize, BOOL bAnsi )
2674
{
2675
  lpPlayerList lpPList;
2676
  LPDPNAME    lpName = lpData;
2677 2678
  DWORD       dwRequiredDataSize;

2679
  FIXME( "(%p)->(0x%08x,%p,%p,%u): ANSI\n",
2680
         This, idPlayer, lpData, lpdwDataSize, bAnsi );
2681

2682 2683 2684 2685 2686
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

2687 2688 2689 2690 2691 2692 2693
  if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
  {
    return DPERR_INVALIDPLAYER;
  }

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

2694
  if( lpPList->lpPData->name.u1.lpszShortNameA )
2695
  {
2696
    dwRequiredDataSize += strlen( lpPList->lpPData->name.u1.lpszShortNameA ) + 1;
2697 2698
  }

2699
  if( lpPList->lpPData->name.u2.lpszLongNameA )
2700
  {
2701
    dwRequiredDataSize += strlen( lpPList->lpPData->name.u2.lpszLongNameA ) + 1;
2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712
  }

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

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

2715
  if( lpPList->lpPData->name.u1.lpszShortNameA )
2716
  {
2717
    strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2718
            lpPList->lpPData->name.u1.lpszShortNameA );
2719 2720 2721
  }
  else
  {
2722
    lpName->u1.lpszShortNameA = NULL;
2723 2724
  }

2725
  if( lpPList->lpPData->name.u1.lpszShortNameA )
2726
  {
2727
    strcpy( ((char*)lpName)+lpPList->lpPData->name.dwSize,
2728
            lpPList->lpPData->name.u2.lpszLongNameA );
2729 2730 2731
  }
  else
  {
2732
    lpName->u2.lpszLongNameA = NULL;
2733 2734
  }

2735 2736 2737
  return DP_OK;
}

2738
static HRESULT WINAPI DirectPlay2AImpl_GetPlayerName
2739
          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
2740 2741
            LPDWORD lpdwDataSize )
{
2742
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2743 2744 2745
  return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, TRUE );
}

2746
static HRESULT WINAPI DirectPlay2WImpl_GetPlayerName
2747
          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
2748
            LPDWORD lpdwDataSize )
2749
{
2750
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2751
  return DP_IF_GetPlayerName( This, idPlayer, lpData, lpdwDataSize, FALSE );
2752 2753
}

2754
static HRESULT DP_GetSessionDesc
2755
          ( IDirectPlay2Impl* This, LPVOID lpData, LPDWORD lpdwDataSize,
2756 2757 2758 2759 2760 2761
            BOOL bAnsi )
{
  DWORD dwRequiredSize;

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

2762 2763 2764 2765 2766
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

2767
  if( ( lpData == NULL ) && ( lpdwDataSize == NULL ) )
2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781
  {
    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;
  }
2782

2783 2784
  DP_CopySessionDesc( lpData, This->dp2->lpSessionDesc, bAnsi );

2785
  return DP_OK;
2786 2787
}

2788 2789 2790
static HRESULT WINAPI DirectPlay2AImpl_GetSessionDesc
          ( LPDIRECTPLAY2A iface, LPVOID lpData, LPDWORD lpdwDataSize )
{
2791
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2792
  return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2793 2794 2795 2796 2797
}

static HRESULT WINAPI DirectPlay2WImpl_GetSessionDesc
          ( LPDIRECTPLAY2 iface, LPVOID lpData, LPDWORD lpdwDataSize )
{
2798
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2799
  return DP_GetSessionDesc( This, lpData, lpdwDataSize, TRUE );
2800 2801 2802 2803 2804 2805
}

/* Intended only for COM compatibility. Always returns an error. */
static HRESULT WINAPI DirectPlay2AImpl_Initialize
          ( LPDIRECTPLAY2A iface, LPGUID lpGUID )
{
2806
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2807 2808 2809 2810 2811 2812 2813 2814
  TRACE("(%p)->(%p): stub\n", This, lpGUID );
  return DPERR_ALREADYINITIALIZED;
}

/* Intended only for COM compatibility. Always returns an error. */
static HRESULT WINAPI DirectPlay2WImpl_Initialize
          ( LPDIRECTPLAY2 iface, LPGUID lpGUID )
{
2815
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2816 2817 2818 2819 2820
  TRACE("(%p)->(%p): stub\n", This, lpGUID );
  return DPERR_ALREADYINITIALIZED;
}


2821
static HRESULT DP_SecureOpen
2822
          ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
2823 2824
            LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
            BOOL bAnsi )
2825
{
2826 2827
  HRESULT hr = DP_OK;

2828
  FIXME( "(%p)->(%p,0x%08x,%p,%p): partial stub\n",
2829
         This, lpsd, dwFlags, lpSecurity, lpCredentials );
2830

Ismael Barros's avatar
Ismael Barros committed
2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841
  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;
  }

2842 2843 2844 2845 2846 2847
  if( This->dp2->bConnectionOpen )
  {
    TRACE( ": rejecting already open connection.\n" );
    return DPERR_ALREADYINITIALIZED;
  }

2848 2849
  /* If we're enumerating, kill the thread */
  DP_KillEnumSessionThread( This );
2850 2851 2852 2853 2854

  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 */
2855
    NS_SetLocalComputerAsNameServer( lpsd, This->dp2->lpNameServerData );
2856

2857
    This->dp2->bHostInterface = TRUE;
2858 2859 2860 2861

    hr = DP_SetSessionDesc( This, lpsd, 0, TRUE, bAnsi );
    if( FAILED( hr ) )
    {
2862
      ERR( "Unable to set session desc: %s\n", DPLAYX_HresultToString( hr ) );
2863 2864
      return hr;
    }
2865 2866
  }

2867 2868 2869 2870 2871 2872 2873 2874
  /* 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" );

    data.bCreate           = (dwFlags & DPOPEN_CREATE ) ? TRUE : FALSE;
2875
    data.lpSPMessageHeader = (dwFlags & DPOPEN_CREATE ) ? NULL
2876 2877 2878 2879 2880 2881
                                                        : NS_GetNSAddr( This->dp2->lpNameServerData );
    data.lpISP             = This->dp2->spData.lpISP;
    data.bReturnStatus     = (dwFlags & DPOPEN_RETURNSTATUS) ? TRUE : FALSE;
    data.dwOpenFlags       = dwFlags;
    data.dwSessionFlags    = This->dp2->lpSessionDesc->dwFlags;

Peter Hunnisett's avatar
Peter Hunnisett committed
2882 2883 2884
    hr = (*This->dp2->spData.lpCB->Open)(&data);
    if( FAILED( hr ) )
    {
2885
      ERR( "Unable to open session: %s\n", DPLAYX_HresultToString( hr ) );
Peter Hunnisett's avatar
Peter Hunnisett committed
2886 2887
      return hr;
    }
2888
  }
Peter Hunnisett's avatar
Peter Hunnisett committed
2889

2890
  {
Peter Hunnisett's avatar
Peter Hunnisett committed
2891
    /* Create the system group of which everything is a part of */
2892 2893 2894 2895
    DPID systemGroup = DPID_SYSTEM_GROUP;

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

2897 2898
  }

2899 2900
  if( dwFlags & DPOPEN_JOIN )
  {
2901
    DPID dpidServerId = DPID_UNKNOWN;
2902

2903 2904 2905
    /* Create the server player for this interface. This way we can receive
     * messages for this session.
     */
2906
    /* FIXME: I suppose that we should be setting an event for a receive
2907 2908 2909 2910
     *        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.
     */
2911 2912
    hr = DP_IF_CreatePlayer( This, NULL, &dpidServerId, NULL, 0, NULL,
                             0,
Peter Hunnisett's avatar
Peter Hunnisett committed
2913
                             DPPLAYER_SERVERPLAYER | DPPLAYER_LOCAL , bAnsi );
2914

2915 2916 2917 2918 2919 2920 2921 2922 2923
  }
  else if( dwFlags & DPOPEN_CREATE )
  {
    DPID dpidNameServerId = DPID_NAME_SERVER;

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

2924 2925 2926 2927 2928 2929
  if( FAILED(hr) )
  {
    ERR( "Couldn't create name server/system player: %s\n",
         DPLAYX_HresultToString(hr) );
  }

2930
  return hr;
2931 2932
}

2933 2934 2935
static HRESULT WINAPI DirectPlay2AImpl_Open
          ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
{
2936
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2937
  TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
2938
  return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, TRUE );
2939 2940
}

2941 2942 2943
static HRESULT WINAPI DirectPlay2WImpl_Open
          ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpsd, DWORD dwFlags )
{
2944
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
2945
  TRACE("(%p)->(%p,0x%08x)\n", This, lpsd, dwFlags );
2946 2947 2948
  return DP_SecureOpen( This, lpsd, dwFlags, NULL, NULL, FALSE );
}

2949
static HRESULT DP_IF_Receive
2950
          ( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
2951 2952 2953 2954
            DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi )
{
  LPDPMSG lpMsg = NULL;

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

2958 2959 2960 2961 2962
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982
  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" );
2983
    }
2984 2985 2986 2987 2988
  }
  else if( ( dwFlags & DPRECEIVE_TOPLAYER ) ||
           ( dwFlags & DPRECEIVE_FROMPLAYER )
         )
  {
2989
    FIXME( "Find matching message 0x%08x\n", dwFlags );
2990 2991 2992
  }
  else
  {
2993
    ERR( "Hmmm..dwFlags 0x%08x\n", dwFlags );
2994 2995 2996 2997 2998 2999 3000 3001
  }

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

  /* Copy into the provided buffer */
3002
  if (lpData) CopyMemory( lpData, lpMsg->msg, *lpdwDataSize );
3003 3004

  return DP_OK;
3005 3006 3007
}

static HRESULT WINAPI DirectPlay2AImpl_Receive
3008
          ( LPDIRECTPLAY2A iface, LPDPID lpidFrom, LPDPID lpidTo,
3009
            DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3010
{
3011
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3012
  return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3013
                        lpData, lpdwDataSize, TRUE );
3014 3015 3016
}

static HRESULT WINAPI DirectPlay2WImpl_Receive
3017
          ( LPDIRECTPLAY2 iface, LPDPID lpidFrom, LPDPID lpidTo,
3018
            DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
3019
{
3020
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3021
  return DP_IF_Receive( This, lpidFrom, lpidTo, dwFlags,
3022
                        lpData, lpdwDataSize, FALSE );
3023 3024 3025 3026 3027
}

static HRESULT WINAPI DirectPlay2AImpl_Send
          ( LPDIRECTPLAY2A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
{
3028
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3029
  return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3030
                    0, 0, NULL, NULL, TRUE );
3031 3032 3033 3034 3035
}

static HRESULT WINAPI DirectPlay2WImpl_Send
          ( LPDIRECTPLAY2 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPVOID lpData, DWORD dwDataSize )
{
3036
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3037
  return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
3038
                    0, 0, NULL, NULL, FALSE );
3039 3040
}

3041
static HRESULT DP_IF_SetGroupData
3042
          ( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
3043
            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3044
{
3045
  lpGroupData lpGData;
3046

3047
  TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3048
         This, idGroup, lpData, dwDataSize, dwFlags, bAnsi );
3049 3050

  /* Parameter check */
3051 3052 3053
  if( ( lpData == NULL ) &&
      ( dwDataSize != 0 )
    )
3054
  {
3055
    return DPERR_INVALIDPARAMS;
3056 3057 3058
  }

  /* Find the pointer to the data for this player */
3059
  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3060 3061 3062 3063
  {
    return DPERR_INVALIDOBJECT;
  }

3064
  if( !(dwFlags & DPSET_LOCAL) )
3065 3066
  {
    FIXME( "Was this group created by this interface?\n" );
3067
    /* FIXME: If this is a remote update need to allow it but not
3068 3069 3070 3071 3072 3073 3074 3075 3076
     *        send a message.
     */
  }

  DP_SetGroupData( lpGData, dwFlags, lpData, dwDataSize );

  /* FIXME: Only send a message if this group is local to the session otherwise
   * it will have been rejected above
   */
3077
  if( !(dwFlags & DPSET_LOCAL) )
3078 3079 3080
  {
    FIXME( "Send msg?\n" );
  }
3081

3082 3083 3084
  return DP_OK;
}

3085
static HRESULT WINAPI DirectPlay2AImpl_SetGroupData
3086
          ( LPDIRECTPLAY2A iface, DPID idGroup, LPVOID lpData,
3087
            DWORD dwDataSize, DWORD dwFlags )
3088
{
3089
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3090 3091 3092
  return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, TRUE );
}

3093
static HRESULT WINAPI DirectPlay2WImpl_SetGroupData
3094
          ( LPDIRECTPLAY2 iface, DPID idGroup, LPVOID lpData,
3095
            DWORD dwDataSize, DWORD dwFlags )
3096
{
3097
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3098
  return DP_IF_SetGroupData( This, idGroup, lpData, dwDataSize, dwFlags, FALSE );
3099 3100
}

3101
static HRESULT DP_IF_SetGroupName
3102
          ( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
3103
            DWORD dwFlags, BOOL bAnsi )
3104
{
3105
  lpGroupData lpGData;
3106

3107
  TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n", This, idGroup,
3108
         lpGroupName, dwFlags, bAnsi );
3109

3110
  if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
3111 3112 3113 3114
  {
    return DPERR_INVALIDGROUP;
  }

3115
  DP_CopyDPNAMEStruct( &lpGData->name, lpGroupName, bAnsi );
3116 3117 3118 3119

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

3120 3121 3122
  return DP_OK;
}

3123
static HRESULT WINAPI DirectPlay2AImpl_SetGroupName
3124
          ( LPDIRECTPLAY2A iface, DPID idGroup, LPDPNAME lpGroupName,
3125 3126
            DWORD dwFlags )
{
3127
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3128 3129 3130
  return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, TRUE );
}

3131
static HRESULT WINAPI DirectPlay2WImpl_SetGroupName
3132
          ( LPDIRECTPLAY2 iface, DPID idGroup, LPDPNAME lpGroupName,
3133
            DWORD dwFlags )
3134
{
3135
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3136
  return DP_IF_SetGroupName( This, idGroup, lpGroupName, dwFlags, FALSE );
3137 3138
}

3139
static HRESULT DP_IF_SetPlayerData
3140
          ( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
3141
            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3142
{
3143
  lpPlayerList lpPList;
3144

3145
  TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x,%u)\n",
3146
         This, idPlayer, lpData, dwDataSize, dwFlags, bAnsi );
3147

3148 3149 3150 3151 3152
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

3153
  /* Parameter check */
3154 3155 3156
  if( ( lpData == NULL ) &&
      ( dwDataSize != 0 )
    )
3157
  {
3158
    return DPERR_INVALIDPARAMS;
3159 3160 3161
  }

  /* Find the pointer to the data for this player */
3162
  if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
3163
  {
3164
    return DPERR_INVALIDPLAYER;
3165 3166
  }

3167
  if( !(dwFlags & DPSET_LOCAL) )
3168 3169
  {
    FIXME( "Was this group created by this interface?\n" );
3170
    /* FIXME: If this is a remote update need to allow it but not
3171 3172 3173 3174 3175
     *        send a message.
     */
  }

  DP_SetPlayerData( lpPList->lpPData, dwFlags, lpData, dwDataSize );
3176

3177
  if( !(dwFlags & DPSET_LOCAL) )
3178
  {
3179
    FIXME( "Send msg?\n" );
3180 3181
  }

3182 3183 3184
  return DP_OK;
}

3185
static HRESULT WINAPI DirectPlay2AImpl_SetPlayerData
3186
          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPVOID lpData,
3187 3188
            DWORD dwDataSize, DWORD dwFlags )
{
3189
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3190
  return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3191 3192 3193
                              dwFlags, TRUE );
}

3194
static HRESULT WINAPI DirectPlay2WImpl_SetPlayerData
3195
          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPVOID lpData,
3196
            DWORD dwDataSize, DWORD dwFlags )
3197
{
3198
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3199
  return DP_IF_SetPlayerData( This, idPlayer, lpData, dwDataSize,
3200
                              dwFlags, FALSE );
3201 3202
}

3203
static HRESULT DP_IF_SetPlayerName
3204
          ( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
3205
            DWORD dwFlags, BOOL bAnsi )
3206
{
3207
  lpPlayerList lpPList;
3208

3209
  TRACE( "(%p)->(0x%08x,%p,0x%08x,%u)\n",
3210
         This, idPlayer, lpPlayerName, dwFlags, bAnsi );
3211

3212 3213 3214 3215 3216
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

3217 3218 3219 3220 3221
  if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
  {
    return DPERR_INVALIDGROUP;
  }

3222
  DP_CopyDPNAMEStruct( &lpPList->lpPData->name, lpPlayerName, bAnsi );
3223 3224 3225

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

3227 3228 3229
  return DP_OK;
}

3230
static HRESULT WINAPI DirectPlay2AImpl_SetPlayerName
3231
          ( LPDIRECTPLAY2A iface, DPID idPlayer, LPDPNAME lpPlayerName,
3232 3233
            DWORD dwFlags )
{
3234
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3235 3236 3237
  return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, TRUE );
}

3238
static HRESULT WINAPI DirectPlay2WImpl_SetPlayerName
3239
          ( LPDIRECTPLAY2 iface, DPID idPlayer, LPDPNAME lpPlayerName,
3240
            DWORD dwFlags )
3241
{
3242
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3243
  return DP_IF_SetPlayerName( This, idPlayer, lpPlayerName, dwFlags, FALSE );
3244 3245
}

3246
static HRESULT DP_SetSessionDesc
3247
          ( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
3248 3249 3250 3251 3252
            DWORD dwFlags, BOOL bInitial, BOOL bAnsi  )
{
  DWORD            dwRequiredSize;
  LPDPSESSIONDESC2 lpTempSessDesc;

3253
  TRACE( "(%p)->(%p,0x%08x,%u,%u)\n",
3254 3255
         This, lpSessDesc, dwFlags, bInitial, bAnsi );

3256 3257 3258 3259 3260
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273
  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 );
3274
  lpTempSessDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwRequiredSize );
3275 3276 3277 3278 3279 3280 3281 3282 3283 3284

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

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

  This->dp2->lpSessionDesc = lpTempSessDesc;
3285 3286
  /* Set the new */
  DP_CopySessionDesc( This->dp2->lpSessionDesc, lpSessDesc, bAnsi );
3287 3288 3289 3290 3291
  if( bInitial )
  {
    /*Initializing session GUID*/
    CoCreateGuid( &(This->dp2->lpSessionDesc->guidInstance) );
  }
3292
  /* If this is an external invocation of the interface, we should be
3293 3294 3295 3296 3297
   * letting everyone know that things have changed. Otherwise this is
   * just an initialization and it doesn't need to be propagated.
   */
  if( !bInitial )
  {
3298
    FIXME( "Need to send a DPMSG_SETSESSIONDESC msg to everyone\n" );
3299 3300 3301 3302 3303
  }

  return DP_OK;
}

3304 3305 3306
static HRESULT WINAPI DirectPlay2AImpl_SetSessionDesc
          ( LPDIRECTPLAY2A iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
{
3307
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3308
  return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
3309 3310 3311 3312 3313
}

static HRESULT WINAPI DirectPlay2WImpl_SetSessionDesc
          ( LPDIRECTPLAY2 iface, LPDPSESSIONDESC2 lpSessDesc, DWORD dwFlags )
{
3314
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
3315 3316 3317 3318
  return DP_SetSessionDesc( This, lpSessDesc, dwFlags, FALSE, TRUE );
}

/* FIXME: See about merging some of this stuff with dplayx_global.c stuff */
3319
static DWORD DP_CalcSessionDescSize( LPCDPSESSIONDESC2 lpSessDesc, BOOL bAnsi )
3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333
{
  DWORD dwSize = 0;

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

  dwSize += sizeof( *lpSessDesc );

  if( bAnsi )
  {
3334
    if( lpSessDesc->u1.lpszSessionNameA )
3335
    {
3336
      dwSize += lstrlenA( lpSessDesc->u1.lpszSessionNameA ) + 1;
3337 3338
    }

3339
    if( lpSessDesc->u2.lpszPasswordA )
3340
    {
3341
      dwSize += lstrlenA( lpSessDesc->u2.lpszPasswordA ) + 1;
3342 3343 3344 3345
    }
  }
  else /* UNICODE */
  {
3346
    if( lpSessDesc->u1.lpszSessionName )
3347 3348
    {
      dwSize += sizeof( WCHAR ) *
3349
        ( lstrlenW( lpSessDesc->u1.lpszSessionName ) + 1 );
3350 3351
    }

3352
    if( lpSessDesc->u2.lpszPassword )
3353 3354
    {
      dwSize += sizeof( WCHAR ) *
3355
        ( lstrlenW( lpSessDesc->u2.lpszPassword ) + 1 );
3356 3357 3358 3359 3360 3361
    }
  }

  return dwSize;
}

Austin English's avatar
Austin English committed
3362
/* Assumes that contiguous buffers are already allocated. */
3363
static void DP_CopySessionDesc( LPDPSESSIONDESC2 lpSessionDest,
3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379
                                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 )
  {
3380
    if( lpSessionSrc->u1.lpszSessionNameA )
3381
    {
3382
      lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3383 3384
                lpSessionDest->u1.lpszSessionNameA );
      lpSessionDest->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
3385
      lpStartOfFreeSpace +=
3386
        lstrlenA( lpSessionDest->u1.lpszSessionNameA ) + 1;
3387
    }
3388

3389
    if( lpSessionSrc->u2.lpszPasswordA )
3390
    {
3391
      lstrcpyA( (LPSTR)lpStartOfFreeSpace,
3392 3393
                lpSessionDest->u2.lpszPasswordA );
      lpSessionDest->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
3394
      lpStartOfFreeSpace +=
3395
        lstrlenA( lpSessionDest->u2.lpszPasswordA ) + 1;
3396
    }
3397 3398 3399
  }
  else /* UNICODE */
  {
3400
    if( lpSessionSrc->u1.lpszSessionName )
3401 3402
    {
      lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3403 3404
                lpSessionDest->u1.lpszSessionName );
      lpSessionDest->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
3405
      lpStartOfFreeSpace += sizeof(WCHAR) *
3406
        ( lstrlenW( lpSessionDest->u1.lpszSessionName ) + 1 );
3407 3408
    }

3409
    if( lpSessionSrc->u2.lpszPassword )
3410 3411
    {
      lstrcpyW( (LPWSTR)lpStartOfFreeSpace,
3412 3413
                lpSessionDest->u2.lpszPassword );
      lpSessionDest->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
3414
      lpStartOfFreeSpace += sizeof(WCHAR) *
3415
        ( lstrlenW( lpSessionDest->u2.lpszPassword ) + 1 );
3416
    }
3417
  }
3418 3419
}

3420

3421
static HRESULT DP_IF_AddGroupToGroup
3422
          ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3423
{
3424
  lpGroupData lpGData;
3425 3426
  lpGroupList lpNewGList;

3427
  TRACE( "(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3428

3429 3430 3431 3432 3433
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

3434
  if( DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) == NULL )
3435 3436 3437 3438
  {
    return DPERR_INVALIDGROUP;
  }

3439
  if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3440 3441 3442
  {
    return DPERR_INVALIDGROUP;
  }
3443

3444
  /* Create a player list (ie "shortcut" ) */
3445
  lpNewGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewGList ) );
3446 3447 3448
  if( lpNewGList == NULL )
  {
    return DPERR_CANTADDPLAYER;
3449
  }
3450 3451

  /* Add the shortcut */
Peter Hunnisett's avatar
Peter Hunnisett committed
3452
  lpGData->uRef++;
3453
  lpNewGList->lpGData = lpGData;
3454 3455

  /* Add the player to the list of players for this group */
3456
  DPQ_INSERT( lpGData->groups, lpNewGList, groups );
3457 3458 3459

  /* Send a ADDGROUPTOGROUP message */
  FIXME( "Not sending message\n" );
3460

3461 3462 3463
  return DP_OK;
}

3464 3465 3466
static HRESULT WINAPI DirectPlay3AImpl_AddGroupToGroup
          ( LPDIRECTPLAY3A iface, DPID idParentGroup, DPID idGroup )
{
3467
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3468 3469 3470
  return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
}

3471 3472 3473
static HRESULT WINAPI DirectPlay3WImpl_AddGroupToGroup
          ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
{
3474
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3475
  return DP_IF_AddGroupToGroup( This, idParentGroup, idGroup );
3476 3477
}

3478
static HRESULT DP_IF_CreateGroupInGroup
3479 3480
          ( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
            LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
3481
            DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi )
3482
{
3483
  lpGroupData lpGParentData;
3484 3485 3486
  lpGroupList lpGList;
  lpGroupData lpGData;

3487
  TRACE( "(%p)->(0x%08x,%p,%p,%p,0x%08x,0x%08x,%u)\n",
3488
         This, idParentGroup, lpidGroup, lpGroupName, lpData,
3489
         dwDataSize, dwFlags, bAnsi );
3490

3491 3492 3493 3494 3495
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

3496
  /* Verify that the specified parent is valid */
3497 3498
  if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This,
                                         idParentGroup ) ) == NULL
3499 3500 3501
    )
  {
    return DPERR_INVALIDGROUP;
3502
  }
3503

3504
  lpGData = DP_CreateGroup( (IDirectPlay2AImpl*)This, lpidGroup, lpGroupName,
3505
                            dwFlags, idParentGroup, bAnsi );
3506 3507 3508 3509 3510

  if( lpGData == NULL )
  {
    return DPERR_CANTADDPLAYER; /* yes player not group */
  }
Peter Hunnisett's avatar
Peter Hunnisett committed
3511 3512 3513

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

3515
  DP_SetGroupData( lpGData, DPSET_REMOTE, lpData, dwDataSize );
3516 3517 3518

  /* 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 */
3519
  lpGList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGList ) );
3520 3521 3522 3523 3524 3525
  if( lpGList == NULL )
  {
    FIXME( "Memory leak\n" );
    return DPERR_CANTADDPLAYER; /* yes player not group */
  }

3526
  lpGList->lpGData = lpGData;
3527

3528 3529 3530 3531 3532 3533 3534 3535
  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" );
3536

3537 3538 3539 3540 3541
    data.idGroup           = *lpidGroup;
    data.dwFlags           = dwFlags;
    data.lpSPMessageHeader = lpMsgHdr;
    data.lpISP             = This->dp2->spData.lpISP;

Peter Hunnisett's avatar
Peter Hunnisett committed
3542
    (*This->dp2->spData.lpCB->CreateGroup)( &data );
3543 3544
  }

3545 3546
  /* Inform all other peers of the creation of a new group. If there are
   * no peers keep this quiet.
3547
   */
3548
  if( This->dp2->lpSessionDesc &&
3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563
      ( 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 */
3564
    DP_SendEx( (IDirectPlay2Impl*)This,
3565 3566 3567
               DPID_SERVERPLAYER, DPID_ALLPLAYERS, 0, &msg, sizeof( msg ),
               0, 0, NULL, NULL, bAnsi );
  }
3568 3569

  return DP_OK;
3570
}
3571

3572
static HRESULT WINAPI DirectPlay3AImpl_CreateGroupInGroup
3573 3574
          ( LPDIRECTPLAY3A iface, DPID idParentGroup, LPDPID lpidGroup,
            LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3575 3576
            DWORD dwFlags )
{
3577
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3578 3579 3580

  *lpidGroup = DPID_UNKNOWN;

3581 3582
  return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
                                   lpGroupName, lpData, dwDataSize, dwFlags,
3583
                                   TRUE );
3584 3585 3586
}

static HRESULT WINAPI DirectPlay3WImpl_CreateGroupInGroup
3587 3588
          ( LPDIRECTPLAY3 iface, DPID idParentGroup, LPDPID lpidGroup,
            LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
3589
            DWORD dwFlags )
3590
{
3591
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3592 3593 3594

  *lpidGroup = DPID_UNKNOWN;

3595 3596
  return DP_IF_CreateGroupInGroup( This, NULL, idParentGroup, lpidGroup,
                                   lpGroupName, lpData, dwDataSize,
3597
                                   dwFlags, FALSE );
3598 3599
}

3600
static HRESULT DP_IF_DeleteGroupFromGroup
3601
          ( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup )
3602
{
3603
  lpGroupList lpGList;
3604
  lpGroupData lpGParentData;
3605

3606
  TRACE("(%p)->(0x%08x,0x%08x)\n", This, idParentGroup, idGroup );
3607 3608

  /* Is the parent group valid? */
3609
  if( ( lpGParentData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idParentGroup ) ) == NULL )
3610 3611
  {
    return DPERR_INVALIDGROUP;
3612
  }
3613 3614

  /* Remove the group from the parent group queue */
3615
  DPQ_REMOVE_ENTRY( lpGParentData->groups, groups, lpGData->dpid, ==, idGroup, lpGList );
3616 3617 3618 3619 3620 3621

  if( lpGList == NULL )
  {
    return DPERR_INVALIDGROUP;
  }

Peter Hunnisett's avatar
Peter Hunnisett committed
3622 3623 3624
  /* Decrement the ref count */
  lpGList->lpGData->uRef--;

3625
  /* Free up the list item */
3626
  HeapFree( GetProcessHeap(), 0, lpGList );
3627 3628 3629 3630

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

3631 3632 3633
  return DP_OK;
}

3634 3635 3636
static HRESULT WINAPI DirectPlay3AImpl_DeleteGroupFromGroup
          ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
{
3637
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3638 3639 3640
  return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
}

3641 3642 3643
static HRESULT WINAPI DirectPlay3WImpl_DeleteGroupFromGroup
          ( LPDIRECTPLAY3 iface, DPID idParentGroup, DPID idGroup )
{
3644
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3645
  return DP_IF_DeleteGroupFromGroup( This, idParentGroup, idGroup );
3646 3647
}

3648
static BOOL DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
3649 3650 3651 3652 3653 3654
                                    LPDWORD lpdwBufSize )
{
  DPCOMPOUNDADDRESSELEMENT dpCompoundAddress;
  HRESULT                  hr;

  dpCompoundAddress.dwDataSize = sizeof( GUID );
3655
  dpCompoundAddress.guidDataType = DPAID_ServiceProvider;
3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684
  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;
}

3685 3686 3687
static HRESULT WINAPI DirectPlay3AImpl_EnumConnections
          ( LPDIRECTPLAY3A iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
{
3688
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3689
  TRACE("(%p)->(%p,%p,%p,0x%08x)\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3690 3691 3692 3693 3694 3695 3696 3697 3698

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

  if( ! ( ( dwFlags & DPCONNECTION_DIRECTPLAY ) ||
          ( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY ) )
3699
    )
3700 3701 3702 3703
  {
    return DPERR_INVALIDFLAGS;
  }

3704
  if( !lpEnumCallback )
3705
  {
3706
     return DPERR_INVALIDPARAMS;
3707 3708 3709 3710 3711
  }

  /* Enumerate DirectPlay service providers */
  if( dwFlags & DPCONNECTION_DIRECTPLAY )
  {
3712 3713
    HKEY hkResult;
    LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
3714
    LPCSTR guidDataSubKey  = "Guid";
3715
    char subKeyName[51];
3716 3717
    DWORD dwIndex, sizeOfSubKeyName=50;
    FILETIME filetime;
3718 3719 3720

    /* Need to loop over the service providers in the registry */
    if( RegOpenKeyExA( HKEY_LOCAL_MACHINE, searchSubKey,
3721
                         0, KEY_READ, &hkResult ) != ERROR_SUCCESS )
3722 3723 3724 3725 3726 3727 3728 3729 3730
    {
      /* 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;
3731
         RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
3732 3733
                        NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
         ++dwIndex, sizeOfSubKeyName=51 )
3734 3735 3736 3737 3738 3739
    {

      HKEY     hkServiceProvider;
      GUID     serviceProviderGUID;
      DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
      char     returnBuffer[51];
3740
      WCHAR    buff[51];
3741
      DPNAME   dpName;
3742
      BOOL     bBuildPass;
3743 3744 3745

      LPVOID                   lpAddressBuffer = NULL;
      DWORD                    dwAddressBufferSize = 0;
3746 3747

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

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

      if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
3758
                            NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
3759 3760 3761
                            &sizeOfReturnBuffer ) != ERROR_SUCCESS )
      {
        ERR(": missing GUID registry data members\n" );
3762
        RegCloseKey(hkServiceProvider);
3763 3764
        continue;
      }
3765
      RegCloseKey(hkServiceProvider);
3766 3767

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

3772
      /* Fill in the DPNAME struct for the service provider */
3773 3774
      dpName.dwSize             = sizeof( dpName );
      dpName.dwFlags            = 0;
3775 3776
      dpName.u1.lpszShortNameA = subKeyName;
      dpName.u2.lpszLongNameA  = NULL;
3777

3778
      /* Create the compound address for the service provider.
Andreas Mohr's avatar
Andreas Mohr committed
3779 3780 3781 3782 3783 3784 3785
       * 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 :) */
3786 3787 3788 3789 3790

      bBuildPass = DP_BuildSPCompoundAddr( &serviceProviderGUID,
                                           &lpAddressBuffer,
                                           &dwAddressBufferSize );
      if( !bBuildPass )
3791
      {
3792 3793
        ERR( "Can't build compound addr\n" );
        return DPERR_GENERIC;
3794
      }
3795 3796

      /* The enumeration will return FALSE if we are not to continue */
3797
      if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3798
                           &dpName, dwFlags, lpContext ) )
3799
      {
3800
         return DP_OK;
3801 3802
      }
    }
3803 3804 3805 3806 3807
  }

  /* Enumerate DirectPlayLobby service providers */
  if( dwFlags & DPCONNECTION_DIRECTPLAYLOBBY )
  {
Peter Hunnisett's avatar
Peter Hunnisett committed
3808 3809
    HKEY hkResult;
    LPCSTR searchSubKey    = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
3810
    LPCSTR guidDataSubKey  = "Guid";
3811
    char subKeyName[51];
Peter Hunnisett's avatar
Peter Hunnisett committed
3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824
    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 )
    {
      /* Hmmm. Does this mean that there are no service providers? */
      ERR(": no service providers?\n");
      return DP_OK;
    }


3825
    /* Traverse all the lobby providers we have available */
Peter Hunnisett's avatar
Peter Hunnisett committed
3826
    for( dwIndex=0;
3827
         RegEnumKeyExA( hkResult, dwIndex, subKeyName, &sizeOfSubKeyName,
Peter Hunnisett's avatar
Peter Hunnisett committed
3828 3829 3830 3831 3832 3833 3834 3835
                        NULL, NULL, NULL, &filetime ) != ERROR_NO_MORE_ITEMS;
         ++dwIndex, sizeOfSubKeyName=51 )
    {

      HKEY     hkServiceProvider;
      GUID     serviceProviderGUID;
      DWORD    returnTypeGUID, sizeOfReturnBuffer = 50;
      char     returnBuffer[51];
3836
      WCHAR    buff[51];
Peter Hunnisett's avatar
Peter Hunnisett committed
3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854
      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,
3855
                            NULL, &returnTypeGUID, (LPBYTE)returnBuffer,
Peter Hunnisett's avatar
Peter Hunnisett committed
3856 3857 3858
                            &sizeOfReturnBuffer ) != ERROR_SUCCESS )
      {
        ERR(": missing GUID registry data members\n" );
3859
        RegCloseKey(hkServiceProvider);
Peter Hunnisett's avatar
Peter Hunnisett committed
3860 3861
        continue;
      }
3862
      RegCloseKey(hkServiceProvider);
Peter Hunnisett's avatar
Peter Hunnisett committed
3863 3864

      /* FIXME: Check return types to ensure we're interpreting data right */
3865
      MultiByteToWideChar( CP_ACP, 0, returnBuffer, -1, buff, sizeof(buff)/sizeof(WCHAR) );
3866
      CLSIDFromString( buff, &serviceProviderGUID );
Peter Hunnisett's avatar
Peter Hunnisett committed
3867 3868 3869 3870 3871
      /* 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;
3872 3873
      dpName.u1.lpszShortNameA = subKeyName;
      dpName.u2.lpszLongNameA  = NULL;
Peter Hunnisett's avatar
Peter Hunnisett committed
3874

3875
      /* Create the compound address for the service provider.
3876 3877 3878 3879
         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
3880
               despite this method taking slightly more heap space and realtime :) */
3881

3882
      dpCompoundAddress.guidDataType = DPAID_LobbyProvider;
Peter Hunnisett's avatar
Peter Hunnisett committed
3883
      dpCompoundAddress.dwDataSize   = sizeof( GUID );
3884
      dpCompoundAddress.lpData       = &serviceProviderGUID;
Peter Hunnisett's avatar
Peter Hunnisett committed
3885

3886
      if( ( hr = DPL_CreateCompoundAddress( &dpCompoundAddress, 1, lpAddressBuffer,
Peter Hunnisett's avatar
Peter Hunnisett committed
3887 3888 3889 3890 3891 3892
                                     &dwAddressBufferSize, TRUE ) ) != DPERR_BUFFERTOOSMALL )
      {
        ERR( "can't get buffer size: %s\n", DPLAYX_HresultToString( hr ) );
        return hr;
      }

3893 3894 3895 3896 3897 3898 3899
      /* 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 ) );
3900
        HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3901 3902 3903 3904 3905
        return hr;
      }

      /* The enumeration will return FALSE if we are not to continue */
      if( !lpEnumCallback( &serviceProviderGUID, lpAddressBuffer, dwAddressBufferSize,
3906
                           &dpName, dwFlags, lpContext ) )
3907
      {
3908
         HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3909 3910
         return DP_OK;
      }
3911
      HeapFree( GetProcessHeap(), 0, lpAddressBuffer );
3912 3913 3914 3915 3916 3917 3918 3919
    }
  }

  return DP_OK;
}

static HRESULT WINAPI DirectPlay3WImpl_EnumConnections
          ( LPDIRECTPLAY3 iface, LPCGUID lpguidApplication, LPDPENUMCONNECTIONSCALLBACK lpEnumCallback, LPVOID lpContext, DWORD dwFlags )
3920
{
3921
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3922
  FIXME("(%p)->(%p,%p,%p,0x%08x): stub\n", This, lpguidApplication, lpEnumCallback, lpContext, dwFlags );
3923 3924 3925
  return DP_OK;
}

3926
static HRESULT DP_IF_EnumGroupsInGroup
3927
          ( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
3928
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
3929 3930 3931 3932 3933
            LPVOID lpContext, DWORD dwFlags, BOOL bAnsi )
{
  lpGroupList lpGList;
  lpGroupData lpGData;

3934
  FIXME( "(%p)->(0x%08x,%p,%p,%p,0x%08x,%u): semi stub\n",
3935
         This, idGroup, lpguidInstance, lpEnumPlayersCallback2,
3936 3937
         lpContext, dwFlags, bAnsi );

3938 3939 3940 3941 3942
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

3943
  if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978
  {
    return DPERR_INVALIDGROUP;
  }

  if( DPQ_IS_EMPTY( lpGData->groups ) )
  {
    return DP_OK;
  }

  lpGList = DPQ_FIRST( lpGData->groups );

  for( ;; )
  {
    /* FIXME: Should check dwFlags for match here */

    if( !(*lpEnumPlayersCallback2)( lpGList->lpGData->dpid, DPPLAYERTYPE_GROUP,
                                    &lpGList->lpGData->name, dwFlags,
                                    lpContext ) )
    {
      return DP_OK; /* User requested break */
    }

    if( DPQ_IS_ENDOFLIST( lpGList->groups ) )
    {
      break;
    }

    lpGList = DPQ_NEXT( lpGList->groups );

  }

  return DP_OK;
}

static HRESULT WINAPI DirectPlay3AImpl_EnumGroupsInGroup
3979 3980
          ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
3981 3982
            DWORD dwFlags )
{
3983
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3984
  return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
3985 3986 3987 3988 3989 3990 3991 3992 3993
                                  lpEnumPlayersCallback2, lpContext, dwFlags,
                                  TRUE );
}

static HRESULT WINAPI DirectPlay3WImpl_EnumGroupsInGroup
          ( LPDIRECTPLAY3A iface, DPID idGroup, LPGUID lpguidInstance,
            LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2, LPVOID lpContext,
            DWORD dwFlags )
{
3994
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
3995 3996 3997 3998 3999 4000 4001 4002
  return DP_IF_EnumGroupsInGroup( This, idGroup, lpguidInstance,
                                  lpEnumPlayersCallback2, lpContext, dwFlags,
                                  FALSE );
}

static HRESULT WINAPI DirectPlay3AImpl_GetGroupConnectionSettings
          ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
{
4003
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4004
  FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4005 4006 4007 4008 4009 4010
  return DP_OK;
}

static HRESULT WINAPI DirectPlay3WImpl_GetGroupConnectionSettings
          ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPVOID lpData, LPDWORD lpdwDataSize )
{
4011
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4012
  FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, dwFlags, idGroup, lpData, lpdwDataSize );
4013 4014 4015
  return DP_OK;
}

4016
static BOOL CALLBACK DP_GetSpLpGuidFromCompoundAddress(
4017 4018 4019 4020 4021 4022 4023 4024 4025 4026
    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 ) )
    )
  {
4027
    TRACE( "Found SP/LP (%s) %s (data size = 0x%08x)\n",
4028 4029 4030 4031
           debugstr_guid( guidDataType ), debugstr_guid( lpData ), dwDataSize );

    if( dwDataSize != sizeof( GUID ) )
    {
4032
      ERR( "Invalid sp/lp guid size 0x%08x\n", dwDataSize );
4033 4034 4035 4036 4037 4038 4039
    }

    memcpy( lpContext, lpData, dwDataSize );

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

4041 4042 4043 4044 4045 4046
  /* Still waiting for what we want */
  return TRUE;
}


/* Find and perform a LoadLibrary on the requested SP or LP GUID */
4047
static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp )
4048
{
4049
  UINT i;
4050
  LPCSTR spSubKey         = "SOFTWARE\\Microsoft\\DirectPlay\\Service Providers";
4051
  LPCSTR lpSubKey         = "SOFTWARE\\Microsoft\\DirectPlay\\Lobby Providers";
4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068
  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 );
4069
    *lpbIsDpSp = (i == 0) ? TRUE : FALSE;
4070

4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091

    /* 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];
4092 4093
      WCHAR    buff[51];
      DWORD    dwTemp, len;
4094 4095

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

4097 4098 4099
      /* 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
4100
      {
4101 4102
         ERR(": what the heck is going on?\n" );
         continue;
Peter Hunnisett's avatar
Peter Hunnisett committed
4103 4104
      }

4105
      if( RegQueryValueExA( hkServiceProvider, guidDataSubKey,
4106
                            NULL, &returnType, (LPBYTE)returnBuffer,
4107
                            &sizeOfReturnBuffer ) != ERROR_SUCCESS )
Peter Hunnisett's avatar
Peter Hunnisett committed
4108
      {
4109 4110
        ERR(": missing GUID registry data members\n" );
        continue;
Peter Hunnisett's avatar
Peter Hunnisett committed
4111
      }
4112

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

4118 4119 4120 4121 4122
      /* Determine if this is the Service Provider that the user asked for */
      if( !IsEqualGUID( &serviceProviderGUID, lpcGuid ) )
      {
        continue;
      }
4123

4124 4125 4126 4127 4128 4129
      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 );
      }
4130

4131
      sizeOfReturnBuffer = 255;
4132

4133 4134
      /* Get dwReserved1 */
      if( RegQueryValueExA( hkServiceProvider, majVerDataSubKey,
4135
                            NULL, &returnType, (LPBYTE)returnBuffer,
4136 4137 4138 4139 4140
                            &sizeOfReturnBuffer ) != ERROR_SUCCESS )
      {
         ERR(": missing dwReserved1 registry data members\n") ;
         continue;
      }
4141

4142
      if( i == 0 )
4143 4144
          memcpy( &lpSpData->dwReserved1, returnBuffer, sizeof(lpSpData->dwReserved1) );

4145
      sizeOfReturnBuffer = 255;
4146

4147 4148
      /* Get dwReserved2 */
      if( RegQueryValueExA( hkServiceProvider, minVerDataSubKey,
4149
                            NULL, &returnType, (LPBYTE)returnBuffer,
4150 4151 4152 4153 4154
                            &sizeOfReturnBuffer ) != ERROR_SUCCESS )
      {
         ERR(": missing dwReserved1 registry data members\n") ;
         continue;
      }
4155

4156
      if( i == 0 )
4157
          memcpy( &lpSpData->dwReserved2, returnBuffer, sizeof(lpSpData->dwReserved2) );
4158

4159
      sizeOfReturnBuffer = 255;
4160

4161 4162
      /* Get the path for this service provider */
      if( ( dwTemp = RegQueryValueExA( hkServiceProvider, pathSubKey,
4163
                            NULL, NULL, (LPBYTE)returnBuffer,
4164 4165
                            &sizeOfReturnBuffer ) ) != ERROR_SUCCESS )
      {
4166
        ERR(": missing PATH registry data members: 0x%08x\n", dwTemp );
4167 4168
        continue;
      }
4169

4170
      TRACE( "Loading %s\n", returnBuffer );
4171 4172 4173
      return LoadLibraryA( returnBuffer );
    }
  }
4174

4175
  return 0;
4176 4177
}

4178 4179 4180 4181 4182 4183 4184 4185
static
HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider )
{
  HRESULT hr;
  LPDPSP_SPINIT SPInit;

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

4187 4188 4189 4190 4191
  if( SPInit == NULL )
  {
    ERR( "Service provider doesn't provide SPInit interface?\n" );
    FreeLibrary( hServiceProvider );
    return DPERR_UNAVAILABLE;
4192
  }
4193 4194

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

4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213
  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;
4214

4215 4216 4217 4218 4219 4220 4221 4222
  return hr;
}

static
HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hLobbyProvider )
{
  HRESULT hr;
  LPSP_INIT DPLSPInit;
4223

4224 4225
  /* Initialize the service provider by calling SPInit */
  DPLSPInit = (LPSP_INIT)GetProcAddress( hLobbyProvider, "DPLSPInit" );
4226

4227 4228 4229 4230 4231
  if( DPLSPInit == NULL )
  {
    ERR( "Service provider doesn't provide DPLSPInit interface?\n" );
    FreeLibrary( hLobbyProvider );
    return DPERR_UNAVAILABLE;
4232
  }
4233 4234

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

4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248
  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;
4249

4250 4251 4252 4253 4254
  /* 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;
4255

4256 4257 4258
  return hr;
}

4259
static HRESULT DP_IF_InitializeConnection
4260
          ( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi )
4261
{
4262
  HMODULE hServiceProvider;
4263 4264
  HRESULT hr;
  GUID guidSP;
4265 4266
  const DWORD dwAddrSize = 80; /* FIXME: Need to calculate it correctly */
  BOOL bIsDpSp; /* TRUE if Direct Play SP, FALSE if Direct Play Lobby SP */
4267

4268
  TRACE("(%p)->(%p,0x%08x,%u)\n", This, lpConnection, dwFlags, bAnsi );
4269

4270 4271 4272 4273 4274
  if ( lpConnection == NULL )
  {
    return DPERR_INVALIDPARAMS;
  }

4275 4276 4277 4278 4279
  if( dwFlags != 0 )
  {
    return DPERR_INVALIDFLAGS;
  }

4280 4281 4282 4283 4284
  if( This->dp2->connectionInitialized != NO_PROVIDER )
  {
    return DPERR_ALREADYINITIALIZED;
  }

4285
  /* Find out what the requested SP is and how large this buffer is */
4286
  hr = DPL_EnumAddress( DP_GetSpLpGuidFromCompoundAddress, lpConnection,
4287 4288 4289 4290 4291 4292 4293 4294 4295
                        dwAddrSize, &guidSP );

  if( FAILED(hr) )
  {
    ERR( "Invalid compound address?\n" );
    return DPERR_UNAVAILABLE;
  }

  /* Load the service provider */
4296
  hServiceProvider = DP_LoadSP( &guidSP, &This->dp2->spData, &bIsDpSp );
4297 4298 4299

  if( hServiceProvider == 0 )
  {
4300
    ERR( "Unable to load service provider %s\n", debugstr_guid(&guidSP) );
4301
    return DPERR_UNAVAILABLE;
4302
  }
4303

4304 4305
  if( bIsDpSp )
  {
4306 4307 4308 4309 4310 4311 4312 4313
     /* Fill in what we can of the Service Provider required information.
      * The rest was be done in DP_LoadSP
      */
     This->dp2->spData.lpAddress = lpConnection;
     This->dp2->spData.dwAddressSize = dwAddrSize;
     This->dp2->spData.lpGuid = &guidSP;

     hr = DP_InitializeDPSP( This, hServiceProvider );
4314 4315 4316
  }
  else
  {
4317
     This->dp2->dplspData.lpAddress = lpConnection;
4318

4319 4320
     hr = DP_InitializeDPLSP( This, hServiceProvider );
  }
4321

4322 4323 4324 4325
  if( FAILED(hr) )
  {
    return hr;
  }
4326

4327 4328 4329
  return DP_OK;
}

4330 4331 4332
static HRESULT WINAPI DirectPlay3AImpl_InitializeConnection
          ( LPDIRECTPLAY3A iface, LPVOID lpConnection, DWORD dwFlags )
{
4333
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4334 4335 4336 4337 4338

  /* This may not be externally invoked once either an SP or LP is initialized */
  if( This->dp2->connectionInitialized != NO_PROVIDER )
  {
    return DPERR_ALREADYINITIALIZED;
4339
  }
4340

4341
  return DP_IF_InitializeConnection( This, lpConnection, dwFlags, TRUE );
4342 4343
}

4344 4345 4346
static HRESULT WINAPI DirectPlay3WImpl_InitializeConnection
          ( LPDIRECTPLAY3 iface, LPVOID lpConnection, DWORD dwFlags )
{
4347
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4348 4349 4350 4351 4352 4353 4354

  /* This may not be externally invoked once either an SP or LP is initialized */
  if( This->dp2->connectionInitialized != NO_PROVIDER )
  {
    return DPERR_ALREADYINITIALIZED;
  }

4355
  return DP_IF_InitializeConnection( This, lpConnection, dwFlags, FALSE );
4356 4357 4358
}

static HRESULT WINAPI DirectPlay3AImpl_SecureOpen
4359
          ( LPDIRECTPLAY3A iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4360
            LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4361
{
4362
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4363
  return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, TRUE );
4364 4365 4366
}

static HRESULT WINAPI DirectPlay3WImpl_SecureOpen
4367
          ( LPDIRECTPLAY3 iface, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
4368
            LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials )
4369
{
4370
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* Yes a dp 2 interface */
4371
  return DP_SecureOpen( This, lpsd, dwFlags, lpSecurity, lpCredentials, FALSE );
4372 4373 4374 4375 4376
}

static HRESULT WINAPI DirectPlay3AImpl_SendChatMessage
          ( LPDIRECTPLAY3A iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
{
4377
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4378
  FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4379 4380 4381 4382 4383 4384
  return DP_OK;
}

static HRESULT WINAPI DirectPlay3WImpl_SendChatMessage
          ( LPDIRECTPLAY3 iface, DPID idFrom, DPID idTo, DWORD dwFlags, LPDPCHAT lpChatMessage )
{
4385
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4386
  FIXME("(%p)->(0x%08x,0x%08x,0x%08x,%p): stub\n", This, idFrom, idTo, dwFlags, lpChatMessage );
4387 4388 4389 4390 4391 4392
  return DP_OK;
}

static HRESULT WINAPI DirectPlay3AImpl_SetGroupConnectionSettings
          ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
{
4393
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4394
  FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4395 4396 4397 4398 4399 4400
  return DP_OK;
}

static HRESULT WINAPI DirectPlay3WImpl_SetGroupConnectionSettings
          ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup, LPDPLCONNECTION lpConnection )
{
4401
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4402
  FIXME("(%p)->(0x%08x,0x%08x,%p): stub\n", This, dwFlags, idGroup, lpConnection );
4403 4404 4405 4406 4407 4408
  return DP_OK;
}

static HRESULT WINAPI DirectPlay3AImpl_StartSession
          ( LPDIRECTPLAY3A iface, DWORD dwFlags, DPID idGroup )
{
4409
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4410
  FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4411 4412 4413 4414 4415 4416
  return DP_OK;
}

static HRESULT WINAPI DirectPlay3WImpl_StartSession
          ( LPDIRECTPLAY3 iface, DWORD dwFlags, DPID idGroup )
{
4417
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4418
  FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, dwFlags, idGroup );
4419 4420
  return DP_OK;
}
4421

4422 4423 4424
static HRESULT WINAPI DirectPlay3AImpl_GetGroupFlags
          ( LPDIRECTPLAY3A iface, DPID idGroup, LPDWORD lpdwFlags )
{
4425
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4426
  FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4427 4428 4429 4430 4431 4432
  return DP_OK;
}

static HRESULT WINAPI DirectPlay3WImpl_GetGroupFlags
          ( LPDIRECTPLAY3 iface, DPID idGroup, LPDWORD lpdwFlags )
{
4433
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4434
  FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpdwFlags );
4435 4436 4437
  return DP_OK;
}

4438
static HRESULT DP_IF_GetGroupParent
4439
          ( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
4440
            BOOL bAnsi )
4441
{
4442
  lpGroupData lpGData;
4443

4444
  TRACE("(%p)->(0x%08x,%p,%u)\n", This, idGroup, lpidGroup, bAnsi );
4445

4446
  if( ( lpGData = DP_FindAnyGroup( (IDirectPlay2AImpl*)This, idGroup ) ) == NULL )
4447 4448 4449 4450
  {
    return DPERR_INVALIDGROUP;
  }

4451
  *lpidGroup = lpGData->dpid;
4452

4453 4454 4455
  return DP_OK;
}

4456 4457 4458
static HRESULT WINAPI DirectPlay3AImpl_GetGroupParent
          ( LPDIRECTPLAY3A iface, DPID idGroup, LPDPID lpidGroup )
{
4459
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4460
  return DP_IF_GetGroupParent( This, idGroup, lpidGroup, TRUE );
4461
}
4462 4463 4464
static HRESULT WINAPI DirectPlay3WImpl_GetGroupParent
          ( LPDIRECTPLAY3 iface, DPID idGroup, LPDPID lpidGroup )
{
4465
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4466
  return DP_IF_GetGroupParent( This, idGroup, lpidGroup, FALSE );
4467 4468 4469 4470 4471
}

static HRESULT WINAPI DirectPlay3AImpl_GetPlayerAccount
          ( LPDIRECTPLAY3A iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
{
4472
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4473
  FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4474 4475 4476 4477 4478 4479
  return DP_OK;
}

static HRESULT WINAPI DirectPlay3WImpl_GetPlayerAccount
          ( LPDIRECTPLAY3 iface, DPID idPlayer, DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize )
{
4480
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4481
  FIXME("(%p)->(0x%08x,0x%08x,%p,%p): stub\n", This, idPlayer, dwFlags, lpData, lpdwDataSize );
4482 4483 4484 4485 4486 4487
  return DP_OK;
}

static HRESULT WINAPI DirectPlay3AImpl_GetPlayerFlags
          ( LPDIRECTPLAY3A iface, DPID idPlayer, LPDWORD lpdwFlags )
{
4488
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4489
  FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4490 4491 4492 4493 4494 4495
  return DP_OK;
}

static HRESULT WINAPI DirectPlay3WImpl_GetPlayerFlags
          ( LPDIRECTPLAY3 iface, DPID idPlayer, LPDWORD lpdwFlags )
{
4496
  IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
4497
  FIXME("(%p)->(0x%08x,%p): stub\n", This, idPlayer, lpdwFlags );
4498 4499 4500 4501 4502 4503
  return DP_OK;
}

static HRESULT WINAPI DirectPlay4AImpl_GetGroupOwner
          ( LPDIRECTPLAY4A iface, DPID idGroup, LPDPID lpidGroupOwner )
{
4504
  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4505
  FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4506 4507 4508 4509 4510 4511
  return DP_OK;
}

static HRESULT WINAPI DirectPlay4WImpl_GetGroupOwner
          ( LPDIRECTPLAY4 iface, DPID idGroup, LPDPID lpidGroupOwner )
{
4512
  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4513
  FIXME("(%p)->(0x%08x,%p): stub\n", This, idGroup, lpidGroupOwner );
4514 4515 4516 4517 4518 4519
  return DP_OK;
}

static HRESULT WINAPI DirectPlay4AImpl_SetGroupOwner
          ( LPDIRECTPLAY4A iface, DPID idGroup , DPID idGroupOwner )
{
4520
  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4521
  FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4522 4523 4524 4525 4526 4527
  return DP_OK;
}

static HRESULT WINAPI DirectPlay4WImpl_SetGroupOwner
          ( LPDIRECTPLAY4 iface, DPID idGroup , DPID idGroupOwner )
{
4528
  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4529
  FIXME("(%p)->(0x%08x,0x%08x): stub\n", This, idGroup, idGroupOwner );
4530 4531 4532
  return DP_OK;
}

4533
static HRESULT DP_SendEx
4534
          ( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4535 4536 4537 4538 4539
            LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
            LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi )
{
  BOOL         bValidDestination = FALSE;

4540
  FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,0x%08x,0x%08x,0x%08x,%p,%p,%u)"
4541 4542 4543 4544
         ": stub\n",
         This, idFrom, idTo, dwFlags, lpData, dwDataSize, dwPriority,
         dwTimeout, lpContext, lpdwMsgID, bAnsi );

4545 4546 4547 4548 4549
  if( This->dp2->connectionInitialized == NO_PROVIDER )
  {
    return DPERR_UNINITIALIZED;
  }

4550
  /* FIXME: Add parameter checking */
4551
  /* FIXME: First call to this needs to acquire a message id which will be
4552 4553 4554 4555 4556 4557 4558 4559 4560 4561
   *        used for multiple sends
   */

  /* NOTE: Can't send messages to yourself - this will be trapped in receive */

  /* Verify that the message is being sent from a valid local player. The
   * from player may be anonymous DPID_UNKNOWN
   */
  if( idFrom != DPID_UNKNOWN )
  {
4562
    if( DP_FindPlayer( This, idFrom ) == NULL )
4563
    {
4564
      WARN( "INFO: Invalid from player 0x%08x\n", idFrom );
4565 4566 4567 4568 4569 4570 4571 4572 4573
      return DPERR_INVALIDPLAYER;
    }
  }

  /* 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( idTo == DPID_ALLPLAYERS )
  {
4574
    bValidDestination = TRUE;
4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591

    /* 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 */
    {
      /* Send to all players we know about */
      FIXME( "Send to all players using EnumPlayersInGroup\n" );
    }
  }

4592
  if( ( !bValidDestination ) &&
4593 4594 4595 4596 4597
      ( DP_FindPlayer( This, idTo ) != NULL )
    )
  {
    bValidDestination = TRUE;

Peter Hunnisett's avatar
Peter Hunnisett committed
4598
    /* Have the service provider send this message */
4599 4600 4601 4602 4603 4604
    /* FIXME: Could optimize for local interface sends */
    return DP_SP_SendEx( This, dwFlags, lpData, dwDataSize, dwPriority,
                         dwTimeout, lpContext, lpdwMsgID );
  }

  if( ( !bValidDestination ) &&
4605
      ( DP_FindAnyGroup( This, idTo ) != NULL )
4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622
    )
  {
    bValidDestination = TRUE;

    /* 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
4623 4624 4625 4626 4627 4628

#if 0
    if( bExpectReply )
    {
      DWORD dwWaitReturn;

4629
      This->dp2->hReplyEvent = CreateEventW( NULL, FALSE, FALSE, NULL );
Peter Hunnisett's avatar
Peter Hunnisett committed
4630 4631 4632 4633 4634 4635 4636 4637

      dwWaitReturn = WaitForSingleObject( hReplyEvent, dwTimeout );
      if( dwWaitReturn != WAIT_OBJECT_0 )
      {
        ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
      }
    }
#endif
4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651
  }

  if( !bValidDestination )
  {
    return DPERR_INVALIDPLAYER;
  }
  else
  {
    /* FIXME: Should return what the send returned */
    return DP_OK;
  }
}


4652
static HRESULT WINAPI DirectPlay4AImpl_SendEx
4653
          ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4654 4655
            LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
            LPVOID lpContext, LPDWORD lpdwMsgID )
4656
{
4657
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4658
  return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4659
                    dwPriority, dwTimeout, lpContext, lpdwMsgID, TRUE );
4660 4661 4662
}

static HRESULT WINAPI DirectPlay4WImpl_SendEx
4663
          ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4664 4665 4666
            LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
            LPVOID lpContext, LPDWORD lpdwMsgID )
{
4667
  IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface; /* yes downcast to 2 */
4668
  return DP_SendEx( This, idFrom, idTo, dwFlags, lpData, dwDataSize,
4669 4670 4671
                    dwPriority, dwTimeout, lpContext, lpdwMsgID, FALSE );
}

4672
static HRESULT DP_SP_SendEx
4673 4674 4675 4676 4677 4678
          ( IDirectPlay2Impl* This, DWORD dwFlags,
            LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
            LPVOID lpContext, LPDWORD lpdwMsgID )
{
  LPDPMSG lpMElem;

Peter Hunnisett's avatar
Peter Hunnisett committed
4679
  FIXME( ": stub\n" );
4680

Peter Hunnisett's avatar
Peter Hunnisett committed
4681
  /* FIXME: This queuing should only be for async messages */
4682

4683 4684
  lpMElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpMElem ) );
  lpMElem->msg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
4685 4686 4687

  CopyMemory( lpMElem->msg, lpData, dwDataSize );

Peter Hunnisett's avatar
Peter Hunnisett committed
4688
  /* FIXME: Need to queue based on priority */
4689 4690
  DPQ_INSERT( This->dp2->sendMsgs, lpMElem, msgs );

4691 4692 4693
  return DP_OK;
}

4694
static HRESULT DP_IF_GetMessageQueue
4695
          ( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
4696 4697 4698 4699
            LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi )
{
  HRESULT hr = DP_OK;

4700
  FIXME( "(%p)->(0x%08x,0x%08x,0x%08x,%p,%p,%u): semi stub\n",
4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714
         This, idFrom, idTo, dwFlags, lpdwNumMsgs, lpdwNumBytes, bAnsi );

  /* FIXME: Do we need to do idFrom and idTo sanity checking here? */
  /* FIXME: What about sends which are not immediate? */

  if( This->dp2->spData.lpCB->GetMessageQueue )
  {
    DPSP_GETMESSAGEQUEUEDATA data;

    FIXME( "Calling SP GetMessageQueue - is it right?\n" );

    /* FIXME: None of this is documented :( */

    data.lpISP        = This->dp2->spData.lpISP;
4715
    data.dwFlags      = dwFlags;
4716 4717 4718 4719
    data.idFrom       = idFrom;
    data.idTo         = idTo;
    data.lpdwNumMsgs  = lpdwNumMsgs;
    data.lpdwNumBytes = lpdwNumBytes;
4720

Peter Hunnisett's avatar
Peter Hunnisett committed
4721
    hr = (*This->dp2->spData.lpCB->GetMessageQueue)( &data );
4722 4723 4724 4725 4726 4727 4728 4729 4730
  }
  else
  {
    FIXME( "No SP for GetMessageQueue - fake some data\n" );
  }

  return hr;
}

4731
static HRESULT WINAPI DirectPlay4AImpl_GetMessageQueue
4732
          ( LPDIRECTPLAY4A iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4733
            LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4734
{
4735
  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4736 4737
  return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
                                lpdwNumBytes, TRUE );
4738 4739 4740
}

static HRESULT WINAPI DirectPlay4WImpl_GetMessageQueue
4741
          ( LPDIRECTPLAY4 iface, DPID idFrom, DPID idTo, DWORD dwFlags,
4742
            LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes )
4743
{
4744
  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4745 4746 4747 4748
  return DP_IF_GetMessageQueue( This, idFrom, idTo, dwFlags, lpdwNumMsgs,
                                lpdwNumBytes, FALSE );
}

4749
static HRESULT DP_IF_CancelMessage
4750
          ( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
4751 4752 4753 4754
            DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi )
{
  HRESULT hr = DP_OK;

4755
  FIXME( "(%p)->(0x%08x,0x%08x,%u): semi stub\n",
4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772
         This, dwMsgID, dwFlags, bAnsi );

  if( This->dp2->spData.lpCB->Cancel )
  {
    DPSP_CANCELDATA data;

    TRACE( "Calling SP Cancel\n" );

    /* FIXME: Undocumented callback */

    data.lpISP          = This->dp2->spData.lpISP;
    data.dwFlags        = dwFlags;
    data.lprglpvSPMsgID = NULL;
    data.cSPMsgID       = dwMsgID;
    data.dwMinPriority  = dwMinPriority;
    data.dwMaxPriority  = dwMaxPriority;

Peter Hunnisett's avatar
Peter Hunnisett committed
4773
    hr = (*This->dp2->spData.lpCB->Cancel)( &data );
4774 4775 4776 4777 4778 4779 4780
  }
  else
  {
    FIXME( "SP doesn't implement Cancel\n" );
  }

  return hr;
4781 4782 4783 4784 4785
}

static HRESULT WINAPI DirectPlay4AImpl_CancelMessage
          ( LPDIRECTPLAY4A iface, DWORD dwMsgID, DWORD dwFlags )
{
4786
  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4787 4788 4789 4790 4791 4792 4793 4794 4795 4796

  if( dwFlags != 0 )
  {
    return DPERR_INVALIDFLAGS;
  }

  if( dwMsgID == 0 )
  {
    dwFlags |= DPCANCELSEND_ALL;
  }
4797

4798
  return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, TRUE );
4799 4800 4801 4802 4803
}

static HRESULT WINAPI DirectPlay4WImpl_CancelMessage
          ( LPDIRECTPLAY4 iface, DWORD dwMsgID, DWORD dwFlags )
{
4804
  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816

  if( dwFlags != 0 )
  {
    return DPERR_INVALIDFLAGS;
  }

  if( dwMsgID == 0 )
  {
    dwFlags |= DPCANCELSEND_ALL;
  }

  return DP_IF_CancelMessage( This, dwMsgID, dwFlags, 0, 0, FALSE );
4817 4818 4819
}

static HRESULT WINAPI DirectPlay4AImpl_CancelPriority
4820
          ( LPDIRECTPLAY4A iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4821
            DWORD dwFlags )
4822
{
4823
  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4824 4825 4826 4827 4828 4829

  if( dwFlags != 0 )
  {
    return DPERR_INVALIDFLAGS;
  }

4830
  return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4831
                              dwMaxPriority, TRUE );
4832 4833 4834
}

static HRESULT WINAPI DirectPlay4WImpl_CancelPriority
4835
          ( LPDIRECTPLAY4 iface, DWORD dwMinPriority, DWORD dwMaxPriority,
4836
            DWORD dwFlags )
4837
{
4838
  IDirectPlay4Impl *This = (IDirectPlay4Impl *)iface;
4839 4840 4841 4842 4843 4844

  if( dwFlags != 0 )
  {
    return DPERR_INVALIDFLAGS;
  }

4845
  return DP_IF_CancelMessage( This, 0, DPCANCELSEND_PRIORITY, dwMinPriority,
4846
                              dwMaxPriority, FALSE );
4847 4848 4849 4850
}

/* Note: Hack so we can reuse the old functions without compiler warnings */
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4851
# define XCAST(fun)     (typeof(directPlay2WVT.fun))
4852 4853 4854 4855
#else
# define XCAST(fun)     (void*)
#endif

4856
static const IDirectPlay2Vtbl directPlay2WVT =
4857
{
4858 4859 4860
  XCAST(QueryInterface)DP_QueryInterface,
  XCAST(AddRef)DP_AddRef,
  XCAST(Release)DP_Release,
4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895

  DirectPlay2WImpl_AddPlayerToGroup,
  DirectPlay2WImpl_Close,
  DirectPlay2WImpl_CreateGroup,
  DirectPlay2WImpl_CreatePlayer,
  DirectPlay2WImpl_DeletePlayerFromGroup,
  DirectPlay2WImpl_DestroyGroup,
  DirectPlay2WImpl_DestroyPlayer,
  DirectPlay2WImpl_EnumGroupPlayers,
  DirectPlay2WImpl_EnumGroups,
  DirectPlay2WImpl_EnumPlayers,
  DirectPlay2WImpl_EnumSessions,
  DirectPlay2WImpl_GetCaps,
  DirectPlay2WImpl_GetGroupData,
  DirectPlay2WImpl_GetGroupName,
  DirectPlay2WImpl_GetMessageCount,
  DirectPlay2WImpl_GetPlayerAddress,
  DirectPlay2WImpl_GetPlayerCaps,
  DirectPlay2WImpl_GetPlayerData,
  DirectPlay2WImpl_GetPlayerName,
  DirectPlay2WImpl_GetSessionDesc,
  DirectPlay2WImpl_Initialize,
  DirectPlay2WImpl_Open,
  DirectPlay2WImpl_Receive,
  DirectPlay2WImpl_Send,
  DirectPlay2WImpl_SetGroupData,
  DirectPlay2WImpl_SetGroupName,
  DirectPlay2WImpl_SetPlayerData,
  DirectPlay2WImpl_SetPlayerName,
  DirectPlay2WImpl_SetSessionDesc
};
#undef XCAST

/* Note: Hack so we can reuse the old functions without compiler warnings */
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4896
# define XCAST(fun)     (typeof(directPlay2AVT.fun))
4897 4898 4899 4900
#else
# define XCAST(fun)     (void*)
#endif

4901
static const IDirectPlay2Vtbl directPlay2AVT =
4902
{
4903 4904 4905
  XCAST(QueryInterface)DP_QueryInterface,
  XCAST(AddRef)DP_AddRef,
  XCAST(Release)DP_Release,
4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941

  DirectPlay2AImpl_AddPlayerToGroup,
  DirectPlay2AImpl_Close,
  DirectPlay2AImpl_CreateGroup,
  DirectPlay2AImpl_CreatePlayer,
  DirectPlay2AImpl_DeletePlayerFromGroup,
  DirectPlay2AImpl_DestroyGroup,
  DirectPlay2AImpl_DestroyPlayer,
  DirectPlay2AImpl_EnumGroupPlayers,
  DirectPlay2AImpl_EnumGroups,
  DirectPlay2AImpl_EnumPlayers,
  DirectPlay2AImpl_EnumSessions,
  DirectPlay2AImpl_GetCaps,
  DirectPlay2AImpl_GetGroupData,
  DirectPlay2AImpl_GetGroupName,
  DirectPlay2AImpl_GetMessageCount,
  DirectPlay2AImpl_GetPlayerAddress,
  DirectPlay2AImpl_GetPlayerCaps,
  DirectPlay2AImpl_GetPlayerData,
  DirectPlay2AImpl_GetPlayerName,
  DirectPlay2AImpl_GetSessionDesc,
  DirectPlay2AImpl_Initialize,
  DirectPlay2AImpl_Open,
  DirectPlay2AImpl_Receive,
  DirectPlay2AImpl_Send,
  DirectPlay2AImpl_SetGroupData,
  DirectPlay2AImpl_SetGroupName,
  DirectPlay2AImpl_SetPlayerData,
  DirectPlay2AImpl_SetPlayerName,
  DirectPlay2AImpl_SetSessionDesc
};
#undef XCAST


/* Note: Hack so we can reuse the old functions without compiler warnings */
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
4942
# define XCAST(fun)     (typeof(directPlay3AVT.fun))
4943 4944 4945 4946
#else
# define XCAST(fun)     (void*)
#endif

4947
static const IDirectPlay3Vtbl directPlay3AVT =
4948
{
4949 4950 4951
  XCAST(QueryInterface)DP_QueryInterface,
  XCAST(AddRef)DP_AddRef,
  XCAST(Release)DP_Release,
4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002

  XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
  XCAST(Close)DirectPlay2AImpl_Close,
  XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
  XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
  XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
  XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
  XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
  XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
  XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
  XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
  XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
  XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
  XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
  XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
  XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
  XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
  XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
  XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
  XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
  XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
  XCAST(Initialize)DirectPlay2AImpl_Initialize,
  XCAST(Open)DirectPlay2AImpl_Open,
  XCAST(Receive)DirectPlay2AImpl_Receive,
  XCAST(Send)DirectPlay2AImpl_Send,
  XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
  XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
  XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
  XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
  XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,

  DirectPlay3AImpl_AddGroupToGroup,
  DirectPlay3AImpl_CreateGroupInGroup,
  DirectPlay3AImpl_DeleteGroupFromGroup,
  DirectPlay3AImpl_EnumConnections,
  DirectPlay3AImpl_EnumGroupsInGroup,
  DirectPlay3AImpl_GetGroupConnectionSettings,
  DirectPlay3AImpl_InitializeConnection,
  DirectPlay3AImpl_SecureOpen,
  DirectPlay3AImpl_SendChatMessage,
  DirectPlay3AImpl_SetGroupConnectionSettings,
  DirectPlay3AImpl_StartSession,
  DirectPlay3AImpl_GetGroupFlags,
  DirectPlay3AImpl_GetGroupParent,
  DirectPlay3AImpl_GetPlayerAccount,
  DirectPlay3AImpl_GetPlayerFlags
};
#undef XCAST

/* Note: Hack so we can reuse the old functions without compiler warnings */
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5003
# define XCAST(fun)     (typeof(directPlay3WVT.fun))
5004 5005 5006
#else
# define XCAST(fun)     (void*)
#endif
5007
static const IDirectPlay3Vtbl directPlay3WVT =
5008
{
5009 5010 5011
  XCAST(QueryInterface)DP_QueryInterface,
  XCAST(AddRef)DP_AddRef,
  XCAST(Release)DP_Release,
5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062

  XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
  XCAST(Close)DirectPlay2WImpl_Close,
  XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
  XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
  XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
  XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
  XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
  XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
  XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
  XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
  XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
  XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
  XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
  XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
  XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
  XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
  XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
  XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
  XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
  XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
  XCAST(Initialize)DirectPlay2WImpl_Initialize,
  XCAST(Open)DirectPlay2WImpl_Open,
  XCAST(Receive)DirectPlay2WImpl_Receive,
  XCAST(Send)DirectPlay2WImpl_Send,
  XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
  XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
  XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
  XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
  XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,

  DirectPlay3WImpl_AddGroupToGroup,
  DirectPlay3WImpl_CreateGroupInGroup,
  DirectPlay3WImpl_DeleteGroupFromGroup,
  DirectPlay3WImpl_EnumConnections,
  DirectPlay3WImpl_EnumGroupsInGroup,
  DirectPlay3WImpl_GetGroupConnectionSettings,
  DirectPlay3WImpl_InitializeConnection,
  DirectPlay3WImpl_SecureOpen,
  DirectPlay3WImpl_SendChatMessage,
  DirectPlay3WImpl_SetGroupConnectionSettings,
  DirectPlay3WImpl_StartSession,
  DirectPlay3WImpl_GetGroupFlags,
  DirectPlay3WImpl_GetGroupParent,
  DirectPlay3WImpl_GetPlayerAccount,
  DirectPlay3WImpl_GetPlayerFlags
};
#undef XCAST

/* Note: Hack so we can reuse the old functions without compiler warnings */
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5063
# define XCAST(fun)     (typeof(directPlay4WVT.fun))
5064 5065 5066
#else
# define XCAST(fun)     (void*)
#endif
5067
static const IDirectPlay4Vtbl directPlay4WVT =
5068
{
5069 5070 5071
  XCAST(QueryInterface)DP_QueryInterface,
  XCAST(AddRef)DP_AddRef,
  XCAST(Release)DP_Release,
5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130

  XCAST(AddPlayerToGroup)DirectPlay2WImpl_AddPlayerToGroup,
  XCAST(Close)DirectPlay2WImpl_Close,
  XCAST(CreateGroup)DirectPlay2WImpl_CreateGroup,
  XCAST(CreatePlayer)DirectPlay2WImpl_CreatePlayer,
  XCAST(DeletePlayerFromGroup)DirectPlay2WImpl_DeletePlayerFromGroup,
  XCAST(DestroyGroup)DirectPlay2WImpl_DestroyGroup,
  XCAST(DestroyPlayer)DirectPlay2WImpl_DestroyPlayer,
  XCAST(EnumGroupPlayers)DirectPlay2WImpl_EnumGroupPlayers,
  XCAST(EnumGroups)DirectPlay2WImpl_EnumGroups,
  XCAST(EnumPlayers)DirectPlay2WImpl_EnumPlayers,
  XCAST(EnumSessions)DirectPlay2WImpl_EnumSessions,
  XCAST(GetCaps)DirectPlay2WImpl_GetCaps,
  XCAST(GetGroupData)DirectPlay2WImpl_GetGroupData,
  XCAST(GetGroupName)DirectPlay2WImpl_GetGroupName,
  XCAST(GetMessageCount)DirectPlay2WImpl_GetMessageCount,
  XCAST(GetPlayerAddress)DirectPlay2WImpl_GetPlayerAddress,
  XCAST(GetPlayerCaps)DirectPlay2WImpl_GetPlayerCaps,
  XCAST(GetPlayerData)DirectPlay2WImpl_GetPlayerData,
  XCAST(GetPlayerName)DirectPlay2WImpl_GetPlayerName,
  XCAST(GetSessionDesc)DirectPlay2WImpl_GetSessionDesc,
  XCAST(Initialize)DirectPlay2WImpl_Initialize,
  XCAST(Open)DirectPlay2WImpl_Open,
  XCAST(Receive)DirectPlay2WImpl_Receive,
  XCAST(Send)DirectPlay2WImpl_Send,
  XCAST(SetGroupData)DirectPlay2WImpl_SetGroupData,
  XCAST(SetGroupName)DirectPlay2WImpl_SetGroupName,
  XCAST(SetPlayerData)DirectPlay2WImpl_SetPlayerData,
  XCAST(SetPlayerName)DirectPlay2WImpl_SetPlayerName,
  XCAST(SetSessionDesc)DirectPlay2WImpl_SetSessionDesc,

  XCAST(AddGroupToGroup)DirectPlay3WImpl_AddGroupToGroup,
  XCAST(CreateGroupInGroup)DirectPlay3WImpl_CreateGroupInGroup,
  XCAST(DeleteGroupFromGroup)DirectPlay3WImpl_DeleteGroupFromGroup,
  XCAST(EnumConnections)DirectPlay3WImpl_EnumConnections,
  XCAST(EnumGroupsInGroup)DirectPlay3WImpl_EnumGroupsInGroup,
  XCAST(GetGroupConnectionSettings)DirectPlay3WImpl_GetGroupConnectionSettings,
  XCAST(InitializeConnection)DirectPlay3WImpl_InitializeConnection,
  XCAST(SecureOpen)DirectPlay3WImpl_SecureOpen,
  XCAST(SendChatMessage)DirectPlay3WImpl_SendChatMessage,
  XCAST(SetGroupConnectionSettings)DirectPlay3WImpl_SetGroupConnectionSettings,
  XCAST(StartSession)DirectPlay3WImpl_StartSession,
  XCAST(GetGroupFlags)DirectPlay3WImpl_GetGroupFlags,
  XCAST(GetGroupParent)DirectPlay3WImpl_GetGroupParent,
  XCAST(GetPlayerAccount)DirectPlay3WImpl_GetPlayerAccount,
  XCAST(GetPlayerFlags)DirectPlay3WImpl_GetPlayerFlags,

  DirectPlay4WImpl_GetGroupOwner,
  DirectPlay4WImpl_SetGroupOwner,
  DirectPlay4WImpl_SendEx,
  DirectPlay4WImpl_GetMessageQueue,
  DirectPlay4WImpl_CancelMessage,
  DirectPlay4WImpl_CancelPriority
};
#undef XCAST


/* Note: Hack so we can reuse the old functions without compiler warnings */
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
5131
# define XCAST(fun)     (typeof(directPlay4AVT.fun))
5132 5133 5134
#else
# define XCAST(fun)     (void*)
#endif
5135
static const IDirectPlay4Vtbl directPlay4AVT =
5136
{
5137 5138 5139
  XCAST(QueryInterface)DP_QueryInterface,
  XCAST(AddRef)DP_AddRef,
  XCAST(Release)DP_Release,
5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195

  XCAST(AddPlayerToGroup)DirectPlay2AImpl_AddPlayerToGroup,
  XCAST(Close)DirectPlay2AImpl_Close,
  XCAST(CreateGroup)DirectPlay2AImpl_CreateGroup,
  XCAST(CreatePlayer)DirectPlay2AImpl_CreatePlayer,
  XCAST(DeletePlayerFromGroup)DirectPlay2AImpl_DeletePlayerFromGroup,
  XCAST(DestroyGroup)DirectPlay2AImpl_DestroyGroup,
  XCAST(DestroyPlayer)DirectPlay2AImpl_DestroyPlayer,
  XCAST(EnumGroupPlayers)DirectPlay2AImpl_EnumGroupPlayers,
  XCAST(EnumGroups)DirectPlay2AImpl_EnumGroups,
  XCAST(EnumPlayers)DirectPlay2AImpl_EnumPlayers,
  XCAST(EnumSessions)DirectPlay2AImpl_EnumSessions,
  XCAST(GetCaps)DirectPlay2AImpl_GetCaps,
  XCAST(GetGroupData)DirectPlay2AImpl_GetGroupData,
  XCAST(GetGroupName)DirectPlay2AImpl_GetGroupName,
  XCAST(GetMessageCount)DirectPlay2AImpl_GetMessageCount,
  XCAST(GetPlayerAddress)DirectPlay2AImpl_GetPlayerAddress,
  XCAST(GetPlayerCaps)DirectPlay2AImpl_GetPlayerCaps,
  XCAST(GetPlayerData)DirectPlay2AImpl_GetPlayerData,
  XCAST(GetPlayerName)DirectPlay2AImpl_GetPlayerName,
  XCAST(GetSessionDesc)DirectPlay2AImpl_GetSessionDesc,
  XCAST(Initialize)DirectPlay2AImpl_Initialize,
  XCAST(Open)DirectPlay2AImpl_Open,
  XCAST(Receive)DirectPlay2AImpl_Receive,
  XCAST(Send)DirectPlay2AImpl_Send,
  XCAST(SetGroupData)DirectPlay2AImpl_SetGroupData,
  XCAST(SetGroupName)DirectPlay2AImpl_SetGroupName,
  XCAST(SetPlayerData)DirectPlay2AImpl_SetPlayerData,
  XCAST(SetPlayerName)DirectPlay2AImpl_SetPlayerName,
  XCAST(SetSessionDesc)DirectPlay2AImpl_SetSessionDesc,

  XCAST(AddGroupToGroup)DirectPlay3AImpl_AddGroupToGroup,
  XCAST(CreateGroupInGroup)DirectPlay3AImpl_CreateGroupInGroup,
  XCAST(DeleteGroupFromGroup)DirectPlay3AImpl_DeleteGroupFromGroup,
  XCAST(EnumConnections)DirectPlay3AImpl_EnumConnections,
  XCAST(EnumGroupsInGroup)DirectPlay3AImpl_EnumGroupsInGroup,
  XCAST(GetGroupConnectionSettings)DirectPlay3AImpl_GetGroupConnectionSettings,
  XCAST(InitializeConnection)DirectPlay3AImpl_InitializeConnection,
  XCAST(SecureOpen)DirectPlay3AImpl_SecureOpen,
  XCAST(SendChatMessage)DirectPlay3AImpl_SendChatMessage,
  XCAST(SetGroupConnectionSettings)DirectPlay3AImpl_SetGroupConnectionSettings,
  XCAST(StartSession)DirectPlay3AImpl_StartSession,
  XCAST(GetGroupFlags)DirectPlay3AImpl_GetGroupFlags,
  XCAST(GetGroupParent)DirectPlay3AImpl_GetGroupParent,
  XCAST(GetPlayerAccount)DirectPlay3AImpl_GetPlayerAccount,
  XCAST(GetPlayerFlags)DirectPlay3AImpl_GetPlayerFlags,

  DirectPlay4AImpl_GetGroupOwner,
  DirectPlay4AImpl_SetGroupOwner,
  DirectPlay4AImpl_SendEx,
  DirectPlay4AImpl_GetMessageQueue,
  DirectPlay4AImpl_CancelMessage,
  DirectPlay4AImpl_CancelPriority
};
#undef XCAST

5196 5197
HRESULT DP_GetSPPlayerData( IDirectPlay2Impl* lpDP,
                            DPID idPlayer,
5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211
                            LPVOID* lplpData )
{
  lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );

  if( lpPlayer == NULL )
  {
    return DPERR_INVALIDPLAYER;
  }

  *lplpData = lpPlayer->lpPData->lpSPPlayerData;

  return DP_OK;
}

5212 5213
HRESULT DP_SetSPPlayerData( IDirectPlay2Impl* lpDP,
                            DPID idPlayer,
5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226
                            LPVOID lpData )
{
  lpPlayerList lpPlayer = DP_FindPlayer( lpDP, idPlayer );

  if( lpPlayer == NULL )
  {
    return DPERR_INVALIDPLAYER;
  }

  lpPlayer->lpPData->lpSPPlayerData = lpData;

  return DP_OK;
}
5227 5228

/***************************************************************************
5229
 *  DirectPlayEnumerateAW
5230
 *
5231
 *  The pointer to the structure lpContext will be filled with the
5232 5233 5234
 *  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.
5235 5236
 *  This structure is then passed to lpEnumCallback for each of the different
 *  services.
5237 5238
 *
 *  This API is useful only for applications written using DirectX3 or
Francois Gouget's avatar
Francois Gouget committed
5239
 *  worse. It is superseded by IDirectPlay3::EnumConnections which also
5240 5241 5242
 *  gives information on the actual connections.
 *
 * defn of a service provider:
5243
 * A dynamic-link library used by DirectPlay to communicate over a network.
5244 5245 5246
 * 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
5247
 * media, and network resources.
5248 5249
 *
 */
5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264
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;
5265

5266 5267 5268 5269 5270 5271
    char  *descriptionA = NULL;
    DWORD max_sizeOfDescriptionA = 0;
    WCHAR *descriptionW = NULL;
    DWORD max_sizeOfDescriptionW = 0;
    
    if (!lpEnumCallbackA && !lpEnumCallbackW)
5272
    {
5273
	return DPERR_INVALIDPARAMS;
5274
    }
5275 5276 5277 5278
    
    /* Need to loop over the service providers in the registry */
    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, searchSubKey,
		      0, KEY_READ, &hkResult) != ERROR_SUCCESS)
5279
    {
5280 5281 5282
	/* 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;
5283
    }
5284 5285 5286 5287
    
    /* Traverse all the service providers we have available */
    dwIndex = 0;
    while (1)
5288
    {
5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331
	WCHAR subKeyName[255]; /* 255 is the maximum key size according to MSDN */
	DWORD sizeOfSubKeyName = sizeof(subKeyName) / sizeof(WCHAR);
	HKEY  hkServiceProvider;
	GUID  serviceProviderGUID;
	WCHAR guidKeyContent[(2 * 16) + 1 + 6 /* This corresponds to '{....-..-..-..-......}' */ ];
	DWORD sizeOfGuidKeyContent = sizeof(guidKeyContent);
	LONG  ret_value;
	
	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;
	}
	CLSIDFromString(guidKeyContent, &serviceProviderGUID );
	
	/* 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
5332
	 *       and have no relation to any of the two dwReserved1 and dwReserved2 keys.
5333 5334 5335 5336 5337 5338
	 *       I think that it simply means that they are in-line with DirectX 6.0
	 */
	if (lpEnumCallbackA)
	{
	    DWORD sizeOfDescription = 0;
	    
5339
	    /* Note that this is the A case of this function, so use the A variant to get the description string */
5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389
	    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);
	    
	    if (!lpEnumCallbackA(&serviceProviderGUID, descriptionA, 6, 0, lpContext))
		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);

	    if (!lpEnumCallbackW(&serviceProviderGUID, descriptionW, 6, 0, lpContext))
		goto end;
	}
      
      dwIndex++;
  }

 end:
    HeapFree(GetProcessHeap(), 0, descriptionA);
    HeapFree(GetProcessHeap(), 0, descriptionW);
    
    return DP_OK;
}
5390

5391 5392 5393 5394 5395 5396 5397 5398 5399
/***************************************************************************
 *  DirectPlayEnumerate  [DPLAYX.9]
 *  DirectPlayEnumerateA [DPLAYX.2]
 */
HRESULT WINAPI DirectPlayEnumerateA(LPDPENUMDPCALLBACKA lpEnumCallback, LPVOID lpContext )
{
    TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
    
    return DirectPlayEnumerateAW(lpEnumCallback, NULL, lpContext);
5400 5401 5402
}

/***************************************************************************
5403
 *  DirectPlayEnumerateW [DPLAYX.3]
5404
 */
5405
HRESULT WINAPI DirectPlayEnumerateW(LPDPENUMDPCALLBACKW lpEnumCallback, LPVOID lpContext )
5406
{
5407 5408 5409
    TRACE("(%p,%p)\n", lpEnumCallback, lpContext);
    
    return DirectPlayEnumerateAW(NULL, lpEnumCallback, lpContext);
5410 5411
}

5412 5413 5414
typedef struct tagCreateEnum
{
  LPVOID  lpConn;
5415
  LPCGUID lpGuid;
5416 5417 5418
} CreateEnumData, *lpCreateEnumData;

/* Find and copy the matching connection for the SP guid */
5419
static BOOL CALLBACK cbDPCreateEnumConnections(
5420 5421 5422 5423 5424 5425 5426
    LPCGUID     lpguidSP,
    LPVOID      lpConnection,
    DWORD       dwConnectionSize,
    LPCDPNAME   lpName,
    DWORD       dwFlags,
    LPVOID      lpContext)
{
5427
  lpCreateEnumData lpData = (lpCreateEnumData)lpContext;
5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445

  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;
}


5446
/***************************************************************************
5447
 *  DirectPlayCreate [DPLAYX.1]
5448 5449 5450
 *
 */
HRESULT WINAPI DirectPlayCreate
5451
( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk )
5452
{
5453 5454 5455
  HRESULT hr;
  LPDIRECTPLAY3A lpDP3A;
  CreateEnumData cbData;
5456

5457
  TRACE( "lpGUID=%s lplpDP=%p pUnk=%p\n", debugstr_guid(lpGUID), lplpDP, pUnk );
5458 5459 5460

  if( pUnk != NULL )
  {
5461
    return CLASS_E_NOAGGREGATION;
5462 5463
  }

5464 5465 5466 5467 5468 5469
  if( (lplpDP == NULL) || (lpGUID == NULL) )
  {
    return DPERR_INVALIDPARAMS;
  }


5470 5471
  /* Create an IDirectPlay object. We don't support that so we'll cheat and
     give them an IDirectPlay2A object and hope that doesn't cause problems */
5472
  if( DP_CreateInterface( &IID_IDirectPlay2A, (LPVOID*)lplpDP ) != DP_OK )
5473 5474
  {
    return DPERR_UNAVAILABLE;
5475
  }
5476

5477 5478 5479
  if( IsEqualGUID( &GUID_NULL, lpGUID ) )
  {
    /* The GUID_NULL means don't bind a service provider. Just return the
5480
       interface as is */
5481 5482 5483
    return DP_OK;
  }

5484 5485
  /* Bind the desired service provider since lpGUID is non NULL */
  TRACE( "Service Provider binding for %s\n", debugstr_guid(lpGUID) );
5486

5487
  /* We're going to use a DP3 interface */
5488
  hr = IDirectPlayX_QueryInterface( *lplpDP, &IID_IDirectPlay3A,
5489 5490 5491
                                    (LPVOID*)&lpDP3A );
  if( FAILED(hr) )
  {
5492
    ERR( "Failed to get DP3 interface: %s\n", DPLAYX_HresultToString(hr) );
5493 5494 5495 5496 5497 5498 5499
    return hr;
  }

  cbData.lpConn = NULL;
  cbData.lpGuid = lpGUID;

  /* We were given a service provider, find info about it... */
5500
  hr = IDirectPlayX_EnumConnections( lpDP3A, NULL, cbDPCreateEnumConnections,
5501 5502
                                     &cbData, DPCONNECTION_DIRECTPLAY );
  if( ( FAILED(hr) ) ||
5503
      ( cbData.lpConn == NULL )
5504
    )
5505
  {
5506
    ERR( "Failed to get Enum for SP: %s\n", DPLAYX_HresultToString(hr) );
5507 5508
    IDirectPlayX_Release( lpDP3A );
    return DPERR_UNAVAILABLE;
5509 5510
  }

5511 5512
  /* Initialize the service provider */
  hr = IDirectPlayX_InitializeConnection( lpDP3A, cbData.lpConn, 0 );
5513
  if( FAILED(hr) )
5514 5515 5516 5517 5518 5519
  {
    ERR( "Failed to Initialize SP: %s\n", DPLAYX_HresultToString(hr) );
    HeapFree( GetProcessHeap(), 0, cbData.lpConn );
    IDirectPlayX_Release( lpDP3A );
    return hr;
  }
5520

5521 5522 5523
  /* Release our version of the interface now that we're done with it */
  IDirectPlayX_Release( lpDP3A );
  HeapFree( GetProcessHeap(), 0, cbData.lpConn );
5524

5525
  return DP_OK;
5526
}