OleCreateFontIndirect(NULL,...) uses the OLE StdFont.
[wine] / dlls / avifil32 / api.c
1 /*
2  * Copyright 1999 Marcus Meissner
3  * Copyright 2002 Michael Günnewig
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
20 #define COM_NO_WINDOWS_H
21 #include <assert.h>
22
23 #include "winbase.h"
24 #include "winnls.h"
25 #include "winuser.h"
26 #include "winreg.h"
27 #include "winerror.h"
28 #include "windowsx.h"
29
30 #include "ole2.h"
31 #include "shellapi.h"
32 #include "vfw.h"
33 #include "msacm.h"
34
35 #include "avifile_private.h"
36
37 #include "wine/debug.h"
38 #include "wine/unicode.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(avifile);
41
42 /***********************************************************************
43  * copied from dlls/shell32/undocshell.h
44  */
45 HRESULT WINAPI SHCoCreateInstance(LPCSTR lpszClsid,REFCLSID rClsid,
46                                   LPUNKNOWN pUnkOuter,REFIID riid,LPVOID *ppv);
47
48 /***********************************************************************
49  * for AVIBuildFilterW -- uses fixed size table
50  */
51 #define MAX_FILTERS 30 /* 30 => 7kB */
52
53 typedef struct _AVIFilter {
54   WCHAR szClsid[40];
55   WCHAR szExtensions[MAX_FILTERS * 7];
56 } AVIFilter;
57
58 /***********************************************************************
59  * for AVISaveOptions
60  */
61 static struct {
62   UINT                  uFlags;
63   INT                   nStreams;
64   PAVISTREAM           *ppavis;
65   LPAVICOMPRESSOPTIONS *ppOptions;
66   INT                   nCurrent;
67 } SaveOpts;
68
69 /***********************************************************************
70  * copied from dlls/ole32/compobj.c
71  */
72 static HRESULT AVIFILE_CLSIDFromString(LPCSTR idstr, LPCLSID id)
73 {
74   BYTE const *s = (BYTE const*)idstr;
75   BYTE *p;
76   INT   i;
77   BYTE table[256];
78
79   if (!s) {
80     memset(id, 0, sizeof(CLSID));
81     return S_OK;
82   } else {  /* validate the CLSID string */
83     if (lstrlenA(s) != 38)
84       return CO_E_CLASSSTRING;
85
86     if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') ||
87         (s[24]!='-') || (s[37]!='}'))
88       return CO_E_CLASSSTRING;
89
90     for (i = 1; i < 37; i++) {
91       if ((i == 9) || (i == 14) || (i == 19) || (i == 24))
92         continue;
93       if (!(((s[i] >= '0') && (s[i] <= '9'))  ||
94             ((s[i] >= 'a') && (s[i] <= 'f'))  ||
95             ((s[i] >= 'A') && (s[i] <= 'F')))
96           )
97         return CO_E_CLASSSTRING;
98     }
99   }
100
101   TRACE("%s -> %p\n", s, id);
102
103   /* quick lookup table */
104   memset(table, 0, 256);
105
106   for (i = 0; i < 10; i++)
107     table['0' + i] = i;
108
109   for (i = 0; i < 6; i++) {
110     table['A' + i] = i+10;
111     table['a' + i] = i+10;
112   }
113
114   /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
115   p = (BYTE *) id;
116
117   s++;  /* skip leading brace  */
118   for (i = 0; i < 4; i++) {
119     p[3 - i] = table[*s]<<4 | table[*(s+1)];
120     s += 2;
121   }
122   p += 4;
123   s++;  /* skip - */
124
125   for (i = 0; i < 2; i++) {
126     p[1-i] = table[*s]<<4 | table[*(s+1)];
127     s += 2;
128   }
129   p += 2;
130   s++;  /* skip - */
131
132   for (i = 0; i < 2; i++) {
133     p[1-i] = table[*s]<<4 | table[*(s+1)];
134     s += 2;
135   }
136   p += 2;
137   s++;  /* skip - */
138
139   /* these are just sequential bytes */
140   for (i = 0; i < 2; i++) {
141     *p++ = table[*s]<<4 | table[*(s+1)];
142     s += 2;
143   }
144   s++;  /* skip - */
145
146   for (i = 0; i < 6; i++) {
147     *p++ = table[*s]<<4 | table[*(s+1)];
148     s += 2;
149   }
150
151   return S_OK;
152 }
153
154 static BOOL AVIFILE_GetFileHandlerByExtension(LPCWSTR szFile, LPCLSID lpclsid)
155 {
156   CHAR   szRegKey[25];
157   CHAR   szValue[100];
158   LPWSTR szExt = strrchrW(szFile, '.');
159   LONG   len = sizeof(szValue) / sizeof(szValue[0]);
160
161   if (szExt == NULL)
162     return FALSE;
163
164   szExt++;
165
166   wsprintfA(szRegKey, "AVIFile\\Extensions\\%.3ls", szExt);
167   if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &len) != ERROR_SUCCESS)
168     return FALSE;
169
170   return (AVIFILE_CLSIDFromString(szValue, lpclsid) == S_OK);
171 }
172
173 /***********************************************************************
174  *              AVIFileInit             (AVIFIL32.@)
175  *              AVIFileInit             (AVIFILE.100)
176  */
177 void WINAPI AVIFileInit(void) {
178   /* need to load ole32.dll if not already done and get some functions */
179   FIXME("(): stub!\n");
180 }
181
182 /***********************************************************************
183  *              AVIFileExit             (AVIFIL32.@)
184  *              AVIFileExit             (AVIFILE.101)
185  */
186 void WINAPI AVIFileExit(void) {
187   /* need to free ole32.dll if we are the last exit call */
188   FIXME("(): stub!\n");
189 }
190
191 /***********************************************************************
192  *              AVIFileOpenA            (AVIFIL32.@)
193  *              AVIFileOpen             (AVIFILE.102)
194  */
195 HRESULT WINAPI AVIFileOpenA(PAVIFILE *ppfile, LPCSTR szFile, UINT uMode,
196                             LPCLSID lpHandler)
197 {
198   LPWSTR  wszFile = NULL;
199   HRESULT hr;
200   int     len;
201
202   TRACE("(%p,%s,0x%08X,%s)\n", ppfile, debugstr_a(szFile), uMode,
203         debugstr_guid(lpHandler));
204
205   /* check parameters */
206   if (ppfile == NULL || szFile == NULL)
207     return AVIERR_BADPARAM;
208
209   /* convert ASCII string to Unicode and call unicode function */
210   len = lstrlenA(szFile);
211   if (len <= 0)
212     return AVIERR_BADPARAM;
213
214   wszFile = (LPWSTR)LocalAlloc(LPTR, (len + 1) * sizeof(WCHAR));
215   if (wszFile == NULL)
216     return AVIERR_MEMORY;
217
218   MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len + 1);
219   wszFile[len + 1] = 0;
220
221   hr = AVIFileOpenW(ppfile, wszFile, uMode, lpHandler);
222
223   LocalFree((HLOCAL)wszFile);
224
225   return hr;
226 }
227
228 /***********************************************************************
229  *              AVIFileOpenW            (AVIFIL32.@)
230  */
231 HRESULT WINAPI AVIFileOpenW(PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode,
232                             LPCLSID lpHandler)
233 {
234   IPersistFile *ppersist = NULL;
235   CLSID         clsidHandler;
236   HRESULT       hr;
237
238   TRACE("(%p,%s,0x%X,%s)\n", ppfile, debugstr_w(szFile), uMode,
239         debugstr_guid(lpHandler));
240
241   /* check parameters */
242   if (ppfile == NULL || szFile == NULL)
243     return AVIERR_BADPARAM;
244
245   *ppfile = NULL;
246
247   /* if no handler then try guessing it by extension */
248   if (lpHandler == NULL) {
249     if (! AVIFILE_GetFileHandlerByExtension(szFile, &clsidHandler))
250       return AVIERR_UNSUPPORTED;
251   } else
252     memcpy(&clsidHandler, lpHandler, sizeof(clsidHandler));
253
254   /* crete instance of handler */
255   hr = SHCoCreateInstance(NULL, &clsidHandler, NULL,
256                           &IID_IAVIFile, (LPVOID*)ppfile);
257   if (FAILED(hr) || *ppfile == NULL)
258     return hr;
259
260   /* ask for IPersistFile interface for loading/creating the file */
261   hr = IAVIFile_QueryInterface(*ppfile, &IID_IPersistFile, (LPVOID*)&ppersist);
262   if (FAILED(hr) || ppersist == NULL) {
263     IAVIFile_Release(*ppfile);
264     *ppfile = NULL;
265     return hr;
266   }
267
268   hr = IPersistFile_Load(ppersist, szFile, uMode);
269   IPersistFile_Release(ppersist);
270   if (FAILED(hr)) {
271     IAVIFile_Release(*ppfile);
272     *ppfile = NULL;
273   }
274
275   return hr;
276 }
277
278 /***********************************************************************
279  *              AVIFileAddRef           (AVIFIL32.@)
280  *              AVIFileAddRef           (AVIFILE.140)
281  */
282 ULONG WINAPI AVIFileAddRef(PAVIFILE pfile)
283 {
284   TRACE("(%p)\n", pfile);
285
286   if (pfile == NULL) {
287     ERR(": bad handle passed!\n");
288     return 0;
289   }
290
291   return IAVIFile_AddRef(pfile);
292 }
293
294 /***********************************************************************
295  *              AVIFileRelease          (AVIFIL32.@)
296  *              AVIFileRelease          (AVIFILE.141)
297  */
298 ULONG WINAPI AVIFileRelease(PAVIFILE pfile)
299 {
300   TRACE("(%p)\n", pfile);
301
302   if (pfile == NULL) {
303     ERR(": bad handle passed!\n");
304     return 0;
305   }
306
307   return IAVIFile_Release(pfile);
308 }
309
310 /***********************************************************************
311  *              AVIFileInfo             (AVIFIL32.@)
312  *              AVIFileInfoA            (AVIFIL32.@)
313  *              AVIFileInfo             (AVIFILE.142)
314  */
315 HRESULT WINAPI AVIFileInfoA(PAVIFILE pfile, LPAVIFILEINFOA afi, LONG size)
316 {
317   AVIFILEINFOW afiw;
318   HRESULT      hres;
319
320   TRACE("(%p,%p,%ld)\n", pfile, afi, size);
321
322   if (pfile == NULL)
323     return AVIERR_BADHANDLE;
324   if ((DWORD)size < sizeof(AVIFILEINFOA))
325     return AVIERR_BADSIZE;
326
327   hres = IAVIFile_Info(pfile, &afiw, sizeof(afiw));
328
329   memcpy(afi, &afiw, sizeof(*afi) - sizeof(afi->szFileType));
330   WideCharToMultiByte(CP_ACP, 0, afiw.szFileType, -1, afi->szFileType,
331                       sizeof(afi->szFileType), NULL, NULL);
332   afi->szFileType[sizeof(afi->szFileType) - 1] = 0;
333
334   return hres;
335 }
336
337 /***********************************************************************
338  *              AVIFileInfoW            (AVIFIL32.@)
339  */
340 HRESULT WINAPI AVIFileInfoW(PAVIFILE pfile, LPAVIFILEINFOW afiw, LONG size)
341 {
342   TRACE("(%p,%p,%ld)\n", pfile, afiw, size);
343
344   if (pfile == NULL)
345     return AVIERR_BADHANDLE;
346
347   return IAVIFile_Info(pfile, afiw, size);
348 }
349
350 /***********************************************************************
351  *              AVIFileGetStream        (AVIFIL32.@)
352  *              AVIFileGetStream        (AVIFILE.143)
353  */
354 HRESULT WINAPI AVIFileGetStream(PAVIFILE pfile, PAVISTREAM *avis,
355                                 DWORD fccType, LONG lParam)
356 {
357   TRACE("(%p,%p,'%4.4s',%ld)\n", pfile, avis, (char*)&fccType, lParam);
358
359   if (pfile == NULL)
360     return AVIERR_BADHANDLE;
361
362   return IAVIFile_GetStream(pfile, avis, fccType, lParam);
363 }
364
365 /***********************************************************************
366  *              AVIFileCreateStreamA    (AVIFIL32.@)
367  *              AVIFileCreateStream     (AVIFILE.144)
368  */
369 HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE pfile, PAVISTREAM *ppavi,
370                                     LPAVISTREAMINFOA psi)
371 {
372   AVISTREAMINFOW        psiw;
373
374   TRACE("(%p,%p,%p)\n", pfile, ppavi, psi);
375
376   if (pfile == NULL)
377     return AVIERR_BADHANDLE;
378
379   /* Only the szName at the end is different */
380   memcpy(&psiw, psi, sizeof(*psi) - sizeof(psi->szName));
381   MultiByteToWideChar(CP_ACP, 0, psi->szName, -1, psiw.szName,
382                       sizeof(psiw.szName) / sizeof(psiw.szName[0]));
383
384   return IAVIFile_CreateStream(pfile, ppavi, &psiw);
385 }
386
387 /***********************************************************************
388  *              AVIFileCreateStreamW    (AVIFIL32.@)
389  */
390 HRESULT WINAPI AVIFileCreateStreamW(PAVIFILE pfile, PAVISTREAM *avis,
391                                     LPAVISTREAMINFOW asi)
392 {
393   TRACE("(%p,%p,%p)\n", pfile, avis, asi);
394
395   return IAVIFile_CreateStream(pfile, avis, asi);
396 }
397
398 /***********************************************************************
399  *              AVIFileWriteData        (AVIFIL32.@)
400  *              AVIFileWriteData        (AVIFILE.146)
401  */
402 HRESULT WINAPI AVIFileWriteData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LONG size)
403 {
404   TRACE("(%p,'%4.4s',%p,%ld)\n", pfile, (char*)&fcc, lp, size);
405
406   if (pfile == NULL)
407     return AVIERR_BADHANDLE;
408
409   return IAVIFile_WriteData(pfile, fcc, lp, size);
410 }
411
412 /***********************************************************************
413  *              AVIFileReadData         (AVIFIL32.@)
414  *              AVIFileReadData         (AVIFILE.147)
415  */
416 HRESULT WINAPI AVIFileReadData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LPLONG size)
417 {
418   TRACE("(%p,'%4.4s',%p,%p)\n", pfile, (char*)&fcc, lp, size);
419
420   if (pfile == NULL)
421     return AVIERR_BADHANDLE;
422
423   return IAVIFile_ReadData(pfile, fcc, lp, size);
424 }
425
426 /***********************************************************************
427  *              AVIFileEndRecord        (AVIFIL32.@)
428  *              AVIFileEndRecord        (AVIFILE.148)
429  */
430 HRESULT WINAPI AVIFileEndRecord(PAVIFILE pfile)
431 {
432   TRACE("(%p)\n", pfile);
433
434   if (pfile == NULL)
435     return AVIERR_BADHANDLE;
436
437   return IAVIFile_EndRecord(pfile);
438 }
439
440 /***********************************************************************
441  *              AVIStreamAddRef         (AVIFIL32.@)
442  *              AVIStreamAddRef         (AVIFILE.160)
443  */
444 ULONG WINAPI AVIStreamAddRef(PAVISTREAM pstream)
445 {
446   TRACE("(%p)\n", pstream);
447
448   if (pstream == NULL) {
449     ERR(": bad handle passed!\n");
450     return 0;
451   }
452
453   return IAVIStream_AddRef(pstream);
454 }
455
456 /***********************************************************************
457  *              AVIStreamRelease        (AVIFIL32.@)
458  *              AVIStreamRelease        (AVIFILE.161)
459  */
460 ULONG WINAPI AVIStreamRelease(PAVISTREAM pstream)
461 {
462   TRACE("(%p)\n", pstream);
463
464   if (pstream == NULL) {
465     ERR(": bad handle passed!\n");
466     return 0;
467   }
468
469   return IAVIStream_Release(pstream);
470 }
471
472 /***********************************************************************
473  *              AVIStreamCreate         (AVIFIL32.@)
474  *              AVIStreamCreate         (AVIFILE.104)
475  */
476 HRESULT WINAPI AVIStreamCreate(PAVISTREAM *ppavi, LONG lParam1, LONG lParam2,
477                                LPCLSID pclsidHandler)
478 {
479   HRESULT hr;
480
481   TRACE("(%p,0x%08lX,0x%08lX,%s)\n", ppavi, lParam1, lParam2,
482         debugstr_guid(pclsidHandler));
483
484   if (ppavi == NULL)
485     return AVIERR_BADPARAM;
486
487   *ppavi = NULL;
488   if (pclsidHandler == NULL)
489     return AVIERR_UNSUPPORTED;
490
491   hr = SHCoCreateInstance(NULL, pclsidHandler, NULL,
492                           &IID_IAVIStream, (LPVOID*)ppavi);
493   if (FAILED(hr) || *ppavi == NULL)
494     return hr;
495
496   hr = IAVIStream_Create(*ppavi, lParam1, lParam2);
497   if (FAILED(hr)) {
498     IAVIStream_Release(*ppavi);
499     *ppavi = NULL;
500   }
501
502   return hr;
503 }
504
505 /***********************************************************************
506  *              AVIStreamInfoA          (AVIFIL32.@)
507  *              AVIStreamInfo           (AVIFILE.162)
508  */
509 HRESULT WINAPI AVIStreamInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
510                               LONG size)
511 {
512   AVISTREAMINFOW asiw;
513   HRESULT        hres;
514
515   TRACE("(%p,%p,%ld)\n", pstream, asi, size);
516
517   if (pstream == NULL)
518     return AVIERR_BADHANDLE;
519   if ((DWORD)size < sizeof(AVISTREAMINFOA))
520     return AVIERR_BADSIZE;
521
522   hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
523
524   memcpy(asi, &asiw, sizeof(asiw) - sizeof(asiw.szName));
525   WideCharToMultiByte(CP_ACP, 0, asiw.szName, -1, asi->szName,
526                       sizeof(asi->szName), NULL, NULL);
527   asi->szName[sizeof(asi->szName) - 1] = 0;
528
529   return hres;
530 }
531
532 /***********************************************************************
533  *              AVIStreamInfoW          (AVIFIL32.@)
534  */
535 HRESULT WINAPI AVIStreamInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
536                               LONG size)
537 {
538   TRACE("(%p,%p,%ld)\n", pstream, asi, size);
539
540   if (pstream == NULL)
541     return AVIERR_BADHANDLE;
542
543   return IAVIStream_Info(pstream, asi, size);
544 }
545
546 /***********************************************************************
547  *              AVIStreamFindSample     (AVIFIL32.@)
548  *              AVIStreamFindSample     (AVIFILE.163)
549  */
550 HRESULT WINAPI AVIStreamFindSample(PAVISTREAM pstream, LONG pos, DWORD flags)
551 {
552   TRACE("(%p,%ld,0x%lX)\n", pstream, pos, flags);
553
554   if (pstream == NULL)
555     return -1;
556
557   return IAVIStream_FindSample(pstream, pos, flags);
558 }
559
560 /***********************************************************************
561  *              AVIStreamReadFormat     (AVIFIL32.@)
562  *              AVIStreamReadFormat     (AVIFILE.164)
563  */
564 HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM pstream, LONG pos,
565                                    LPVOID format, LPLONG formatsize)
566 {
567   TRACE("(%p,%ld,%p,%p)\n", pstream, pos, format, formatsize);
568
569   if (pstream == NULL)
570     return AVIERR_BADHANDLE;
571
572   return IAVIStream_ReadFormat(pstream, pos, format, formatsize);
573 }
574
575 /***********************************************************************
576  *              AVIStreamSetFormat      (AVIFIL32.@)
577  *              AVIStreamSetFormat      (AVIFILE.169)
578  */
579 HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM pstream, LONG pos,
580                                   LPVOID format, LONG formatsize)
581 {
582   TRACE("(%p,%ld,%p,%ld)\n", pstream, pos, format, formatsize);
583
584   if (pstream == NULL)
585     return AVIERR_BADHANDLE;
586
587   return IAVIStream_SetFormat(pstream, pos, format, formatsize);
588 }
589
590 /***********************************************************************
591  *              AVIStreamRead           (AVIFIL32.@)
592  *              AVIStreamRead           (AVIFILE.167)
593  */
594 HRESULT WINAPI AVIStreamRead(PAVISTREAM pstream, LONG start, LONG samples,
595                              LPVOID buffer, LONG buffersize,
596                              LPLONG bytesread, LPLONG samplesread)
597 {
598   TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", pstream, start, samples, buffer,
599         buffersize, bytesread, samplesread);
600
601   if (pstream == NULL)
602     return AVIERR_BADHANDLE;
603
604   return IAVIStream_Read(pstream, start, samples, buffer, buffersize,
605                          bytesread, samplesread);
606 }
607
608 /***********************************************************************
609  *              AVIStreamWrite          (AVIFIL32.@)
610  *              AVIStreamWrite          (AVIFILE.168)
611  */
612 HRESULT WINAPI AVIStreamWrite(PAVISTREAM pstream, LONG start, LONG samples,
613                               LPVOID buffer, LONG buffersize, DWORD flags,
614                               LPLONG sampwritten, LPLONG byteswritten)
615 {
616   TRACE("(%p,%ld,%ld,%p,%ld,0x%lX,%p,%p)\n", pstream, start, samples, buffer,
617         buffersize, flags, sampwritten, byteswritten);
618
619   if (pstream == NULL)
620     return AVIERR_BADHANDLE;
621
622   return IAVIStream_Write(pstream, start, samples, buffer, buffersize,
623                           flags, sampwritten, byteswritten);
624 }
625
626 /***********************************************************************
627  *              AVIStreamReadData       (AVIFIL32.@)
628  *              AVIStreamReadData       (AVIFILE.165)
629  */
630 HRESULT WINAPI AVIStreamReadData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
631                                  LPLONG lpread)
632 {
633   TRACE("(%p,'%4.4s',%p,%p)\n", pstream, (char*)&fcc, lp, lpread);
634
635   if (pstream == NULL)
636     return AVIERR_BADHANDLE;
637
638   return IAVIStream_ReadData(pstream, fcc, lp, lpread);
639 }
640
641 /***********************************************************************
642  *              AVIStreamWriteData      (AVIFIL32.@)
643  *              AVIStreamWriteData      (AVIFILE.166)
644  */
645 HRESULT WINAPI AVIStreamWriteData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
646                                   LONG size)
647 {
648   TRACE("(%p,'%4.4s',%p,%ld)\n", pstream, (char*)&fcc, lp, size);
649
650   if (pstream == NULL)
651     return AVIERR_BADHANDLE;
652
653   return IAVIStream_WriteData(pstream, fcc, lp, size);
654 }
655
656 /***********************************************************************
657  *              AVIStreamGetFrameOpen   (AVIFIL32.@)
658  *              AVIStreamGetFrameOpen   (AVIFILE.112)
659  */
660 PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream,
661                                        LPBITMAPINFOHEADER lpbiWanted)
662 {
663   PGETFRAME pg = NULL;
664
665   TRACE("(%p,%p)\n", pstream, lpbiWanted);
666
667   if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) ||
668       pg == NULL) {
669     pg = AVIFILE_CreateGetFrame(pstream);
670     if (pg == NULL)
671       return NULL;
672   }
673
674   if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) {
675     IGetFrame_Release(pg);
676     return NULL;
677   }
678
679   return pg;
680 }
681
682 /***********************************************************************
683  *              AVIStreamGetFrame       (AVIFIL32.@)
684  *              AVIStreamGetFrame       (AVIFILE.110)
685  */
686 LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos)
687 {
688   TRACE("(%p,%ld)\n", pg, pos);
689
690   if (pg == NULL)
691     return NULL;
692
693   return IGetFrame_GetFrame(pg, pos);
694 }
695
696 /***********************************************************************
697  *              AVIStreamGetFrameClose  (AVIFIL32.@)
698  *              AVIStreamGetFrameClose  (AVIFILE.111)
699  */
700 HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg)
701 {
702   TRACE("(%p)\n", pg);
703
704   if (pg != NULL)
705     return IGetFrame_Release(pg);
706   return 0;
707 }
708
709 /***********************************************************************
710  *              AVIMakeCompressedStream (AVIFIL32.@)
711  */
712 HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,
713                                        PAVISTREAM psSource,
714                                        LPAVICOMPRESSOPTIONS aco,
715                                        LPCLSID pclsidHandler)
716 {
717   AVISTREAMINFOW asiw;
718   CHAR           szRegKey[25];
719   CHAR           szValue[100];
720   CLSID          clsidHandler;
721   HRESULT        hr;
722   LONG           size = sizeof(szValue);
723
724   TRACE("(%p,%p,%p,%s)\n", ppsCompressed, psSource, aco,
725         debugstr_guid(pclsidHandler));
726
727   if (ppsCompressed == NULL)
728     return AVIERR_BADPARAM;
729   if (psSource == NULL)
730     return AVIERR_BADHANDLE;
731
732   *ppsCompressed = NULL;
733
734   /* if no handler given get default ones based on streamtype */
735   if (pclsidHandler == NULL) {
736     hr = IAVIStream_Info(psSource, &asiw, sizeof(asiw));
737     if (FAILED(hr))
738       return hr;
739
740     wsprintfA(szRegKey, "AVIFile\\Compressors\\%4.4s", (char*)&asiw.fccType);
741     if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &size) != ERROR_SUCCESS)
742       return AVIERR_UNSUPPORTED;
743     if (AVIFILE_CLSIDFromString(szValue, &clsidHandler) != S_OK)
744       return AVIERR_UNSUPPORTED;
745   } else
746     memcpy(&clsidHandler, pclsidHandler, sizeof(clsidHandler));
747
748   hr = SHCoCreateInstance(NULL, &clsidHandler, NULL,
749                           &IID_IAVIStream, (LPVOID*)ppsCompressed);
750   if (FAILED(hr) || *ppsCompressed == NULL)
751     return hr;
752
753   hr = IAVIStream_Create(*ppsCompressed, (LPARAM)psSource, (LPARAM)aco);
754   if (FAILED(hr)) {
755     IAVIStream_Release(*ppsCompressed);
756     *ppsCompressed = NULL;
757   }
758
759   return hr;
760 }
761
762 /***********************************************************************
763  *              AVIMakeFileFromStreams  (AVIFIL32.@)
764  */
765 HRESULT WINAPI AVIMakeFileFromStreams(PAVIFILE *ppfile, int nStreams,
766                                       PAVISTREAM *ppStreams)
767 {
768   TRACE("(%p,%d,%p)\n", ppfile, nStreams, ppStreams);
769
770   if (nStreams < 0 || ppfile == NULL || ppStreams == NULL)
771     return AVIERR_BADPARAM;
772
773   *ppfile = AVIFILE_CreateAVITempFile(nStreams, ppStreams);
774   if (*ppfile == NULL)
775     return AVIERR_MEMORY;
776
777   return AVIERR_OK;
778 }
779
780 /***********************************************************************
781  *              AVIStreamOpenFromFile   (AVIFILE.103)
782  *              AVIStreamOpenFromFileA  (AVIFIL32.@)
783  */
784 HRESULT WINAPI AVIStreamOpenFromFileA(PAVISTREAM *ppavi, LPCSTR szFile,
785                                       DWORD fccType, LONG lParam,
786                                       UINT mode, LPCLSID pclsidHandler)
787 {
788   PAVIFILE pfile = NULL;
789   HRESULT  hr;
790
791   TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_a(szFile),
792         (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
793
794   if (ppavi == NULL || szFile == NULL)
795     return AVIERR_BADPARAM;
796
797   *ppavi = NULL;
798
799   hr = AVIFileOpenA(&pfile, szFile, mode, pclsidHandler);
800   if (FAILED(hr) || pfile == NULL)
801     return hr;
802
803   hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
804   IAVIFile_Release(pfile);
805
806   return hr;
807 }
808
809 /***********************************************************************
810  *              AVIStreamOpenFromFileW  (AVIFIL32.@)
811  */
812 HRESULT WINAPI AVIStreamOpenFromFileW(PAVISTREAM *ppavi, LPCWSTR szFile,
813                                       DWORD fccType, LONG lParam,
814                                       UINT mode, LPCLSID pclsidHandler)
815 {
816   PAVIFILE pfile = NULL;
817   HRESULT  hr;
818
819   TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_w(szFile),
820         (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
821
822   if (ppavi == NULL || szFile == NULL)
823     return AVIERR_BADPARAM;
824
825   *ppavi = NULL;
826
827   hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler);
828   if (FAILED(hr) || pfile == NULL)
829     return hr;
830
831   hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
832   IAVIFile_Release(pfile);
833
834   return hr;
835 }
836
837 /***********************************************************************
838  *              AVIStreamStart          (AVIFILE.130)
839  *              AVIStreamStart          (AVIFIL32.@)
840  */
841 LONG WINAPI AVIStreamStart(PAVISTREAM pstream)
842 {
843   AVISTREAMINFOW asiw;
844
845   TRACE("(%p)\n", pstream);
846
847   if (pstream == NULL)
848     return 0;
849
850   if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
851     return 0;
852
853   return asiw.dwStart;
854 }
855
856 /***********************************************************************
857  *              AVIStreamLength         (AVIFILE.131)
858  *              AVIStreamLength         (AVIFIL32.@)
859  */
860 LONG WINAPI AVIStreamLength(PAVISTREAM pstream)
861 {
862   AVISTREAMINFOW asiw;
863
864   TRACE("(%p)\n", pstream);
865
866   if (pstream == NULL)
867     return 0;
868
869   if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
870     return 0;
871
872   return asiw.dwLength;
873 }
874
875 /***********************************************************************
876  *              AVIStreamSampleToTime   (AVIFILE.133)
877  *              AVIStreamSampleToTime   (AVIFIL32.@)
878  */
879 LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample)
880 {
881   AVISTREAMINFOW asiw;
882
883   TRACE("(%p,%ld)\n", pstream, lSample);
884
885   if (pstream == NULL)
886     return -1;
887
888   if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
889     return -1;
890   if (asiw.dwRate == 0)
891     return -1;
892
893   return (LONG)(((float)lSample * asiw.dwScale * 1000.0) / asiw.dwRate);
894 }
895
896 /***********************************************************************
897  *              AVIStreamTimeToSample   (AVIFILE.132)
898  *              AVIStreamTimeToSample   (AVIFIL32.@)
899  */
900 LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime)
901 {
902   AVISTREAMINFOW asiw;
903
904   TRACE("(%p,%ld)\n", pstream, lTime);
905
906   if (pstream == NULL)
907     return -1;
908
909   if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
910     return -1;
911   if (asiw.dwScale == 0)
912     return -1;
913
914   return (LONG)(((float)lTime * asiw.dwRate) / asiw.dwScale / 1000.0);
915 }
916
917 /***********************************************************************
918  *              AVIBuildFilterA         (AVIFIL32.@)
919  *              AVIBuildFilter          (AVIFILE.123)
920  */
921 HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving)
922 {
923   LPWSTR  wszFilter;
924   HRESULT hr;
925
926   TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
927
928   /* check parameters */
929   if (szFilter == NULL)
930     return AVIERR_BADPARAM;
931   if (cbFilter < 2)
932     return AVIERR_BADSIZE;
933
934   szFilter[0] = 0;
935   szFilter[1] = 0;
936
937   wszFilter = (LPWSTR)GlobalAllocPtr(GHND, cbFilter);
938   if (wszFilter == NULL)
939     return AVIERR_MEMORY;
940
941   hr = AVIBuildFilterW(wszFilter, cbFilter, fSaving);
942   if (SUCCEEDED(hr)) {
943     WideCharToMultiByte(CP_ACP, 0, wszFilter, cbFilter,
944                         szFilter, cbFilter, NULL, NULL);
945   }
946
947   GlobalFreePtr(wszFilter);
948
949   return hr;
950 }
951
952 /***********************************************************************
953  *              AVIBuildFilterW         (AVIFIL32.@)
954  */
955 HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving)
956 {
957   static const WCHAR szClsid[] = {'C','L','S','I','D',0};
958   static const WCHAR szExtensionFmt[] = {';','*','.','%','s',0};
959   static const WCHAR szAVIFileExtensions[] =
960     {'A','V','I','F','i','l','e','\\','E','x','t','e','n','s','i','o','n','s',0};
961
962   AVIFilter *lp;
963   WCHAR      szAllFiles[40];
964   WCHAR      szFileExt[10];
965   WCHAR      szValue[128];
966   HKEY       hKey;
967   DWORD      n, i;
968   LONG       size;
969   DWORD      count = 0;
970
971   TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
972
973   /* check parameters */
974   if (szFilter == NULL)
975     return AVIERR_BADPARAM;
976   if (cbFilter < 2)
977     return AVIERR_BADSIZE;
978
979   lp = (AVIFilter*)GlobalAllocPtr(GHND, MAX_FILTERS * sizeof(AVIFilter));
980   if (lp == NULL)
981     return AVIERR_MEMORY;
982
983   /*
984    * 1. iterate over HKEY_CLASSES_ROOT\\AVIFile\\Extensions and collect
985    *    extensions and CLSID's
986    * 2. iterate over collected CLSID's and copy it's description and it's
987    *    extensions to szFilter if it fits
988    *
989    * First filter is named "All multimedia files" and it's filter is a
990    * collection of all possible extensions except "*.*".
991    */
992   if (RegOpenKeyW(HKEY_CLASSES_ROOT, szAVIFileExtensions, &hKey) != S_OK) {
993     GlobalFreePtr(lp);
994     return AVIERR_ERROR;
995   }
996   for (n = 0;RegEnumKeyW(hKey, n, szFileExt, sizeof(szFileExt)) == S_OK;n++) {
997     /* get CLSID to extension */
998     size = sizeof(szValue)/sizeof(szValue[0]);
999     if (RegQueryValueW(hKey, szFileExt, szValue, &size) != S_OK)
1000       break;
1001
1002     /* search if the CLSID is already known */
1003     for (i = 1; i <= count; i++) {
1004       if (lstrcmpW(lp[i].szClsid, szValue) == 0)
1005         break; /* a new one */
1006     }
1007
1008     if (count - i == -1U) {
1009       /* it's a new CLSID */
1010
1011       /* FIXME: How do we get info's about read/write capabilities? */
1012
1013       if (count >= MAX_FILTERS) {
1014         /* try to inform user of our full fixed size table */
1015         ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS);
1016         break;
1017       }
1018
1019       lstrcpyW(lp[i].szClsid, szValue);
1020
1021       count++;
1022     }
1023
1024     /* append extension to the filter */
1025     wsprintfW(szValue, szExtensionFmt, szFileExt);
1026     if (lp[i].szExtensions[0] == 0)
1027       lstrcatW(lp[i].szExtensions, szValue + 1);
1028     else
1029       lstrcatW(lp[i].szExtensions, szValue);
1030
1031     /* also append to the "all multimedia"-filter */
1032     if (lp[0].szExtensions[0] == 0)
1033       lstrcatW(lp[0].szExtensions, szValue + 1);
1034     else
1035       lstrcatW(lp[0].szExtensions, szValue);
1036   }
1037   RegCloseKey(hKey);
1038
1039   /* 2. get descriptions for the CLSIDs and fill out szFilter */
1040   if (RegOpenKeyW(HKEY_CLASSES_ROOT, szClsid, &hKey) != S_OK) {
1041     GlobalFreePtr(lp);
1042     return AVIERR_ERROR;
1043   }
1044   for (n = 0; n <= count; n++) {
1045     /* first the description */
1046     if (n != 0) {
1047       size = sizeof(szValue)/sizeof(szValue[0]);
1048       if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == S_OK) {
1049         size = lstrlenW(szValue);
1050         lstrcpynW(szFilter, szValue, cbFilter);
1051       }
1052     } else
1053       size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter);
1054
1055     /* check for enough space */
1056     size++;
1057     if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) {
1058       szFilter[0] = 0;
1059       szFilter[1] = 0;
1060       GlobalFreePtr(lp);
1061       RegCloseKey(hKey);
1062       return AVIERR_BUFFERTOOSMALL;
1063     }
1064     cbFilter -= size;
1065     szFilter += size;
1066
1067     /* and then the filter */
1068     lstrcpynW(szFilter, lp[n].szExtensions, cbFilter);
1069     size = lstrlenW(lp[n].szExtensions) + 1;
1070     cbFilter -= size;
1071     szFilter += size;
1072   }
1073
1074   RegCloseKey(hKey);
1075   GlobalFreePtr(lp);
1076
1077   /* add "All files" "*.*" filter if enough space left */
1078   size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES,
1079                      szAllFiles, sizeof(szAllFiles)) + 1;
1080   if (cbFilter > size) {
1081     int i;
1082
1083     /* replace '@' with \000 to separate description of filter */
1084     for (i = 0; i < size && szAllFiles[i] != 0; i++) {
1085       if (szAllFiles[i] == '@') {
1086         szAllFiles[i] = 0;
1087         break;
1088       }
1089     }
1090       
1091     memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0]));
1092     szFilter += size;
1093     szFilter[0] = 0;
1094
1095     return AVIERR_OK;
1096   } else {
1097     szFilter[0] = 0;
1098     return AVIERR_BUFFERTOOSMALL;
1099   }
1100 }
1101
1102 static BOOL AVISaveOptionsFmtChoose(HWND hWnd)
1103 {
1104   LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent];
1105   AVISTREAMINFOW       sInfo;
1106
1107   TRACE("(%p)\n", hWnd);
1108
1109   if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) {
1110     ERR(": bad state!\n");
1111     return FALSE;
1112   }
1113
1114   if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent],
1115                             &sInfo, sizeof(sInfo)))) {
1116     ERR(": AVIStreamInfoW failed!\n");
1117     return FALSE;
1118   }
1119
1120   if (sInfo.fccType == streamtypeVIDEO) {
1121     COMPVARS cv;
1122     BOOL     ret;
1123
1124     memset(&cv, 0, sizeof(cv));
1125
1126     if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) {
1127       memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS));
1128       pOptions->fccType    = streamtypeVIDEO;
1129       pOptions->fccHandler = comptypeDIB;
1130       pOptions->dwQuality  = (DWORD)ICQUALITY_DEFAULT;
1131     }
1132
1133     cv.cbSize     = sizeof(cv);
1134     cv.dwFlags    = ICMF_COMPVARS_VALID;
1135     /*cv.fccType    = pOptions->fccType; */
1136     cv.fccHandler = pOptions->fccHandler;
1137     cv.lQ         = pOptions->dwQuality;
1138     cv.lpState    = pOptions->lpParms;
1139     cv.cbState    = pOptions->cbParms;
1140     if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES)
1141       cv.lKey = pOptions->dwKeyFrameEvery;
1142     else
1143       cv.lKey = 0;
1144     if (pOptions->dwFlags & AVICOMPRESSF_DATARATE)
1145       cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */
1146     else
1147       cv.lDataRate = 0;
1148
1149     ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL,
1150                              SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL);
1151
1152     if (ret) {
1153       pOptions->fccHandler = cv.fccHandler;
1154       pOptions->lpParms   = cv.lpState;
1155       pOptions->cbParms   = cv.cbState;
1156       pOptions->dwQuality = cv.lQ;
1157       if (cv.lKey != 0) {
1158         pOptions->dwKeyFrameEvery = cv.lKey;
1159         pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES;
1160       } else
1161         pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES;
1162       if (cv.lDataRate != 0) {
1163         pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */
1164         pOptions->dwFlags |= AVICOMPRESSF_DATARATE;
1165       } else
1166         pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE;
1167       pOptions->dwFlags  |= AVICOMPRESSF_VALID;
1168     }
1169     ICCompressorFree(&cv);
1170
1171     return ret;
1172   } else if (sInfo.fccType == streamtypeAUDIO) {
1173     ACMFORMATCHOOSEW afmtc;
1174     MMRESULT         ret;
1175     LONG             size;
1176
1177     /* FIXME: check ACM version -- Which version is needed? */
1178
1179     memset(&afmtc, 0, sizeof(afmtc));
1180     afmtc.cbStruct  = sizeof(afmtc);
1181     afmtc.fdwStyle  = 0;
1182     afmtc.hwndOwner = hWnd;
1183
1184     acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size);
1185     if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) {
1186       pOptions->lpFormat = GlobalAllocPtr(GMEM_MOVEABLE, size);
1187       pOptions->cbFormat = size;
1188     } else if (pOptions->cbFormat < (DWORD)size) {
1189       pOptions->lpFormat = GlobalReAllocPtr(pOptions->lpFormat, size, GMEM_MOVEABLE);
1190       pOptions->cbFormat = size;
1191     }
1192     if (pOptions->lpFormat == NULL)
1193       return FALSE;
1194     afmtc.pwfx  = pOptions->lpFormat;
1195     afmtc.cbwfx = pOptions->cbFormat;
1196
1197     size = 0;
1198     AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],
1199                         sInfo.dwStart, &size);
1200     if (size < (LONG)sizeof(PCMWAVEFORMAT))
1201       size = sizeof(PCMWAVEFORMAT);
1202     afmtc.pwfxEnum = GlobalAllocPtr(GHND, size);
1203     if (afmtc.pwfxEnum != NULL) {
1204       AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],
1205                           sInfo.dwStart, afmtc.pwfxEnum, &size);
1206       afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT;
1207     }
1208
1209     ret = acmFormatChooseW(&afmtc);
1210     if (ret == S_OK)
1211       pOptions->dwFlags |= AVICOMPRESSF_VALID;
1212
1213     if (afmtc.pwfxEnum != NULL)
1214       GlobalFreePtr(afmtc.pwfxEnum);
1215
1216     return (ret == S_OK ? TRUE : FALSE);
1217   } else {
1218     ERR(": unknown streamtype 0x%08lX\n", sInfo.fccType);
1219     return FALSE;
1220   }
1221 }
1222
1223 static void AVISaveOptionsUpdate(HWND hWnd)
1224 {
1225   static const WCHAR szVideoFmt[]={'%','l','d','x','%','l','d','x','%','d',0};
1226   static const WCHAR szAudioFmt[]={'%','s',' ','%','s',0};
1227
1228   WCHAR          szFormat[128];
1229   AVISTREAMINFOW sInfo;
1230   LPVOID         lpFormat;
1231   LONG           size;
1232
1233   TRACE("(%p)\n", hWnd);
1234
1235   SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0);
1236   if (SaveOpts.nCurrent < 0)
1237     return;
1238
1239   if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo))))
1240     return;
1241
1242   AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size);
1243   if (size > 0) {
1244     szFormat[0] = 0;
1245
1246     /* read format to build format descriotion string */
1247     lpFormat = GlobalAllocPtr(GHND, size);
1248     if (lpFormat != NULL) {
1249       if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) {
1250         if (sInfo.fccType == streamtypeVIDEO) {
1251           LPBITMAPINFOHEADER lpbi = lpFormat;
1252           ICINFO icinfo;
1253
1254           wsprintfW(szFormat, szVideoFmt, lpbi->biWidth,
1255                     lpbi->biHeight, lpbi->biBitCount);
1256
1257           if (lpbi->biCompression != BI_RGB) {
1258             HIC    hic;
1259
1260             hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat,
1261                            NULL, ICMODE_DECOMPRESS);
1262             if (hic != NULL) {
1263               if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK)
1264                 lstrcatW(szFormat, icinfo.szDescription);
1265               ICClose(hic);
1266             }
1267           } else {
1268             LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED,
1269                         icinfo.szDescription, sizeof(icinfo.szDescription));
1270             lstrcatW(szFormat, icinfo.szDescription);
1271           }
1272         } else if (sInfo.fccType == streamtypeAUDIO) {
1273           ACMFORMATTAGDETAILSW aftd;
1274           ACMFORMATDETAILSW    afd;
1275
1276           memset(&aftd, 0, sizeof(aftd));
1277           memset(&afd, 0, sizeof(afd));
1278
1279           aftd.cbStruct     = sizeof(aftd);
1280           aftd.dwFormatTag  = afd.dwFormatTag =
1281             ((PWAVEFORMATEX)lpFormat)->wFormatTag;
1282           aftd.cbFormatSize = afd.cbwfx = size;
1283
1284           afd.cbStruct      = sizeof(afd);
1285           afd.pwfx          = lpFormat;
1286
1287           if (acmFormatTagDetailsW(NULL, &aftd,
1288                                    ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) {
1289             if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK)
1290               wsprintfW(szFormat, szAudioFmt, afd.szFormat, aftd.szFormatTag);
1291           }
1292         }
1293       }
1294       GlobalFreePtr(lpFormat);
1295     }
1296
1297     /* set text for format description */
1298     SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat);
1299
1300     /* Disable option button for unsupported streamtypes */
1301     if (sInfo.fccType == streamtypeVIDEO ||
1302         sInfo.fccType == streamtypeAUDIO)
1303       EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE);
1304     else
1305       EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE);
1306   }
1307
1308 }
1309
1310 INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg,
1311                                     WPARAM wParam, LPARAM lParam)
1312 {
1313   DWORD dwInterleave;
1314   BOOL  bIsInterleaved;
1315   INT   n;
1316
1317   /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/
1318
1319   switch (uMsg) {
1320   case WM_INITDIALOG:
1321     SaveOpts.nCurrent = 0;
1322     if (SaveOpts.nStreams == 1) {
1323       EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd));
1324       return TRUE;
1325     }
1326
1327     /* add streams */
1328     for (n = 0; n < SaveOpts.nStreams; n++) {
1329       AVISTREAMINFOW sInfo;
1330
1331       AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo));
1332       SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING,
1333                           0L, (LPARAM)sInfo.szName);
1334     }
1335
1336     /* select first stream */
1337     SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0);
1338     SendMessageW(hWnd, WM_COMMAND,
1339                  GET_WM_COMMAND_MPS(IDC_STREAM, hWnd, CBN_SELCHANGE));
1340
1341     /* initialize interleave */
1342     if (SaveOpts.ppOptions[0] != NULL &&
1343         (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_VALID)) {
1344       bIsInterleaved = (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_INTERLEAVE);
1345       dwInterleave = SaveOpts.ppOptions[0]->dwInterleaveEvery;
1346     } else {
1347       bIsInterleaved = TRUE;
1348       dwInterleave   = 0;
1349     }
1350     CheckDlgButton(hWnd, IDC_INTERLEAVE, bIsInterleaved);
1351     SetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, dwInterleave, FALSE);
1352     EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), bIsInterleaved);
1353     break;
1354   case WM_COMMAND:
1355     switch (GET_WM_COMMAND_ID(wParam, lParam)) {
1356     case IDOK:
1357       /* get data from controls and save them */
1358       dwInterleave   = GetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, NULL, 0);
1359       bIsInterleaved = IsDlgButtonChecked(hWnd, IDC_INTERLEAVE);
1360       for (n = 0; n < SaveOpts.nStreams; n++) {
1361         if (SaveOpts.ppOptions[n] != NULL) {
1362           if (bIsInterleaved) {
1363             SaveOpts.ppOptions[n]->dwFlags |= AVICOMPRESSF_INTERLEAVE;
1364             SaveOpts.ppOptions[n]->dwInterleaveEvery = dwInterleave;
1365           } else
1366             SaveOpts.ppOptions[n]->dwFlags &= ~AVICOMPRESSF_INTERLEAVE;
1367         }
1368       }
1369       /* fall through */
1370     case IDCANCEL:
1371       EndDialog(hWnd, GET_WM_COMMAND_CMD(wParam, lParam) == IDOK);
1372       break;
1373     case IDC_INTERLEAVE:
1374       EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY),
1375                    IsDlgButtonChecked(hWnd, IDC_INTERLEAVE));
1376       break;
1377     case IDC_STREAM:
1378       if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) {
1379         /* update control elements */
1380         AVISaveOptionsUpdate(hWnd);
1381       }
1382       break;
1383     case IDC_OPTIONS:
1384       AVISaveOptionsFmtChoose(hWnd);
1385       break;
1386     };
1387     return TRUE;
1388   };
1389
1390   return FALSE;
1391 }
1392
1393 /***********************************************************************
1394  *              AVISaveOptions          (AVIFIL32.@)
1395  */
1396 BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams,
1397                            PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions)
1398 {
1399   LPAVICOMPRESSOPTIONS pSavedOptions = NULL;
1400   INT ret, n;
1401
1402   TRACE("(%p,0x%X,%d,%p,%p)\n", hWnd, uFlags, nStreams,
1403         ppavi, ppOptions);
1404
1405   /* check parameters */
1406   if (nStreams <= 0 || ppavi == NULL || ppOptions == NULL)
1407     return AVIERR_BADPARAM;
1408
1409   /* save options for case user press cancel */
1410   if (ppOptions != NULL && nStreams > 1) {
1411     pSavedOptions = GlobalAllocPtr(GHND,nStreams * sizeof(AVICOMPRESSOPTIONS));
1412     if (pSavedOptions == NULL)
1413       return FALSE;
1414
1415     for (n = 0; n < nStreams; n++) {
1416       if (ppOptions[n] != NULL)
1417         memcpy(pSavedOptions + n, ppOptions[n], sizeof(AVICOMPRESSOPTIONS));
1418     }
1419   }
1420
1421   SaveOpts.uFlags    = uFlags;
1422   SaveOpts.nStreams  = nStreams;
1423   SaveOpts.ppavis    = ppavi;
1424   SaveOpts.ppOptions = ppOptions;
1425
1426   ret = DialogBoxW(AVIFILE_hModule, MAKEINTRESOURCEW(IDD_SAVEOPTIONS),
1427                    hWnd, AVISaveOptionsDlgProc);
1428
1429   if (ret == -1)
1430     ret = FALSE;
1431
1432   /* restore options when user pressed cancel */
1433   if (pSavedOptions != NULL && ret == FALSE) {
1434     for (n = 0; n < nStreams; n++) {
1435       if (ppOptions[n] != NULL)
1436         memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS));
1437     }
1438     GlobalFreePtr(pSavedOptions);
1439   }
1440
1441   return (BOOL)ret;
1442 }
1443
1444 /***********************************************************************
1445  *              AVISaveOptionsFree      (AVIFIL32.@)
1446  *              AVISaveOptionsFree      (AVIFILE.124)
1447  */
1448 HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions)
1449 {
1450   TRACE("(%d,%p)\n", nStreams, ppOptions);
1451
1452   if (nStreams < 0 || ppOptions == NULL)
1453     return AVIERR_BADPARAM;
1454
1455   for (; nStreams > 0; nStreams--) {
1456     if (ppOptions[nStreams] != NULL) {
1457       ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID;
1458
1459       if (ppOptions[nStreams]->lpParms != NULL) {
1460         GlobalFreePtr(ppOptions[nStreams]->lpParms);
1461         ppOptions[nStreams]->lpParms = NULL;
1462         ppOptions[nStreams]->cbParms = 0;
1463       }
1464       if (ppOptions[nStreams]->lpFormat != NULL) {
1465         GlobalFreePtr(ppOptions[nStreams]->lpFormat);
1466         ppOptions[nStreams]->lpFormat = NULL;
1467         ppOptions[nStreams]->cbFormat = 0;
1468       }
1469     }
1470   }
1471
1472   return AVIERR_OK;
1473 }
1474
1475 /***********************************************************************
1476  *              AVISaveVA               (AVIFIL32.@)
1477  */
1478 HRESULT WINAPI AVISaveVA(LPCSTR szFile, CLSID *pclsidHandler,
1479                          AVISAVECALLBACK lpfnCallback, int nStream,
1480                          PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1481 {
1482   LPWSTR  wszFile = NULL;
1483   HRESULT hr;
1484   int     len;
1485
1486   TRACE("%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler,
1487         lpfnCallback, nStream, ppavi, plpOptions);
1488
1489   if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1490     return AVIERR_BADPARAM;
1491
1492   /* convert ASCII string to Unicode and call Unicode function */
1493   len = lstrlenA(szFile);
1494   if (len <= 0)
1495     return AVIERR_BADPARAM;
1496
1497   wszFile = (LPWSTR)LocalAlloc(LPTR, (len + 1) * sizeof(WCHAR));
1498   if (wszFile == NULL)
1499     return AVIERR_MEMORY;
1500
1501   MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len + 1);
1502   wszFile[len + 1] = 0;
1503
1504   hr = AVISaveVW(wszFile, pclsidHandler, lpfnCallback,
1505                  nStream, ppavi, plpOptions);
1506
1507   LocalFree((HLOCAL)wszFile);
1508
1509   return hr;
1510 }
1511
1512 /***********************************************************************
1513  *              AVISaveVW               (AVIFIL32.@)
1514  */
1515 HRESULT WINAPI AVISaveVW(LPCWSTR szFile, CLSID *pclsidHandler,
1516                          AVISAVECALLBACK lpfnCallback, int nStream,
1517                          PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
1518 {
1519   FIXME("(%s,%p,%p,%d,%p,%p), stub!\n", debugstr_w(szFile), pclsidHandler,
1520         lpfnCallback, nStream, ppavi, plpOptions);
1521
1522   if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
1523     return AVIERR_BADPARAM;
1524
1525   return AVIERR_UNSUPPORTED;
1526 }
1527
1528 /***********************************************************************
1529  *              CreateEditableStream    (AVIFIL32.@)
1530  */
1531 HRESULT WINAPI CreateEditableStream(PAVISTREAM *ppEditable, PAVISTREAM pSource)
1532 {
1533   FIXME("(%p,%p), stub!\n", ppEditable, pSource);
1534
1535   if (pSource == NULL)
1536     return AVIERR_BADHANDLE;
1537   if (ppEditable == NULL)
1538     return AVIERR_BADPARAM;
1539
1540   *ppEditable = NULL;
1541
1542   return AVIERR_UNSUPPORTED;
1543 }
1544
1545 /***********************************************************************
1546  *              EditStreamClone         (AVIFIL32.@)
1547  */
1548 HRESULT WINAPI EditStreamClone(PAVISTREAM pStream, PAVISTREAM *ppResult)
1549 {
1550   PAVIEDITSTREAM pEdit = NULL;
1551   HRESULT        hr;
1552
1553   TRACE("(%p,%p)\n", pStream, ppResult);
1554
1555   if (pStream == NULL)
1556     return AVIERR_BADHANDLE;
1557   if (ppResult == NULL)
1558     return AVIERR_BADPARAM;
1559
1560   *ppResult = NULL;
1561
1562   hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
1563   if (SUCCEEDED(hr) && pEdit != NULL) {
1564     hr = IAVIEditStream_Clone(pEdit, ppResult);
1565
1566     IAVIEditStream_Release(pEdit);
1567   } else
1568     hr = AVIERR_UNSUPPORTED;
1569
1570   return hr;
1571 }
1572
1573 /***********************************************************************
1574  *              EditStreamCopy          (AVIFIL32.@)
1575  */
1576 HRESULT WINAPI EditStreamCopy(PAVISTREAM pStream, LONG *plStart,
1577                               LONG *plLength, PAVISTREAM *ppResult)
1578 {
1579   PAVIEDITSTREAM pEdit = NULL;
1580   HRESULT        hr;
1581
1582   TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
1583
1584   if (pStream == NULL)
1585     return AVIERR_BADHANDLE;
1586   if (plStart == NULL || plLength == NULL || ppResult == NULL)
1587     return AVIERR_BADPARAM;
1588
1589   *ppResult = NULL;
1590
1591   hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
1592   if (SUCCEEDED(hr) && pEdit != NULL) {
1593     hr = IAVIEditStream_Copy(pEdit, plStart, plLength, ppResult);
1594
1595     IAVIEditStream_Release(pEdit);
1596   } else
1597     hr = AVIERR_UNSUPPORTED;
1598
1599   return hr;
1600 }
1601
1602 /***********************************************************************
1603  *              EditStreamCut           (AVIFIL32.@)
1604  */
1605 HRESULT WINAPI EditStreamCut(PAVISTREAM pStream, LONG *plStart,
1606                              LONG *plLength, PAVISTREAM *ppResult)
1607 {
1608   PAVIEDITSTREAM pEdit = NULL;
1609   HRESULT        hr;
1610
1611   TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
1612
1613   if (pStream == NULL)
1614     return AVIERR_BADHANDLE;
1615   if (plStart == NULL || plLength == NULL || ppResult == NULL)
1616     return AVIERR_BADPARAM;
1617
1618   *ppResult = NULL;
1619
1620   hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
1621   if (SUCCEEDED(hr) && pEdit != NULL) {
1622     hr = IAVIEditStream_Cut(pEdit, plStart, plLength, ppResult);
1623
1624     IAVIEditStream_Release(pEdit);
1625   } else
1626     hr = AVIERR_UNSUPPORTED;
1627
1628   return hr;
1629 }
1630
1631 /***********************************************************************
1632  *              EditStreamPaste         (AVIFIL32.@)
1633  */
1634 HRESULT WINAPI EditStreamPaste(PAVISTREAM pDest, LONG *plStart, LONG *plLength,
1635                                PAVISTREAM pSource, LONG lStart, LONG lEnd)
1636 {
1637   PAVIEDITSTREAM pEdit = NULL;
1638   HRESULT        hr;
1639
1640   TRACE("(%p,%p,%p,%p,%ld,%ld)\n", pDest, plStart, plLength,
1641         pSource, lStart, lEnd);
1642
1643   if (pDest == NULL || pSource == NULL)
1644     return AVIERR_BADHANDLE;
1645   if (plStart == NULL || plLength == NULL || lStart < 0)
1646     return AVIERR_BADPARAM;
1647
1648   hr = IAVIStream_QueryInterface(pDest, &IID_IAVIEditStream,(LPVOID*)&pEdit);
1649   if (SUCCEEDED(hr) && pEdit != NULL) {
1650     hr = IAVIEditStream_Paste(pEdit, plStart, plLength, pSource, lStart, lEnd);
1651
1652     IAVIEditStream_Release(pEdit);
1653   } else
1654     hr = AVIERR_UNSUPPORTED;
1655
1656   return hr;
1657 }
1658
1659 /***********************************************************************
1660  *              EditStreamSetInfoA      (AVIFIL32.@)
1661  */
1662 HRESULT WINAPI EditStreamSetInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
1663                                   LONG size)
1664 {
1665   AVISTREAMINFOW asiw;
1666
1667   TRACE("(%p,%p,%ld)\n", pstream, asi, size);
1668
1669   if (pstream == NULL)
1670     return AVIERR_BADHANDLE;
1671   if ((DWORD)size < sizeof(AVISTREAMINFOA))
1672     return AVIERR_BADSIZE;
1673
1674   memcpy(&asiw, asi, sizeof(asi) - sizeof(asi->szName));
1675   MultiByteToWideChar(CP_ACP, 0, asi->szName, -1,
1676                       asiw.szName, sizeof(asiw.szName));
1677
1678   return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
1679 }
1680
1681 /***********************************************************************
1682  *              EditStreamSetInfoW      (AVIFIL32.@)
1683  */
1684 HRESULT WINAPI EditStreamSetInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
1685                                   LONG size)
1686 {
1687   PAVIEDITSTREAM pEdit = NULL;
1688   HRESULT        hr;
1689
1690   TRACE("(%p,%p,%ld)\n", pstream, asi, size);
1691
1692   hr = IAVIStream_QueryInterface(pstream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
1693   if (SUCCEEDED(hr) && pEdit != NULL) {
1694     hr = IAVIEditStream_SetInfo(pEdit, asi, size);
1695
1696     IAVIEditStream_Release(pEdit);
1697   } else
1698     hr = AVIERR_UNSUPPORTED;
1699
1700   return hr;
1701 }
1702
1703 /***********************************************************************
1704  *              EditStreamSetNameA      (AVIFIL32.@)
1705  */
1706 HRESULT WINAPI EditStreamSetNameA(PAVISTREAM pstream, LPCSTR szName)
1707 {
1708   AVISTREAMINFOA asia;
1709   HRESULT        hres;
1710
1711   TRACE("(%p,%s)\n", pstream, debugstr_a(szName));
1712
1713   if (pstream == NULL)
1714     return AVIERR_BADHANDLE;
1715   if (szName == NULL)
1716     return AVIERR_BADPARAM;
1717
1718   hres = AVIStreamInfoA(pstream, &asia, sizeof(asia));
1719   if (FAILED(hres))
1720     return hres;
1721
1722   memset(asia.szName, 0, sizeof(asia.szName));
1723   lstrcpynA(asia.szName, szName, sizeof(asia.szName)/sizeof(asia.szName[0]));
1724
1725   return EditStreamSetInfoA(pstream, &asia, sizeof(asia));
1726 }
1727
1728 /***********************************************************************
1729  *              EditStreamSetNameW      (AVIFIL32.@)
1730  */
1731 HRESULT WINAPI EditStreamSetNameW(PAVISTREAM pstream, LPCWSTR szName)
1732 {
1733   AVISTREAMINFOW asiw;
1734   HRESULT        hres;
1735
1736   TRACE("(%p,%s)\n", pstream, debugstr_w(szName));
1737
1738   if (pstream == NULL)
1739     return AVIERR_BADHANDLE;
1740   if (szName == NULL)
1741     return AVIERR_BADPARAM;
1742
1743   hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
1744   if (FAILED(hres))
1745     return hres;
1746
1747   memset(asiw.szName, 0, sizeof(asiw.szName));
1748   lstrcpynW(asiw.szName, szName, sizeof(asiw.szName)/sizeof(asiw.szName[0]));
1749
1750   return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
1751 }
1752
1753 /***********************************************************************
1754  *              AVIClearClipboard       (AVIFIL32.@)
1755  */
1756 HRESULT WINAPI AVIClearClipboard(void)
1757 {
1758   TRACE("()\n");
1759
1760   return AVIERR_UNSUPPORTED; /* OleSetClipboard(NULL); */
1761 }
1762
1763 /***********************************************************************
1764  *              AVIGetFromClipboard     (AVIFIL32.@)
1765  */
1766 HRESULT WINAPI AVIGetFromClipboard(PAVIFILE *ppfile)
1767 {
1768   FIXME("(%p), stub!\n", ppfile);
1769
1770   *ppfile = NULL;
1771
1772   return AVIERR_UNSUPPORTED;
1773 }
1774
1775 /***********************************************************************
1776  *              AVIPutFileOnClipboard   (AVIFIL32.@)
1777  */
1778 HRESULT WINAPI AVIPutFileOnClipboard(PAVIFILE pfile)
1779 {
1780   FIXME("(%p), stub!\n", pfile);
1781
1782   if (pfile == NULL)
1783     return AVIERR_BADHANDLE;
1784
1785   return AVIERR_UNSUPPORTED;
1786 }