Optimized debugging API to reduce code size.
[wine] / dlls / dplayx / dplayx_global.c
1 /* dplayx.dll global data implementation.
2  *
3  * Copyright 1999 - 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 <stdio.h>
14 #include "debugtools.h"
15 #include "winbase.h"
16 #include "winerror.h"
17 #include "heap.h"  /* Really shouldn't be using those HEAP_strdupA interfaces should I? */
18
19 #include "dplayx_global.h"
20
21 DEFAULT_DEBUG_CHANNEL(dplay);
22
23 /* FIXME: Need to do all that fun other dll referencing type of stuff */
24 /* FIXME: Need to allocate a giant static area */
25
26 /* Static data for all processes */
27 static LPSTR lpszDplayxSemaName = "WINE_DPLAYX_SM";
28 static HANDLE hDplayxSema;
29
30
31
32 #define DPLAYX_AquireSemaphore()  TRACE( "Waiting for DPLAYX sema\n" ); \
33                                   WaitForSingleObject( hDplayxSema, INFINITE ); TRACE( "Through wait\n" )
34 #define DPLAYX_ReleaseSemaphore() ReleaseSemaphore( hDplayxSema, 1, NULL ); \
35                                   TRACE( "DPLAYX Sema released\n" ); /* FIXME: Is this correct? */
36
37
38 /* HACK for simple global data right now */ 
39 enum { numSupportedLobbies = 32 };
40 typedef struct tagDirectPlayLobbyData
41 {
42   DWORD           dwConnFlags;
43   DPSESSIONDESC2  sessionDesc;
44   DPNAME          playerName;
45   GUID            guidSP;
46   LPVOID          lpAddress;
47   DWORD           dwAddressSize;
48   DWORD           dwAppID;
49   HANDLE          hReceiveEvent;
50   DWORD           dwAppLaunchedFromID;
51 } DirectPlayLobbyData, *lpDirectPlayLobbyData;
52
53 static DirectPlayLobbyData lobbyData[ numSupportedLobbies ];
54
55 /* Function prototypes */
56 BOOL  DPLAYX_IsAppIdLobbied( DWORD dwAppId, lpDirectPlayLobbyData* dplData );
57 void DPLAYX_InitializeLobbyDataEntry( lpDirectPlayLobbyData lpData );
58
59
60
61
62
63 /*************************************************************************** 
64  * Called to initialize the global data. This will only be used on the 
65  * loading of the dll 
66  ***************************************************************************/ 
67 void DPLAYX_ConstructData(void)
68 {
69   UINT i;
70
71   TRACE( "DPLAYX dll loaded - construct called\n" );
72
73   /* Create a semahopre to block access to DPLAYX global data structs 
74      It starts unblocked, and allows up to 65000 users blocked on it. Seems reasonable
75      for the time being */
76   hDplayxSema = CreateSemaphoreA( NULL, 1, 65000, lpszDplayxSemaName ); 
77
78   if( !hDplayxSema )
79   {
80     /* Really don't have any choice but to continue... */
81     ERR( "Semaphore creation error 0x%08lx\n", GetLastError() );
82   }
83
84   /* Set all lobbies to be "empty" */ 
85   for( i=0; i < numSupportedLobbies; i++ )
86   {
87     DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] );
88   }
89
90 }
91
92 /*************************************************************************** 
93  * Called to destroy all global data. This will only be used on the 
94  * unloading of the dll 
95  ***************************************************************************/ 
96 void DPLAYX_DestructData(void)
97 {
98   TRACE( "DPLAYX dll unloaded - destruct called\n" );
99
100   /* delete the semaphore */
101   CloseHandle( hDplayxSema );
102 }
103
104
105 void DPLAYX_InitializeLobbyDataEntry( lpDirectPlayLobbyData lpData )
106 {
107   ZeroMemory( lpData, sizeof( *lpData ) );
108
109   /* Set the handle to a better invalid value */
110   lpData->hReceiveEvent = INVALID_HANDLE_VALUE;
111 }
112
113 /* NOTE: This must be called with the semaphore aquired. 
114  * TRUE/FALSE with a pointer to it's data returned. Pointer data is
115  * is only valid if TRUE is returned.
116  */
117 BOOL  DPLAYX_IsAppIdLobbied( DWORD dwAppID, lpDirectPlayLobbyData* lplpDplData )
118 {
119   INT i;
120
121   *lplpDplData = NULL;
122
123   if( dwAppID == 0 )
124   {
125     dwAppID = GetCurrentProcessId();
126     TRACE( "Translated dwAppID == 0 into 0x%08lx\n", dwAppID );
127   }
128
129   for( i=0; i < numSupportedLobbies; i++ )
130   {
131     if( lobbyData[ i ].dwAppID == dwAppID )
132     {
133       /* This process is lobbied */ 
134       *lplpDplData = &lobbyData[ i ];
135       return TRUE;
136     }
137   }
138
139   return FALSE;
140 }
141
142 /* Reserve a spot for the new appliction. TRUE means success and FALSE failure.  */
143 BOOL DPLAYX_CreateLobbyApplication( DWORD dwAppID, HANDLE hReceiveEvent )
144 {
145   UINT i;
146
147   /* 0 is the marker for unused application data slots */
148   if( dwAppID == 0 )
149   {
150     return FALSE;
151   } 
152
153   DPLAYX_AquireSemaphore();
154
155   /* Find an empty space in the list and insert the data */
156   for( i=0; i < numSupportedLobbies; i++ )
157   {
158     if( lobbyData[ i ].dwAppID == 0 )
159     {
160       /* This process is now lobbied */
161       lobbyData[ i ].dwAppID             = dwAppID;
162       lobbyData[ i ].hReceiveEvent       = hReceiveEvent;
163       lobbyData[ i ].dwAppLaunchedFromID = GetCurrentProcessId();
164
165       DPLAYX_ReleaseSemaphore();
166       return TRUE;
167     }
168   }
169
170   DPLAYX_ReleaseSemaphore();
171   return FALSE;
172 }
173
174 /* I'm not sure when I'm going to need this, but here it is */
175 BOOL DPLAYX_DestroyLobbyApplication( DWORD dwAppID ) 
176 {
177   UINT i;
178
179   DPLAYX_AquireSemaphore();
180
181   /* Find an empty space in the list and insert the data */
182   for( i=0; i < numSupportedLobbies; i++ )
183   {
184     if( lobbyData[ i ].dwAppID == dwAppID )
185     {
186       /* Mark this entry unused */
187       DPLAYX_InitializeLobbyDataEntry( &lobbyData[ i ] );
188
189       DPLAYX_ReleaseSemaphore();
190       return TRUE;
191     }
192   }
193
194   DPLAYX_ReleaseSemaphore();
195   ERR( "Unable to find global entry for application\n" );
196   return FALSE;
197 }
198
199 HRESULT DPLAYX_GetConnectionSettingsA
200 ( DWORD dwAppID,
201   LPVOID lpData,
202   LPDWORD lpdwDataSize )
203 {
204   lpDirectPlayLobbyData lpDplData;
205   LPDPLCONNECTION lpDplConnection;
206
207   /* Verify buffer size */
208   if ( ( lpData == NULL ) ||
209        ( *lpdwDataSize < sizeof( DPLCONNECTION ) )
210      )
211   {
212     *lpdwDataSize = sizeof( DPLCONNECTION );
213
214     return DPERR_BUFFERTOOSMALL;
215   }
216
217   DPLAYX_AquireSemaphore();
218
219   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
220   {
221     DPLAYX_ReleaseSemaphore();
222     return DPERR_NOTLOBBIED;
223   }
224
225   /* Copy the information */
226   lpDplConnection = (LPDPLCONNECTION)lpData;
227
228   /* Copy everything we've got into here */
229   /* Need to actually store the stuff here. Check if we've already allocated each field first. */
230   lpDplConnection->dwSize = sizeof( DPLCONNECTION );
231   lpDplConnection->dwFlags = lpDplData->dwConnFlags;
232
233   /* Copy LPDPSESSIONDESC2 struct */
234   lpDplConnection->lpSessionDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->sessionDesc ) );
235   memcpy( lpDplConnection->lpSessionDesc, &lpDplData->sessionDesc, sizeof( lpDplData->sessionDesc ) );
236
237   if( lpDplData->sessionDesc.sess.lpszSessionNameA )
238   {
239     lpDplConnection->lpSessionDesc->sess.lpszSessionNameA =
240       HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.sess.lpszSessionNameA );
241   }
242
243   if( lpDplData->sessionDesc.pass.lpszPasswordA )
244   {
245     lpDplConnection->lpSessionDesc->pass.lpszPasswordA =
246       HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.pass.lpszPasswordA );
247   }
248
249   lpDplConnection->lpSessionDesc->dwReserved1 = lpDplData->sessionDesc.dwReserved1;
250   lpDplConnection->lpSessionDesc->dwReserved2 = lpDplData->sessionDesc.dwReserved2;
251
252   /* Copy DPNAME struct - seems to be optional - check for existance first */
253   lpDplConnection->lpPlayerName = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->playerName ) );
254   memcpy( lpDplConnection->lpPlayerName, &(lpDplData->playerName), sizeof( lpDplData->playerName ) );
255
256   if( lpDplData->playerName.psn.lpszShortNameA )
257   {
258     lpDplConnection->lpPlayerName->psn.lpszShortNameA =
259       HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.psn.lpszShortNameA );
260   }
261
262   if( lpDplData->playerName.pln.lpszLongNameA )
263   {
264     lpDplConnection->lpPlayerName->pln.lpszLongNameA =
265       HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.pln.lpszLongNameA );
266   }
267
268   memcpy( &lpDplConnection->guidSP, &lpDplData->guidSP, sizeof( lpDplData->guidSP ) );
269
270   lpDplConnection->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->dwAddressSize );
271   memcpy( lpDplConnection->lpAddress, lpDplData->lpAddress, lpDplData->dwAddressSize );
272
273   lpDplConnection->dwAddressSize = lpDplData->dwAddressSize;
274
275   /* FIXME: Send a message - or only the first time? */
276
277   DPLAYX_ReleaseSemaphore();
278
279   return DP_OK;
280 }
281
282 HRESULT DPLAYX_GetConnectionSettingsW
283 ( DWORD dwAppID,
284   LPVOID lpData,
285   LPDWORD lpdwDataSize )
286 {
287   lpDirectPlayLobbyData lpDplData;
288   LPDPLCONNECTION lpDplConnection;
289
290   /* Verify buffer size */
291   if ( ( lpData == NULL ) ||
292        ( *lpdwDataSize < sizeof( DPLCONNECTION ) )
293      )
294   {
295     *lpdwDataSize = sizeof( DPLCONNECTION );
296
297     return DPERR_BUFFERTOOSMALL;
298   }
299
300   DPLAYX_AquireSemaphore();
301
302   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
303   {
304     DPLAYX_ReleaseSemaphore();
305     return DPERR_NOTLOBBIED;
306   }
307
308   /* Copy the information */
309   lpDplConnection = (LPDPLCONNECTION)lpData;
310
311   /* Copy everything we've got into here */
312   /* Need to actually store the stuff here. Check if we've already allocated each field first. */
313   lpDplConnection->dwSize = sizeof( DPLCONNECTION );
314   lpDplConnection->dwFlags = lpDplData->dwConnFlags;
315
316   /* Copy LPDPSESSIONDESC2 struct */
317   lpDplConnection->lpSessionDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->sessionDesc ) );
318   memcpy( lpDplConnection->lpSessionDesc, &lpDplData->sessionDesc, sizeof( lpDplData->sessionDesc ) );
319
320   if( lpDplData->sessionDesc.sess.lpszSessionName )
321   {
322     lpDplConnection->lpSessionDesc->sess.lpszSessionName =
323       HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.sess.lpszSessionName );
324   }
325
326   if( lpDplData->sessionDesc.pass.lpszPassword )
327   {
328     lpDplConnection->lpSessionDesc->pass.lpszPassword =
329       HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.pass.lpszPassword );
330   }
331
332   lpDplConnection->lpSessionDesc->dwReserved1 = lpDplData->sessionDesc.dwReserved1;
333   lpDplConnection->lpSessionDesc->dwReserved2 = lpDplData->sessionDesc.dwReserved2;
334
335   /* Copy DPNAME struct - seems to be optional - check for existance first */
336   lpDplConnection->lpPlayerName = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->playerName ) );
337   memcpy( lpDplConnection->lpPlayerName, &(lpDplData->playerName), sizeof( lpDplData->playerName ) );
338
339   if( lpDplData->playerName.psn.lpszShortName )
340   {
341     lpDplConnection->lpPlayerName->psn.lpszShortName =
342       HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.psn.lpszShortName );
343   }
344
345   if( lpDplData->playerName.pln.lpszLongName )
346   {
347     lpDplConnection->lpPlayerName->pln.lpszLongName =
348       HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.pln.lpszLongName );
349   }
350
351   memcpy( &lpDplConnection->guidSP, &lpDplData->guidSP, sizeof( lpDplData->guidSP ) );
352
353   lpDplConnection->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->dwAddressSize );
354   memcpy( lpDplConnection->lpAddress, lpDplData->lpAddress, lpDplData->dwAddressSize );
355
356   lpDplConnection->dwAddressSize = lpDplData->dwAddressSize;
357
358   /* FIXME: Send a message - or only the first time? */
359
360   DPLAYX_ReleaseSemaphore();
361
362   return DP_OK;
363 }
364
365
366 HRESULT DPLAYX_SetConnectionSettingsA
367 ( DWORD dwFlags,
368   DWORD dwAppID,
369   LPDPLCONNECTION lpConn )
370 {
371   lpDirectPlayLobbyData lpDplData;
372
373   /* Paramater check */
374   if( dwFlags || !lpConn )
375   {
376     ERR("invalid parameters.\n");
377     return DPERR_INVALIDPARAMS;
378   }
379
380   /* Store information */
381   if(  lpConn->dwSize != sizeof(DPLCONNECTION) )
382   {
383     ERR(": old/new DPLCONNECTION type? Size=%08lx vs. expected=%ul bytes\n",
384          lpConn->dwSize, sizeof( DPLCONNECTION ) );
385
386     return DPERR_INVALIDPARAMS;
387   }
388
389   if( dwAppID == 0 )
390   {
391     dwAppID = GetCurrentProcessId();
392   }
393
394   DPLAYX_AquireSemaphore();
395
396   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
397   {
398     /* FIXME: Create a new entry for this dwAppID? */
399     DPLAYX_ReleaseSemaphore();
400
401     return DPERR_GENERIC;
402   }
403
404   /* Store information */
405   if(  lpConn->dwSize != sizeof(DPLCONNECTION) )
406   {
407     DPLAYX_ReleaseSemaphore();
408
409     ERR(": old/new DPLCONNECTION type? Size=%lu vs. expected=%u bytes\n",
410          lpConn->dwSize, sizeof( DPLCONNECTION ) );
411
412     return DPERR_INVALIDPARAMS;
413   }
414
415   /* Need to investigate the lpConn->lpSessionDesc to figure out
416    * what type of session we need to join/create.
417    */
418   if(  (!lpConn->lpSessionDesc ) ||
419        ( lpConn->lpSessionDesc->dwSize != sizeof( DPSESSIONDESC2 ) )
420     )
421   {
422     DPLAYX_ReleaseSemaphore();
423
424     ERR("DPSESSIONDESC passed in? Size=%lu vs. expected=%u bytes\n",
425          lpConn->lpSessionDesc->dwSize, sizeof( DPSESSIONDESC2 ) );
426
427     return DPERR_INVALIDPARAMS;
428   }
429
430   /* FIXME: How do I store this stuff so that it can be read by all processes? Static area? What about strings? Ewww...large global shared */ 
431
432   /* Need to actually store the stuff here. Check if we've already allocated each field first. */
433   lpDplData->dwConnFlags = lpConn->dwFlags;
434
435   /* Copy LPDPSESSIONDESC2 struct - this is required */
436   memcpy( &lpDplData->sessionDesc, lpConn->lpSessionDesc, sizeof( *(lpConn->lpSessionDesc) ) );
437
438   /* FIXME: Can this just be shorted? Does it handle the NULL case correctly? */
439   if( lpConn->lpSessionDesc->sess.lpszSessionNameA )
440     lpDplData->sessionDesc.sess.lpszSessionNameA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->sess.lpszSessionNameA );
441   else
442     lpDplData->sessionDesc.sess.lpszSessionNameA = NULL;
443
444   if( lpConn->lpSessionDesc->pass.lpszPasswordA )
445     lpDplData->sessionDesc.pass.lpszPasswordA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->pass.lpszPasswordA );
446   else
447     lpDplData->sessionDesc.pass.lpszPasswordA = NULL;
448
449   lpDplData->sessionDesc.dwReserved1 = lpConn->lpSessionDesc->dwReserved1;
450   lpDplData->sessionDesc.dwReserved2 = lpConn->lpSessionDesc->dwReserved2;
451
452   /* Copy DPNAME struct - seems to be optional - check for existance first */
453   if( lpConn->lpPlayerName )
454   {
455      memcpy( &lpDplData->playerName, lpConn->lpPlayerName, sizeof( *lpConn->lpPlayerName ) );
456
457      if( lpConn->lpPlayerName->psn.lpszShortNameA )
458        lpDplData->playerName.psn.lpszShortNameA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->psn.lpszShortNameA );
459
460      if( lpConn->lpPlayerName->pln.lpszLongNameA )
461        lpDplData->playerName.pln.lpszLongNameA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->pln.lpszLongNameA );
462
463   }
464
465   memcpy( &lpDplData->guidSP, &lpConn->guidSP, sizeof( lpConn->guidSP ) );
466
467   lpDplData->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->dwAddressSize );
468   memcpy( lpDplData->lpAddress, lpConn->lpAddress, lpConn->dwAddressSize );
469
470   lpDplData->dwAddressSize = lpConn->dwAddressSize;
471
472   /* FIXME: Send a message - I think */
473
474   DPLAYX_ReleaseSemaphore();
475
476   return DP_OK;
477 }
478
479 HRESULT DPLAYX_SetConnectionSettingsW
480 ( DWORD dwFlags,
481   DWORD dwAppID,
482   LPDPLCONNECTION lpConn )
483 {
484   lpDirectPlayLobbyData lpDplData;
485
486   /* Paramater check */
487   if( dwFlags || !lpConn )
488   {
489     ERR("invalid parameters.\n");
490     return DPERR_INVALIDPARAMS;
491   }
492
493   /* Store information */
494   if(  lpConn->dwSize != sizeof(DPLCONNECTION) )
495   {
496     ERR(": old/new DPLCONNECTION type? Size=%lu vs. expected=%u bytes\n",
497          lpConn->dwSize, sizeof( DPLCONNECTION ) );
498
499     return DPERR_INVALIDPARAMS;
500   }
501
502   if( dwAppID == 0 )
503   {
504     dwAppID = GetCurrentProcessId();
505   }
506
507   DPLAYX_AquireSemaphore();
508
509   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
510   {
511     DPLAYX_ReleaseSemaphore();
512     return DPERR_NOTLOBBIED;
513   }
514
515   /* Need to investigate the lpConn->lpSessionDesc to figure out
516    * what type of session we need to join/create.
517    */
518   if(  (!lpConn->lpSessionDesc ) ||
519        ( lpConn->lpSessionDesc->dwSize != sizeof( DPSESSIONDESC2 ) )
520     )
521   {
522     DPLAYX_ReleaseSemaphore();
523
524     ERR("DPSESSIONDESC passed in? Size=%lu vs. expected=%u bytes\n",
525          lpConn->lpSessionDesc->dwSize, sizeof( DPSESSIONDESC2 ) );
526
527     return DPERR_INVALIDPARAMS;
528   }
529
530   /* FIXME: How do I store this stuff so that it can be read by all processes? Static area? What about strings? Ewww...large global shared */ 
531
532   /* Need to actually store the stuff here. Check if we've already allocated each field first. */
533   lpDplData->dwConnFlags = lpConn->dwFlags;
534
535   /* Copy LPDPSESSIONDESC2 struct - this is required */
536   memcpy( &lpDplData->sessionDesc, lpConn->lpSessionDesc, sizeof( *(lpConn->lpSessionDesc) ) );
537
538   /* FIXME: Can this just be shorted? Does it handle the NULL case correctly? */
539   if( lpConn->lpSessionDesc->sess.lpszSessionName )
540     lpDplData->sessionDesc.sess.lpszSessionName = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->sess.lpszSessionName );
541   else
542     lpDplData->sessionDesc.sess.lpszSessionName = NULL;
543
544   if( lpConn->lpSessionDesc->pass.lpszPassword )
545     lpDplData->sessionDesc.pass.lpszPassword = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->pass.lpszPassword );
546   else
547     lpDplData->sessionDesc.pass.lpszPassword = NULL;
548
549   lpDplData->sessionDesc.dwReserved1 = lpConn->lpSessionDesc->dwReserved1;
550   lpDplData->sessionDesc.dwReserved2 = lpConn->lpSessionDesc->dwReserved2;
551
552   /* Copy DPNAME struct - seems to be optional - check for existance first */
553   if( lpConn->lpPlayerName )
554   {
555      memcpy( &lpDplData->playerName, lpConn->lpPlayerName, sizeof( *lpConn->lpPlayerName ) );
556
557      if( lpConn->lpPlayerName->psn.lpszShortName )
558        lpDplData->playerName.psn.lpszShortName = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->psn.lpszShortName );
559
560      if( lpConn->lpPlayerName->pln.lpszLongName )
561        lpDplData->playerName.pln.lpszLongName = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->pln.lpszLongName );
562
563   }
564
565   memcpy( &lpDplData->guidSP, &lpConn->guidSP, sizeof( lpConn->guidSP ) );
566
567   lpDplData->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->dwAddressSize );
568   memcpy( lpDplData->lpAddress, lpConn->lpAddress, lpConn->dwAddressSize );
569
570   lpDplData->dwAddressSize = lpConn->dwAddressSize;
571
572   /* FIXME: Send a message - I think */
573
574   DPLAYX_ReleaseSemaphore();
575
576   return DP_OK;
577 }
578
579 /* NOTE: This is potentially not thread safe. You are not guaranteed to end up 
580          with the correct string printed in the case where the HRESULT is not
581          known. You'll just get the last hr passed in printed. This can change
582          over time if this method is used alot :) */
583 LPCSTR DPLAYX_HresultToString(HRESULT hr)
584 {
585   static char szTempStr[12];
586
587   switch (hr)
588   {
589     case DP_OK:  
590       return "DP_OK";
591     case DPERR_ALREADYINITIALIZED: 
592       return "DPERR_ALREADYINITIALIZED";
593     case DPERR_ACCESSDENIED: 
594       return "DPERR_ACCESSDENIED";
595     case DPERR_ACTIVEPLAYERS: 
596       return "DPERR_ACTIVEPLAYERS";
597     case DPERR_BUFFERTOOSMALL: 
598       return "DPERR_BUFFERTOOSMALL";
599     case DPERR_CANTADDPLAYER: 
600       return "DPERR_CANTADDPLAYER";
601     case DPERR_CANTCREATEGROUP: 
602       return "DPERR_CANTCREATEGROUP";
603     case DPERR_CANTCREATEPLAYER: 
604       return "DPERR_CANTCREATEPLAYER";
605     case DPERR_CANTCREATESESSION: 
606       return "DPERR_CANTCREATESESSION";
607     case DPERR_CAPSNOTAVAILABLEYET: 
608       return "DPERR_CAPSNOTAVAILABLEYET";
609     case DPERR_EXCEPTION: 
610       return "DPERR_EXCEPTION";
611     case DPERR_GENERIC: 
612       return "DPERR_GENERIC";
613     case DPERR_INVALIDFLAGS: 
614       return "DPERR_INVALIDFLAGS";
615     case DPERR_INVALIDOBJECT: 
616       return "DPERR_INVALIDOBJECT";
617     case DPERR_INVALIDPARAMS: 
618       return "DPERR_INVALIDPARAMS";
619     case DPERR_INVALIDPLAYER: 
620       return "DPERR_INVALIDPLAYER";
621     case DPERR_INVALIDGROUP: 
622       return "DPERR_INVALIDGROUP";
623     case DPERR_NOCAPS: 
624       return "DPERR_NOCAPS";
625     case DPERR_NOCONNECTION: 
626       return "DPERR_NOCONNECTION";
627     case DPERR_OUTOFMEMORY: 
628       return "DPERR_OUTOFMEMORY";
629     case DPERR_NOMESSAGES: 
630       return "DPERR_NOMESSAGES";
631     case DPERR_NONAMESERVERFOUND: 
632       return "DPERR_NONAMESERVERFOUND";
633     case DPERR_NOPLAYERS: 
634       return "DPERR_NOPLAYERS";
635     case DPERR_NOSESSIONS: 
636       return "DPERR_NOSESSIONS";
637 /* This one isn't defined yet in WINE sources. I don't know the value
638     case DPERR_PENDING: 
639       return "DPERR_PENDING";
640 */
641     case DPERR_SENDTOOBIG: 
642       return "DPERR_SENDTOOBIG";
643     case DPERR_TIMEOUT: 
644       return "DPERR_TIMEOUT";
645     case DPERR_UNAVAILABLE: 
646       return "DPERR_UNAVAILABLE";
647     case DPERR_UNSUPPORTED: 
648       return "DPERR_UNSUPPORTED";
649     case DPERR_BUSY: 
650       return "DPERR_BUSY";
651     case DPERR_USERCANCEL: 
652       return "DPERR_USERCANCEL";
653     case DPERR_NOINTERFACE: 
654       return "DPERR_NOINTERFACE";
655     case DPERR_CANNOTCREATESERVER: 
656       return "DPERR_CANNOTCREATESERVER";
657     case DPERR_PLAYERLOST: 
658       return "DPERR_PLAYERLOST";
659     case DPERR_SESSIONLOST: 
660       return "DPERR_SESSIONLOST";
661     case DPERR_UNINITIALIZED: 
662       return "DPERR_UNINITIALIZED";
663     case DPERR_NONEWPLAYERS: 
664       return "DPERR_NONEWPLAYERS";
665     case DPERR_INVALIDPASSWORD: 
666       return "DPERR_INVALIDPASSWORD";
667     case DPERR_CONNECTING: 
668       return "DPERR_CONNECTING";
669     case DPERR_CONNECTIONLOST: 
670       return "DPERR_CONNECTIONLOST";
671     case DPERR_UNKNOWNMESSAGE:
672       return "DPERR_UNKNOWNMESSAGE";
673     case DPERR_CANCELFAILED: 
674       return "DPERR_CANCELFAILED";
675     case DPERR_INVALIDPRIORITY: 
676       return "DPERR_INVALIDPRIORITY";
677     case DPERR_NOTHANDLED: 
678       return "DPERR_NOTHANDLED";
679     case DPERR_CANCELLED: 
680       return "DPERR_CANCELLED";
681     case DPERR_ABORTED: 
682       return "DPERR_ABORTED";
683     case DPERR_BUFFERTOOLARGE: 
684       return "DPERR_BUFFERTOOLARGE";
685     case DPERR_CANTCREATEPROCESS: 
686       return "DPERR_CANTCREATEPROCESS";
687     case DPERR_APPNOTSTARTED: 
688       return "DPERR_APPNOTSTARTED";
689     case DPERR_INVALIDINTERFACE: 
690       return "DPERR_INVALIDINTERFACE";
691     case DPERR_NOSERVICEPROVIDER: 
692       return "DPERR_NOSERVICEPROVIDER";
693     case DPERR_UNKNOWNAPPLICATION: 
694       return "DPERR_UNKNOWNAPPLICATION";
695     case DPERR_NOTLOBBIED: 
696       return "DPERR_NOTLOBBIED";
697     case DPERR_SERVICEPROVIDERLOADED: 
698       return "DPERR_SERVICEPROVIDERLOADED";
699     case DPERR_ALREADYREGISTERED: 
700       return "DPERR_ALREADYREGISTERED";
701     case DPERR_NOTREGISTERED: 
702       return "DPERR_NOTREGISTERED";
703     case DPERR_AUTHENTICATIONFAILED: 
704       return "DPERR_AUTHENTICATIONFAILED";
705     case DPERR_CANTLOADSSPI: 
706       return "DPERR_CANTLOADSSPI";
707     case DPERR_ENCRYPTIONFAILED: 
708       return "DPERR_ENCRYPTIONFAILED";
709     case DPERR_SIGNFAILED: 
710       return "DPERR_SIGNFAILED";
711     case DPERR_CANTLOADSECURITYPACKAGE: 
712       return "DPERR_CANTLOADSECURITYPACKAGE";
713     case DPERR_ENCRYPTIONNOTSUPPORTED: 
714       return "DPERR_ENCRYPTIONNOTSUPPORTED";
715     case DPERR_CANTLOADCAPI: 
716       return "DPERR_CANTLOADCAPI";
717     case DPERR_NOTLOGGEDIN: 
718       return "DPERR_NOTLOGGEDIN";
719     case DPERR_LOGONDENIED: 
720       return "DPERR_LOGONDENIED";
721     default:
722       /* For errors not in the list, return HRESULT as a string
723          This part is not thread safe */
724       WARN( "Unknown error 0x%08lx\n", hr );
725       sprintf( szTempStr, "0x%08lx", hr );
726       return szTempStr;
727   }
728 }
729