xref: /reactos/win32ss/user/ntuser/dde.c (revision 845faec4)
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, 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
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
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 
477