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