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