Keep track of per-column information inside the listview.
[wine] / dlls / msvideo / msvideo_main.c
1 /*
2  * Copyright 1998 Marcus Meissner
3  * Copyright 2000 Bradley Baetz
4  *
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.
9  *
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.
14  *
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
18  *
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.
22  */
23
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "winbase.h"
28 #include "windef.h"
29 #include "winnls.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winver.h"
33 #include "vfw.h"
34 #include "vfw16.h"
35 #include "wine/winbase16.h"
36 #include "wine/debug.h"
37 #include "stackframe.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(msvideo);
40
41 /* ### start build ### */
42 extern LONG CALLBACK MSVIDEO_CallTo16_long_lwwll(FARPROC16,LONG,WORD,WORD,LONG,LONG);
43 /* ### stop build ### */
44
45 LPVOID MSVIDEO_MapMsg16To32(UINT msg, LPDWORD lParam1, LPDWORD lParam2);
46 void MSVIDEO_UnmapMsg16To32(UINT msg, LPVOID lpv, LPDWORD lParam1, LPDWORD lParam2);
47 LRESULT MSVIDEO_SendMessage(HIC hic, UINT msg, DWORD lParam1, DWORD lParam2, BOOL bFrom32);
48
49 #define HDRVR_16(h32)           (LOWORD(h32))
50
51
52 /***********************************************************************
53  *              VideoForWindowsVersion          [MSVFW32.2]
54  *              VideoForWindowsVersion          [MSVIDEO.2]
55  * Returns the version in major.minor form.
56  * In Windows95 this returns 0x040003b6 (4.950)
57  */
58 DWORD WINAPI VideoForWindowsVersion(void) {
59         return 0x040003B6; /* 4.950 */
60 }
61
62 /***********************************************************************
63  *              VideoCapDriverDescAndVer        [MSVIDEO.22]
64  */
65 DWORD WINAPI VideoCapDriverDescAndVer(
66         WORD nr,LPSTR buf1,WORD buf1len,LPSTR buf2,WORD buf2len
67 ) {
68         DWORD   verhandle;
69         WORD    xnr = nr;
70         DWORD   infosize;
71         UINT    subblocklen;
72         char    *s,buf[2000],fn[260];
73         LPBYTE  infobuf;
74         LPVOID  subblock;
75
76         TRACE("(%d,%p,%d,%p,%d)\n",nr,buf1,buf1len,buf2,buf2len);
77         if (GetPrivateProfileStringA("drivers32",NULL,NULL,buf,sizeof(buf),"system.ini")) {
78                 s = buf;
79                 while (*s) {
80                         if (!strncasecmp(s,"vid",3)) {
81                             if (!xnr)
82                                 break;
83                             xnr--;
84                         }
85                         s=s+strlen(s)+1; /* either next char or \0 */
86                 }
87         } else
88             return 20; /* hmm, out of entries even if we don't have any */
89         if (xnr) {
90                 FIXME("No more VID* entries found\n");
91                 return 20;
92         }
93         GetPrivateProfileStringA("drivers32",s,NULL,fn,sizeof(fn),"system.ini");
94         infosize = GetFileVersionInfoSizeA(fn,&verhandle);
95         if (!infosize) {
96             TRACE("%s has no fileversioninfo.\n",fn);
97             return 18;
98         }
99         infobuf = HeapAlloc(GetProcessHeap(),0,infosize);
100         if (GetFileVersionInfoA(fn,verhandle,infosize,infobuf)) {
101             char        vbuf[200];
102             /* Yes, two space behind : */
103             /* FIXME: test for buflen */
104             sprintf(vbuf,"Version:  %d.%d.%d.%d\n",
105                     ((WORD*)infobuf)[0x0f],
106                     ((WORD*)infobuf)[0x0e],
107                     ((WORD*)infobuf)[0x11],
108                     ((WORD*)infobuf)[0x10]
109             );
110             TRACE("version of %s is %s\n",fn,vbuf);
111             strncpy(buf2,vbuf,buf2len);
112         } else {
113             TRACE("GetFileVersionInfoA failed for %s.\n",fn);
114             strncpy(buf2,fn,buf2len); /* msvideo.dll appears to copy fn*/
115         }
116         /* FIXME: language problem? */
117         if (VerQueryValueA(     infobuf,
118                                 "\\StringFileInfo\\040904E4\\FileDescription",
119                                 &subblock,
120                                 &subblocklen
121         )) {
122             TRACE("VQA returned %s\n",(LPCSTR)subblock);
123             strncpy(buf1,subblock,buf1len);
124         } else {
125             TRACE("VQA did not return on query \\StringFileInfo\\040904E4\\FileDescription?\n");
126             strncpy(buf1,fn,buf1len); /* msvideo.dll appears to copy fn*/
127         }
128         HeapFree(GetProcessHeap(),0,infobuf);
129         return 0;
130 }
131
132 /* system.ini: [drivers] */
133
134 /***********************************************************************
135  *              ICInfo                          [MSVFW32.@]
136  * Get information about an installable compressor. Return TRUE if there
137  * is one.
138  */
139 BOOL VFWAPI ICInfo(
140         DWORD fccType,          /* [in] type of compressor ('vidc') */
141         DWORD fccHandler,       /* [in] <n>th compressor */
142         ICINFO *lpicinfo)       /* [out] information about compressor */
143 {
144         char    type[5],buf[2000];
145
146         memcpy(type,&fccType,4);type[4]=0;
147         TRACE("(%s,%ld,%p).\n",type,fccHandler,lpicinfo);
148         /* does OpenDriver/CloseDriver */
149         lpicinfo->dwSize = sizeof(ICINFO);
150         lpicinfo->fccType = fccType;
151         lpicinfo->dwFlags = 0;
152         if (GetPrivateProfileStringA("drivers32",NULL,NULL,buf,2000,"system.ini")) {
153                 char *s = buf;
154                 while (*s) {
155                         if (!strncasecmp(type,s,4)) {
156                                 if(!fccHandler--) {
157                                         lpicinfo->fccHandler = mmioStringToFOURCCA(s+5,0);
158                                         return TRUE;
159                                 }
160                         }
161                         s=s+strlen(s)+1; /* either next char or \0 */
162                 }
163         }
164         return FALSE;
165 }
166
167 /***********************************************************************
168  *              ICInfo                          [MSVIDEO.200]
169  */
170 BOOL16 VFWAPI ICInfo16(
171         DWORD     fccType,    /* [in] */
172         DWORD     fccHandler, /* [in] */
173         ICINFO16 *lpicinfo)   /* [in/out] NOTE: SEGPTR */
174 {
175         BOOL16 ret;
176         LPVOID lpv;
177         DWORD lParam = (DWORD)lpicinfo;
178         DWORD size = ((ICINFO*)(MapSL((SEGPTR)lpicinfo)))->dwSize;
179
180         /* Use the mapping functions to map the ICINFO structure */
181         lpv = MSVIDEO_MapMsg16To32(ICM_GETINFO,&lParam,&size);
182
183         ret = ICInfo(fccType,fccHandler,(ICINFO*)lParam);
184
185         MSVIDEO_UnmapMsg16To32(ICM_GETINFO,lpv,&lParam,&size);
186
187         return ret;
188 }
189
190 /***********************************************************************
191  *              ICOpen                          [MSVFW32.@]
192  * Opens an installable compressor. Return special handle.
193  */
194 HIC VFWAPI ICOpen(DWORD fccType,DWORD fccHandler,UINT wMode) {
195         char            type[5],handler[5],codecname[20];
196         ICOPEN          icopen;
197         HDRVR           hdrv;
198         HIC16           hic;
199         WINE_HIC        *whic;
200
201         memcpy(type,&fccType,4);type[4]=0;
202         memcpy(handler,&fccHandler,4);handler[4]=0;
203         TRACE("(%s,%s,0x%08lx)\n",type,handler,(DWORD)wMode);
204
205         sprintf(codecname,"%s.%s",type,handler);
206
207         /* Well, lParam2 is in fact a LPVIDEO_OPEN_PARMS, but it has the
208          * same layout as ICOPEN
209          */
210         icopen.fccType          = fccType;
211         icopen.fccHandler       = fccHandler;
212         icopen.dwSize           = sizeof(ICOPEN);
213         icopen.dwFlags          = wMode;
214         /* FIXME: do we need to fill out the rest too? */
215         hdrv=OpenDriverA(codecname,"drivers32",(LPARAM)&icopen);
216         if (!hdrv) {
217             if (!strcasecmp(type,"vids")) {
218                 sprintf(codecname,"vidc.%s",handler);
219                 fccType = mmioFOURCC('v','i','d','c');
220             }
221             hdrv=OpenDriverA(codecname,"drivers32",(LPARAM)&icopen);
222             if (!hdrv)
223                     return 0;
224         }
225         /* The handle should be a valid 16-bit handle as well */
226         hic = GlobalAlloc16(GHND,sizeof(WINE_HIC));
227         whic = (WINE_HIC*)GlobalLock16(hic);
228         whic->hdrv      = hdrv;
229         whic->driverproc= NULL;
230         whic->private   = 0;
231         GlobalUnlock16(hic);
232         TRACE("=> 0x%08lx\n",(DWORD)hic);
233         return hic;
234 }
235
236 HIC MSVIDEO_OpenFunc(DWORD fccType, DWORD fccHandler, UINT wMode, FARPROC lpfnHandler, BOOL bFrom32) {
237         char    type[5],handler[5],codecname[20];
238         HIC16   hic;
239         ICOPEN icopen;
240         SEGPTR seg_icopen;
241         WINE_HIC        *whic;
242
243         memcpy(type,&fccType,4);type[4]=0;
244         memcpy(handler,&fccHandler,4);handler[4]=0;
245         TRACE("(%s,%s,%d,%p,%d)\n",type,handler,wMode,lpfnHandler,bFrom32?32:16);
246
247         icopen.fccType    = fccType;
248         icopen.fccHandler = fccHandler;
249         icopen.dwSize     = sizeof(ICOPEN);
250         icopen.dwFlags    = wMode;
251
252         sprintf(codecname,"%s.%s",type,handler);
253
254         hic = GlobalAlloc16(GHND,sizeof(WINE_HIC));
255         if (!hic)
256                 return 0;
257         whic = GlobalLock16(hic);
258         whic->driverproc = lpfnHandler;
259
260         whic->private = bFrom32;
261
262         /* Now try opening/loading the driver. Taken from DRIVER_AddToList */
263         /* What if the function is used more than once? */
264
265         if (MSVIDEO_SendMessage(hic,DRV_LOAD,0L,0L,bFrom32) != DRV_SUCCESS) {
266                 WARN("DRV_LOAD failed for hic 0x%08lx\n",(DWORD)hic);
267                 GlobalFree16(hic);
268                 return 0;
269         }
270         /* return value is not checked */
271         MSVIDEO_SendMessage(hic,DRV_ENABLE,0L,0L,bFrom32);
272
273         seg_icopen = MapLS( &icopen );
274         whic->hdrv = (HDRVR)MSVIDEO_SendMessage(hic,DRV_OPEN,0,seg_icopen,FALSE);
275         UnMapLS( seg_icopen );
276         if (whic->hdrv == 0) {
277                 WARN("DRV_OPEN failed for hic 0x%08lx\n",(DWORD)hic);
278                 GlobalFree16(hic);
279                 return 0;
280         }
281
282         GlobalUnlock16(hic);
283         TRACE("=> 0x%08lx\n",(DWORD)hic);
284         return hic;
285 }
286
287 /***********************************************************************
288  *              ICOpenFunction                  [MSVFW32.@]
289  */
290 HIC VFWAPI ICOpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode, FARPROC lpfnHandler) {
291         return MSVIDEO_OpenFunc(fccType,fccHandler,wMode,lpfnHandler,TRUE);
292 }
293
294 /***********************************************************************
295  *              ICOpenFunction                  [MSVIDEO.206]
296  */
297 HIC16 VFWAPI ICOpenFunction16(DWORD fccType, DWORD fccHandler, UINT16 wMode, FARPROC16 lpfnHandler)
298 {
299         return MSVIDEO_OpenFunc(fccType, fccHandler, wMode, (FARPROC)lpfnHandler,FALSE);
300 }
301
302 /***********************************************************************
303  *              ICGetInfo                       [MSVFW32.@]
304  */
305 LRESULT VFWAPI ICGetInfo(HIC hic,ICINFO *picinfo,DWORD cb) {
306         LRESULT         ret;
307
308         TRACE("(0x%08lx,%p,%ld)\n",(DWORD)hic,picinfo,cb);
309         ret = ICSendMessage(hic,ICM_GETINFO,(DWORD)picinfo,cb);
310         TRACE(" -> 0x%08lx\n",ret);
311         return ret;
312 }
313
314 /***********************************************************************
315  *              ICLocate                        [MSVFW32.@]
316  */
317 HIC VFWAPI ICLocate(
318         DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn,
319         LPBITMAPINFOHEADER lpbiOut, WORD wMode)
320 {
321         char    type[5],handler[5];
322         HIC     hic;
323         DWORD   querymsg;
324         LPSTR pszBuffer;
325
326         type[4]=0;memcpy(type,&fccType,4);
327         handler[4]=0;memcpy(handler,&fccHandler,4);
328
329         TRACE("(%s,%s,%p,%p,0x%04x)\n", type, handler, lpbiIn, lpbiOut, wMode);
330
331         switch (wMode) {
332         case ICMODE_FASTCOMPRESS:
333         case ICMODE_COMPRESS:
334                 querymsg = ICM_COMPRESS_QUERY;
335                 break;
336         case ICMODE_FASTDECOMPRESS:
337         case ICMODE_DECOMPRESS:
338                 querymsg = ICM_DECOMPRESS_QUERY;
339                 break;
340         case ICMODE_DRAW:
341                 querymsg = ICM_DRAW_QUERY;
342                 break;
343         default:
344                 WARN("Unknown mode (%d)\n",wMode);
345                 return 0;
346         }
347
348         /* Easy case: handler/type match, we just fire a query and return */
349         hic = ICOpen(fccType,fccHandler,wMode);
350         if (hic) {
351                 if (!ICSendMessage(hic,querymsg,(DWORD)lpbiIn,(DWORD)lpbiOut))
352                         return hic;
353                 ICClose(hic);
354         }
355
356         type[4]='.';memcpy(type,&fccType,4);
357         handler[4]='.';memcpy(handler,&fccHandler,4);
358
359         /* Now try each driver in turn. 32 bit codecs only. */
360         /* FIXME: Move this to an init routine? */
361
362         pszBuffer = (LPSTR)HeapAlloc(GetProcessHeap(),0,1024);
363         if (GetPrivateProfileSectionA("drivers32",pszBuffer,1024,"system.ini")) {
364                 char* s = pszBuffer;
365                 while (*s) {
366                         if (!strncasecmp(type,s,5)) {
367                                 char *s2 = s;
368                                 while (*s2 != '\0' && *s2 != '.') s2++;
369                                 if (*s2++) {
370                                         HIC h;
371
372                                         h = ICOpen(fccType,*(DWORD*)s2,wMode);
373                                         if (h) {
374                                                 if (!ICSendMessage(h,querymsg,(DWORD)lpbiIn,(DWORD)lpbiOut))
375                                                         return h;
376                                                 ICClose(h);
377                                         }
378                                 }
379                         }
380                         s += strlen(s) + 1;
381                 }
382         }
383         HeapFree(GetProcessHeap(),0,pszBuffer);
384
385         if (fccType==streamtypeVIDEO) {
386                 hic = ICLocate(ICTYPE_VIDEO,fccHandler,lpbiIn,lpbiOut,wMode);
387                 if (hic)
388                         return hic;
389         }
390
391         type[4] = handler[4] = '\0';
392         WARN("(%.4s,%.4s,%p,%p,0x%04x) not found!\n",type,handler,lpbiIn,lpbiOut,wMode);
393         return 0;
394 }
395
396 /***********************************************************************
397  *              ICGetDisplayFormat                      [MSVFW32.@]
398  */
399 HIC VFWAPI ICGetDisplayFormat(
400         HIC hic,LPBITMAPINFOHEADER lpbiIn,LPBITMAPINFOHEADER lpbiOut,
401         INT depth,INT dx,INT dy)
402 {
403         HIC     tmphic = hic;
404
405         FIXME("(0x%08lx,%p,%p,%d,%d,%d),stub!\n",(DWORD)hic,lpbiIn,lpbiOut,depth,dx,dy);
406         if (!tmphic) {
407                 tmphic=ICLocate(ICTYPE_VIDEO,0,lpbiIn,NULL,ICMODE_DECOMPRESS);
408                 if (!tmphic)
409                         return tmphic;
410         }
411         if ((dy == lpbiIn->biHeight) && (dx == lpbiIn->biWidth))
412                 dy = dx = 0; /* no resize needed */
413
414         /* Can we decompress it ? */
415         if (ICDecompressQuery(tmphic,lpbiIn,NULL) != 0)
416                 goto errout; /* no, sorry */
417
418         ICDecompressGetFormat(tmphic,lpbiIn,lpbiOut);
419
420         if (lpbiOut->biCompression != 0) {
421            FIXME("Ooch, how come decompressor outputs compressed data (%ld)??\n",
422                          lpbiOut->biCompression);
423         }
424         if (lpbiOut->biSize < sizeof(*lpbiOut)) {
425            FIXME("Ooch, size of output BIH is too small (%ld)\n",
426                          lpbiOut->biSize);
427            lpbiOut->biSize = sizeof(*lpbiOut);
428         }
429         if (!depth) {
430                 HDC     hdc;
431
432                 hdc = GetDC(0);
433                 depth = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES);
434                 ReleaseDC(0,hdc);
435                 if (depth==15)  depth = 16;
436                 if (depth<8)    depth =  8;
437         }
438         if (lpbiIn->biBitCount == 8)
439                 depth = 8;
440
441         TRACE("=> 0x%08lx\n",(DWORD)tmphic);
442         return tmphic;
443 errout:
444         if (hic!=tmphic)
445                 ICClose(tmphic);
446
447         TRACE("=> 0\n");
448         return 0;
449 }
450
451 /***********************************************************************
452  *              ICCompress                      [MSVFW32.@]
453  */
454 DWORD VFWAPIV
455 ICCompress(
456         HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiOutput,LPVOID lpData,
457         LPBITMAPINFOHEADER lpbiInput,LPVOID lpBits,LPDWORD lpckid,
458         LPDWORD lpdwFlags,LONG lFrameNum,DWORD dwFrameSize,DWORD dwQuality,
459         LPBITMAPINFOHEADER lpbiPrev,LPVOID lpPrev)
460 {
461         ICCOMPRESS      iccmp;
462
463         TRACE("(0x%08lx,%ld,%p,%p,%p,%p,...)\n",(DWORD)hic,dwFlags,lpbiOutput,lpData,lpbiInput,lpBits);
464
465         iccmp.dwFlags           = dwFlags;
466
467         iccmp.lpbiOutput        = lpbiOutput;
468         iccmp.lpOutput          = lpData;
469         iccmp.lpbiInput         = lpbiInput;
470         iccmp.lpInput           = lpBits;
471
472         iccmp.lpckid            = lpckid;
473         iccmp.lpdwFlags         = lpdwFlags;
474         iccmp.lFrameNum         = lFrameNum;
475         iccmp.dwFrameSize       = dwFrameSize;
476         iccmp.dwQuality         = dwQuality;
477         iccmp.lpbiPrev          = lpbiPrev;
478         iccmp.lpPrev            = lpPrev;
479         return ICSendMessage(hic,ICM_COMPRESS,(DWORD)&iccmp,sizeof(iccmp));
480 }
481
482 /***********************************************************************
483  *              ICDecompress                    [MSVFW32.@]
484  */
485 DWORD VFWAPIV  ICDecompress(HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiFormat,
486                                 LPVOID lpData,LPBITMAPINFOHEADER lpbi,LPVOID lpBits)
487 {
488         ICDECOMPRESS    icd;
489         DWORD ret;
490
491         TRACE("(0x%08lx,%ld,%p,%p,%p,%p)\n",(DWORD)hic,dwFlags,lpbiFormat,lpData,lpbi,lpBits);
492
493         TRACE("lpBits[0] == %ld\n",((LPDWORD)lpBits)[0]);
494
495         icd.dwFlags     = dwFlags;
496         icd.lpbiInput   = lpbiFormat;
497         icd.lpInput     = lpData;
498
499         icd.lpbiOutput  = lpbi;
500         icd.lpOutput    = lpBits;
501         icd.ckid        = 0;
502         ret = ICSendMessage(hic,ICM_DECOMPRESS,(DWORD)&icd,sizeof(ICDECOMPRESS));
503
504         TRACE("lpBits[0] == %ld\n",((LPDWORD)lpBits)[0]);
505
506         TRACE("-> %ld\n",ret);
507
508         return ret;
509 }
510
511 #define COPY(x,y) (x->y = x##16->y);
512 #define COPYPTR(x,y) (x->y = MapSL((SEGPTR)x##16->y));
513
514 LPVOID MSVIDEO_MapICDEX16To32(LPDWORD lParam) {
515         LPVOID ret;
516
517         ICDECOMPRESSEX *icdx = HeapAlloc(GetProcessHeap(),0,sizeof(ICDECOMPRESSEX));
518         ICDECOMPRESSEX16 *icdx16 = MapSL(*lParam);
519         ret = icdx16;
520
521         COPY(icdx,dwFlags);
522         COPYPTR(icdx,lpbiSrc);
523         COPYPTR(icdx,lpSrc);
524         COPYPTR(icdx,lpbiDst);
525         COPYPTR(icdx,lpDst);
526         COPY(icdx,xDst);
527         COPY(icdx,yDst);
528         COPY(icdx,dxDst);
529         COPY(icdx,dyDst);
530         COPY(icdx,xSrc);
531         COPY(icdx,ySrc);
532         COPY(icdx,dxSrc);
533         COPY(icdx,dySrc);
534
535         *lParam = (DWORD)(icdx);
536         return ret;
537 }
538
539 LPVOID MSVIDEO_MapMsg16To32(UINT msg, LPDWORD lParam1, LPDWORD lParam2) {
540         LPVOID ret = 0;
541
542         TRACE("Mapping %d\n",msg);
543
544         switch (msg) {
545         case DRV_LOAD:
546         case DRV_ENABLE:
547         case DRV_CLOSE:
548         case DRV_DISABLE:
549         case DRV_FREE:
550         case ICM_ABOUT:
551         case ICM_CONFIGURE:
552         case ICM_COMPRESS_END:
553         case ICM_DECOMPRESS_END:
554         case ICM_DECOMPRESSEX_END:
555         case ICM_SETQUALITY:
556         case ICM_DRAW_START_PLAY:
557         case ICM_DRAW_STOP_PLAY:
558         case ICM_DRAW_REALIZE:
559         case ICM_DRAW_RENDERBUFFER:
560         case ICM_DRAW_END:
561                 break;
562         case DRV_OPEN:
563         case ICM_GETDEFAULTQUALITY:
564         case ICM_GETQUALITY:
565         case ICM_SETSTATE:
566         case ICM_DRAW_WINDOW:
567         case ICM_GETBUFFERSWANTED:
568                 *lParam1 = (DWORD)MapSL(*lParam1);
569                 break;
570         case ICM_GETINFO:
571                 {
572                         ICINFO *ici = HeapAlloc(GetProcessHeap(),0,sizeof(ICINFO));
573                         ICINFO16 *ici16;
574
575                         ici16 = MapSL(*lParam1);
576                         ret = ici16;
577
578                         ici->dwSize = sizeof(ICINFO);
579                         COPY(ici,fccType);
580                         COPY(ici,fccHandler);
581                         COPY(ici,dwFlags);
582                         COPY(ici,dwVersion);
583                         COPY(ici,dwVersionICM);
584                         MultiByteToWideChar( CP_ACP, 0, ici16->szName, -1, ici->szName, 16 );
585                         MultiByteToWideChar( CP_ACP, 0, ici16->szDescription, -1, ici->szDescription, 128 );
586                         MultiByteToWideChar( CP_ACP, 0, ici16->szDriver, -1, ici->szDriver, 128 );
587                         *lParam1 = (DWORD)(ici);
588                         *lParam2 = sizeof(ICINFO);
589                 }
590                 break;
591         case ICM_COMPRESS:
592                 {
593                         ICCOMPRESS *icc = HeapAlloc(GetProcessHeap(),0,sizeof(ICCOMPRESS));
594                         ICCOMPRESS *icc16;
595
596                         icc16 = MapSL(*lParam1);
597                         ret = icc16;
598
599                         COPY(icc,dwFlags);
600                         COPYPTR(icc,lpbiOutput);
601                         COPYPTR(icc,lpOutput);
602                         COPYPTR(icc,lpbiInput);
603                         COPYPTR(icc,lpInput);
604                         COPYPTR(icc,lpckid);
605                         COPYPTR(icc,lpdwFlags);
606                         COPY(icc,lFrameNum);
607                         COPY(icc,dwFrameSize);
608                         COPY(icc,dwQuality);
609                         COPYPTR(icc,lpbiPrev);
610                         COPYPTR(icc,lpPrev);
611
612                         *lParam1 = (DWORD)(icc);
613                         *lParam2 = sizeof(ICCOMPRESS);
614                 }
615                 break;
616         case ICM_DECOMPRESS:
617                 {
618                         ICDECOMPRESS *icd = HeapAlloc(GetProcessHeap(),0,sizeof(ICDECOMPRESS));
619                         ICDECOMPRESS *icd16; /* Same structure except for the pointers */
620
621                         icd16 = MapSL(*lParam1);
622                         ret = icd16;
623
624                         COPY(icd,dwFlags);
625                         COPYPTR(icd,lpbiInput);
626                         COPYPTR(icd,lpInput);
627                         COPYPTR(icd,lpbiOutput);
628                         COPYPTR(icd,lpOutput);
629                         COPY(icd,ckid);
630
631                         *lParam1 = (DWORD)(icd);
632                         *lParam2 = sizeof(ICDECOMPRESS);
633                 }
634                 break;
635         case ICM_COMPRESS_BEGIN:
636         case ICM_COMPRESS_GET_FORMAT:
637         case ICM_COMPRESS_GET_SIZE:
638         case ICM_COMPRESS_QUERY:
639         case ICM_DECOMPRESS_GET_FORMAT:
640         case ICM_DECOMPRESS_QUERY:
641         case ICM_DECOMPRESS_BEGIN:
642         case ICM_DECOMPRESS_SET_PALETTE:
643         case ICM_DECOMPRESS_GET_PALETTE:
644                 *lParam1 = (DWORD)MapSL(*lParam1);
645                 *lParam2 = (DWORD)MapSL(*lParam2);
646                 break;
647         case ICM_DECOMPRESSEX_QUERY:
648                 if ((*lParam2 != sizeof(ICDECOMPRESSEX16)) && (*lParam2 != 0))
649                         WARN("*lParam2 has unknown value %p\n",(ICDECOMPRESSEX16*)*lParam2);
650                 /* FIXME: *lParm2 is meant to be 0 or an ICDECOMPRESSEX16*, but is sizeof(ICDECOMRPESSEX16)
651                  * This is because of ICMessage(). Special case it?
652                  {
653                  LPVOID* addr = HeapAlloc(GetProcessHeap(),0,2*sizeof(LPVOID));
654                  addr[0] = MSVIDEO_MapICDEX16To32(lParam1);
655                  if (*lParam2)
656                  addr[1] = MSVIDEO_MapICDEX16To32(lParam2);
657                  else
658                  addr[1] = 0;
659
660                  ret = addr;
661                  }
662                  break;*/
663         case ICM_DECOMPRESSEX_BEGIN:
664         case ICM_DECOMPRESSEX:
665                 ret = MSVIDEO_MapICDEX16To32(lParam1);
666                 *lParam2 = sizeof(ICDECOMPRESSEX);
667                 break;
668         case ICM_DRAW_BEGIN:
669                 {
670                         ICDRAWBEGIN *icdb = HeapAlloc(GetProcessHeap(),0,sizeof(ICDRAWBEGIN));
671                         ICDRAWBEGIN16 *icdb16 = MapSL(*lParam1);
672                         ret = icdb16;
673
674                         COPY(icdb,dwFlags);
675                         icdb->hpal = HPALETTE_32(icdb16->hpal);
676                         icdb->hwnd = HWND_32(icdb16->hwnd);
677                         COPY(icdb,hdc);
678                         COPY(icdb,xDst);
679                         COPY(icdb,yDst);
680                         COPY(icdb,dxDst);
681                         COPY(icdb,dyDst);
682                         COPYPTR(icdb,lpbi);
683                         COPY(icdb,xSrc);
684                         COPY(icdb,ySrc);
685                         COPY(icdb,dxSrc);
686                         COPY(icdb,dySrc);
687                         COPY(icdb,dwRate);
688                         COPY(icdb,dwScale);
689
690                         *lParam1 = (DWORD)(icdb);
691                         *lParam2 = sizeof(ICDRAWBEGIN);
692                 }
693                 break;
694         case ICM_DRAW_SUGGESTFORMAT:
695                 {
696                         ICDRAWSUGGEST *icds = HeapAlloc(GetProcessHeap(),0,sizeof(ICDRAWSUGGEST));
697                         ICDRAWSUGGEST16 *icds16 = MapSL(*lParam1);
698
699                         ret = icds16;
700
701                         COPY(icds,dwFlags);
702                         COPYPTR(icds,lpbiIn);
703                         COPYPTR(icds,lpbiSuggest);
704                         COPY(icds,dxSrc);
705                         COPY(icds,dySrc);
706                         COPY(icds,dxDst);
707                         COPY(icds,dyDst);
708                         COPY(icds,hicDecompressor);
709
710                         *lParam1 = (DWORD)(icds);
711                         *lParam2 = sizeof(ICDRAWSUGGEST);
712                 }
713                 break;
714         case ICM_DRAW:
715                 {
716                         ICDRAW *icd = HeapAlloc(GetProcessHeap(),0,sizeof(ICDRAW));
717                         ICDRAW *icd16 = MapSL(*lParam1);
718                         ret = icd16;
719
720                         COPY(icd,dwFlags);
721                         COPYPTR(icd,lpFormat);
722                         COPYPTR(icd,lpData);
723                         COPY(icd,cbData);
724                         COPY(icd,lTime);
725
726                         *lParam1 = (DWORD)(icd);
727                         *lParam2 = sizeof(ICDRAW);
728                 }
729                 break;
730         case ICM_DRAW_START:
731         case ICM_DRAW_STOP:
732                 break;
733         default:
734                 FIXME("%d is not yet handled. Expect a crash.\n",msg);
735         }
736         return ret;
737 }
738
739 #undef COPY
740 #undef COPYPTR
741
742 void MSVIDEO_UnmapMsg16To32(UINT msg, LPVOID data16, LPDWORD lParam1, LPDWORD lParam2) {
743         TRACE("Unmapping %d\n",msg);
744
745 #define UNCOPY(x,y) (x##16->y = x->y);
746
747         switch (msg) {
748         case ICM_GETINFO:
749                 {
750                         ICINFO *ici = (ICINFO*)(*lParam1);
751                         ICINFO16 *ici16 = (ICINFO16*)data16;
752
753                         UNCOPY(ici,fccType);
754                         UNCOPY(ici,fccHandler);
755                         UNCOPY(ici,dwFlags);
756                         UNCOPY(ici,dwVersion);
757                         UNCOPY(ici,dwVersionICM);
758                         WideCharToMultiByte( CP_ACP, 0, ici->szName, -1, ici16->szName,
759                                              sizeof(ici16->szName), NULL, NULL );
760                         ici16->szName[sizeof(ici16->szName)-1] = 0;
761                         WideCharToMultiByte( CP_ACP, 0, ici->szDescription, -1, ici16->szDescription,
762                                              sizeof(ici16->szDescription), NULL, NULL );
763                         ici16->szDescription[sizeof(ici16->szDescription)-1] = 0;
764                         /* This just gives garbage for some reason - BB
765                            lstrcpynWtoA(ici16->szDriver,ici->szDriver,128);*/
766
767                         HeapFree(GetProcessHeap(),0,ici);
768                 }
769                 break;
770         case ICM_DECOMPRESS_QUERY:
771                 /*{
772                   LPVOID* x = data16;
773                   HeapFree(GetProcessHeap(),0,x[0]);
774                   if (x[1])
775                   HeapFree(GetProcessHeap(),0,x[1]);
776                   }
777                   break;*/
778         case ICM_COMPRESS:
779         case ICM_DECOMPRESS:
780         case ICM_DECOMPRESSEX_QUERY:
781         case ICM_DECOMPRESSEX_BEGIN:
782         case ICM_DECOMPRESSEX:
783         case ICM_DRAW_BEGIN:
784         case ICM_DRAW_SUGGESTFORMAT:
785         case ICM_DRAW:
786                 HeapFree(GetProcessHeap(),0,data16);
787                 break;
788         default:
789                 ERR("Unmapping unmapped msg %d\n",msg);
790         }
791 #undef UNCOPY
792 }
793
794 LRESULT MSVIDEO_SendMessage(HIC hic,UINT msg,DWORD lParam1,DWORD lParam2, BOOL bFrom32) {
795         LRESULT         ret;
796         WINE_HIC        *whic = GlobalLock16(hic);
797         LPVOID data16 = 0;
798         BOOL bDrv32;
799
800 #define XX(x) case x: TRACE("(0x%08lx,"#x",0x%08lx,0x%08lx,%d)\n",(DWORD)hic,lParam1,lParam2,bFrom32?32:16);break;
801
802         switch (msg) {
803                 /* DRV_* */
804                 XX(DRV_LOAD);
805                 XX(DRV_ENABLE);
806                 XX(DRV_OPEN);
807                 XX(DRV_CLOSE);
808                 XX(DRV_DISABLE);
809                 XX(DRV_FREE);
810                 /* ICM_RESERVED+X */
811                 XX(ICM_ABOUT);
812                 XX(ICM_CONFIGURE);
813                 XX(ICM_GET);
814                 XX(ICM_GETINFO);
815                 XX(ICM_GETDEFAULTQUALITY);
816                 XX(ICM_GETQUALITY);
817                 XX(ICM_GETSTATE);
818                 XX(ICM_SETQUALITY);
819                 XX(ICM_SET);
820                 XX(ICM_SETSTATE);
821                 /* ICM_USER+X */
822                 XX(ICM_COMPRESS_FRAMES_INFO);
823                 XX(ICM_COMPRESS_GET_FORMAT);
824                 XX(ICM_COMPRESS_GET_SIZE);
825                 XX(ICM_COMPRESS_QUERY);
826                 XX(ICM_COMPRESS_BEGIN);
827                 XX(ICM_COMPRESS);
828                 XX(ICM_COMPRESS_END);
829                 XX(ICM_DECOMPRESS_GET_FORMAT);
830                 XX(ICM_DECOMPRESS_QUERY);
831                 XX(ICM_DECOMPRESS_BEGIN);
832                 XX(ICM_DECOMPRESS);
833                 XX(ICM_DECOMPRESS_END);
834                 XX(ICM_DECOMPRESS_SET_PALETTE);
835                 XX(ICM_DECOMPRESS_GET_PALETTE);
836                 XX(ICM_DRAW_QUERY);
837                 XX(ICM_DRAW_BEGIN);
838                 XX(ICM_DRAW_GET_PALETTE);
839                 XX(ICM_DRAW_START);
840                 XX(ICM_DRAW_STOP);
841                 XX(ICM_DRAW_END);
842                 XX(ICM_DRAW_GETTIME);
843                 XX(ICM_DRAW);
844                 XX(ICM_DRAW_WINDOW);
845                 XX(ICM_DRAW_SETTIME);
846                 XX(ICM_DRAW_REALIZE);
847                 XX(ICM_DRAW_FLUSH);
848                 XX(ICM_DRAW_RENDERBUFFER);
849                 XX(ICM_DRAW_START_PLAY);
850                 XX(ICM_DRAW_STOP_PLAY);
851                 XX(ICM_DRAW_SUGGESTFORMAT);
852                 XX(ICM_DRAW_CHANGEPALETTE);
853                 XX(ICM_GETBUFFERSWANTED);
854                 XX(ICM_GETDEFAULTKEYFRAMERATE);
855                 XX(ICM_DECOMPRESSEX_BEGIN);
856                 XX(ICM_DECOMPRESSEX_QUERY);
857                 XX(ICM_DECOMPRESSEX);
858                 XX(ICM_DECOMPRESSEX_END);
859                 XX(ICM_SET_STATUS_PROC);
860         default:
861                 FIXME("(0x%08lx,0x%08lx,0x%08lx,0x%08lx,%i) unknown message\n",(DWORD)hic,(DWORD)msg,lParam1,lParam2,bFrom32?32:16);
862         }
863
864 #undef XX
865
866         if (!whic) return ICERR_BADHANDLE;
867
868         if (whic->driverproc) { /* IC is a function */
869                 bDrv32 = whic->private;
870         } else {
871                 bDrv32 = ((GetDriverFlags(whic->hdrv) & (WINE_GDF_EXIST|WINE_GDF_16BIT)) == WINE_GDF_EXIST);
872         }
873
874         if (!bFrom32) {
875                 if (bDrv32)
876                         data16 = MSVIDEO_MapMsg16To32(msg,&lParam1,&lParam2);
877         } else {
878                 if (!bDrv32) {
879                         ERR("Can't do 32->16 mappings\n");
880                         ret = -1;
881                         goto out;
882                 }
883         }
884
885         if (whic->driverproc) {
886                 if (bDrv32) {
887                         ret = whic->driverproc(whic->hdrv,hic,msg,lParam1,lParam2);
888                 } else {
889                         ret = MSVIDEO_CallTo16_long_lwwll((FARPROC16)whic->driverproc,HDRVR_16(whic->hdrv),hic,msg,lParam1,lParam2);
890                 }
891         } else {
892                 ret = SendDriverMessage(whic->hdrv,msg,lParam1,lParam2);
893         }
894
895         if (data16)
896                 MSVIDEO_UnmapMsg16To32(msg,data16,&lParam1,&lParam2);
897
898  out:
899         GlobalUnlock16(hic);
900
901         TRACE(" -> 0x%08lx\n",ret);
902         return ret;
903 }
904
905 /***********************************************************************
906  *              ICSendMessage                   [MSVFW32.@]
907  */
908 LRESULT VFWAPI ICSendMessage(HIC hic, UINT msg, DWORD lParam1, DWORD lParam2) {
909         return MSVIDEO_SendMessage(hic,msg,lParam1,lParam2,TRUE);
910 }
911
912 /***********************************************************************
913  *              ICSendMessage                   [MSVIDEO.205]
914  */
915 LRESULT VFWAPI ICSendMessage16(HIC16 hic, UINT16 msg, DWORD lParam1, DWORD lParam2) {
916         return MSVIDEO_SendMessage(hic,msg,lParam1,lParam2,FALSE);
917 }
918
919 /***********************************************************************
920  *              ICDrawBegin             [MSVFW32.@]
921  */
922 DWORD VFWAPIV ICDrawBegin(
923         HIC                hic,     /* [in] */
924         DWORD              dwFlags, /* [in] flags */
925         HPALETTE           hpal,    /* [in] palette to draw with */
926         HWND               hwnd,    /* [in] window to draw to */
927         HDC                hdc,     /* [in] HDC to draw to */
928         INT                xDst,    /* [in] destination rectangle */
929         INT                yDst,    /* [in] */
930         INT                dxDst,   /* [in] */
931         INT                dyDst,   /* [in] */
932         LPBITMAPINFOHEADER lpbi,    /* [in] format of frame to draw */
933         INT                xSrc,    /* [in] source rectangle */
934         INT                ySrc,    /* [in] */
935         INT                dxSrc,   /* [in] */
936         INT                dySrc,   /* [in] */
937         DWORD              dwRate,  /* [in] frames/second = (dwRate/dwScale) */
938         DWORD              dwScale) /* [in] */
939 {
940
941         ICDRAWBEGIN     icdb;
942
943         TRACE("(0x%08lx,%ld,0x%08lx,0x%08lx,0x%08lx,%u,%u,%u,%u,%p,%u,%u,%u,%u,%ld,%ld)\n",
944                   (DWORD)hic, dwFlags, (DWORD)hpal, (DWORD)hwnd, (DWORD)hdc, xDst, yDst, dxDst, dyDst,
945                   lpbi, xSrc, ySrc, dxSrc, dySrc, dwRate, dwScale);
946
947         icdb.dwFlags = dwFlags;
948         icdb.hpal = hpal;
949         icdb.hwnd = hwnd;
950         icdb.hdc = hdc;
951         icdb.xDst = xDst;
952         icdb.yDst = yDst;
953         icdb.dxDst = dxDst;
954         icdb.dyDst = dyDst;
955         icdb.lpbi = lpbi;
956         icdb.xSrc = xSrc;
957         icdb.ySrc = ySrc;
958         icdb.dxSrc = dxSrc;
959         icdb.dySrc = dySrc;
960         icdb.dwRate = dwRate;
961         icdb.dwScale = dwScale;
962         return ICSendMessage(hic,ICM_DRAW_BEGIN,(DWORD)&icdb,sizeof(icdb));
963 }
964
965 /***********************************************************************
966  *              ICDraw                  [MSVFW32.@]
967  */
968 DWORD VFWAPIV ICDraw(HIC hic, DWORD dwFlags, LPVOID lpFormat, LPVOID lpData, DWORD cbData, LONG lTime) {
969         ICDRAW  icd;
970
971         TRACE("(0x%09lx,%ld,%p,%p,%ld,%ld)\n",(DWORD)hic,dwFlags,lpFormat,lpData,cbData,lTime);
972
973         icd.dwFlags = dwFlags;
974         icd.lpFormat = lpFormat;
975         icd.lpData = lpData;
976         icd.cbData = cbData;
977         icd.lTime = lTime;
978
979         return ICSendMessage(hic,ICM_DRAW,(DWORD)&icd,sizeof(icd));
980 }
981
982 /***********************************************************************
983  *              ICClose                 [MSVFW32.@]
984  */
985 LRESULT WINAPI ICClose(HIC hic) {
986         WINE_HIC *whic = GlobalLock16(hic);
987         TRACE("(0x%08lx)\n",(DWORD)hic);
988         if (whic->driverproc) {
989                 ICSendMessage(hic,DRV_CLOSE,0,0);
990                 ICSendMessage(hic,DRV_DISABLE,0,0);
991                 ICSendMessage(hic,DRV_FREE,0,0);
992         } else {
993                 CloseDriver(whic->hdrv,0,0);
994         }
995
996         GlobalUnlock16(hic);
997         GlobalFree16(hic);
998         return 0;
999 }
1000
1001
1002
1003 /***********************************************************************
1004  *              ICImageCompress [MSVFW32.@]
1005  */
1006 HANDLE VFWAPI ICImageCompress(
1007         HIC hic, UINT uiFlags,
1008         LPBITMAPINFO lpbiIn, LPVOID lpBits,
1009         LPBITMAPINFO lpbiOut, LONG lQuality,
1010         LONG* plSize)
1011 {
1012         FIXME("(%08x,%08x,%p,%p,%p,%ld,%p)\n",
1013                 hic, uiFlags, lpbiIn, lpBits, lpbiOut, lQuality, plSize);
1014
1015         return (HANDLE)NULL;
1016 }
1017
1018 /***********************************************************************
1019  *              ICImageDecompress       [MSVFW32.@]
1020  */
1021
1022 HANDLE VFWAPI ICImageDecompress(
1023         HIC hic, UINT uiFlags, LPBITMAPINFO lpbiIn,
1024         LPVOID lpBits, LPBITMAPINFO lpbiOut)
1025 {
1026         HGLOBAL hMem = (HGLOBAL)NULL;
1027         BYTE*   pMem = NULL;
1028         BOOL    bReleaseIC = FALSE;
1029         BYTE*   pHdr = NULL;
1030         LONG    cbHdr = 0;
1031         BOOL    bSucceeded = FALSE;
1032         BOOL    bInDecompress = FALSE;
1033         DWORD   biSizeImage;
1034
1035         TRACE("(%08x,%08x,%p,%p,%p)\n",
1036                 hic, uiFlags, lpbiIn, lpBits, lpbiOut);
1037
1038         if ( hic == (HIC)NULL )
1039         {
1040                 hic = ICDecompressOpen( mmioFOURCC('V','I','D','C'), 0, &lpbiIn->bmiHeader, (lpbiOut != NULL) ? &lpbiOut->bmiHeader : NULL );
1041                 if ( hic == (HIC)NULL )
1042                 {
1043                         WARN("no handler\n" );
1044                         goto err;
1045                 }
1046                 bReleaseIC = TRUE;
1047         }
1048         if ( uiFlags != 0 )
1049         {
1050                 FIXME( "unknown flag %08x\n", uiFlags );
1051                 goto err;
1052         }
1053         if ( lpbiIn == NULL || lpBits == NULL )
1054         {
1055                 WARN("invalid argument\n");
1056                 goto err;
1057         }
1058
1059         if ( lpbiOut != NULL )
1060         {
1061                 if ( lpbiOut->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) )
1062                         goto err;
1063                 cbHdr = sizeof(BITMAPINFOHEADER);
1064                 if ( lpbiOut->bmiHeader.biCompression == 3 )
1065                         cbHdr += sizeof(DWORD)*3;
1066                 else
1067                 if ( lpbiOut->bmiHeader.biBitCount <= 8 )
1068                 {
1069                         if ( lpbiOut->bmiHeader.biClrUsed == 0 )
1070                                 cbHdr += sizeof(RGBQUAD) * (1<<lpbiOut->bmiHeader.biBitCount);
1071                         else
1072                                 cbHdr += sizeof(RGBQUAD) * lpbiOut->bmiHeader.biClrUsed;
1073                 }
1074         }
1075         else
1076         {
1077                 TRACE( "get format\n" );
1078
1079                 cbHdr = ICDecompressGetFormatSize(hic,lpbiIn);
1080                 if ( cbHdr < sizeof(BITMAPINFOHEADER) )
1081                         goto err;
1082                 pHdr = (BYTE*)HeapAlloc(GetProcessHeap(),0,cbHdr+sizeof(RGBQUAD)*256);
1083                 if ( pHdr == NULL )
1084                         goto err;
1085                 ZeroMemory( pHdr, cbHdr+sizeof(RGBQUAD)*256 );
1086                 if ( ICDecompressGetFormat( hic, lpbiIn, (BITMAPINFO*)pHdr ) != ICERR_OK )
1087                         goto err;
1088                 lpbiOut = (BITMAPINFO*)pHdr;
1089                 if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
1090                          ICDecompressGetPalette( hic, lpbiIn, lpbiOut ) != ICERR_OK &&
1091                          lpbiIn->bmiHeader.biBitCount == lpbiOut->bmiHeader.biBitCount )
1092                 {
1093                         if ( lpbiIn->bmiHeader.biClrUsed == 0 )
1094                                 memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*(1<<lpbiOut->bmiHeader.biBitCount) );
1095                         else
1096                                 memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*lpbiIn->bmiHeader.biClrUsed );
1097                 }
1098                 if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
1099                          lpbiOut->bmiHeader.biClrUsed == 0 )
1100                         lpbiOut->bmiHeader.biClrUsed = 1<<lpbiOut->bmiHeader.biBitCount;
1101
1102                 lpbiOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1103                 cbHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*lpbiOut->bmiHeader.biClrUsed;
1104         }
1105
1106         biSizeImage = lpbiOut->bmiHeader.biSizeImage;
1107         if ( biSizeImage == 0 )
1108                 biSizeImage = ((((lpbiOut->bmiHeader.biWidth * lpbiOut->bmiHeader.biBitCount + 7) >> 3) + 3) & (~3)) * abs(lpbiOut->bmiHeader.biHeight);
1109
1110         TRACE( "call ICDecompressBegin\n" );
1111
1112         if ( ICDecompressBegin( hic, lpbiIn, lpbiOut ) != ICERR_OK )
1113                 goto err;
1114         bInDecompress = TRUE;
1115
1116         TRACE( "cbHdr %ld, biSizeImage %ld\n", cbHdr, biSizeImage );
1117
1118         hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_ZEROINIT, cbHdr + biSizeImage );
1119         if ( hMem == (HGLOBAL)NULL )
1120         {
1121                 WARN( "out of memory\n" );
1122                 goto err;
1123         }
1124         pMem = (BYTE*)GlobalLock( hMem );
1125         if ( pMem == NULL )
1126                 goto err;
1127         memcpy( pMem, lpbiOut, cbHdr );
1128
1129         TRACE( "call ICDecompress\n" );
1130         if ( ICDecompress( hic, 0, &lpbiIn->bmiHeader, lpBits, &lpbiOut->bmiHeader, pMem+cbHdr ) != ICERR_OK )
1131                 goto err;
1132
1133         bSucceeded = TRUE;
1134 err:
1135         if ( bInDecompress )
1136                 ICDecompressEnd( hic );
1137         if ( bReleaseIC )
1138                 ICClose(hic);
1139         if ( pHdr != NULL )
1140                 HeapFree(GetProcessHeap(),0,pHdr);
1141         if ( pMem != NULL )
1142                 GlobalUnlock( hMem );
1143         if ( !bSucceeded && hMem != (HGLOBAL)NULL )
1144         {
1145                 GlobalFree(hMem); hMem = (HGLOBAL)NULL;
1146         }
1147
1148         return (HANDLE)hMem;
1149 }