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