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