DInput keyboard handling checks for incoming X11 events.
[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 *s = (BYTE*)idstr;
75   BYTE *p;
76   INT   i;
77   BYTE table[256];
78
79   if (!s) {
80     memset(s, 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 (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  */
368 HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE pfile, PAVISTREAM *ppavi,
369                                     LPAVISTREAMINFOA psi)
370 {
371   AVISTREAMINFOW        psiw;
372
373   TRACE("(%p,%p,%p)\n", pfile, ppavi, psi);
374
375   if (pfile == NULL)
376     return AVIERR_BADHANDLE;
377
378   /* Only the szName at the end is different */
379   memcpy(&psiw, psi, sizeof(*psi) - sizeof(psi->szName));
380   MultiByteToWideChar(CP_ACP, 0, psi->szName, -1, psiw.szName,
381                       sizeof(psiw.szName) / sizeof(psiw.szName[0]));
382
383   return IAVIFile_CreateStream(pfile, ppavi, &psiw);
384 }
385
386 /***********************************************************************
387  *              AVIFileCreateStreamW    (AVIFIL32.@)
388  */
389 HRESULT WINAPI AVIFileCreateStreamW(PAVIFILE pfile, PAVISTREAM *avis,
390                                     LPAVISTREAMINFOW asi)
391 {
392   TRACE("(%p,%p,%p)\n", pfile, avis, asi);
393
394   return IAVIFile_CreateStream(pfile, avis, asi);
395 }
396
397 /***********************************************************************
398  *              AVIFileWriteData        (AVIFIL32.@)
399  */
400 HRESULT WINAPI AVIFileWriteData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LONG size)
401 {
402   TRACE("(%p,'%4.4s',%p,%ld)\n", pfile, (char*)&fcc, lp, size);
403
404   if (pfile == NULL)
405     return AVIERR_BADHANDLE;
406
407   return IAVIFile_WriteData(pfile, fcc, lp, size);
408 }
409
410 /***********************************************************************
411  *              AVIFileReadData         (AVIFIL32.@)
412  */
413 HRESULT WINAPI AVIFileReadData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LPLONG size)
414 {
415   TRACE("(%p,'%4.4s',%p,%p)\n", pfile, (char*)&fcc, lp, size);
416
417   if (pfile == NULL)
418     return AVIERR_BADHANDLE;
419
420   return IAVIFile_ReadData(pfile, fcc, lp, size);
421 }
422
423 /***********************************************************************
424  *              AVIFileEndRecord        (AVIFIL32.@)
425  *              AVIFileEndRecord        (AVIFILE.148)
426  */
427 HRESULT WINAPI AVIFileEndRecord(PAVIFILE pfile)
428 {
429   TRACE("(%p)\n", pfile);
430
431   if (pfile == NULL)
432     return AVIERR_BADHANDLE;
433
434   return IAVIFile_EndRecord(pfile);
435 }
436
437 /***********************************************************************
438  *              AVIStreamAddRef         (AVIFIL32.@)
439  *              AVIStreamAddRef         (AVIFILE.160)
440  */
441 ULONG WINAPI AVIStreamAddRef(PAVISTREAM pstream)
442 {
443   TRACE("(%p)\n", pstream);
444
445   if (pstream == NULL) {
446     ERR(": bad handle passed!\n");
447     return 0;
448   }
449
450   return IAVIStream_AddRef(pstream);
451 }
452
453 /***********************************************************************
454  *              AVIStreamRelease        (AVIFIL32.@)
455  *              AVIStreamRelease        (AVIFILE.161)
456  */
457 ULONG WINAPI AVIStreamRelease(PAVISTREAM pstream)
458 {
459   TRACE("(%p)\n", pstream);
460
461   if (pstream == NULL) {
462     ERR(": bad handle passed!\n");
463     return 0;
464   }
465
466   return IAVIStream_Release(pstream);
467 }
468
469 /***********************************************************************
470  *              AVIStreamCreate         (AVIFIL32.@)
471  *              AVIStreamCreate         (AVIFILE.104)
472  */
473 HRESULT WINAPI AVIStreamCreate(PAVISTREAM *ppavi, LONG lParam1, LONG lParam2,
474                                LPCLSID pclsidHandler)
475 {
476   HRESULT hr;
477
478   TRACE("(%p,0x%08lX,0x%08lX,%s)\n", ppavi, lParam1, lParam2,
479         debugstr_guid(pclsidHandler));
480
481   if (ppavi == NULL)
482     return AVIERR_BADPARAM;
483
484   *ppavi = NULL;
485   if (pclsidHandler == NULL)
486     return AVIERR_UNSUPPORTED;
487
488   hr = SHCoCreateInstance(NULL, pclsidHandler, NULL,
489                           &IID_IAVIStream, (LPVOID*)ppavi);
490   if (FAILED(hr) || *ppavi == NULL)
491     return hr;
492
493   hr = IAVIStream_Create(*ppavi, lParam1, lParam2);
494   if (FAILED(hr)) {
495     IAVIStream_Release(*ppavi);
496     *ppavi = NULL;
497   }
498
499   return hr;
500 }
501
502 /***********************************************************************
503  *              AVIStreamInfoA          (AVIFIL32.@)
504  */
505 HRESULT WINAPI AVIStreamInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
506                               LONG size)
507 {
508   AVISTREAMINFOW asiw;
509   HRESULT        hres;
510
511   TRACE("(%p,%p,%ld)\n", pstream, asi, size);
512
513   if (pstream == NULL)
514     return AVIERR_BADHANDLE;
515   if (size < sizeof(AVISTREAMINFOA))
516     return AVIERR_BADSIZE;
517
518   hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
519
520   memcpy(asi, &asiw, sizeof(asiw) - sizeof(asiw.szName));
521   WideCharToMultiByte(CP_ACP, 0, asiw.szName, -1, asi->szName,
522                       sizeof(asi->szName), NULL, NULL);
523   asi->szName[sizeof(asi->szName) - 1] = 0;
524
525   return hres;
526 }
527
528 /***********************************************************************
529  *              AVIStreamInfoW          (AVIFIL32.@)
530  */
531 HRESULT WINAPI AVIStreamInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
532                               LONG size)
533 {
534   TRACE("(%p,%p,%ld)\n", pstream, asi, size);
535
536   if (pstream == NULL)
537     return AVIERR_BADHANDLE;
538
539   return IAVIStream_Info(pstream, asi, size);
540 }
541
542 /***********************************************************************
543  *              AVIStreamFindSample     (AVIFIL32.@)
544  */
545 HRESULT WINAPI AVIStreamFindSample(PAVISTREAM pstream, LONG pos, DWORD flags)
546 {
547   TRACE("(%p,%ld,0x%lX)\n", pstream, pos, flags);
548
549   if (pstream == NULL)
550     return -1;
551
552   return IAVIStream_FindSample(pstream, pos, flags);
553 }
554
555 /***********************************************************************
556  *              AVIStreamReadFormat     (AVIFIL32.@)
557  */
558 HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM pstream, LONG pos,
559                                    LPVOID format, LPLONG formatsize)
560 {
561   TRACE("(%p,%ld,%p,%p)\n", pstream, pos, format, formatsize);
562
563   if (pstream == NULL)
564     return AVIERR_BADHANDLE;
565
566   return IAVIStream_ReadFormat(pstream, pos, format, formatsize);
567 }
568
569 /***********************************************************************
570  *              AVIStreamSetFormat      (AVIFIL32.@)
571  */
572 HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM pstream, LONG pos,
573                                   LPVOID format, LONG formatsize)
574 {
575   TRACE("(%p,%ld,%p,%ld)\n", pstream, pos, format, formatsize);
576
577   if (pstream == NULL)
578     return AVIERR_BADHANDLE;
579
580   return IAVIStream_SetFormat(pstream, pos, format, formatsize);
581 }
582
583 /***********************************************************************
584  *              AVIStreamRead           (AVIFIL32.@)
585  */
586 HRESULT WINAPI AVIStreamRead(PAVISTREAM pstream, LONG start, LONG samples,
587                              LPVOID buffer, LONG buffersize,
588                              LPLONG bytesread, LPLONG samplesread)
589 {
590   TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", pstream, start, samples, buffer,
591         buffersize, bytesread, samplesread);
592
593   if (pstream == NULL)
594     return AVIERR_BADHANDLE;
595
596   return IAVIStream_Read(pstream, start, samples, buffer, buffersize,
597                          bytesread, samplesread);
598 }
599
600 /***********************************************************************
601  *              AVIStreamWrite          (AVIFIL32.@)
602  */
603 HRESULT WINAPI AVIStreamWrite(PAVISTREAM pstream, LONG start, LONG samples,
604                               LPVOID buffer, LONG buffersize, DWORD flags,
605                               LPLONG sampwritten, LPLONG byteswritten)
606 {
607   TRACE("(%p,%ld,%ld,%p,%ld,0x%lX,%p,%p)\n", pstream, start, samples, buffer,
608         buffersize, flags, sampwritten, byteswritten);
609
610   if (pstream == NULL)
611     return AVIERR_BADHANDLE;
612
613   return IAVIStream_Write(pstream, start, samples, buffer, buffersize,
614                           flags, sampwritten, byteswritten);
615 }
616
617 /***********************************************************************
618  *              AVIStreamReadData       (AVIFIL32.@)
619  */
620 HRESULT WINAPI AVIStreamReadData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
621                                  LPLONG lpread)
622 {
623   TRACE("(%p,'%4.4s',%p,%p)\n", pstream, (char*)&fcc, lp, lpread);
624
625   if (pstream == NULL)
626     return AVIERR_BADHANDLE;
627
628   return IAVIStream_ReadData(pstream, fcc, lp, lpread);
629 }
630
631 /***********************************************************************
632  *              AVIStreamWriteData      (AVIFIL32.@)
633  */
634 HRESULT WINAPI AVIStreamWriteData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
635                                   LONG size)
636 {
637   TRACE("(%p,'%4.4s',%p,%ld)\n", pstream, (char*)&fcc, lp, size);
638
639   if (pstream == NULL)
640     return AVIERR_BADHANDLE;
641
642   return IAVIStream_WriteData(pstream, fcc, lp, size);
643 }
644
645 /***********************************************************************
646  *              AVIStreamGetFrameOpen   (AVIFIL32.@)
647  */
648 PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream,
649                                        LPBITMAPINFOHEADER lpbiWanted)
650 {
651   PGETFRAME pg = NULL;
652
653   TRACE("(%p,%p)\n", pstream, lpbiWanted);
654
655   if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) ||
656       pg == NULL) {
657     pg = AVIFILE_CreateGetFrame(pstream);
658     if (pg == NULL)
659       return NULL;
660   }
661
662   if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) {
663     IGetFrame_Release(pg);
664     return NULL;
665   }
666
667   return pg;
668 }
669
670 /***********************************************************************
671  *              AVIStreamGetFrame       (AVIFIL32.@)
672  */
673 LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos)
674 {
675   TRACE("(%p,%ld)\n", pg, pos);
676
677   if (pg == NULL)
678     return NULL;
679
680   return IGetFrame_GetFrame(pg, pos);
681 }
682
683 /***********************************************************************
684  *              AVIStreamGetFrameClose (AVIFIL32.@)
685  */
686 HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg)
687 {
688   TRACE("(%p)\n", pg);
689
690   if (pg != NULL)
691     return IGetFrame_Release(pg);
692   return 0;
693 }
694
695 /***********************************************************************
696  *              AVIMakeCompressedStream (AVIFIL32.@)
697  */
698 HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,
699                                        PAVISTREAM psSource,
700                                        LPAVICOMPRESSOPTIONS aco,
701                                        LPCLSID pclsidHandler)
702 {
703   AVISTREAMINFOW asiw;
704   CHAR           szRegKey[25];
705   CHAR           szValue[100];
706   CLSID          clsidHandler;
707   HRESULT        hr;
708   LONG           size = sizeof(szValue);
709
710   TRACE("(%p,%p,%p,%s)\n", ppsCompressed, psSource, aco,
711         debugstr_guid(pclsidHandler));
712
713   if (ppsCompressed == NULL)
714     return AVIERR_BADPARAM;
715   if (psSource == NULL)
716     return AVIERR_BADHANDLE;
717
718   *ppsCompressed = NULL;
719
720   /* if no handler given get default ones based on streamtype */
721   if (pclsidHandler == NULL) {
722     hr = IAVIStream_Info(psSource, &asiw, sizeof(asiw));
723     if (FAILED(hr))
724       return hr;
725
726     wsprintfA(szRegKey, "AVIFile\\Compressors\\%4.4s", (char*)&asiw.fccType);
727     if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &size) != ERROR_SUCCESS)
728       return AVIERR_UNSUPPORTED;
729     if (AVIFILE_CLSIDFromString(szValue, &clsidHandler) != S_OK)
730       return AVIERR_UNSUPPORTED;
731   } else
732     memcpy(&clsidHandler, pclsidHandler, sizeof(clsidHandler));
733
734   hr = SHCoCreateInstance(NULL, &clsidHandler, NULL,
735                           &IID_IAVIStream, (LPVOID*)ppsCompressed);
736   if (FAILED(hr) || *ppsCompressed == NULL)
737     return hr;
738
739   hr = IAVIStream_Create(*ppsCompressed, (LPARAM)psSource, (LPARAM)aco);
740   if (FAILED(hr)) {
741     IAVIStream_Release(*ppsCompressed);
742     *ppsCompressed = NULL;
743   }
744
745   return hr;
746 }
747
748 /***********************************************************************
749  *              AVIStreamOpenFromFile   (AVIFILE.103)
750  *              AVIStreamOpenFromFileA  (AVIFIL32.@)
751  */
752 HRESULT WINAPI AVIStreamOpenFromFileA(PAVISTREAM *ppavi, LPCSTR szFile,
753                                       DWORD fccType, LONG lParam,
754                                       UINT mode, LPCLSID pclsidHandler)
755 {
756   PAVIFILE pfile = NULL;
757   HRESULT  hr;
758
759   TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_a(szFile),
760         (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
761
762   if (ppavi == NULL || szFile == NULL)
763     return AVIERR_BADPARAM;
764
765   *ppavi = NULL;
766
767   hr = AVIFileOpenA(&pfile, szFile, mode, pclsidHandler);
768   if (FAILED(hr) || pfile == NULL)
769     return hr;
770
771   hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
772   IAVIFile_Release(pfile);
773
774   return hr;
775 }
776
777 /***********************************************************************
778  *              AVIStreamOpenFromFileW  (AVIFIL32.@)
779  */
780 HRESULT WINAPI AVIStreamOpenFromFileW(PAVISTREAM *ppavi, LPCWSTR szFile,
781                                       DWORD fccType, LONG lParam,
782                                       UINT mode, LPCLSID pclsidHandler)
783 {
784   PAVIFILE pfile = NULL;
785   HRESULT  hr;
786
787   TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_w(szFile),
788         (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
789
790   if (ppavi == NULL || szFile == NULL)
791     return AVIERR_BADPARAM;
792
793   *ppavi = NULL;
794
795   hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler);
796   if (FAILED(hr) || pfile == NULL)
797     return hr;
798
799   hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
800   IAVIFile_Release(pfile);
801
802   return hr;
803 }
804
805 /***********************************************************************
806  *              AVIStreamStart          (AVIFILE.130)
807  *              AVIStreamStart          (AVIFIL32.@)
808  */
809 LONG WINAPI AVIStreamStart(PAVISTREAM pstream)
810 {
811   AVISTREAMINFOW asiw;
812
813   TRACE("(%p)\n", pstream);
814
815   if (pstream == NULL)
816     return 0;
817
818   if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
819     return 0;
820
821   return asiw.dwStart;
822 }
823
824 /***********************************************************************
825  *              AVIStreamLength         (AVIFILE.131)
826  *              AVIStreamLength         (AVIFIL32.@)
827  */
828 LONG WINAPI AVIStreamLength(PAVISTREAM pstream)
829 {
830   AVISTREAMINFOW asiw;
831
832   TRACE("(%p)\n", pstream);
833
834   if (pstream == NULL)
835     return 0;
836
837   if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
838     return 0;
839
840   return asiw.dwLength;
841 }
842
843 /***********************************************************************
844  *              AVIStreamSampleToTime   (AVIFILE.133)
845  *              AVIStreamSampleToTime   (AVIFIL32.@)
846  */
847 LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample)
848 {
849   AVISTREAMINFOW asiw;
850
851   TRACE("(%p,%ld)\n", pstream, lSample);
852
853   if (pstream == NULL)
854     return -1;
855
856   if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
857     return -1;
858   if (asiw.dwRate == 0)
859     return -1;
860
861   return (LONG)(((float)lSample * asiw.dwScale * 1000.0) / asiw.dwRate);
862 }
863
864 /***********************************************************************
865  *              AVIStreamTimeToSample   (AVIFILE.132)
866  *              AVIStreamTimeToSample   (AVIFIL32.@)
867  */
868 LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime)
869 {
870   AVISTREAMINFOW asiw;
871
872   TRACE("(%p,%ld)\n", pstream, lTime);
873
874   if (pstream == NULL)
875     return -1;
876
877   if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
878     return -1;
879   if (asiw.dwScale == 0)
880     return -1;
881
882   return (LONG)(((float)lTime * asiw.dwRate) / asiw.dwScale / 1000.0);
883 }
884
885 /***********************************************************************
886  *              AVIBuildFilterA         (AVIFIL32.@)
887  */
888 HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving)
889 {
890   LPWSTR  wszFilter;
891   HRESULT hr;
892
893   TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
894
895   /* check parameters */
896   if (szFilter == NULL)
897     return AVIERR_BADPARAM;
898   if (cbFilter < 2)
899     return AVIERR_BADSIZE;
900
901   szFilter[0] = 0;
902   szFilter[1] = 0;
903
904   wszFilter = (LPWSTR)GlobalAllocPtr(GHND, cbFilter);
905   if (wszFilter == NULL)
906     return AVIERR_MEMORY;
907
908   hr = AVIBuildFilterW(wszFilter, cbFilter, fSaving);
909   if (SUCCEEDED(hr)) {
910     WideCharToMultiByte(CP_ACP, 0, wszFilter, cbFilter,
911                         szFilter, cbFilter, NULL, NULL);
912   }
913
914   GlobalFreePtr(wszFilter);
915
916   return hr;
917 }
918
919 /***********************************************************************
920  *              AVIBuildFilterW         (AVIFIL32.@)
921  */
922 HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving)
923 {
924   static const WCHAR szClsid[] = {'C','L','S','I','D',0};
925   static const WCHAR szExtensionFmt[] = {';','*','.','%','s',0};
926   static const WCHAR szAVIFileExtensions[] =
927     {'A','V','I','F','i','l','e','\\','E','x','t','e','n','s','i','o','n','s',0};
928
929   AVIFilter *lp;
930   WCHAR      szAllFiles[40];
931   WCHAR      szFileExt[10];
932   WCHAR      szValue[128];
933   HKEY       hKey;
934   LONG       n, i;
935   LONG       size;
936   LONG       count = 0;
937
938   TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
939
940   /* check parameters */
941   if (szFilter == NULL)
942     return AVIERR_BADPARAM;
943   if (cbFilter < 2)
944     return AVIERR_BADSIZE;
945
946   lp = (AVIFilter*)GlobalAllocPtr(GHND, MAX_FILTERS * sizeof(AVIFilter));
947   if (lp == NULL)
948     return AVIERR_MEMORY;
949
950   /*
951    * 1. iterate over HKEY_CLASSES_ROOT\\AVIFile\\Extensions and collect
952    *    extensions and CLSID's
953    * 2. iterate over collected CLSID's and copy it's description and it's
954    *    extensions to szFilter if it fits
955    *
956    * First filter is named "All multimedia files" and it's filter is a
957    * collection of all possible extensions except "*.*".
958    */
959   if (RegOpenKeyW(HKEY_CLASSES_ROOT, szAVIFileExtensions, &hKey) != S_OK) {
960     GlobalFreePtr(lp);
961     return AVIERR_ERROR;
962   }
963   for (n = 0;RegEnumKeyW(hKey, n, szFileExt, sizeof(szFileExt)) == S_OK;n++) {
964     /* get CLSID to extension */
965     size = sizeof(szValue)/sizeof(szValue[0]);
966     if (RegQueryValueW(hKey, szFileExt, szValue, &size) != S_OK)
967       break;
968
969     /* search if the CLSID is already known */
970     for (i = 1; i <= count; i++) {
971       if (lstrcmpW(lp[i].szClsid, szValue) == 0)
972         break; /* a new one */
973     }
974
975     if (count - i == -1) {
976       /* it's a new CLSID */
977
978       /* FIXME: How do we get info's about read/write capabilities? */
979
980       if (count >= MAX_FILTERS) {
981         /* try to inform user of our full fixed size table */
982         ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS);
983         break;
984       }
985
986       lstrcpyW(lp[i].szClsid, szValue);
987
988       count++;
989     }
990
991     /* append extension to the filter */
992     wsprintfW(szValue, szExtensionFmt, szFileExt);
993     if (lp[i].szExtensions[0] == 0)
994       lstrcatW(lp[i].szExtensions, szValue + 1);
995     else
996       lstrcatW(lp[i].szExtensions, szValue);
997
998     /* also append to the "all multimedia"-filter */
999     if (lp[0].szExtensions[0] == 0)
1000       lstrcatW(lp[0].szExtensions, szValue + 1);
1001     else
1002       lstrcatW(lp[0].szExtensions, szValue);
1003   }
1004   RegCloseKey(hKey);
1005
1006   /* 2. get descriptions for the CLSIDs and fill out szFilter */
1007   if (RegOpenKeyW(HKEY_CLASSES_ROOT, szClsid, &hKey) != S_OK) {
1008     GlobalFreePtr(lp);
1009     return AVIERR_ERROR;
1010   }
1011   for (n = 0; n <= count; n++) {
1012     /* first the description */
1013     if (n != 0) {
1014       size = sizeof(szValue)/sizeof(szValue[0]);
1015       if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == S_OK) {
1016         size = lstrlenW(szValue);
1017         lstrcpynW(szFilter, szValue, cbFilter);
1018       }
1019     } else
1020       size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter);
1021
1022     /* check for enough space */
1023     size++;
1024     if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) {
1025       szFilter[0] = 0;
1026       szFilter[1] = 0;
1027       GlobalFreePtr(lp);
1028       RegCloseKey(hKey);
1029       return AVIERR_BUFFERTOOSMALL;
1030     }
1031     cbFilter -= size;
1032     szFilter += size;
1033
1034     /* and then the filter */
1035     lstrcpynW(szFilter, lp[n].szExtensions, cbFilter);
1036     size = lstrlenW(lp[n].szExtensions) + 1;
1037     cbFilter -= size;
1038     szFilter += size;
1039   }
1040
1041   RegCloseKey(hKey);
1042   GlobalFreePtr(lp);
1043
1044   /* add "All files" "*.*" filter if enough space left */
1045   size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES,
1046                      szAllFiles, sizeof(szAllFiles)) + 1;
1047   if (cbFilter > size) {
1048     int i;
1049
1050     /* replace '@' with \000 to separate description of filter */
1051     for (i = 0; i < size && szAllFiles[i] != 0; i++) {
1052       if (szAllFiles[i] == '@') {
1053         szAllFiles[i] = 0;
1054         break;
1055       }
1056     }
1057       
1058     memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0]));
1059     szFilter += size;
1060     szFilter[0] = 0;
1061
1062     return AVIERR_OK;
1063   } else {
1064     szFilter[0] = 0;
1065     return AVIERR_BUFFERTOOSMALL;
1066   }
1067 }
1068
1069 static BOOL AVISaveOptionsFmtChoose(HWND hWnd)
1070 {
1071   LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent];
1072   AVISTREAMINFOW       sInfo;
1073
1074   TRACE("(%p)\n", hWnd);
1075
1076   if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) {
1077     ERR(": bad state!\n");
1078     return FALSE;
1079   }
1080
1081   if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent],
1082                             &sInfo, sizeof(sInfo)))) {
1083     ERR(": AVIStreamInfoW failed!\n");
1084     return FALSE;
1085   }
1086
1087   if (sInfo.fccType == streamtypeVIDEO) {
1088     COMPVARS cv;
1089     BOOL     ret;
1090
1091     memset(&cv, 0, sizeof(cv));
1092
1093     if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) {
1094       memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS));
1095       pOptions->fccType    = streamtypeVIDEO;
1096       pOptions->fccHandler = comptypeDIB;
1097       pOptions->dwQuality  = ICQUALITY_DEFAULT;
1098     }
1099
1100     cv.cbSize     = sizeof(cv);
1101     cv.dwFlags    = ICMF_COMPVARS_VALID;
1102     /*cv.fccType    = pOptions->fccType; */
1103     cv.fccHandler = pOptions->fccHandler;
1104     cv.lQ         = pOptions->dwQuality;
1105     cv.lpState    = pOptions->lpParms;
1106     cv.cbState    = pOptions->cbParms;
1107     if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES)
1108       cv.lKey = pOptions->dwKeyFrameEvery;
1109     else
1110       cv.lKey = 0;
1111     if (pOptions->dwFlags & AVICOMPRESSF_DATARATE)
1112       cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */
1113     else
1114       cv.lDataRate = 0;
1115
1116     ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL,
1117                              SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL);
1118
1119     if (ret) {
1120       pOptions->lpParms   = cv.lpState;
1121       pOptions->cbParms   = cv.cbState;
1122       pOptions->dwQuality = cv.lQ;
1123       if (cv.lKey != 0) {
1124         pOptions->dwKeyFrameEvery = cv.lKey;
1125         pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES;
1126       } else
1127         pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES;
1128       if (cv.lDataRate != 0) {
1129         pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */
1130         pOptions->dwFlags |= AVICOMPRESSF_DATARATE;
1131       } else
1132         pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE;
1133       pOptions->dwFlags  |= AVICOMPRESSF_VALID;
1134     }
1135     ICCompressorFree(&cv);
1136
1137     return ret;
1138   } else if (sInfo.fccType == streamtypeAUDIO) {
1139     ACMFORMATCHOOSEW afmtc;
1140     MMRESULT         ret;
1141     LONG             size;
1142
1143     /* FIXME: check ACM version -- Which version is needed? */
1144
1145     memset(&afmtc, 0, sizeof(afmtc));
1146     afmtc.cbStruct  = sizeof(afmtc);
1147     afmtc.fdwStyle  = 0;
1148     afmtc.hwndOwner = hWnd;
1149
1150     acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size);
1151     if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) {
1152       pOptions->lpFormat = GlobalAllocPtr(GMEM_MOVEABLE, size);
1153       pOptions->cbFormat = size;
1154     } else if (pOptions->cbFormat < size) {
1155       pOptions->lpFormat = GlobalReAllocPtr(pOptions->lpFormat, size, GMEM_MOVEABLE);
1156       pOptions->cbFormat = size;
1157     }
1158     if (pOptions->lpFormat == NULL)
1159       return FALSE;
1160     afmtc.pwfx  = pOptions->lpFormat;
1161     afmtc.cbwfx = pOptions->cbFormat;
1162
1163     size = 0;
1164     AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],
1165                         sInfo.dwStart, &size);
1166     if (size < sizeof(PCMWAVEFORMAT))
1167       size = sizeof(PCMWAVEFORMAT);
1168     afmtc.pwfxEnum = GlobalAllocPtr(GHND, size);
1169     if (afmtc.pwfxEnum != NULL) {
1170       AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],
1171                           sInfo.dwStart, afmtc.pwfxEnum, &size);
1172       afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT;
1173     }
1174
1175     ret = acmFormatChooseW(&afmtc);
1176     if (ret == S_OK)
1177       pOptions->dwFlags |= AVICOMPRESSF_VALID;
1178
1179     if (afmtc.pwfxEnum != NULL)
1180       GlobalFreePtr(afmtc.pwfxEnum);
1181
1182     return (ret == S_OK ? TRUE : FALSE);
1183   } else {
1184     ERR(": unknown streamtype 0x%08lX\n", sInfo.fccType);
1185     return FALSE;
1186   }
1187 }
1188
1189 static void AVISaveOptionsUpdate(HWND hWnd)
1190 {
1191   static const WCHAR szVideoFmt[]={'%','l','d','x','%','l','d','x','%','d',0};
1192   static const WCHAR szAudioFmt[]={'%','s',' ','%','s',0};
1193
1194   WCHAR          szFormat[128];
1195   AVISTREAMINFOW sInfo;
1196   LPVOID         lpFormat;
1197   LONG           size;
1198
1199   TRACE("(%p)\n", hWnd);
1200
1201   SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0);
1202   if (SaveOpts.nCurrent < 0)
1203     return;
1204
1205   if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo))))
1206     return;
1207
1208   AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size);
1209   if (size > 0) {
1210     szFormat[0] = 0;
1211
1212     /* read format to build format descriotion string */
1213     lpFormat = GlobalAllocPtr(GHND, size);
1214     if (lpFormat != NULL) {
1215       if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) {
1216         if (sInfo.fccType == streamtypeVIDEO) {
1217           LPBITMAPINFOHEADER lpbi = lpFormat;
1218           ICINFO icinfo;
1219
1220           wsprintfW(szFormat, szVideoFmt, lpbi->biWidth,
1221                     lpbi->biHeight, lpbi->biBitCount);
1222
1223           if (lpbi->biCompression != BI_RGB) {
1224             HIC    hic;
1225
1226             hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat,
1227                            NULL, ICMODE_DECOMPRESS);
1228             if (hic != NULL) {
1229               if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK)
1230                 lstrcatW(szFormat, icinfo.szDescription);
1231               ICClose(hic);
1232             }
1233           } else {
1234             LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED,
1235                         icinfo.szDescription, sizeof(icinfo.szDescription));
1236             lstrcatW(szFormat, icinfo.szDescription);
1237           }
1238         } else if (sInfo.fccType == streamtypeAUDIO) {
1239           ACMFORMATTAGDETAILSW aftd;
1240           ACMFORMATDETAILSW    afd;
1241
1242           memset(&aftd, 0, sizeof(aftd));
1243           memset(&afd, 0, sizeof(afd));
1244
1245           aftd.cbStruct     = sizeof(aftd);
1246           aftd.dwFormatTag  = afd.dwFormatTag =
1247             ((PWAVEFORMATEX)lpFormat)->wFormatTag;
1248           aftd.cbFormatSize = afd.cbwfx = size;
1249
1250           afd.cbStruct      = sizeof(afd);
1251           afd.pwfx          = lpFormat;
1252
1253           if (acmFormatTagDetailsW(NULL, &aftd,
1254                                    ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) {
1255             if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK)
1256               wsprintfW(szFormat, szAudioFmt, afd.szFormat, aftd.szFormatTag);
1257           }
1258         }
1259       }
1260       GlobalFreePtr(lpFormat);
1261     }
1262
1263     /* set text for format description */
1264     SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat);
1265
1266     /* Disable option button for unsupported streamtypes */
1267     if (sInfo.fccType == streamtypeVIDEO ||
1268         sInfo.fccType == streamtypeAUDIO)
1269       EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE);
1270     else
1271       EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE);
1272   }
1273
1274 }
1275
1276 INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg,
1277                                     WPARAM wParam, LPARAM lParam)
1278 {
1279   DWORD dwInterleave;
1280   BOOL  bIsInterleaved;
1281   INT   n;
1282
1283   /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/
1284
1285   switch (uMsg) {
1286   case WM_INITDIALOG:
1287     SaveOpts.nCurrent = 0;
1288     if (SaveOpts.nStreams == 1) {
1289       EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd));
1290       return FALSE;
1291     }
1292
1293     /* add streams */
1294     for (n = 0; n < SaveOpts.nStreams; n++) {
1295       AVISTREAMINFOW sInfo;
1296
1297       AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo));
1298       SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING,
1299                           0L, (LPARAM)sInfo.szName);
1300     }
1301
1302     /* select first stream */
1303     SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0);
1304     SendMessageW(hWnd, WM_COMMAND,
1305                  GET_WM_COMMAND_MPS(IDC_STREAM, hWnd, CBN_SELCHANGE));
1306
1307     /* initialize interleave */
1308     if (SaveOpts.ppOptions[0] != NULL &&
1309         (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_VALID)) {
1310       bIsInterleaved = (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_INTERLEAVE);
1311       dwInterleave = SaveOpts.ppOptions[0]->dwInterleaveEvery;
1312     } else {
1313       bIsInterleaved = TRUE;
1314       dwInterleave   = 0;
1315     }
1316     CheckDlgButton(hWnd, IDC_INTERLEAVE, bIsInterleaved);
1317     SetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, dwInterleave, FALSE);
1318     EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), bIsInterleaved);
1319     break;
1320   case WM_COMMAND:
1321     switch (GET_WM_COMMAND_CMD(wParam, lParam)) {
1322     case IDOK:
1323       /* get data from controls and save them */
1324       dwInterleave   = GetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, NULL, 0);
1325       bIsInterleaved = IsDlgButtonChecked(hWnd, IDC_INTERLEAVE);
1326       for (n = 0; n < SaveOpts.nStreams; n++) {
1327         if (SaveOpts.ppOptions[n] != NULL) {
1328           if (bIsInterleaved) {
1329             SaveOpts.ppOptions[n]->dwFlags |= AVICOMPRESSF_INTERLEAVE;
1330             SaveOpts.ppOptions[n]->dwInterleaveEvery = dwInterleave;
1331           } else
1332             SaveOpts.ppOptions[n]->dwFlags &= ~AVICOMPRESSF_INTERLEAVE;
1333         }
1334       }
1335       /* fall through */
1336     case IDCANCEL:
1337       EndDialog(hWnd, GET_WM_COMMAND_CMD(wParam, lParam) == IDOK);
1338       break;
1339     case IDC_INTERLEAVE:
1340       EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY),
1341                    IsDlgButtonChecked(hWnd, IDC_INTERLEAVE));
1342       break;
1343     case IDC_STREAM:
1344       if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) {
1345         /* update control elements */
1346         AVISaveOptionsUpdate(hWnd);
1347       }
1348       break;
1349     case IDC_OPTIONS:
1350       AVISaveOptionsFmtChoose(hWnd);
1351       break;
1352     };
1353     return FALSE;
1354   };
1355
1356   return TRUE;
1357 }
1358
1359 /***********************************************************************
1360  *              AVISaveOptions          (AVIFIL32.@)
1361  */
1362 BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams,
1363                            PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions)
1364 {
1365   LPAVICOMPRESSOPTIONS pSavedOptions = NULL;
1366   INT ret, n;
1367
1368   TRACE("(%p,0x%X,%d,%p,%p)\n", hWnd, uFlags, nStreams,
1369         ppavi, ppOptions);
1370
1371   /* check parameters */
1372   if (nStreams <= 0 || ppavi == NULL || ppOptions == NULL)
1373     return AVIERR_BADPARAM;
1374
1375   /* save options for case user press cancel */
1376   if (ppOptions != NULL && nStreams > 1) {
1377     pSavedOptions = GlobalAllocPtr(GHND,nStreams * sizeof(AVICOMPRESSOPTIONS));
1378     if (pSavedOptions == NULL)
1379       return FALSE;
1380
1381     for (n = 0; n < nStreams; n++) {
1382       if (ppOptions[n] != NULL)
1383         memcpy(pSavedOptions + n, ppOptions[n], sizeof(AVICOMPRESSOPTIONS));
1384     }
1385   }
1386
1387   SaveOpts.uFlags    = uFlags;
1388   SaveOpts.nStreams  = nStreams;
1389   SaveOpts.ppavis    = ppavi;
1390   SaveOpts.ppOptions = ppOptions;
1391
1392   ret = DialogBoxW(AVIFILE_hModule, MAKEINTRESOURCEW(IDD_SAVEOPTIONS),
1393                    hWnd, AVISaveOptionsDlgProc);
1394
1395   if (ret == -1)
1396     ret = FALSE;
1397
1398   /* restore options when user pressed cancel */
1399   if (pSavedOptions != NULL && ret == FALSE) {
1400     for (n = 0; n < nStreams; n++) {
1401       if (ppOptions[n] != NULL)
1402         memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS));
1403     }
1404     GlobalFreePtr(pSavedOptions);
1405   }
1406
1407   return (BOOL)ret;
1408 }
1409
1410 /***********************************************************************
1411  *              AVISaveOptionsFree      (AVIFIL32.@)
1412  */
1413 HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions)
1414 {
1415   TRACE("(%d,%p)\n", nStreams, ppOptions);
1416
1417   if (nStreams < 0 || ppOptions == NULL)
1418     return AVIERR_BADPARAM;
1419
1420   for (; nStreams > 0; nStreams--) {
1421     if (ppOptions[nStreams] != NULL) {
1422       ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID;
1423
1424       if (ppOptions[nStreams]->lpParms != NULL) {
1425         GlobalFreePtr(ppOptions[nStreams]->lpParms);
1426         ppOptions[nStreams]->lpParms = NULL;
1427         ppOptions[nStreams]->cbParms = 0;
1428       }
1429       if (ppOptions[nStreams]->lpFormat != NULL) {
1430         GlobalFreePtr(ppOptions[nStreams]->lpFormat);
1431         ppOptions[nStreams]->lpFormat = NULL;
1432         ppOptions[nStreams]->cbFormat = 0;
1433       }
1434     }
1435   }
1436
1437   return AVIERR_OK;
1438 }