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
IntDDEPostCallback(IN PWND pWnd,IN UINT Msg,IN WPARAM wParam,IN OUT LPARAM * lParam,IN OUT PVOID * Buffer)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
IntDDEGetCallback(IN PWND pWnd,IN OUT PMSG pMsg,IN PVOID Buffer,IN int size)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
IntDdePostMessageHook(IN PWND pWnd,IN UINT Msg,IN WPARAM wParam,IN OUT LPARAM * lParam,IN OUT LONG_PTR * ExtraInfo)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
IntDdeGetMessageHook(PMSG pMsg,LONG_PTR ExtraInfo)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, TRUE);
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, TRUE);
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
IntDdeSendMessageHook(PWND pWnd,UINT Msg,WPARAM wParam,LPARAM lParam)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, TRUE);
423 }
424 return TRUE;
425 }
426
427
428 BOOL
429 APIENTRY
NtUserDdeGetQualityOfService(IN HWND hwndClient,IN HWND hWndServer,OUT PSECURITY_QUALITY_OF_SERVICE pqosPrev)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
NtUserDdeSetQualityOfService(IN HWND hwndClient,IN PSECURITY_QUALITY_OF_SERVICE pqosNew,OUT PSECURITY_QUALITY_OF_SERVICE pqosPrev)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
NtUserImpersonateDdeClientWindow(HWND hWndClient,HWND hWndServer)454 NtUserImpersonateDdeClientWindow(
455 HWND hWndClient,
456 HWND hWndServer)
457 {
458 STUB
459
460 return 0;
461 }
462
463 DWORD
464 APIENTRY
NtUserDdeInitialize(DWORD Unknown0,DWORD Unknown1,DWORD Unknown2,DWORD Unknown3,DWORD Unknown4)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
477