dplaysp.c 19.1 KB
Newer Older
1
/* This contains the implementation of the interface Service
2
 * Providers require to communicate with Direct Play
3
 *
4
 * Copyright 2000 Peter Hunnisett
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20
 */

21
#include <string.h>
22
#include "winerror.h"
23
#include "wine/debug.h"
24

25
#include "wine/dplaysp.h"
26 27 28 29 30 31 32 33
#include "dplay_global.h"
#include "name_server.h"
#include "dplayx_messages.h"

#include "dplayx_global.h" /* FIXME: For global hack */

/* FIXME: Need to add interface locking inside procedures */

34
WINE_DEFAULT_DEBUG_CHANNEL(dplay);
35

36
typedef struct IDirectPlaySPImpl
37
{
38
  IDirectPlaySP IDirectPlaySP_iface;
39
  LONG ref;
40 41 42 43 44 45
  void *remote_data;
  DWORD remote_data_size;
  void *local_data;
  DWORD local_data_size;
  IDirectPlayImpl *dplay; /* FIXME: This should perhaps be iface not impl */
} IDirectPlaySPImpl;
46

47 48 49 50 51
/* This structure is passed to the DP object for safe keeping */
typedef struct tagDP_SPPLAYERDATA
{
  LPVOID lpPlayerLocalData;
  DWORD  dwPlayerLocalDataSize;
52

53 54 55
  LPVOID lpPlayerRemoteData;
  DWORD  dwPlayerRemoteDataSize;
} DP_SPPLAYERDATA, *LPDP_SPPLAYERDATA;
56 57


58 59
static inline IDirectPlaySPImpl *impl_from_IDirectPlaySP( IDirectPlaySP *iface )
{
60
  return CONTAINING_RECORD( iface, IDirectPlaySPImpl, IDirectPlaySP_iface );
61 62
}

63
static HRESULT WINAPI IDirectPlaySPImpl_QueryInterface( IDirectPlaySP *iface, REFIID riid,
64
        void **ppv )
65
{
66
  TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid( riid ), ppv );
67

68
  if ( IsEqualGUID( &IID_IUnknown, riid ) || IsEqualGUID( &IID_IDirectPlaySP, riid ) )
69
  {
70 71 72
    *ppv = iface;
    IDirectPlaySP_AddRef( iface );
    return S_OK;
73
  }
74

75 76 77
  FIXME( "Unsupported interface %s\n", debugstr_guid( riid ) );
  *ppv = NULL;
  return E_NOINTERFACE;
78
}
79

80
static ULONG WINAPI IDirectPlaySPImpl_AddRef( IDirectPlaySP *iface )
81
{
82
  IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface );
83
  ULONG ref = InterlockedIncrement( &This->ref );
84

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

87
  return ref;
88 89
}

90
static ULONG WINAPI IDirectPlaySPImpl_Release( IDirectPlaySP *iface )
91
{
92
  IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface );
93
  ULONG ref = InterlockedDecrement( &This->ref );
94

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

97
  if( !ref )
98
  {
99 100
    HeapFree( GetProcessHeap(), 0, This->remote_data );
    HeapFree( GetProcessHeap(), 0, This->local_data );
101 102 103
    HeapFree( GetProcessHeap(), 0, This );
  }

104
  return ref;
105 106
}

107 108
static HRESULT WINAPI IDirectPlaySPImpl_AddMRUEntry( IDirectPlaySP *iface, LPCWSTR lpSection,
        LPCWSTR lpKey, const void *lpData, DWORD dwDataSize, DWORD dwMaxEntries )
109
{
110
  IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface );
111

112 113
  /* Should be able to call the comctl32 undocumented MRU routines.
     I suspect that the interface works appropriately */
114
  FIXME( "(%p)->(%p,%p%p,0x%08x,0x%08x): stub\n",
115 116 117 118 119
         This, lpSection, lpKey, lpData, dwDataSize, dwMaxEntries );

  return DP_OK;
}

120 121 122
static HRESULT WINAPI IDirectPlaySPImpl_CreateAddress( IDirectPlaySP *iface, REFGUID guidSP,
        REFGUID guidDataType, const void *lpData, DWORD dwDataSize, void *lpAddress,
        DWORD *lpdwAddressSize )
123
{
124
  IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface );
125

126
  FIXME( "(%p)->(%s,%s,%p,0x%08x,%p,%p): stub\n",
127 128 129 130 131 132
         This, debugstr_guid(guidSP), debugstr_guid(guidDataType),
         lpData, dwDataSize, lpAddress, lpdwAddressSize );

  return DP_OK;
}

133 134 135
static HRESULT WINAPI IDirectPlaySPImpl_EnumAddress( IDirectPlaySP *iface,
        LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, const void *lpAddress, DWORD dwAddressSize,
        void *lpContext )
136
{
137
  IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface );
138

139
  TRACE( "(%p)->(%p,%p,0x%08x,%p)\n",
140 141 142 143 144 145 146
         This, lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext );

  DPL_EnumAddress( lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext );

  return DP_OK;
}

147 148
static HRESULT WINAPI IDirectPlaySPImpl_EnumMRUEntries( IDirectPlaySP *iface, LPCWSTR lpSection,
        LPCWSTR lpKey, LPENUMMRUCALLBACK lpEnumMRUCallback, void *lpContext )
149
{
150
  IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface );
151

152 153
  /* Should be able to call the comctl32 undocumented MRU routines.
     I suspect that the interface works appropriately */
Andrey Gusev's avatar
Andrey Gusev committed
154
  FIXME( "(%p)->(%p,%p,%p,%p): stub\n",
155 156 157 158 159
         This, lpSection, lpKey, lpEnumMRUCallback, lpContext );

  return DP_OK;
}

160 161
static HRESULT WINAPI IDirectPlaySPImpl_GetPlayerFlags( IDirectPlaySP *iface, DPID idPlayer,
        DWORD *lpdwPlayerFlags )
162
{
163
  IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface );
164

165
  FIXME( "(%p)->(0x%08x,%p): stub\n",
166 167 168 169 170
         This, idPlayer, lpdwPlayerFlags );

  return DP_OK;
}

171 172
static HRESULT WINAPI IDirectPlaySPImpl_GetSPPlayerData( IDirectPlaySP *iface, DPID idPlayer,
        void **lplpData, DWORD *lpdwDataSize, DWORD dwFlags )
173
{
174
  IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface );
175 176
  HRESULT hr;
  LPDP_SPPLAYERDATA lpPlayerData;
177

178
  TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n",
179 180
         This, idPlayer, lplpData, lpdwDataSize, dwFlags );

181
  hr = DP_GetSPPlayerData( This->dplay, idPlayer, (void**)&lpPlayerData );
182 183 184 185 186 187 188

  if( FAILED(hr) )
  {
    TRACE( "Couldn't get player data: %s\n", DPLAYX_HresultToString(hr) );
    return DPERR_INVALIDPLAYER;
  }

189
  /* What to do in the case where there is nothing set yet? */
190 191 192 193 194 195 196 197 198 199 200 201 202 203
  if( dwFlags == DPSET_LOCAL )
  {
    *lplpData     = lpPlayerData->lpPlayerLocalData;
    *lpdwDataSize = lpPlayerData->dwPlayerLocalDataSize;
  }
  else if( dwFlags == DPSET_REMOTE )
  {
    *lplpData     = lpPlayerData->lpPlayerRemoteData;
    *lpdwDataSize = lpPlayerData->dwPlayerRemoteDataSize;
  }

  if( *lplpData == NULL )
  {
    hr = DPERR_GENERIC;
204
  }
205 206

  return hr;
207 208
}

209 210
static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage( IDirectPlaySP *iface, void *lpMessageBody,
        DWORD dwMessageBodySize, void *lpMessageHeader )
211
{
212
  IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface );
213
  LPDPMSG_SENDENVELOPE lpMsg = lpMessageBody;
214
  HRESULT hr = DPERR_GENERIC;
Peter Hunnisett's avatar
Peter Hunnisett committed
215 216
  WORD wCommandId;
  WORD wVersion;
217
  DPSP_REPLYDATA data;
218

219
  FIXME( "(%p)->(%p,0x%08x,%p): mostly stub\n",
220 221
         This, lpMessageBody, dwMessageBodySize, lpMessageHeader );

Peter Hunnisett's avatar
Peter Hunnisett committed
222 223 224
  wCommandId = lpMsg->wCommandId;
  wVersion   = lpMsg->wVersion;

225
  TRACE( "Incoming message has envelope of 0x%08x, %u, %u\n",
Peter Hunnisett's avatar
Peter Hunnisett committed
226
         lpMsg->dwMagic, wCommandId, wVersion );
227 228 229

  if( lpMsg->dwMagic != DPMSGMAGIC_DPLAYMSG )
  {
230
    ERR( "Unknown magic 0x%08x!\n", lpMsg->dwMagic );
231
    return DPERR_GENERIC;
232 233
  }

234
#if 0
235
  {
236
    const LPDWORD lpcHeader = lpMessageHeader;
237

238 239 240 241
    TRACE( "lpMessageHeader = [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx]\n",
           lpcHeader[0], lpcHeader[1], lpcHeader[2], lpcHeader[3], lpcHeader[4] );
   }
#endif
242

243 244 245
  /* Pass everything else to Direct Play */
  data.lpMessage     = NULL;
  data.dwMessageSize = 0;
246

247
  /* Pass this message to the dplay interface to handle */
248 249
  hr = DP_HandleMessage( This->dplay, lpMessageBody, dwMessageBodySize, lpMessageHeader,
                         wCommandId, wVersion, &data.lpMessage, &data.dwMessageSize );
250

251 252 253 254
  if( FAILED(hr) )
  {
    ERR( "Command processing failed %s\n", DPLAYX_HresultToString(hr) );
  }
255

256 257 258 259 260 261
  /* Do we want a reply? */
  if( data.lpMessage != NULL )
  {
    data.lpSPMessageHeader = lpMessageHeader;
    data.idNameServer      = 0;
    data.lpISP             = iface;
262

263
    hr = This->dplay->dp2->spData.lpCB->Reply( &data );
264

265
    if( FAILED(hr) )
Peter Hunnisett's avatar
Peter Hunnisett committed
266
    {
267
      ERR( "Reply failed %s\n", DPLAYX_HresultToString(hr) );
Peter Hunnisett's avatar
Peter Hunnisett committed
268
    }
269 270
  }

271 272
  return hr;

273 274 275
#if 0
  HRESULT hr = DP_OK;
  HANDLE  hReceiveEvent = 0;
276
  /* FIXME: Acquire some sort of interface lock */
277 278 279
  /* FIXME: Need some sort of context for this callback. Need to determine
   *        how this is actually done with the SP
   */
Peter Hunnisett's avatar
Peter Hunnisett committed
280
  /* FIXME: Who needs to delete the message when done? */
281 282 283 284
  switch( lpMsg->dwType )
  {
    case DPSYS_CREATEPLAYERORGROUP:
    {
285
      LPDPMSG_CREATEPLAYERORGROUP msg = lpMsg;
286 287 288

      if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
      {
289 290
        hr = DP_IF_CreatePlayer( This, lpMessageHeader, msg->dpId,
                                 &msg->dpnName, 0, msg->lpData,
291 292 293 294 295 296 297
                                 msg->dwDataSize, msg->dwFlags, ... );
      }
      else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
      {
        /* Group in group situation? */
        if( msg->dpIdParent == DPID_NOPARENT_GROUP )
        {
298 299
          hr = DP_IF_CreateGroup( This, lpMessageHeader, msg->dpId,
                                  &msg->dpnName, 0, msg->lpData,
300 301 302 303 304
                                  msg->dwDataSize, msg->dwFlags, ... );
        }
        else /* Group in Group */
        {
          hr = DP_IF_CreateGroupInGroup( This, lpMessageHeader, msg->dpIdParent,
305
                                         &msg->dpnName, 0, msg->lpData,
306 307 308 309 310 311 312 313 314 315 316 317 318 319
                                         msg->dwDataSize, msg->dwFlags, ... );
        }
      }
      else /* Hmmm? */
      {
        ERR( "Corrupt msg->dwPlayerType for DPSYS_CREATEPLAYERORGROUP\n" );
        return;
      }

      break;
    }

    case DPSYS_DESTROYPLAYERORGROUP:
    {
320
      LPDPMSG_DESTROYPLAYERORGROUP msg = lpMsg;
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340

      if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
      {
        hr = DP_IF_DestroyPlayer( This, msg->dpId, ... );
      }
      else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
      {
        hr = DP_IF_DestroyGroup( This, msg->dpId, ... );
      }
      else /* Hmmm? */
      {
        ERR( "Corrupt msg->dwPlayerType for DPSYS_DESTROYPLAYERORGROUP\n" );
        return;
      }

      break;
    }

    case DPSYS_ADDPLAYERTOGROUP:
    {
341
      LPDPMSG_ADDPLAYERTOGROUP msg = lpMsg;
342 343 344 345 346 347 348

      hr = DP_IF_AddPlayerToGroup( This, msg->dpIdGroup, msg->dpIdPlayer, ... );
      break;
    }

    case DPSYS_DELETEPLAYERFROMGROUP:
    {
349
      LPDPMSG_DELETEPLAYERFROMGROUP msg = lpMsg;
350 351 352 353 354 355 356 357 358

      hr = DP_IF_DeletePlayerFromGroup( This, msg->dpIdGroup, msg->dpIdPlayer,
                                        ... );

      break;
    }

    case DPSYS_SESSIONLOST:
    {
359
      LPDPMSG_SESSIONLOST msg = lpMsg;
360 361 362 363 364 365 366 367

      FIXME( "DPSYS_SESSIONLOST not handled\n" );

      break;
    }

    case DPSYS_HOST:
    {
368
      LPDPMSG_HOST msg = lpMsg;
369 370 371 372 373 374 375 376

      FIXME( "DPSYS_HOST not handled\n" );

      break;
    }

    case DPSYS_SETPLAYERORGROUPDATA:
    {
377
      LPDPMSG_SETPLAYERORGROUPDATA msg = lpMsg;
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398

      if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
      {
        hr = DP_IF_SetPlayerData( This, msg->dpId, msg->lpData, msg->dwDataSize,                                  DPSET_REMOTE, ... );
      }
      else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
      {
        hr = DP_IF_SetGroupData( This, msg->dpId, msg->lpData, msg->dwDataSize,
                                 DPSET_REMOTE, ... );
      }
      else /* Hmmm? */
      {
        ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" );
        return;
      }

      break;
    }

    case DPSYS_SETPLAYERORGROUPNAME:
    {
399
      LPDPMSG_SETPLAYERORGROUPNAME msg = lpMsg;
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419

      if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER )
      {
        hr = DP_IF_SetPlayerName( This, msg->dpId, msg->dpnName, ... );
      }
      else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP )
      {
        hr = DP_IF_SetGroupName( This, msg->dpId, msg->dpnName, ... );
      }
      else /* Hmmm? */
      {
        ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" );
        return;
      }

      break;
    }

    case DPSYS_SETSESSIONDESC;
    {
420
      LPDPMSG_SETSESSIONDESC msg = lpMsg;
421 422 423 424 425 426 427 428

      hr = DP_IF_SetSessionDesc( This, &msg->dpDesc );

      break;
    }

    case DPSYS_ADDGROUPTOGROUP:
    {
429
      LPDPMSG_ADDGROUPTOGROUP msg = lpMsg;
430 431 432 433 434 435 436 437 438

      hr = DP_IF_AddGroupToGroup( This, msg->dpIdParentGroup, msg->dpIdGroup,
                                  ... );

      break;
    }

    case DPSYS_DELETEGROUPFROMGROUP:
    {
439
      LPDPMSG_DELETEGROUPFROMGROUP msg = lpMsg;
440 441 442 443 444 445 446 447 448

      hr = DP_IF_DeleteGroupFromGroup( This, msg->dpIdParentGroup,
                                       msg->dpIdGroup, ... );

      break;
    }

    case DPSYS_SECUREMESSAGE:
    {
449
      LPDPMSG_SECUREMESSAGE msg = lpMsg;
450 451 452 453 454 455 456 457

      FIXME( "DPSYS_SECUREMESSAGE not implemented\n" );

      break;
    }

    case DPSYS_STARTSESSION:
    {
458
      LPDPMSG_STARTSESSION msg = lpMsg;
459 460 461 462 463 464 465 466

      FIXME( "DPSYS_STARTSESSION not implemented\n" );

      break;
    }

    case DPSYS_CHAT:
    {
467
      LPDPMSG_CHAT msg = lpMsg;
468

469
      FIXME( "DPSYS_CHAT not implemented\n" );
470 471

      break;
472
    }
473 474 475

    case DPSYS_SETGROUPOWNER:
    {
476
      LPDPMSG_SETGROUPOWNER msg = lpMsg;
477 478 479 480 481 482 483 484

      FIXME( "DPSYS_SETGROUPOWNER not implemented\n" );

      break;
    }

    case DPSYS_SENDCOMPLETE:
    {
485
      LPDPMSG_SENDCOMPLETE msg = lpMsg;
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508

      FIXME( "DPSYS_SENDCOMPLETE not implemented\n" );

      break;
    }

    default:
    {
      /* NOTE: This should be a user defined type. There is nothing that we
       *       need to do with it except queue it.
       */
      TRACE( "Received user message type(?) 0x%08lx through SP.\n",
              lpMsg->dwType );
      break;
    }
  }

  FIXME( "Queue message in the receive queue. Need some context data!\n" );

  if( FAILED(hr) )
  {
    ERR( "Unable to perform action for msg type 0x%08lx\n", lpMsg->dwType );
  }
Francois Gouget's avatar
Francois Gouget committed
509
  /* If a receive event was registered for this player, invoke it */
510 511 512 513 514 515 516
  if( hReceiveEvent )
  {
    SetEvent( hReceiveEvent );
  }
#endif
}

517 518
static HRESULT WINAPI IDirectPlaySPImpl_SetSPPlayerData( IDirectPlaySP *iface, DPID idPlayer,
        void *lpData, DWORD dwDataSize, DWORD dwFlags )
519
{
520
  IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface );
521 522
  HRESULT           hr;
  LPDP_SPPLAYERDATA lpPlayerEntry;
523
  LPVOID            lpPlayerData;
524

525
  TRACE( "(%p)->(0x%08x,%p,0x%08x,0x%08x)\n", This, idPlayer, lpData, dwDataSize, dwFlags );
526

527
  hr = DP_GetSPPlayerData( This->dplay, idPlayer, (void**)&lpPlayerEntry );
528 529 530 531 532
  if( FAILED(hr) )
  {
    /* Player must not exist */
    return DPERR_INVALIDPLAYER;
  }
533

534 535
  lpPlayerData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
  CopyMemory( lpPlayerData, lpData, dwDataSize );
536

537 538 539 540 541 542 543 544 545 546 547
  if( dwFlags == DPSET_LOCAL )
  {
    lpPlayerEntry->lpPlayerLocalData = lpPlayerData;
    lpPlayerEntry->dwPlayerLocalDataSize = dwDataSize;
  }
  else if( dwFlags == DPSET_REMOTE )
  {
    lpPlayerEntry->lpPlayerRemoteData = lpPlayerData;
    lpPlayerEntry->dwPlayerRemoteDataSize = dwDataSize;
  }

548
  hr = DP_SetSPPlayerData( This->dplay, idPlayer, lpPlayerEntry );
549 550

  return hr;
551 552
}

553 554 555
static HRESULT WINAPI IDirectPlaySPImpl_CreateCompoundAddress( IDirectPlaySP *iface,
        const DPCOMPOUNDADDRESSELEMENT *lpElements, DWORD dwElementCount, void *lpAddress,
        DWORD *lpdwAddressSize )
556
{
557
  IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface );
558

559
  FIXME( "(%p)->(%p,0x%08x,%p,%p): stub\n",
560 561 562 563 564
         This, lpElements, dwElementCount, lpAddress, lpdwAddressSize );

  return DP_OK;
}

565 566
static HRESULT WINAPI IDirectPlaySPImpl_GetSPData( IDirectPlaySP *iface, void **lplpData,
        DWORD *lpdwDataSize, DWORD dwFlags )
567
{
568
  IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface );
569
  HRESULT hr = DP_OK;
570

571
  TRACE( "(%p)->(%p,%p,0x%08x)\n", This, lplpData, lpdwDataSize, dwFlags );
572 573 574

#if 0
  /* This is what the documentation says... */
575
  if( dwFlags != DPSET_REMOTE )
576 577 578 579 580 581 582 583
  {
    return DPERR_INVALIDPARAMS;
  }
#else
  /* ... but most service providers call this with 1 */
  /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
   * thing?
   */
584
  if( dwFlags != DPSET_REMOTE )
585
  {
586
    TRACE( "Undocumented dwFlags 0x%08x used\n", dwFlags );
587 588 589
  }
#endif

590 591
  /* FIXME: What to do in the case where this isn't initialized yet? */

592 593 594
  /* Yes, we're supposed to return a pointer to the memory we have stored! */
  if( dwFlags == DPSET_REMOTE )
  {
595 596
    *lpdwDataSize = This->remote_data_size;
    *lplpData = This->remote_data;
597

598
    if( !This->remote_data )
599
      hr = DPERR_GENERIC;
600 601 602
  }
  else if( dwFlags == DPSET_LOCAL )
  {
603 604
    *lpdwDataSize = This->local_data_size;
    *lplpData = This->local_data;
605

606
    if( !This->local_data )
607
      hr = DPERR_GENERIC;
608 609
  }

610
  return hr;
611 612
}

613 614
static HRESULT WINAPI IDirectPlaySPImpl_SetSPData( IDirectPlaySP *iface, void *lpData,
        DWORD dwDataSize, DWORD dwFlags )
615
{
616
  IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface );
617 618
  LPVOID lpSpData;

619
  TRACE( "(%p)->(%p,0x%08x,0x%08x)\n", This, lpData, dwDataSize, dwFlags );
620 621 622

#if 0
  /* This is what the documentation says... */
623
  if( dwFlags != DPSET_REMOTE )
624 625 626 627 628 629 630 631
  {
    return DPERR_INVALIDPARAMS;
  }
#else
  /* ... but most service providers call this with 1 */
  /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of
   * thing?
   */
632
  if( dwFlags != DPSET_REMOTE )
633
  {
634
    TRACE( "Undocumented dwFlags 0x%08x used\n", dwFlags );
635 636 637
  }
#endif

638
  lpSpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize );
639 640 641 642 643
  CopyMemory( lpSpData, lpData, dwDataSize );

  /* If we have data already allocated, free it and replace it */
  if( dwFlags == DPSET_REMOTE )
  {
644 645 646
    HeapFree( GetProcessHeap(), 0, This->remote_data );
    This->remote_data_size = dwDataSize;
    This->remote_data = lpSpData;
647 648 649
  }
  else if ( dwFlags == DPSET_LOCAL )
  {
650 651 652
    HeapFree( GetProcessHeap(), 0, This->local_data );
    This->local_data = lpSpData;
    This->local_data_size = dwDataSize;
653 654 655 656 657
  }

  return DP_OK;
}

658 659
static void WINAPI IDirectPlaySPImpl_SendComplete( IDirectPlaySP *iface, void *unknownA,
        DWORD unknownB )
660
{
661
  IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface );
662

663
  FIXME( "(%p)->(%p,0x%08x): stub\n",
664 665 666
         This, unknownA, unknownB );
}

667
static const IDirectPlaySPVtbl directPlaySPVT =
668
{
669 670 671
  IDirectPlaySPImpl_QueryInterface,
  IDirectPlaySPImpl_AddRef,
  IDirectPlaySPImpl_Release,
672 673 674 675 676 677 678 679 680 681 682 683 684
  IDirectPlaySPImpl_AddMRUEntry,
  IDirectPlaySPImpl_CreateAddress,
  IDirectPlaySPImpl_EnumAddress,
  IDirectPlaySPImpl_EnumMRUEntries,
  IDirectPlaySPImpl_GetPlayerFlags,
  IDirectPlaySPImpl_GetSPPlayerData,
  IDirectPlaySPImpl_HandleMessage,
  IDirectPlaySPImpl_SetSPPlayerData,
  IDirectPlaySPImpl_CreateCompoundAddress,
  IDirectPlaySPImpl_GetSPData,
  IDirectPlaySPImpl_SetSPData,
  IDirectPlaySPImpl_SendComplete
};
685

686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
HRESULT dplaysp_create( REFIID riid, void **ppv, IDirectPlayImpl *dp )
{
  IDirectPlaySPImpl *obj;
  HRESULT hr;

  TRACE( "(%s, %p)\n", debugstr_guid( riid ), ppv );

  *ppv = NULL;
  obj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *obj ) );
  if ( !obj )
    return DPERR_OUTOFMEMORY;

  obj->IDirectPlaySP_iface.lpVtbl = &directPlaySPVT;
  obj->ref = 1;
  obj->dplay = dp;

  hr = IDirectPlaySP_QueryInterface( &obj->IDirectPlaySP_iface, riid, ppv );
  IDirectPlaySP_Release( &obj->IDirectPlaySP_iface );

  return hr;
}
707 708 709 710

/* DP external interfaces to call into DPSP interface */

/* Allocate the structure */
711
LPVOID DPSP_CreateSPPlayerData(void)
712 713
{
  TRACE( "Creating SPPlayer data struct\n" );
714
  return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
715 716
                    sizeof( DP_SPPLAYERDATA ) );
}