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 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * 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 #include "dplay_global.h" 27 #include "name_server.h" 28 #include "dplayx_messages.h" 29 30 #include "dplayx_global.h" /* FIXME: For global hack */ 31 32 /* FIXME: Need to add interface locking inside procedures */ 33 34 WINE_DEFAULT_DEBUG_CHANNEL(dplay); 35 36 typedef struct IDirectPlaySPImpl 37 { 38 IDirectPlaySP IDirectPlaySP_iface; 39 LONG ref; 40 void *remote_data; 41 DWORD remote_data_size; 42 void *local_data; 43 DWORD local_data_size; 44 IDirectPlayImpl *dplay; /* FIXME: This should perhaps be iface not impl */ 45 } IDirectPlaySPImpl; 46 47 /* This structure is passed to the DP object for safe keeping */ 48 typedef struct tagDP_SPPLAYERDATA 49 { 50 LPVOID lpPlayerLocalData; 51 DWORD dwPlayerLocalDataSize; 52 53 LPVOID lpPlayerRemoteData; 54 DWORD dwPlayerRemoteDataSize; 55 } DP_SPPLAYERDATA, *LPDP_SPPLAYERDATA; 56 57 58 static inline IDirectPlaySPImpl *impl_from_IDirectPlaySP( IDirectPlaySP *iface ) 59 { 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 *ppv = iface; 71 IDirectPlaySP_AddRef( iface ); 72 return S_OK; 73 } 74 75 FIXME( "Unsupported interface %s\n", debugstr_guid( riid ) ); 76 *ppv = NULL; 77 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 HeapFree( GetProcessHeap(), 0, This->remote_data ); 100 HeapFree( GetProcessHeap(), 0, This->local_data ); 101 HeapFree( GetProcessHeap(), 0, This ); 102 } 103 104 return ref; 105 } 106 107 static HRESULT WINAPI IDirectPlaySPImpl_AddMRUEntry( IDirectPlaySP *iface, LPCWSTR lpSection, 108 LPCWSTR lpKey, const void *lpData, DWORD dwDataSize, DWORD dwMaxEntries ) 109 { 110 IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface ); 111 112 /* Should be able to call the comctl32 undocumented MRU routines. 113 I suspect that the interface works appropriately */ 114 FIXME( "(%p)->(%p,%p%p,0x%08x,0x%08x): stub\n", 115 This, lpSection, lpKey, lpData, dwDataSize, dwMaxEntries ); 116 117 return DP_OK; 118 } 119 120 static HRESULT WINAPI IDirectPlaySPImpl_CreateAddress( IDirectPlaySP *iface, REFGUID guidSP, 121 REFGUID guidDataType, const void *lpData, DWORD dwDataSize, void *lpAddress, 122 DWORD *lpdwAddressSize ) 123 { 124 IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface ); 125 126 FIXME( "(%p)->(%s,%s,%p,0x%08x,%p,%p): stub\n", 127 This, debugstr_guid(guidSP), debugstr_guid(guidDataType), 128 lpData, dwDataSize, lpAddress, lpdwAddressSize ); 129 130 return DP_OK; 131 } 132 133 static HRESULT WINAPI IDirectPlaySPImpl_EnumAddress( IDirectPlaySP *iface, 134 LPDPENUMADDRESSCALLBACK lpEnumAddressCallback, const void *lpAddress, DWORD dwAddressSize, 135 void *lpContext ) 136 { 137 IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface ); 138 139 TRACE( "(%p)->(%p,%p,0x%08x,%p)\n", 140 This, lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext ); 141 142 DPL_EnumAddress( lpEnumAddressCallback, lpAddress, dwAddressSize, lpContext ); 143 144 return DP_OK; 145 } 146 147 static HRESULT WINAPI IDirectPlaySPImpl_EnumMRUEntries( IDirectPlaySP *iface, LPCWSTR lpSection, 148 LPCWSTR lpKey, LPENUMMRUCALLBACK lpEnumMRUCallback, void *lpContext ) 149 { 150 IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface ); 151 152 /* Should be able to call the comctl32 undocumented MRU routines. 153 I suspect that the interface works appropriately */ 154 FIXME( "(%p)->(%p,%p,%p,%p): stub\n", 155 This, lpSection, lpKey, lpEnumMRUCallback, lpContext ); 156 157 return DP_OK; 158 } 159 160 static HRESULT WINAPI IDirectPlaySPImpl_GetPlayerFlags( IDirectPlaySP *iface, DPID idPlayer, 161 DWORD *lpdwPlayerFlags ) 162 { 163 IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface ); 164 165 FIXME( "(%p)->(0x%08x,%p): stub\n", 166 This, idPlayer, lpdwPlayerFlags ); 167 168 return DP_OK; 169 } 170 171 static HRESULT WINAPI IDirectPlaySPImpl_GetSPPlayerData( IDirectPlaySP *iface, DPID idPlayer, 172 void **lplpData, DWORD *lpdwDataSize, DWORD dwFlags ) 173 { 174 IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface ); 175 HRESULT hr; 176 LPDP_SPPLAYERDATA lpPlayerData; 177 178 TRACE( "(%p)->(0x%08x,%p,%p,0x%08x)\n", 179 This, idPlayer, lplpData, lpdwDataSize, dwFlags ); 180 181 hr = DP_GetSPPlayerData( This->dplay, idPlayer, (void**)&lpPlayerData ); 182 183 if( FAILED(hr) ) 184 { 185 TRACE( "Couldn't get player data: %s\n", DPLAYX_HresultToString(hr) ); 186 return DPERR_INVALIDPLAYER; 187 } 188 189 /* What to do in the case where there is nothing set yet? */ 190 if( dwFlags == DPSET_LOCAL ) 191 { 192 *lplpData = lpPlayerData->lpPlayerLocalData; 193 *lpdwDataSize = lpPlayerData->dwPlayerLocalDataSize; 194 } 195 else if( dwFlags == DPSET_REMOTE ) 196 { 197 *lplpData = lpPlayerData->lpPlayerRemoteData; 198 *lpdwDataSize = lpPlayerData->dwPlayerRemoteDataSize; 199 } 200 201 if( *lplpData == NULL ) 202 { 203 hr = DPERR_GENERIC; 204 } 205 206 return hr; 207 } 208 209 static HRESULT WINAPI IDirectPlaySPImpl_HandleMessage( IDirectPlaySP *iface, void *lpMessageBody, 210 DWORD dwMessageBodySize, void *lpMessageHeader ) 211 { 212 IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface ); 213 LPDPMSG_SENDENVELOPE lpMsg = lpMessageBody; 214 HRESULT hr = DPERR_GENERIC; 215 WORD wCommandId; 216 WORD wVersion; 217 DPSP_REPLYDATA data; 218 219 FIXME( "(%p)->(%p,0x%08x,%p): mostly stub\n", 220 This, lpMessageBody, dwMessageBodySize, lpMessageHeader ); 221 222 wCommandId = lpMsg->wCommandId; 223 wVersion = lpMsg->wVersion; 224 225 TRACE( "Incoming message has envelope of 0x%08x, %u, %u\n", 226 lpMsg->dwMagic, wCommandId, wVersion ); 227 228 if( lpMsg->dwMagic != DPMSGMAGIC_DPLAYMSG ) 229 { 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 TRACE( "lpMessageHeader = [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx] [0x%08lx]\n", 239 lpcHeader[0], lpcHeader[1], lpcHeader[2], lpcHeader[3], lpcHeader[4] ); 240 } 241 #endif 242 243 /* Pass everything else to Direct Play */ 244 data.lpMessage = NULL; 245 data.dwMessageSize = 0; 246 247 /* Pass this message to the dplay interface to handle */ 248 hr = DP_HandleMessage( This->dplay, lpMessageBody, dwMessageBodySize, lpMessageHeader, 249 wCommandId, wVersion, &data.lpMessage, &data.dwMessageSize ); 250 251 if( FAILED(hr) ) 252 { 253 ERR( "Command processing failed %s\n", DPLAYX_HresultToString(hr) ); 254 } 255 256 /* Do we want a reply? */ 257 if( data.lpMessage != NULL ) 258 { 259 data.lpSPMessageHeader = lpMessageHeader; 260 data.idNameServer = 0; 261 data.lpISP = iface; 262 263 hr = This->dplay->dp2->spData.lpCB->Reply( &data ); 264 265 if( FAILED(hr) ) 266 { 267 ERR( "Reply failed %s\n", DPLAYX_HresultToString(hr) ); 268 } 269 } 270 271 return hr; 272 273 #if 0 274 HRESULT hr = DP_OK; 275 HANDLE hReceiveEvent = 0; 276 /* FIXME: Acquire some sort of interface lock */ 277 /* FIXME: Need some sort of context for this callback. Need to determine 278 * how this is actually done with the SP 279 */ 280 /* FIXME: Who needs to delete the message when done? */ 281 switch( lpMsg->dwType ) 282 { 283 case DPSYS_CREATEPLAYERORGROUP: 284 { 285 LPDPMSG_CREATEPLAYERORGROUP msg = lpMsg; 286 287 if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER ) 288 { 289 hr = DP_IF_CreatePlayer( This, lpMessageHeader, msg->dpId, 290 &msg->dpnName, 0, msg->lpData, 291 msg->dwDataSize, msg->dwFlags, ... ); 292 } 293 else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP ) 294 { 295 /* Group in group situation? */ 296 if( msg->dpIdParent == DPID_NOPARENT_GROUP ) 297 { 298 hr = DP_IF_CreateGroup( This, lpMessageHeader, msg->dpId, 299 &msg->dpnName, 0, msg->lpData, 300 msg->dwDataSize, msg->dwFlags, ... ); 301 } 302 else /* Group in Group */ 303 { 304 hr = DP_IF_CreateGroupInGroup( This, lpMessageHeader, msg->dpIdParent, 305 &msg->dpnName, 0, msg->lpData, 306 msg->dwDataSize, msg->dwFlags, ... ); 307 } 308 } 309 else /* Hmmm? */ 310 { 311 ERR( "Corrupt msg->dwPlayerType for DPSYS_CREATEPLAYERORGROUP\n" ); 312 return; 313 } 314 315 break; 316 } 317 318 case DPSYS_DESTROYPLAYERORGROUP: 319 { 320 LPDPMSG_DESTROYPLAYERORGROUP msg = lpMsg; 321 322 if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER ) 323 { 324 hr = DP_IF_DestroyPlayer( This, msg->dpId, ... ); 325 } 326 else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP ) 327 { 328 hr = DP_IF_DestroyGroup( This, msg->dpId, ... ); 329 } 330 else /* Hmmm? */ 331 { 332 ERR( "Corrupt msg->dwPlayerType for DPSYS_DESTROYPLAYERORGROUP\n" ); 333 return; 334 } 335 336 break; 337 } 338 339 case DPSYS_ADDPLAYERTOGROUP: 340 { 341 LPDPMSG_ADDPLAYERTOGROUP msg = lpMsg; 342 343 hr = DP_IF_AddPlayerToGroup( This, msg->dpIdGroup, msg->dpIdPlayer, ... ); 344 break; 345 } 346 347 case DPSYS_DELETEPLAYERFROMGROUP: 348 { 349 LPDPMSG_DELETEPLAYERFROMGROUP msg = lpMsg; 350 351 hr = DP_IF_DeletePlayerFromGroup( This, msg->dpIdGroup, msg->dpIdPlayer, 352 ... ); 353 354 break; 355 } 356 357 case DPSYS_SESSIONLOST: 358 { 359 LPDPMSG_SESSIONLOST msg = lpMsg; 360 361 FIXME( "DPSYS_SESSIONLOST not handled\n" ); 362 363 break; 364 } 365 366 case DPSYS_HOST: 367 { 368 LPDPMSG_HOST msg = lpMsg; 369 370 FIXME( "DPSYS_HOST not handled\n" ); 371 372 break; 373 } 374 375 case DPSYS_SETPLAYERORGROUPDATA: 376 { 377 LPDPMSG_SETPLAYERORGROUPDATA msg = lpMsg; 378 379 if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER ) 380 { 381 hr = DP_IF_SetPlayerData( This, msg->dpId, msg->lpData, msg->dwDataSize, DPSET_REMOTE, ... ); 382 } 383 else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP ) 384 { 385 hr = DP_IF_SetGroupData( This, msg->dpId, msg->lpData, msg->dwDataSize, 386 DPSET_REMOTE, ... ); 387 } 388 else /* Hmmm? */ 389 { 390 ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" ); 391 return; 392 } 393 394 break; 395 } 396 397 case DPSYS_SETPLAYERORGROUPNAME: 398 { 399 LPDPMSG_SETPLAYERORGROUPNAME msg = lpMsg; 400 401 if( msg->dwPlayerType == DPPLAYERTYPE_PLAYER ) 402 { 403 hr = DP_IF_SetPlayerName( This, msg->dpId, msg->dpnName, ... ); 404 } 405 else if( msg->dwPlayerType == DPPLAYERTYPE_GROUP ) 406 { 407 hr = DP_IF_SetGroupName( This, msg->dpId, msg->dpnName, ... ); 408 } 409 else /* Hmmm? */ 410 { 411 ERR( "Corrupt msg->dwPlayerType for LPDPMSG_SETPLAYERORGROUPDATA\n" ); 412 return; 413 } 414 415 break; 416 } 417 418 case DPSYS_SETSESSIONDESC; 419 { 420 LPDPMSG_SETSESSIONDESC msg = lpMsg; 421 422 hr = DP_IF_SetSessionDesc( This, &msg->dpDesc ); 423 424 break; 425 } 426 427 case DPSYS_ADDGROUPTOGROUP: 428 { 429 LPDPMSG_ADDGROUPTOGROUP msg = lpMsg; 430 431 hr = DP_IF_AddGroupToGroup( This, msg->dpIdParentGroup, msg->dpIdGroup, 432 ... ); 433 434 break; 435 } 436 437 case DPSYS_DELETEGROUPFROMGROUP: 438 { 439 LPDPMSG_DELETEGROUPFROMGROUP msg = lpMsg; 440 441 hr = DP_IF_DeleteGroupFromGroup( This, msg->dpIdParentGroup, 442 msg->dpIdGroup, ... ); 443 444 break; 445 } 446 447 case DPSYS_SECUREMESSAGE: 448 { 449 LPDPMSG_SECUREMESSAGE msg = lpMsg; 450 451 FIXME( "DPSYS_SECUREMESSAGE not implemented\n" ); 452 453 break; 454 } 455 456 case DPSYS_STARTSESSION: 457 { 458 LPDPMSG_STARTSESSION msg = lpMsg; 459 460 FIXME( "DPSYS_STARTSESSION not implemented\n" ); 461 462 break; 463 } 464 465 case DPSYS_CHAT: 466 { 467 LPDPMSG_CHAT msg = lpMsg; 468 469 FIXME( "DPSYS_CHAT not implemented\n" ); 470 471 break; 472 } 473 474 case DPSYS_SETGROUPOWNER: 475 { 476 LPDPMSG_SETGROUPOWNER msg = lpMsg; 477 478 FIXME( "DPSYS_SETGROUPOWNER not implemented\n" ); 479 480 break; 481 } 482 483 case DPSYS_SENDCOMPLETE: 484 { 485 LPDPMSG_SENDCOMPLETE msg = lpMsg; 486 487 FIXME( "DPSYS_SENDCOMPLETE not implemented\n" ); 488 489 break; 490 } 491 492 default: 493 { 494 /* NOTE: This should be a user defined type. There is nothing that we 495 * need to do with it except queue it. 496 */ 497 TRACE( "Received user message type(?) 0x%08lx through SP.\n", 498 lpMsg->dwType ); 499 break; 500 } 501 } 502 503 FIXME( "Queue message in the receive queue. Need some context data!\n" ); 504 505 if( FAILED(hr) ) 506 { 507 ERR( "Unable to perform action for msg type 0x%08lx\n", lpMsg->dwType ); 508 } 509 /* If a receive event was registered for this player, invoke it */ 510 if( hReceiveEvent ) 511 { 512 SetEvent( hReceiveEvent ); 513 } 514 #endif 515 } 516 517 static HRESULT WINAPI IDirectPlaySPImpl_SetSPPlayerData( IDirectPlaySP *iface, DPID idPlayer, 518 void *lpData, DWORD dwDataSize, DWORD dwFlags ) 519 { 520 IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface ); 521 HRESULT hr; 522 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 if( FAILED(hr) ) 529 { 530 /* Player must not exist */ 531 return DPERR_INVALIDPLAYER; 532 } 533 534 lpPlayerData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize ); 535 CopyMemory( lpPlayerData, lpData, dwDataSize ); 536 537 if( dwFlags == DPSET_LOCAL ) 538 { 539 lpPlayerEntry->lpPlayerLocalData = lpPlayerData; 540 lpPlayerEntry->dwPlayerLocalDataSize = dwDataSize; 541 } 542 else if( dwFlags == DPSET_REMOTE ) 543 { 544 lpPlayerEntry->lpPlayerRemoteData = lpPlayerData; 545 lpPlayerEntry->dwPlayerRemoteDataSize = dwDataSize; 546 } 547 548 hr = DP_SetSPPlayerData( This->dplay, idPlayer, lpPlayerEntry ); 549 550 return hr; 551 } 552 553 static HRESULT WINAPI IDirectPlaySPImpl_CreateCompoundAddress( IDirectPlaySP *iface, 554 const DPCOMPOUNDADDRESSELEMENT *lpElements, DWORD dwElementCount, void *lpAddress, 555 DWORD *lpdwAddressSize ) 556 { 557 IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface ); 558 559 FIXME( "(%p)->(%p,0x%08x,%p,%p): stub\n", 560 This, lpElements, dwElementCount, lpAddress, lpdwAddressSize ); 561 562 return DP_OK; 563 } 564 565 static HRESULT WINAPI IDirectPlaySPImpl_GetSPData( IDirectPlaySP *iface, void **lplpData, 566 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 #if 0 574 /* This is what the documentation says... */ 575 if( dwFlags != DPSET_REMOTE ) 576 { 577 return DPERR_INVALIDPARAMS; 578 } 579 #else 580 /* ... but most service providers call this with 1 */ 581 /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of 582 * thing? 583 */ 584 if( dwFlags != DPSET_REMOTE ) 585 { 586 TRACE( "Undocumented dwFlags 0x%08x used\n", dwFlags ); 587 } 588 #endif 589 590 /* FIXME: What to do in the case where this isn't initialized yet? */ 591 592 /* Yes, we're supposed to return a pointer to the memory we have stored! */ 593 if( dwFlags == DPSET_REMOTE ) 594 { 595 *lpdwDataSize = This->remote_data_size; 596 *lplpData = This->remote_data; 597 598 if( !This->remote_data ) 599 hr = DPERR_GENERIC; 600 } 601 else if( dwFlags == DPSET_LOCAL ) 602 { 603 *lpdwDataSize = This->local_data_size; 604 *lplpData = This->local_data; 605 606 if( !This->local_data ) 607 hr = DPERR_GENERIC; 608 } 609 610 return hr; 611 } 612 613 static HRESULT WINAPI IDirectPlaySPImpl_SetSPData( IDirectPlaySP *iface, void *lpData, 614 DWORD dwDataSize, DWORD dwFlags ) 615 { 616 IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface ); 617 LPVOID lpSpData; 618 619 TRACE( "(%p)->(%p,0x%08x,0x%08x)\n", This, lpData, dwDataSize, dwFlags ); 620 621 #if 0 622 /* This is what the documentation says... */ 623 if( dwFlags != DPSET_REMOTE ) 624 { 625 return DPERR_INVALIDPARAMS; 626 } 627 #else 628 /* ... but most service providers call this with 1 */ 629 /* Guess that this is using a DPSET_LOCAL or DPSET_REMOTE type of 630 * thing? 631 */ 632 if( dwFlags != DPSET_REMOTE ) 633 { 634 TRACE( "Undocumented dwFlags 0x%08x used\n", dwFlags ); 635 } 636 #endif 637 638 lpSpData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwDataSize ); 639 CopyMemory( lpSpData, lpData, dwDataSize ); 640 641 /* If we have data already allocated, free it and replace it */ 642 if( dwFlags == DPSET_REMOTE ) 643 { 644 HeapFree( GetProcessHeap(), 0, This->remote_data ); 645 This->remote_data_size = dwDataSize; 646 This->remote_data = lpSpData; 647 } 648 else if ( dwFlags == DPSET_LOCAL ) 649 { 650 HeapFree( GetProcessHeap(), 0, This->local_data ); 651 This->local_data = lpSpData; 652 This->local_data_size = dwDataSize; 653 } 654 655 return DP_OK; 656 } 657 658 static void WINAPI IDirectPlaySPImpl_SendComplete( IDirectPlaySP *iface, void *unknownA, 659 DWORD unknownB ) 660 { 661 IDirectPlaySPImpl *This = impl_from_IDirectPlaySP( iface ); 662 663 FIXME( "(%p)->(%p,0x%08x): stub\n", 664 This, unknownA, unknownB ); 665 } 666 667 static const IDirectPlaySPVtbl directPlaySPVT = 668 { 669 IDirectPlaySPImpl_QueryInterface, 670 IDirectPlaySPImpl_AddRef, 671 IDirectPlaySPImpl_Release, 672 IDirectPlaySPImpl_AddMRUEntry, 673 IDirectPlaySPImpl_CreateAddress, 674 IDirectPlaySPImpl_EnumAddress, 675 IDirectPlaySPImpl_EnumMRUEntries, 676 IDirectPlaySPImpl_GetPlayerFlags, 677 IDirectPlaySPImpl_GetSPPlayerData, 678 IDirectPlaySPImpl_HandleMessage, 679 IDirectPlaySPImpl_SetSPPlayerData, 680 IDirectPlaySPImpl_CreateCompoundAddress, 681 IDirectPlaySPImpl_GetSPData, 682 IDirectPlaySPImpl_SetSPData, 683 IDirectPlaySPImpl_SendComplete 684 }; 685 686 HRESULT dplaysp_create( REFIID riid, void **ppv, IDirectPlayImpl *dp ) 687 { 688 IDirectPlaySPImpl *obj; 689 HRESULT hr; 690 691 TRACE( "(%s, %p)\n", debugstr_guid( riid ), ppv ); 692 693 *ppv = NULL; 694 obj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *obj ) ); 695 if ( !obj ) 696 return DPERR_OUTOFMEMORY; 697 698 obj->IDirectPlaySP_iface.lpVtbl = &directPlaySPVT; 699 obj->ref = 1; 700 obj->dplay = dp; 701 702 hr = IDirectPlaySP_QueryInterface( &obj->IDirectPlaySP_iface, riid, ppv ); 703 IDirectPlaySP_Release( &obj->IDirectPlaySP_iface ); 704 705 return hr; 706 } 707 708 /* DP external interfaces to call into DPSP interface */ 709 710 /* Allocate the structure */ 711 LPVOID DPSP_CreateSPPlayerData(void) 712 { 713 TRACE( "Creating SPPlayer data struct\n" ); 714 return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 715 sizeof( DP_SPPLAYERDATA ) ); 716 } 717