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