Added support for nested exceptions happening inside a catch block.
[wine/multimedia.git] / dlls / msvideo / msvideo_main.c
blob9fbc380aef2c513bf124af06622cfff471f018ea
1 /*
2 * Copyright 1998 Marcus Meissner
3 * Copyright 2000 Bradley Baetz
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * FIXME: This all assumes 32 bit codecs
20 * Win95 appears to prefer 32 bit codecs, even from 16 bit code.
21 * There is the ICOpenFunction16 to worry about still, though.
24 #include <stdio.h>
25 #include <string.h>
27 #include "winbase.h"
28 #include "windef.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "vfw.h"
32 #include "wine/winbase16.h"
33 #include "wine/debug.h"
34 #include "msvideo_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(msvideo);
38 LRESULT (CALLBACK *pFnCallTo16)(HDRVR, HIC, UINT, LPARAM, LPARAM) = NULL;
40 /***********************************************************************
41 * VideoForWindowsVersion [MSVFW32.2]
42 * VideoForWindowsVersion [MSVIDEO.2]
43 * Returns the version in major.minor form.
44 * In Windows95 this returns 0x040003b6 (4.950)
46 DWORD WINAPI VideoForWindowsVersion(void)
48 return 0x040003B6; /* 4.950 */
51 /* system.ini: [drivers] */
53 /***********************************************************************
54 * ICInfo [MSVFW32.@]
55 * Get information about an installable compressor. Return TRUE if there
56 * is one.
58 BOOL VFWAPI ICInfo(
59 DWORD fccType, /* [in] type of compressor ('vidc') */
60 DWORD fccHandler, /* [in] <n>th compressor */
61 ICINFO *lpicinfo) /* [out] information about compressor */
63 char type[5],buf[2000];
65 memcpy(type,&fccType,4);type[4]=0;
66 TRACE("(%s,%ld,%p).\n",type,fccHandler,lpicinfo);
67 /* does OpenDriver/CloseDriver */
68 lpicinfo->dwSize = sizeof(ICINFO);
69 lpicinfo->fccType = fccType;
70 lpicinfo->dwFlags = 0;
71 if (GetPrivateProfileStringA("drivers32",NULL,NULL,buf,2000,"system.ini")) {
72 char *s = buf;
73 while (*s) {
74 if (!strncasecmp(type,s,4)) {
75 if(!fccHandler--) {
76 lpicinfo->fccHandler = mmioStringToFOURCCA(s+5,0);
77 return TRUE;
80 s=s+strlen(s)+1; /* either next char or \0 */
83 return FALSE;
86 /***********************************************************************
87 * ICOpen [MSVFW32.@]
88 * Opens an installable compressor. Return special handle.
90 HIC VFWAPI ICOpen(DWORD fccType,DWORD fccHandler,UINT wMode) {
91 char type[5],handler[5],codecname[20];
92 ICOPEN icopen;
93 HDRVR hdrv;
94 HIC hic;
95 WINE_HIC *whic;
96 BOOL bIs16;
98 memcpy(type,&fccType,4);type[4]=0;
99 memcpy(handler,&fccHandler,4);handler[4]=0;
100 TRACE("(%s,%s,0x%08lx)\n",type,handler,(DWORD)wMode);
102 sprintf(codecname,"%s.%s",type,handler);
104 /* Well, lParam2 is in fact a LPVIDEO_OPEN_PARMS, but it has the
105 * same layout as ICOPEN
107 icopen.dwSize = sizeof(ICOPEN);
108 icopen.fccType = fccType;
109 icopen.fccHandler = fccHandler;
110 icopen.dwVersion = 0x00001000; /* FIXME */
111 icopen.dwFlags = wMode;
112 icopen.dwError = 0;
113 icopen.pV1Reserved = NULL;
114 icopen.pV2Reserved = NULL;
115 icopen.dnDevNode = 0; /* FIXME */
117 hdrv=OpenDriverA(codecname,"drivers32",(LPARAM)&icopen);
118 if (!hdrv) {
119 if (!strcasecmp(type,"vids")) {
120 sprintf(codecname,"vidc.%s",handler);
121 fccType = mmioFOURCC('v','i','d','c');
123 hdrv=OpenDriverA(codecname,"drivers32",(LPARAM)&icopen);
124 if (!hdrv)
125 return 0;
127 bIs16 = GetDriverFlags(hdrv) & WINE_GDF_16BIT;
129 if (bIs16 && !pFnCallTo16)
131 FIXME("Got a 16 bit driver, but no 16 bit support in msvfw\n");
132 return 0;
134 /* The handle should be a valid 16-bit handle as well */
135 hic = HIC_32(GlobalAlloc16(GHND,sizeof(WINE_HIC)));
136 whic = (WINE_HIC*)GlobalLock16(HIC_16(hic));
137 whic->hdrv = hdrv;
138 /* FIXME: is the signature the real one ? */
139 whic->driverproc = bIs16 ? (DRIVERPROC)pFnCallTo16 : NULL;
140 whic->driverproc16 = NULL;
142 GlobalUnlock16(HIC_16(hic));
143 TRACE("=> %p\n",hic);
144 return HIC_32(hic);
147 /***********************************************************************
148 * MSVIDEO_OpenFunction
150 HIC MSVIDEO_OpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode,
151 DRIVERPROC lpfnHandler, DRIVERPROC16 lpfnHandler16)
153 char type[5],handler[5],codecname[20];
154 HIC hic;
155 ICOPEN icopen;
156 WINE_HIC *whic;
158 memcpy(type,&fccType,4);type[4]=0;
159 memcpy(handler,&fccHandler,4);handler[4]=0;
160 TRACE("(%s,%s,%d,%p,%p)\n",type,handler,wMode,lpfnHandler,lpfnHandler16);
162 icopen.fccType = fccType;
163 icopen.fccHandler = fccHandler;
164 icopen.dwSize = sizeof(ICOPEN);
165 icopen.dwFlags = wMode;
167 sprintf(codecname,"%s.%s",type,handler);
169 hic = HIC_32(GlobalAlloc16(GHND,sizeof(WINE_HIC)));
170 if (!hic)
171 return 0;
172 whic = GlobalLock16(HIC_16(hic));
173 whic->driverproc = lpfnHandler;
174 whic->driverproc16 = lpfnHandler16;
176 /* Now try opening/loading the driver. Taken from DRIVER_AddToList */
177 /* What if the function is used more than once? */
179 if (MSVIDEO_SendMessage(hic,DRV_LOAD,0L,0L) != DRV_SUCCESS) {
180 WARN("DRV_LOAD failed for hic %p\n", hic);
181 GlobalFree16(HIC_16(hic));
182 return 0;
184 /* return value is not checked */
185 MSVIDEO_SendMessage(hic,DRV_ENABLE,0L,0L);
187 whic->hdrv = (HDRVR)MSVIDEO_SendMessage(hic,DRV_OPEN,0,(DWORD)&icopen);
189 if (whic->hdrv == 0) {
190 WARN("DRV_OPEN failed for hic %p\n",hic);
191 GlobalFree16(HIC_16(hic));
192 return 0;
195 GlobalUnlock16(HIC_16(hic));
196 TRACE("=> %p\n",hic);
197 return hic;
200 /***********************************************************************
201 * ICOpenFunction [MSVFW32.@]
203 HIC VFWAPI ICOpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode, FARPROC lpfnHandler)
205 return MSVIDEO_OpenFunction(fccType, fccHandler, wMode, (DRIVERPROC)lpfnHandler, NULL);
208 /***********************************************************************
209 * ICGetInfo [MSVFW32.@]
211 LRESULT VFWAPI ICGetInfo(HIC hic,ICINFO *picinfo,DWORD cb) {
212 LRESULT ret;
214 TRACE("(%p,%p,%ld)\n",hic,picinfo,cb);
215 ret = ICSendMessage(hic,ICM_GETINFO,(DWORD)picinfo,cb);
216 TRACE(" -> 0x%08lx\n",ret);
217 return ret;
220 /***********************************************************************
221 * ICLocate [MSVFW32.@]
223 HIC VFWAPI ICLocate(
224 DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn,
225 LPBITMAPINFOHEADER lpbiOut, WORD wMode)
227 char type[5],handler[5];
228 HIC hic;
229 DWORD querymsg;
230 LPSTR pszBuffer;
232 type[4]=0;memcpy(type,&fccType,4);
233 handler[4]=0;memcpy(handler,&fccHandler,4);
235 TRACE("(%s,%s,%p,%p,0x%04x)\n", type, handler, lpbiIn, lpbiOut, wMode);
237 switch (wMode) {
238 case ICMODE_FASTCOMPRESS:
239 case ICMODE_COMPRESS:
240 querymsg = ICM_COMPRESS_QUERY;
241 break;
242 case ICMODE_FASTDECOMPRESS:
243 case ICMODE_DECOMPRESS:
244 querymsg = ICM_DECOMPRESS_QUERY;
245 break;
246 case ICMODE_DRAW:
247 querymsg = ICM_DRAW_QUERY;
248 break;
249 default:
250 WARN("Unknown mode (%d)\n",wMode);
251 return 0;
254 /* Easy case: handler/type match, we just fire a query and return */
255 hic = ICOpen(fccType,fccHandler,wMode);
256 if (hic) {
257 if (!ICSendMessage(hic,querymsg,(DWORD)lpbiIn,(DWORD)lpbiOut))
258 return hic;
259 ICClose(hic);
262 type[4]='.';memcpy(type,&fccType,4);
263 handler[4]='.';memcpy(handler,&fccHandler,4);
265 /* Now try each driver in turn. 32 bit codecs only. */
266 /* FIXME: Move this to an init routine? */
268 pszBuffer = (LPSTR)HeapAlloc(GetProcessHeap(),0,1024);
269 if (GetPrivateProfileSectionA("drivers32",pszBuffer,1024,"system.ini")) {
270 char* s = pszBuffer;
271 while (*s) {
272 if (!strncasecmp(type,s,5)) {
273 char *s2 = s;
274 while (*s2 != '\0' && *s2 != '.') s2++;
275 if (*s2++) {
276 HIC h;
278 h = ICOpen(fccType,*(DWORD*)s2,wMode);
279 if (h) {
280 if (!ICSendMessage(h,querymsg,(DWORD)lpbiIn,(DWORD)lpbiOut))
281 return h;
282 ICClose(h);
286 s += strlen(s) + 1;
289 HeapFree(GetProcessHeap(),0,pszBuffer);
291 if (fccType==streamtypeVIDEO) {
292 hic = ICLocate(ICTYPE_VIDEO,fccHandler,lpbiIn,lpbiOut,wMode);
293 if (hic)
294 return hic;
297 type[4] = handler[4] = '\0';
298 WARN("(%.4s,%.4s,%p,%p,0x%04x) not found!\n",type,handler,lpbiIn,lpbiOut,wMode);
299 return 0;
302 /***********************************************************************
303 * ICGetDisplayFormat [MSVFW32.@]
305 HIC VFWAPI ICGetDisplayFormat(
306 HIC hic,LPBITMAPINFOHEADER lpbiIn,LPBITMAPINFOHEADER lpbiOut,
307 INT depth,INT dx,INT dy)
309 HIC tmphic = hic;
311 FIXME("(%p,%p,%p,%d,%d,%d),stub!\n",hic,lpbiIn,lpbiOut,depth,dx,dy);
312 if (!tmphic) {
313 tmphic=ICLocate(ICTYPE_VIDEO,0,lpbiIn,NULL,ICMODE_DECOMPRESS);
314 if (!tmphic)
315 return tmphic;
317 if ((dy == lpbiIn->biHeight) && (dx == lpbiIn->biWidth))
318 dy = dx = 0; /* no resize needed */
320 /* Can we decompress it ? */
321 if (ICDecompressQuery(tmphic,lpbiIn,NULL) != 0)
322 goto errout; /* no, sorry */
324 ICDecompressGetFormat(tmphic,lpbiIn,lpbiOut);
326 if (lpbiOut->biCompression != 0) {
327 FIXME("Ooch, how come decompressor outputs compressed data (%ld)??\n",
328 lpbiOut->biCompression);
330 if (lpbiOut->biSize < sizeof(*lpbiOut)) {
331 FIXME("Ooch, size of output BIH is too small (%ld)\n",
332 lpbiOut->biSize);
333 lpbiOut->biSize = sizeof(*lpbiOut);
335 if (!depth) {
336 HDC hdc;
338 hdc = GetDC(0);
339 depth = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
340 ReleaseDC(0,hdc);
341 if (depth==15) depth = 16;
342 if (depth<8) depth = 8;
344 if (lpbiIn->biBitCount == 8)
345 depth = 8;
347 TRACE("=> %p\n", tmphic);
348 return tmphic;
349 errout:
350 if (hic!=tmphic)
351 ICClose(tmphic);
353 TRACE("=> 0\n");
354 return 0;
357 /***********************************************************************
358 * ICCompress [MSVFW32.@]
360 DWORD VFWAPIV
361 ICCompress(
362 HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiOutput,LPVOID lpData,
363 LPBITMAPINFOHEADER lpbiInput,LPVOID lpBits,LPDWORD lpckid,
364 LPDWORD lpdwFlags,LONG lFrameNum,DWORD dwFrameSize,DWORD dwQuality,
365 LPBITMAPINFOHEADER lpbiPrev,LPVOID lpPrev)
367 ICCOMPRESS iccmp;
369 TRACE("(%p,%ld,%p,%p,%p,%p,...)\n",hic,dwFlags,lpbiOutput,lpData,lpbiInput,lpBits);
371 iccmp.dwFlags = dwFlags;
373 iccmp.lpbiOutput = lpbiOutput;
374 iccmp.lpOutput = lpData;
375 iccmp.lpbiInput = lpbiInput;
376 iccmp.lpInput = lpBits;
378 iccmp.lpckid = lpckid;
379 iccmp.lpdwFlags = lpdwFlags;
380 iccmp.lFrameNum = lFrameNum;
381 iccmp.dwFrameSize = dwFrameSize;
382 iccmp.dwQuality = dwQuality;
383 iccmp.lpbiPrev = lpbiPrev;
384 iccmp.lpPrev = lpPrev;
385 return ICSendMessage(hic,ICM_COMPRESS,(DWORD)&iccmp,sizeof(iccmp));
388 /***********************************************************************
389 * ICDecompress [MSVFW32.@]
391 DWORD VFWAPIV ICDecompress(HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiFormat,
392 LPVOID lpData,LPBITMAPINFOHEADER lpbi,LPVOID lpBits)
394 ICDECOMPRESS icd;
395 DWORD ret;
397 TRACE("(%p,%ld,%p,%p,%p,%p)\n",hic,dwFlags,lpbiFormat,lpData,lpbi,lpBits);
399 TRACE("lpBits[0] == %ld\n",((LPDWORD)lpBits)[0]);
401 icd.dwFlags = dwFlags;
402 icd.lpbiInput = lpbiFormat;
403 icd.lpInput = lpData;
405 icd.lpbiOutput = lpbi;
406 icd.lpOutput = lpBits;
407 icd.ckid = 0;
408 ret = ICSendMessage(hic,ICM_DECOMPRESS,(DWORD)&icd,sizeof(ICDECOMPRESS));
410 TRACE("lpBits[0] == %ld\n",((LPDWORD)lpBits)[0]);
412 TRACE("-> %ld\n",ret);
414 return ret;
417 /******************************************************************
418 * MSVIDEO_SendMessage
422 LRESULT MSVIDEO_SendMessage(HIC hic,UINT msg,DWORD lParam1,DWORD lParam2)
424 LRESULT ret;
425 WINE_HIC* whic = GlobalLock16(HIC_16(hic));
427 #define XX(x) case x: TRACE("(%p,"#x",0x%08lx,0x%08lx)\n",hic,lParam1,lParam2);break;
429 switch (msg) {
430 /* DRV_* */
431 XX(DRV_LOAD);
432 XX(DRV_ENABLE);
433 XX(DRV_OPEN);
434 XX(DRV_CLOSE);
435 XX(DRV_DISABLE);
436 XX(DRV_FREE);
437 /* ICM_RESERVED+X */
438 XX(ICM_ABOUT);
439 XX(ICM_CONFIGURE);
440 XX(ICM_GET);
441 XX(ICM_GETINFO);
442 XX(ICM_GETDEFAULTQUALITY);
443 XX(ICM_GETQUALITY);
444 XX(ICM_GETSTATE);
445 XX(ICM_SETQUALITY);
446 XX(ICM_SET);
447 XX(ICM_SETSTATE);
448 /* ICM_USER+X */
449 XX(ICM_COMPRESS_FRAMES_INFO);
450 XX(ICM_COMPRESS_GET_FORMAT);
451 XX(ICM_COMPRESS_GET_SIZE);
452 XX(ICM_COMPRESS_QUERY);
453 XX(ICM_COMPRESS_BEGIN);
454 XX(ICM_COMPRESS);
455 XX(ICM_COMPRESS_END);
456 XX(ICM_DECOMPRESS_GET_FORMAT);
457 XX(ICM_DECOMPRESS_QUERY);
458 XX(ICM_DECOMPRESS_BEGIN);
459 XX(ICM_DECOMPRESS);
460 XX(ICM_DECOMPRESS_END);
461 XX(ICM_DECOMPRESS_SET_PALETTE);
462 XX(ICM_DECOMPRESS_GET_PALETTE);
463 XX(ICM_DRAW_QUERY);
464 XX(ICM_DRAW_BEGIN);
465 XX(ICM_DRAW_GET_PALETTE);
466 XX(ICM_DRAW_START);
467 XX(ICM_DRAW_STOP);
468 XX(ICM_DRAW_END);
469 XX(ICM_DRAW_GETTIME);
470 XX(ICM_DRAW);
471 XX(ICM_DRAW_WINDOW);
472 XX(ICM_DRAW_SETTIME);
473 XX(ICM_DRAW_REALIZE);
474 XX(ICM_DRAW_FLUSH);
475 XX(ICM_DRAW_RENDERBUFFER);
476 XX(ICM_DRAW_START_PLAY);
477 XX(ICM_DRAW_STOP_PLAY);
478 XX(ICM_DRAW_SUGGESTFORMAT);
479 XX(ICM_DRAW_CHANGEPALETTE);
480 XX(ICM_GETBUFFERSWANTED);
481 XX(ICM_GETDEFAULTKEYFRAMERATE);
482 XX(ICM_DECOMPRESSEX_BEGIN);
483 XX(ICM_DECOMPRESSEX_QUERY);
484 XX(ICM_DECOMPRESSEX);
485 XX(ICM_DECOMPRESSEX_END);
486 XX(ICM_SET_STATUS_PROC);
487 default:
488 FIXME("(%p,0x%08lx,0x%08lx,0x%08lx) unknown message\n",hic,(DWORD)msg,lParam1,lParam2);
491 #undef XX
493 if (!whic) return ICERR_BADHANDLE;
495 if (whic->driverproc) {
496 ret = whic->driverproc((DWORD)hic, whic->hdrv, msg, lParam1, lParam2);
497 } else {
498 ret = SendDriverMessage(whic->hdrv, msg, lParam1, lParam2);
501 GlobalUnlock16(HIC_16(hic));
503 TRACE(" -> 0x%08lx\n",ret);
504 return ret;
507 /***********************************************************************
508 * ICSendMessage [MSVFW32.@]
510 LRESULT VFWAPI ICSendMessage(HIC hic, UINT msg, DWORD lParam1, DWORD lParam2) {
511 return MSVIDEO_SendMessage(hic,msg,lParam1,lParam2);
514 /***********************************************************************
515 * ICDrawBegin [MSVFW32.@]
517 DWORD VFWAPIV ICDrawBegin(
518 HIC hic, /* [in] */
519 DWORD dwFlags, /* [in] flags */
520 HPALETTE hpal, /* [in] palette to draw with */
521 HWND hwnd, /* [in] window to draw to */
522 HDC hdc, /* [in] HDC to draw to */
523 INT xDst, /* [in] destination rectangle */
524 INT yDst, /* [in] */
525 INT dxDst, /* [in] */
526 INT dyDst, /* [in] */
527 LPBITMAPINFOHEADER lpbi, /* [in] format of frame to draw */
528 INT xSrc, /* [in] source rectangle */
529 INT ySrc, /* [in] */
530 INT dxSrc, /* [in] */
531 INT dySrc, /* [in] */
532 DWORD dwRate, /* [in] frames/second = (dwRate/dwScale) */
533 DWORD dwScale) /* [in] */
536 ICDRAWBEGIN icdb;
538 TRACE("(%p,%ld,%p,%p,%p,%u,%u,%u,%u,%p,%u,%u,%u,%u,%ld,%ld)\n",
539 hic, dwFlags, hpal, hwnd, hdc, xDst, yDst, dxDst, dyDst,
540 lpbi, xSrc, ySrc, dxSrc, dySrc, dwRate, dwScale);
542 icdb.dwFlags = dwFlags;
543 icdb.hpal = hpal;
544 icdb.hwnd = hwnd;
545 icdb.hdc = hdc;
546 icdb.xDst = xDst;
547 icdb.yDst = yDst;
548 icdb.dxDst = dxDst;
549 icdb.dyDst = dyDst;
550 icdb.lpbi = lpbi;
551 icdb.xSrc = xSrc;
552 icdb.ySrc = ySrc;
553 icdb.dxSrc = dxSrc;
554 icdb.dySrc = dySrc;
555 icdb.dwRate = dwRate;
556 icdb.dwScale = dwScale;
557 return ICSendMessage(hic,ICM_DRAW_BEGIN,(DWORD)&icdb,sizeof(icdb));
560 /***********************************************************************
561 * ICDraw [MSVFW32.@]
563 DWORD VFWAPIV ICDraw(HIC hic, DWORD dwFlags, LPVOID lpFormat, LPVOID lpData, DWORD cbData, LONG lTime) {
564 ICDRAW icd;
566 TRACE("(%p,%ld,%p,%p,%ld,%ld)\n",hic,dwFlags,lpFormat,lpData,cbData,lTime);
568 icd.dwFlags = dwFlags;
569 icd.lpFormat = lpFormat;
570 icd.lpData = lpData;
571 icd.cbData = cbData;
572 icd.lTime = lTime;
574 return ICSendMessage(hic,ICM_DRAW,(DWORD)&icd,sizeof(icd));
577 /***********************************************************************
578 * ICClose [MSVFW32.@]
580 LRESULT WINAPI ICClose(HIC hic) {
581 WINE_HIC *whic = GlobalLock16(HIC_16(hic));
582 TRACE("(%p)\n",hic);
583 if (whic->driverproc) {
584 ICSendMessage(hic,DRV_CLOSE,0,0);
585 ICSendMessage(hic,DRV_DISABLE,0,0);
586 ICSendMessage(hic,DRV_FREE,0,0);
587 } else {
588 CloseDriver(whic->hdrv,0,0);
591 GlobalUnlock16(HIC_16(hic));
592 GlobalFree16(HIC_16(hic));
593 return 0;
598 /***********************************************************************
599 * ICImageCompress [MSVFW32.@]
601 HANDLE VFWAPI ICImageCompress(
602 HIC hic, UINT uiFlags,
603 LPBITMAPINFO lpbiIn, LPVOID lpBits,
604 LPBITMAPINFO lpbiOut, LONG lQuality,
605 LONG* plSize)
607 FIXME("(%p,%08x,%p,%p,%p,%ld,%p)\n",
608 hic, uiFlags, lpbiIn, lpBits, lpbiOut, lQuality, plSize);
610 return (HANDLE)NULL;
613 /***********************************************************************
614 * ICImageDecompress [MSVFW32.@]
617 HANDLE VFWAPI ICImageDecompress(
618 HIC hic, UINT uiFlags, LPBITMAPINFO lpbiIn,
619 LPVOID lpBits, LPBITMAPINFO lpbiOut)
621 HGLOBAL hMem = (HGLOBAL)NULL;
622 BYTE* pMem = NULL;
623 BOOL bReleaseIC = FALSE;
624 BYTE* pHdr = NULL;
625 LONG cbHdr = 0;
626 BOOL bSucceeded = FALSE;
627 BOOL bInDecompress = FALSE;
628 DWORD biSizeImage;
630 TRACE("(%p,%08x,%p,%p,%p)\n",
631 hic, uiFlags, lpbiIn, lpBits, lpbiOut);
633 if ( hic == (HIC)NULL )
635 hic = ICDecompressOpen( mmioFOURCC('V','I','D','C'), 0, &lpbiIn->bmiHeader, (lpbiOut != NULL) ? &lpbiOut->bmiHeader : NULL );
636 if ( hic == (HIC)NULL )
638 WARN("no handler\n" );
639 goto err;
641 bReleaseIC = TRUE;
643 if ( uiFlags != 0 )
645 FIXME( "unknown flag %08x\n", uiFlags );
646 goto err;
648 if ( lpbiIn == NULL || lpBits == NULL )
650 WARN("invalid argument\n");
651 goto err;
654 if ( lpbiOut != NULL )
656 if ( lpbiOut->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) )
657 goto err;
658 cbHdr = sizeof(BITMAPINFOHEADER);
659 if ( lpbiOut->bmiHeader.biCompression == 3 )
660 cbHdr += sizeof(DWORD)*3;
661 else
662 if ( lpbiOut->bmiHeader.biBitCount <= 8 )
664 if ( lpbiOut->bmiHeader.biClrUsed == 0 )
665 cbHdr += sizeof(RGBQUAD) * (1<<lpbiOut->bmiHeader.biBitCount);
666 else
667 cbHdr += sizeof(RGBQUAD) * lpbiOut->bmiHeader.biClrUsed;
670 else
672 TRACE( "get format\n" );
674 cbHdr = ICDecompressGetFormatSize(hic,lpbiIn);
675 if ( cbHdr < sizeof(BITMAPINFOHEADER) )
676 goto err;
677 pHdr = (BYTE*)HeapAlloc(GetProcessHeap(),0,cbHdr+sizeof(RGBQUAD)*256);
678 if ( pHdr == NULL )
679 goto err;
680 ZeroMemory( pHdr, cbHdr+sizeof(RGBQUAD)*256 );
681 if ( ICDecompressGetFormat( hic, lpbiIn, (BITMAPINFO*)pHdr ) != ICERR_OK )
682 goto err;
683 lpbiOut = (BITMAPINFO*)pHdr;
684 if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
685 ICDecompressGetPalette( hic, lpbiIn, lpbiOut ) != ICERR_OK &&
686 lpbiIn->bmiHeader.biBitCount == lpbiOut->bmiHeader.biBitCount )
688 if ( lpbiIn->bmiHeader.biClrUsed == 0 )
689 memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*(1<<lpbiOut->bmiHeader.biBitCount) );
690 else
691 memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*lpbiIn->bmiHeader.biClrUsed );
693 if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
694 lpbiOut->bmiHeader.biClrUsed == 0 )
695 lpbiOut->bmiHeader.biClrUsed = 1<<lpbiOut->bmiHeader.biBitCount;
697 lpbiOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
698 cbHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*lpbiOut->bmiHeader.biClrUsed;
701 biSizeImage = lpbiOut->bmiHeader.biSizeImage;
702 if ( biSizeImage == 0 )
703 biSizeImage = ((((lpbiOut->bmiHeader.biWidth * lpbiOut->bmiHeader.biBitCount + 7) >> 3) + 3) & (~3)) * abs(lpbiOut->bmiHeader.biHeight);
705 TRACE( "call ICDecompressBegin\n" );
707 if ( ICDecompressBegin( hic, lpbiIn, lpbiOut ) != ICERR_OK )
708 goto err;
709 bInDecompress = TRUE;
711 TRACE( "cbHdr %ld, biSizeImage %ld\n", cbHdr, biSizeImage );
713 hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_ZEROINIT, cbHdr + biSizeImage );
714 if ( hMem == (HGLOBAL)NULL )
716 WARN( "out of memory\n" );
717 goto err;
719 pMem = (BYTE*)GlobalLock( hMem );
720 if ( pMem == NULL )
721 goto err;
722 memcpy( pMem, lpbiOut, cbHdr );
724 TRACE( "call ICDecompress\n" );
725 if ( ICDecompress( hic, 0, &lpbiIn->bmiHeader, lpBits, &lpbiOut->bmiHeader, pMem+cbHdr ) != ICERR_OK )
726 goto err;
728 bSucceeded = TRUE;
729 err:
730 if ( bInDecompress )
731 ICDecompressEnd( hic );
732 if ( bReleaseIC )
733 ICClose(hic);
734 if ( pHdr != NULL )
735 HeapFree(GetProcessHeap(),0,pHdr);
736 if ( pMem != NULL )
737 GlobalUnlock( hMem );
738 if ( !bSucceeded && hMem != (HGLOBAL)NULL )
740 GlobalFree(hMem); hMem = (HGLOBAL)NULL;
743 return (HANDLE)hMem;