|  | /* | 
|  | * Copyright 1999 Marcus Meissner | 
|  | * Copyright 2002-2003 Michael Günnewig | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include <stdarg.h> | 
|  |  | 
|  | #define COBJMACROS | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winnls.h" | 
|  | #include "wingdi.h" | 
|  | #include "winuser.h" | 
|  | #include "winreg.h" | 
|  | #include "winerror.h" | 
|  |  | 
|  | #include "ole2.h" | 
|  | #include "shellapi.h" | 
|  | #include "shlobj.h" | 
|  | #include "vfw.h" | 
|  | #include "msacm.h" | 
|  |  | 
|  | #include "avifile_private.h" | 
|  |  | 
|  | #include "wine/debug.h" | 
|  | #include "wine/unicode.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(avifile); | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | * for AVIBuildFilterW -- uses fixed size table | 
|  | */ | 
|  | #define MAX_FILTERS 30 /* 30 => 7kB */ | 
|  |  | 
|  | typedef struct _AVIFilter { | 
|  | WCHAR szClsid[40]; | 
|  | WCHAR szExtensions[MAX_FILTERS * 7]; | 
|  | } AVIFilter; | 
|  |  | 
|  | /*********************************************************************** | 
|  | * for AVISaveOptions | 
|  | */ | 
|  | static struct { | 
|  | UINT                  uFlags; | 
|  | INT                   nStreams; | 
|  | PAVISTREAM           *ppavis; | 
|  | LPAVICOMPRESSOPTIONS *ppOptions; | 
|  | INT                   nCurrent; | 
|  | } SaveOpts; | 
|  |  | 
|  | /*********************************************************************** | 
|  | * copied from dlls/ole32/compobj.c | 
|  | */ | 
|  | static HRESULT AVIFILE_CLSIDFromString(LPCSTR idstr, LPCLSID id) | 
|  | { | 
|  | BYTE const *s; | 
|  | BYTE *p; | 
|  | INT   i; | 
|  | BYTE table[256]; | 
|  |  | 
|  | if (!idstr) { | 
|  | memset(id, 0, sizeof(CLSID)); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /* validate the CLSID string */ | 
|  | if (lstrlenA(idstr) != 38) | 
|  | return CO_E_CLASSSTRING; | 
|  |  | 
|  | s = (BYTE const*)idstr; | 
|  | if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || | 
|  | (s[24]!='-') || (s[37]!='}')) | 
|  | return CO_E_CLASSSTRING; | 
|  |  | 
|  | for (i = 1; i < 37; i++) { | 
|  | if ((i == 9) || (i == 14) || (i == 19) || (i == 24)) | 
|  | continue; | 
|  | if (!(((s[i] >= '0') && (s[i] <= '9'))  || | 
|  | ((s[i] >= 'a') && (s[i] <= 'f'))  || | 
|  | ((s[i] >= 'A') && (s[i] <= 'F'))) | 
|  | ) | 
|  | return CO_E_CLASSSTRING; | 
|  | } | 
|  |  | 
|  | TRACE("%s -> %p\n", s, id); | 
|  |  | 
|  | /* quick lookup table */ | 
|  | memset(table, 0, 256); | 
|  |  | 
|  | for (i = 0; i < 10; i++) | 
|  | table['0' + i] = i; | 
|  |  | 
|  | for (i = 0; i < 6; i++) { | 
|  | table['A' + i] = i+10; | 
|  | table['a' + i] = i+10; | 
|  | } | 
|  |  | 
|  | /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */ | 
|  | p = (BYTE *) id; | 
|  |  | 
|  | s++;	/* skip leading brace  */ | 
|  | for (i = 0; i < 4; i++) { | 
|  | p[3 - i] = table[*s]<<4 | table[*(s+1)]; | 
|  | s += 2; | 
|  | } | 
|  | p += 4; | 
|  | s++;	/* skip - */ | 
|  |  | 
|  | for (i = 0; i < 2; i++) { | 
|  | p[1-i] = table[*s]<<4 | table[*(s+1)]; | 
|  | s += 2; | 
|  | } | 
|  | p += 2; | 
|  | s++;	/* skip - */ | 
|  |  | 
|  | for (i = 0; i < 2; i++) { | 
|  | p[1-i] = table[*s]<<4 | table[*(s+1)]; | 
|  | s += 2; | 
|  | } | 
|  | p += 2; | 
|  | s++;	/* skip - */ | 
|  |  | 
|  | /* these are just sequential bytes */ | 
|  | for (i = 0; i < 2; i++) { | 
|  | *p++ = table[*s]<<4 | table[*(s+1)]; | 
|  | s += 2; | 
|  | } | 
|  | s++;	/* skip - */ | 
|  |  | 
|  | for (i = 0; i < 6; i++) { | 
|  | *p++ = table[*s]<<4 | table[*(s+1)]; | 
|  | s += 2; | 
|  | } | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static BOOL AVIFILE_GetFileHandlerByExtension(LPCWSTR szFile, LPCLSID lpclsid) | 
|  | { | 
|  | CHAR   szRegKey[25]; | 
|  | CHAR   szValue[100]; | 
|  | LPWSTR szExt = strrchrW(szFile, '.'); | 
|  | LONG   len = sizeof(szValue) / sizeof(szValue[0]); | 
|  |  | 
|  | if (szExt == NULL) | 
|  | return FALSE; | 
|  |  | 
|  | szExt++; | 
|  |  | 
|  | wsprintfA(szRegKey, "AVIFile\\Extensions\\%.3ls", szExt); | 
|  | if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &len) != ERROR_SUCCESS) | 
|  | return FALSE; | 
|  |  | 
|  | return (AVIFILE_CLSIDFromString(szValue, lpclsid) == S_OK); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIFileInit		(AVIFIL32.@) | 
|  | */ | 
|  | void WINAPI AVIFileInit(void) { | 
|  | OleInitialize(NULL); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIFileExit		(AVIFIL32.@) | 
|  | */ | 
|  | void WINAPI AVIFileExit(void) { | 
|  | /* need to free ole32.dll if we are the last exit call */ | 
|  | /* OleUninitialize() */ | 
|  | FIXME("(): stub!\n"); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIFileOpen		(AVIFIL32.@) | 
|  | *		AVIFileOpenA		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIFileOpenA(PAVIFILE *ppfile, LPCSTR szFile, UINT uMode, | 
|  | LPCLSID lpHandler) | 
|  | { | 
|  | LPWSTR  wszFile = NULL; | 
|  | HRESULT hr; | 
|  | int     len; | 
|  |  | 
|  | TRACE("(%p,%s,0x%08X,%s)\n", ppfile, debugstr_a(szFile), uMode, | 
|  | debugstr_guid(lpHandler)); | 
|  |  | 
|  | /* check parameters */ | 
|  | if (ppfile == NULL || szFile == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | /* convert ASCII string to Unicode and call unicode function */ | 
|  | len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0); | 
|  | if (len <= 0) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | wszFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); | 
|  | if (wszFile == NULL) | 
|  | return AVIERR_MEMORY; | 
|  |  | 
|  | MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len); | 
|  |  | 
|  | hr = AVIFileOpenW(ppfile, wszFile, uMode, lpHandler); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, wszFile); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIFileOpenW		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIFileOpenW(PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode, | 
|  | LPCLSID lpHandler) | 
|  | { | 
|  | IPersistFile *ppersist = NULL; | 
|  | CLSID         clsidHandler; | 
|  | HRESULT       hr; | 
|  |  | 
|  | TRACE("(%p,%s,0x%X,%s)\n", ppfile, debugstr_w(szFile), uMode, | 
|  | debugstr_guid(lpHandler)); | 
|  |  | 
|  | /* check parameters */ | 
|  | if (ppfile == NULL || szFile == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | *ppfile = NULL; | 
|  |  | 
|  | /* if no handler then try guessing it by extension */ | 
|  | if (lpHandler == NULL) { | 
|  | if (! AVIFILE_GetFileHandlerByExtension(szFile, &clsidHandler)) | 
|  | clsidHandler = CLSID_AVIFile; | 
|  | } else | 
|  | clsidHandler = *lpHandler; | 
|  |  | 
|  | /* create instance of handler */ | 
|  | hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIFile, (LPVOID*)ppfile); | 
|  | if (FAILED(hr) || *ppfile == NULL) | 
|  | return hr; | 
|  |  | 
|  | /* ask for IPersistFile interface for loading/creating the file */ | 
|  | hr = IAVIFile_QueryInterface(*ppfile, &IID_IPersistFile, (LPVOID*)&ppersist); | 
|  | if (FAILED(hr) || ppersist == NULL) { | 
|  | IAVIFile_Release(*ppfile); | 
|  | *ppfile = NULL; | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | hr = IPersistFile_Load(ppersist, szFile, uMode); | 
|  | IPersistFile_Release(ppersist); | 
|  | if (FAILED(hr)) { | 
|  | IAVIFile_Release(*ppfile); | 
|  | *ppfile = NULL; | 
|  | } | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIFileAddRef		(AVIFIL32.@) | 
|  | */ | 
|  | ULONG WINAPI AVIFileAddRef(PAVIFILE pfile) | 
|  | { | 
|  | TRACE("(%p)\n", pfile); | 
|  |  | 
|  | if (pfile == NULL) { | 
|  | ERR(": bad handle passed!\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return IAVIFile_AddRef(pfile); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIFileRelease		(AVIFIL32.@) | 
|  | */ | 
|  | ULONG WINAPI AVIFileRelease(PAVIFILE pfile) | 
|  | { | 
|  | TRACE("(%p)\n", pfile); | 
|  |  | 
|  | if (pfile == NULL) { | 
|  | ERR(": bad handle passed!\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return IAVIFile_Release(pfile); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIFileInfo		(AVIFIL32.@) | 
|  | *		AVIFileInfoA		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIFileInfoA(PAVIFILE pfile, LPAVIFILEINFOA afi, LONG size) | 
|  | { | 
|  | AVIFILEINFOW afiw; | 
|  | HRESULT      hres; | 
|  |  | 
|  | TRACE("(%p,%p,%d)\n", pfile, afi, size); | 
|  |  | 
|  | if (pfile == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  | if ((DWORD)size < sizeof(AVIFILEINFOA)) | 
|  | return AVIERR_BADSIZE; | 
|  |  | 
|  | hres = IAVIFile_Info(pfile, &afiw, sizeof(afiw)); | 
|  |  | 
|  | memcpy(afi, &afiw, sizeof(*afi) - sizeof(afi->szFileType)); | 
|  | WideCharToMultiByte(CP_ACP, 0, afiw.szFileType, -1, afi->szFileType, | 
|  | sizeof(afi->szFileType), NULL, NULL); | 
|  | afi->szFileType[sizeof(afi->szFileType) - 1] = 0; | 
|  |  | 
|  | return hres; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIFileInfoW		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIFileInfoW(PAVIFILE pfile, LPAVIFILEINFOW afiw, LONG size) | 
|  | { | 
|  | TRACE("(%p,%p,%d)\n", pfile, afiw, size); | 
|  |  | 
|  | if (pfile == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | return IAVIFile_Info(pfile, afiw, size); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIFileGetStream	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIFileGetStream(PAVIFILE pfile, PAVISTREAM *avis, | 
|  | DWORD fccType, LONG lParam) | 
|  | { | 
|  | TRACE("(%p,%p,'%4.4s',%d)\n", pfile, avis, (char*)&fccType, lParam); | 
|  |  | 
|  | if (pfile == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | return IAVIFile_GetStream(pfile, avis, fccType, lParam); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIFileCreateStream	(AVIFIL32.@) | 
|  | *		AVIFileCreateStreamA	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE pfile, PAVISTREAM *ppavi, | 
|  | LPAVISTREAMINFOA psi) | 
|  | { | 
|  | AVISTREAMINFOW	psiw; | 
|  |  | 
|  | TRACE("(%p,%p,%p)\n", pfile, ppavi, psi); | 
|  |  | 
|  | if (pfile == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | /* Only the szName at the end is different */ | 
|  | memcpy(&psiw, psi, sizeof(*psi) - sizeof(psi->szName)); | 
|  | MultiByteToWideChar(CP_ACP, 0, psi->szName, -1, psiw.szName, | 
|  | sizeof(psiw.szName) / sizeof(psiw.szName[0])); | 
|  |  | 
|  | return IAVIFile_CreateStream(pfile, ppavi, &psiw); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIFileCreateStreamW	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIFileCreateStreamW(PAVIFILE pfile, PAVISTREAM *avis, | 
|  | LPAVISTREAMINFOW asi) | 
|  | { | 
|  | TRACE("(%p,%p,%p)\n", pfile, avis, asi); | 
|  |  | 
|  | if (pfile == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | return IAVIFile_CreateStream(pfile, avis, asi); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIFileWriteData	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIFileWriteData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LONG size) | 
|  | { | 
|  | TRACE("(%p,'%4.4s',%p,%d)\n", pfile, (char*)&fcc, lp, size); | 
|  |  | 
|  | if (pfile == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | return IAVIFile_WriteData(pfile, fcc, lp, size); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIFileReadData		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIFileReadData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LPLONG size) | 
|  | { | 
|  | TRACE("(%p,'%4.4s',%p,%p)\n", pfile, (char*)&fcc, lp, size); | 
|  |  | 
|  | if (pfile == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | return IAVIFile_ReadData(pfile, fcc, lp, size); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIFileEndRecord	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIFileEndRecord(PAVIFILE pfile) | 
|  | { | 
|  | TRACE("(%p)\n", pfile); | 
|  |  | 
|  | if (pfile == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | return IAVIFile_EndRecord(pfile); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamAddRef		(AVIFIL32.@) | 
|  | */ | 
|  | ULONG WINAPI AVIStreamAddRef(PAVISTREAM pstream) | 
|  | { | 
|  | TRACE("(%p)\n", pstream); | 
|  |  | 
|  | if (pstream == NULL) { | 
|  | ERR(": bad handle passed!\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return IAVIStream_AddRef(pstream); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamRelease	(AVIFIL32.@) | 
|  | */ | 
|  | ULONG WINAPI AVIStreamRelease(PAVISTREAM pstream) | 
|  | { | 
|  | TRACE("(%p)\n", pstream); | 
|  |  | 
|  | if (pstream == NULL) { | 
|  | ERR(": bad handle passed!\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return IAVIStream_Release(pstream); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamCreate		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIStreamCreate(PAVISTREAM *ppavi, LONG lParam1, LONG lParam2, | 
|  | LPCLSID pclsidHandler) | 
|  | { | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p,0x%08X,0x%08X,%s)\n", ppavi, lParam1, lParam2, | 
|  | debugstr_guid(pclsidHandler)); | 
|  |  | 
|  | if (ppavi == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | *ppavi = NULL; | 
|  | if (pclsidHandler == NULL) | 
|  | return AVIERR_UNSUPPORTED; | 
|  |  | 
|  | hr = CoCreateInstance(pclsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppavi); | 
|  | if (FAILED(hr) || *ppavi == NULL) | 
|  | return hr; | 
|  |  | 
|  | hr = IAVIStream_Create(*ppavi, lParam1, lParam2); | 
|  | if (FAILED(hr)) { | 
|  | IAVIStream_Release(*ppavi); | 
|  | *ppavi = NULL; | 
|  | } | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamInfo		(AVIFIL32.@) | 
|  | *		AVIStreamInfoA		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIStreamInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi, | 
|  | LONG size) | 
|  | { | 
|  | AVISTREAMINFOW asiw; | 
|  | HRESULT	 hres; | 
|  |  | 
|  | TRACE("(%p,%p,%d)\n", pstream, asi, size); | 
|  |  | 
|  | if (pstream == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  | if ((DWORD)size < sizeof(AVISTREAMINFOA)) | 
|  | return AVIERR_BADSIZE; | 
|  |  | 
|  | hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw)); | 
|  |  | 
|  | memcpy(asi, &asiw, sizeof(asiw) - sizeof(asiw.szName)); | 
|  | WideCharToMultiByte(CP_ACP, 0, asiw.szName, -1, asi->szName, | 
|  | sizeof(asi->szName), NULL, NULL); | 
|  | asi->szName[sizeof(asi->szName) - 1] = 0; | 
|  |  | 
|  | return hres; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamInfoW		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIStreamInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi, | 
|  | LONG size) | 
|  | { | 
|  | TRACE("(%p,%p,%d)\n", pstream, asi, size); | 
|  |  | 
|  | if (pstream == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | return IAVIStream_Info(pstream, asi, size); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamFindSample	(AVIFIL32.@) | 
|  | */ | 
|  | LONG WINAPI AVIStreamFindSample(PAVISTREAM pstream, LONG pos, LONG flags) | 
|  | { | 
|  | TRACE("(%p,%d,0x%X)\n", pstream, pos, flags); | 
|  |  | 
|  | if (pstream == NULL) | 
|  | return -1; | 
|  |  | 
|  | return IAVIStream_FindSample(pstream, pos, flags); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamReadFormat	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM pstream, LONG pos, | 
|  | LPVOID format, LPLONG formatsize) | 
|  | { | 
|  | TRACE("(%p,%d,%p,%p)\n", pstream, pos, format, formatsize); | 
|  |  | 
|  | if (pstream == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | return IAVIStream_ReadFormat(pstream, pos, format, formatsize); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamSetFormat	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM pstream, LONG pos, | 
|  | LPVOID format, LONG formatsize) | 
|  | { | 
|  | TRACE("(%p,%d,%p,%d)\n", pstream, pos, format, formatsize); | 
|  |  | 
|  | if (pstream == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | return IAVIStream_SetFormat(pstream, pos, format, formatsize); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamRead		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIStreamRead(PAVISTREAM pstream, LONG start, LONG samples, | 
|  | LPVOID buffer, LONG buffersize, | 
|  | LPLONG bytesread, LPLONG samplesread) | 
|  | { | 
|  | TRACE("(%p,%d,%d,%p,%d,%p,%p)\n", pstream, start, samples, buffer, | 
|  | buffersize, bytesread, samplesread); | 
|  |  | 
|  | if (pstream == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | return IAVIStream_Read(pstream, start, samples, buffer, buffersize, | 
|  | bytesread, samplesread); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamWrite		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIStreamWrite(PAVISTREAM pstream, LONG start, LONG samples, | 
|  | LPVOID buffer, LONG buffersize, DWORD flags, | 
|  | LPLONG sampwritten, LPLONG byteswritten) | 
|  | { | 
|  | TRACE("(%p,%d,%d,%p,%d,0x%X,%p,%p)\n", pstream, start, samples, buffer, | 
|  | buffersize, flags, sampwritten, byteswritten); | 
|  |  | 
|  | if (pstream == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | return IAVIStream_Write(pstream, start, samples, buffer, buffersize, | 
|  | flags, sampwritten, byteswritten); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamReadData	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIStreamReadData(PAVISTREAM pstream, DWORD fcc, LPVOID lp, | 
|  | LPLONG lpread) | 
|  | { | 
|  | TRACE("(%p,'%4.4s',%p,%p)\n", pstream, (char*)&fcc, lp, lpread); | 
|  |  | 
|  | if (pstream == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | return IAVIStream_ReadData(pstream, fcc, lp, lpread); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamWriteData	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIStreamWriteData(PAVISTREAM pstream, DWORD fcc, LPVOID lp, | 
|  | LONG size) | 
|  | { | 
|  | TRACE("(%p,'%4.4s',%p,%d)\n", pstream, (char*)&fcc, lp, size); | 
|  |  | 
|  | if (pstream == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | return IAVIStream_WriteData(pstream, fcc, lp, size); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamGetFrameOpen	(AVIFIL32.@) | 
|  | */ | 
|  | PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream, | 
|  | LPBITMAPINFOHEADER lpbiWanted) | 
|  | { | 
|  | PGETFRAME pg = NULL; | 
|  |  | 
|  | TRACE("(%p,%p)\n", pstream, lpbiWanted); | 
|  |  | 
|  | if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) || | 
|  | pg == NULL) { | 
|  | pg = AVIFILE_CreateGetFrame(pstream); | 
|  | if (pg == NULL) | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) { | 
|  | IGetFrame_Release(pg); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return pg; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamGetFrame	(AVIFIL32.@) | 
|  | */ | 
|  | LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos) | 
|  | { | 
|  | TRACE("(%p,%d)\n", pg, pos); | 
|  |  | 
|  | if (pg == NULL) | 
|  | return NULL; | 
|  |  | 
|  | return IGetFrame_GetFrame(pg, pos); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamGetFrameClose	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg) | 
|  | { | 
|  | TRACE("(%p)\n", pg); | 
|  |  | 
|  | if (pg != NULL) | 
|  | return IGetFrame_Release(pg); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIMakeCompressedStream	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed, | 
|  | PAVISTREAM psSource, | 
|  | LPAVICOMPRESSOPTIONS aco, | 
|  | LPCLSID pclsidHandler) | 
|  | { | 
|  | AVISTREAMINFOW asiw; | 
|  | CHAR           szRegKey[25]; | 
|  | CHAR           szValue[100]; | 
|  | CLSID          clsidHandler; | 
|  | HRESULT        hr; | 
|  | LONG           size = sizeof(szValue); | 
|  |  | 
|  | TRACE("(%p,%p,%p,%s)\n", ppsCompressed, psSource, aco, | 
|  | debugstr_guid(pclsidHandler)); | 
|  |  | 
|  | if (ppsCompressed == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  | if (psSource == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | *ppsCompressed = NULL; | 
|  |  | 
|  | /* if no handler given get default ones based on streamtype */ | 
|  | if (pclsidHandler == NULL) { | 
|  | hr = IAVIStream_Info(psSource, &asiw, sizeof(asiw)); | 
|  | if (FAILED(hr)) | 
|  | return hr; | 
|  |  | 
|  | wsprintfA(szRegKey, "AVIFile\\Compressors\\%4.4s", (char*)&asiw.fccType); | 
|  | if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &size) != ERROR_SUCCESS) | 
|  | return AVIERR_UNSUPPORTED; | 
|  | if (AVIFILE_CLSIDFromString(szValue, &clsidHandler) != S_OK) | 
|  | return AVIERR_UNSUPPORTED; | 
|  | } else | 
|  | clsidHandler = *pclsidHandler; | 
|  |  | 
|  | hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppsCompressed); | 
|  | if (FAILED(hr) || *ppsCompressed == NULL) | 
|  | return hr; | 
|  |  | 
|  | hr = IAVIStream_Create(*ppsCompressed, (LPARAM)psSource, (LPARAM)aco); | 
|  | if (FAILED(hr)) { | 
|  | IAVIStream_Release(*ppsCompressed); | 
|  | *ppsCompressed = NULL; | 
|  | } | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIMakeFileFromStreams	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIMakeFileFromStreams(PAVIFILE *ppfile, int nStreams, | 
|  | PAVISTREAM *ppStreams) | 
|  | { | 
|  | TRACE("(%p,%d,%p)\n", ppfile, nStreams, ppStreams); | 
|  |  | 
|  | if (nStreams < 0 || ppfile == NULL || ppStreams == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | *ppfile = AVIFILE_CreateAVITempFile(nStreams, ppStreams); | 
|  | if (*ppfile == NULL) | 
|  | return AVIERR_MEMORY; | 
|  |  | 
|  | return AVIERR_OK; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamOpenFromFile	(AVIFIL32.@) | 
|  | *		AVIStreamOpenFromFileA	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIStreamOpenFromFileA(PAVISTREAM *ppavi, LPCSTR szFile, | 
|  | DWORD fccType, LONG lParam, | 
|  | UINT mode, LPCLSID pclsidHandler) | 
|  | { | 
|  | PAVIFILE pfile = NULL; | 
|  | HRESULT  hr; | 
|  |  | 
|  | TRACE("(%p,%s,'%4.4s',%d,0x%X,%s)\n", ppavi, debugstr_a(szFile), | 
|  | (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler)); | 
|  |  | 
|  | if (ppavi == NULL || szFile == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | *ppavi = NULL; | 
|  |  | 
|  | hr = AVIFileOpenA(&pfile, szFile, mode, pclsidHandler); | 
|  | if (FAILED(hr) || pfile == NULL) | 
|  | return hr; | 
|  |  | 
|  | hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam); | 
|  | IAVIFile_Release(pfile); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamOpenFromFileW	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIStreamOpenFromFileW(PAVISTREAM *ppavi, LPCWSTR szFile, | 
|  | DWORD fccType, LONG lParam, | 
|  | UINT mode, LPCLSID pclsidHandler) | 
|  | { | 
|  | PAVIFILE pfile = NULL; | 
|  | HRESULT  hr; | 
|  |  | 
|  | TRACE("(%p,%s,'%4.4s',%d,0x%X,%s)\n", ppavi, debugstr_w(szFile), | 
|  | (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler)); | 
|  |  | 
|  | if (ppavi == NULL || szFile == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | *ppavi = NULL; | 
|  |  | 
|  | hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler); | 
|  | if (FAILED(hr) || pfile == NULL) | 
|  | return hr; | 
|  |  | 
|  | hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam); | 
|  | IAVIFile_Release(pfile); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamBeginStreaming	(AVIFIL32.@) | 
|  | */ | 
|  | LONG WINAPI AVIStreamBeginStreaming(PAVISTREAM pavi, LONG lStart, LONG lEnd, LONG lRate) | 
|  | { | 
|  | IAVIStreaming* pstream = NULL; | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p,%d,%d,%d)\n", pavi, lStart, lEnd, lRate); | 
|  |  | 
|  | if (pavi == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream); | 
|  | if (SUCCEEDED(hr) && pstream != NULL) { | 
|  | hr = IAVIStreaming_Begin(pstream, lStart, lEnd, lRate); | 
|  | IAVIStreaming_Release(pstream); | 
|  | } else | 
|  | hr = AVIERR_OK; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamEndStreaming	(AVIFIL32.@) | 
|  | */ | 
|  | LONG WINAPI AVIStreamEndStreaming(PAVISTREAM pavi) | 
|  | { | 
|  | IAVIStreaming* pstream = NULL; | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p)\n", pavi); | 
|  |  | 
|  | hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream); | 
|  | if (SUCCEEDED(hr) && pstream != NULL) { | 
|  | IAVIStreaming_End(pstream); | 
|  | IAVIStreaming_Release(pstream); | 
|  | } | 
|  |  | 
|  | return AVIERR_OK; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamStart		(AVIFIL32.@) | 
|  | */ | 
|  | LONG WINAPI AVIStreamStart(PAVISTREAM pstream) | 
|  | { | 
|  | AVISTREAMINFOW asiw; | 
|  |  | 
|  | TRACE("(%p)\n", pstream); | 
|  |  | 
|  | if (pstream == NULL) | 
|  | return 0; | 
|  |  | 
|  | if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw)))) | 
|  | return 0; | 
|  |  | 
|  | return asiw.dwStart; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamLength		(AVIFIL32.@) | 
|  | */ | 
|  | LONG WINAPI AVIStreamLength(PAVISTREAM pstream) | 
|  | { | 
|  | AVISTREAMINFOW asiw; | 
|  |  | 
|  | TRACE("(%p)\n", pstream); | 
|  |  | 
|  | if (pstream == NULL) | 
|  | return 0; | 
|  |  | 
|  | if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw)))) | 
|  | return 0; | 
|  |  | 
|  | return asiw.dwLength; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamSampleToTime	(AVIFIL32.@) | 
|  | */ | 
|  | LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample) | 
|  | { | 
|  | AVISTREAMINFOW asiw; | 
|  | LONG time; | 
|  |  | 
|  | TRACE("(%p,%d)\n", pstream, lSample); | 
|  |  | 
|  | if (pstream == NULL) | 
|  | return -1; | 
|  |  | 
|  | if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw)))) | 
|  | return -1; | 
|  | if (asiw.dwRate == 0) | 
|  | return -1; | 
|  |  | 
|  | /* limit to stream bounds */ | 
|  | if (lSample < asiw.dwStart) | 
|  | lSample = asiw.dwStart; | 
|  | if (lSample > asiw.dwStart + asiw.dwLength) | 
|  | lSample = asiw.dwStart + asiw.dwLength; | 
|  |  | 
|  | if (asiw.dwRate / asiw.dwScale < 1000) | 
|  | time = (LONG)(((float)lSample * asiw.dwScale * 1000) / asiw.dwRate); | 
|  | else | 
|  | time = (LONG)(((float)lSample * asiw.dwScale * 1000 + (asiw.dwRate - 1)) / asiw.dwRate); | 
|  |  | 
|  | TRACE(" -> %d\n",time); | 
|  | return time; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIStreamTimeToSample	(AVIFIL32.@) | 
|  | */ | 
|  | LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime) | 
|  | { | 
|  | AVISTREAMINFOW asiw; | 
|  | ULONG sample; | 
|  |  | 
|  | TRACE("(%p,%d)\n", pstream, lTime); | 
|  |  | 
|  | if (pstream == NULL || lTime < 0) | 
|  | return -1; | 
|  |  | 
|  | if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw)))) | 
|  | return -1; | 
|  | if (asiw.dwScale == 0) | 
|  | return -1; | 
|  |  | 
|  | if (asiw.dwRate / asiw.dwScale < 1000) | 
|  | sample = (LONG)((((float)asiw.dwRate * lTime) / (asiw.dwScale * 1000))); | 
|  | else | 
|  | sample = (LONG)(((float)asiw.dwRate * lTime + (asiw.dwScale * 1000 - 1)) / (asiw.dwScale * 1000)); | 
|  |  | 
|  | /* limit to stream bounds */ | 
|  | if (sample < asiw.dwStart) | 
|  | sample = asiw.dwStart; | 
|  | if (sample > asiw.dwStart + asiw.dwLength) | 
|  | sample = asiw.dwStart + asiw.dwLength; | 
|  |  | 
|  | TRACE(" -> %d\n", sample); | 
|  | return sample; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIBuildFilter		(AVIFIL32.@) | 
|  | *		AVIBuildFilterA		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving) | 
|  | { | 
|  | LPWSTR  wszFilter; | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p,%d,%d)\n", szFilter, cbFilter, fSaving); | 
|  |  | 
|  | /* check parameters */ | 
|  | if (szFilter == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  | if (cbFilter < 2) | 
|  | return AVIERR_BADSIZE; | 
|  |  | 
|  | szFilter[0] = 0; | 
|  | szFilter[1] = 0; | 
|  |  | 
|  | wszFilter = HeapAlloc(GetProcessHeap(), 0, cbFilter * sizeof(WCHAR)); | 
|  | if (wszFilter == NULL) | 
|  | return AVIERR_MEMORY; | 
|  |  | 
|  | hr = AVIBuildFilterW(wszFilter, cbFilter, fSaving); | 
|  | if (SUCCEEDED(hr)) { | 
|  | WideCharToMultiByte(CP_ACP, 0, wszFilter, cbFilter, | 
|  | szFilter, cbFilter, NULL, NULL); | 
|  | } | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, wszFilter); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIBuildFilterW		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving) | 
|  | { | 
|  | static const WCHAR all_files[] = { '*','.','*',0,0 }; | 
|  | static const WCHAR szClsid[] = {'C','L','S','I','D',0}; | 
|  | static const WCHAR szExtensionFmt[] = {';','*','.','%','s',0}; | 
|  | static const WCHAR szAVIFileExtensions[] = | 
|  | {'A','V','I','F','i','l','e','\\','E','x','t','e','n','s','i','o','n','s',0}; | 
|  |  | 
|  | AVIFilter *lp; | 
|  | WCHAR      szAllFiles[40]; | 
|  | WCHAR      szFileExt[10]; | 
|  | WCHAR      szValue[128]; | 
|  | HKEY       hKey; | 
|  | DWORD      n, i; | 
|  | LONG       size; | 
|  | DWORD      count = 0; | 
|  |  | 
|  | TRACE("(%p,%d,%d)\n", szFilter, cbFilter, fSaving); | 
|  |  | 
|  | /* check parameters */ | 
|  | if (szFilter == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  | if (cbFilter < 2) | 
|  | return AVIERR_BADSIZE; | 
|  |  | 
|  | lp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_FILTERS * sizeof(AVIFilter)); | 
|  | if (lp == NULL) | 
|  | return AVIERR_MEMORY; | 
|  |  | 
|  | /* | 
|  | * 1. iterate over HKEY_CLASSES_ROOT\\AVIFile\\Extensions and collect | 
|  | *    extensions and CLSID's | 
|  | * 2. iterate over collected CLSID's and copy its description and its | 
|  | *    extensions to szFilter if it fits | 
|  | * | 
|  | * First filter is named "All multimedia files" and its filter is a | 
|  | * collection of all possible extensions except "*.*". | 
|  | */ | 
|  | if (RegOpenKeyW(HKEY_CLASSES_ROOT, szAVIFileExtensions, &hKey) != ERROR_SUCCESS) { | 
|  | HeapFree(GetProcessHeap(), 0, lp); | 
|  | return AVIERR_ERROR; | 
|  | } | 
|  | for (n = 0;RegEnumKeyW(hKey, n, szFileExt, sizeof(szFileExt)/sizeof(szFileExt[0])) == ERROR_SUCCESS;n++) { | 
|  | /* get CLSID to extension */ | 
|  | size = sizeof(szValue); | 
|  | if (RegQueryValueW(hKey, szFileExt, szValue, &size) != ERROR_SUCCESS) | 
|  | break; | 
|  |  | 
|  | /* search if the CLSID is already known */ | 
|  | for (i = 1; i <= count; i++) { | 
|  | if (lstrcmpW(lp[i].szClsid, szValue) == 0) | 
|  | break; /* a new one */ | 
|  | } | 
|  |  | 
|  | if (i == count + 1) { | 
|  | /* it's a new CLSID */ | 
|  |  | 
|  | /* FIXME: How do we get info's about read/write capabilities? */ | 
|  |  | 
|  | if (count >= MAX_FILTERS) { | 
|  | /* try to inform user of our full fixed size table */ | 
|  | ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS); | 
|  | break; | 
|  | } | 
|  |  | 
|  | lstrcpyW(lp[i].szClsid, szValue); | 
|  |  | 
|  | count++; | 
|  | } | 
|  |  | 
|  | /* append extension to the filter */ | 
|  | wsprintfW(szValue, szExtensionFmt, szFileExt); | 
|  | if (lp[i].szExtensions[0] == 0) | 
|  | lstrcatW(lp[i].szExtensions, szValue + 1); | 
|  | else | 
|  | lstrcatW(lp[i].szExtensions, szValue); | 
|  |  | 
|  | /* also append to the "all multimedia"-filter */ | 
|  | if (lp[0].szExtensions[0] == 0) | 
|  | lstrcatW(lp[0].szExtensions, szValue + 1); | 
|  | else | 
|  | lstrcatW(lp[0].szExtensions, szValue); | 
|  | } | 
|  | RegCloseKey(hKey); | 
|  |  | 
|  | /* 2. get descriptions for the CLSIDs and fill out szFilter */ | 
|  | if (RegOpenKeyW(HKEY_CLASSES_ROOT, szClsid, &hKey) != ERROR_SUCCESS) { | 
|  | HeapFree(GetProcessHeap(), 0, lp); | 
|  | return AVIERR_ERROR; | 
|  | } | 
|  | for (n = 0; n <= count; n++) { | 
|  | /* first the description */ | 
|  | if (n != 0) { | 
|  | size = sizeof(szValue); | 
|  | if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == ERROR_SUCCESS) { | 
|  | size = lstrlenW(szValue); | 
|  | lstrcpynW(szFilter, szValue, cbFilter); | 
|  | } | 
|  | } else | 
|  | size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter); | 
|  |  | 
|  | /* check for enough space */ | 
|  | size++; | 
|  | if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) { | 
|  | szFilter[0] = 0; | 
|  | szFilter[1] = 0; | 
|  | HeapFree(GetProcessHeap(), 0, lp); | 
|  | RegCloseKey(hKey); | 
|  | return AVIERR_BUFFERTOOSMALL; | 
|  | } | 
|  | cbFilter -= size; | 
|  | szFilter += size; | 
|  |  | 
|  | /* and then the filter */ | 
|  | lstrcpynW(szFilter, lp[n].szExtensions, cbFilter); | 
|  | size = lstrlenW(lp[n].szExtensions) + 1; | 
|  | cbFilter -= size; | 
|  | szFilter += size; | 
|  | } | 
|  |  | 
|  | RegCloseKey(hKey); | 
|  | HeapFree(GetProcessHeap(), 0, lp); | 
|  |  | 
|  | /* add "All files" "*.*" filter if enough space left */ | 
|  | size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES, | 
|  | szAllFiles, (sizeof(szAllFiles) - sizeof(all_files))/sizeof(WCHAR)) + 1; | 
|  | memcpy( szAllFiles + size, all_files, sizeof(all_files) ); | 
|  | size += sizeof(all_files) / sizeof(WCHAR); | 
|  |  | 
|  | if (cbFilter > size) { | 
|  | memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0])); | 
|  | return AVIERR_OK; | 
|  | } else { | 
|  | szFilter[0] = 0; | 
|  | return AVIERR_BUFFERTOOSMALL; | 
|  | } | 
|  | } | 
|  |  | 
|  | static BOOL AVISaveOptionsFmtChoose(HWND hWnd) | 
|  | { | 
|  | LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent]; | 
|  | AVISTREAMINFOW       sInfo; | 
|  |  | 
|  | TRACE("(%p)\n", hWnd); | 
|  |  | 
|  | if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) { | 
|  | ERR(": bad state!\n"); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], | 
|  | &sInfo, sizeof(sInfo)))) { | 
|  | ERR(": AVIStreamInfoW failed!\n"); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | if (sInfo.fccType == streamtypeVIDEO) { | 
|  | COMPVARS cv; | 
|  | BOOL     ret; | 
|  |  | 
|  | memset(&cv, 0, sizeof(cv)); | 
|  |  | 
|  | if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) { | 
|  | memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS)); | 
|  | pOptions->fccType    = streamtypeVIDEO; | 
|  | pOptions->fccHandler = comptypeDIB; | 
|  | pOptions->dwQuality  = (DWORD)ICQUALITY_DEFAULT; | 
|  | } | 
|  |  | 
|  | cv.cbSize     = sizeof(cv); | 
|  | cv.dwFlags    = ICMF_COMPVARS_VALID; | 
|  | /*cv.fccType    = pOptions->fccType; */ | 
|  | cv.fccHandler = pOptions->fccHandler; | 
|  | cv.lQ         = pOptions->dwQuality; | 
|  | cv.lpState    = pOptions->lpParms; | 
|  | cv.cbState    = pOptions->cbParms; | 
|  | if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES) | 
|  | cv.lKey = pOptions->dwKeyFrameEvery; | 
|  | else | 
|  | cv.lKey = 0; | 
|  | if (pOptions->dwFlags & AVICOMPRESSF_DATARATE) | 
|  | cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */ | 
|  | else | 
|  | cv.lDataRate = 0; | 
|  |  | 
|  | ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL, | 
|  | SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL); | 
|  |  | 
|  | if (ret) { | 
|  | pOptions->fccHandler = cv.fccHandler; | 
|  | pOptions->lpParms   = cv.lpState; | 
|  | pOptions->cbParms   = cv.cbState; | 
|  | pOptions->dwQuality = cv.lQ; | 
|  | if (cv.lKey != 0) { | 
|  | pOptions->dwKeyFrameEvery = cv.lKey; | 
|  | pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES; | 
|  | } else | 
|  | pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES; | 
|  | if (cv.lDataRate != 0) { | 
|  | pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */ | 
|  | pOptions->dwFlags |= AVICOMPRESSF_DATARATE; | 
|  | } else | 
|  | pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE; | 
|  | pOptions->dwFlags  |= AVICOMPRESSF_VALID; | 
|  | } | 
|  | ICCompressorFree(&cv); | 
|  |  | 
|  | return ret; | 
|  | } else if (sInfo.fccType == streamtypeAUDIO) { | 
|  | ACMFORMATCHOOSEW afmtc; | 
|  | MMRESULT         ret; | 
|  | LONG             size; | 
|  |  | 
|  | /* FIXME: check ACM version -- Which version is needed? */ | 
|  |  | 
|  | memset(&afmtc, 0, sizeof(afmtc)); | 
|  | afmtc.cbStruct  = sizeof(afmtc); | 
|  | afmtc.fdwStyle  = 0; | 
|  | afmtc.hwndOwner = hWnd; | 
|  |  | 
|  | acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size); | 
|  | if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) { | 
|  | pOptions->lpFormat = HeapAlloc(GetProcessHeap(), 0, size); | 
|  | if (!pOptions->lpFormat) return FALSE; | 
|  | pOptions->cbFormat = size; | 
|  | } else if (pOptions->cbFormat < (DWORD)size) { | 
|  | void *new_buffer = HeapReAlloc(GetProcessHeap(), 0, pOptions->lpFormat, size); | 
|  | if (!new_buffer) return FALSE; | 
|  | pOptions->lpFormat = new_buffer; | 
|  | pOptions->cbFormat = size; | 
|  | } | 
|  | afmtc.pwfx  = pOptions->lpFormat; | 
|  | afmtc.cbwfx = pOptions->cbFormat; | 
|  |  | 
|  | size = 0; | 
|  | AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent], | 
|  | sInfo.dwStart, &size); | 
|  | if (size < (LONG)sizeof(PCMWAVEFORMAT)) | 
|  | size = sizeof(PCMWAVEFORMAT); | 
|  | afmtc.pwfxEnum = HeapAlloc(GetProcessHeap(), 0, size); | 
|  | if (afmtc.pwfxEnum != NULL) { | 
|  | AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent], | 
|  | sInfo.dwStart, afmtc.pwfxEnum, &size); | 
|  | afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT; | 
|  | } | 
|  |  | 
|  | ret = acmFormatChooseW(&afmtc); | 
|  | if (ret == S_OK) | 
|  | pOptions->dwFlags |= AVICOMPRESSF_VALID; | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, afmtc.pwfxEnum); | 
|  | return (ret == S_OK ? TRUE : FALSE); | 
|  | } else { | 
|  | ERR(": unknown streamtype 0x%08X\n", sInfo.fccType); | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void AVISaveOptionsUpdate(HWND hWnd) | 
|  | { | 
|  | static const WCHAR szVideoFmt[]={'%','l','d','x','%','l','d','x','%','d',0}; | 
|  | static const WCHAR szAudioFmt[]={'%','s',' ','%','s',0}; | 
|  |  | 
|  | WCHAR          szFormat[128]; | 
|  | AVISTREAMINFOW sInfo; | 
|  | LPVOID         lpFormat; | 
|  | LONG           size; | 
|  |  | 
|  | TRACE("(%p)\n", hWnd); | 
|  |  | 
|  | SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0); | 
|  | if (SaveOpts.nCurrent < 0) | 
|  | return; | 
|  |  | 
|  | if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo)))) | 
|  | return; | 
|  |  | 
|  | AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size); | 
|  | if (size > 0) { | 
|  | szFormat[0] = 0; | 
|  |  | 
|  | /* read format to build format description string */ | 
|  | lpFormat = HeapAlloc(GetProcessHeap(), 0, size); | 
|  | if (lpFormat != NULL) { | 
|  | if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) { | 
|  | if (sInfo.fccType == streamtypeVIDEO) { | 
|  | LPBITMAPINFOHEADER lpbi = lpFormat; | 
|  | ICINFO icinfo; | 
|  |  | 
|  | wsprintfW(szFormat, szVideoFmt, lpbi->biWidth, | 
|  | lpbi->biHeight, lpbi->biBitCount); | 
|  |  | 
|  | if (lpbi->biCompression != BI_RGB) { | 
|  | HIC    hic; | 
|  |  | 
|  | hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat, | 
|  | NULL, ICMODE_DECOMPRESS); | 
|  | if (hic != NULL) { | 
|  | if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK) | 
|  | lstrcatW(szFormat, icinfo.szDescription); | 
|  | ICClose(hic); | 
|  | } | 
|  | } else { | 
|  | LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED, | 
|  | icinfo.szDescription, | 
|  | sizeof(icinfo.szDescription)/sizeof(icinfo.szDescription[0])); | 
|  | lstrcatW(szFormat, icinfo.szDescription); | 
|  | } | 
|  | } else if (sInfo.fccType == streamtypeAUDIO) { | 
|  | ACMFORMATTAGDETAILSW aftd; | 
|  | ACMFORMATDETAILSW    afd; | 
|  |  | 
|  | memset(&aftd, 0, sizeof(aftd)); | 
|  | memset(&afd, 0, sizeof(afd)); | 
|  |  | 
|  | aftd.cbStruct     = sizeof(aftd); | 
|  | aftd.dwFormatTag  = afd.dwFormatTag = | 
|  | ((PWAVEFORMATEX)lpFormat)->wFormatTag; | 
|  | aftd.cbFormatSize = afd.cbwfx = size; | 
|  |  | 
|  | afd.cbStruct      = sizeof(afd); | 
|  | afd.pwfx          = lpFormat; | 
|  |  | 
|  | if (acmFormatTagDetailsW(NULL, &aftd, | 
|  | ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) { | 
|  | if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK) | 
|  | wsprintfW(szFormat, szAudioFmt, afd.szFormat, aftd.szFormatTag); | 
|  | } | 
|  | } | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, lpFormat); | 
|  | } | 
|  |  | 
|  | /* set text for format description */ | 
|  | SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat); | 
|  |  | 
|  | /* Disable option button for unsupported streamtypes */ | 
|  | if (sInfo.fccType == streamtypeVIDEO || | 
|  | sInfo.fccType == streamtypeAUDIO) | 
|  | EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE); | 
|  | else | 
|  | EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE); | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | static INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg, | 
|  | WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | DWORD dwInterleave; | 
|  | BOOL  bIsInterleaved; | 
|  | INT   n; | 
|  |  | 
|  | /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/ | 
|  |  | 
|  | switch (uMsg) { | 
|  | case WM_INITDIALOG: | 
|  | SaveOpts.nCurrent = 0; | 
|  | if (SaveOpts.nStreams == 1) { | 
|  | EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd)); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /* add streams */ | 
|  | for (n = 0; n < SaveOpts.nStreams; n++) { | 
|  | AVISTREAMINFOW sInfo; | 
|  |  | 
|  | AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo)); | 
|  | SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING, | 
|  | 0L, (LPARAM)sInfo.szName); | 
|  | } | 
|  |  | 
|  | /* select first stream */ | 
|  | SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0); | 
|  | SendMessageW(hWnd, WM_COMMAND, MAKELONG(IDC_STREAM, CBN_SELCHANGE), (LPARAM)hWnd); | 
|  |  | 
|  | /* initialize interleave */ | 
|  | if (SaveOpts.ppOptions[0] != NULL && | 
|  | (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_VALID)) { | 
|  | bIsInterleaved = (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_INTERLEAVE); | 
|  | dwInterleave = SaveOpts.ppOptions[0]->dwInterleaveEvery; | 
|  | } else { | 
|  | bIsInterleaved = TRUE; | 
|  | dwInterleave   = 0; | 
|  | } | 
|  | CheckDlgButton(hWnd, IDC_INTERLEAVE, bIsInterleaved); | 
|  | SetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, dwInterleave, FALSE); | 
|  | EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), bIsInterleaved); | 
|  | break; | 
|  | case WM_COMMAND: | 
|  | switch (LOWORD(wParam)) { | 
|  | case IDOK: | 
|  | /* get data from controls and save them */ | 
|  | dwInterleave   = GetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, NULL, 0); | 
|  | bIsInterleaved = IsDlgButtonChecked(hWnd, IDC_INTERLEAVE); | 
|  | for (n = 0; n < SaveOpts.nStreams; n++) { | 
|  | if (SaveOpts.ppOptions[n] != NULL) { | 
|  | if (bIsInterleaved) { | 
|  | SaveOpts.ppOptions[n]->dwFlags |= AVICOMPRESSF_INTERLEAVE; | 
|  | SaveOpts.ppOptions[n]->dwInterleaveEvery = dwInterleave; | 
|  | } else | 
|  | SaveOpts.ppOptions[n]->dwFlags &= ~AVICOMPRESSF_INTERLEAVE; | 
|  | } | 
|  | } | 
|  | /* fall through */ | 
|  | case IDCANCEL: | 
|  | EndDialog(hWnd, LOWORD(wParam) == IDOK); | 
|  | break; | 
|  | case IDC_INTERLEAVE: | 
|  | EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), | 
|  | IsDlgButtonChecked(hWnd, IDC_INTERLEAVE)); | 
|  | break; | 
|  | case IDC_STREAM: | 
|  | if (HIWORD(wParam) == CBN_SELCHANGE) { | 
|  | /* update control elements */ | 
|  | AVISaveOptionsUpdate(hWnd); | 
|  | } | 
|  | break; | 
|  | case IDC_OPTIONS: | 
|  | AVISaveOptionsFmtChoose(hWnd); | 
|  | break; | 
|  | }; | 
|  | return TRUE; | 
|  | }; | 
|  |  | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVISaveOptions		(AVIFIL32.@) | 
|  | */ | 
|  | BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams, | 
|  | PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions) | 
|  | { | 
|  | LPAVICOMPRESSOPTIONS pSavedOptions = NULL; | 
|  | INT ret, n; | 
|  |  | 
|  | TRACE("(%p,0x%X,%d,%p,%p)\n", hWnd, uFlags, nStreams, | 
|  | ppavi, ppOptions); | 
|  |  | 
|  | /* check parameters */ | 
|  | if (nStreams <= 0 || ppavi == NULL || ppOptions == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | /* save options in case the user presses cancel */ | 
|  | if (nStreams > 1) { | 
|  | pSavedOptions = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(AVICOMPRESSOPTIONS)); | 
|  | if (pSavedOptions == NULL) | 
|  | return FALSE; | 
|  |  | 
|  | for (n = 0; n < nStreams; n++) { | 
|  | if (ppOptions[n] != NULL) | 
|  | memcpy(pSavedOptions + n, ppOptions[n], sizeof(AVICOMPRESSOPTIONS)); | 
|  | } | 
|  | } | 
|  |  | 
|  | SaveOpts.uFlags    = uFlags; | 
|  | SaveOpts.nStreams  = nStreams; | 
|  | SaveOpts.ppavis    = ppavi; | 
|  | SaveOpts.ppOptions = ppOptions; | 
|  |  | 
|  | ret = DialogBoxW(AVIFILE_hModule, MAKEINTRESOURCEW(IDD_SAVEOPTIONS), | 
|  | hWnd, AVISaveOptionsDlgProc); | 
|  |  | 
|  | if (ret == -1) | 
|  | ret = FALSE; | 
|  |  | 
|  | /* restore options when user pressed cancel */ | 
|  | if (pSavedOptions != NULL) { | 
|  | if (ret == FALSE) { | 
|  | for (n = 0; n < nStreams; n++) { | 
|  | if (ppOptions[n] != NULL) | 
|  | memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS)); | 
|  | } | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, pSavedOptions); | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVISaveOptionsFree	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions) | 
|  | { | 
|  | TRACE("(%d,%p)\n", nStreams, ppOptions); | 
|  |  | 
|  | if (nStreams < 0 || ppOptions == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | for (nStreams--; nStreams >= 0; nStreams--) { | 
|  | if (ppOptions[nStreams] != NULL) { | 
|  | ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID; | 
|  |  | 
|  | if (ppOptions[nStreams]->lpParms != NULL) { | 
|  | HeapFree(GetProcessHeap(), 0, ppOptions[nStreams]->lpParms); | 
|  | ppOptions[nStreams]->lpParms = NULL; | 
|  | ppOptions[nStreams]->cbParms = 0; | 
|  | } | 
|  | if (ppOptions[nStreams]->lpFormat != NULL) { | 
|  | HeapFree(GetProcessHeap(), 0, ppOptions[nStreams]->lpFormat); | 
|  | ppOptions[nStreams]->lpFormat = NULL; | 
|  | ppOptions[nStreams]->cbFormat = 0; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return AVIERR_OK; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVISaveVA		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVISaveVA(LPCSTR szFile, CLSID *pclsidHandler, | 
|  | AVISAVECALLBACK lpfnCallback, int nStream, | 
|  | PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions) | 
|  | { | 
|  | LPWSTR  wszFile = NULL; | 
|  | HRESULT hr; | 
|  | int     len; | 
|  |  | 
|  | TRACE("%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler, | 
|  | lpfnCallback, nStream, ppavi, plpOptions); | 
|  |  | 
|  | if (szFile == NULL || ppavi == NULL || plpOptions == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | /* convert ASCII string to Unicode and call Unicode function */ | 
|  | len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0); | 
|  | if (len <= 0) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | wszFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); | 
|  | if (wszFile == NULL) | 
|  | return AVIERR_MEMORY; | 
|  |  | 
|  | MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len); | 
|  |  | 
|  | hr = AVISaveVW(wszFile, pclsidHandler, lpfnCallback, | 
|  | nStream, ppavi, plpOptions); | 
|  |  | 
|  | HeapFree(GetProcessHeap(), 0, wszFile); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIFILE_AVISaveDefaultCallback	(internal) | 
|  | */ | 
|  | static BOOL WINAPI AVIFILE_AVISaveDefaultCallback(INT progress) | 
|  | { | 
|  | TRACE("(%d)\n", progress); | 
|  |  | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVISaveVW		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVISaveVW(LPCWSTR szFile, CLSID *pclsidHandler, | 
|  | AVISAVECALLBACK lpfnCallback, int nStreams, | 
|  | PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions) | 
|  | { | 
|  | LONG           lStart[MAX_AVISTREAMS]; | 
|  | PAVISTREAM     pOutStreams[MAX_AVISTREAMS]; | 
|  | PAVISTREAM     pInStreams[MAX_AVISTREAMS]; | 
|  | AVIFILEINFOW   fInfo; | 
|  | AVISTREAMINFOW sInfo; | 
|  |  | 
|  | PAVIFILE       pfile = NULL; /* the output AVI file */ | 
|  | LONG           lFirstVideo = -1; | 
|  | int            curStream; | 
|  |  | 
|  | /* for interleaving ... */ | 
|  | DWORD          dwInterleave = 0; /* interleave rate */ | 
|  | DWORD          dwFileInitialFrames; | 
|  | LONG           lFileLength; | 
|  | LONG           lSampleInc; | 
|  |  | 
|  | /* for reading/writing the data ... */ | 
|  | LPVOID         lpBuffer = NULL; | 
|  | LONG           cbBuffer;        /* real size of lpBuffer */ | 
|  | LONG           lBufferSize;     /* needed bytes for format(s), etc. */ | 
|  | LONG           lReadBytes; | 
|  | LONG           lReadSamples; | 
|  | HRESULT        hres; | 
|  |  | 
|  | TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_w(szFile), pclsidHandler, | 
|  | lpfnCallback, nStreams, ppavi, plpOptions); | 
|  |  | 
|  | if (szFile == NULL || ppavi == NULL || plpOptions == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  | if (nStreams >= MAX_AVISTREAMS) { | 
|  | WARN("Can't write AVI with %d streams only supports %d -- change MAX_AVISTREAMS!\n", nStreams, MAX_AVISTREAMS); | 
|  | return AVIERR_INTERNAL; | 
|  | } | 
|  |  | 
|  | if (lpfnCallback == NULL) | 
|  | lpfnCallback = AVIFILE_AVISaveDefaultCallback; | 
|  |  | 
|  | /* clear local variable(s) */ | 
|  | for (curStream = 0; curStream < nStreams; curStream++) { | 
|  | pInStreams[curStream]  = NULL; | 
|  | pOutStreams[curStream] = NULL; | 
|  | } | 
|  |  | 
|  | /* open output AVI file (create it if it doesn't exist) */ | 
|  | hres = AVIFileOpenW(&pfile, szFile, OF_CREATE|OF_SHARE_EXCLUSIVE|OF_WRITE, | 
|  | pclsidHandler); | 
|  | if (FAILED(hres)) | 
|  | return hres; | 
|  | AVIFileInfoW(pfile, &fInfo, sizeof(fInfo)); /* for dwCaps */ | 
|  |  | 
|  | /* initialize our data structures part 1 */ | 
|  | for (curStream = 0; curStream < nStreams; curStream++) { | 
|  | PAVISTREAM pCurStream = ppavi[curStream]; | 
|  |  | 
|  | hres = AVIStreamInfoW(pCurStream, &sInfo, sizeof(sInfo)); | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  |  | 
|  | /* search first video stream and check for interleaving */ | 
|  | if (sInfo.fccType == streamtypeVIDEO) { | 
|  | /* remember first video stream -- needed for interleaving */ | 
|  | if (lFirstVideo < 0) | 
|  | lFirstVideo = curStream; | 
|  | } else if (!dwInterleave) { | 
|  | /* check if any non-video stream wants to be interleaved */ | 
|  | WARN("options.flags=0x%X options.dwInterleave=%u\n",plpOptions[curStream]->dwFlags,plpOptions[curStream]->dwInterleaveEvery); | 
|  | if (plpOptions[curStream] != NULL && | 
|  | plpOptions[curStream]->dwFlags & AVICOMPRESSF_INTERLEAVE) | 
|  | dwInterleave = plpOptions[curStream]->dwInterleaveEvery; | 
|  | } | 
|  |  | 
|  | /* create de-/compressed stream interface if needed */ | 
|  | pInStreams[curStream] = NULL; | 
|  | if (plpOptions[curStream] != NULL) { | 
|  | if (plpOptions[curStream]->fccHandler || | 
|  | plpOptions[curStream]->lpFormat != NULL) { | 
|  | DWORD dwKeySave = plpOptions[curStream]->dwKeyFrameEvery; | 
|  |  | 
|  | if (fInfo.dwCaps & AVIFILECAPS_ALLKEYFRAMES) | 
|  | plpOptions[curStream]->dwKeyFrameEvery = 1; | 
|  |  | 
|  | hres = AVIMakeCompressedStream(&pInStreams[curStream], pCurStream, | 
|  | plpOptions[curStream], NULL); | 
|  | plpOptions[curStream]->dwKeyFrameEvery = dwKeySave; | 
|  | if (FAILED(hres) || pInStreams[curStream] == NULL) { | 
|  | pInStreams[curStream] = NULL; | 
|  | goto error; | 
|  | } | 
|  |  | 
|  | /* test stream interface and update stream-info */ | 
|  | hres = AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo)); | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* now handle streams which will only be copied */ | 
|  | if (pInStreams[curStream] == NULL) { | 
|  | pCurStream = pInStreams[curStream] = ppavi[curStream]; | 
|  | AVIStreamAddRef(pCurStream); | 
|  | } else | 
|  | pCurStream = pInStreams[curStream]; | 
|  |  | 
|  | lStart[curStream] = sInfo.dwStart; | 
|  | } /* for all streams */ | 
|  |  | 
|  | /* check that first video stream is the first stream */ | 
|  | if (lFirstVideo > 0) { | 
|  | PAVISTREAM pTmp = pInStreams[lFirstVideo]; | 
|  | LONG lTmp = lStart[lFirstVideo]; | 
|  |  | 
|  | pInStreams[lFirstVideo] = pInStreams[0]; | 
|  | pInStreams[0] = pTmp; | 
|  | lStart[lFirstVideo] = lStart[0]; | 
|  | lStart[0] = lTmp; | 
|  | lFirstVideo = 0; | 
|  | } | 
|  |  | 
|  | /* allocate buffer for formats, data, etc. of an initial size of 64 kBytes*/ | 
|  | cbBuffer = 0x00010000; | 
|  | lpBuffer = HeapAlloc(GetProcessHeap(), 0, cbBuffer); | 
|  | if (lpBuffer == NULL) { | 
|  | hres = AVIERR_MEMORY; | 
|  | goto error; | 
|  | } | 
|  |  | 
|  | AVIStreamInfoW(pInStreams[0], &sInfo, sizeof(sInfo)); | 
|  | lFileLength = sInfo.dwLength; | 
|  | dwFileInitialFrames = 0; | 
|  | if (lFirstVideo >= 0) { | 
|  | /* check for correct version of the format | 
|  | *  -- need at least BITMAPINFOHEADER or newer | 
|  | */ | 
|  | lSampleInc = 1; | 
|  | lBufferSize = cbBuffer; | 
|  | hres = AVIStreamReadFormat(pInStreams[lFirstVideo], AVIStreamStart(pInStreams[lFirstVideo]), lpBuffer, &lBufferSize); | 
|  | if (lBufferSize < (LONG)sizeof(BITMAPINFOHEADER)) | 
|  | hres = AVIERR_INTERNAL; | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  | } else /* use one second blocks for interleaving if no video present */ | 
|  | lSampleInc = AVIStreamTimeToSample(pInStreams[0], 1000000); | 
|  |  | 
|  | /* create output streams */ | 
|  | for (curStream = 0; curStream < nStreams; curStream++) { | 
|  | AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo)); | 
|  |  | 
|  | sInfo.dwInitialFrames = 0; | 
|  | if (dwInterleave != 0 && curStream > 0 && sInfo.fccType != streamtypeVIDEO) { | 
|  | /* 750 ms initial frames for non-video streams */ | 
|  | sInfo.dwInitialFrames = AVIStreamTimeToSample(pInStreams[0], 750); | 
|  | } | 
|  |  | 
|  | hres = AVIFileCreateStreamW(pfile, &pOutStreams[curStream], &sInfo); | 
|  | if (pOutStreams[curStream] != NULL && SUCCEEDED(hres)) { | 
|  | /* copy initial format for this stream */ | 
|  | lBufferSize = cbBuffer; | 
|  | hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart, | 
|  | lpBuffer, &lBufferSize); | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  | hres = AVIStreamSetFormat(pOutStreams[curStream], 0, lpBuffer, lBufferSize); | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  |  | 
|  | /* try to copy stream handler data */ | 
|  | lBufferSize = cbBuffer; | 
|  | hres = AVIStreamReadData(pInStreams[curStream], ckidSTREAMHANDLERDATA, | 
|  | lpBuffer, &lBufferSize); | 
|  | if (SUCCEEDED(hres) && lBufferSize > 0) { | 
|  | hres = AVIStreamWriteData(pOutStreams[curStream],ckidSTREAMHANDLERDATA, | 
|  | lpBuffer, lBufferSize); | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  | } | 
|  |  | 
|  | if (dwFileInitialFrames < sInfo.dwInitialFrames) | 
|  | dwFileInitialFrames = sInfo.dwInitialFrames; | 
|  | lReadBytes = | 
|  | AVIStreamSampleToSample(pOutStreams[0], pInStreams[curStream], | 
|  | sInfo.dwLength); | 
|  | if (lFileLength < lReadBytes) | 
|  | lFileLength = lReadBytes; | 
|  | } else { | 
|  | /* creation of de-/compression stream interface failed */ | 
|  | WARN("creation of (de-)compression stream failed for stream %d\n",curStream); | 
|  | AVIStreamRelease(pInStreams[curStream]); | 
|  | if (curStream + 1 >= nStreams) { | 
|  | /* move the others one up */ | 
|  | PAVISTREAM *ppas = &pInStreams[curStream]; | 
|  | int            n = nStreams - (curStream + 1); | 
|  |  | 
|  | do { | 
|  | *ppas = pInStreams[curStream + 1]; | 
|  | } while (--n); | 
|  | } | 
|  | nStreams--; | 
|  | curStream--; | 
|  | } | 
|  | } /* create output streams for all input streams */ | 
|  |  | 
|  | /* have we still something to write, or lost everything? */ | 
|  | if (nStreams <= 0) | 
|  | goto error; | 
|  |  | 
|  | if (dwInterleave) { | 
|  | LONG lCurFrame = -dwFileInitialFrames; | 
|  |  | 
|  | /* interleaved file */ | 
|  | if (dwInterleave == 1) | 
|  | AVIFileEndRecord(pfile); | 
|  |  | 
|  | for (; lCurFrame < lFileLength; lCurFrame += lSampleInc) { | 
|  | for (curStream = 0; curStream < nStreams; curStream++) { | 
|  | LONG lLastSample; | 
|  |  | 
|  | hres = AVIStreamInfoW(pOutStreams[curStream], &sInfo, sizeof(sInfo)); | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  |  | 
|  | /* initial frames phase at the end for this stream? */ | 
|  | if (-(LONG)sInfo.dwInitialFrames > lCurFrame) | 
|  | continue; | 
|  |  | 
|  | if ((lFileLength - lSampleInc) <= lCurFrame) { | 
|  | lLastSample = AVIStreamLength(pInStreams[curStream]); | 
|  | lFirstVideo = lLastSample + AVIStreamStart(pInStreams[curStream]); | 
|  | } else { | 
|  | if (curStream != 0) { | 
|  | lFirstVideo = | 
|  | AVIStreamSampleToSample(pInStreams[curStream], pInStreams[0], | 
|  | (sInfo.fccType == streamtypeVIDEO ? | 
|  | (LONG)dwInterleave : lSampleInc) + | 
|  | sInfo.dwInitialFrames + lCurFrame); | 
|  | } else | 
|  | lFirstVideo = lSampleInc + (sInfo.dwInitialFrames + lCurFrame); | 
|  |  | 
|  | lLastSample = AVIStreamEnd(pInStreams[curStream]); | 
|  | if (lLastSample <= lFirstVideo) | 
|  | lFirstVideo = lLastSample; | 
|  | } | 
|  |  | 
|  | /* copy needed samples now */ | 
|  | WARN("copy from stream %d samples %d to %d...\n",curStream, | 
|  | lStart[curStream],lFirstVideo); | 
|  | while (lFirstVideo > lStart[curStream]) { | 
|  | DWORD flags = 0; | 
|  |  | 
|  | /* copy format in case it can change */ | 
|  | lBufferSize = cbBuffer; | 
|  | hres = AVIStreamReadFormat(pInStreams[curStream], lStart[curStream], | 
|  | lpBuffer, &lBufferSize); | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  | AVIStreamSetFormat(pOutStreams[curStream], lStart[curStream], | 
|  | lpBuffer, lBufferSize); | 
|  |  | 
|  | /* try to read data until we got it, or error */ | 
|  | do { | 
|  | hres = AVIStreamRead(pInStreams[curStream], lStart[curStream], | 
|  | lFirstVideo - lStart[curStream], lpBuffer, | 
|  | cbBuffer, &lReadBytes, &lReadSamples); | 
|  | } while ((hres == AVIERR_BUFFERTOOSMALL) && | 
|  | (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL); | 
|  | if (lpBuffer == NULL) | 
|  | hres = AVIERR_MEMORY; | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  |  | 
|  | if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart)) | 
|  | flags = AVIIF_KEYFRAME; | 
|  | hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples, | 
|  | lpBuffer, lReadBytes, flags, NULL, NULL); | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  |  | 
|  | lStart[curStream] += lReadSamples; | 
|  | } | 
|  | lStart[curStream] = lFirstVideo; | 
|  | } /* stream by stream */ | 
|  |  | 
|  | /* need to close this block? */ | 
|  | if (dwInterleave == 1) { | 
|  | hres = AVIFileEndRecord(pfile); | 
|  | if (FAILED(hres)) | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* show progress */ | 
|  | if (lpfnCallback(MulDiv(dwFileInitialFrames + lCurFrame, 100, | 
|  | dwFileInitialFrames + lFileLength))) { | 
|  | hres = AVIERR_USERABORT; | 
|  | break; | 
|  | } | 
|  | } /* copy frame by frame */ | 
|  | } else { | 
|  | /* non-interleaved file */ | 
|  |  | 
|  | for (curStream = 0; curStream < nStreams; curStream++) { | 
|  | /* show progress */ | 
|  | if (lpfnCallback(MulDiv(curStream, 100, nStreams))) { | 
|  | hres = AVIERR_USERABORT; | 
|  | goto error; | 
|  | } | 
|  |  | 
|  | AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo)); | 
|  |  | 
|  | if (sInfo.dwSampleSize != 0) { | 
|  | /* sample-based data like audio */ | 
|  | while (sInfo.dwStart < sInfo.dwLength) { | 
|  | LONG lSamples = cbBuffer / sInfo.dwSampleSize; | 
|  |  | 
|  | /* copy format in case it can change */ | 
|  | lBufferSize = cbBuffer; | 
|  | hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart, | 
|  | lpBuffer, &lBufferSize); | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  | AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart, | 
|  | lpBuffer, lBufferSize); | 
|  |  | 
|  | /* limit to stream boundaries */ | 
|  | if (lSamples != (LONG)(sInfo.dwLength - sInfo.dwStart)) | 
|  | lSamples = sInfo.dwLength - sInfo.dwStart; | 
|  |  | 
|  | /* now try to read until we get it, or an error occurs */ | 
|  | do { | 
|  | lReadBytes   = cbBuffer; | 
|  | lReadSamples = 0; | 
|  | hres = AVIStreamRead(pInStreams[curStream],sInfo.dwStart,lSamples, | 
|  | lpBuffer,cbBuffer,&lReadBytes,&lReadSamples); | 
|  | } while ((hres == AVIERR_BUFFERTOOSMALL) && | 
|  | (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL); | 
|  | if (lpBuffer == NULL) | 
|  | hres = AVIERR_MEMORY; | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  | if (lReadSamples != 0) { | 
|  | sInfo.dwStart += lReadSamples; | 
|  | hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples, | 
|  | lpBuffer, lReadBytes, 0, NULL , NULL); | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  |  | 
|  | /* show progress */ | 
|  | if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+ | 
|  | MulDiv(curStream, 100, nStreams))) { | 
|  | hres = AVIERR_USERABORT; | 
|  | goto error; | 
|  | } | 
|  | } else { | 
|  | if ((sInfo.dwLength - sInfo.dwStart) != 1) { | 
|  | hres = AVIERR_FILEREAD; | 
|  | goto error; | 
|  | } | 
|  | } | 
|  | } | 
|  | } else { | 
|  | /* block-based data like video */ | 
|  | for (; sInfo.dwStart < sInfo.dwLength; sInfo.dwStart++) { | 
|  | DWORD flags = 0; | 
|  |  | 
|  | /* copy format in case it can change */ | 
|  | lBufferSize = cbBuffer; | 
|  | hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart, | 
|  | lpBuffer, &lBufferSize); | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  | AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart, | 
|  | lpBuffer, lBufferSize); | 
|  |  | 
|  | /* try to read block and resize buffer if necessary */ | 
|  | do { | 
|  | lReadSamples = 0; | 
|  | lReadBytes   = cbBuffer; | 
|  | hres = AVIStreamRead(pInStreams[curStream], sInfo.dwStart, 1, | 
|  | lpBuffer, cbBuffer,&lReadBytes,&lReadSamples); | 
|  | } while ((hres == AVIERR_BUFFERTOOSMALL) && | 
|  | (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL); | 
|  | if (lpBuffer == NULL) | 
|  | hres = AVIERR_MEMORY; | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  | if (lReadSamples != 1) { | 
|  | hres = AVIERR_FILEREAD; | 
|  | goto error; | 
|  | } | 
|  |  | 
|  | if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart)) | 
|  | flags = AVIIF_KEYFRAME; | 
|  | hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples, | 
|  | lpBuffer, lReadBytes, flags, NULL, NULL); | 
|  | if (FAILED(hres)) | 
|  | goto error; | 
|  |  | 
|  | /* show progress */ | 
|  | if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+ | 
|  | MulDiv(curStream, 100, nStreams))) { | 
|  | hres = AVIERR_USERABORT; | 
|  | goto error; | 
|  | } | 
|  | } /* copy all blocks */ | 
|  | } | 
|  | } /* copy data stream by stream */ | 
|  | } | 
|  |  | 
|  | error: | 
|  | HeapFree(GetProcessHeap(), 0, lpBuffer); | 
|  | if (pfile != NULL) { | 
|  | for (curStream = 0; curStream < nStreams; curStream++) { | 
|  | if (pOutStreams[curStream] != NULL) | 
|  | AVIStreamRelease(pOutStreams[curStream]); | 
|  | if (pInStreams[curStream] != NULL) | 
|  | AVIStreamRelease(pInStreams[curStream]); | 
|  | } | 
|  |  | 
|  | AVIFileRelease(pfile); | 
|  | } | 
|  |  | 
|  | return hres; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		CreateEditableStream	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI CreateEditableStream(PAVISTREAM *ppEditable, PAVISTREAM pSource) | 
|  | { | 
|  | IAVIEditStream *pEdit = NULL; | 
|  | HRESULT	  hr; | 
|  |  | 
|  | TRACE("(%p,%p)\n", ppEditable, pSource); | 
|  |  | 
|  | if (ppEditable == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | *ppEditable = NULL; | 
|  |  | 
|  | if (pSource != NULL) { | 
|  | hr = IAVIStream_QueryInterface(pSource, &IID_IAVIEditStream, | 
|  | (LPVOID*)&pEdit); | 
|  | if (SUCCEEDED(hr) && pEdit != NULL) { | 
|  | hr = IAVIEditStream_Clone(pEdit, ppEditable); | 
|  | IAVIEditStream_Release(pEdit); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* need own implementation of IAVIEditStream */ | 
|  | pEdit = AVIFILE_CreateEditStream(pSource); | 
|  | if (pEdit == NULL) | 
|  | return AVIERR_MEMORY; | 
|  |  | 
|  | hr = IAVIEditStream_QueryInterface(pEdit, &IID_IAVIStream, | 
|  | (LPVOID*)ppEditable); | 
|  | IAVIEditStream_Release(pEdit); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		EditStreamClone		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI EditStreamClone(PAVISTREAM pStream, PAVISTREAM *ppResult) | 
|  | { | 
|  | PAVIEDITSTREAM pEdit = NULL; | 
|  | HRESULT        hr; | 
|  |  | 
|  | TRACE("(%p,%p)\n", pStream, ppResult); | 
|  |  | 
|  | if (pStream == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  | if (ppResult == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | *ppResult = NULL; | 
|  |  | 
|  | hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit); | 
|  | if (SUCCEEDED(hr) && pEdit != NULL) { | 
|  | hr = IAVIEditStream_Clone(pEdit, ppResult); | 
|  |  | 
|  | IAVIEditStream_Release(pEdit); | 
|  | } else | 
|  | hr = AVIERR_UNSUPPORTED; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		EditStreamCopy		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI EditStreamCopy(PAVISTREAM pStream, LONG *plStart, | 
|  | LONG *plLength, PAVISTREAM *ppResult) | 
|  | { | 
|  | PAVIEDITSTREAM pEdit = NULL; | 
|  | HRESULT        hr; | 
|  |  | 
|  | TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult); | 
|  |  | 
|  | if (pStream == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  | if (plStart == NULL || plLength == NULL || ppResult == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | *ppResult = NULL; | 
|  |  | 
|  | hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit); | 
|  | if (SUCCEEDED(hr) && pEdit != NULL) { | 
|  | hr = IAVIEditStream_Copy(pEdit, plStart, plLength, ppResult); | 
|  |  | 
|  | IAVIEditStream_Release(pEdit); | 
|  | } else | 
|  | hr = AVIERR_UNSUPPORTED; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		EditStreamCut		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI EditStreamCut(PAVISTREAM pStream, LONG *plStart, | 
|  | LONG *plLength, PAVISTREAM *ppResult) | 
|  | { | 
|  | PAVIEDITSTREAM pEdit = NULL; | 
|  | HRESULT        hr; | 
|  |  | 
|  | TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult); | 
|  |  | 
|  | if (ppResult != NULL) | 
|  | *ppResult = NULL; | 
|  | if (pStream == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  | if (plStart == NULL || plLength == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit); | 
|  | if (SUCCEEDED(hr) && pEdit != NULL) { | 
|  | hr = IAVIEditStream_Cut(pEdit, plStart, plLength, ppResult); | 
|  |  | 
|  | IAVIEditStream_Release(pEdit); | 
|  | } else | 
|  | hr = AVIERR_UNSUPPORTED; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		EditStreamPaste		(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI EditStreamPaste(PAVISTREAM pDest, LONG *plStart, LONG *plLength, | 
|  | PAVISTREAM pSource, LONG lStart, LONG lEnd) | 
|  | { | 
|  | PAVIEDITSTREAM pEdit = NULL; | 
|  | HRESULT        hr; | 
|  |  | 
|  | TRACE("(%p,%p,%p,%p,%d,%d)\n", pDest, plStart, plLength, | 
|  | pSource, lStart, lEnd); | 
|  |  | 
|  | if (pDest == NULL || pSource == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  | if (plStart == NULL || plLength == NULL || lStart < 0) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | hr = IAVIStream_QueryInterface(pDest, &IID_IAVIEditStream,(LPVOID*)&pEdit); | 
|  | if (SUCCEEDED(hr) && pEdit != NULL) { | 
|  | hr = IAVIEditStream_Paste(pEdit, plStart, plLength, pSource, lStart, lEnd); | 
|  |  | 
|  | IAVIEditStream_Release(pEdit); | 
|  | } else | 
|  | hr = AVIERR_UNSUPPORTED; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		EditStreamSetInfoA	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI EditStreamSetInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi, | 
|  | LONG size) | 
|  | { | 
|  | AVISTREAMINFOW asiw; | 
|  |  | 
|  | TRACE("(%p,%p,%d)\n", pstream, asi, size); | 
|  |  | 
|  | if (size >= 0 && size < sizeof(AVISTREAMINFOA)) | 
|  | return AVIERR_BADSIZE; | 
|  |  | 
|  | memcpy(&asiw, asi, sizeof(asiw) - sizeof(asiw.szName)); | 
|  | MultiByteToWideChar(CP_ACP, 0, asi->szName, -1, | 
|  | asiw.szName, sizeof(asiw.szName)/sizeof(WCHAR)); | 
|  |  | 
|  | return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw)); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		EditStreamSetInfoW	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI EditStreamSetInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi, | 
|  | LONG size) | 
|  | { | 
|  | PAVIEDITSTREAM pEdit = NULL; | 
|  | HRESULT        hr; | 
|  |  | 
|  | TRACE("(%p,%p,%d)\n", pstream, asi, size); | 
|  |  | 
|  | if (size >= 0 && size < sizeof(AVISTREAMINFOA)) | 
|  | return AVIERR_BADSIZE; | 
|  |  | 
|  | hr = IAVIStream_QueryInterface(pstream, &IID_IAVIEditStream,(LPVOID*)&pEdit); | 
|  | if (SUCCEEDED(hr) && pEdit != NULL) { | 
|  | hr = IAVIEditStream_SetInfo(pEdit, asi, size); | 
|  |  | 
|  | IAVIEditStream_Release(pEdit); | 
|  | } else | 
|  | hr = AVIERR_UNSUPPORTED; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		EditStreamSetNameA	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI EditStreamSetNameA(PAVISTREAM pstream, LPCSTR szName) | 
|  | { | 
|  | AVISTREAMINFOA asia; | 
|  | HRESULT        hres; | 
|  |  | 
|  | TRACE("(%p,%s)\n", pstream, debugstr_a(szName)); | 
|  |  | 
|  | if (pstream == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  | if (szName == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | hres = AVIStreamInfoA(pstream, &asia, sizeof(asia)); | 
|  | if (FAILED(hres)) | 
|  | return hres; | 
|  |  | 
|  | memset(asia.szName, 0, sizeof(asia.szName)); | 
|  | lstrcpynA(asia.szName, szName, sizeof(asia.szName)/sizeof(asia.szName[0])); | 
|  |  | 
|  | return EditStreamSetInfoA(pstream, &asia, sizeof(asia)); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		EditStreamSetNameW	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI EditStreamSetNameW(PAVISTREAM pstream, LPCWSTR szName) | 
|  | { | 
|  | AVISTREAMINFOW asiw; | 
|  | HRESULT        hres; | 
|  |  | 
|  | TRACE("(%p,%s)\n", pstream, debugstr_w(szName)); | 
|  |  | 
|  | if (pstream == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  | if (szName == NULL) | 
|  | return AVIERR_BADPARAM; | 
|  |  | 
|  | hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw)); | 
|  | if (FAILED(hres)) | 
|  | return hres; | 
|  |  | 
|  | memset(asiw.szName, 0, sizeof(asiw.szName)); | 
|  | lstrcpynW(asiw.szName, szName, sizeof(asiw.szName)/sizeof(asiw.szName[0])); | 
|  |  | 
|  | return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw)); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIClearClipboard	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIClearClipboard(void) | 
|  | { | 
|  | TRACE("()\n"); | 
|  |  | 
|  | return AVIERR_UNSUPPORTED; /* OleSetClipboard(NULL); */ | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIGetFromClipboard	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIGetFromClipboard(PAVIFILE *ppfile) | 
|  | { | 
|  | FIXME("(%p), stub!\n", ppfile); | 
|  |  | 
|  | *ppfile = NULL; | 
|  |  | 
|  | return AVIERR_UNSUPPORTED; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      AVIMakeStreamFromClipboard (AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIMakeStreamFromClipboard(UINT cfFormat, HANDLE hGlobal, | 
|  | PAVISTREAM * ppstream) | 
|  | { | 
|  | FIXME("(0x%08x,%p,%p), stub!\n", cfFormat, hGlobal, ppstream); | 
|  |  | 
|  | if (ppstream == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | return AVIERR_UNSUPPORTED; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		AVIPutFileOnClipboard	(AVIFIL32.@) | 
|  | */ | 
|  | HRESULT WINAPI AVIPutFileOnClipboard(PAVIFILE pfile) | 
|  | { | 
|  | FIXME("(%p), stub!\n", pfile); | 
|  |  | 
|  | if (pfile == NULL) | 
|  | return AVIERR_BADHANDLE; | 
|  |  | 
|  | return AVIERR_UNSUPPORTED; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPIV AVISaveA(LPCSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback, | 
|  | int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...) | 
|  | { | 
|  | FIXME("(%s,%p,%p,0x%08x,%p,%p), stub!\n", debugstr_a(szFile), pclsidHandler, lpfnCallback, | 
|  | nStreams, pavi, lpOptions); | 
|  |  | 
|  | return AVIERR_UNSUPPORTED; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPIV AVISaveW(LPCWSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback, | 
|  | int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...) | 
|  | { | 
|  | FIXME("(%s,%p,%p,0x%08x,%p,%p), stub!\n", debugstr_w(szFile), pclsidHandler, lpfnCallback, | 
|  | nStreams, pavi, lpOptions); | 
|  |  | 
|  | return AVIERR_UNSUPPORTED; | 
|  | } |