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 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_dtrans.hxx" 26 #include "FmtFilter.hxx" 27 #include <osl/diagnose.h> 28 #include <comphelper/sequence.hxx> 29 30 #if defined _MSC_VER 31 #pragma warning(push,1) 32 #pragma warning(disable:4917) 33 #endif 34 #include <Shobjidl.h> 35 #include <shlguid.h> 36 #include <ObjIdl.h> 37 #include <shellapi.h> 38 #if defined _MSC_VER 39 #pragma warning(pop) 40 #endif 41 42 #include <string> 43 #include <sstream> 44 #include <vector> 45 #include <iomanip> 46 47 #include <systools/win32/comtools.hxx> 48 49 using namespace com::sun::star::uno; 50 using rtl::OString; 51 52 #pragma pack(2) 53 struct METAFILEHEADER 54 { 55 DWORD key; 56 short hmf; 57 SMALL_RECT bbox; 58 WORD inch; 59 DWORD reserved; 60 WORD checksum; 61 }; 62 #pragma pack() 63 64 //------------------------------------------------------------------------ 65 // convert a windows metafile picture to a openoffice metafile picture 66 //------------------------------------------------------------------------ 67 68 Sequence< sal_Int8 > SAL_CALL WinMFPictToOOMFPict( Sequence< sal_Int8 >& aMetaFilePict ) 69 { 70 OSL_ASSERT( aMetaFilePict.getLength( ) == sizeof( METAFILEPICT ) ); 71 72 Sequence< sal_Int8 > mfpictStream; 73 METAFILEPICT* pMFPict = reinterpret_cast< METAFILEPICT* >( aMetaFilePict.getArray( ) ); 74 HMETAFILE hMf = pMFPict->hMF; 75 sal_uInt32 nCount = GetMetaFileBitsEx( hMf, 0, NULL ); 76 77 if ( nCount > 0 ) 78 { 79 mfpictStream.realloc( nCount + sizeof( METAFILEHEADER ) ); 80 81 METAFILEHEADER* pMFHeader = reinterpret_cast< METAFILEHEADER* >( mfpictStream.getArray( ) ); 82 SMALL_RECT aRect = { 0, 83 0, 84 static_cast< short >( pMFPict->xExt ), 85 static_cast< short >( pMFPict->yExt ) }; 86 USHORT nInch; 87 88 switch( pMFPict->mm ) 89 { 90 case MM_TEXT: 91 nInch = 72; 92 break; 93 94 case MM_LOMETRIC: 95 nInch = 100; 96 break; 97 98 case MM_HIMETRIC: 99 nInch = 1000; 100 break; 101 102 case MM_LOENGLISH: 103 nInch = 254; 104 break; 105 106 case MM_HIENGLISH: 107 case MM_ISOTROPIC: 108 case MM_ANISOTROPIC: 109 nInch = 2540; 110 break; 111 112 case MM_TWIPS: 113 nInch = 1440; 114 break; 115 116 default: 117 nInch = 576; 118 } 119 120 pMFHeader->key = 0x9AC6CDD7L; 121 pMFHeader->hmf = 0; 122 pMFHeader->bbox = aRect; 123 pMFHeader->inch = nInch; 124 pMFHeader->reserved = 0; 125 pMFHeader->checksum = 0; 126 127 char* pMFBuff = reinterpret_cast< char* >( mfpictStream.getArray( ) ); 128 129 nCount = GetMetaFileBitsEx( pMFPict->hMF, nCount, pMFBuff + sizeof( METAFILEHEADER ) ); 130 OSL_ASSERT( nCount > 0 ); 131 } 132 133 return mfpictStream; 134 } 135 136 //------------------------------------------------------------- 137 // convert a windows enhanced metafile to a openoffice metafile 138 //------------------------------------------------------------- 139 140 Sequence< sal_Int8 > SAL_CALL WinENHMFPictToOOMFPict( HENHMETAFILE hEnhMetaFile ) 141 { 142 Sequence< sal_Int8 > aRet; 143 UINT nSize = 0; 144 145 if( hEnhMetaFile && 146 ( ( nSize = GetEnhMetaFileBits( hEnhMetaFile, 0, NULL ) ) != 0 ) ) 147 { 148 aRet.realloc( nSize ); 149 150 if( GetEnhMetaFileBits( hEnhMetaFile, nSize, (sal_uChar*) aRet.getArray() ) != nSize ) 151 aRet.realloc( 0 ); 152 } 153 154 return aRet; 155 } 156 157 //------------------------------------------------------------------------ 158 // convert a openoffice metafile picture to a windows metafile picture 159 //------------------------------------------------------------------------ 160 161 HMETAFILEPICT SAL_CALL OOMFPictToWinMFPict( Sequence< sal_Int8 >& aOOMetaFilePict ) 162 { 163 HMETAFILEPICT hPict = NULL; 164 HMETAFILE hMtf = SetMetaFileBitsEx( aOOMetaFilePict.getLength(), (sal_uChar*) aOOMetaFilePict.getConstArray() ); 165 166 if( hMtf ) 167 { 168 METAFILEPICT* pPict = (METAFILEPICT*) GlobalLock( hPict = GlobalAlloc( GHND, sizeof( METAFILEPICT ) ) ); 169 170 pPict->mm = 8; 171 pPict->xExt = 0; 172 pPict->yExt = 0; 173 pPict->hMF = hMtf; 174 175 GlobalUnlock( hPict ); 176 } 177 178 return hPict; 179 } 180 181 //----------------------------------------------------------------------------- 182 // convert a openoffice metafile picture to a windows enhanced metafile picture 183 //----------------------------------------------------------------------------- 184 185 HENHMETAFILE SAL_CALL OOMFPictToWinENHMFPict( Sequence< sal_Int8 >& aOOMetaFilePict ) 186 { 187 HENHMETAFILE hEnhMtf = SetEnhMetaFileBits( aOOMetaFilePict.getLength(), (sal_uChar*) aOOMetaFilePict.getConstArray() ); 188 189 return hEnhMtf; 190 } 191 192 //------------------------------------------------------------------------ 193 // convert a windows device independent bitmap into a openoffice bitmap 194 //------------------------------------------------------------------------ 195 196 Sequence< sal_Int8 > SAL_CALL WinDIBToOOBMP( const Sequence< sal_Int8 >& aWinDIB ) 197 { 198 OSL_ASSERT( aWinDIB.getLength( ) > sizeof( BITMAPINFOHEADER ) ); 199 200 Sequence< sal_Int8 > ooBmpStream; 201 202 ooBmpStream.realloc( aWinDIB.getLength( ) + sizeof(BITMAPFILEHEADER) ); 203 204 const BITMAPINFOHEADER *pBmpInfoHdr = (const BITMAPINFOHEADER*)aWinDIB.getConstArray(); 205 BITMAPFILEHEADER *pBmpFileHdr = reinterpret_cast< BITMAPFILEHEADER* >( ooBmpStream.getArray() ); 206 DWORD nOffset = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ); 207 208 rtl_copyMemory( pBmpFileHdr + 1, pBmpInfoHdr, aWinDIB.getLength( ) ); 209 210 if( pBmpInfoHdr->biBitCount <= 8 ) 211 nOffset += ( pBmpInfoHdr->biClrUsed ? pBmpInfoHdr->biClrUsed : ( 1 << pBmpInfoHdr->biBitCount ) ) << 2; 212 else if( ( BI_BITFIELDS == pBmpInfoHdr->biCompression ) && ( ( 16 == pBmpInfoHdr->biBitCount ) || ( 32 == pBmpInfoHdr->biBitCount ) ) ) 213 nOffset += 12; 214 215 pBmpFileHdr->bfType = 'MB'; 216 pBmpFileHdr->bfSize = 0; // maybe: nMemSize + sizeof(BITMAPFILEHEADER) 217 pBmpFileHdr->bfReserved1 = 0; 218 pBmpFileHdr->bfReserved2 = 0; 219 pBmpFileHdr->bfOffBits = nOffset; 220 221 return ooBmpStream; 222 } 223 224 //------------------------------------------------------------------------ 225 // convert a openoffice bitmap into a windows device independent bitmap 226 //------------------------------------------------------------------------ 227 228 Sequence< sal_Int8 > SAL_CALL OOBmpToWinDIB( Sequence< sal_Int8 >& aOOBmp ) 229 { 230 OSL_ASSERT( aOOBmp.getLength( ) > 231 ( sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) ) ); 232 233 Sequence< sal_Int8 > winDIBStream( aOOBmp.getLength( ) - sizeof( BITMAPFILEHEADER ) ); 234 235 rtl_copyMemory( winDIBStream.getArray( ), 236 aOOBmp.getArray( ) + sizeof( BITMAPFILEHEADER ), 237 aOOBmp.getLength( ) - sizeof( BITMAPFILEHEADER ) ); 238 239 return winDIBStream; 240 } 241 242 //------------------------------------------------------------------------------ 243 // converts the openoffice text/html clipboard format to the HTML Format 244 // well known under MS Windows 245 // the MS HTML Format has a header before the real html data 246 // 247 // Version:1.0 Version number of the clipboard. Staring is 0.9 248 // StartHTML: Byte count from the beginning of the clipboard to the start 249 // of the context, or -1 if no context 250 // EndHTML: Byte count from the beginning of the clipboard to the end 251 // of the context, or -1 if no context 252 // StartFragment: Byte count from the beginning of the clipboard to the 253 // start of the fragment 254 // EndFragment: Byte count from the beginning of the clipboard to the 255 // end of the fragment 256 // StartSelection: Byte count from the beginning of the clipboard to the 257 // start of the selection 258 // EndSelection: Byte count from the beginning of the clipboard to the 259 // end of the selection 260 // 261 // StartSelection and EndSelection are optional 262 // The fragment should be preceded and followed by the HTML comments 263 // <!--StartFragment--> and <!--EndFragment--> (no space between !-- and the 264 // text 265 //------------------------------------------------------------------------------ 266 /* 267 Sequence< sal_Int8 > SAL_CALL TextHtmlToHTMLFormat( Sequence< sal_Int8 >& aTextHtml ) 268 { 269 OSL_ASSERT( aTextHtml.getLength( ) > 0 ); 270 271 // check parameter 272 if ( !(aTextHtml.getLength( ) > 0) ) 273 return Sequence< sal_Int8 >( ); 274 275 // we create a buffer with the approximated size of 276 // the HTML Format header 277 char aHTMLFmtHdr[120]; 278 279 rtl_zeroMemory( aHTMLFmtHdr, sizeof( aHTMLFmtHdr ) ); 280 281 // fill the buffer with dummy values to calc the 282 // exact length 283 284 wsprintf( 285 aHTMLFmtHdr, 286 "Version:1.0\nStartHTML:%010d\r\nnEndHTML:%010d\r\nStartFragment:%010\r\nnEndFragment:%010d\r\n", 0, 0, 0, 0 ); 287 288 sal_uInt32 lHTMLFmtHdr = rtl_str_getLength( aHTMLFmtHdr ); 289 290 // the office allways writes the start 291 // and end html tag in upper cases and 292 // without spaces 293 // both tags don't allow parameters 294 OString startHtmlTag( "<HTML>" ); 295 OString endHtmlTag( "</HTML>" ); 296 297 // we don't include '>' into the search 298 // because the body tag allows parameters 299 // e.g. <BODY param> 300 // #92840# 301 OString startBodyTag( "<BODY" ); 302 OString endBodyTag( "</BODY" ); 303 304 OString textHtml( 305 reinterpret_cast< const sal_Char* >( aTextHtml.getConstArray( ) ), 306 aTextHtml.getLength( ) ); 307 308 sal_Int32 nStartHtml = textHtml.indexOf( startHtmlTag ); 309 sal_Int32 nEndHtml = textHtml.indexOf( endHtmlTag ); 310 sal_Int32 nStartFrgmt = textHtml.indexOf( startBodyTag ); 311 sal_Int32 nEndFrgmt = textHtml.indexOf( endBodyTag ); 312 313 OSL_ASSERT( (nStartHtml >= 0) && (nEndHtml > nStartHtml) && (nStartFrgmt > nStartHtml) && (nEndFrgmt > nStartFrgmt) ); 314 315 Sequence< sal_Int8 > aHTMLFmtSequence; 316 317 if ( (nStartHtml > -1) && (nEndHtml > -1) && (nStartFrgmt > -1) && (nEndFrgmt > -1) ) 318 { 319 nStartHtml = nStartHtml + lHTMLFmtHdr - 1; // we start one before <HTML> Word 2000 does also so 320 nEndHtml = nEndHtml + lHTMLFmtHdr + endHtmlTag.getLength( ) + 1; // our SOffice 5.2 wants 2 behind </HTML>? 321 nStartFrgmt = nStartFrgmt + startBodyTag.getLength( ) + lHTMLFmtHdr; // after the <BODY> tag 322 nEndFrgmt = nEndFrgmt + lHTMLFmtHdr; 323 324 // fill the html header 325 rtl_zeroMemory( aHTMLFmtHdr, sizeof( aHTMLFmtHdr ) ); 326 327 wsprintf( 328 aHTMLFmtHdr, 329 "Version:1.0\nStartHTML:%010d\r\nEndHTML:%010d\r\nStartFragment:%010d\r\nEndFragment:%010d\r\n", 330 nStartHtml, nEndHtml, nStartFrgmt, nEndFrgmt ); 331 332 // we add space for a trailing \0 333 aHTMLFmtSequence.realloc( lHTMLFmtHdr + aTextHtml.getLength( ) + 1 ); 334 rtl_zeroMemory( aHTMLFmtSequence.getArray( ), aHTMLFmtSequence.getLength( ) ); 335 336 // copy the HTML Format header 337 rtl_copyMemory( 338 static_cast< LPVOID >( aHTMLFmtSequence.getArray( ) ), 339 static_cast< LPVOID >( aHTMLFmtHdr ), lHTMLFmtHdr ); 340 341 // concat the text/html 342 rtl_copyMemory( 343 static_cast< LPVOID >( aHTMLFmtSequence.getArray( ) + lHTMLFmtHdr ), 344 static_cast< LPVOID >( aTextHtml.getArray( ) ), 345 aTextHtml.getLength( ) ); 346 } 347 348 return aHTMLFmtSequence; 349 } 350 */ 351 352 std::string GetHtmlFormatHeader(size_t startHtml, size_t endHtml, size_t startFragment, size_t endFragment) 353 { 354 std::ostringstream htmlHeader; 355 htmlHeader << "Version:1.0" << '\r' << '\n'; 356 htmlHeader << "StartHTML:" << std::setw(10) << std::setfill('0') << std::dec << startHtml << '\r' << '\n'; 357 htmlHeader << "EndHTML:" << std::setw(10) << std::setfill('0') << std::dec << endHtml << '\r' << '\n'; 358 htmlHeader << "StartFragment:" << std::setw(10) << std::setfill('0') << std::dec << startFragment << '\r' << '\n'; 359 htmlHeader << "EndFragment:" << std::setw(10) << std::setfill('0') << std::dec << endFragment << '\r' << '\n'; 360 return htmlHeader.str(); 361 } 362 363 // the office allways writes the start and end html tag in upper cases and 364 // without spaces both tags don't allow parameters 365 const std::string TAG_HTML = std::string("<HTML>"); 366 const std::string TAG_END_HTML = std::string("</HTML>"); 367 368 // The body tag may have parameters so we need to search for the 369 // closing '>' manually e.g. <BODY param> #92840# 370 const std::string TAG_BODY = std::string("<BODY"); 371 const std::string TAG_END_BODY = std::string("</BODY"); 372 373 Sequence<sal_Int8> SAL_CALL TextHtmlToHTMLFormat(Sequence<sal_Int8>& aTextHtml) 374 { 375 OSL_ASSERT(aTextHtml.getLength() > 0); 376 377 if (!(aTextHtml.getLength() > 0)) 378 return Sequence<sal_Int8>(); 379 380 // fill the buffer with dummy values to calc the exact length 381 std::string dummyHtmlHeader = GetHtmlFormatHeader(0, 0, 0, 0); 382 size_t lHtmlFormatHeader = dummyHtmlHeader.length(); 383 384 std::string textHtml( 385 reinterpret_cast<const sal_Char*>(aTextHtml.getConstArray()), 386 reinterpret_cast<const sal_Char*>(aTextHtml.getConstArray()) + aTextHtml.getLength()); 387 388 std::string::size_type nStartHtml = textHtml.find(TAG_HTML) + lHtmlFormatHeader - 1; // we start one before '<HTML>' Word 2000 does also so 389 std::string::size_type nEndHtml = textHtml.find(TAG_END_HTML) + lHtmlFormatHeader + TAG_END_HTML.length() + 1; // our SOffice 5.2 wants 2 behind </HTML>? 390 391 // The body tag may have parameters so we need to search for the 392 // closing '>' manually e.g. <BODY param> #92840# 393 std::string::size_type nStartFragment = textHtml.find(">", textHtml.find(TAG_BODY)) + lHtmlFormatHeader + 1; 394 std::string::size_type nEndFragment = textHtml.find(TAG_END_BODY) + lHtmlFormatHeader; 395 396 std::string htmlFormat = GetHtmlFormatHeader(nStartHtml, nEndHtml, nStartFragment, nEndFragment); 397 htmlFormat += textHtml; 398 399 Sequence<sal_Int8> byteSequence(htmlFormat.length() + 1); // space the trailing '\0' 400 rtl_zeroMemory(byteSequence.getArray(), byteSequence.getLength()); 401 402 rtl_copyMemory( 403 static_cast<void*>(byteSequence.getArray()), 404 static_cast<const void*>(htmlFormat.c_str()), 405 htmlFormat.length()); 406 407 return byteSequence; 408 } 409 410 std::wstring getFileExtension(const std::wstring& aFilename) 411 { 412 std::wstring::size_type idx = aFilename.rfind(L"."); 413 if ((idx != std::wstring::npos)) 414 { 415 return std::wstring(aFilename, idx); 416 } 417 return std::wstring(); 418 } 419 420 const std::wstring SHELL_LINK_FILE_EXTENSION = L".lnk"; 421 422 bool isShellLink(const std::wstring& aFilename) 423 { 424 std::wstring ext = getFileExtension(aFilename); 425 return (_wcsicmp(ext.c_str(), SHELL_LINK_FILE_EXTENSION.c_str()) == 0); 426 } 427 428 /** Resolve a Windows Shell Link (lnk) file. If a resolution 429 is not possible simply return the provided name of the 430 lnk file. */ 431 std::wstring getShellLinkTarget(const std::wstring& aLnkFile) 432 { 433 OSL_ASSERT(isShellLink(aLnkFile)); 434 435 std::wstring target = aLnkFile; 436 437 try 438 { 439 sal::systools::COMReference<IShellLinkA> pIShellLink; 440 HRESULT hr = CoCreateInstance( 441 CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, reinterpret_cast<LPVOID*>(&pIShellLink)); 442 if (FAILED(hr)) 443 return target; 444 445 sal::systools::COMReference<IPersistFile> pIPersistFile = 446 pIShellLink.QueryInterface<IPersistFile>(IID_IPersistFile); 447 448 hr = pIPersistFile->Load(aLnkFile.c_str(), STGM_READ); 449 if (FAILED(hr)) 450 return target; 451 452 hr = pIShellLink->Resolve(NULL, SLR_UPDATE | SLR_NO_UI); 453 if (FAILED(hr)) 454 return target; 455 456 char pathA[MAX_PATH]; 457 WIN32_FIND_DATA wfd; 458 hr = pIShellLink->GetPath(pathA, MAX_PATH, &wfd, SLGP_RAWPATH); 459 if (FAILED(hr)) 460 return target; 461 462 wchar_t pathW[MAX_PATH]; 463 MultiByteToWideChar(CP_ACP, 0, pathA, -1, pathW, MAX_PATH); 464 target = pathW; 465 } 466 catch(sal::systools::ComError& ex) 467 { 468 OSL_ENSURE(false, ex.what()); 469 ex = ex; 470 } 471 return target; 472 } 473 474 typedef std::vector<std::wstring> FileList_t; 475 typedef FileList_t::value_type FileList_ValueType_t; 476 typedef Sequence<sal_Int8> ByteSequence_t; 477 478 /* Calculate the size required for turning a string list into 479 a double '\0' terminated string buffer */ 480 size_t CalcSizeForStringListBuffer(const FileList_t& fileList) 481 { 482 if (fileList.size() == 0) 483 return 0; 484 485 size_t size = 1; // one for the very final '\0' 486 FileList_t::const_iterator iter_end = fileList.end(); 487 for (FileList_t::const_iterator iter = fileList.begin(); iter != iter_end; ++iter) 488 { 489 size += iter->length() + 1; // length including terminating '\0' 490 } 491 return (size * sizeof(FileList_ValueType_t::value_type)); 492 } 493 494 ByteSequence_t FileListToByteSequence(const FileList_t& fileList) 495 { 496 ByteSequence_t bseq; 497 size_t size = CalcSizeForStringListBuffer(fileList); 498 499 if (size > 0) 500 { 501 bseq.realloc(size); 502 wchar_t* p = reinterpret_cast<wchar_t*>(bseq.getArray()); 503 ZeroMemory(p, size); 504 505 FileList_t::const_iterator iter; 506 FileList_t::const_iterator iter_end = fileList.end(); 507 for (iter = fileList.begin(); iter != iter_end; ++iter) 508 { 509 wcsncpy(p, iter->c_str(), iter->length()); 510 p += (iter->length() + 1); 511 } 512 } 513 return bseq; 514 } 515 516 ByteSequence_t CF_HDROPToFileList(HGLOBAL hGlobal) 517 { 518 UINT nFiles = DragQueryFileW((HDROP)hGlobal, 0xFFFFFFFF, NULL, 0); 519 FileList_t files; 520 521 for (UINT i = 0; i < nFiles; i++) 522 { 523 wchar_t buff[MAX_PATH]; 524 /*UINT size =*/ DragQueryFileW((HDROP)hGlobal, i, buff, MAX_PATH); 525 std::wstring filename = buff; 526 if (isShellLink(filename)) 527 filename = getShellLinkTarget(filename); 528 files.push_back(filename); 529 } 530 return FileListToByteSequence(files); 531 } 532 533 //------------------------------------------------------------------------ 534 // convert a windows bitmap handle into a openoffice bitmap 535 //------------------------------------------------------------------------ 536 537 Sequence< sal_Int8 > SAL_CALL WinBITMAPToOOBMP( HBITMAP aHBMP ) 538 { 539 Sequence< sal_Int8 > ooBmpStream; 540 541 SIZE aBmpSize; 542 if( GetBitmapDimensionEx( aHBMP, &aBmpSize ) ) 543 { 544 // fill bitmap info header 545 size_t nDataBytes = 4 * aBmpSize.cy * aBmpSize.cy; 546 Sequence< sal_Int8 > aBitmapStream( 547 sizeof(BITMAPINFO) + 548 nDataBytes 549 ); 550 PBITMAPINFOHEADER pBmp = (PBITMAPINFOHEADER)aBitmapStream.getArray(); 551 pBmp->biSize = sizeof( BITMAPINFOHEADER ); 552 pBmp->biWidth = aBmpSize.cx; 553 pBmp->biHeight = aBmpSize.cy; 554 pBmp->biPlanes = 1; 555 pBmp->biBitCount = 32; 556 pBmp->biCompression = BI_RGB; 557 pBmp->biSizeImage = (DWORD)nDataBytes; 558 pBmp->biXPelsPerMeter = 1000; 559 pBmp->biYPelsPerMeter = 1000; 560 pBmp->biClrUsed = 0; 561 pBmp->biClrImportant = 0; 562 if( GetDIBits( 0, // DC, 0 is a default GC, basically that of the desktop 563 aHBMP, 564 0, aBmpSize.cy, 565 aBitmapStream.getArray() + sizeof(BITMAPINFO), 566 (LPBITMAPINFO)pBmp, 567 DIB_RGB_COLORS ) ) 568 { 569 ooBmpStream = WinDIBToOOBMP( aBitmapStream ); 570 } 571 } 572 573 return ooBmpStream; 574 } 575 576