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