3850bd9d2ee8d6df54e4f77a3aaefc792cbd946f
[reactos.git] / reactos / win32ss / user / ntuser / dde.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Dynamic Data Exchange
5 * FILE: win32ss/user/ntuser/dde.c
6 * PROGRAMER:
7 */
8
9 #include <win32k.h>
10
11 #include <dde.h>
12
13 DBG_DEFAULT_CHANNEL(UserMisc);
14
15 //
16 // Default information used to support client impersonation.
17 //
18 SECURITY_QUALITY_OF_SERVICE gqosDefault = {sizeof(SECURITY_QUALITY_OF_SERVICE),SecurityImpersonation,SECURITY_STATIC_TRACKING,TRUE};
19
20 typedef struct _DDEIMP
21 {
22 SECURITY_QUALITY_OF_SERVICE qos;
23 SECURITY_CLIENT_CONTEXT ClientContext;
24 WORD cRefInit;
25 WORD cRefConv;
26 } DDEIMP, *PDDEIMP;
27
28 typedef struct _DDE_DATA
29 {
30 LPARAM lParam;
31 int cbSize;
32 PVOID pvBuffer;
33 } DDE_DATA, *PDDE_DATA;
34
35 typedef struct _DDE_PROP
36 {
37 PWND spwnd;
38 PWND spwndPartner;
39 PDDEIMP pddei;
40 } DDE_PROP, *PDDE_PROP;
41
42
43 //
44 // DDE Posting message callback to user side.
45 //
46 int
47 APIENTRY
48 IntDDEPostCallback(
49 IN PWND pWnd,
50 IN UINT Msg,
51 IN WPARAM wParam,
52 IN OUT LPARAM *lParam,
53 IN OUT PVOID *Buffer)
54 {
55 NTSTATUS Status;
56 ULONG ArgumentLength, ResultLength;
57 PVOID Argument, ResultPointer;
58 PDDEPOSTGET_CALLBACK_ARGUMENTS Common;
59 int size = 0;
60 ResultPointer = NULL;
61 ResultLength = ArgumentLength = sizeof(DDEPOSTGET_CALLBACK_ARGUMENTS);
62
63 Argument = IntCbAllocateMemory(ArgumentLength);
64 if (NULL == Argument)
65 {
66 return FALSE;
67 }
68
69 Common = (PDDEPOSTGET_CALLBACK_ARGUMENTS) Argument;
70
71 Common->pvData = 0;
72 Common->size = 0;
73 Common->hwnd = UserHMGetHandle(pWnd);
74 Common->message = Msg;
75 Common->wParam = wParam;
76 Common->lParam = *lParam;
77
78 UserLeaveCo();
79
80 Status = KeUserModeCallback(USER32_CALLBACK_DDEPOST,
81 Argument,
82 ArgumentLength,
83 &ResultPointer,
84 &ResultLength);
85
86 UserEnterCo();
87
88 if (!NT_SUCCESS(Status) || ResultPointer == NULL )
89 {
90 ERR("DDE Post callback failed!\n");
91 IntCbFreeMemory(Argument);
92 return 0;
93 }
94
95 RtlCopyMemory(Common, ResultPointer, ArgumentLength);
96
97 size = Common->size;
98 *lParam = Common->lParam;
99 *Buffer = Common->pvData;
100
101 IntCbFreeMemory(Argument);
102
103 return size ? size : -1;
104 }
105
106 //
107 // DDE Get/Peek message callback to user side.
108 //
109 BOOL
110 APIENTRY
111 IntDDEGetCallback(
112 IN PWND pWnd,
113 IN OUT PMSG pMsg,
114 IN PVOID Buffer,
115 IN int size)
116 {
117 NTSTATUS Status;
118 ULONG ArgumentLength, ResultLength;
119 PVOID Argument, ResultPointer;
120 PDDEPOSTGET_CALLBACK_ARGUMENTS Common;
121
122 ResultPointer = NULL;
123 ResultLength = ArgumentLength = sizeof(DDEPOSTGET_CALLBACK_ARGUMENTS)+size;
124
125 Argument = IntCbAllocateMemory(ArgumentLength);
126 if (NULL == Argument)
127 {
128 return FALSE;
129 }
130
131 Common = (PDDEPOSTGET_CALLBACK_ARGUMENTS) Argument;
132
133 Common->size = size;
134 Common->hwnd = pMsg->hwnd;
135 Common->message = pMsg->message;
136 Common->wParam = pMsg->wParam;
137 Common->lParam = pMsg->lParam;
138
139 if (size && Buffer) RtlCopyMemory(&Common->buffer, Buffer, size);
140
141 UserLeaveCo();
142
143 Status = KeUserModeCallback(USER32_CALLBACK_DDEGET,
144 Argument,
145 ArgumentLength,
146 &ResultPointer,
147 &ResultLength);
148
149 UserEnterCo();
150
151 if (!NT_SUCCESS(Status) || ResultPointer == NULL )
152 {
153 ERR("DDE Get callback failed!\n");
154 IntCbFreeMemory(Argument);
155 return FALSE;
156 }
157
158 RtlMoveMemory(Common, ResultPointer, ArgumentLength);
159
160 pMsg->lParam = Common->lParam;
161
162 IntCbFreeMemory(Argument);
163
164 return TRUE;
165 }
166
167 //
168 // DDE Post message hook, intercept DDE messages before going on to the target Processes Thread queue.
169 //
170 BOOL
171 APIENTRY
172 IntDdePostMessageHook(
173 IN PWND pWnd,
174 IN UINT Msg,
175 IN WPARAM wParam,
176 IN OUT LPARAM *lParam,
177 IN OUT LONG_PTR *ExtraInfo)
178 {
179 PWND pWndClient;
180 PDDE_DATA pddeData;
181 int size;
182 HGDIOBJ Object = NULL;
183 PVOID userBuf = NULL;
184 PVOID Buffer = NULL;
185 LPARAM lp = *lParam;
186
187 if (pWnd->head.pti->ppi != gptiCurrent->ppi)
188 {
189 TRACE("Posting long DDE 0x%x\n",Msg);
190 // Initiate is sent only across borders.
191 if (Msg == WM_DDE_INITIATE)
192 {
193 return FALSE;
194 }
195
196 pWndClient = UserGetWindowObject((HWND)wParam);
197 if (pWndClient == NULL)
198 {
199 // This is terminating so post it.
200 if ( Msg == WM_DDE_TERMINATE)
201 {
202 TRACE("DDE Posted WM_DDE_TERMINATE\n");
203 return TRUE;
204 }
205 TRACE("Invalid DDE Client Window handle\n");
206 return FALSE;
207 }
208
209 if ( Msg == WM_DDE_REQUEST || Msg == WM_DDE_UNADVISE )
210 {
211 // Do not bother to callback after validation.
212 return TRUE;
213 }
214
215 if ( Msg == WM_DDE_TERMINATE )
216 {
217 //// FIXME Remove Stuff if any...
218
219 // Do not bother to callback.
220 return TRUE;
221 }
222
223 if ( Msg == WM_DDE_EXECUTE && *lParam == 0)
224 {
225 // Do not bother to do a callback.
226 TRACE("DDE Post EXECUTE lParam 0\n");
227 return FALSE;
228 }
229
230 // Callback.
231 if ((size = IntDDEPostCallback(pWnd, Msg, wParam, &lp, &userBuf)) == 0)
232 {
233 ERR("DDE Post Callback return 0 0x%x\n", Msg);
234 return FALSE;
235 }
236
237 // No error HACK.
238 if (size == -1)
239 {
240 size = 0;
241 }
242 else
243 {
244 // Set buffer with users data size.
245 Buffer = ExAllocatePoolWithTag(PagedPool, size, USERTAG_DDE);
246 if (Buffer == NULL)
247 {
248 ERR("Failed to allocate %i bytes.\n", size);
249 return FALSE;
250 }
251 // No SEH? Yes, the user memory is freed after the Acknowledgment or at Termination.
252 RtlCopyMemory(Buffer, userBuf, size);
253 }
254
255 TRACE("DDE Post size %d 0x%x\n",size, Msg);
256
257 switch(Msg)
258 {
259 case WM_DDE_POKE:
260 {
261 DDEPOKE *pddePoke = Buffer;
262 NT_ASSERT(pddePoke != NULL);
263 switch(pddePoke->cfFormat)
264 {
265 case CF_BITMAP:
266 case CF_DIB:
267 case CF_PALETTE:
268 RtlCopyMemory(&Object, pddePoke->Value, sizeof(HGDIOBJ));
269 break;
270 default:
271 break;
272 }
273 break;
274 }
275 case WM_DDE_DATA:
276 {
277 DDEDATA *pddeData2 = Buffer;
278 NT_ASSERT(pddeData2 != NULL);
279 switch(pddeData2->cfFormat)
280 {
281 case CF_BITMAP:
282 case CF_DIB:
283 case CF_PALETTE:
284 RtlCopyMemory(&Object, pddeData2->Value, sizeof(HGDIOBJ));
285 break;
286 default:
287 break;
288 }
289 break;
290 }
291 default:
292 break;
293 }
294
295 if (Object)
296 {
297 // Give gdi object to the other process.
298 GreSetObjectOwner(Object, pWnd->head.pti->ppi->W32Pid);
299 }
300
301 pddeData = ExAllocatePoolWithTag(PagedPool, sizeof(DDE_DATA), USERTAG_DDE5);
302 if (pddeData == NULL)
303 {
304 ERR("Failed to allocate DDE_DATA\n");
305 ExFreePoolWithTag(Buffer, USERTAG_DDE);
306 return FALSE;
307 }
308
309 pddeData->cbSize = size;
310 pddeData->pvBuffer = Buffer;
311 pddeData->lParam = lp;
312
313 TRACE("DDE Post lParam c=%08lx\n",lp);
314 *lParam = lp;
315
316 // Attach this data packet to the user message.
317 *ExtraInfo = (LONG_PTR)pddeData;
318 }
319 return TRUE;
320 }
321
322 //
323 // DDE Get/Peek message hook, take preprocessed information and recombined it for the current Process Thread.
324 //
325 BOOL APIENTRY
326 IntDdeGetMessageHook(PMSG pMsg, LONG_PTR ExtraInfo)
327 {
328 PWND pWnd, pWndClient;
329 PDDE_DATA pddeData;
330 PDDE_PROP pddeProp;
331 BOOL Ret;
332
333 pWnd = UserGetWindowObject(pMsg->hwnd);
334 if (pWnd == NULL)
335 {
336 ERR("DDE Get Window is dead. %p\n", pMsg->hwnd);
337 return TRUE;
338 }
339
340 if (pMsg->message == WM_DDE_TERMINATE)
341 {
342 pddeProp = (PDDE_PROP)UserGetProp(pWnd, AtomDDETrack);
343 if (pddeProp)
344 {
345 pWndClient = UserGetWindowObject((HWND)pMsg->wParam);
346 if (pWndClient == NULL)
347 {
348 ERR("DDE Get Client WM_DDE_TERMINATE\n");
349 }
350
351 UserRemoveProp(pWnd, AtomDDETrack);
352 ExFreePoolWithTag(pddeProp, USERTAG_DDE1);
353 }
354 return TRUE;
355 }
356
357 TRACE("DDE Get Msg 0x%x\n",pMsg->message);
358
359 pddeData = (PDDE_DATA)ExtraInfo;
360
361 if ( pddeData )
362 {
363 TRACE("DDE Get size %d lParam c=%08lx lp c=%08lx\n",pddeData->cbSize, pMsg->lParam, pddeData->lParam);
364
365 // Callback.
366 Ret = IntDDEGetCallback( pWnd, pMsg, pddeData->pvBuffer, pddeData->cbSize);
367 if (!Ret)
368 {
369 ERR("DDE Get CB failed\n");
370 }
371
372 if (pddeData->pvBuffer) ExFreePoolWithTag(pddeData->pvBuffer, USERTAG_DDE);
373
374 ExFreePoolWithTag(pddeData, USERTAG_DDE5);
375
376 return Ret;
377 }
378 TRACE("DDE Get No DDE Data found!\n");
379 return TRUE;
380 }
381
382 //
383 // DDE Send message hook, intercept DDE messages and associate them in a partnership with property.
384 //
385 BOOL FASTCALL
386 IntDdeSendMessageHook(PWND pWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
387 {
388 PWND pWndServer;
389 PDDE_PROP pddeProp;
390
391 if (pWnd->head.pti->ppi != gptiCurrent->ppi)
392 {
393 TRACE("Sending long DDE 0x%x\n",Msg);
394
395 // Allow only Acknowledge and Initiate to be sent across borders.
396 if (Msg != WM_DDE_ACK )
397 {
398 if (Msg == WM_DDE_INITIATE) return TRUE;
399 return FALSE;
400 }
401
402 TRACE("Sending long WM_DDE_ACK\n");
403
404 pWndServer = UserGetWindowObject((HWND)wParam);
405 if (pWndServer == NULL)
406 {
407 ERR("Invalid DDE Server Window handle\n");
408 return FALSE;
409 }
410
411 // Setup property so this conversation can be tracked.
412 pddeProp = ExAllocatePoolWithTag(PagedPool, sizeof(DDE_PROP), USERTAG_DDE1);
413 if (pddeProp == NULL)
414 {
415 ERR("failed to allocate DDE_PROP\n");
416 return FALSE;
417 }
418
419 pddeProp->spwnd = pWndServer;
420 pddeProp->spwndPartner = pWnd;
421
422 UserSetProp(pWndServer, AtomDDETrack, (HANDLE)pddeProp);
423 }
424 return TRUE;
425 }
426
427
428 BOOL
429 APIENTRY
430 NtUserDdeGetQualityOfService(
431 IN HWND hwndClient,
432 IN HWND hWndServer,
433 OUT PSECURITY_QUALITY_OF_SERVICE pqosPrev)
434 {
435 STUB
436
437 return 0;
438 }
439
440 BOOL
441 APIENTRY
442 NtUserDdeSetQualityOfService(
443 IN HWND hwndClient,
444 IN PSECURITY_QUALITY_OF_SERVICE pqosNew,
445 OUT PSECURITY_QUALITY_OF_SERVICE pqosPrev)
446 {
447 STUB
448
449 return 0;
450 }
451
452 BOOL
453 APIENTRY
454 NtUserImpersonateDdeClientWindow(
455 HWND hWndClient,
456 HWND hWndServer)
457 {
458 STUB
459
460 return 0;
461 }
462
463 DWORD
464 APIENTRY
465 NtUserDdeInitialize(
466 DWORD Unknown0,
467 DWORD Unknown1,
468 DWORD Unknown2,
469 DWORD Unknown3,
470 DWORD Unknown4)
471 {
472 STUB
473
474 return 0;
475 }
476