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