forked from wine-mirror/wine
-
Notifications
You must be signed in to change notification settings - Fork 1
/
dplay.c
5451 lines (4526 loc) · 167 KB
/
dplay.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* Direct Play 2,3,4 Implementation
*
* Copyright 1998,1999,2000,2001 - Peter Hunnisett
*
* 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
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "wine/port.h"
#include <stdarg.h>
#include <string.h>
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
#include "winerror.h"
#include "winbase.h"
#include "winnt.h"
#include "winreg.h"
#include "winnls.h"
#include "wine/unicode.h"
#include "wine/debug.h"
#include "dpinit.h"
#include "dplayx_global.h"
#include "name_server.h"
#include "dplayx_queue.h"
#include "dplaysp.h"
#include "dplay_global.h"
WINE_DEFAULT_DEBUG_CHANNEL(dplay);
/* FIXME: Should this be externed? */
extern HRESULT DPL_CreateCompoundAddress
( LPCDPCOMPOUNDADDRESSELEMENT lpElements, DWORD dwElementCount,
LPVOID lpAddress, LPDWORD lpdwAddressSize, BOOL bAnsiInterface );
/* Local function prototypes */
static lpPlayerList DP_FindPlayer( IDirectPlay2AImpl* This, DPID dpid );
static lpPlayerData DP_CreatePlayer( IDirectPlay2Impl* iface, LPDPID lpid,
LPDPNAME lpName, DWORD dwFlags,
HANDLE hEvent, BOOL bAnsi );
static BOOL DP_CopyDPNAMEStruct( LPDPNAME lpDst, LPDPNAME lpSrc, BOOL bAnsi );
static void DP_SetPlayerData( lpPlayerData lpPData, DWORD dwFlags,
LPVOID lpData, DWORD dwDataSize );
static lpGroupData DP_CreateGroup( IDirectPlay2AImpl* iface, LPDPID lpid,
LPDPNAME lpName, DWORD dwFlags,
DPID idParent, BOOL bAnsi );
static void DP_SetGroupData( lpGroupData lpGData, DWORD dwFlags,
LPVOID lpData, DWORD dwDataSize );
static void DP_DeleteDPNameStruct( LPDPNAME lpDPName );
static void DP_DeletePlayer( IDirectPlay2Impl* This, DPID dpid );
static BOOL CALLBACK cbDeletePlayerFromAllGroups( DPID dpId,
DWORD dwPlayerType,
LPCDPNAME lpName,
DWORD dwFlags,
LPVOID lpContext );
static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid );
static BOOL CALLBACK cbRemoveGroupOrPlayer( DPID dpId, DWORD dwPlayerType,
LPCDPNAME lpName, DWORD dwFlags,
LPVOID lpContext );
static void DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid );
/* Forward declarations of virtual tables */
static const IDirectPlay2Vtbl directPlay2AVT;
static const IDirectPlay3Vtbl directPlay3AVT;
static const IDirectPlay4Vtbl directPlay4AVT;
static const IDirectPlay2Vtbl directPlay2WVT;
static const IDirectPlay3Vtbl directPlay3WVT;
static const IDirectPlay4Vtbl directPlay4WVT;
/* Helper methods for player/group interfaces */
static HRESULT WINAPI DP_IF_DeletePlayerFromGroup
( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
DPID idPlayer, BOOL bAnsi );
static HRESULT WINAPI DP_IF_CreatePlayer
( IDirectPlay2Impl* This, LPVOID lpMsgHdr, LPDPID lpidPlayer,
LPDPNAME lpPlayerName, HANDLE hEvent, LPVOID lpData,
DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
static HRESULT WINAPI DP_IF_DestroyGroup
( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup, BOOL bAnsi );
static HRESULT WINAPI DP_IF_DestroyPlayer
( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idPlayer, BOOL bAnsi );
static HRESULT WINAPI DP_IF_EnumGroupPlayers
( IDirectPlay2Impl* This, DPID idGroup, LPGUID lpguidInstance,
LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
static HRESULT WINAPI DP_IF_EnumGroups
( IDirectPlay2Impl* This, LPGUID lpguidInstance,
LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
static HRESULT WINAPI DP_IF_EnumPlayers
( IDirectPlay2Impl* This, LPGUID lpguidInstance,
LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
static HRESULT WINAPI DP_IF_GetGroupData
( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
static HRESULT WINAPI DP_IF_GetGroupName
( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
LPDWORD lpdwDataSize, BOOL bAnsi );
static HRESULT WINAPI DP_IF_GetPlayerData
( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
LPDWORD lpdwDataSize, DWORD dwFlags, BOOL bAnsi );
static HRESULT WINAPI DP_IF_GetPlayerName
( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
LPDWORD lpdwDataSize, BOOL bAnsi );
static HRESULT WINAPI DP_IF_SetGroupName
( IDirectPlay2Impl* This, DPID idGroup, LPDPNAME lpGroupName,
DWORD dwFlags, BOOL bAnsi );
static HRESULT WINAPI DP_IF_SetPlayerData
( IDirectPlay2Impl* This, DPID idPlayer, LPVOID lpData,
DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
static HRESULT WINAPI DP_IF_SetPlayerName
( IDirectPlay2Impl* This, DPID idPlayer, LPDPNAME lpPlayerName,
DWORD dwFlags, BOOL bAnsi );
static HRESULT WINAPI DP_IF_AddGroupToGroup
( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
static HRESULT WINAPI DP_IF_CreateGroup
( IDirectPlay2AImpl* This, LPVOID lpMsgHdr, LPDPID lpidGroup,
LPDPNAME lpGroupName, LPVOID lpData, DWORD dwDataSize,
DWORD dwFlags, BOOL bAnsi );
static HRESULT WINAPI DP_IF_CreateGroupInGroup
( IDirectPlay3Impl* This, LPVOID lpMsgHdr, DPID idParentGroup,
LPDPID lpidGroup, LPDPNAME lpGroupName, LPVOID lpData,
DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
static HRESULT WINAPI DP_IF_AddPlayerToGroup
( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
DPID idPlayer, BOOL bAnsi );
static HRESULT WINAPI DP_IF_DeleteGroupFromGroup
( IDirectPlay3Impl* This, DPID idParentGroup, DPID idGroup );
static HRESULT WINAPI DP_SetSessionDesc
( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpSessDesc,
DWORD dwFlags, BOOL bInitial, BOOL bAnsi );
static HRESULT WINAPI DP_SecureOpen
( IDirectPlay2Impl* This, LPCDPSESSIONDESC2 lpsd, DWORD dwFlags,
LPCDPSECURITYDESC lpSecurity, LPCDPCREDENTIALS lpCredentials,
BOOL bAnsi );
static HRESULT WINAPI DP_SendEx
( IDirectPlay2Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
LPVOID lpContext, LPDWORD lpdwMsgID, BOOL bAnsi );
static HRESULT WINAPI DP_IF_Receive
( IDirectPlay2Impl* This, LPDPID lpidFrom, LPDPID lpidTo,
DWORD dwFlags, LPVOID lpData, LPDWORD lpdwDataSize, BOOL bAnsi );
static HRESULT WINAPI DP_IF_GetMessageQueue
( IDirectPlay4Impl* This, DPID idFrom, DPID idTo, DWORD dwFlags,
LPDWORD lpdwNumMsgs, LPDWORD lpdwNumBytes, BOOL bAnsi );
static HRESULT WINAPI DP_SP_SendEx
( IDirectPlay2Impl* This, DWORD dwFlags,
LPVOID lpData, DWORD dwDataSize, DWORD dwPriority, DWORD dwTimeout,
LPVOID lpContext, LPDWORD lpdwMsgID );
static HRESULT WINAPI DP_IF_SetGroupData
( IDirectPlay2Impl* This, DPID idGroup, LPVOID lpData,
DWORD dwDataSize, DWORD dwFlags, BOOL bAnsi );
static HRESULT WINAPI DP_IF_GetPlayerCaps
( IDirectPlay2Impl* This, DPID idPlayer, LPDPCAPS lpDPCaps,
DWORD dwFlags );
static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi );
static HRESULT WINAPI DP_IF_CancelMessage
( IDirectPlay4Impl* This, DWORD dwMsgID, DWORD dwFlags,
DWORD dwMinPriority, DWORD dwMaxPriority, BOOL bAnsi );
static HRESULT WINAPI DP_IF_EnumGroupsInGroup
( IDirectPlay3AImpl* This, DPID idGroup, LPGUID lpguidInstance,
LPDPENUMPLAYERSCALLBACK2 lpEnumPlayersCallback2,
LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
static HRESULT WINAPI DP_IF_GetGroupParent
( IDirectPlay3AImpl* This, DPID idGroup, LPDPID lpidGroup,
BOOL bAnsi );
static HRESULT WINAPI DP_IF_GetCaps
( IDirectPlay2Impl* This, LPDPCAPS lpDPCaps, DWORD dwFlags );
static HRESULT WINAPI DP_IF_EnumSessions
( IDirectPlay2Impl* This, LPDPSESSIONDESC2 lpsd, DWORD dwTimeout,
LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,
LPVOID lpContext, DWORD dwFlags, BOOL bAnsi );
static HRESULT WINAPI DP_IF_InitializeConnection
( IDirectPlay3Impl* This, LPVOID lpConnection, DWORD dwFlags, BOOL bAnsi );
static BOOL CALLBACK cbDPCreateEnumConnections( LPCGUID lpguidSP,
LPVOID lpConnection, DWORD dwConnectionSize, LPCDPNAME lpName,
DWORD dwFlags, LPVOID lpContext );
static BOOL WINAPI DP_BuildSPCompoundAddr( LPGUID lpcSpGuid, LPVOID* lplpAddrBuf,
LPDWORD lpdwBufSize );
static inline DPID DP_NextObjectId(void);
static DPID DP_GetRemoteNextObjectId(void);
static void DP_CopySessionDesc( LPDPSESSIONDESC2 destSessionDesc,
LPCDPSESSIONDESC2 srcSessDesc, BOOL bAnsi );
static HMODULE DP_LoadSP( LPCGUID lpcGuid, LPSPINITDATA lpSpData, LPBOOL lpbIsDpSp );
static HRESULT DP_InitializeDPSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
static HRESULT DP_InitializeDPLSP( IDirectPlay3Impl* This, HMODULE hServiceProvider );
#define DPID_NOPARENT_GROUP 0 /* Magic number to indicate no parent of group */
#define DPID_SYSTEM_GROUP DPID_NOPARENT_GROUP /* If system group is supported
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
static LONG kludgePlayerGroupId = 1000;
/* ------------------------------------------------------------------ */
static BOOL DP_CreateIUnknown( LPVOID lpDP )
{
IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
This->unk = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->unk) ) );
if ( This->unk == NULL )
{
return FALSE;
}
InitializeCriticalSection( &This->unk->DP_lock );
return TRUE;
}
static BOOL DP_DestroyIUnknown( LPVOID lpDP )
{
IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
DeleteCriticalSection( &This->unk->DP_lock );
HeapFree( GetProcessHeap(), 0, This->unk );
return TRUE;
}
static BOOL DP_CreateDirectPlay2( LPVOID lpDP )
{
IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
This->dp2 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp2) ) );
if ( This->dp2 == NULL )
{
return FALSE;
}
This->dp2->bConnectionOpen = FALSE;
This->dp2->hEnumSessionThread = INVALID_HANDLE_VALUE;
This->dp2->bHostInterface = FALSE;
DPQ_INIT(This->dp2->receiveMsgs);
DPQ_INIT(This->dp2->sendMsgs);
DPQ_INIT(This->dp2->replysExpected);
if( !NS_InitializeSessionCache( &This->dp2->lpNameServerData ) )
{
/* FIXME: Memory leak */
return FALSE;
}
/* Provide an initial session desc with nothing in it */
This->dp2->lpSessionDesc = HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof( *This->dp2->lpSessionDesc ) );
if( This->dp2->lpSessionDesc == NULL )
{
/* FIXME: Memory leak */
return FALSE;
}
This->dp2->lpSessionDesc->dwSize = sizeof( *This->dp2->lpSessionDesc );
/* We are emulating a dp 6 implementation */
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;
/* This is the pointer to the service provider */
if( FAILED( DPSP_CreateInterface( &IID_IDirectPlaySP,
(LPVOID*)&This->dp2->spData.lpISP, This ) )
)
{
/* FIXME: Memory leak */
return FALSE;
}
/* 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;
}
return TRUE;
}
/* 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 )
{
HeapFree( GetProcessHeap(), 0, elem );
}
/* Function to delete the list of groups with this interface. Needs to
* delete the group and player lists associated with this group as well
* as the group data associated with this group. It should not delete
* player data as that is shared with the top player list and will be
* deleted with that.
*/
DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList );
DPQ_DECL_DELETECB( cbDeleteGroupsElem, lpGroupList )
{
DPQ_DELETEQ( elem->lpGData->groups, groups,
lpGroupList, cbDeleteElemFromHeap );
DPQ_DELETEQ( elem->lpGData->players, players,
lpPlayerList, cbDeleteElemFromHeap );
HeapFree( GetProcessHeap(), 0, elem->lpGData );
HeapFree( GetProcessHeap(), 0, elem );
}
/* Function to delete the list of players with this interface. Needs to
* delete the player data for all players as well.
*/
DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList );
DPQ_DECL_DELETECB( cbDeletePlayerElem, lpPlayerList )
{
HeapFree( GetProcessHeap(), 0, elem->lpPData );
HeapFree( GetProcessHeap(), 0, elem );
}
static BOOL DP_DestroyDirectPlay2( LPVOID lpDP )
{
IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)lpDP;
if( This->dp2->hEnumSessionThread != INVALID_HANDLE_VALUE )
{
TerminateThread( This->dp2->hEnumSessionThread, 0 );
CloseHandle( This->dp2->hEnumSessionThread );
}
/* 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)();
}
/* Unload the SP (if it exists) */
if( This->dp2->hServiceProvider != 0 )
{
FreeLibrary( This->dp2->hServiceProvider );
}
/* Unload the Lobby Provider (if it exists) */
if( This->dp2->hDPLobbyProvider != 0 )
{
FreeLibrary( This->dp2->hDPLobbyProvider );
}
#if 0
DPQ_DELETEQ( This->dp2->players, players, lpPlayerList, cbDeletePlayerElem );
DPQ_DELETEQ( This->dp2->groups, groups, lpGroupList, cbDeleteGroupsElem );
#endif
/* FIXME: Need to delete receive and send msgs queue contents */
NS_DeleteSessionCache( This->dp2->lpNameServerData );
HeapFree( GetProcessHeap(), 0, This->dp2->lpSessionDesc );
IDirectPlaySP_Release( This->dp2->spData.lpISP );
/* Delete the contents */
HeapFree( GetProcessHeap(), 0, This->dp2 );
return TRUE;
}
static BOOL DP_CreateDirectPlay3( LPVOID lpDP )
{
IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
This->dp3 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp3) ) );
if ( This->dp3 == NULL )
{
return FALSE;
}
return TRUE;
}
static BOOL DP_DestroyDirectPlay3( LPVOID lpDP )
{
IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
/* Delete the contents */
HeapFree( GetProcessHeap(), 0, This->dp3 );
return TRUE;
}
static BOOL DP_CreateDirectPlay4( LPVOID lpDP )
{
IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)lpDP;
This->dp4 = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *(This->dp4) ) );
if ( This->dp4 == NULL )
{
return FALSE;
}
return TRUE;
}
static BOOL DP_DestroyDirectPlay4( LPVOID lpDP )
{
IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)lpDP;
/* Delete the contents */
HeapFree( GetProcessHeap(), 0, This->dp4 );
return TRUE;
}
/* Create a new interface */
extern
HRESULT DP_CreateInterface
( REFIID riid, LPVOID* ppvObj )
{
TRACE( " for %s\n", debugstr_guid( riid ) );
*ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof( IDirectPlay2Impl ) );
if( *ppvObj == NULL )
{
return DPERR_OUTOFMEMORY;
}
if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
{
IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj;
This->lpVtbl = &directPlay2WVT;
}
else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
{
IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj;
This->lpVtbl = &directPlay2AVT;
}
else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
{
IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj;
This->lpVtbl = &directPlay3WVT;
}
else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
{
IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj;
This->lpVtbl = &directPlay3AVT;
}
else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
{
IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj;
This->lpVtbl = &directPlay4WVT;
}
else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
{
IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj;
This->lpVtbl = &directPlay4AVT;
}
else
{
/* Unsupported interface */
HeapFree( GetProcessHeap(), 0, *ppvObj );
*ppvObj = NULL;
return E_NOINTERFACE;
}
/* Initialize it */
if ( DP_CreateIUnknown( *ppvObj ) &&
DP_CreateDirectPlay2( *ppvObj ) &&
DP_CreateDirectPlay3( *ppvObj ) &&
DP_CreateDirectPlay4( *ppvObj )
)
{
IDirectPlayX_AddRef( (LPDIRECTPLAY2A)*ppvObj );
return S_OK;
}
/* Initialize failed, destroy it */
DP_DestroyDirectPlay4( *ppvObj );
DP_DestroyDirectPlay3( *ppvObj );
DP_DestroyDirectPlay2( *ppvObj );
DP_DestroyIUnknown( *ppvObj );
HeapFree( GetProcessHeap(), 0, *ppvObj );
*ppvObj = NULL;
return DPERR_NOMEMORY;
}
/* Direct Play methods */
/* Shared between all dplay types */
static HRESULT WINAPI DP_QueryInterface
( LPDIRECTPLAY2 iface, REFIID riid, LPVOID* ppvObj )
{
IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
TRACE("(%p)->(%s,%p)\n", This, debugstr_guid( riid ), ppvObj );
*ppvObj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof( *This ) );
if( *ppvObj == NULL )
{
return DPERR_OUTOFMEMORY;
}
CopyMemory( *ppvObj, This, sizeof( *This ) );
(*(IDirectPlay2Impl**)ppvObj)->ulInterfaceRef = 0;
if( IsEqualGUID( &IID_IDirectPlay2, riid ) )
{
IDirectPlay2Impl *This = (IDirectPlay2Impl *)*ppvObj;
This->lpVtbl = &directPlay2WVT;
}
else if( IsEqualGUID( &IID_IDirectPlay2A, riid ) )
{
IDirectPlay2AImpl *This = (IDirectPlay2AImpl *)*ppvObj;
This->lpVtbl = &directPlay2AVT;
}
else if( IsEqualGUID( &IID_IDirectPlay3, riid ) )
{
IDirectPlay3Impl *This = (IDirectPlay3Impl *)*ppvObj;
This->lpVtbl = &directPlay3WVT;
}
else if( IsEqualGUID( &IID_IDirectPlay3A, riid ) )
{
IDirectPlay3AImpl *This = (IDirectPlay3AImpl *)*ppvObj;
This->lpVtbl = &directPlay3AVT;
}
else if( IsEqualGUID( &IID_IDirectPlay4, riid ) )
{
IDirectPlay4Impl *This = (IDirectPlay4Impl *)*ppvObj;
This->lpVtbl = &directPlay4WVT;
}
else if( IsEqualGUID( &IID_IDirectPlay4A, riid ) )
{
IDirectPlay4AImpl *This = (IDirectPlay4AImpl *)*ppvObj;
This->lpVtbl = &directPlay4AVT;
}
else
{
/* Unsupported interface */
HeapFree( GetProcessHeap(), 0, *ppvObj );
*ppvObj = NULL;
return E_NOINTERFACE;
}
IDirectPlayX_AddRef( (LPDIRECTPLAY2)*ppvObj );
return S_OK;
}
/* Shared between all dplay types */
static ULONG WINAPI DP_AddRef
( LPDIRECTPLAY3 iface )
{
ULONG ulInterfaceRefCount, ulObjRefCount;
IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
ulObjRefCount = InterlockedIncrement( &This->unk->ulObjRef );
ulInterfaceRefCount = InterlockedIncrement( &This->ulInterfaceRef );
TRACE( "ref count incremented to %lu:%lu for %p\n",
ulInterfaceRefCount, ulObjRefCount, This );
return ulObjRefCount;
}
static ULONG WINAPI DP_Release
( LPDIRECTPLAY3 iface )
{
ULONG ulInterfaceRefCount, ulObjRefCount;
IDirectPlay3Impl *This = (IDirectPlay3Impl *)iface;
ulObjRefCount = InterlockedDecrement( &This->unk->ulObjRef );
ulInterfaceRefCount = InterlockedDecrement( &This->ulInterfaceRef );
TRACE( "ref count decremented to %lu:%lu for %p\n",
ulInterfaceRefCount, ulObjRefCount, This );
/* Deallocate if this is the last reference to the object */
if( ulObjRefCount == 0 )
{
/* If we're destroying the object, this must be the last ref
of the last interface */
DP_DestroyDirectPlay4( This );
DP_DestroyDirectPlay3( This );
DP_DestroyDirectPlay2( This );
DP_DestroyIUnknown( This );
}
/* Deallocate the interface */
if( ulInterfaceRefCount == 0 )
{
HeapFree( GetProcessHeap(), 0, This );
}
return ulObjRefCount;
}
static inline DPID DP_NextObjectId(void)
{
return (DPID)InterlockedIncrement( &kludgePlayerGroupId );
}
/* *lplpReply will be non NULL iff there is something to reply */
HRESULT DP_HandleMessage( IDirectPlay2Impl* This, LPCVOID lpcMessageBody,
DWORD dwMessageBodySize, LPCVOID lpcMessageHeader,
WORD wCommandId, WORD wVersion,
LPVOID* lplpReply, LPDWORD lpdwMsgSize )
{
TRACE( "(%p)->(%p,0x%08lx,%p,%u,%u)\n",
This, lpcMessageBody, dwMessageBodySize, lpcMessageHeader, wCommandId,
wVersion );
switch( wCommandId )
{
/* 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,
(LPDPMSG_ENUMSESSIONSREPLY)lpcMessageBody,
This->dp2->lpNameServerData );
break;
}
case DPMSGCMD_REQUESTNEWPLAYERID:
{
LPCDPMSG_REQUESTNEWPLAYERID lpcMsg =
(LPCDPMSG_REQUESTNEWPLAYERID)lpcMessageBody;
LPDPMSG_NEWPLAYERIDREPLY lpReply;
*lpdwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpReply );
*lplpReply = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, *lpdwMsgSize );
FIXME( "Ignoring dwFlags 0x%08lx in request msg\n",
lpcMsg->dwFlags );
/* Setup the reply */
lpReply = (LPDPMSG_NEWPLAYERIDREPLY)( (BYTE*)(*lplpReply) +
This->dp2->spData.dwSPHeaderSize );
lpReply->envelope.dwMagic = DPMSGMAGIC_DPLAYMSG;
lpReply->envelope.wCommandId = DPMSGCMD_NEWPLAYERIDREPLY;
lpReply->envelope.wVersion = DPMSGVER_DP6;
lpReply->dpidNewPlayerId = DP_NextObjectId();
TRACE( "Allocating new playerid 0x%08lx from remote request\n",
lpReply->dpidNewPlayerId );
break;
}
case DPMSGCMD_GETNAMETABLEREPLY:
case DPMSGCMD_NEWPLAYERIDREPLY:
{
#if 0
if( wCommandId == DPMSGCMD_NEWPLAYERIDREPLY )
DebugBreak();
#endif
DP_MSG_ReplyReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
break;
}
#if 1
case DPMSGCMD_JUSTENVELOPE:
{
TRACE( "GOT THE SELF MESSAGE: %p -> 0x%08lx\n", lpcMessageHeader, ((LPDWORD)lpcMessageHeader)[1] );
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;
}
case DPMSGCMD_FORWARDADDPLAYERNACK:
{
DP_MSG_ErrorReceived( This, wCommandId, lpcMessageBody, dwMessageBodySize );
break;
}
default:
{
FIXME( "Unknown wCommandId %u. Ignoring message\n", wCommandId );
DebugBreak();
break;
}
}
/* FIXME: There is code in dplaysp.c to handle dplay commands. Move to here. */
return DP_OK;
}
static HRESULT WINAPI DP_IF_AddPlayerToGroup
( IDirectPlay2Impl* This, LPVOID lpMsgHdr, DPID idGroup,
DPID idPlayer, BOOL bAnsi )
{
lpGroupData lpGData;
lpPlayerList lpPList;
lpPlayerList lpNewPList;
TRACE( "(%p)->(%p,0x%08lx,0x%08lx,%u)\n",
This, lpMsgHdr, idGroup, idPlayer, bAnsi );
/* Find the group */
if( ( lpGData = DP_FindAnyGroup( This, idGroup ) ) == NULL )
{
return DPERR_INVALIDGROUP;
}
/* Find the player */
if( ( lpPList = DP_FindPlayer( This, idPlayer ) ) == NULL )
{
return DPERR_INVALIDPLAYER;
}
/* Create a player list (ie "shortcut" ) */
lpNewPList = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpNewPList ) );
if( lpNewPList == NULL )
{
return DPERR_CANTADDPLAYER;
}
/* Add the shortcut */
lpPList->lpPData->uRef++;
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;
TRACE( "Calling SP AddPlayerToGroup\n" );
data.idPlayer = idPlayer;
data.idGroup = idGroup;
data.lpISP = This->dp2->spData.lpISP;
(*This->dp2->spData.lpCB->AddPlayerToGroup)( &data );
}
/* Inform all other peers of the addition of player to the group. If there are
* no peers keep this event quiet.
* Also, if this event was the result of another machine sending it to us,
* don't bother rebroadcasting it.
*/
if( ( lpMsgHdr == NULL ) &&
This->dp2->lpSessionDesc &&
( This->dp2->lpSessionDesc->dwFlags & DPSESSION_MULTICASTSERVER ) )
{
DPMSG_ADDPLAYERTOGROUP msg;
msg.dwType = DPSYS_ADDPLAYERTOGROUP;
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 )
{
IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, TRUE );
}
static HRESULT WINAPI DirectPlay2WImpl_AddPlayerToGroup
( LPDIRECTPLAY2 iface, DPID idGroup, DPID idPlayer )
{
IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
return DP_IF_AddPlayerToGroup( This, NULL, idGroup, idPlayer, FALSE );
}
static HRESULT WINAPI DP_IF_Close( IDirectPlay2Impl* This, BOOL bAnsi )
{
HRESULT hr = DP_OK;
TRACE("(%p)->(%u)\n", This, bAnsi );
/* 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;
hr = (*This->dp2->spData.lpCB->CloseEx)( &data );
}
else if ( This->dp2->spData.lpCB->Close ) /* Try obsolete version */
{
TRACE( "Calling SP Close (obsolete interface)\n" );
hr = (*This->dp2->spData.lpCB->Close)();
}
return hr;
}
static HRESULT WINAPI DirectPlay2AImpl_Close
( LPDIRECTPLAY2A iface )
{
IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
return DP_IF_Close( This, TRUE );
}
static HRESULT WINAPI DirectPlay2WImpl_Close
( LPDIRECTPLAY2 iface )
{
IDirectPlay2Impl *This = (IDirectPlay2Impl *)iface;
return DP_IF_Close( This, FALSE );
}
static
lpGroupData DP_CreateGroup( IDirectPlay2AImpl* This, LPDPID lpid,
LPDPNAME lpName, DWORD dwFlags,
DPID idParent, BOOL bAnsi )
{
lpGroupData lpGData;
/* Allocate the new space and add to end of high level group list */
lpGData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( *lpGData ) );
if( lpGData == NULL )
{
return NULL;
}
DPQ_INIT(lpGData->groups);
DPQ_INIT(lpGData->players);
/* Set the desired player ID - no sanity checking to see if it exists */
lpGData->dpid = *lpid;
DP_CopyDPNAMEStruct( &lpGData->name, lpName, bAnsi );
/* FIXME: Should we check that the parent exists? */
lpGData->parent = idParent;
/* FIXME: Should we validate the dwFlags? */
lpGData->dwFlags = dwFlags;
TRACE( "Created group id 0x%08lx\n", *lpid );
return lpGData;
}
/* This method assumes that all links to it are already deleted */
static void
DP_DeleteGroup( IDirectPlay2Impl* This, DPID dpid )
{
lpGroupList lpGList;
TRACE( "(%p)->(0x%08lx)\n", This, dpid );
DPQ_REMOVE_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGList );
if( lpGList == NULL )
{
ERR( "DPID 0x%08lx not found\n", dpid );
return;
}
if( --(lpGList->lpGData->uRef) )
{
FIXME( "Why is this not the last reference to group?\n" );
DebugBreak();
}
/* Delete player */
DP_DeleteDPNameStruct( &lpGList->lpGData->name );
HeapFree( GetProcessHeap(), 0, lpGList->lpGData );
/* Remove and Delete Player List object */
HeapFree( GetProcessHeap(), 0, lpGList );
}
static lpGroupData DP_FindAnyGroup( IDirectPlay2AImpl* This, DPID dpid )
{
lpGroupList lpGroups;
TRACE( "(%p)->(0x%08lx)\n", This, dpid );
if( dpid == DPID_SYSTEM_GROUP )
{
return This->dp2->lpSysGroup;
}
else
{
DPQ_FIND_ENTRY( This->dp2->lpSysGroup->groups, groups, lpGData->dpid, ==, dpid, lpGroups );
}
if( lpGroups == NULL )
{
return NULL;