[USER32] Add wine/debug.h to the PCH and remove an unneeded wine/unicode.h inclusion.
[reactos.git] / win32ss / user / user32 / misc / dde.c
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 }