Fixed definitions of TTTOOLINFOA/W_V1_SIZE and
[wine] / dlls / dplayx / dplayx_global.c
1 /* dplayx.dll global data implementation.
2  *
3  * Copyright 1999,2000 - Peter Hunnisett
4  *
5  * <presently under construction - contact hunnise@nortelnetworks.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 /* NOTE: Methods that begin with DPLAYX_ are used for dealing with
23  *       dplayx.dll data which is accessible from all processes.
24  */
25
26 #include <stdarg.h>
27 #include <string.h>
28
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
31 #include "wine/debug.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winerror.h"
35 #include "wine/unicode.h"
36
37 #include "wingdi.h"
38 #include "winuser.h"
39
40 #include "dplayx_global.h"
41 #include "dplayx_messages.h" /* For CreateMessageReceptionThread only */
42
43 WINE_DEFAULT_DEBUG_CHANNEL(dplay);
44
45 /* FIXME: Need to do all that fun other dll referencing type of stuff */
46
47 /* Static data for all processes */
48 static LPCSTR lpszDplayxSemaName = "WINE_DPLAYX_SM";
49 static HANDLE hDplayxSema;
50
51 static LPCSTR lpszDplayxFileMapping = "WINE_DPLAYX_FM";
52 static HANDLE hDplayxSharedMem;
53
54 static LPVOID lpSharedStaticData = NULL;
55
56
57 #define DPLAYX_AquireSemaphore()  TRACE( "Waiting for DPLAYX semaphore\n" ); \
58                                   WaitForSingleObject( hDplayxSema, INFINITE );\
59                                   TRACE( "Through wait\n" )
60
61 #define DPLAYX_ReleaseSemaphore() ReleaseSemaphore( hDplayxSema, 1, NULL ); \
62                                   TRACE( "DPLAYX Semaphore released\n" ) /* FIXME: Is this correct? */
63
64
65 /* HACK for simple global data right now */
66 #define dwStaticSharedSize (128 * 1024) /* 128 KBytes */
67 #define dwDynamicSharedSize (512 * 1024) /* 512 KBytes */
68 #define dwTotalSharedSize  ( dwStaticSharedSize + dwDynamicSharedSize )
69
70
71 /* FIXME: Is there no easier way? */
72
73 /* Pretend the entire dynamic area is carved up into 512 byte blocks.
74  * Each block has 4 bytes which are 0 unless used */
75 #define dwBlockSize 512
76 #define dwMaxBlock  (dwDynamicSharedSize/dwBlockSize)
77
78 typedef struct
79 {
80   DWORD used;
81   DWORD data[dwBlockSize-sizeof(DWORD)];
82 } DPLAYX_MEM_SLICE;
83
84 static DPLAYX_MEM_SLICE* lpMemArea;
85
86 void DPLAYX_PrivHeapFree( LPVOID addr );
87 void DPLAYX_PrivHeapFree( LPVOID addr )
88 {
89   LPVOID lpAddrStart;
90   DWORD dwBlockUsed;
91
92   /* Handle getting passed a NULL */
93   if( addr == NULL )
94   {
95     return;
96   }
97
98   lpAddrStart = (char*)addr - sizeof(DWORD); /* Find block header */
99   dwBlockUsed =  ((BYTE*)lpAddrStart - (BYTE*)lpMemArea)/dwBlockSize;
100
101   lpMemArea[ dwBlockUsed ].used = 0;
102 }
103
104 /* FIXME: This should be static, but is being used for a hack right now */
105 LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size );
106 LPVOID DPLAYX_PrivHeapAlloc( DWORD flags, DWORD size )
107 {
108   LPVOID lpvArea = NULL;
109   UINT   uBlockUsed;
110
111   if( size > (dwBlockSize - sizeof(DWORD)) )
112   {
113     FIXME( "Size exceeded. Request of 0x%08lx\n", size );
114     size = dwBlockSize - sizeof(DWORD);
115   }
116
117   /* Find blank area */
118   uBlockUsed = 0;
119   while( ( lpMemArea[ uBlockUsed ].used != 0 ) && ( uBlockUsed <= dwMaxBlock ) ) { uBlockUsed++; }
120
121   if( uBlockUsed <= dwMaxBlock )
122   {
123     /* Set the area used */
124     lpMemArea[ uBlockUsed ].used = 1;
125     lpvArea = &(lpMemArea[ uBlockUsed ].data);
126   }
127   else
128   {
129     ERR( "No free block found\n" );
130     return NULL;
131   }
132
133   if( flags & HEAP_ZERO_MEMORY )
134   {
135     ZeroMemory( lpvArea, size );
136   }
137
138   return lpvArea;
139 }
140
141 LPSTR DPLAYX_strdupA( DWORD flags, LPCSTR str );
142 LPSTR DPLAYX_strdupA( DWORD flags, LPCSTR str )
143 {
144   LPSTR p = DPLAYX_PrivHeapAlloc( flags, strlen(str) + 1 );
145   if(p) {
146     strcpy( p, str );
147   }
148   return p;
149 }
150
151 LPWSTR DPLAYX_strdupW( DWORD flags, LPCWSTR str );
152 LPWSTR DPLAYX_strdupW( DWORD flags, LPCWSTR str )
153 {
154   INT len = strlenW(str) + 1;
155   LPWSTR p = DPLAYX_PrivHeapAlloc( flags, len * sizeof(WCHAR) );
156   if(p) {
157     strcpyW( p, str );
158   }
159   return p;
160 }
161
162
163 enum { numSupportedLobbies = 32, numSupportedSessions = 32 };
164 typedef struct tagDPLAYX_LOBBYDATA
165 {
166   /* Points to lpConn + block of contiguous extra memory for dynamic parts
167    * of the struct directly following
168    */
169   LPDPLCONNECTION lpConn;
170
171   /* Information for dplobby interfaces */
172   DWORD           dwAppID;
173   DWORD           dwAppLaunchedFromID;
174
175   /* Should this lobby app send messages to creator at important life
176    * stages
177    */
178   HANDLE hInformOnAppStart;
179   HANDLE hInformOnAppDeath;
180   HANDLE hInformOnSettingRead;
181
182   /* Sundries */
183   BOOL bWaitForConnectionSettings;
184   DWORD dwLobbyMsgThreadId;
185
186
187 } DPLAYX_LOBBYDATA, *LPDPLAYX_LOBBYDATA;
188
189 static DPLAYX_LOBBYDATA* lobbyData = NULL;
190 /* static DPLAYX_LOBBYDATA lobbyData[ numSupportedLobbies ]; */
191
192 static DPSESSIONDESC2* sessionData = NULL;
193 /* static DPSESSIONDESC2* sessionData[ numSupportedSessions ]; */
194
195 /* Function prototypes */
196 DWORD DPLAYX_SizeOfLobbyDataA( LPDPLCONNECTION lpDplData );
197 DWORD DPLAYX_SizeOfLobbyDataW( LPDPLCONNECTION lpDplData );
198 void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src );
199 void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, LPDPLCONNECTION src );
200 BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppId, LPDPLAYX_LOBBYDATA* dplData );
201 void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData );
202 BOOL DPLAYX_CopyIntoSessionDesc2A( LPDPSESSIONDESC2  lpSessionDest,
203                                    LPCDPSESSIONDESC2 lpSessionSrc );
204
205
206
207 /***************************************************************************
208  * Called to initialize the global data. This will only be used on the
209  * loading of the dll
210  ***************************************************************************/
211 BOOL DPLAYX_ConstructData(void)
212 {
213   SECURITY_ATTRIBUTES s_attrib;
214   BOOL                bInitializeSharedMemory = FALSE;
215   LPVOID              lpDesiredMemoryMapStart = (LPVOID)0x50000000;
216   HANDLE              hInformOnStart;
217
218   TRACE( "DPLAYX dll loaded - construct called\n" );
219
220   /* Create a semaphore to block access to DPLAYX global data structs */
221
222   s_attrib.bInheritHandle       = TRUE;
223   s_attrib.lpSecurityDescriptor = NULL;
224   s_attrib.nLength              = sizeof(s_attrib);
225
226   hDplayxSema = CreateSemaphoreA( &s_attrib, 1, 1, lpszDplayxSemaName );
227
228   /* First instance creates the semaphore. Others just use it */
229   if( GetLastError() == ERROR_SUCCESS )
230   {
231     TRACE( "Semaphore %p created\n", hDplayxSema );
232
233     /* The semaphore creator will also build the shared memory */
234     bInitializeSharedMemory = TRUE;
235   }
236   else if ( GetLastError() == ERROR_ALREADY_EXISTS )
237   {
238     TRACE( "Found semaphore handle %p\n", hDplayxSema );
239   }
240   else
241   {
242     ERR( ": semaphore error %ld\n", GetLastError() );
243     return FALSE;
244   }
245
246   SetLastError( ERROR_SUCCESS );
247
248   DPLAYX_AquireSemaphore();
249
250   hDplayxSharedMem = CreateFileMappingA( INVALID_HANDLE_VALUE,
251                                          &s_attrib,
252                                          PAGE_READWRITE | SEC_COMMIT,
253                                          0,
254                                          dwTotalSharedSize,
255                                          lpszDplayxFileMapping );
256
257   if( GetLastError() == ERROR_SUCCESS )
258   {
259     TRACE( "File mapped %p created\n", hDplayxSharedMem );
260   }
261   else if ( GetLastError() == ERROR_ALREADY_EXISTS )
262   {
263     TRACE( "Found FileMapping handle %p\n", hDplayxSharedMem );
264   }
265   else
266   {
267     ERR( ": unable to create shared memory (%ld)\n", GetLastError() );
268     return FALSE;
269   }
270
271   lpSharedStaticData = MapViewOfFileEx( hDplayxSharedMem,
272                                         FILE_MAP_WRITE,
273                                         0, 0, 0, lpDesiredMemoryMapStart );
274
275   if( lpSharedStaticData == NULL )
276   {
277     ERR( ": unable to map static data into process memory space (%ld)\n",
278          GetLastError() );
279     return FALSE;
280   }
281   else
282   {
283     if( lpDesiredMemoryMapStart == lpSharedStaticData )
284     {
285       TRACE( "File mapped to %p\n", lpSharedStaticData );
286     }
287     else
288     {
289       /* Presently the shared data structures use pointers. If the
290        * files are no mapped into the same area, the pointers will no
291        * longer make any sense :(
292        * FIXME: In the future make the shared data structures have some
293        *        sort of fixup to make them independent between data spaces.
294        *        This will also require a rework of the session data stuff.
295        */
296       ERR( "File mapped to %p (not %p). Expect failure\n",
297             lpSharedStaticData, lpDesiredMemoryMapStart );
298     }
299   }
300
301   /* Dynamic area starts just after the static area */
302   lpMemArea = (LPVOID)((BYTE*)lpSharedStaticData + dwStaticSharedSize);
303
304   /* FIXME: Crude hack */
305   lobbyData   = (DPLAYX_LOBBYDATA*)lpSharedStaticData;
306   sessionData = (DPSESSIONDESC2*)((BYTE*)lpSharedStaticData + (dwStaticSharedSize/2));
307
308   /* Initialize shared data segments. */
309   if( bInitializeSharedMemory )
310   {
311     UINT i;
312
313     TRACE( "Initializing shared memory\n" );
314
315     /* Set all lobbies to be "empty" */
316     for( i=0; i < numSupportedLobbies; i++ )
317     {
318       DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] );
319     }
320
321     /* Set all sessions to be "empty" */
322     for( i=0; i < numSupportedSessions; i++ )
323     {
324       sessionData[i].dwSize = 0;
325     }
326
327     /* Zero out the dynmaic area */
328     ZeroMemory( lpMemArea, dwDynamicSharedSize );
329
330     /* Just for fun sync the whole data area */
331     FlushViewOfFile( lpSharedStaticData, dwTotalSharedSize );
332   }
333
334   DPLAYX_ReleaseSemaphore();
335
336   /* Everything was created correctly. Signal the lobby client that
337    * we started up correctly
338    */
339   if( DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, FALSE ) &&
340       hInformOnStart
341     )
342   {
343     BOOL bSuccess;
344     bSuccess = SetEvent( hInformOnStart );
345     TRACE( "Signalling lobby app start event %p %s\n",
346              hInformOnStart, bSuccess ? "succeed" : "failed" );
347
348     /* Close out handle */
349     DPLAYX_GetThisLobbyHandles( &hInformOnStart, NULL, NULL, TRUE );
350   }
351
352   return TRUE;
353 }
354
355 /***************************************************************************
356  * Called to destroy all global data. This will only be used on the
357  * unloading of the dll
358  ***************************************************************************/
359 BOOL DPLAYX_DestructData(void)
360 {
361   HANDLE hInformOnDeath;
362
363   TRACE( "DPLAYX dll unloaded - destruct called\n" );
364
365   /* If required, inform that this app is dying */
366   if( DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, FALSE ) &&
367       hInformOnDeath
368     )
369   {
370     BOOL bSuccess;
371     bSuccess = SetEvent( hInformOnDeath );
372     TRACE( "Signalling lobby app death event %p %s\n",
373              hInformOnDeath, bSuccess ? "succeed" : "failed" );
374
375     /* Close out handle */
376     DPLAYX_GetThisLobbyHandles( NULL, &hInformOnDeath, NULL, TRUE );
377   }
378
379   /* DO CLEAN UP (LAST) */
380
381   /* Delete the semaphore */
382   CloseHandle( hDplayxSema );
383
384   /* Delete shared memory file mapping */
385   UnmapViewOfFile( lpSharedStaticData );
386   CloseHandle( hDplayxSharedMem );
387
388   return FALSE;
389 }
390
391
392 void DPLAYX_InitializeLobbyDataEntry( LPDPLAYX_LOBBYDATA lpData )
393 {
394   ZeroMemory( lpData, sizeof( *lpData ) );
395 }
396
397 /* NOTE: This must be called with the semaphore aquired.
398  * TRUE/FALSE with a pointer to it's data returned. Pointer data is
399  * is only valid if TRUE is returned.
400  */
401 BOOL DPLAYX_IsAppIdLobbied( DWORD dwAppID, LPDPLAYX_LOBBYDATA* lplpDplData )
402 {
403   UINT i;
404
405   *lplpDplData = NULL;
406
407   if( dwAppID == 0 )
408   {
409     dwAppID = GetCurrentProcessId();
410     TRACE( "Translated dwAppID == 0 into 0x%08lx\n", dwAppID );
411   }
412
413   for( i=0; i < numSupportedLobbies; i++ )
414   {
415     if( lobbyData[ i ].dwAppID == dwAppID )
416     {
417       /* This process is lobbied */
418       TRACE( "Found 0x%08lx @ %u\n", dwAppID, i );
419       *lplpDplData = &lobbyData[ i ];
420       return TRUE;
421     }
422   }
423
424   return FALSE;
425 }
426
427 /* Reserve a spot for the new appliction. TRUE means success and FALSE failure.  */
428 BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID )
429 {
430   UINT i;
431
432   /* 0 is the marker for unused application data slots */
433   if( dwAppID == 0 )
434   {
435     return FALSE;
436   }
437
438   DPLAYX_AquireSemaphore();
439
440   /* Find an empty space in the list and insert the data */
441   for( i=0; i < numSupportedLobbies; i++ )
442   {
443     if( lobbyData[ i ].dwAppID == 0 )
444     {
445       /* This process is now lobbied */
446       TRACE( "Setting lobbyData[%u] for (0x%08lx,0x%08lx)\n",
447               i, dwAppID, GetCurrentProcessId() );
448
449       lobbyData[ i ].dwAppID              = dwAppID;
450       lobbyData[ i ].dwAppLaunchedFromID  = GetCurrentProcessId();
451
452       /* FIXME: Where is the best place for this? In interface or here? */
453       lobbyData[ i ].hInformOnAppStart = 0;
454       lobbyData[ i ].hInformOnAppDeath = 0;
455       lobbyData[ i ].hInformOnSettingRead = 0;
456
457       DPLAYX_ReleaseSemaphore();
458       return TRUE;
459     }
460   }
461
462   ERR( "No empty lobbies\n" );
463
464   DPLAYX_ReleaseSemaphore();
465   return FALSE;
466 }
467
468 /* I'm not sure when I'm going to need this, but here it is */
469 BOOL DPLAYX_DestroyLobbyApplication( DWORD dwAppID )
470 {
471   UINT i;
472
473   DPLAYX_AquireSemaphore();
474
475   /* Find an empty space in the list and insert the data */
476   for( i=0; i < numSupportedLobbies; i++ )
477   {
478     if( lobbyData[ i ].dwAppID == dwAppID )
479     {
480       /* FIXME: Should free up anything unused. Tisk tisk :0 */
481       /* Mark this entry unused */
482       TRACE( "Marking lobbyData[%u] unused\n", i );
483       DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] );
484
485       DPLAYX_ReleaseSemaphore();
486       return TRUE;
487     }
488   }
489
490   DPLAYX_ReleaseSemaphore();
491   ERR( "Unable to find global entry for application\n" );
492   return FALSE;
493 }
494
495 BOOL DPLAYX_SetLobbyHandles( DWORD dwAppID,
496                              HANDLE hStart, HANDLE hDeath, HANDLE hConnRead )
497 {
498   LPDPLAYX_LOBBYDATA lpLData;
499
500   /* Need to explictly give lobby application. Can't set for yourself */
501   if( dwAppID == 0 )
502   {
503     return FALSE;
504   }
505
506   DPLAYX_AquireSemaphore();
507
508   if( !DPLAYX_IsAppIdLobbied( dwAppID, &lpLData ) )
509   {
510     DPLAYX_ReleaseSemaphore();
511     return FALSE;
512   }
513
514   lpLData->hInformOnAppStart    = hStart;
515   lpLData->hInformOnAppDeath    = hDeath;
516   lpLData->hInformOnSettingRead = hConnRead;
517
518   DPLAYX_ReleaseSemaphore();
519
520   return TRUE;
521 }
522
523 BOOL DPLAYX_GetThisLobbyHandles( LPHANDLE lphStart,
524                                  LPHANDLE lphDeath,
525                                  LPHANDLE lphConnRead,
526                                  BOOL     bClearSetHandles )
527 {
528   LPDPLAYX_LOBBYDATA lpLData;
529
530   DPLAYX_AquireSemaphore();
531
532   if( !DPLAYX_IsAppIdLobbied( 0, &lpLData ) )
533   {
534     DPLAYX_ReleaseSemaphore();
535     return FALSE;
536   }
537
538   if( lphStart != NULL )
539   {
540     if( lpLData->hInformOnAppStart == 0 )
541     {
542       DPLAYX_ReleaseSemaphore();
543       return FALSE;
544     }
545
546     *lphStart = lpLData->hInformOnAppStart;
547
548     if( bClearSetHandles )
549     {
550       CloseHandle( lpLData->hInformOnAppStart );
551       lpLData->hInformOnAppStart = 0;
552     }
553   }
554
555   if( lphDeath != NULL )
556   {
557     if( lpLData->hInformOnAppDeath == 0 )
558     {
559       DPLAYX_ReleaseSemaphore();
560       return FALSE;
561     }
562
563     *lphDeath = lpLData->hInformOnAppDeath;
564
565     if( bClearSetHandles )
566     {
567       CloseHandle( lpLData->hInformOnAppDeath );
568       lpLData->hInformOnAppDeath = 0;
569     }
570   }
571
572   if( lphConnRead != NULL )
573   {
574     if( lpLData->hInformOnSettingRead == 0 )
575     {
576       DPLAYX_ReleaseSemaphore();
577       return FALSE;
578     }
579
580     *lphConnRead = lpLData->hInformOnSettingRead;
581
582     if( bClearSetHandles )
583     {
584       CloseHandle( lpLData->hInformOnSettingRead );
585       lpLData->hInformOnSettingRead = 0;
586     }
587   }
588
589   DPLAYX_ReleaseSemaphore();
590
591   return TRUE;
592 }
593
594
595 HRESULT DPLAYX_GetConnectionSettingsA
596 ( DWORD dwAppID,
597   LPVOID lpData,
598   LPDWORD lpdwDataSize )
599 {
600   LPDPLAYX_LOBBYDATA lpDplData;
601   DWORD              dwRequiredDataSize = 0;
602   HANDLE             hInformOnSettingRead;
603
604   DPLAYX_AquireSemaphore();
605
606   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
607   {
608     DPLAYX_ReleaseSemaphore();
609
610     TRACE( "Application 0x%08lx is not lobbied\n", dwAppID );
611     return DPERR_NOTLOBBIED;
612   }
613
614   dwRequiredDataSize = DPLAYX_SizeOfLobbyDataA( lpDplData->lpConn );
615
616   /* Do they want to know the required buffer size or is the provided buffer
617    * big enough?
618    */
619   if ( ( lpData == NULL ) ||
620        ( *lpdwDataSize < dwRequiredDataSize )
621      )
622   {
623     DPLAYX_ReleaseSemaphore();
624
625     *lpdwDataSize = DPLAYX_SizeOfLobbyDataA( lpDplData->lpConn );
626
627     return DPERR_BUFFERTOOSMALL;
628   }
629
630   DPLAYX_CopyConnStructA( (LPDPLCONNECTION)lpData, lpDplData->lpConn );
631
632   DPLAYX_ReleaseSemaphore();
633
634   /* They have gotten the information - signal the event if required */
635   if( DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, FALSE ) &&
636       hInformOnSettingRead
637     )
638   {
639     BOOL bSuccess;
640     bSuccess = SetEvent( hInformOnSettingRead );
641     TRACE( "Signalling setting read event %p %s\n",
642              hInformOnSettingRead, bSuccess ? "succeed" : "failed" );
643
644     /* Close out handle */
645     DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, TRUE );
646   }
647
648   return DP_OK;
649 }
650
651 /* Assumption: Enough contiguous space was allocated at dest */
652 void DPLAYX_CopyConnStructA( LPDPLCONNECTION dest, LPDPLCONNECTION src )
653 {
654   BYTE* lpStartOfFreeSpace;
655
656   CopyMemory( dest, src, sizeof( DPLCONNECTION ) );
657
658   lpStartOfFreeSpace = ((BYTE*)dest) + sizeof( DPLCONNECTION );
659
660   /* Copy the LPDPSESSIONDESC2 structure if it exists */
661   if( src->lpSessionDesc )
662   {
663     dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace;
664     lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 );
665     CopyMemory( dest->lpSessionDesc, src->lpSessionDesc, sizeof( DPSESSIONDESC2 ) );
666
667     /* Session names may or may not exist */
668     if( src->lpSessionDesc->u1.lpszSessionNameA )
669     {
670       strcpy( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->u1.lpszSessionNameA );
671       dest->lpSessionDesc->u1.lpszSessionNameA = (LPSTR)lpStartOfFreeSpace;
672       lpStartOfFreeSpace +=
673         strlen( (LPSTR)dest->lpSessionDesc->u1.lpszSessionNameA ) + 1;
674     }
675
676     if( src->lpSessionDesc->u2.lpszPasswordA )
677     {
678       strcpy( (LPSTR)lpStartOfFreeSpace, src->lpSessionDesc->u2.lpszPasswordA );
679       dest->lpSessionDesc->u2.lpszPasswordA = (LPSTR)lpStartOfFreeSpace;
680       lpStartOfFreeSpace +=
681         strlen( (LPSTR)dest->lpSessionDesc->u2.lpszPasswordA ) + 1;
682     }
683   }
684
685   /* DPNAME structure is optional */
686   if( src->lpPlayerName )
687   {
688     dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace;
689     lpStartOfFreeSpace += sizeof( DPNAME );
690     CopyMemory( dest->lpPlayerName, src->lpPlayerName, sizeof( DPNAME ) );
691
692     if( src->lpPlayerName->u1.lpszShortNameA )
693     {
694       strcpy( (LPSTR)lpStartOfFreeSpace, src->lpPlayerName->u1.lpszShortNameA );
695       dest->lpPlayerName->u1.lpszShortNameA = (LPSTR)lpStartOfFreeSpace;
696       lpStartOfFreeSpace +=
697         strlen( (LPSTR)dest->lpPlayerName->u1.lpszShortNameA ) + 1;
698     }
699
700     if( src->lpPlayerName->u2.lpszLongNameA )
701     {
702       strcpy( (LPSTR)lpStartOfFreeSpace, src->lpPlayerName->u2.lpszLongNameA );
703       dest->lpPlayerName->u2.lpszLongNameA = (LPSTR)lpStartOfFreeSpace;
704       lpStartOfFreeSpace +=
705         strlen( (LPSTR)dest->lpPlayerName->u2.lpszLongName ) + 1 ;
706     }
707
708   }
709
710   /* Copy address if it exists */
711   if( src->lpAddress )
712   {
713     dest->lpAddress = (LPVOID)lpStartOfFreeSpace;
714     CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize );
715     /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */
716   }
717 }
718
719 HRESULT DPLAYX_GetConnectionSettingsW
720 ( DWORD dwAppID,
721   LPVOID lpData,
722   LPDWORD lpdwDataSize )
723 {
724   LPDPLAYX_LOBBYDATA lpDplData;
725   DWORD              dwRequiredDataSize = 0;
726   HANDLE             hInformOnSettingRead;
727
728   DPLAYX_AquireSemaphore();
729
730   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
731   {
732     DPLAYX_ReleaseSemaphore();
733     return DPERR_NOTLOBBIED;
734   }
735
736   dwRequiredDataSize = DPLAYX_SizeOfLobbyDataW( lpDplData->lpConn );
737
738   /* Do they want to know the required buffer size or is the provided buffer
739    * big enough?
740    */
741   if ( ( lpData == NULL ) ||
742        ( *lpdwDataSize < dwRequiredDataSize )
743      )
744   {
745     DPLAYX_ReleaseSemaphore();
746
747     *lpdwDataSize = DPLAYX_SizeOfLobbyDataW( lpDplData->lpConn );
748
749     return DPERR_BUFFERTOOSMALL;
750   }
751
752   DPLAYX_CopyConnStructW( (LPDPLCONNECTION)lpData, lpDplData->lpConn );
753
754   DPLAYX_ReleaseSemaphore();
755
756   /* They have gotten the information - signal the event if required */
757   if( DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, FALSE ) &&
758       hInformOnSettingRead
759     )
760   {
761     BOOL bSuccess;
762     bSuccess = SetEvent( hInformOnSettingRead );
763     TRACE( "Signalling setting read event %p %s\n",
764              hInformOnSettingRead, bSuccess ? "succeed" : "failed" );
765
766     /* Close out handle */
767     DPLAYX_GetThisLobbyHandles( NULL, NULL, &hInformOnSettingRead, TRUE );
768   }
769
770   return DP_OK;
771 }
772
773 /* Assumption: Enough contiguous space was allocated at dest */
774 void DPLAYX_CopyConnStructW( LPDPLCONNECTION dest, LPDPLCONNECTION src )
775 {
776   BYTE*              lpStartOfFreeSpace;
777
778   CopyMemory( dest, src, sizeof( DPLCONNECTION ) );
779
780   lpStartOfFreeSpace = ( (BYTE*)dest) + sizeof( DPLCONNECTION );
781
782   /* Copy the LPDPSESSIONDESC2 structure if it exists */
783   if( src->lpSessionDesc )
784   {
785     dest->lpSessionDesc = (LPDPSESSIONDESC2)lpStartOfFreeSpace;
786     lpStartOfFreeSpace += sizeof( DPSESSIONDESC2 );
787     CopyMemory( dest->lpSessionDesc, src->lpSessionDesc, sizeof( DPSESSIONDESC2 ) );
788
789     /* Session names may or may not exist */
790     if( src->lpSessionDesc->u1.lpszSessionName )
791     {
792       strcpyW( (LPWSTR)lpStartOfFreeSpace, dest->lpSessionDesc->u1.lpszSessionName );
793       src->lpSessionDesc->u1.lpszSessionName = (LPWSTR)lpStartOfFreeSpace;
794       lpStartOfFreeSpace +=  sizeof(WCHAR) *
795         ( strlenW( (LPWSTR)dest->lpSessionDesc->u1.lpszSessionName ) + 1 );
796     }
797
798     if( src->lpSessionDesc->u2.lpszPassword )
799     {
800       strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpSessionDesc->u2.lpszPassword );
801       dest->lpSessionDesc->u2.lpszPassword = (LPWSTR)lpStartOfFreeSpace;
802       lpStartOfFreeSpace +=  sizeof(WCHAR) *
803         ( strlenW( (LPWSTR)dest->lpSessionDesc->u2.lpszPassword ) + 1 );
804     }
805   }
806
807   /* DPNAME structure is optional */
808   if( src->lpPlayerName )
809   {
810     dest->lpPlayerName = (LPDPNAME)lpStartOfFreeSpace;
811     lpStartOfFreeSpace += sizeof( DPNAME );
812     CopyMemory( dest->lpPlayerName, src->lpPlayerName, sizeof( DPNAME ) );
813
814     if( src->lpPlayerName->u1.lpszShortName )
815     {
816       strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpPlayerName->u1.lpszShortName );
817       dest->lpPlayerName->u1.lpszShortName = (LPWSTR)lpStartOfFreeSpace;
818       lpStartOfFreeSpace +=  sizeof(WCHAR) *
819         ( strlenW( (LPWSTR)dest->lpPlayerName->u1.lpszShortName ) + 1 );
820     }
821
822     if( src->lpPlayerName->u2.lpszLongName )
823     {
824       strcpyW( (LPWSTR)lpStartOfFreeSpace, src->lpPlayerName->u2.lpszLongName );
825       dest->lpPlayerName->u2.lpszLongName = (LPWSTR)lpStartOfFreeSpace;
826       lpStartOfFreeSpace +=  sizeof(WCHAR) *
827         ( strlenW( (LPWSTR)dest->lpPlayerName->u2.lpszLongName ) + 1 );
828     }
829
830   }
831
832   /* Copy address if it exists */
833   if( src->lpAddress )
834   {
835     dest->lpAddress = (LPVOID)lpStartOfFreeSpace;
836     CopyMemory( lpStartOfFreeSpace, src->lpAddress, src->dwAddressSize );
837     /* No need to advance lpStartOfFreeSpace as there is no more "dynamic" data */
838   }
839
840 }
841
842 /* Store the structure into the shared data structre. Ensure that allocs for
843  * variable length strings come from the shared data structure.
844  * FIXME: We need to free information as well
845  */
846 HRESULT DPLAYX_SetConnectionSettingsA
847 ( DWORD dwFlags,
848   DWORD dwAppID,
849   LPDPLCONNECTION lpConn )
850 {
851   LPDPLAYX_LOBBYDATA lpDplData;
852
853   /* Parameter check */
854   if( dwFlags || !lpConn )
855   {
856     ERR("invalid parameters.\n");
857     return DPERR_INVALIDPARAMS;
858   }
859
860   /* Store information */
861   if(  lpConn->dwSize != sizeof(DPLCONNECTION) )
862   {
863     ERR(": old/new DPLCONNECTION type? Size=%08lx vs. expected=%ul bytes\n",
864          lpConn->dwSize, sizeof( DPLCONNECTION ) );
865
866     return DPERR_INVALIDPARAMS;
867   }
868
869   DPLAYX_AquireSemaphore();
870
871   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
872   {
873     DPLAYX_ReleaseSemaphore();
874
875     return DPERR_NOTLOBBIED;
876   }
877
878   if(  (!lpConn->lpSessionDesc ) ||
879        ( lpConn->lpSessionDesc->dwSize != sizeof( DPSESSIONDESC2 ) )
880     )
881   {
882     DPLAYX_ReleaseSemaphore();
883
884     ERR("DPSESSIONDESC passed in? Size=%lu vs. expected=%u bytes\n",
885          lpConn->lpSessionDesc->dwSize, sizeof( DPSESSIONDESC2 ) );
886
887     return DPERR_INVALIDPARAMS;
888   }
889
890   /* Free the existing memory */
891   DPLAYX_PrivHeapFree( lpDplData->lpConn );
892
893   lpDplData->lpConn = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY,
894                                             DPLAYX_SizeOfLobbyDataA( lpConn ) );
895
896   DPLAYX_CopyConnStructA( lpDplData->lpConn, lpConn );
897
898
899   DPLAYX_ReleaseSemaphore();
900
901   /* FIXME: Send a message - I think */
902
903   return DP_OK;
904 }
905
906 /* Store the structure into the shared data structre. Ensure that allocs for
907  * variable length strings come from the shared data structure.
908  * FIXME: We need to free information as well
909  */
910 HRESULT DPLAYX_SetConnectionSettingsW
911 ( DWORD dwFlags,
912   DWORD dwAppID,
913   LPDPLCONNECTION lpConn )
914 {
915   LPDPLAYX_LOBBYDATA lpDplData;
916
917   /* Parameter check */
918   if( dwFlags || !lpConn )
919   {
920     ERR("invalid parameters.\n");
921     return DPERR_INVALIDPARAMS;
922   }
923
924   /* Store information */
925   if(  lpConn->dwSize != sizeof(DPLCONNECTION) )
926   {
927     ERR(": old/new DPLCONNECTION type? Size=%lu vs. expected=%u bytes\n",
928          lpConn->dwSize, sizeof( DPLCONNECTION ) );
929
930     return DPERR_INVALIDPARAMS;
931   }
932
933   DPLAYX_AquireSemaphore();
934
935   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
936   {
937     DPLAYX_ReleaseSemaphore();
938
939     return DPERR_NOTLOBBIED;
940   }
941
942   /* Free the existing memory */
943   DPLAYX_PrivHeapFree( lpDplData->lpConn );
944
945   lpDplData->lpConn = DPLAYX_PrivHeapAlloc( HEAP_ZERO_MEMORY,
946                                             DPLAYX_SizeOfLobbyDataW( lpConn ) );
947
948   DPLAYX_CopyConnStructW( lpDplData->lpConn, lpConn );
949
950
951   DPLAYX_ReleaseSemaphore();
952
953   /* FIXME: Send a message - I think */
954
955   return DP_OK;
956 }
957
958 DWORD DPLAYX_SizeOfLobbyDataA( LPDPLCONNECTION lpConn )
959 {
960   DWORD dwTotalSize = sizeof( DPLCONNECTION );
961
962   /* Just a safety check */
963   if( lpConn == NULL )
964   {
965     ERR( "lpConn is NULL\n" );
966     return 0;
967   }
968
969   if( lpConn->lpSessionDesc != NULL )
970   {
971     dwTotalSize += sizeof( DPSESSIONDESC2 );
972
973     if( lpConn->lpSessionDesc->u1.lpszSessionNameA )
974     {
975       dwTotalSize += strlen( lpConn->lpSessionDesc->u1.lpszSessionNameA ) + 1;
976     }
977
978     if( lpConn->lpSessionDesc->u2.lpszPasswordA )
979     {
980       dwTotalSize += strlen( lpConn->lpSessionDesc->u2.lpszPasswordA ) + 1;
981     }
982   }
983
984   if( lpConn->lpPlayerName != NULL )
985   {
986     dwTotalSize += sizeof( DPNAME );
987
988     if( lpConn->lpPlayerName->u1.lpszShortNameA )
989     {
990       dwTotalSize += strlen( lpConn->lpPlayerName->u1.lpszShortNameA ) + 1;
991     }
992
993     if( lpConn->lpPlayerName->u2.lpszLongNameA )
994     {
995       dwTotalSize += strlen( lpConn->lpPlayerName->u2.lpszLongNameA ) + 1;
996     }
997
998   }
999
1000   dwTotalSize += lpConn->dwAddressSize;
1001
1002   return dwTotalSize;
1003 }
1004
1005 DWORD DPLAYX_SizeOfLobbyDataW( LPDPLCONNECTION lpConn )
1006 {
1007   DWORD dwTotalSize = sizeof( DPLCONNECTION );
1008
1009   /* Just a safety check */
1010   if( lpConn == NULL )
1011   {
1012     ERR( "lpConn is NULL\n" );
1013     return 0;
1014   }
1015
1016   if( lpConn->lpSessionDesc != NULL )
1017   {
1018     dwTotalSize += sizeof( DPSESSIONDESC2 );
1019
1020     if( lpConn->lpSessionDesc->u1.lpszSessionName )
1021     {
1022       dwTotalSize += sizeof( WCHAR ) *
1023         ( strlenW( lpConn->lpSessionDesc->u1.lpszSessionName ) + 1 );
1024     }
1025
1026     if( lpConn->lpSessionDesc->u2.lpszPassword )
1027     {
1028       dwTotalSize += sizeof( WCHAR ) *
1029         ( strlenW( lpConn->lpSessionDesc->u2.lpszPassword ) + 1 );
1030     }
1031   }
1032
1033   if( lpConn->lpPlayerName != NULL )
1034   {
1035     dwTotalSize += sizeof( DPNAME );
1036
1037     if( lpConn->lpPlayerName->u1.lpszShortName )
1038     {
1039       dwTotalSize += sizeof( WCHAR ) *
1040         ( strlenW( lpConn->lpPlayerName->u1.lpszShortName ) + 1 );
1041     }
1042
1043     if( lpConn->lpPlayerName->u2.lpszLongName )
1044     {
1045       dwTotalSize += sizeof( WCHAR ) *
1046         ( strlenW( lpConn->lpPlayerName->u2.lpszLongName ) + 1 );
1047     }
1048
1049   }
1050
1051   dwTotalSize += lpConn->dwAddressSize;
1052
1053   return dwTotalSize;
1054 }
1055
1056
1057
1058 LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateSessionDesc2A( LPCDPSESSIONDESC2 lpSessionSrc )
1059 {
1060    LPDPSESSIONDESC2 lpSessionDest =
1061      (LPDPSESSIONDESC2)HeapAlloc( GetProcessHeap(),
1062                                   HEAP_ZERO_MEMORY, sizeof( *lpSessionSrc ) );
1063    DPLAYX_CopyIntoSessionDesc2A( lpSessionDest, lpSessionSrc );
1064
1065    return lpSessionDest;
1066 }
1067
1068 /* Copy an ANSI session desc structure to the given buffer */
1069 BOOL DPLAYX_CopyIntoSessionDesc2A( LPDPSESSIONDESC2  lpSessionDest,
1070                                    LPCDPSESSIONDESC2 lpSessionSrc )
1071 {
1072   CopyMemory( lpSessionDest, lpSessionSrc, sizeof( *lpSessionSrc ) );
1073
1074   if( lpSessionSrc->u1.lpszSessionNameA )
1075   {
1076       if ((lpSessionDest->u1.lpszSessionNameA = HeapAlloc( GetProcessHeap(), 0,
1077                                                              strlen(lpSessionSrc->u1.lpszSessionNameA)+1 )))
1078           strcpy( lpSessionDest->u1.lpszSessionNameA, lpSessionSrc->u1.lpszSessionNameA );
1079   }
1080   if( lpSessionSrc->u2.lpszPasswordA )
1081   {
1082       if ((lpSessionDest->u2.lpszPasswordA = HeapAlloc( GetProcessHeap(), 0,
1083                                                           strlen(lpSessionSrc->u2.lpszPasswordA)+1 )))
1084           strcpy( lpSessionDest->u2.lpszPasswordA, lpSessionSrc->u2.lpszPasswordA );
1085   }
1086
1087   return TRUE;
1088 }
1089
1090 /* Start the index at 0. index will be updated to equal that which should
1091    be passed back into this function for the next element */
1092 LPDPSESSIONDESC2 DPLAYX_CopyAndAllocateLocalSession( UINT* index )
1093 {
1094   for( ; (*index) < numSupportedSessions; (*index)++ )
1095   {
1096     if( sessionData[(*index)].dwSize != 0 )
1097     {
1098       return DPLAYX_CopyAndAllocateSessionDesc2A( &sessionData[(*index)++] );
1099     }
1100   }
1101
1102   /* No more sessions */
1103   return NULL;
1104 }
1105
1106 /* Start the index at 0. index will be updated to equal that which should
1107    be passed back into this function for the next element */
1108 BOOL DPLAYX_CopyLocalSession( UINT* index, LPDPSESSIONDESC2 lpsd )
1109 {
1110   for( ; (*index) < numSupportedSessions; (*index)++ )
1111   {
1112     if( sessionData[(*index)].dwSize != 0 )
1113     {
1114       return DPLAYX_CopyIntoSessionDesc2A( lpsd, &sessionData[(*index)++] );
1115     }
1116   }
1117
1118   /* No more sessions */
1119   return FALSE;
1120 }
1121
1122 void DPLAYX_SetLocalSession( LPCDPSESSIONDESC2 lpsd )
1123 {
1124   UINT i;
1125
1126   /* FIXME: Is this an error if it exists already? */
1127
1128   /* Crude/wrong implementation for now. Just always add to first empty spot */
1129   for( i=0; i < numSupportedSessions; i++ )
1130   {
1131     /* Is this one empty? */
1132     if( sessionData[i].dwSize == 0 )
1133     {
1134       DPLAYX_CopyIntoSessionDesc2A( &sessionData[i], lpsd );
1135       break;
1136     }
1137   }
1138
1139 }
1140
1141 BOOL DPLAYX_WaitForConnectionSettings( BOOL bWait )
1142 {
1143   LPDPLAYX_LOBBYDATA lpLobbyData;
1144
1145   DPLAYX_AquireSemaphore();
1146
1147   if( !DPLAYX_IsAppIdLobbied( 0, &lpLobbyData ) )
1148   {
1149     DPLAYX_ReleaseSemaphore();
1150     return FALSE;
1151   }
1152
1153   lpLobbyData->bWaitForConnectionSettings = bWait;
1154
1155   DPLAYX_ReleaseSemaphore();
1156
1157   return TRUE;
1158 }
1159
1160 BOOL DPLAYX_AnyLobbiesWaitingForConnSettings(void)
1161 {
1162   UINT i;
1163   BOOL bFound = FALSE;
1164
1165   DPLAYX_AquireSemaphore();
1166
1167   for( i=0; i < numSupportedLobbies; i++ )
1168   {
1169     if( ( lobbyData[ i ].dwAppID != 0 ) &&            /* lobby initialized */
1170         ( lobbyData[ i ].bWaitForConnectionSettings ) /* Waiting */
1171       )
1172     {
1173       bFound = TRUE;
1174       break;
1175     }
1176   }
1177
1178   DPLAYX_ReleaseSemaphore();
1179
1180   return bFound;
1181 }
1182
1183 BOOL DPLAYX_SetLobbyMsgThreadId( DWORD dwAppId, DWORD dwThreadId )
1184 {
1185   LPDPLAYX_LOBBYDATA lpLobbyData;
1186
1187   DPLAYX_AquireSemaphore();
1188
1189   if( !DPLAYX_IsAppIdLobbied( dwAppId, &lpLobbyData ) )
1190   {
1191     DPLAYX_ReleaseSemaphore();
1192     return FALSE;
1193   }
1194
1195   lpLobbyData->dwLobbyMsgThreadId = dwThreadId;
1196
1197   DPLAYX_ReleaseSemaphore();
1198
1199   return TRUE;
1200 }
1201
1202 /* NOTE: This is potentially not thread safe. You are not guaranteed to end up
1203          with the correct string printed in the case where the HRESULT is not
1204          known. You'll just get the last hr passed in printed. This can change
1205          over time if this method is used alot :) */
1206 LPCSTR DPLAYX_HresultToString(HRESULT hr)
1207 {
1208   static char szTempStr[12];
1209
1210   switch (hr)
1211   {
1212     case DP_OK:
1213       return "DP_OK";
1214     case DPERR_ALREADYINITIALIZED:
1215       return "DPERR_ALREADYINITIALIZED";
1216     case DPERR_ACCESSDENIED:
1217       return "DPERR_ACCESSDENIED";
1218     case DPERR_ACTIVEPLAYERS:
1219       return "DPERR_ACTIVEPLAYERS";
1220     case DPERR_BUFFERTOOSMALL:
1221       return "DPERR_BUFFERTOOSMALL";
1222     case DPERR_CANTADDPLAYER:
1223       return "DPERR_CANTADDPLAYER";
1224     case DPERR_CANTCREATEGROUP:
1225       return "DPERR_CANTCREATEGROUP";
1226     case DPERR_CANTCREATEPLAYER:
1227       return "DPERR_CANTCREATEPLAYER";
1228     case DPERR_CANTCREATESESSION:
1229       return "DPERR_CANTCREATESESSION";
1230     case DPERR_CAPSNOTAVAILABLEYET:
1231       return "DPERR_CAPSNOTAVAILABLEYET";
1232     case DPERR_EXCEPTION:
1233       return "DPERR_EXCEPTION";
1234     case DPERR_GENERIC:
1235       return "DPERR_GENERIC";
1236     case DPERR_INVALIDFLAGS:
1237       return "DPERR_INVALIDFLAGS";
1238     case DPERR_INVALIDOBJECT:
1239       return "DPERR_INVALIDOBJECT";
1240     case DPERR_INVALIDPARAMS:
1241       return "DPERR_INVALIDPARAMS";
1242     case DPERR_INVALIDPLAYER:
1243       return "DPERR_INVALIDPLAYER";
1244     case DPERR_INVALIDGROUP:
1245       return "DPERR_INVALIDGROUP";
1246     case DPERR_NOCAPS:
1247       return "DPERR_NOCAPS";
1248     case DPERR_NOCONNECTION:
1249       return "DPERR_NOCONNECTION";
1250     case DPERR_OUTOFMEMORY:
1251       return "DPERR_OUTOFMEMORY";
1252     case DPERR_NOMESSAGES:
1253       return "DPERR_NOMESSAGES";
1254     case DPERR_NONAMESERVERFOUND:
1255       return "DPERR_NONAMESERVERFOUND";
1256     case DPERR_NOPLAYERS:
1257       return "DPERR_NOPLAYERS";
1258     case DPERR_NOSESSIONS:
1259       return "DPERR_NOSESSIONS";
1260     case DPERR_PENDING:
1261       return "DPERR_PENDING";
1262     case DPERR_SENDTOOBIG:
1263       return "DPERR_SENDTOOBIG";
1264     case DPERR_TIMEOUT:
1265       return "DPERR_TIMEOUT";
1266     case DPERR_UNAVAILABLE:
1267       return "DPERR_UNAVAILABLE";
1268     case DPERR_UNSUPPORTED:
1269       return "DPERR_UNSUPPORTED";
1270     case DPERR_BUSY:
1271       return "DPERR_BUSY";
1272     case DPERR_USERCANCEL:
1273       return "DPERR_USERCANCEL";
1274     case DPERR_NOINTERFACE:
1275       return "DPERR_NOINTERFACE";
1276     case DPERR_CANNOTCREATESERVER:
1277       return "DPERR_CANNOTCREATESERVER";
1278     case DPERR_PLAYERLOST:
1279       return "DPERR_PLAYERLOST";
1280     case DPERR_SESSIONLOST:
1281       return "DPERR_SESSIONLOST";
1282     case DPERR_UNINITIALIZED:
1283       return "DPERR_UNINITIALIZED";
1284     case DPERR_NONEWPLAYERS:
1285       return "DPERR_NONEWPLAYERS";
1286     case DPERR_INVALIDPASSWORD:
1287       return "DPERR_INVALIDPASSWORD";
1288     case DPERR_CONNECTING:
1289       return "DPERR_CONNECTING";
1290     case DPERR_CONNECTIONLOST:
1291       return "DPERR_CONNECTIONLOST";
1292     case DPERR_UNKNOWNMESSAGE:
1293       return "DPERR_UNKNOWNMESSAGE";
1294     case DPERR_CANCELFAILED:
1295       return "DPERR_CANCELFAILED";
1296     case DPERR_INVALIDPRIORITY:
1297       return "DPERR_INVALIDPRIORITY";
1298     case DPERR_NOTHANDLED:
1299       return "DPERR_NOTHANDLED";
1300     case DPERR_CANCELLED:
1301       return "DPERR_CANCELLED";
1302     case DPERR_ABORTED:
1303       return "DPERR_ABORTED";
1304     case DPERR_BUFFERTOOLARGE:
1305       return "DPERR_BUFFERTOOLARGE";
1306     case DPERR_CANTCREATEPROCESS:
1307       return "DPERR_CANTCREATEPROCESS";
1308     case DPERR_APPNOTSTARTED:
1309       return "DPERR_APPNOTSTARTED";
1310     case DPERR_INVALIDINTERFACE:
1311       return "DPERR_INVALIDINTERFACE";
1312     case DPERR_NOSERVICEPROVIDER:
1313       return "DPERR_NOSERVICEPROVIDER";
1314     case DPERR_UNKNOWNAPPLICATION:
1315       return "DPERR_UNKNOWNAPPLICATION";
1316     case DPERR_NOTLOBBIED:
1317       return "DPERR_NOTLOBBIED";
1318     case DPERR_SERVICEPROVIDERLOADED:
1319       return "DPERR_SERVICEPROVIDERLOADED";
1320     case DPERR_ALREADYREGISTERED:
1321       return "DPERR_ALREADYREGISTERED";
1322     case DPERR_NOTREGISTERED:
1323       return "DPERR_NOTREGISTERED";
1324     case DPERR_AUTHENTICATIONFAILED:
1325       return "DPERR_AUTHENTICATIONFAILED";
1326     case DPERR_CANTLOADSSPI:
1327       return "DPERR_CANTLOADSSPI";
1328     case DPERR_ENCRYPTIONFAILED:
1329       return "DPERR_ENCRYPTIONFAILED";
1330     case DPERR_SIGNFAILED:
1331       return "DPERR_SIGNFAILED";
1332     case DPERR_CANTLOADSECURITYPACKAGE:
1333       return "DPERR_CANTLOADSECURITYPACKAGE";
1334     case DPERR_ENCRYPTIONNOTSUPPORTED:
1335       return "DPERR_ENCRYPTIONNOTSUPPORTED";
1336     case DPERR_CANTLOADCAPI:
1337       return "DPERR_CANTLOADCAPI";
1338     case DPERR_NOTLOGGEDIN:
1339       return "DPERR_NOTLOGGEDIN";
1340     case DPERR_LOGONDENIED:
1341       return "DPERR_LOGONDENIED";
1342     default:
1343       /* For errors not in the list, return HRESULT as a string
1344          This part is not thread safe */
1345       WARN( "Unknown error 0x%08lx\n", hr );
1346       wsprintfA( szTempStr, "0x%08lx", hr );
1347       return szTempStr;
1348   }
1349 }