1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 // MARKER(update_precomp.py): autogen include statement, do not remove 24 #include "precompiled_dtrans.hxx" 25 26 #define INCL_DOSERRORS 27 28 #include <stdio.h> 29 #include <string.h> 30 #include <unistd.h> 31 32 #include <rtl/string.hxx> 33 34 #include "OTransferable.hxx" 35 #include "globals.hxx" 36 37 38 OTransferable::OTransferable( HWND hwndTarget, PDRAGINFO dragInfo) 39 : m_aFlavorList( 1), 40 mHwndTarget( hwndTarget), 41 mDragInfo( dragInfo), 42 removeOnExit( false), 43 pDTShare( NULL), 44 renderDRM( DRM_NULL), 45 mimeType( MIMETYPE_NULL) 46 { 47 USHORT cItems; 48 PDRAGITEM dragItem; 49 PSZ pNativeRMF; 50 51 strcpy( fullpath, ""); 52 53 cItems = DrgQueryDragitemCount(dragInfo); 54 if (cItems > 1) { 55 debug_printf("OTransferable::OTransferable multiple drop not supported"); 56 return; 57 } 58 59 ULONG ulLength; 60 PSZ pBuffer; 61 62 // get 1st item 63 dragItem = DrgQueryDragitemPtr(dragInfo, 0); 64 65 // dump true type 66 ulLength = DrgQueryTrueTypeLen( dragItem) + 1; 67 pBuffer = (PSZ) malloc( ulLength); 68 DrgQueryTrueType( dragItem, ulLength, pBuffer); 69 debug_printf("DrgQueryTrueType %s", pBuffer); 70 free( pBuffer); 71 72 // get native RMF format 73 ulLength = DrgQueryNativeRMFLen( dragItem) + 1; 74 pNativeRMF = (PSZ) malloc( ulLength); 75 DrgQueryNativeRMF( dragItem, ulLength, pNativeRMF); 76 debug_printf("OTransferable::OTransferable DrgQueryNativeRMF %s", pNativeRMF); 77 78 debug_printf("OTransferable::OTransferable DrgVerifyRMF DRM_ATOM %d", DrgVerifyRMF( dragItem, "DRM_ATOM", NULL)); 79 debug_printf("OTransferable::OTransferable DrgVerifyRMF DRM_OS2FILE %d", DrgVerifyRMF( dragItem, "DRM_OS2FILE", NULL)); 80 debug_printf("OTransferable::OTransferable DrgVerifyRMF DRM_PRINTOBJECT %d", DrgVerifyRMF( dragItem, "DRM_PRINTOBJECT", NULL)); 81 debug_printf("OTransferable::OTransferable DrgVerifyRMF DRM_SHAREDMEM %d", DrgVerifyRMF( dragItem, "DRM_SHAREDMEM", NULL)); 82 debug_printf("OTransferable::OTransferable DrgVerifyRMF DRM_DTSHARE %d", DrgVerifyRMF( dragItem, "DRM_DTSHARE", NULL)); 83 84 DataFlavor df; 85 86 if (strstr( pNativeRMF, "<DRM_ATOM") != 0 87 || strstr( pNativeRMF, "<DRM_DTSHARE") != 0 88 || strstr( pNativeRMF, "<DRM_SHAREDMEM") != 0) { 89 90 df.MimeType = OUString::createFromAscii( "text/plain;charset=utf-16" ); 91 df.DataType = getCppuType( static_cast<rtl::OUString*>(0)); 92 m_aFlavorList[0] = df; 93 mimeType = MIMETYPE_TEXT; 94 95 } else if (strstr( pNativeRMF, "<DRM_OS2FILE") != 0) { 96 97 df.MimeType = OUString::createFromAscii( 98 "application/x-openoffice-file;windows_formatname=\"FileName\""); 99 df.DataType = getCppuType( static_cast<OUString*>(0)); 100 m_aFlavorList[0] = df; 101 mimeType = MIMETYPE_FILE; 102 103 } else { 104 105 mimeType = MIMETYPE_NULL; 106 debug_printf("OTransferable::OTransferable UNKNOWN native RMF"); 107 108 } 109 110 free( pNativeRMF); 111 112 } 113 114 OTransferable::~OTransferable() 115 { 116 if (removeOnExit) { 117 int rc; 118 rc = unlink( fullpath); 119 debug_printf( "OTransferable::~OTransferable unlink rc=%d", rc); 120 } 121 } 122 123 124 // 125 // a generic request dispatcher 126 // 127 bool OTransferable::RequestFileRendering( PDRAGITEM pditem, HWND hwnd, 128 PCSZ pRMF, PCSZ pName) 129 { 130 PDRAGTRANSFER pdxfer; 131 132 pdxfer = DrgAllocDragtransfer( 1); 133 if (!pdxfer) 134 return true; 135 136 pdxfer->cb = sizeof(DRAGTRANSFER); 137 pdxfer->hwndClient = hwnd; 138 pdxfer->pditem = pditem; 139 pdxfer->hstrSelectedRMF = DrgAddStrHandle( pRMF); 140 pdxfer->hstrRenderToName = 0; 141 pdxfer->ulTargetInfo = pditem->ulItemID; 142 pdxfer->usOperation = (USHORT)DO_COPY; 143 pdxfer->fsReply = 0; 144 145 // send the msg before setting a render-to name 146 if (pditem->fsControl & DC_PREPAREITEM) 147 DrgSendTransferMsg( pditem->hwndItem, DM_RENDERPREPARE, (MPARAM)pdxfer, 0); 148 149 if (pName) 150 pdxfer->hstrRenderToName = DrgAddStrHandle( pName); 151 else 152 pdxfer->hstrRenderToName = 0; 153 154 // send the msg after setting a render-to name 155 if ((pditem->fsControl & (DC_PREPARE | DC_PREPAREITEM)) == DC_PREPARE) 156 DrgSendTransferMsg( pditem->hwndItem, DM_RENDERPREPARE, (MPARAM)pdxfer, 0); 157 158 // ask the source to render the selected item 159 if (!DrgSendTransferMsg( pditem->hwndItem, DM_RENDER, (MPARAM)pdxfer, 0)) 160 return true; 161 162 return false; 163 } 164 165 // currently, the same filename is used for every render request; 166 // it is deleted when the drag session ends 167 // 168 bool OTransferable::RenderToOS2File( PDRAGITEM pditem, HWND hwnd) 169 { 170 bool rv = true; 171 172 const char * pszRMF; 173 if (DrgVerifyRMF(pditem, "DRM_OS2FILE", "DRF_TEXT")) 174 pszRMF = OS2FILE_TXTRMF; 175 else 176 pszRMF = OS2FILE_UNKRMF; 177 178 // create temp name 179 strcpy( fullpath, tempnam( NULL, "AOO")); 180 debug_printf("OTransferable::RenderToOS2File to %s", fullpath); 181 182 rv = RequestFileRendering( pditem, hwnd, pszRMF, fullpath); 183 184 return rv; 185 } 186 187 // DTShare uses 1mb of uncommitted named-shared memory 188 // (next time I'll do it differently - rw) 189 // 190 bool OTransferable::RenderToDTShare( PDRAGITEM pditem, HWND hwnd) 191 { 192 bool rv; 193 194 APIRET rc = DosAllocSharedMem( &pDTShare, DTSHARE_NAME, 0x100000, 195 PAG_WRITE | PAG_READ | OBJ_ANY); 196 if (rc != NO_ERROR && 197 rc != ERROR_ALREADY_EXISTS) { // Did the kernel handle OBJ_ANY? 198 // Try again without OBJ_ANY and if the first failure was not caused 199 // by OBJ_ANY then we will get the same failure, else we have taken 200 // care of pre-FP13 systems where the kernel couldn't handle it. 201 rc = DosAllocSharedMem( &pDTShare, DTSHARE_NAME, 0x100000, 202 PAG_WRITE | PAG_READ); 203 } 204 205 if (rc == ERROR_ALREADY_EXISTS) 206 rc = DosGetNamedSharedMem( &pDTShare, DTSHARE_NAME, 207 PAG_WRITE | PAG_READ); 208 if (rc) 209 rv = true; // error 210 else 211 rv = RequestFileRendering( pditem, hwnd, DTSHARE_RMF, DTSHARE_NAME); 212 213 return rv; 214 } 215 216 // SharedMem rendering, memory is allocated by source window 217 // 218 bool OTransferable::RenderToSharedMem( PDRAGITEM pditem, HWND hwnd) 219 { 220 bool rv; 221 222 rv = RequestFileRendering( pditem, hwnd, SHAREDMEM_RMF, NULL); 223 224 return rv; 225 } 226 227 bool OTransferable::requestRendering( void) 228 { 229 char path[CCHMAXPATH]; 230 char file[CCHMAXPATH]; 231 PDRAGITEM dragItem; 232 233 // unknown rendering 234 renderDRM = DRM_NULL; 235 236 // only 1st item supported 237 dragItem = DrgQueryDragitemPtr( mDragInfo, 0); 238 239 // check if we already have all necessary fields or a rendering 240 // request must be sent to source window 241 242 switch( mimeType) { 243 case MIMETYPE_NULL: 244 debug_printf("OTransferable::requestRendering INTERNAL ERROR, mimetype undef"); 245 break; 246 247 case MIMETYPE_FILE: 248 if (DrgVerifyRMF( dragItem, "DRM_OS2FILE", NULL) 249 && dragItem->hstrSourceName == NULLHANDLE) { 250 251 // if hstrSourceName is NULL we need to ask source for rendering 252 bool rv; 253 debug_printf("OTransferable::requestRendering request rendering"); 254 rv = RenderToOS2File( dragItem, mHwndTarget); 255 debug_printf("OTransferable::requestRendering requested rendering rv=%d", rv); 256 renderDRM = DRM_OS2FILE; 257 258 // notify rendering request ongoing 259 return true; 260 261 } else if (DrgVerifyRMF( dragItem, "DRM_OS2FILE", NULL)) { 262 263 // we have hstrSourceName, no need for rendering, 264 // we already have enough data for rendering path now 265 266 // get full path 267 DrgQueryStrName(dragItem->hstrContainerName, sizeof(path), path); 268 debug_printf("OTransferable::getTransferData hstrSourceName %x", dragItem->hstrSourceName); 269 debug_printf("OTransferable::getTransferData hstrTargetName %x", dragItem->hstrTargetName); 270 DrgQueryStrName(dragItem->hstrSourceName, sizeof(file), file); 271 sprintf( fullpath, "%s%s", path, file); 272 debug_printf("OTransferable::getTransferData fullpath %s", fullpath); 273 renderDRM = DRM_OS2FILE; 274 275 } else { 276 debug_printf("OTransferable::requestRendering UNKNOWN request for FILE mimetype"); 277 } 278 break; 279 280 case MIMETYPE_TEXT: 281 if (DrgVerifyRMF( dragItem, "DRM_ATOM", NULL)) { 282 283 DrgQueryStrName(dragItem->ulItemID, sizeof(fullpath), fullpath); 284 debug_printf("OTransferable::requestRendering DRM_ATOM '%s'", fullpath); 285 renderDRM = DRM_ATOM; 286 287 // no request rendering necessary 288 return false; 289 290 } else if (DrgVerifyRMF( dragItem, "DRM_DTSHARE", NULL)) { 291 292 bool rv; 293 debug_printf("OTransferable::requestRendering request DRM_DTSHARE rendering"); 294 rv = RenderToDTShare( dragItem, mHwndTarget); 295 debug_printf("OTransferable::requestRendering requested DRM_DTSHARE rendering rv=%d", rv); 296 renderDRM = DRM_DTSHARE; 297 298 // notify rendering request ongoing 299 return true; 300 301 } else if (DrgVerifyRMF( dragItem, "DRM_SHAREDMEM", NULL)) { 302 303 bool rv; 304 debug_printf("OTransferable::requestRendering request DRM_SHAREDMEM rendering"); 305 rv = RenderToSharedMem( dragItem, mHwndTarget); 306 debug_printf("OTransferable::requestRendering requested DRM_SHAREDMEM rendering rv=%d", rv); 307 renderDRM = DRM_SHAREDMEM; 308 309 // notify rendering request ongoing 310 return true; 311 312 } else { 313 debug_printf("OTransferable::requestRendering UNKNOWN request for TEXT mimetype"); 314 } 315 break; 316 } 317 318 // request rendering not necessary 319 return false; 320 321 } 322 323 // 324 // AOO window received DM_RENDERCOMPLETE message 325 // 326 bool OTransferable::renderComplete( PDRAGTRANSFER pdxfer) 327 { 328 switch( renderDRM) { 329 case DRM_NULL: 330 // already handled in requestRendering() 331 break; 332 case DRM_ATOM: 333 // set full path from source rendered name string 334 DrgQueryStrName( pdxfer->hstrRenderToName, sizeof(fullpath), fullpath); 335 debug_printf("OTransferable::setDragTransfer fullpath %s", fullpath); 336 break; 337 case DRM_DTSHARE: 338 // handled in getTransferData() 339 break; 340 case DRM_SHAREDMEM: 341 // save pointer 342 pSharedMem = (char *) pdxfer->hstrRenderToName; 343 // extraction handled in getTransferData() 344 break; 345 case DRM_OS2FILE: 346 // we already know the path, no need to use hstrRenderToName 347 debug_printf("OTransferable::setDragTransfer fullpath %s", fullpath); 348 // remove tmp file on destruction 349 removeOnExit = true; 350 break; 351 } 352 353 // send success to source window 354 DrgSendTransferMsg( pdxfer->hwndClient, DM_ENDCONVERSATION, 355 (MPARAM) pdxfer->ulTargetInfo, 356 (MPARAM) DMFL_TARGETSUCCESSFUL); 357 358 // free resources 359 DrgDeleteStrHandle( pdxfer->hstrSelectedRMF); 360 DrgDeleteStrHandle( pdxfer->hstrRenderToName); 361 DrgFreeDragtransfer( pdxfer); 362 363 return false; 364 } 365 366 Any SAL_CALL OTransferable::getTransferData( const DataFlavor& df) 367 throw(UnsupportedFlavorException, IOException, RuntimeException) 368 { 369 OUString m_aData; 370 char * pszText = 0; 371 int pszLen; 372 ULONG size = ~0; 373 ULONG flags = 0; 374 APIRET rc; 375 bool renderOk = false; 376 377 debug_printf("OTransferable::getTransferData MimeType %s", 378 ::rtl::OUStringToOString( df.MimeType, RTL_TEXTENCODING_UTF8 ).getStr()); 379 380 // handle shared memory cases 381 switch( renderDRM) { 382 case DRM_DTSHARE: 383 384 pszLen = ((ULONG*)pDTShare)[0]; 385 pszText = (char*) malloc( pszLen + 1); 386 if (pszText) { 387 strcpy(pszText, &((char*)pDTShare)[sizeof(ULONG)] ); 388 } 389 // using DosGetNamedSharedMem() on memory we allocated appears 390 // to increment its usage ctr, so we have to free it 2x 391 DosFreeMem(pDTShare); 392 DosFreeMem(pDTShare); 393 // reset pointer 394 pDTShare = NULL; 395 396 // prepare data for AOO 397 m_aData = OUString( pszText, pszLen, RTL_TEXTENCODING_UTF8); 398 break; 399 400 case DRM_SHAREDMEM: 401 rc = DosQueryMem((PVOID) pSharedMem, &size, &flags); 402 renderOk = rc == 0; 403 if (renderOk) { 404 renderOk = (flags & (PAG_COMMIT | PAG_READ | PAG_BASE)) == 405 (PAG_COMMIT | PAG_READ | PAG_BASE); 406 } 407 if (renderOk) { 408 ULONG realSize = *(ULONG *) pSharedMem; 409 renderOk = realSize <= size; 410 if (renderOk) { 411 // prepare data for AOO 412 m_aData = OUString( pSharedMem + sizeof(ULONG), realSize, RTL_TEXTENCODING_UTF8); 413 } 414 } 415 // free memory only if it is given by another process, 416 // otherwise DefaultDragWorker will free it 417 if (flags & PAG_SHARED) 418 DosFreeMem((PVOID) pSharedMem); 419 break; 420 421 case DRM_ATOM: 422 case DRM_OS2FILE: 423 // data is in fullpath string 424 // prepare data for AOO 425 m_aData = OUString( fullpath, strlen(fullpath), RTL_TEXTENCODING_UTF8); 426 break; 427 428 default: 429 debug_printf( "OTransferable::getTransferData unsupported DRM_* type %d", 430 renderDRM); 431 break; 432 } 433 434 // return data 435 return makeAny( m_aData ); 436 } 437 438 // ----------------------------------------------------------------------- 439 440 Sequence< DataFlavor > SAL_CALL OTransferable::getTransferDataFlavors( ) 441 throw(RuntimeException) 442 { 443 return m_aFlavorList; 444 } 445 446 // ----------------------------------------------------------------------- 447 448 sal_Bool SAL_CALL OTransferable::isDataFlavorSupported( const DataFlavor& ) 449 throw(RuntimeException) 450 { 451 return sal_True; 452 } 453