- Small fixes/updates
[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
223     TRACE( "Application 0x%08lx is not lobbied\n", dwAppID );
224     return DPERR_NOTLOBBIED;
225   }
226
227   /* Copy the information */
228   lpDplConnection = (LPDPLCONNECTION)lpData;
229
230   /* Copy everything we've got into here */
231   /* Need to actually store the stuff here. Check if we've already allocated each field first. */
232   lpDplConnection->dwSize = sizeof( DPLCONNECTION );
233   lpDplConnection->dwFlags = lpDplData->dwConnFlags;
234
235   /* Copy LPDPSESSIONDESC2 struct */
236   lpDplConnection->lpSessionDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->sessionDesc ) );
237   memcpy( lpDplConnection->lpSessionDesc, &lpDplData->sessionDesc, sizeof( lpDplData->sessionDesc ) );
238
239   if( lpDplData->sessionDesc.sess.lpszSessionNameA )
240   {
241     lpDplConnection->lpSessionDesc->sess.lpszSessionNameA =
242       HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.sess.lpszSessionNameA );
243   }
244
245   if( lpDplData->sessionDesc.pass.lpszPasswordA )
246   {
247     lpDplConnection->lpSessionDesc->pass.lpszPasswordA =
248       HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.pass.lpszPasswordA );
249   }
250
251   lpDplConnection->lpSessionDesc->dwReserved1 = lpDplData->sessionDesc.dwReserved1;
252   lpDplConnection->lpSessionDesc->dwReserved2 = lpDplData->sessionDesc.dwReserved2;
253
254   /* Copy DPNAME struct - seems to be optional - check for existance first */
255   lpDplConnection->lpPlayerName = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->playerName ) );
256   memcpy( lpDplConnection->lpPlayerName, &(lpDplData->playerName), sizeof( lpDplData->playerName ) );
257
258   if( lpDplData->playerName.psn.lpszShortNameA )
259   {
260     lpDplConnection->lpPlayerName->psn.lpszShortNameA =
261       HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.psn.lpszShortNameA );
262   }
263
264   if( lpDplData->playerName.pln.lpszLongNameA )
265   {
266     lpDplConnection->lpPlayerName->pln.lpszLongNameA =
267       HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.pln.lpszLongNameA );
268   }
269
270   memcpy( &lpDplConnection->guidSP, &lpDplData->guidSP, sizeof( lpDplData->guidSP ) );
271
272   lpDplConnection->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->dwAddressSize );
273   memcpy( lpDplConnection->lpAddress, lpDplData->lpAddress, lpDplData->dwAddressSize );
274
275   lpDplConnection->dwAddressSize = lpDplData->dwAddressSize;
276
277   /* FIXME: Send a message - or only the first time? */
278
279   DPLAYX_ReleaseSemaphore();
280
281   return DP_OK;
282 }
283
284 HRESULT DPLAYX_GetConnectionSettingsW
285 ( DWORD dwAppID,
286   LPVOID lpData,
287   LPDWORD lpdwDataSize )
288 {
289   lpDirectPlayLobbyData lpDplData;
290   LPDPLCONNECTION lpDplConnection;
291
292   /* Verify buffer size */
293   if ( ( lpData == NULL ) ||
294        ( *lpdwDataSize < sizeof( DPLCONNECTION ) )
295      )
296   {
297     *lpdwDataSize = sizeof( DPLCONNECTION );
298
299     return DPERR_BUFFERTOOSMALL;
300   }
301
302   DPLAYX_AquireSemaphore();
303
304   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
305   {
306     DPLAYX_ReleaseSemaphore();
307     return DPERR_NOTLOBBIED;
308   }
309
310   /* Copy the information */
311   lpDplConnection = (LPDPLCONNECTION)lpData;
312
313   /* Copy everything we've got into here */
314   /* Need to actually store the stuff here. Check if we've already allocated each field first. */
315   lpDplConnection->dwSize = sizeof( DPLCONNECTION );
316   lpDplConnection->dwFlags = lpDplData->dwConnFlags;
317
318   /* Copy LPDPSESSIONDESC2 struct */
319   lpDplConnection->lpSessionDesc = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->sessionDesc ) );
320   memcpy( lpDplConnection->lpSessionDesc, &lpDplData->sessionDesc, sizeof( lpDplData->sessionDesc ) );
321
322   if( lpDplData->sessionDesc.sess.lpszSessionName )
323   {
324     lpDplConnection->lpSessionDesc->sess.lpszSessionName =
325       HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.sess.lpszSessionName );
326   }
327
328   if( lpDplData->sessionDesc.pass.lpszPassword )
329   {
330     lpDplConnection->lpSessionDesc->pass.lpszPassword =
331       HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->sessionDesc.pass.lpszPassword );
332   }
333
334   lpDplConnection->lpSessionDesc->dwReserved1 = lpDplData->sessionDesc.dwReserved1;
335   lpDplConnection->lpSessionDesc->dwReserved2 = lpDplData->sessionDesc.dwReserved2;
336
337   /* Copy DPNAME struct - seems to be optional - check for existance first */
338   lpDplConnection->lpPlayerName = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof( lpDplData->playerName ) );
339   memcpy( lpDplConnection->lpPlayerName, &(lpDplData->playerName), sizeof( lpDplData->playerName ) );
340
341   if( lpDplData->playerName.psn.lpszShortName )
342   {
343     lpDplConnection->lpPlayerName->psn.lpszShortName =
344       HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.psn.lpszShortName );
345   }
346
347   if( lpDplData->playerName.pln.lpszLongName )
348   {
349     lpDplConnection->lpPlayerName->pln.lpszLongName =
350       HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->playerName.pln.lpszLongName );
351   }
352
353   memcpy( &lpDplConnection->guidSP, &lpDplData->guidSP, sizeof( lpDplData->guidSP ) );
354
355   lpDplConnection->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpDplData->dwAddressSize );
356   memcpy( lpDplConnection->lpAddress, lpDplData->lpAddress, lpDplData->dwAddressSize );
357
358   lpDplConnection->dwAddressSize = lpDplData->dwAddressSize;
359
360   /* FIXME: Send a message - or only the first time? */
361
362   DPLAYX_ReleaseSemaphore();
363
364   return DP_OK;
365 }
366
367
368 HRESULT DPLAYX_SetConnectionSettingsA
369 ( DWORD dwFlags,
370   DWORD dwAppID,
371   LPDPLCONNECTION lpConn )
372 {
373   lpDirectPlayLobbyData lpDplData;
374
375   /* Paramater check */
376   if( dwFlags || !lpConn )
377   {
378     ERR("invalid parameters.\n");
379     return DPERR_INVALIDPARAMS;
380   }
381
382   /* Store information */
383   if(  lpConn->dwSize != sizeof(DPLCONNECTION) )
384   {
385     ERR(": old/new DPLCONNECTION type? Size=%08lx vs. expected=%ul bytes\n",
386          lpConn->dwSize, sizeof( DPLCONNECTION ) );
387
388     return DPERR_INVALIDPARAMS;
389   }
390
391   if( dwAppID == 0 )
392   {
393     dwAppID = GetCurrentProcessId();
394   }
395
396   DPLAYX_AquireSemaphore();
397
398   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
399   {
400     /* FIXME: Create a new entry for this dwAppID? */
401     DPLAYX_ReleaseSemaphore();
402
403     return DPERR_GENERIC;
404   }
405
406   /* Store information */
407   if(  lpConn->dwSize != sizeof(DPLCONNECTION) )
408   {
409     DPLAYX_ReleaseSemaphore();
410
411     ERR(": old/new DPLCONNECTION type? Size=%lu vs. expected=%u bytes\n",
412          lpConn->dwSize, sizeof( DPLCONNECTION ) );
413
414     return DPERR_INVALIDPARAMS;
415   }
416
417   /* Need to investigate the lpConn->lpSessionDesc to figure out
418    * what type of session we need to join/create.
419    */
420   if(  (!lpConn->lpSessionDesc ) ||
421        ( lpConn->lpSessionDesc->dwSize != sizeof( DPSESSIONDESC2 ) )
422     )
423   {
424     DPLAYX_ReleaseSemaphore();
425
426     ERR("DPSESSIONDESC passed in? Size=%lu vs. expected=%u bytes\n",
427          lpConn->lpSessionDesc->dwSize, sizeof( DPSESSIONDESC2 ) );
428
429     return DPERR_INVALIDPARAMS;
430   }
431
432   /* 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 */ 
433
434   /* Need to actually store the stuff here. Check if we've already allocated each field first. */
435   lpDplData->dwConnFlags = lpConn->dwFlags;
436
437   /* Copy LPDPSESSIONDESC2 struct - this is required */
438   memcpy( &lpDplData->sessionDesc, lpConn->lpSessionDesc, sizeof( *(lpConn->lpSessionDesc) ) );
439
440   /* FIXME: Can this just be shorted? Does it handle the NULL case correctly? */
441   if( lpConn->lpSessionDesc->sess.lpszSessionNameA )
442     lpDplData->sessionDesc.sess.lpszSessionNameA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->sess.lpszSessionNameA );
443   else
444     lpDplData->sessionDesc.sess.lpszSessionNameA = NULL;
445
446   if( lpConn->lpSessionDesc->pass.lpszPasswordA )
447     lpDplData->sessionDesc.pass.lpszPasswordA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->pass.lpszPasswordA );
448   else
449     lpDplData->sessionDesc.pass.lpszPasswordA = NULL;
450
451   lpDplData->sessionDesc.dwReserved1 = lpConn->lpSessionDesc->dwReserved1;
452   lpDplData->sessionDesc.dwReserved2 = lpConn->lpSessionDesc->dwReserved2;
453
454   /* Copy DPNAME struct - seems to be optional - check for existance first */
455   if( lpConn->lpPlayerName )
456   {
457      memcpy( &lpDplData->playerName, lpConn->lpPlayerName, sizeof( *lpConn->lpPlayerName ) );
458
459      if( lpConn->lpPlayerName->psn.lpszShortNameA )
460        lpDplData->playerName.psn.lpszShortNameA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->psn.lpszShortNameA );
461
462      if( lpConn->lpPlayerName->pln.lpszLongNameA )
463        lpDplData->playerName.pln.lpszLongNameA = HEAP_strdupA( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->pln.lpszLongNameA );
464
465   }
466
467   memcpy( &lpDplData->guidSP, &lpConn->guidSP, sizeof( lpConn->guidSP ) );
468
469   lpDplData->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->dwAddressSize );
470   memcpy( lpDplData->lpAddress, lpConn->lpAddress, lpConn->dwAddressSize );
471
472   lpDplData->dwAddressSize = lpConn->dwAddressSize;
473
474   /* FIXME: Send a message - I think */
475
476   DPLAYX_ReleaseSemaphore();
477
478   return DP_OK;
479 }
480
481 HRESULT DPLAYX_SetConnectionSettingsW
482 ( DWORD dwFlags,
483   DWORD dwAppID,
484   LPDPLCONNECTION lpConn )
485 {
486   lpDirectPlayLobbyData lpDplData;
487
488   /* Paramater check */
489   if( dwFlags || !lpConn )
490   {
491     ERR("invalid parameters.\n");
492     return DPERR_INVALIDPARAMS;
493   }
494
495   /* Store information */
496   if(  lpConn->dwSize != sizeof(DPLCONNECTION) )
497   {
498     ERR(": old/new DPLCONNECTION type? Size=%lu vs. expected=%u bytes\n",
499          lpConn->dwSize, sizeof( DPLCONNECTION ) );
500
501     return DPERR_INVALIDPARAMS;
502   }
503
504   if( dwAppID == 0 )
505   {
506     dwAppID = GetCurrentProcessId();
507   }
508
509   DPLAYX_AquireSemaphore();
510
511   if ( ! DPLAYX_IsAppIdLobbied( dwAppID, &lpDplData ) )
512   {
513     DPLAYX_ReleaseSemaphore();
514     return DPERR_NOTLOBBIED;
515   }
516
517   /* Need to investigate the lpConn->lpSessionDesc to figure out
518    * what type of session we need to join/create.
519    */
520   if(  (!lpConn->lpSessionDesc ) ||
521        ( lpConn->lpSessionDesc->dwSize != sizeof( DPSESSIONDESC2 ) )
522     )
523   {
524     DPLAYX_ReleaseSemaphore();
525
526     ERR("DPSESSIONDESC passed in? Size=%lu vs. expected=%u bytes\n",
527          lpConn->lpSessionDesc->dwSize, sizeof( DPSESSIONDESC2 ) );
528
529     return DPERR_INVALIDPARAMS;
530   }
531
532   /* 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 */ 
533
534   /* Need to actually store the stuff here. Check if we've already allocated each field first. */
535   lpDplData->dwConnFlags = lpConn->dwFlags;
536
537   /* Copy LPDPSESSIONDESC2 struct - this is required */
538   memcpy( &lpDplData->sessionDesc, lpConn->lpSessionDesc, sizeof( *(lpConn->lpSessionDesc) ) );
539
540   /* FIXME: Can this just be shorted? Does it handle the NULL case correctly? */
541   if( lpConn->lpSessionDesc->sess.lpszSessionName )
542     lpDplData->sessionDesc.sess.lpszSessionName = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->sess.lpszSessionName );
543   else
544     lpDplData->sessionDesc.sess.lpszSessionName = NULL;
545
546   if( lpConn->lpSessionDesc->pass.lpszPassword )
547     lpDplData->sessionDesc.pass.lpszPassword = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpSessionDesc->pass.lpszPassword );
548   else
549     lpDplData->sessionDesc.pass.lpszPassword = NULL;
550
551   lpDplData->sessionDesc.dwReserved1 = lpConn->lpSessionDesc->dwReserved1;
552   lpDplData->sessionDesc.dwReserved2 = lpConn->lpSessionDesc->dwReserved2;
553
554   /* Copy DPNAME struct - seems to be optional - check for existance first */
555   if( lpConn->lpPlayerName )
556   {
557      memcpy( &lpDplData->playerName, lpConn->lpPlayerName, sizeof( *lpConn->lpPlayerName ) );
558
559      if( lpConn->lpPlayerName->psn.lpszShortName )
560        lpDplData->playerName.psn.lpszShortName = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->psn.lpszShortName );
561
562      if( lpConn->lpPlayerName->pln.lpszLongName )
563        lpDplData->playerName.pln.lpszLongName = HEAP_strdupW( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->lpPlayerName->pln.lpszLongName );
564
565   }
566
567   memcpy( &lpDplData->guidSP, &lpConn->guidSP, sizeof( lpConn->guidSP ) );
568
569   lpDplData->lpAddress = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpConn->dwAddressSize );
570   memcpy( lpDplData->lpAddress, lpConn->lpAddress, lpConn->dwAddressSize );
571
572   lpDplData->dwAddressSize = lpConn->dwAddressSize;
573
574   /* FIXME: Send a message - I think */
575
576   DPLAYX_ReleaseSemaphore();
577
578   return DP_OK;
579 }
580
581 /* NOTE: This is potentially not thread safe. You are not guaranteed to end up 
582          with the correct string printed in the case where the HRESULT is not
583          known. You'll just get the last hr passed in printed. This can change
584          over time if this method is used alot :) */
585 LPCSTR DPLAYX_HresultToString(HRESULT hr)
586 {
587   static char szTempStr[12];
588
589   switch (hr)
590   {
591     case DP_OK:  
592       return "DP_OK";
593     case DPERR_ALREADYINITIALIZED: 
594       return "DPERR_ALREADYINITIALIZED";
595     case DPERR_ACCESSDENIED: 
596       return "DPERR_ACCESSDENIED";
597     case DPERR_ACTIVEPLAYERS: 
598       return "DPERR_ACTIVEPLAYERS";
599     case DPERR_BUFFERTOOSMALL: 
600       return "DPERR_BUFFERTOOSMALL";
601     case DPERR_CANTADDPLAYER: 
602       return "DPERR_CANTADDPLAYER";
603     case DPERR_CANTCREATEGROUP: 
604       return "DPERR_CANTCREATEGROUP";
605     case DPERR_CANTCREATEPLAYER: 
606       return "DPERR_CANTCREATEPLAYER";
607     case DPERR_CANTCREATESESSION: 
608       return "DPERR_CANTCREATESESSION";
609     case DPERR_CAPSNOTAVAILABLEYET: 
610       return "DPERR_CAPSNOTAVAILABLEYET";
611     case DPERR_EXCEPTION: 
612       return "DPERR_EXCEPTION";
613     case DPERR_GENERIC: 
614       return "DPERR_GENERIC";
615     case DPERR_INVALIDFLAGS: 
616       return "DPERR_INVALIDFLAGS";
617     case DPERR_INVALIDOBJECT: 
618       return "DPERR_INVALIDOBJECT";
619     case DPERR_INVALIDPARAMS: 
620       return "DPERR_INVALIDPARAMS";
621     case DPERR_INVALIDPLAYER: 
622       return "DPERR_INVALIDPLAYER";
623     case DPERR_INVALIDGROUP: 
624       return "DPERR_INVALIDGROUP";
625     case DPERR_NOCAPS: 
626       return "DPERR_NOCAPS";
627     case DPERR_NOCONNECTION: 
628       return "DPERR_NOCONNECTION";
629     case DPERR_OUTOFMEMORY: 
630       return "DPERR_OUTOFMEMORY";
631     case DPERR_NOMESSAGES: 
632       return "DPERR_NOMESSAGES";
633     case DPERR_NONAMESERVERFOUND: 
634       return "DPERR_NONAMESERVERFOUND";
635     case DPERR_NOPLAYERS: 
636       return "DPERR_NOPLAYERS";
637     case DPERR_NOSESSIONS: 
638       return "DPERR_NOSESSIONS";
639 /* This one isn't defined yet in WINE sources. I don't know the value
640     case DPERR_PENDING: 
641       return "DPERR_PENDING";
642 */
643     case DPERR_SENDTOOBIG: 
644       return "DPERR_SENDTOOBIG";
645     case DPERR_TIMEOUT: 
646       return "DPERR_TIMEOUT";
647     case DPERR_UNAVAILABLE: 
648       return "DPERR_UNAVAILABLE";
649     case DPERR_UNSUPPORTED: 
650       return "DPERR_UNSUPPORTED";
651     case DPERR_BUSY: 
652       return "DPERR_BUSY";
653     case DPERR_USERCANCEL: 
654       return "DPERR_USERCANCEL";
655     case DPERR_NOINTERFACE: 
656       return "DPERR_NOINTERFACE";
657     case DPERR_CANNOTCREATESERVER: 
658       return "DPERR_CANNOTCREATESERVER";
659     case DPERR_PLAYERLOST: 
660       return "DPERR_PLAYERLOST";
661     case DPERR_SESSIONLOST: 
662       return "DPERR_SESSIONLOST";
663     case DPERR_UNINITIALIZED: 
664       return "DPERR_UNINITIALIZED";
665     case DPERR_NONEWPLAYERS: 
666       return "DPERR_NONEWPLAYERS";
667     case DPERR_INVALIDPASSWORD: 
668       return "DPERR_INVALIDPASSWORD";
669     case DPERR_CONNECTING: 
670       return "DPERR_CONNECTING";
671     case DPERR_CONNECTIONLOST: 
672       return "DPERR_CONNECTIONLOST";
673     case DPERR_UNKNOWNMESSAGE:
674       return "DPERR_UNKNOWNMESSAGE";
675     case DPERR_CANCELFAILED: 
676       return "DPERR_CANCELFAILED";
677     case DPERR_INVALIDPRIORITY: 
678       return "DPERR_INVALIDPRIORITY";
679     case DPERR_NOTHANDLED: 
680       return "DPERR_NOTHANDLED";
681     case DPERR_CANCELLED: 
682       return "DPERR_CANCELLED";
683     case DPERR_ABORTED: 
684       return "DPERR_ABORTED";
685     case DPERR_BUFFERTOOLARGE: 
686       return "DPERR_BUFFERTOOLARGE";
687     case DPERR_CANTCREATEPROCESS: 
688       return "DPERR_CANTCREATEPROCESS";
689     case DPERR_APPNOTSTARTED: 
690       return "DPERR_APPNOTSTARTED";
691     case DPERR_INVALIDINTERFACE: 
692       return "DPERR_INVALIDINTERFACE";
693     case DPERR_NOSERVICEPROVIDER: 
694       return "DPERR_NOSERVICEPROVIDER";
695     case DPERR_UNKNOWNAPPLICATION: 
696       return "DPERR_UNKNOWNAPPLICATION";
697     case DPERR_NOTLOBBIED: 
698       return "DPERR_NOTLOBBIED";
699     case DPERR_SERVICEPROVIDERLOADED: 
700       return "DPERR_SERVICEPROVIDERLOADED";
701     case DPERR_ALREADYREGISTERED: 
702       return "DPERR_ALREADYREGISTERED";
703     case DPERR_NOTREGISTERED: 
704       return "DPERR_NOTREGISTERED";
705     case DPERR_AUTHENTICATIONFAILED: 
706       return "DPERR_AUTHENTICATIONFAILED";
707     case DPERR_CANTLOADSSPI: 
708       return "DPERR_CANTLOADSSPI";
709     case DPERR_ENCRYPTIONFAILED: 
710       return "DPERR_ENCRYPTIONFAILED";
711     case DPERR_SIGNFAILED: 
712       return "DPERR_SIGNFAILED";
713     case DPERR_CANTLOADSECURITYPACKAGE: 
714       return "DPERR_CANTLOADSECURITYPACKAGE";
715     case DPERR_ENCRYPTIONNOTSUPPORTED: 
716       return "DPERR_ENCRYPTIONNOTSUPPORTED";
717     case DPERR_CANTLOADCAPI: 
718       return "DPERR_CANTLOADCAPI";
719     case DPERR_NOTLOGGEDIN: 
720       return "DPERR_NOTLOGGEDIN";
721     case DPERR_LOGONDENIED: 
722       return "DPERR_LOGONDENIED";
723     default:
724       /* For errors not in the list, return HRESULT as a string
725          This part is not thread safe */
726       WARN( "Unknown error 0x%08lx\n", hr );
727       sprintf( szTempStr, "0x%08lx", hr );
728       return szTempStr;
729   }
730 }
731