xref: /reactos/win32ss/user/user32/misc/dde.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS user32.dll
4  * PURPOSE:          Dynamic Data Exchange
5  * FILE:             win32ss/user/user32/misc/dde.c
6  * PROGRAMER:
7  */
8 
9 #include <user32.h>
10 #include <wine/debug.h>
11 
12 WINE_DEFAULT_DEBUG_CHANNEL(ddeml);
13 
14 
15 BOOL FASTCALL DdeAddPair(HGLOBAL ClientMem, HGLOBAL ServerMem);
16 HGLOBAL FASTCALL DdeGetPair(HGLOBAL ServerMem);
17 
18 
19 /* description of the data fields that need to be packed along with a sent message */
20 struct packed_message
21 {
22     //union packed_structs ps;
23     int         count;
24     const void *data;
25     int         size;
26 };
27 
28 /* add a data field to a packed message */
29 static inline void push_data( struct packed_message *data, const void *ptr, int size )
30 {
31     data->data = ptr;
32     data->size = size;
33     data->count++;
34 }
35 
36 /* pack a pointer into a 32/64 portable format */
37 static inline ULONGLONG pack_ptr( const void *ptr )
38 {
39     return (ULONG_PTR)ptr;
40 }
41 
42 /* unpack a potentially 64-bit pointer, returning 0 when truncated */
43 static inline void *unpack_ptr( ULONGLONG ptr64 )
44 {
45     if ((ULONG_PTR)ptr64 != ptr64) return 0;
46        return (void *)(ULONG_PTR)ptr64;
47 }
48 
49 
50 /***********************************************************************
51  *		post_dde_message
52  *
53  * Post a DDE message
54  */
55 BOOL post_dde_message( struct packed_message *data, UINT message, LPARAM lParam , LPARAM *lp)
56 {
57     void*       ptr = NULL;
58     int         size = 0;
59     UINT_PTR    uiLo, uiHi;
60     HGLOBAL     hunlock = 0;
61     ULONGLONG   hpack;
62 
63     if (!UnpackDDElParam( message, lParam, &uiLo, &uiHi ))
64     {
65         ERR("Unpack failed %x\n",message);
66         return FALSE;
67     }
68 
69     *lp = lParam;
70     switch (message)
71     {
72         /* DDE messages which don't require packing are:
73          * WM_DDE_INITIATE
74          * WM_DDE_TERMINATE
75          * WM_DDE_REQUEST
76          * WM_DDE_UNADVISE
77          */
78     case WM_DDE_ACK:
79         if (HIWORD(uiHi))
80         {
81             /* uiHi should contain a hMem from WM_DDE_EXECUTE */
82             HGLOBAL h = DdeGetPair( (HANDLE)uiHi );
83             if (h)
84             {
85                 hpack = pack_ptr( h );
86                 /* send back the value of h on the other side */
87                 push_data( data, &hpack, sizeof(hpack) );
88                 *lp = uiLo;
89                 TRACE( "send dde-ack %lx %08lx => %p\n", uiLo, uiHi, h );
90             }
91         }
92         else
93         {
94             /* uiHi should contain either an atom or 0 */
95             TRACE( "send dde-ack %lx atom=%lx\n", uiLo, uiHi );
96             *lp = MAKELONG( uiLo, uiHi );
97         }
98         break;
99     case WM_DDE_ADVISE:
100     case WM_DDE_DATA:
101     case WM_DDE_POKE:
102         size = 0;
103         if (uiLo)
104         {
105             size = GlobalSize( (HGLOBAL)uiLo ) ;
106             TRACE("WM_DDE_A D P size %d\n",size);
107             if ( (message == WM_DDE_ADVISE && size < sizeof(DDEADVISE)) ||
108                  (message == WM_DDE_DATA   && size < FIELD_OFFSET(DDEDATA, Value)) ||
109                  (message == WM_DDE_POKE   && size < FIELD_OFFSET(DDEPOKE, Value)) )
110             return FALSE;
111         }
112         else if (message != WM_DDE_DATA)
113         {
114             TRACE("WM_DDE uiLo 0\n");
115             return FALSE;
116         }
117 
118         *lp = uiHi;
119         if (uiLo)
120         {
121             if ((ptr = GlobalLock( (HGLOBAL)uiLo) ))
122             {
123                 DDEDATA *dde_data = ptr;
124                 TRACE("unused %d, fResponse %d, fRelease %d, fDeferUpd %d, fAckReq %d, cfFormat %d\n",
125                        dde_data->unused, dde_data->fResponse, dde_data->fRelease,
126                        dde_data->reserved, dde_data->fAckReq, dde_data->cfFormat);
127                 push_data( data, ptr, size );
128                 hunlock = (HGLOBAL)uiLo;
129             }
130         }
131         TRACE( "send ddepack %u %lx\n", size, uiHi );
132         break;
133     case WM_DDE_EXECUTE:
134         if (lParam)
135         {
136             if ((ptr = GlobalLock( (HGLOBAL)lParam) ))
137             {
138                 size = GlobalSize( (HGLOBAL)lParam );
139                 push_data(data, ptr, size);
140                 /* so that the other side can send it back on ACK */
141                 *lp = lParam;
142                 hunlock = (HGLOBAL)lParam;
143                 TRACE("WM_DDE_EXECUTE text size %d\n",GlobalSize( (HGLOBAL)lParam ));
144             }
145         }
146         break;
147     }
148 
149     FreeDDElParam(message, lParam);
150 
151     if (hunlock) GlobalUnlock(hunlock);
152 
153     return TRUE;
154 }
155 
156 /***********************************************************************
157  *		unpack_dde_message
158  *
159  * Unpack a posted DDE message received from another process.
160  */
161 BOOL unpack_dde_message( HWND hwnd, UINT message, LPARAM *lparam, PVOID buffer, int size )
162 {
163     UINT_PTR	uiLo, uiHi;
164     HGLOBAL	hMem = 0;
165     void*	ptr;
166 
167     TRACE("udm : Size %d\n",size);
168 
169     switch (message)
170     {
171     case WM_DDE_ACK:
172         if (size)
173         {
174             ULONGLONG hpack;
175             /* hMem is being passed */
176             if (size != sizeof(hpack)) return FALSE;
177             if (!buffer) return FALSE;
178             uiLo = *lparam;
179             memcpy( &hpack, buffer, size );
180             hMem = unpack_ptr( hpack );
181             uiHi = (UINT_PTR)hMem;
182             TRACE("recv dde-ack %lx mem=%lx[%lx]\n", uiLo, uiHi, GlobalSize( hMem ));
183         }
184         else
185         {
186             uiLo = LOWORD( *lparam );
187             uiHi = HIWORD( *lparam );
188             TRACE("recv dde-ack %lx atom=%lx\n", uiLo, uiHi);
189         }
190 	*lparam = PackDDElParam( WM_DDE_ACK, uiLo, uiHi );
191 	break;
192     case WM_DDE_ADVISE:
193     case WM_DDE_DATA:
194     case WM_DDE_POKE:
195 	if ((!buffer) && message != WM_DDE_DATA) return FALSE;
196 	uiHi = *lparam;
197         if (size)
198         {
199             if (!(hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, size )))
200                 return FALSE;
201             if ((ptr = GlobalLock( hMem )))
202             {
203                 memcpy( ptr, buffer, size );
204                 GlobalUnlock( hMem );
205             }
206             else
207             {
208                 GlobalFree( hMem );
209                 return FALSE;
210             }
211         }
212         uiLo = (UINT_PTR)hMem;
213 
214 	*lparam = PackDDElParam( message, uiLo, uiHi );
215 	break;
216     case WM_DDE_EXECUTE:
217 	if (size)
218 	{
219 	    if (!buffer) return FALSE;
220             if (!(hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, size ))) return FALSE;
221             if ((ptr = GlobalLock( hMem )))
222 	    {
223 		memcpy( ptr, buffer, size );
224 		GlobalUnlock( hMem );
225                 TRACE( "exec: pairing c=%08lx s=%p\n", *lparam, hMem );
226                 if (!DdeAddPair( (HGLOBAL)*lparam, hMem ))
227                 {
228                     GlobalFree( hMem );
229                     TRACE("udm exec: GF 1\n");
230                     return FALSE;
231                 }
232             }
233             else
234             {
235                 GlobalFree( hMem );
236                 TRACE("udm exec: GF 2\n");
237                 return FALSE;
238             }
239 	}
240 	else
241         {
242 	    TRACE("udm exec: No Size\n");
243 	    return FALSE;
244         }
245 
246         TRACE( "exec: exit c=%08lx s=%p\n", *lparam, hMem );
247         *lparam = (LPARAM)hMem;
248         break;
249     }
250     return TRUE;
251 }
252 
253 //
254 //  DDE Post kernel callback.
255 //
256 NTSTATUS
257 WINAPI
258 User32CallDDEPostFromKernel(PVOID Arguments, ULONG ArgumentLength)
259 {
260   struct packed_message data;
261   BOOL Ret;
262   NTSTATUS Status = STATUS_SUCCESS;
263   PDDEPOSTGET_CALLBACK_ARGUMENTS Common = Arguments;
264 
265   data.data = 0;
266   data.size = 0;
267   TRACE("DDE Post CB\n");
268   Ret = post_dde_message( &data, Common->message, Common->lParam, &Common->lParam);
269 
270   if (Ret)
271   {
272      Common->pvData = (PVOID)data.data;
273      Common->size = data.size;
274      TRACE("DDE Post CB size %d\n",data.size);
275   }
276   else
277   {
278      ERR("DDE Post CB Return bad msg 0x%x Size %d\n",Common->message,Common->size);
279      Status = STATUS_UNSUCCESSFUL;
280   }
281 
282   return ZwCallbackReturn(Arguments, ArgumentLength, Status);
283 }
284 
285 //
286 //  DDE Get/Peek kernel callback.
287 //
288 NTSTATUS
289 WINAPI
290 User32CallDDEGetFromKernel(PVOID Arguments, ULONG ArgumentLength)
291 {
292   BOOL Ret;
293   NTSTATUS Status = STATUS_SUCCESS;
294   PDDEPOSTGET_CALLBACK_ARGUMENTS Common = Arguments;
295 
296   TRACE("DDE Get CB size %d\n",Common->size);
297 
298   Ret = unpack_dde_message( Common->hwnd, Common->message, &Common->lParam, Common->buffer, Common->size );
299 
300   if (!Ret)
301   {
302      ERR("DDE Get CB Return bad msg 0x%x\n",Common->message);
303      Status = STATUS_UNSUCCESSFUL;
304   }
305   return ZwCallbackReturn(Arguments, ArgumentLength, Status);
306 }
307 
308 
309 /*
310  * @unimplemented
311  */
312 BOOL WINAPI DdeGetQualityOfService(HWND hWnd, DWORD Reserved, PSECURITY_QUALITY_OF_SERVICE pqosPrev)
313 {
314   UNIMPLEMENTED;
315   return FALSE;
316 }
317