xref: /reactos/dll/win32/msvfw32/msvideo_main.c (revision 80bb48e7)
1 /*
2  * Copyright 1998 Marcus Meissner
3  * Copyright 2000 Bradley Baetz
4  * Copyright 2003 Michael Günnewig
5  * Copyright 2005 Dmitry Timoshkov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * FIXME: This all assumes 32 bit codecs
22  *		Win95 appears to prefer 32 bit codecs, even from 16 bit code.
23  *		There is the ICOpenFunction16 to worry about still, though.
24  *
25  * TODO
26  *      - no thread safety
27  */
28 
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winreg.h"
36 #include "winnls.h"
37 #include "wingdi.h"
38 #include "wine/winternl.h"
39 #include "winuser.h"
40 #include "commdlg.h"
41 #include "vfw.h"
42 #include "msvideo_private.h"
43 #include "wine/debug.h"
44 #include "wine/heap.h"
45 #include "wine/list.h"
46 
47 /* Drivers32 settings */
48 #define HKLM_DRIVERS32 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32"
49 
50 WINE_DEFAULT_DEBUG_CHANNEL(msvideo);
51 
52 /* This one is a macro in order to work for both ASCII and Unicode */
53 #define fourcc_to_string(str, fcc) do { \
54 	(str)[0] = LOBYTE(LOWORD(fcc)); \
55 	(str)[1] = HIBYTE(LOWORD(fcc)); \
56 	(str)[2] = LOBYTE(HIWORD(fcc)); \
57 	(str)[3] = HIBYTE(HIWORD(fcc)); \
58 	} while(0)
59 
wine_dbgstr_fcc(DWORD fcc)60 static inline const char *wine_dbgstr_fcc( DWORD fcc )
61 {
62     char fcc_str[5];
63     fourcc_to_string(fcc_str, fcc);
64     fcc_str[4] = '\0';
65     /* Last byte may be ' ' in some cases like "DIB " */
66     if (isalnum(fcc_str[0]) && isalnum(fcc_str[1]) && isalnum(fcc_str[2])
67     && (isalnum(fcc_str[3]) || isspace(fcc_str[3])))
68         return wine_dbg_sprintf("%s", fcc_str);
69     return wine_dbg_sprintf("0x%08x", fcc);
70 }
71 
wine_dbgstr_icerr(int ret)72 static const char *wine_dbgstr_icerr( int ret )
73 {
74     const char *str;
75     if (ret <= ICERR_CUSTOM)
76         return wine_dbg_sprintf("ICERR_CUSTOM (%d)", ret);
77 #define XX(x) case (x): str = #x; break
78     switch (ret)
79     {
80         XX(ICERR_OK);
81         XX(ICERR_DONTDRAW);
82         XX(ICERR_NEWPALETTE);
83         XX(ICERR_GOTOKEYFRAME);
84         XX(ICERR_STOPDRAWING);
85         XX(ICERR_UNSUPPORTED);
86         XX(ICERR_BADFORMAT);
87         XX(ICERR_MEMORY);
88         XX(ICERR_INTERNAL);
89         XX(ICERR_BADFLAGS);
90         XX(ICERR_BADPARAM);
91         XX(ICERR_BADSIZE);
92         XX(ICERR_BADHANDLE);
93         XX(ICERR_CANTUPDATE);
94         XX(ICERR_ABORT);
95         XX(ICERR_ERROR);
96         XX(ICERR_BADBITDEPTH);
97         XX(ICERR_BADIMAGESIZE);
98         default: str = wine_dbg_sprintf("UNKNOWN (%d)", ret);
99     }
100 #undef XX
101     return str;
102 }
103 
104 static WINE_HIC*        MSVIDEO_FirstHic /* = NULL */;
105 
106 struct reg_driver
107 {
108     DWORD       fccType;
109     DWORD       fccHandler;
110     DRIVERPROC  proc;
111     struct list entry;
112 };
113 
114 static struct list reg_driver_list = LIST_INIT(reg_driver_list);
115 
116 HMODULE MSVFW32_hModule;
117 
DllMain(HINSTANCE hinst,DWORD reason,LPVOID reserved)118 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
119 {
120     TRACE("%p,%x,%p\n", hinst, reason, reserved);
121 
122     switch(reason)
123     {
124         case DLL_PROCESS_ATTACH:
125             DisableThreadLibraryCalls(hinst);
126             MSVFW32_hModule = hinst;
127             break;
128     }
129     return TRUE;
130 }
131 
132 /******************************************************************
133  *		MSVIDEO_SendMessage
134  *
135  *
136  */
MSVIDEO_SendMessage(WINE_HIC * whic,UINT msg,DWORD_PTR lParam1,DWORD_PTR lParam2)137 static LRESULT MSVIDEO_SendMessage(WINE_HIC* whic, UINT msg, DWORD_PTR lParam1, DWORD_PTR lParam2)
138 {
139     LRESULT     ret;
140 
141 #define XX(x) case x: TRACE("(%p,"#x",0x%08lx,0x%08lx)\n",whic,lParam1,lParam2); break
142 
143     switch (msg) {
144         /* DRV_* */
145         XX(DRV_LOAD);
146         XX(DRV_ENABLE);
147         XX(DRV_OPEN);
148         XX(DRV_CLOSE);
149         XX(DRV_DISABLE);
150         XX(DRV_FREE);
151         /* ICM_RESERVED+X */
152         XX(ICM_ABOUT);
153         XX(ICM_CONFIGURE);
154         XX(ICM_GET);
155         XX(ICM_GETINFO);
156         XX(ICM_GETDEFAULTQUALITY);
157         XX(ICM_GETQUALITY);
158         XX(ICM_GETSTATE);
159         XX(ICM_SETQUALITY);
160         XX(ICM_SET);
161         XX(ICM_SETSTATE);
162         /* ICM_USER+X */
163         XX(ICM_COMPRESS_FRAMES_INFO);
164         XX(ICM_COMPRESS_GET_FORMAT);
165         XX(ICM_COMPRESS_GET_SIZE);
166         XX(ICM_COMPRESS_QUERY);
167         XX(ICM_COMPRESS_BEGIN);
168         XX(ICM_COMPRESS);
169         XX(ICM_COMPRESS_END);
170         XX(ICM_DECOMPRESS_GET_FORMAT);
171         XX(ICM_DECOMPRESS_QUERY);
172         XX(ICM_DECOMPRESS_BEGIN);
173         XX(ICM_DECOMPRESS);
174         XX(ICM_DECOMPRESS_END);
175         XX(ICM_DECOMPRESS_SET_PALETTE);
176         XX(ICM_DECOMPRESS_GET_PALETTE);
177         XX(ICM_DRAW_QUERY);
178         XX(ICM_DRAW_BEGIN);
179         XX(ICM_DRAW_GET_PALETTE);
180         XX(ICM_DRAW_START);
181         XX(ICM_DRAW_STOP);
182         XX(ICM_DRAW_END);
183         XX(ICM_DRAW_GETTIME);
184         XX(ICM_DRAW);
185         XX(ICM_DRAW_WINDOW);
186         XX(ICM_DRAW_SETTIME);
187         XX(ICM_DRAW_REALIZE);
188         XX(ICM_DRAW_FLUSH);
189         XX(ICM_DRAW_RENDERBUFFER);
190         XX(ICM_DRAW_START_PLAY);
191         XX(ICM_DRAW_STOP_PLAY);
192         XX(ICM_DRAW_SUGGESTFORMAT);
193         XX(ICM_DRAW_CHANGEPALETTE);
194         XX(ICM_GETBUFFERSWANTED);
195         XX(ICM_GETDEFAULTKEYFRAMERATE);
196         XX(ICM_DECOMPRESSEX_BEGIN);
197         XX(ICM_DECOMPRESSEX_QUERY);
198         XX(ICM_DECOMPRESSEX);
199         XX(ICM_DECOMPRESSEX_END);
200         XX(ICM_SET_STATUS_PROC);
201     default:
202         FIXME("(%p,0x%08x,0x%08lx,0x%08lx) unknown message\n",whic,msg,lParam1,lParam2);
203     }
204 
205 #undef XX
206 
207     if (whic->driverproc) {
208 	/* dwDriverId parameter is the value returned by the DRV_OPEN */
209         ret = whic->driverproc(whic->driverId, whic->hdrv, msg, lParam1, lParam2);
210     } else {
211         ret = SendDriverMessage(whic->hdrv, msg, lParam1, lParam2);
212     }
213 
214     TRACE("	-> %s\n", wine_dbgstr_icerr(ret));
215     return ret;
216 }
217 
compare_fourcc(DWORD fcc1,DWORD fcc2)218 static int compare_fourcc(DWORD fcc1, DWORD fcc2)
219 {
220   char fcc_str1[4];
221   char fcc_str2[4];
222   fourcc_to_string(fcc_str1, fcc1);
223   fourcc_to_string(fcc_str2, fcc2);
224   return _strnicmp(fcc_str1, fcc_str2, 4);
225 }
226 
get_size_image(LONG width,LONG height,WORD depth)227 static DWORD get_size_image(LONG width, LONG height, WORD depth)
228 {
229     DWORD ret = width * depth;
230     ret = (ret + 7) / 8;    /* divide by byte size, rounding up */
231     ret = (ret + 3) & ~3;   /* align to 4 bytes */
232     ret *= abs(height);
233     return ret;
234 }
235 
236 /******************************************************************
237  *		MSVIDEO_GetHicPtr
238  *
239  *
240  */
MSVIDEO_GetHicPtr(HIC hic)241 static WINE_HIC*   MSVIDEO_GetHicPtr(HIC hic)
242 {
243     WINE_HIC*   whic;
244 
245     for (whic = MSVIDEO_FirstHic; whic && whic->hic != hic; whic = whic->next);
246     return whic;
247 }
248 
249 /***********************************************************************
250  *		VideoForWindowsVersion		[MSVFW32.2]
251  *		VideoForWindowsVersion		[MSVIDEO.2]
252  * Returns the version in major.minor form.
253  * In Windows95 this returns 0x040003b6 (4.950)
254  */
VideoForWindowsVersion(void)255 DWORD WINAPI VideoForWindowsVersion(void)
256 {
257     return 0x040003B6; /* 4.950 */
258 }
259 
260 /***********************************************************************
261  *		ICInfo				[MSVFW32.@]
262  * Get information about an installable compressor. Return TRUE if there
263  * is one.
264  *
265  * PARAMS
266  *   fccType     [I] type of compressor (e.g. 'vidc')
267  *   fccHandler  [I] real fcc for handler or <n>th compressor
268  *   lpicinfo    [O] information about compressor
269  */
ICInfo(DWORD type,DWORD handler,ICINFO * info)270 BOOL VFWAPI ICInfo(DWORD type, DWORD handler, ICINFO *info)
271 {
272     char name_buf[10], buf[2048];
273     DWORD ret_type, ret_handler;
274     struct reg_driver *driver;
275     DWORD i, count = 0;
276     LONG res;
277     HKEY key;
278 
279     TRACE("type %s, handler %s, info %p.\n",
280             wine_dbgstr_fcc(type), wine_dbgstr_fcc(handler), info);
281 
282     memset(info, 0, sizeof(*info));
283     info->dwSize = sizeof(*info);
284     info->dwVersionICM = ICVERSION;
285 
286     if (!RegOpenKeyExA(HKEY_LOCAL_MACHINE, HKLM_DRIVERS32, 0, KEY_QUERY_VALUE, &key))
287     {
288         i = 0;
289         for (;;)
290         {
291             DWORD name_len = ARRAY_SIZE(name_buf), driver_len = ARRAY_SIZE(info->szDriver);
292 
293             res = RegEnumValueA(key, i++, name_buf, &name_len, 0, 0, (BYTE *)buf, &driver_len);
294             if (res == ERROR_NO_MORE_ITEMS) break;
295 
296             if (name_len != 9 || name_buf[4] != '.') continue;
297             ret_type = mmioStringToFOURCCA(name_buf, 0);
298             ret_handler = mmioStringToFOURCCA(name_buf + 5, 0);
299             if (type && compare_fourcc(type, ret_type)) continue;
300             if (compare_fourcc(handler, ret_handler) && handler != count++) continue;
301 
302             info->fccType = ret_type;
303             info->fccHandler = ret_handler;
304             MultiByteToWideChar(CP_ACP, 0, buf, -1, info->szDriver, ARRAY_SIZE(info->szDriver));
305             TRACE("Returning codec %s, driver %s.\n", debugstr_a(name_buf), debugstr_a(buf));
306             return TRUE;
307         }
308         RegCloseKey(key);
309     }
310 
311     if (GetPrivateProfileSectionA("drivers32", buf, sizeof(buf), "system.ini"))
312     {
313         char *s;
314         for (s = buf; *s; s += strlen(s) + 1)
315         {
316             if (s[4] != '.' || s[9] != '=') continue;
317             ret_type = mmioStringToFOURCCA(s, 0);
318             ret_handler = mmioStringToFOURCCA(s + 5, 0);
319             if (type && compare_fourcc(type, ret_type)) continue;
320             if (compare_fourcc(handler, ret_handler) && handler != count++) continue;
321 
322             info->fccType = ret_type;
323             info->fccHandler = ret_handler;
324             MultiByteToWideChar(CP_ACP, 0, s + 10, -1, info->szDriver, ARRAY_SIZE(info->szDriver));
325             TRACE("Returning codec %s, driver %s.\n", debugstr_an(s, 8), debugstr_a(s + 10));
326             return TRUE;
327         }
328     }
329 
330     LIST_FOR_EACH_ENTRY(driver, &reg_driver_list, struct reg_driver, entry)
331     {
332         if (type && compare_fourcc(type, driver->fccType)) continue;
333         if (compare_fourcc(handler, driver->fccHandler) && handler != count++) continue;
334         if (driver->proc(0, NULL, ICM_GETINFO, (DWORD_PTR)info, sizeof(*info)) == sizeof(*info))
335             return TRUE;
336     }
337 
338     info->fccType = type;
339     info->fccHandler = handler;
340     WARN("No driver found for codec %s.%s.\n", wine_dbgstr_fcc(type), wine_dbgstr_fcc(handler));
341     return FALSE;
342 }
343 
344 static DWORD IC_HandleRef = 1;
345 
346 /***********************************************************************
347  *              ICInstall                       [MSVFW32.@]
348  */
ICInstall(DWORD type,DWORD handler,LPARAM lparam,char * desc,UINT flags)349 BOOL VFWAPI ICInstall(DWORD type, DWORD handler, LPARAM lparam, char *desc, UINT flags)
350 {
351     struct reg_driver *driver;
352 
353     TRACE("type %s, handler %s, lparam %#lx, desc %s, flags %#x.\n",
354             wine_dbgstr_fcc(type), wine_dbgstr_fcc(handler), lparam, debugstr_a(desc), flags);
355 
356     LIST_FOR_EACH_ENTRY(driver, &reg_driver_list, struct reg_driver, entry)
357     {
358         if (!compare_fourcc(type, driver->fccType)
359                 && !compare_fourcc(handler, driver->fccHandler))
360         {
361             return FALSE;
362         }
363     }
364 
365     switch (flags)
366     {
367     case ICINSTALL_FUNCTION:
368         if (!(driver = heap_alloc_zero(sizeof(*driver))))
369             return FALSE;
370         driver->fccType = type;
371         driver->fccHandler = handler;
372         driver->proc = (DRIVERPROC)lparam;
373         list_add_tail(&reg_driver_list, &driver->entry);
374         return TRUE;
375     case ICINSTALL_DRIVER:
376     {
377         const char *driver = (const char *)lparam;
378         char value[10];
379         HKEY key;
380         LONG res;
381 
382         if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, HKLM_DRIVERS32, 0, KEY_SET_VALUE, &key))
383             return FALSE;
384         fourcc_to_string(value, type);
385         value[4] = '.';
386         fourcc_to_string(value + 5, handler);
387         value[9] = 0;
388         res = RegSetValueExA(key, value, 0, REG_SZ, (const BYTE *)driver, strlen(driver) + 1);
389         RegCloseKey(key);
390         return !res;
391     }
392     default:
393         FIXME("Unhandled flags %#x.\n", flags);
394         return FALSE;
395     }
396 }
397 
398 /***********************************************************************
399  *              ICRemove                        [MSVFW32.@]
400  */
ICRemove(DWORD type,DWORD handler,UINT flags)401 BOOL VFWAPI ICRemove(DWORD type, DWORD handler, UINT flags)
402 {
403     struct reg_driver *driver;
404     char value[10];
405     HKEY key;
406     LONG res;
407 
408     TRACE("type %s, handler %s, flags %#x.\n",
409             wine_dbgstr_fcc(type), wine_dbgstr_fcc(handler), flags);
410 
411     LIST_FOR_EACH_ENTRY(driver, &reg_driver_list, struct reg_driver, entry)
412     {
413         if (!compare_fourcc(type, driver->fccType)
414                 && !compare_fourcc(handler, driver->fccHandler))
415         {
416             list_remove(&driver->entry);
417             heap_free(driver);
418             return TRUE;
419         }
420     }
421 
422     if (!RegOpenKeyExA(HKEY_LOCAL_MACHINE, HKLM_DRIVERS32, 0, KEY_SET_VALUE, &key))
423     {
424         fourcc_to_string(value, type);
425         value[4] = '.';
426         fourcc_to_string(value + 5, handler);
427         value[9] = 0;
428         res = RegDeleteValueA(key, value);
429         RegCloseKey(key);
430         return !res;
431     }
432 
433     return FALSE;
434 }
435 
436 
437 /***********************************************************************
438  *		ICOpen				[MSVFW32.@]
439  * Opens an installable compressor. Return special handle.
440  */
ICOpen(DWORD fccType,DWORD fccHandler,UINT wMode)441 HIC VFWAPI ICOpen(DWORD fccType, DWORD fccHandler, UINT wMode)
442 {
443     WCHAR		codecname[10];
444     ICOPEN		icopen;
445     WINE_HIC*           whic;
446     static const WCHAR  drv32W[] = {'d','r','i','v','e','r','s','3','2','\0'};
447     struct reg_driver *driver;
448     HDRVR hdrv = NULL;
449 
450     TRACE("(%s,%s,0x%08x)\n", wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wMode);
451 
452     if (!fccHandler) /* No specific handler, return the first valid for wMode */
453     {
454         HIC local;
455         ICINFO info;
456         DWORD loop = 0;
457         info.dwSize = sizeof(info);
458         while(ICInfo(fccType, loop++, &info))
459         {
460             /* Ensure fccHandler is not 0x0 because we will recurse on ICOpen */
461             if(!info.fccHandler)
462                 continue;
463             local = ICOpen(fccType, info.fccHandler, wMode);
464             if (local != 0)
465             {
466                 TRACE("Returning %s as default handler for %s\n",
467                       wine_dbgstr_fcc(info.fccHandler), wine_dbgstr_fcc(fccType));
468                 return local;
469             }
470         }
471     }
472 
473     LIST_FOR_EACH_ENTRY(driver, &reg_driver_list, struct reg_driver, entry)
474     {
475         if (!compare_fourcc(fccType, driver->fccType)
476                 && !compare_fourcc(fccHandler, driver->fccHandler))
477         {
478             return ICOpenFunction(driver->fccType, driver->fccHandler, wMode, driver->proc);
479         }
480     }
481 
482     /* Well, lParam2 is in fact a LPVIDEO_OPEN_PARMS, but it has the
483      * same layout as ICOPEN
484      */
485     icopen.dwSize      = sizeof(ICOPEN);
486     icopen.fccType     = fccType;
487     icopen.fccHandler  = fccHandler;
488     icopen.dwVersion   = 0x00001000; /* FIXME */
489     icopen.dwFlags     = wMode;
490     icopen.dwError     = 0;
491     icopen.pV1Reserved = NULL;
492     icopen.pV2Reserved = NULL;
493     icopen.dnDevNode   = 0; /* FIXME */
494 
495     if (!hdrv)
496     {
497         /* normalize to lower case as in 'vidc' */
498         ((char*)&fccType)[0] = tolower(((char*)&fccType)[0]);
499         ((char*)&fccType)[1] = tolower(((char*)&fccType)[1]);
500         ((char*)&fccType)[2] = tolower(((char*)&fccType)[2]);
501         ((char*)&fccType)[3] = tolower(((char*)&fccType)[3]);
502         icopen.fccType = fccType;
503         /* Seek the driver in the registry */
504         fourcc_to_string(codecname, fccType);
505         codecname[4] = '.';
506         fourcc_to_string(codecname + 5, fccHandler);
507         codecname[9] = '\0';
508 
509         hdrv = OpenDriver(codecname, drv32W, (LPARAM)&icopen);
510         if (!hdrv)
511             return 0;
512     }
513 
514     if (!(whic = heap_alloc(sizeof(*whic))))
515     {
516         CloseDriver(hdrv, 0, 0);
517         return FALSE;
518     }
519     whic->hdrv          = hdrv;
520     whic->driverproc    = NULL;
521     whic->type          = fccType;
522     whic->handler       = fccHandler;
523     while (MSVIDEO_GetHicPtr((HIC)(ULONG_PTR)IC_HandleRef) != NULL) IC_HandleRef++;
524     whic->hic           = (HIC)(ULONG_PTR)IC_HandleRef++;
525     whic->next          = MSVIDEO_FirstHic;
526     MSVIDEO_FirstHic = whic;
527 
528     TRACE("=> %p\n", whic->hic);
529     return whic->hic;
530 }
531 
532 /***********************************************************************
533  *		ICOpenFunction			[MSVFW32.@]
534  */
ICOpenFunction(DWORD fccType,DWORD fccHandler,UINT wMode,DRIVERPROC lpfnHandler)535 HIC VFWAPI ICOpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode, DRIVERPROC lpfnHandler)
536 {
537     ICOPEN      icopen;
538     WINE_HIC*   whic;
539 
540     TRACE("(%s,%s,%d,%p)\n",
541           wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wMode, lpfnHandler);
542 
543     icopen.dwSize      = sizeof(ICOPEN);
544     icopen.fccType     = fccType;
545     icopen.fccHandler  = fccHandler;
546     icopen.dwVersion   = ICVERSION;
547     icopen.dwFlags     = wMode;
548     icopen.dwError     = 0;
549     icopen.pV1Reserved = NULL;
550     icopen.pV2Reserved = NULL;
551     icopen.dnDevNode   = 0; /* FIXME */
552 
553     if (!(whic = heap_alloc(sizeof(*whic))))
554         return NULL;
555 
556     whic->driverproc   = lpfnHandler;
557     while (MSVIDEO_GetHicPtr((HIC)(ULONG_PTR)IC_HandleRef) != NULL) IC_HandleRef++;
558     whic->hic          = (HIC)(ULONG_PTR)IC_HandleRef++;
559     whic->next         = MSVIDEO_FirstHic;
560     MSVIDEO_FirstHic = whic;
561 
562     /* Now try opening/loading the driver. Taken from DRIVER_AddToList */
563     /* What if the function is used more than once? */
564 
565     if (MSVIDEO_SendMessage(whic, DRV_LOAD, 0L, 0L) != DRV_SUCCESS)
566     {
567         WARN("DRV_LOAD failed for hic %p\n", whic->hic);
568         MSVIDEO_FirstHic = whic->next;
569         heap_free(whic);
570         return 0;
571     }
572     /* return value is not checked */
573     MSVIDEO_SendMessage(whic, DRV_ENABLE, 0L, 0L);
574 
575     whic->driverId = (DWORD)MSVIDEO_SendMessage(whic, DRV_OPEN, 0, (DWORD_PTR)&icopen);
576     /* FIXME: What should we put here? */
577     whic->hdrv = NULL;
578 
579     if (whic->driverId == 0)
580     {
581         WARN("DRV_OPEN failed for hic %p\n", whic->hic);
582         MSVIDEO_FirstHic = whic->next;
583         heap_free(whic);
584         return 0;
585     }
586 
587     TRACE("=> %p\n", whic->hic);
588     return whic->hic;
589 }
590 
591 /***********************************************************************
592  *		ICGetInfo			[MSVFW32.@]
593  */
ICGetInfo(HIC hic,ICINFO * picinfo,DWORD cb)594 LRESULT VFWAPI ICGetInfo(HIC hic, ICINFO *picinfo, DWORD cb)
595 {
596     LRESULT	ret;
597     WINE_HIC*   whic = MSVIDEO_GetHicPtr(hic);
598 
599     TRACE("(%p,%p,%d)\n", hic, picinfo, cb);
600 
601     if (!whic) return ICERR_BADHANDLE;
602     if (!picinfo) return MMSYSERR_INVALPARAM;
603 
604     /* (WS) The field szDriver should be initialized because the driver
605      * is not obliged and often will not do it. Some applications, like
606      * VirtualDub, rely on this field and will occasionally crash if it
607      * goes uninitialized.
608      */
609     if (cb >= sizeof(ICINFO)) picinfo->szDriver[0] = '\0';
610 
611     ret = ICSendMessage(hic, ICM_GETINFO, (DWORD_PTR)picinfo, cb);
612 
613     /* (WS) When szDriver was not supplied by the driver itself, apparently
614      * Windows will set its value equal to the driver file name. This can
615      * be obtained from the registry as we do here.
616      */
617     if (cb >= sizeof(ICINFO) && picinfo->szDriver[0] == 0)
618     {
619         ICINFO  ii;
620 
621         memset(&ii, 0, sizeof(ii));
622         ii.dwSize = sizeof(ii);
623         ICInfo(picinfo->fccType, picinfo->fccHandler, &ii);
624         lstrcpyW(picinfo->szDriver, ii.szDriver);
625     }
626 
627     return ret;
628 }
629 
630 /***********************************************************************
631  *              ICLocate                        [MSVFW32.@]
632  */
ICLocate(DWORD type,DWORD handler,BITMAPINFOHEADER * in,BITMAPINFOHEADER * out,WORD mode)633 HIC VFWAPI ICLocate(DWORD type, DWORD handler, BITMAPINFOHEADER *in,
634         BITMAPINFOHEADER *out, WORD mode)
635 {
636     ICINFO info = {sizeof(info)};
637     UINT msg;
638     HIC hic;
639     DWORD i;
640 
641     TRACE("type %s, handler %s, in %p, out %p, mode %u.\n",
642             wine_dbgstr_fcc(type), wine_dbgstr_fcc(handler), in, out, mode);
643 
644     switch (mode)
645     {
646     case ICMODE_FASTCOMPRESS:
647     case ICMODE_COMPRESS:
648         msg = ICM_COMPRESS_QUERY;
649         break;
650     case ICMODE_FASTDECOMPRESS:
651     case ICMODE_DECOMPRESS:
652         msg = ICM_DECOMPRESS_QUERY;
653         break;
654     case ICMODE_DRAW:
655         msg = ICM_DRAW_QUERY;
656         break;
657     default:
658         FIXME("Unhandled mode %#x.\n", mode);
659         return 0;
660     }
661 
662     if ((hic = ICOpen(type, handler, mode)))
663     {
664         if (!ICSendMessage(hic, msg, (DWORD_PTR)in, (DWORD_PTR)out))
665         {
666             TRACE("Found codec %s.%s.\n", wine_dbgstr_fcc(type),
667                     wine_dbgstr_fcc(handler));
668             return hic;
669         }
670         ICClose(hic);
671     }
672 
673     for (i = 0; ICInfo(type, i, &info); ++i)
674     {
675         if ((hic = ICOpen(info.fccType, info.fccHandler, mode)))
676         {
677             if (!ICSendMessage(hic, msg, (DWORD_PTR)in, (DWORD_PTR)out))
678             {
679                 TRACE("Found codec %s.%s.\n", wine_dbgstr_fcc(info.fccType),
680                         wine_dbgstr_fcc(info.fccHandler));
681                 return hic;
682             }
683             ICClose(hic);
684         }
685     }
686 
687     if (type == streamtypeVIDEO)
688         return ICLocate(ICTYPE_VIDEO, handler, in, out, mode);
689 
690     WARN("Could not find a driver for codec %s.%s.\n",
691             wine_dbgstr_fcc(type), wine_dbgstr_fcc(handler));
692 
693     return 0;
694 }
695 
696 /***********************************************************************
697  *		ICGetDisplayFormat			[MSVFW32.@]
698  */
ICGetDisplayFormat(HIC hic,BITMAPINFOHEADER * in,BITMAPINFOHEADER * out,int depth,int width,int height)699 HIC VFWAPI ICGetDisplayFormat(HIC hic, BITMAPINFOHEADER *in, BITMAPINFOHEADER *out,
700                               int depth, int width, int height)
701 {
702     HIC tmphic = hic;
703 
704     TRACE("(%p, %p, %p, %d, %d, %d)\n", hic, in, out, depth, width, height);
705 
706     if (!tmphic)
707     {
708         tmphic = ICLocate(ICTYPE_VIDEO, 0, in, NULL, ICMODE_DECOMPRESS);
709         if (!tmphic)
710             return NULL;
711     }
712 
713     if (ICDecompressQuery(tmphic, in, NULL))
714         goto err;
715 
716     if (width <= 0 || height <= 0)
717     {
718         width = in->biWidth;
719         height = in->biHeight;
720     }
721 
722     if (!depth)
723         depth = 32;
724 
725     *out = *in;
726     out->biSize = sizeof(*out);
727     out->biWidth = width;
728     out->biHeight = height;
729     out->biCompression = BI_RGB;
730     out->biSizeImage = get_size_image(width, height, depth);
731 
732     /* first try the given depth */
733     out->biBitCount = depth;
734     out->biSizeImage = get_size_image(width, height, out->biBitCount);
735     if (!ICDecompressQuery(tmphic, in, out))
736     {
737         if (depth == 8)
738             ICDecompressGetPalette(tmphic, in, out);
739         return tmphic;
740     }
741 
742     /* then try 16, both with BI_RGB and BI_BITFIELDS */
743     if (depth <= 16)
744     {
745         out->biBitCount = 16;
746         out->biSizeImage = get_size_image(width, height, out->biBitCount);
747         if (!ICDecompressQuery(tmphic, in, out))
748             return tmphic;
749 
750         out->biCompression = BI_BITFIELDS;
751         if (!ICDecompressQuery(tmphic, in, out))
752             return tmphic;
753         out->biCompression = BI_RGB;
754     }
755 
756     /* then try 24 */
757     if (depth <= 24)
758     {
759         out->biBitCount = 24;
760         out->biSizeImage = get_size_image(width, height, out->biBitCount);
761         if (!ICDecompressQuery(tmphic, in, out))
762             return tmphic;
763     }
764 
765     /* then try 32 */
766     if (depth <= 32)
767     {
768         out->biBitCount = 32;
769         out->biSizeImage = get_size_image(width, height, out->biBitCount);
770         if (!ICDecompressQuery(tmphic, in, out))
771             return tmphic;
772     }
773 
774     /* as a last resort, try 32 bpp with the original width and height */
775     out->biWidth = in->biWidth;
776     out->biHeight = in->biHeight;
777     out->biBitCount = 32;
778     out->biSizeImage = get_size_image(out->biWidth, out->biHeight, out->biBitCount);
779     if (!ICDecompressQuery(tmphic, in, out))
780         return tmphic;
781 
782     /* finally, ask the compressor for its default output format */
783     if (!ICSendMessage(tmphic, ICM_DECOMPRESS_GET_FORMAT, (DWORD_PTR)in, (DWORD_PTR)out))
784         return tmphic;
785 
786 err:
787     if (hic != tmphic)
788         ICClose(tmphic);
789 
790     return NULL;
791 }
792 
793 /***********************************************************************
794  *		ICCompress			[MSVFW32.@]
795  */
796 DWORD VFWAPIV
ICCompress(HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiOutput,LPVOID lpData,LPBITMAPINFOHEADER lpbiInput,LPVOID lpBits,LPDWORD lpckid,LPDWORD lpdwFlags,LONG lFrameNum,DWORD dwFrameSize,DWORD dwQuality,LPBITMAPINFOHEADER lpbiPrev,LPVOID lpPrev)797 ICCompress(
798 	HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiOutput,LPVOID lpData,
799 	LPBITMAPINFOHEADER lpbiInput,LPVOID lpBits,LPDWORD lpckid,
800 	LPDWORD lpdwFlags,LONG lFrameNum,DWORD dwFrameSize,DWORD dwQuality,
801 	LPBITMAPINFOHEADER lpbiPrev,LPVOID lpPrev)
802 {
803 	ICCOMPRESS	iccmp;
804 
805 	TRACE("(%p,%d,%p,%p,%p,%p,...)\n",hic,dwFlags,lpbiOutput,lpData,lpbiInput,lpBits);
806 
807 	iccmp.dwFlags		= dwFlags;
808 
809 	iccmp.lpbiOutput	= lpbiOutput;
810 	iccmp.lpOutput		= lpData;
811 	iccmp.lpbiInput		= lpbiInput;
812 	iccmp.lpInput		= lpBits;
813 
814 	iccmp.lpckid		= lpckid;
815 	iccmp.lpdwFlags		= lpdwFlags;
816 	iccmp.lFrameNum		= lFrameNum;
817 	iccmp.dwFrameSize	= dwFrameSize;
818 	iccmp.dwQuality		= dwQuality;
819 	iccmp.lpbiPrev		= lpbiPrev;
820 	iccmp.lpPrev		= lpPrev;
821 	return ICSendMessage(hic,ICM_COMPRESS,(DWORD_PTR)&iccmp,sizeof(iccmp));
822 }
823 
824 /***********************************************************************
825  *		ICDecompress			[MSVFW32.@]
826  */
ICDecompress(HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiFormat,LPVOID lpData,LPBITMAPINFOHEADER lpbi,LPVOID lpBits)827 DWORD VFWAPIV  ICDecompress(HIC hic,DWORD dwFlags,LPBITMAPINFOHEADER lpbiFormat,
828 				LPVOID lpData,LPBITMAPINFOHEADER lpbi,LPVOID lpBits)
829 {
830 	ICDECOMPRESS	icd;
831 	DWORD ret;
832 
833 	TRACE("(%p,%d,%p,%p,%p,%p)\n",hic,dwFlags,lpbiFormat,lpData,lpbi,lpBits);
834 
835 	icd.dwFlags	= dwFlags;
836 	icd.lpbiInput	= lpbiFormat;
837 	icd.lpInput	= lpData;
838 
839 	icd.lpbiOutput	= lpbi;
840 	icd.lpOutput	= lpBits;
841 	icd.ckid	= 0;
842 	ret = ICSendMessage(hic,ICM_DECOMPRESS,(DWORD_PTR)&icd,sizeof(ICDECOMPRESS));
843 
844 	return ret;
845 }
846 
847 
848 struct choose_compressor
849 {
850     UINT flags;
851     LPCSTR title;
852     COMPVARS cv;
853 };
854 
855 struct codec_info
856 {
857     HIC hic;
858     ICINFO icinfo;
859 };
860 
enum_compressors(HWND list,COMPVARS * pcv,BOOL enum_all)861 static BOOL enum_compressors(HWND list, COMPVARS *pcv, BOOL enum_all)
862 {
863     UINT id, total = 0;
864     ICINFO icinfo;
865 
866     id = 0;
867 
868     while (ICInfo(pcv->fccType, id, &icinfo))
869     {
870         struct codec_info *ic;
871         DWORD idx;
872         HIC hic;
873 
874         id++;
875 
876         hic = ICOpen(icinfo.fccType, icinfo.fccHandler, ICMODE_COMPRESS);
877 
878         if (hic)
879         {
880             /* for unknown reason fccHandler reported by the driver
881              * doesn't always work, use the one returned by ICInfo instead.
882              */
883             DWORD fccHandler = icinfo.fccHandler;
884 
885             if (!enum_all && pcv->lpbiIn)
886             {
887                 if (ICCompressQuery(hic, pcv->lpbiIn, NULL) != ICERR_OK)
888                 {
889                     TRACE("fccHandler %s doesn't support input DIB format %d\n",
890                           wine_dbgstr_fcc(icinfo.fccHandler), pcv->lpbiIn->bmiHeader.biCompression);
891                     ICClose(hic);
892                     continue;
893                 }
894             }
895 
896             ICGetInfo(hic, &icinfo, sizeof(icinfo));
897             icinfo.fccHandler = fccHandler;
898 
899             idx = SendMessageW(list, CB_ADDSTRING, 0, (LPARAM)icinfo.szDescription);
900 
901             ic = heap_alloc(sizeof(*ic));
902             ic->icinfo = icinfo;
903             ic->hic = hic;
904             SendMessageW(list, CB_SETITEMDATA, idx, (LPARAM)ic);
905         }
906         total++;
907     }
908 
909     return total != 0;
910 }
911 
icm_choose_compressor_dlgproc(HWND hdlg,UINT msg,WPARAM wparam,LPARAM lparam)912 static INT_PTR CALLBACK icm_choose_compressor_dlgproc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
913 {
914     switch (msg)
915     {
916     case WM_INITDIALOG:
917     {
918         struct codec_info *ic;
919         WCHAR buf[128];
920         struct choose_compressor *choose_comp = (struct choose_compressor *)lparam;
921 
922         SetWindowLongPtrW(hdlg, DWLP_USER, lparam);
923 
924         /* FIXME */
925         choose_comp->flags &= ~(ICMF_CHOOSE_DATARATE | ICMF_CHOOSE_KEYFRAME);
926 
927         if (choose_comp->title)
928             SetWindowTextA(hdlg, choose_comp->title);
929 
930         if (!(choose_comp->flags & ICMF_CHOOSE_DATARATE))
931         {
932             ShowWindow(GetDlgItem(hdlg, IDC_DATARATE_CHECKBOX), SW_HIDE);
933             ShowWindow(GetDlgItem(hdlg, IDC_DATARATE), SW_HIDE);
934             ShowWindow(GetDlgItem(hdlg, IDC_DATARATE_KB), SW_HIDE);
935         }
936 
937         if (!(choose_comp->flags & ICMF_CHOOSE_KEYFRAME))
938         {
939             ShowWindow(GetDlgItem(hdlg, IDC_KEYFRAME_CHECKBOX), SW_HIDE);
940             ShowWindow(GetDlgItem(hdlg, IDC_KEYFRAME), SW_HIDE);
941             ShowWindow(GetDlgItem(hdlg, IDC_KEYFRAME_FRAMES), SW_HIDE);
942         }
943 
944         /* FIXME */
945         EnableWindow(GetDlgItem(hdlg, IDC_QUALITY_SCROLL), FALSE);
946         EnableWindow(GetDlgItem(hdlg, IDC_QUALITY_TXT), FALSE);
947 
948         /*if (!(choose_comp->flags & ICMF_CHOOSE_PREVIEW))
949             ShowWindow(GetDlgItem(hdlg, IDC_PREVIEW), SW_HIDE);*/
950 
951         LoadStringW(MSVFW32_hModule, IDS_FULLFRAMES, buf, 128);
952         SendDlgItemMessageW(hdlg, IDC_COMP_LIST, CB_ADDSTRING, 0, (LPARAM)buf);
953 
954         ic = heap_alloc(sizeof(*ic));
955         ic->icinfo.fccType = streamtypeVIDEO;
956         ic->icinfo.fccHandler = comptypeDIB;
957         ic->hic = 0;
958         SendDlgItemMessageW(hdlg, IDC_COMP_LIST, CB_SETITEMDATA, 0, (LPARAM)ic);
959 
960         enum_compressors(GetDlgItem(hdlg, IDC_COMP_LIST), &choose_comp->cv, choose_comp->flags & ICMF_CHOOSE_ALLCOMPRESSORS);
961 
962         SendDlgItemMessageW(hdlg, IDC_COMP_LIST, CB_SETCURSEL, 0, 0);
963         SetFocus(GetDlgItem(hdlg, IDC_COMP_LIST));
964 
965         SetWindowLongPtrW(hdlg, DWLP_USER, (ULONG_PTR)choose_comp);
966         break;
967     }
968 
969     case WM_COMMAND:
970         switch (LOWORD(wparam))
971         {
972         case IDC_COMP_LIST:
973         {
974             INT cur_sel;
975             struct codec_info *ic;
976             BOOL can_configure = FALSE, can_about = FALSE;
977             struct choose_compressor *choose_comp;
978 
979             if (HIWORD(wparam) != CBN_SELCHANGE && HIWORD(wparam) != CBN_SETFOCUS)
980                 break;
981 
982             choose_comp = (struct choose_compressor *)GetWindowLongPtrW(hdlg, DWLP_USER);
983 
984             cur_sel = SendMessageW((HWND)lparam, CB_GETCURSEL, 0, 0);
985 
986             ic = (struct codec_info *)SendMessageW((HWND)lparam, CB_GETITEMDATA, cur_sel, 0);
987             if (ic && ic->hic)
988             {
989                 if (ICQueryConfigure(ic->hic) == DRVCNF_OK)
990                     can_configure = TRUE;
991                 if (ICQueryAbout(ic->hic) == DRVCNF_OK)
992                     can_about = TRUE;
993             }
994             EnableWindow(GetDlgItem(hdlg, IDC_CONFIGURE), can_configure);
995             EnableWindow(GetDlgItem(hdlg, IDC_ABOUT), can_about);
996 
997             if (choose_comp->flags & ICMF_CHOOSE_DATARATE)
998             {
999                 /* FIXME */
1000             }
1001             if (choose_comp->flags & ICMF_CHOOSE_KEYFRAME)
1002             {
1003                 /* FIXME */
1004             }
1005 
1006             break;
1007         }
1008 
1009         case IDC_CONFIGURE:
1010         case IDC_ABOUT:
1011         {
1012             HWND list = GetDlgItem(hdlg, IDC_COMP_LIST);
1013             INT cur_sel;
1014             struct codec_info *ic;
1015 
1016             if (HIWORD(wparam) != BN_CLICKED)
1017                 break;
1018 
1019             cur_sel = SendMessageW(list, CB_GETCURSEL, 0, 0);
1020 
1021             ic = (struct codec_info *)SendMessageW(list, CB_GETITEMDATA, cur_sel, 0);
1022             if (ic && ic->hic)
1023             {
1024                 if (LOWORD(wparam) == IDC_CONFIGURE)
1025                     ICConfigure(ic->hic, hdlg);
1026                 else
1027                     ICAbout(ic->hic, hdlg);
1028             }
1029 
1030             break;
1031         }
1032 
1033         case IDOK:
1034         {
1035             HWND list = GetDlgItem(hdlg, IDC_COMP_LIST);
1036             INT cur_sel;
1037             struct codec_info *ic;
1038 
1039             if (HIWORD(wparam) != BN_CLICKED)
1040                 break;
1041 
1042             cur_sel = SendMessageW(list, CB_GETCURSEL, 0, 0);
1043             ic = (struct codec_info *)SendMessageW(list, CB_GETITEMDATA, cur_sel, 0);
1044             if (ic)
1045             {
1046                 struct choose_compressor *choose_comp = (struct choose_compressor *)GetWindowLongPtrW(hdlg, DWLP_USER);
1047 
1048                 choose_comp->cv.hic = ic->hic;
1049                 choose_comp->cv.fccType = ic->icinfo.fccType;
1050                 choose_comp->cv.fccHandler = ic->icinfo.fccHandler;
1051                 /* FIXME: fill everything else */
1052 
1053                 /* prevent closing the codec handle below */
1054                 ic->hic = 0;
1055             }
1056         }
1057         /* fall through */
1058         case IDCANCEL:
1059         {
1060             HWND list = GetDlgItem(hdlg, IDC_COMP_LIST);
1061             INT idx = 0;
1062 
1063             if (HIWORD(wparam) != BN_CLICKED)
1064                 break;
1065 
1066             while (1)
1067             {
1068                 struct codec_info *ic;
1069 
1070                 ic = (struct codec_info *)SendMessageW(list, CB_GETITEMDATA, idx++, 0);
1071 
1072                 if (!ic || (LONG_PTR)ic == CB_ERR) break;
1073 
1074                 if (ic->hic) ICClose(ic->hic);
1075                 heap_free(ic);
1076             }
1077 
1078             EndDialog(hdlg, LOWORD(wparam) == IDOK);
1079             break;
1080         }
1081 
1082         default:
1083             break;
1084         }
1085         break;
1086 
1087     default:
1088         break;
1089     }
1090 
1091     return FALSE;
1092 }
1093 
1094 /***********************************************************************
1095  *		ICCompressorChoose   [MSVFW32.@]
1096  */
ICCompressorChoose(HWND hwnd,UINT uiFlags,LPVOID pvIn,LPVOID lpData,PCOMPVARS pc,LPSTR lpszTitle)1097 BOOL VFWAPI ICCompressorChoose(HWND hwnd, UINT uiFlags, LPVOID pvIn,
1098                                LPVOID lpData, PCOMPVARS pc, LPSTR lpszTitle)
1099 {
1100     struct choose_compressor choose_comp;
1101     BOOL ret;
1102 
1103     TRACE("(%p,%08x,%p,%p,%p,%s)\n", hwnd, uiFlags, pvIn, lpData, pc, lpszTitle);
1104 
1105     if (!pc || pc->cbSize != sizeof(COMPVARS))
1106         return FALSE;
1107 
1108     if (!(pc->dwFlags & ICMF_COMPVARS_VALID))
1109     {
1110         pc->dwFlags   = 0;
1111         pc->fccType   = pc->fccHandler = 0;
1112         pc->hic       = NULL;
1113         pc->lpbiIn    = NULL;
1114         pc->lpbiOut   = NULL;
1115         pc->lpBitsOut = pc->lpBitsPrev = pc->lpState = NULL;
1116         pc->lQ        = ICQUALITY_DEFAULT;
1117         pc->lKey      = -1;
1118         pc->lDataRate = 300; /* kB */
1119         pc->lpState   = NULL;
1120         pc->cbState   = 0;
1121     }
1122     if (pc->fccType == 0)
1123         pc->fccType = ICTYPE_VIDEO;
1124 
1125     choose_comp.cv = *pc;
1126     choose_comp.flags = uiFlags;
1127     choose_comp.title = lpszTitle;
1128 
1129     ret = DialogBoxParamW(MSVFW32_hModule, MAKEINTRESOURCEW(ICM_CHOOSE_COMPRESSOR), hwnd,
1130                           icm_choose_compressor_dlgproc, (LPARAM)&choose_comp);
1131 
1132     if (ret)
1133     {
1134         *pc = choose_comp.cv;
1135         pc->dwFlags |= ICMF_COMPVARS_VALID;
1136     }
1137 
1138     return ret;
1139 }
1140 
1141 
1142 /***********************************************************************
1143  *		ICCompressorFree   [MSVFW32.@]
1144  */
ICCompressorFree(PCOMPVARS pc)1145 void VFWAPI ICCompressorFree(PCOMPVARS pc)
1146 {
1147     TRACE("(%p)\n", pc);
1148 
1149     if (pc && pc->cbSize == sizeof(COMPVARS))
1150     {
1151         if (pc->hic)
1152         {
1153             ICClose(pc->hic);
1154             pc->hic = NULL;
1155         }
1156         heap_free(pc->lpbiIn);
1157         pc->lpbiIn = NULL;
1158         heap_free(pc->lpBitsOut);
1159         pc->lpBitsOut = NULL;
1160         heap_free(pc->lpBitsPrev);
1161         pc->lpBitsPrev = NULL;
1162         heap_free(pc->lpState);
1163         pc->lpState = NULL;
1164         pc->dwFlags = 0;
1165     }
1166 }
1167 
1168 /***********************************************************************
1169  *		ICSendMessage			[MSVFW32.@]
1170  */
ICSendMessage(HIC hic,UINT msg,DWORD_PTR lParam1,DWORD_PTR lParam2)1171 LRESULT VFWAPI ICSendMessage(HIC hic, UINT msg, DWORD_PTR lParam1, DWORD_PTR lParam2)
1172 {
1173     WINE_HIC*   whic = MSVIDEO_GetHicPtr(hic);
1174 
1175     if (!whic) return ICERR_BADHANDLE;
1176     return MSVIDEO_SendMessage(whic, msg, lParam1, lParam2);
1177 }
1178 
1179 /***********************************************************************
1180  *		ICDrawBegin		[MSVFW32.@]
1181  */
ICDrawBegin(HIC hic,DWORD dwFlags,HPALETTE hpal,HWND hwnd,HDC hdc,INT xDst,INT yDst,INT dxDst,INT dyDst,LPBITMAPINFOHEADER lpbi,INT xSrc,INT ySrc,INT dxSrc,INT dySrc,DWORD dwRate,DWORD dwScale)1182 DWORD VFWAPIV ICDrawBegin(
1183 	HIC                hic,     /* [in] */
1184 	DWORD              dwFlags, /* [in] flags */
1185 	HPALETTE           hpal,    /* [in] palette to draw with */
1186 	HWND               hwnd,    /* [in] window to draw to */
1187 	HDC                hdc,     /* [in] HDC to draw to */
1188 	INT                xDst,    /* [in] destination rectangle */
1189 	INT                yDst,    /* [in] */
1190 	INT                dxDst,   /* [in] */
1191 	INT                dyDst,   /* [in] */
1192 	LPBITMAPINFOHEADER lpbi,    /* [in] format of frame to draw */
1193 	INT                xSrc,    /* [in] source rectangle */
1194 	INT                ySrc,    /* [in] */
1195 	INT                dxSrc,   /* [in] */
1196 	INT                dySrc,   /* [in] */
1197 	DWORD              dwRate,  /* [in] frames/second = (dwRate/dwScale) */
1198 	DWORD              dwScale) /* [in] */
1199 {
1200 
1201 	ICDRAWBEGIN	icdb;
1202 
1203 	TRACE("(%p,%d,%p,%p,%p,%u,%u,%u,%u,%p,%u,%u,%u,%u,%d,%d)\n",
1204 		  hic, dwFlags, hpal, hwnd, hdc, xDst, yDst, dxDst, dyDst,
1205 		  lpbi, xSrc, ySrc, dxSrc, dySrc, dwRate, dwScale);
1206 
1207 	icdb.dwFlags = dwFlags;
1208 	icdb.hpal = hpal;
1209 	icdb.hwnd = hwnd;
1210 	icdb.hdc = hdc;
1211 	icdb.xDst = xDst;
1212 	icdb.yDst = yDst;
1213 	icdb.dxDst = dxDst;
1214 	icdb.dyDst = dyDst;
1215 	icdb.lpbi = lpbi;
1216 	icdb.xSrc = xSrc;
1217 	icdb.ySrc = ySrc;
1218 	icdb.dxSrc = dxSrc;
1219 	icdb.dySrc = dySrc;
1220 	icdb.dwRate = dwRate;
1221 	icdb.dwScale = dwScale;
1222 	return ICSendMessage(hic,ICM_DRAW_BEGIN,(DWORD_PTR)&icdb,sizeof(icdb));
1223 }
1224 
1225 /***********************************************************************
1226  *		ICDraw			[MSVFW32.@]
1227  */
ICDraw(HIC hic,DWORD dwFlags,LPVOID lpFormat,LPVOID lpData,DWORD cbData,LONG lTime)1228 DWORD VFWAPIV ICDraw(HIC hic, DWORD dwFlags, LPVOID lpFormat, LPVOID lpData, DWORD cbData, LONG lTime) {
1229 	ICDRAW	icd;
1230 
1231 	TRACE("(%p,%d,%p,%p,%d,%d)\n",hic,dwFlags,lpFormat,lpData,cbData,lTime);
1232 
1233 	icd.dwFlags = dwFlags;
1234 	icd.lpFormat = lpFormat;
1235 	icd.lpData = lpData;
1236 	icd.cbData = cbData;
1237 	icd.lTime = lTime;
1238 
1239 	return ICSendMessage(hic,ICM_DRAW,(DWORD_PTR)&icd,sizeof(icd));
1240 }
1241 
1242 /***********************************************************************
1243  *		ICClose			[MSVFW32.@]
1244  */
ICClose(HIC hic)1245 LRESULT WINAPI ICClose(HIC hic)
1246 {
1247     WINE_HIC* whic = MSVIDEO_GetHicPtr(hic);
1248     WINE_HIC** p;
1249 
1250     TRACE("(%p)\n",hic);
1251 
1252     if (!whic) return ICERR_BADHANDLE;
1253 
1254     if (whic->driverproc)
1255     {
1256         MSVIDEO_SendMessage(whic, DRV_CLOSE, 0, 0);
1257         MSVIDEO_SendMessage(whic, DRV_DISABLE, 0, 0);
1258         MSVIDEO_SendMessage(whic, DRV_FREE, 0, 0);
1259     }
1260     else
1261     {
1262         CloseDriver(whic->hdrv, 0, 0);
1263     }
1264 
1265     /* remove whic from list */
1266     for (p = &MSVIDEO_FirstHic; *p != NULL; p = &((*p)->next))
1267     {
1268         if ((*p) == whic)
1269         {
1270             *p = whic->next;
1271             break;
1272         }
1273     }
1274 
1275     heap_free(whic);
1276     return 0;
1277 }
1278 
1279 
1280 
1281 /***********************************************************************
1282  *		ICImageCompress	[MSVFW32.@]
1283  */
ICImageCompress(HIC hic,UINT uiFlags,LPBITMAPINFO lpbiIn,LPVOID lpBits,LPBITMAPINFO lpbiOut,LONG lQuality,LONG * plSize)1284 HANDLE VFWAPI ICImageCompress(
1285 	HIC hic, UINT uiFlags,
1286 	LPBITMAPINFO lpbiIn, LPVOID lpBits,
1287 	LPBITMAPINFO lpbiOut, LONG lQuality,
1288 	LONG* plSize)
1289 {
1290 	FIXME("(%p,%08x,%p,%p,%p,%d,%p)\n",
1291 		hic, uiFlags, lpbiIn, lpBits, lpbiOut, lQuality, plSize);
1292 
1293 	return NULL;
1294 }
1295 
1296 /***********************************************************************
1297  *		ICImageDecompress	[MSVFW32.@]
1298  */
1299 
ICImageDecompress(HIC hic,UINT uiFlags,LPBITMAPINFO lpbiIn,LPVOID lpBits,LPBITMAPINFO lpbiOut)1300 HANDLE VFWAPI ICImageDecompress(
1301 	HIC hic, UINT uiFlags, LPBITMAPINFO lpbiIn,
1302 	LPVOID lpBits, LPBITMAPINFO lpbiOut)
1303 {
1304 	HGLOBAL	hMem = NULL;
1305 	BYTE*	pMem = NULL;
1306 	BOOL	bReleaseIC = FALSE;
1307 	BYTE*	pHdr = NULL;
1308 	ULONG	cbHdr = 0;
1309 	BOOL	bSucceeded = FALSE;
1310 	BOOL	bInDecompress = FALSE;
1311 	DWORD	biSizeImage;
1312 
1313 	TRACE("(%p,%08x,%p,%p,%p)\n",
1314 		hic, uiFlags, lpbiIn, lpBits, lpbiOut);
1315 
1316 	if ( hic == NULL )
1317 	{
1318 		hic = ICDecompressOpen( ICTYPE_VIDEO, 0, &lpbiIn->bmiHeader, (lpbiOut != NULL) ? &lpbiOut->bmiHeader : NULL );
1319 		if ( hic == NULL )
1320 		{
1321 			WARN("no handler\n" );
1322 			goto err;
1323 		}
1324 		bReleaseIC = TRUE;
1325 	}
1326 	if ( uiFlags != 0 )
1327 	{
1328 		FIXME( "unknown flag %08x\n", uiFlags );
1329 		goto err;
1330 	}
1331 	if ( lpbiIn == NULL || lpBits == NULL )
1332 	{
1333 		WARN("invalid argument\n");
1334 		goto err;
1335 	}
1336 
1337 	if ( lpbiOut != NULL )
1338 	{
1339 		if ( lpbiOut->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) )
1340 			goto err;
1341 		cbHdr = sizeof(BITMAPINFOHEADER);
1342 		if ( lpbiOut->bmiHeader.biCompression == 3 )
1343 			cbHdr += sizeof(DWORD)*3;
1344 		else
1345 		if ( lpbiOut->bmiHeader.biBitCount <= 8 )
1346 		{
1347 			if ( lpbiOut->bmiHeader.biClrUsed == 0 )
1348 				cbHdr += sizeof(RGBQUAD) * (1<<lpbiOut->bmiHeader.biBitCount);
1349 			else
1350 				cbHdr += sizeof(RGBQUAD) * lpbiOut->bmiHeader.biClrUsed;
1351 		}
1352 	}
1353 	else
1354 	{
1355 		TRACE( "get format\n" );
1356 
1357 		cbHdr = ICDecompressGetFormatSize(hic,lpbiIn);
1358 		if ( cbHdr < sizeof(BITMAPINFOHEADER) )
1359 			goto err;
1360 		if (!(pHdr = heap_alloc_zero(cbHdr + sizeof(RGBQUAD) * 256)))
1361 			goto err;
1362 		if ( ICDecompressGetFormat( hic, lpbiIn, pHdr ) != ICERR_OK )
1363 			goto err;
1364 		lpbiOut = (BITMAPINFO*)pHdr;
1365 		if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
1366 			 ICDecompressGetPalette( hic, lpbiIn, lpbiOut ) != ICERR_OK &&
1367 			 lpbiIn->bmiHeader.biBitCount == lpbiOut->bmiHeader.biBitCount )
1368 		{
1369 			if ( lpbiIn->bmiHeader.biClrUsed == 0 )
1370 				memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*(1<<lpbiOut->bmiHeader.biBitCount) );
1371 			else
1372 				memcpy( lpbiOut->bmiColors, lpbiIn->bmiColors, sizeof(RGBQUAD)*lpbiIn->bmiHeader.biClrUsed );
1373 		}
1374 		if ( lpbiOut->bmiHeader.biBitCount <= 8 &&
1375 			 lpbiOut->bmiHeader.biClrUsed == 0 )
1376 			lpbiOut->bmiHeader.biClrUsed = 1<<lpbiOut->bmiHeader.biBitCount;
1377 
1378 		lpbiOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1379 		cbHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*lpbiOut->bmiHeader.biClrUsed;
1380 	}
1381 
1382 	biSizeImage = lpbiOut->bmiHeader.biSizeImage;
1383 	if ( biSizeImage == 0 )
1384 		biSizeImage = get_size_image(lpbiOut->bmiHeader.biWidth, lpbiOut->bmiHeader.biHeight, lpbiOut->bmiHeader.biBitCount);
1385 
1386 	TRACE( "call ICDecompressBegin\n" );
1387 
1388 	if ( ICDecompressBegin( hic, lpbiIn, lpbiOut ) != ICERR_OK )
1389 		goto err;
1390 	bInDecompress = TRUE;
1391 
1392 	TRACE( "cbHdr %d, biSizeImage %d\n", cbHdr, biSizeImage );
1393 
1394 	hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_ZEROINIT, cbHdr + biSizeImage );
1395 	if ( hMem == NULL )
1396 	{
1397 		WARN( "out of memory\n" );
1398 		goto err;
1399 	}
1400 	pMem = GlobalLock( hMem );
1401 	if ( pMem == NULL )
1402 		goto err;
1403 	memcpy( pMem, lpbiOut, cbHdr );
1404 
1405 	TRACE( "call ICDecompress\n" );
1406 	if ( ICDecompress( hic, 0, &lpbiIn->bmiHeader, lpBits, &lpbiOut->bmiHeader, pMem+cbHdr ) != ICERR_OK )
1407 		goto err;
1408 
1409 	bSucceeded = TRUE;
1410 err:
1411 	if ( bInDecompress )
1412 		ICDecompressEnd( hic );
1413 	if ( bReleaseIC )
1414 		ICClose(hic);
1415         heap_free(pHdr);
1416 	if ( pMem != NULL )
1417 		GlobalUnlock( hMem );
1418 	if ( !bSucceeded && hMem != NULL )
1419 	{
1420 		GlobalFree(hMem); hMem = NULL;
1421 	}
1422 
1423 	return hMem;
1424 }
1425 
1426 /***********************************************************************
1427  *      ICSeqCompressFrame   [MSVFW32.@]
1428  */
ICSeqCompressFrame(PCOMPVARS pc,UINT uiFlags,LPVOID lpBits,BOOL * pfKey,LONG * plSize)1429 LPVOID VFWAPI ICSeqCompressFrame(PCOMPVARS pc, UINT uiFlags, LPVOID lpBits, BOOL *pfKey, LONG *plSize)
1430 {
1431     ICCOMPRESS* icComp = pc->lpState;
1432     DWORD ret;
1433     TRACE("(%p, 0x%08x, %p, %p, %p)\n", pc, uiFlags, lpBits, pfKey, plSize);
1434 
1435     if (pc->cbState != sizeof(ICCOMPRESS))
1436     {
1437        ERR("Invalid cbState %i\n", pc->cbState);
1438        return NULL;
1439     }
1440 
1441     if (!pc->lKeyCount++)
1442        icComp->dwFlags = ICCOMPRESS_KEYFRAME;
1443     else
1444     {
1445         if (pc->lKey && pc->lKeyCount == (pc->lKey - 1))
1446         /* No key frames if pc->lKey == 0 */
1447            pc->lKeyCount = 0;
1448         icComp->dwFlags = 0;
1449     }
1450 
1451     icComp->lpInput = lpBits;
1452     icComp->lFrameNum = pc->lFrame++;
1453     icComp->lpOutput = pc->lpBitsOut;
1454     icComp->lpPrev = pc->lpBitsPrev;
1455     ret = ICSendMessage(pc->hic, ICM_COMPRESS, (DWORD_PTR)icComp, sizeof(*icComp));
1456 
1457     if (ret == ICERR_OK)
1458     {
1459         LPVOID oldprev, oldout;
1460 
1461         if (icComp->dwFlags & AVIIF_KEYFRAME)
1462         {
1463             pc->lKeyCount = 1;
1464             *pfKey = TRUE;
1465             TRACE("Key frame\n");
1466         }
1467         else
1468             *pfKey = FALSE;
1469 
1470         *plSize = icComp->lpbiOutput->biSizeImage;
1471 
1472         /* We shift Prev and Out, so we don't have to allocate and release memory */
1473         oldprev = pc->lpBitsPrev;
1474         oldout = pc->lpBitsOut;
1475         pc->lpBitsPrev = oldout;
1476         pc->lpBitsOut = oldprev;
1477 
1478         TRACE("returning: %p, compressed frame size %u\n", icComp->lpOutput, *plSize);
1479         return icComp->lpOutput;
1480     }
1481     return NULL;
1482 }
1483 
clear_compvars(PCOMPVARS pc)1484 static void clear_compvars(PCOMPVARS pc)
1485 {
1486     heap_free(pc->lpbiIn);
1487     heap_free(pc->lpBitsPrev);
1488     heap_free(pc->lpBitsOut);
1489     heap_free(pc->lpState);
1490     pc->lpbiIn = pc->lpBitsPrev = pc->lpBitsOut = pc->lpState = NULL;
1491     if (pc->dwFlags & 0x80000000)
1492     {
1493         heap_free(pc->lpbiOut);
1494         pc->lpbiOut = NULL;
1495         pc->dwFlags &= ~0x80000000;
1496     }
1497 }
1498 
1499 /***********************************************************************
1500  *      ICSeqCompressFrameEnd   [MSVFW32.@]
1501  */
ICSeqCompressFrameEnd(PCOMPVARS pc)1502 void VFWAPI ICSeqCompressFrameEnd(PCOMPVARS pc)
1503 {
1504     TRACE("(%p)\n", pc);
1505     ICSendMessage(pc->hic, ICM_COMPRESS_END, 0, 0);
1506     clear_compvars(pc);
1507 }
1508 
copy_bitmapinfo(const BITMAPINFO * src)1509 static BITMAPINFO *copy_bitmapinfo(const BITMAPINFO *src)
1510 {
1511     int num_colors;
1512     unsigned int size;
1513     BITMAPINFO *dst;
1514 
1515     if (src->bmiHeader.biClrUsed)
1516         num_colors = min(src->bmiHeader.biClrUsed, 256);
1517     else
1518         num_colors = src->bmiHeader.biBitCount > 8 ? 0 : 1 << src->bmiHeader.biBitCount;
1519 
1520     size = FIELD_OFFSET(BITMAPINFO, bmiColors[num_colors]);
1521     if (src->bmiHeader.biCompression == BI_BITFIELDS)
1522         size += 3 * sizeof(DWORD);
1523 
1524     if (!(dst = heap_alloc(size)))
1525         return NULL;
1526 
1527     memcpy(dst, src, size);
1528     return dst;
1529 }
1530 
1531 /***********************************************************************
1532  *      ICSeqCompressFrameStart [MSVFW32.@]
1533  */
ICSeqCompressFrameStart(PCOMPVARS pc,LPBITMAPINFO lpbiIn)1534 BOOL VFWAPI ICSeqCompressFrameStart(PCOMPVARS pc, LPBITMAPINFO lpbiIn)
1535 {
1536     /* I'm ignoring bmiColors as I don't know what to do with it,
1537      * it doesn't appear to be used though
1538      */
1539     DWORD ret;
1540     ICCOMPRESS* icComp;
1541 
1542     if (!(pc->lpbiIn = copy_bitmapinfo(lpbiIn)))
1543         return FALSE;
1544 
1545     if (!(pc->lpState = heap_alloc(sizeof(ICCOMPRESS) + sizeof(*icComp->lpckid) + sizeof(*icComp->lpdwFlags))))
1546         goto error;
1547 
1548     pc->cbState = sizeof(ICCOMPRESS);
1549 
1550     if (!pc->lpbiOut)
1551     {
1552         /* Ask compressor for needed header size */
1553         int size = ICSendMessage(pc->hic, ICM_COMPRESS_GET_FORMAT,
1554                                  (DWORD_PTR)pc->lpbiIn, 0);
1555         if (size <= 0)
1556             goto error;
1557 
1558         if (!(pc->lpbiOut = heap_alloc_zero(size)))
1559             goto error;
1560         /* Flag to show that we allocated lpbiOut for proper cleanup */
1561         pc->dwFlags |= 0x80000000;
1562 
1563         ret = ICSendMessage(pc->hic, ICM_COMPRESS_GET_FORMAT,
1564                             (DWORD_PTR)pc->lpbiIn, (DWORD_PTR)pc->lpbiOut);
1565         if (ret != ICERR_OK)
1566         {
1567             ERR("Could not get output format from compressor\n");
1568             goto error;
1569         }
1570         if (!pc->lpbiOut->bmiHeader.biSizeImage)
1571         {
1572             /* If we can't know the output frame size for sure at least allocate
1573              * the same size of the input frame and also at least 8Kb to be sure
1574              * that poor compressors will have enough memory to work if the input
1575              * frame is too small.
1576              */
1577             pc->lpbiOut->bmiHeader.biSizeImage = max(8192, pc->lpbiIn->bmiHeader.biSizeImage);
1578             ERR("Bad codec! Invalid output frame size, guessing from input\n");
1579         }
1580     }
1581 
1582     TRACE("Input: %ux%u, fcc %s, bpp %u, size %u\n",
1583           pc->lpbiIn->bmiHeader.biWidth, pc->lpbiIn->bmiHeader.biHeight,
1584           wine_dbgstr_fcc(pc->lpbiIn->bmiHeader.biCompression),
1585           pc->lpbiIn->bmiHeader.biBitCount,
1586           pc->lpbiIn->bmiHeader.biSizeImage);
1587     TRACE("Output: %ux%u, fcc %s, bpp %u, size %u\n",
1588           pc->lpbiOut->bmiHeader.biWidth, pc->lpbiOut->bmiHeader.biHeight,
1589           wine_dbgstr_fcc(pc->lpbiOut->bmiHeader.biCompression),
1590           pc->lpbiOut->bmiHeader.biBitCount,
1591           pc->lpbiOut->bmiHeader.biSizeImage);
1592 
1593     /* Buffer for compressed frame data */
1594     if (!(pc->lpBitsOut = heap_alloc(pc->lpbiOut->bmiHeader.biSizeImage)))
1595         goto error;
1596 
1597     /* Buffer for previous compressed frame data */
1598     if (!(pc->lpBitsPrev = heap_alloc(pc->lpbiOut->bmiHeader.biSizeImage)))
1599         goto error;
1600 
1601     TRACE("Compvars:\n"
1602           "\tsize: %i\n"
1603           "\tflags: 0x%x\n"
1604           "\thic: %p\n"
1605           "\ttype: %s\n"
1606           "\thandler: %s\n"
1607           "\tin/out: %p/%p\n"
1608           "\tkey/data/quality: %i/%i/%i\n",
1609     pc->cbSize, pc->dwFlags, pc->hic, wine_dbgstr_fcc(pc->fccType),
1610     wine_dbgstr_fcc(pc->fccHandler), pc->lpbiIn, pc->lpbiOut, pc->lKey,
1611     pc->lDataRate, pc->lQ);
1612 
1613     ret = ICSendMessage(pc->hic, ICM_COMPRESS_BEGIN, (DWORD_PTR)pc->lpbiIn, (DWORD_PTR)pc->lpbiOut);
1614     if (ret == ICERR_OK)
1615     {
1616         icComp = pc->lpState;
1617         /* Initialise some variables */
1618         pc->lFrame = 0; pc->lKeyCount = 0;
1619 
1620         icComp->lpbiOutput = &pc->lpbiOut->bmiHeader;
1621         icComp->lpbiInput = &pc->lpbiIn->bmiHeader;
1622         icComp->lpckid = (DWORD *)(icComp + 1);
1623         *icComp->lpckid = 0;
1624         icComp->lpdwFlags = (DWORD *)((char *)(icComp + 1) + sizeof(*icComp->lpckid));
1625         *icComp->lpdwFlags = 0;
1626         icComp->dwFrameSize = 0;
1627         icComp->dwQuality = pc->lQ;
1628         icComp->lpbiPrev = &pc->lpbiIn->bmiHeader;
1629         return TRUE;
1630     }
1631 error:
1632     clear_compvars(pc);
1633     return FALSE;
1634 }
1635 
1636 /***********************************************************************
1637  *      GetFileNamePreview   [MSVFW32.@]
1638  */
GetFileNamePreview(LPVOID lpofn,BOOL bSave,BOOL bUnicode)1639 static BOOL GetFileNamePreview(LPVOID lpofn,BOOL bSave,BOOL bUnicode)
1640 {
1641   CHAR    szFunctionName[20];
1642   BOOL    (*fnGetFileName)(LPVOID);
1643   HMODULE hComdlg32;
1644   BOOL    ret;
1645 
1646   FIXME("(%p,%d,%d), semi-stub!\n",lpofn,bSave,bUnicode);
1647 
1648   lstrcpyA(szFunctionName, (bSave ? "GetSaveFileName" : "GetOpenFileName"));
1649   lstrcatA(szFunctionName, (bUnicode ? "W" : "A"));
1650 
1651   hComdlg32 = LoadLibraryA("COMDLG32.DLL");
1652   if (hComdlg32 == NULL)
1653     return FALSE;
1654 
1655   fnGetFileName = (LPVOID)GetProcAddress(hComdlg32, szFunctionName);
1656   if (fnGetFileName == NULL)
1657   {
1658     FreeLibrary(hComdlg32);
1659     return FALSE;
1660   }
1661 
1662   /* FIXME: need to add OFN_ENABLEHOOK and our own handler */
1663   ret = fnGetFileName(lpofn);
1664 
1665   FreeLibrary(hComdlg32);
1666   return ret;
1667 }
1668 
1669 /***********************************************************************
1670  *		GetOpenFileNamePreviewA	[MSVFW32.@]
1671  */
GetOpenFileNamePreviewA(LPOPENFILENAMEA lpofn)1672 BOOL WINAPI GetOpenFileNamePreviewA(LPOPENFILENAMEA lpofn)
1673 {
1674   FIXME("(%p), semi-stub!\n", lpofn);
1675 
1676   return GetFileNamePreview(lpofn, FALSE, FALSE);
1677 }
1678 
1679 /***********************************************************************
1680  *		GetOpenFileNamePreviewW	[MSVFW32.@]
1681  */
GetOpenFileNamePreviewW(LPOPENFILENAMEW lpofn)1682 BOOL WINAPI GetOpenFileNamePreviewW(LPOPENFILENAMEW lpofn)
1683 {
1684   FIXME("(%p), semi-stub!\n", lpofn);
1685 
1686   return GetFileNamePreview(lpofn, FALSE, TRUE);
1687 }
1688 
1689 /***********************************************************************
1690  *		GetSaveFileNamePreviewA	[MSVFW32.@]
1691  */
GetSaveFileNamePreviewA(LPOPENFILENAMEA lpofn)1692 BOOL WINAPI GetSaveFileNamePreviewA(LPOPENFILENAMEA lpofn)
1693 {
1694   FIXME("(%p), semi-stub!\n", lpofn);
1695 
1696   return GetFileNamePreview(lpofn, TRUE, FALSE);
1697 }
1698 
1699 /***********************************************************************
1700  *		GetSaveFileNamePreviewW	[MSVFW32.@]
1701  */
GetSaveFileNamePreviewW(LPOPENFILENAMEW lpofn)1702 BOOL WINAPI GetSaveFileNamePreviewW(LPOPENFILENAMEW lpofn)
1703 {
1704   FIXME("(%p), semi-stub!\n", lpofn);
1705 
1706   return GetFileNamePreview(lpofn, TRUE, TRUE);
1707 }
1708