Removed a few dependencies on kernel32 functions.
[wine] / dlls / dplayx / dplayx_messages.c
1 /* DirectPlay & DirectPlayLobby messaging implementation
2  *
3  * Copyright 2000 - Peter Hunnisett
4  *
5  * <presently under construction - contact hunnise@nortelnetworks.com>
6  *
7  */
8
9 #include "winbase.h"
10 #include "debugtools.h"
11
12 #include "wingdi.h"
13 #include "winuser.h"
14 #include "winerror.h"
15
16 #include "dplayx_messages.h"
17 #include "dplay_global.h"
18 #include "dplayx_global.h"
19
20 DEFAULT_DEBUG_CHANNEL(dplay)
21
22 typedef struct tagMSGTHREADINFO
23 {
24   HANDLE hStart;
25   HANDLE hDeath; 
26   HANDLE hSettingRead;
27   HANDLE hNotifyEvent; 
28 } MSGTHREADINFO, *LPMSGTHREADINFO;
29
30
31 static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext );
32
33 /* Create the message reception thread to allow the application to receive
34  * asynchronous message reception
35  */
36 DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart, 
37                                          HANDLE hDeath, HANDLE hConnRead )
38 {
39   DWORD           dwMsgThreadId;
40   LPMSGTHREADINFO lpThreadInfo;
41
42   lpThreadInfo = HeapAlloc( GetProcessHeap(), 0, sizeof( *lpThreadInfo ) );
43   if( lpThreadInfo == NULL )
44   {
45     return 0;
46   }
47
48   /* The notify event may or may not exist. Depends if async comm or not */
49   if( hNotifyEvent &&
50       !DuplicateHandle( GetCurrentProcess(), hNotifyEvent, 
51                         GetCurrentProcess(), &lpThreadInfo->hNotifyEvent, 
52                         0, FALSE, DUPLICATE_SAME_ACCESS ) )
53   {
54     ERR( "Unable to duplicate event handle\n" );
55     goto error;
56   }
57
58   /* These 3 handles don't need to be duplicated because we don't keep a
59    * reference to them where they're created. They're created specifically
60    * for the message thread 
61    */
62   lpThreadInfo->hStart       = hStart;
63   lpThreadInfo->hDeath       = hDeath;
64   lpThreadInfo->hSettingRead = hConnRead;
65
66   if( !CreateThread( NULL,                  /* Security attribs */
67                      0,                     /* Stack */ 
68                      DPL_MSG_ThreadMain,    /* Msg reception function */
69                      lpThreadInfo,          /* Msg reception func parameter */
70                      0,                     /* Flags */
71                      &dwMsgThreadId         /* Updated with thread id */
72                    )
73     )
74   {
75     ERR( "Unable to create msg thread\n" );
76     goto error;
77   }
78
79   /* FIXME: Should I be closing the handle to the thread or does that
80             terminate the thread? */
81  
82   return dwMsgThreadId;
83
84 error:
85
86   HeapFree( GetProcessHeap(), 0, lpThreadInfo );
87
88   return 0;
89 }
90
91 static DWORD CALLBACK DPL_MSG_ThreadMain( LPVOID lpContext )
92 {
93   LPMSGTHREADINFO lpThreadInfo = (LPMSGTHREADINFO)lpContext;
94   DWORD dwWaitResult;
95  
96   TRACE( "Msg thread created. Waiting on app startup\n" );
97
98   /* Wait to ensure that the lobby application is started w/ 1 min timeout */
99   dwWaitResult = WaitForSingleObject( lpThreadInfo->hStart, 10000 /* 10 sec */ );
100   if( dwWaitResult == WAIT_TIMEOUT )
101   {
102     FIXME( "Should signal app/wait creation failure (0x%08lx)\n", dwWaitResult );
103     goto end_of_thread;
104   }
105
106   /* Close this handle as it's not needed anymore */
107   CloseHandle( lpThreadInfo->hStart );
108   lpThreadInfo->hStart = 0;
109
110   /* Wait until the lobby knows what it is */
111   dwWaitResult = WaitForSingleObject( lpThreadInfo->hSettingRead, INFINITE );
112   if( dwWaitResult == WAIT_TIMEOUT )
113   {
114     ERR( "App Read connection setting timeout fail (0x%08lx)\n", dwWaitResult );
115   }
116
117   /* Close this handle as it's not needed anymore */
118   CloseHandle( lpThreadInfo->hSettingRead );
119   lpThreadInfo->hSettingRead = 0;
120
121   TRACE( "App created && intialized starting main message reception loop\n" );
122
123   for ( ;; )
124   {
125     MSG lobbyMsg;
126 #ifdef STRICT
127     HANDLE hNullHandle = NULL;
128 #else
129     HANDLE hNullHandle = 0;
130 #endif
131
132     GetMessageW( &lobbyMsg, hNullHandle, 0, 0 );
133   }
134
135 end_of_thread:
136   TRACE( "Msg thread exiting!\n" );
137   HeapFree( GetProcessHeap(), 0, lpThreadInfo );
138
139   return 0;
140 }
141
142
143 HRESULT DP_MSG_SendRequestPlayerId( IDirectPlay2AImpl* This, DWORD dwFlags,
144                                     LPDPID lpdpidAllocatedId )
145 {
146   LPVOID                     lpMsg;
147   LPDPMSG_REQUESTNEWPLAYERID lpMsgBody;
148   DWORD                      dwMsgSize;
149   DWORD                      dwWaitReturn;
150   HRESULT                    hr = DP_OK;
151
152   dwMsgSize = This->dp2->spData.dwSPHeaderSize + sizeof( *lpMsgBody );
153
154   lpMsg = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwMsgSize );
155
156   lpMsgBody = (LPDPMSG_REQUESTNEWPLAYERID)( (BYTE*)lpMsg + 
157                                              This->dp2->spData.dwSPHeaderSize );
158
159   lpMsgBody->envelope.dwMagic    = DPMSGMAGIC_DPLAYMSG;
160   lpMsgBody->envelope.wCommandId = DPMSGCMD_REQUESTNEWPLAYERID;
161   lpMsgBody->envelope.wVersion   = DPMSGVER_DP6;
162
163   lpMsgBody->dwFlags = dwFlags;
164
165   /* FIXME: Need to have a more advanced queuing system as this needs to
166    *        block on send until we get response. Otherwise we need to be
167    *        able to ensure we can pick out the exact response. Of course,
168    *        with something as non critical as this, would it matter? The
169    *        id has been effectively reserved for this session...
170    */
171   { 
172     DPSP_SENDDATA data;
173
174     data.dwFlags        = DPSEND_GUARANTEED;
175     data.idPlayerTo     = 0; /* Name server */
176     data.idPlayerFrom   = 0; /* Sending from DP */
177     data.lpMessage      = lpMsg;
178     data.dwMessageSize  = dwMsgSize;
179     data.bSystemMessage = TRUE; /* Allow reply to be sent */
180     data.lpISP          = This->dp2->spData.lpISP;
181
182     /* Setup for receipt */
183     This->dp2->hMsgReceipt = CreateEventA( NULL, FALSE, FALSE, NULL );
184
185     TRACE( "Sending request for player id\n" );
186  
187     hr = (*This->dp2->spData.lpCB->Send)( &data );
188
189     if( FAILED(hr) )
190     {
191       ERR( "Request for new playerID send failed: %s\n",
192            DPLAYX_HresultToString( hr ) );
193       return DPERR_NOCONNECTION;
194     }
195   }
196
197   dwWaitReturn = WaitForSingleObject( This->dp2->hMsgReceipt, 30000 );
198   if( dwWaitReturn != WAIT_OBJECT_0 )
199   {
200     ERR( "Wait failed 0x%08lx\n", dwWaitReturn );
201     hr = DPERR_TIMEOUT;
202   }
203
204   CloseHandle( This->dp2->hMsgReceipt );
205   This->dp2->hMsgReceipt = 0;
206
207   /* Need to examine the data and extract the new player id */
208   if( !FAILED(hr) )
209   {
210     LPCDPMSG_NEWPLAYERIDREPLY lpcReply; 
211
212     lpcReply = (LPCDPMSG_NEWPLAYERIDREPLY)This->dp2->lpMsgReceived;
213
214     *lpdpidAllocatedId = lpcReply->dpidNewPlayerId;   
215
216     TRACE( "Received reply for id = 0x%08lx\n", lpcReply->dpidNewPlayerId );
217
218     /* FIXME: I think that the rest of the message has something to do
219      *        with remote data for the player that perhaps I need to setup.
220      */
221 #if 0
222    /* Set the passed service provider data */
223    IDirectPlaySP_SetSPData( This->dp2->spData.lpISP, data, 
224                             msgsize, DPSET_REMOTE );
225
226 #endif
227
228     HeapFree( GetProcessHeap(), 0, This->dp2->lpMsgReceived ); 
229     This->dp2->lpMsgReceived = NULL;
230   }
231
232   return hr;
233 }
234
235
236 /* This function seems to cause a trap in the SP. It would seem unnecessary */
237 /* FIXME: Remove this method if not required */
238 HRESULT DP_MSG_OpenStream( IDirectPlay2AImpl* This )
239 {
240   HRESULT       hr;
241   DPSP_SENDDATA data;
242
243   data.dwFlags        = DPSEND_OPENSTREAM;
244   data.idPlayerTo     = 0; /* Name server */
245   data.idPlayerFrom   = 0; /* From DP itself */
246   data.lpMessage      = NULL;
247   data.dwMessageSize  = This->dp2->spData.dwSPHeaderSize;
248   data.bSystemMessage = FALSE; /* FIXME? */
249   data.lpISP          = This->dp2->spData.lpISP;
250
251   hr = (*This->dp2->spData.lpCB->Send)( &data );
252
253   if( FAILED(hr) )
254   {
255       ERR( "Request for open stream send failed: %s\n",
256            DPLAYX_HresultToString( hr ) );
257   }
258
259   /* FIXME: hack to give some time for channel to open */
260   SleepEx( 1000 /* 1 sec */, FALSE );
261
262   return hr;
263 }