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