#define COBJMACROS
#define CONST_VTABLE
#include "wine/test.h"
#include "initguid.h"
#include "wingdi.h"
#include "vfw.h"
DEFINE_AVIGUID(CLSID_WAVFile, 0x00020003, 0, 0);
static const CHAR winetest0[] = "winetest0";
static const CHAR winetest1[] = "winetest1";
static const CHAR testfilename[] = "wine_avifil32_test.avi";
static const DWORD deffh[] =
{
FOURCC_RIFF, 0x34c6 , formtypeAVI,
FOURCC_LIST, 0x1ac ,
listtypeAVIHEADER, ckidAVIMAINHDR, sizeof(MainAVIHeader),
};
static const MainAVIHeader defmah =
{
0x00008256,
0x000080e8,
0x00000000,
0x00000910,
1,
0,
2,
0x00100000,
8,
6,
{ 0, 0, 0, 0 }
};
static const AVIStreamHeader defash0 =
{
streamtypeVIDEO,
0x30323449,
0x00000000,
0,
0,
0,
0x000003e9,
0x00007530,
0,
1,
0x00100000,
0xffffffff,
0,
{ 0, 0, 0, 0 }
};
static const AVIStreamHeader defash1 =
{
streamtypeAUDIO,
1,
0,
0,
0,
0,
1,
0x00002b11,
0,
0x00000665,
0x00003000,
0xffffffff,
2,
{ 0, 0, 0, 0 }
};
static const PCMWAVEFORMAT defpcmwf =
{
{
1,
2,
11025,
22050,
2,
},
8,
};
typedef struct common_avi_headers {
DWORD fh[sizeof(deffh)];
MainAVIHeader mah;
AVIStreamHeader ash0;
AVIStreamHeader ash1;
PCMWAVEFORMAT pcmwf;
} COMMON_AVI_HEADERS;
static const DWORD streamlist[] =
{
FOURCC_LIST, 0xd4 ,
listtypeSTREAMHEADER, ckidSTREAMHEADER, 0x38 ,
};
static const DWORD videostreamformat[] =
{
ckidSTREAMFORMAT, 0x28 ,
0x00000028, 0x00000008, 0x00000006, 0x00180001,
0x30323449, 0x00000090, 0x00000000, 0x00000000,
0x00000000, 0x00000000,
};
static const DWORD padding1[] =
{
ckidAVIPADDING, 0xc ,
0x00000004, 0x00000000, 0x63643030
};
static const DWORD videopropheader[] =
{
0x70727076, 0x44 ,
0x00000000, 0x00000000,
0x0000001e, 0x00000008, 0x00000006, 0x00100009,
0x00000008, 0x00000006, 0x00000001, 0x00000006,
0x00000008, 0x00000006, 0x00000008, 0x00000000,
0x00000000, 0x00000000, 0x00000000,
FOURCC_LIST, 0x70 ,
listtypeSTREAMHEADER, ckidSTREAMHEADER, 0x38 ,
};
static const DWORD audiostreamformat_pre[] =
{
ckidSTREAMFORMAT, sizeof(PCMWAVEFORMAT) ,
};
static DWORD data[] =
{
ckidAVIPADDING, 0xc ,
0x00000004, 0x00000000, 0x62773130,
ckidAVIPADDING, 0xc ,
0x6c6d646f, 0x686c6d64, 0x000000f8,
FOURCC_LIST, 0x18 ,
0x4f464e49,
0x54465349, 0xc ,
0x6676614c, 0x332e3235, 0x00302e37,
ckidAVIPADDING, 0x4 ,
0,
FOURCC_LIST, 0xd1b , listtypeAVIMOVIE,
0, 0
};
static void test_AVISaveOptions(void)
{
AVICOMPRESSOPTIONS options[2];
LPAVICOMPRESSOPTIONS poptions[2];
PAVISTREAM streams[2] = {NULL, NULL};
HRESULT hres;
DWORD res;
LONG lres;
poptions[0] = &options[0];
poptions[1] = &options[1];
ZeroMemory(options, sizeof(options));
SetLastError(0xdeadbeef);
hres = CreateEditableStream(&streams[0], NULL);
ok(hres == AVIERR_OK, "0: got 0x%lx and %p (expected AVIERR_OK)\n", hres, streams[0]);
SetLastError(0xdeadbeef);
hres = CreateEditableStream(&streams[1], NULL);
ok(hres == AVIERR_OK, "1: got 0x%lx and %p (expected AVIERR_OK)\n", hres, streams[1]);
SetLastError(0xdeadbeef);
hres = EditStreamSetNameA(streams[0], winetest0);
ok(hres == AVIERR_OK, "0: got 0x%lx (expected AVIERR_OK)\n", hres);
SetLastError(0xdeadbeef);
hres = EditStreamSetNameA(streams[1], winetest1);
ok(hres == AVIERR_OK, "1: got 0x%lx (expected AVIERR_OK)\n", hres);
if (winetest_interactive) {
SetLastError(0xdeadbeef);
res = AVISaveOptions(0, ICMF_CHOOSE_DATARATE |ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_ALLCOMPRESSORS,
2, streams, poptions);
trace("got %lu with 0x%lx/%lu\n", res, GetLastError(), GetLastError());
}
SetLastError(0xdeadbeef);
lres = AVISaveOptionsFree(2, poptions);
ok(lres == AVIERR_OK, "got 0x%lx with 0x%lx/%lu\n", lres, GetLastError(), GetLastError());
SetLastError(0xdeadbeef);
res = AVIStreamRelease(streams[0]);
ok(res == 0, "0: got refcount %lu (expected 0)\n", res);
SetLastError(0xdeadbeef);
res = AVIStreamRelease(streams[1]);
ok(res == 0, "1: got refcount %lu (expected 0)\n", res);
}
static void test_EditStreamSetInfo(void)
{
PAVISTREAM stream = NULL;
HRESULT hres;
AVISTREAMINFOA info, info2;
hres = CreateEditableStream(&stream, NULL);
ok(hres == AVIERR_OK, "got 0x%08lX, expected AVIERR_OK\n", hres);
hres = EditStreamSetInfoA(stream, NULL, 0);
ok( hres == AVIERR_BADSIZE, "got 0x%08lX, expected AVIERR_BADSIZE\n", hres);
hres = EditStreamSetInfoA(stream, NULL, sizeof(AVISTREAMINFOA)-1 );
ok( hres == AVIERR_BADSIZE, "got 0x%08lX, expected AVIERR_BADSIZE\n", hres);
if(0)
{
EditStreamSetInfoA(NULL, &info, sizeof(info) );
EditStreamSetInfoA(stream, NULL, sizeof(AVISTREAMINFOA) );
EditStreamSetInfoA(stream, NULL, -1);
}
hres = AVIStreamInfoA(stream, &info, sizeof(info) );
ok( hres == 0, "got 0x%08lX, expected 0\n", hres);
#define IS_INFO_UPDATED(m) do { \
hres = EditStreamSetInfoA(stream, &info, sizeof(info) ); \
ok( hres == 0, "got 0x%08lX, expected 0\n", hres); \
hres = AVIStreamInfoA(stream, &info2, sizeof(info2) ); \
ok( hres == 0, "got 0x%08lX, expected 0\n", hres); \
ok( info2.m == info.m, "EditStreamSetInfo did not update "#m" parameter\n" ); \
} while(0)
info.dwStart++;
IS_INFO_UPDATED(dwStart);
info.dwStart = 0;
IS_INFO_UPDATED(dwStart);
info.wPriority++;
IS_INFO_UPDATED(wPriority);
info.wPriority = 0;
IS_INFO_UPDATED(wPriority);
info.wLanguage++;
IS_INFO_UPDATED(wLanguage);
info.wLanguage = 0;
IS_INFO_UPDATED(wLanguage);
info.dwScale++;
IS_INFO_UPDATED(dwScale);
info.dwScale = 0;
IS_INFO_UPDATED(dwScale);
info.dwRate++;
IS_INFO_UPDATED(dwRate);
info.dwRate = 0;
IS_INFO_UPDATED(dwRate);
info.dwQuality++;
IS_INFO_UPDATED(dwQuality);
info.dwQuality = 0;
IS_INFO_UPDATED(dwQuality);
info.dwQuality = -2;
IS_INFO_UPDATED(dwQuality);
info.dwQuality = ICQUALITY_HIGH+1;
IS_INFO_UPDATED(dwQuality);
info.rcFrame.left = 0;
IS_INFO_UPDATED(rcFrame.left);
info.rcFrame.top = 0;
IS_INFO_UPDATED(rcFrame.top);
info.rcFrame.right = 0;
IS_INFO_UPDATED(rcFrame.right);
info.rcFrame.bottom = 0;
IS_INFO_UPDATED(rcFrame.bottom);
info.rcFrame.left = -1;
IS_INFO_UPDATED(rcFrame.left);
info.rcFrame.top = -1;
IS_INFO_UPDATED(rcFrame.top);
info.rcFrame.right = -1;
IS_INFO_UPDATED(rcFrame.right);
info.rcFrame.bottom = -1;
IS_INFO_UPDATED(rcFrame.bottom);
AVIStreamRelease(stream);
#undef IS_INFO_UPDATED
}
static void init_test_struct(COMMON_AVI_HEADERS *cah)
{
memcpy(cah->fh, deffh, sizeof(deffh));
cah->mah = defmah;
cah->ash0 = defash0;
cah->ash1 = defash1;
cah->pcmwf = defpcmwf;
}
static void create_avi_file(const COMMON_AVI_HEADERS *cah, char *filename)
{
HANDLE hFile;
DWORD written;
hFile = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
ok(hFile != INVALID_HANDLE_VALUE, "Couldn't create file\n");
WriteFile(hFile, &cah->fh, sizeof(deffh), &written, NULL);
WriteFile(hFile, &cah->mah, sizeof(MainAVIHeader), &written, NULL);
WriteFile(hFile, streamlist, sizeof(streamlist), &written, NULL);
WriteFile(hFile, &cah->ash0, 0x38, &written, NULL);
WriteFile(hFile, videostreamformat, sizeof(videostreamformat), &written, NULL);
WriteFile(hFile, padding1, sizeof(padding1), &written, NULL);
WriteFile(hFile, videopropheader, sizeof(videopropheader), &written, NULL);
WriteFile(hFile, &cah->ash1, 0x38, &written, NULL);
WriteFile(hFile, audiostreamformat_pre, sizeof(audiostreamformat_pre), &written, NULL);
WriteFile(hFile, &cah->pcmwf, sizeof(PCMWAVEFORMAT), &written, NULL);
WriteFile(hFile, data, sizeof(data), &written, NULL);
CloseHandle(hFile);
}
static ULONG get_file_refcount(PAVIFILE file)
{
AVIFileAddRef(file);
return AVIFileRelease(file);
}
static void test_default_data(void)
{
COMMON_AVI_HEADERS cah;
char filename[MAX_PATH];
PAVIFILE pFile;
int res;
LONG lSize;
PAVISTREAM pStream0;
PAVISTREAM pStream1;
AVISTREAMINFOA asi0, asi1;
WAVEFORMATEX wfx;
ULONG refcount;
GetTempPathA(MAX_PATH, filename);
strcpy(filename+strlen(filename), testfilename);
init_test_struct(&cah);
create_avi_file(&cah, filename);
res = AVIFileOpenA(&pFile, filename, OF_SHARE_DENY_WRITE, 0L);
ok(res == 0, "Unable to open file: error=%u\n", res);
pStream0 = (void *)0xdeadbeef;
res = AVIFileGetStream(pFile, &pStream0, ~0U, 0);
ok(res == AVIERR_NODATA, "expected AVIERR_NODATA, got %u\n", res);
ok(pStream0 == NULL, "AVIFileGetStream should set stream to NULL\n");
res = AVIFileGetStream(pFile, &pStream0, 0, 0);
ok(res == 0, "Unable to open video stream: error=%u\n", res);
res = AVIFileGetStream(pFile, &pStream1, 0, 1);
ok(res == 0, "Unable to open audio stream: error=%u\n", res);
res = AVIStreamInfoA(pStream0, &asi0, sizeof(asi0));
ok(res == 0, "Unable to read stream info: error=%u\n", res);
res = AVIStreamInfoA(pStream1, &asi1, sizeof(asi1));
ok(res == 0, "Unable to read stream info: error=%u\n", res);
res = AVIStreamReadFormat(pStream0, AVIStreamStart(pStream1), NULL, &lSize);
ok(res == 0, "Unable to read format size: error=%u\n", res);
res = AVIStreamReadFormat(pStream1, AVIStreamStart(pStream1), &wfx, &lSize);
ok(res == 0, "Unable to read format: error=%u\n", res);
ok(asi0.fccType == streamtypeVIDEO, "got 0x%lx (expected streamtypeVIDEO)\n", asi0.fccType);
ok(asi0.fccHandler == 0x30323449, "got 0x%lx (expected 0x30323449)\n", asi0.fccHandler);
ok(asi0.dwFlags == 0, "got %lu (expected 0)\n", asi0.dwFlags);
ok(asi0.wPriority == 0, "got %u (expected 0)\n", asi0.wPriority);
ok(asi0.wLanguage == 0, "got %u (expected 0)\n", asi0.wLanguage);
ok(asi0.dwScale == 1001, "got %lu (expected 1001)\n", asi0.dwScale);
ok(asi0.dwRate == 30000, "got %lu (expected 30000)\n", asi0.dwRate);
ok(asi0.dwStart == 0, "got %lu (expected 0)\n", asi0.dwStart);
ok(asi0.dwLength == 1, "got %lu (expected 1)\n", asi0.dwLength);
ok(asi0.dwInitialFrames == 0, "got %lu (expected 0)\n", asi0.dwInitialFrames);
ok(asi0.dwSuggestedBufferSize == 0, "got %lu (expected 0)\n", asi0.dwSuggestedBufferSize);
ok(asi0.dwQuality == 0xffffffff, "got 0x%lx (expected 0xffffffff)\n", asi0.dwQuality);
ok(asi0.dwSampleSize == 0, "got %lu (expected 0)\n", asi0.dwSampleSize);
ok(asi0.rcFrame.left == 0, "got %lu (expected 0)\n", asi0.rcFrame.left);
ok(asi0.rcFrame.top == 0, "got %lu (expected 0)\n", asi0.rcFrame.top);
ok(asi0.rcFrame.right == 8, "got %lu (expected 8)\n", asi0.rcFrame.right);
ok(asi0.rcFrame.bottom == 6, "got %lu (expected 6)\n", asi0.rcFrame.bottom);
ok(asi0.dwEditCount == 0, "got %lu (expected 0)\n", asi0.dwEditCount);
ok(asi0.dwFormatChangeCount == 0, "got %lu (expected 0)\n", asi0.dwFormatChangeCount);
ok(asi1.fccType == streamtypeAUDIO, "got 0x%lx (expected streamtypeVIDEO)\n", asi1.fccType);
ok(asi1.fccHandler == 0x1, "got 0x%lx (expected 0x1)\n", asi1.fccHandler);
ok(asi1.dwFlags == 0, "got %lu (expected 0)\n", asi1.dwFlags);
ok(asi1.wPriority == 0, "got %u (expected 0)\n", asi1.wPriority);
ok(asi1.wLanguage == 0, "got %u (expected 0)\n", asi1.wLanguage);
ok(asi1.dwScale == 1, "got %lu (expected 1)\n", asi1.dwScale);
ok(asi1.dwRate == 11025, "got %lu (expected 11025)\n", asi1.dwRate);
ok(asi1.dwStart == 0, "got %lu (expected 0)\n", asi1.dwStart);
ok(asi1.dwLength == 1637, "got %lu (expected 1637)\n", asi1.dwLength);
ok(asi1.dwInitialFrames == 0, "got %lu (expected 0)\n", asi1.dwInitialFrames);
ok(asi1.dwSuggestedBufferSize == 0, "got %lu (expected 0)\n", asi1.dwSuggestedBufferSize);
ok(asi1.dwQuality == 0xffffffff, "got 0x%lx (expected 0xffffffff)\n", asi1.dwQuality);
ok(asi1.dwSampleSize == 2, "got %lu (expected 2)\n", asi1.dwSampleSize);
ok(asi1.rcFrame.left == 0, "got %lu (expected 0)\n", asi1.rcFrame.left);
ok(asi1.rcFrame.top == 0, "got %lu (expected 0)\n", asi1.rcFrame.top);
ok(asi1.rcFrame.right == 0, "got %lu (expected 0)\n", asi1.rcFrame.right);
ok(asi1.rcFrame.bottom == 0, "got %lu (expected 0)\n", asi1.rcFrame.bottom);
ok(asi1.dwEditCount == 0, "got %lu (expected 0)\n", asi1.dwEditCount);
ok(asi1.dwFormatChangeCount == 0, "got %lu (expected 0)\n", asi1.dwFormatChangeCount);
ok(wfx.wFormatTag == 1, "got %u (expected 1)\n",wfx.wFormatTag);
ok(wfx.nChannels == 2, "got %u (expected 2)\n",wfx.nChannels);
ok(wfx.wFormatTag == 1, "got %u (expected 1)\n",wfx.wFormatTag);
ok(wfx.nSamplesPerSec == 11025, "got %lu (expected 11025)\n",wfx.nSamplesPerSec);
ok(wfx.nAvgBytesPerSec == 22050, "got %lu (expected 22050)\n",wfx.nAvgBytesPerSec);
ok(wfx.nBlockAlign == 2, "got %u (expected 2)\n",wfx.nBlockAlign);
refcount = get_file_refcount(pFile);
ok(refcount == 3, "got %lu (expected 3)\n", refcount);
AVIStreamRelease(pStream0);
refcount = get_file_refcount(pFile);
ok(refcount == 2, "got %lu (expected 2)\n", refcount);
AVIStreamAddRef(pStream1);
refcount = get_file_refcount(pFile);
ok(refcount == 2, "got %lu (expected 2)\n", refcount);
AVIStreamRelease(pStream1);
AVIStreamRelease(pStream1);
refcount = get_file_refcount(pFile);
ok(refcount == 1, "got %lu (expected 1)\n", refcount);
refcount = AVIStreamRelease(pStream1);
ok(refcount == (ULONG)-1, "got %lu (expected 4294967295)\n", refcount);
refcount = get_file_refcount(pFile);
ok(refcount == 1, "got %lu (expected 1)\n", refcount);
refcount = AVIFileRelease(pFile);
ok(refcount == 0, "got %lu (expected 0)\n", refcount);
ok(DeleteFileA(filename) !=0, "Deleting file %s failed\n", filename);
}
static void test_amh_corruption(void)
{
COMMON_AVI_HEADERS cah;
char filename[MAX_PATH];
PAVIFILE pFile;
int res;
GetTempPathA(MAX_PATH, filename);
strcpy(filename+strlen(filename), testfilename);
init_test_struct(&cah);
cah.fh[3] = mmioFOURCC('A', 'V', 'i', ' ');
create_avi_file(&cah, filename);
res = AVIFileOpenA(&pFile, filename, OF_SHARE_DENY_WRITE, 0L);
ok(res != 0, "Able to open file: error=%u\n", res);
ok(DeleteFileA(filename) !=0, "Deleting file %s failed\n", filename);
}
static void test_ash1_corruption(void)
{
COMMON_AVI_HEADERS cah;
char filename[MAX_PATH];
PAVIFILE pFile;
int res;
PAVISTREAM pStream1;
AVISTREAMINFOA asi1;
GetTempPathA(MAX_PATH, filename);
strcpy(filename+strlen(filename), testfilename);
init_test_struct(&cah);
cah.ash1.dwSampleSize = 0xdeadbeef;
create_avi_file(&cah, filename);
res = AVIFileOpenA(&pFile, filename, OF_SHARE_DENY_WRITE, 0L);
ok(res == 0, "Unable to open file: error=%u\n", res);
res = AVIFileGetStream(pFile, &pStream1, 0, 1);
ok(res == 0, "Unable to open audio stream: error=%u\n", res);
res = AVIStreamInfoA(pStream1, &asi1, sizeof(asi1));
ok(res == 0, "Unable to read stream info: error=%u\n", res);
ok(asi1.dwSampleSize == 2, "got %lu (expected 2)\n", asi1.dwSampleSize);
AVIStreamRelease(pStream1);
AVIFileRelease(pFile);
ok(DeleteFileA(filename) !=0, "Deleting file %s failed\n", filename);
}
static void test_ash1_corruption2(void)
{
COMMON_AVI_HEADERS cah;
char filename[MAX_PATH];
PAVIFILE pFile;
int res;
PAVISTREAM pStream1;
AVISTREAMINFOA asi1;
GetTempPathA(MAX_PATH, filename);
strcpy(filename+strlen(filename), testfilename);
init_test_struct(&cah);
cah.pcmwf.wf.nBlockAlign = 0xdead;
create_avi_file(&cah, filename);
res = AVIFileOpenA(&pFile, filename, OF_SHARE_DENY_WRITE, 0L);
ok(res == 0, "Unable to open file: error=%u\n", res);
res = AVIFileGetStream(pFile, &pStream1, 0, 1);
ok(res == 0, "Unable to open audio stream: error=%u\n", res);
ok(AVIStreamInfoA(pStream1, &asi1, sizeof(asi1)) == 0, "Unable to read stream info\n");
ok(asi1.dwSampleSize == 0xdead, "got 0x%lx (expected 0xdead)\n", asi1.dwSampleSize);
AVIStreamRelease(pStream1);
AVIFileRelease(pFile);
ok(DeleteFileA(filename) !=0, "Deleting file %s failed\n", filename);
}
struct unk_impl {
IUnknown IUnknown_iface;
LONG ref;
IUnknown *inner_unk;
};
static inline struct unk_impl *impl_from_IUnknown(IUnknown *iface)
{
return CONTAINING_RECORD(iface, struct unk_impl, IUnknown_iface);
}
static HRESULT WINAPI unk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
{
struct unk_impl *This = impl_from_IUnknown(iface);
LONG ref = This->ref;
HRESULT hr;
if (IsEqualGUID(riid, &IID_IUnknown))
{
*ppv = iface;
IUnknown_AddRef(iface);
return S_OK;
}
hr = IUnknown_QueryInterface(This->inner_unk, riid, ppv);
if (hr == S_OK)
{
trace("Working around COM aggregation ref counting bug\n");
ok(ref == This->ref, "Outer ref count expected %ld got %ld\n", ref, This->ref);
IUnknown_AddRef((IUnknown*)*ppv);
ref = IUnknown_Release(This->inner_unk);
ok(ref == 1, "Inner ref count expected 1 got %ld\n", ref);
}
return hr;
}
static ULONG WINAPI unk_AddRef(IUnknown *iface)
{
struct unk_impl *This = impl_from_IUnknown(iface);
return InterlockedIncrement(&This->ref);
}
static ULONG WINAPI unk_Release(IUnknown *iface)
{
struct unk_impl *This = impl_from_IUnknown(iface);
return InterlockedDecrement(&This->ref);
}
static const IUnknownVtbl unk_vtbl =
{
unk_QueryInterface,
unk_AddRef,
unk_Release
};
static void test_COM(void)
{
struct unk_impl unk_obj = {{&unk_vtbl}, 19, NULL};
IAVIFile *avif = NULL;
IPersistFile *pf;
IUnknown *unk;
LONG refcount;
HRESULT hr;
hr = CoCreateInstance(&CLSID_AVIFile, &unk_obj.IUnknown_iface, CLSCTX_INPROC_SERVER,
&IID_IUnknown, (void**)&unk_obj.inner_unk);
ok(hr == S_OK, "COM aggregation failed: %08lx, expected S_OK\n", hr);
hr = IUnknown_QueryInterface(&unk_obj.IUnknown_iface, &IID_IAVIFile, (void**)&avif);
ok(hr == S_OK, "QueryInterface for IID_IAVIFile failed: %08lx\n", hr);
refcount = IAVIFile_AddRef(avif);
ok(refcount == unk_obj.ref, "AVIFile just pretends to support COM aggregation\n");
refcount = IAVIFile_Release(avif);
ok(refcount == unk_obj.ref, "AVIFile just pretends to support COM aggregation\n");
hr = IAVIFile_QueryInterface(avif, &IID_IPersistFile, (void**)&pf);
ok(hr == S_OK, "QueryInterface for IID_IPersistFile failed: %08lx\n", hr);
refcount = IPersistFile_Release(pf);
ok(refcount == unk_obj.ref, "AVIFile just pretends to support COM aggregation\n");
refcount = IAVIFile_Release(avif);
ok(refcount == 19, "Outer ref count should be back at 19 but is %ld\n", refcount);
refcount = IUnknown_Release(unk_obj.inner_unk);
ok(refcount == 0, "Inner ref count should be 0 but is %lu\n", refcount);
hr = CoCreateInstance(&CLSID_AVIFile, NULL, CLSCTX_INPROC_SERVER, &IID_IAVIStream,
(void**)&avif);
ok(hr == E_NOINTERFACE, "AVIFile create failed: %08lx, expected E_NOINTERFACE\n", hr);
hr = CoCreateInstance(&CLSID_AVIFile, NULL, CLSCTX_INPROC_SERVER, &IID_IAVIFile, (void**)&avif);
ok(hr == S_OK, "AVIFile create failed: %08lx, expected S_OK\n", hr);
refcount = IAVIFile_AddRef(avif);
ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
hr = IAVIFile_QueryInterface(avif, &IID_IUnknown, (void**)&unk);
ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %08lx\n", hr);
refcount = IUnknown_AddRef(unk);
ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
hr = IAVIFile_QueryInterface(avif, &IID_IPersistFile, (void**)&pf);
ok(hr == S_OK, "QueryInterface for IID_IPersistFile failed: %08lx\n", hr);
refcount = IPersistFile_AddRef(pf);
ok(refcount == 6, "refcount == %lu, expected 6\n", refcount);
while (IAVIFile_Release(avif));
}
static void test_COM_wavfile(void)
{
struct unk_impl unk_obj = {{&unk_vtbl}, 19, NULL};
IAVIFile *avif = NULL;
IPersistFile *pf;
IAVIStream *avis;
IUnknown *unk;
ULONG refcount;
HRESULT hr;
hr = CoCreateInstance(&CLSID_WAVFile, &unk_obj.IUnknown_iface, CLSCTX_INPROC_SERVER,
&IID_IUnknown, (void**)&unk_obj.inner_unk);
ok(hr == S_OK, "COM aggregation failed: %08lx, expected S_OK\n", hr);
hr = IUnknown_QueryInterface(&unk_obj.IUnknown_iface, &IID_IAVIFile, (void**)&avif);
ok(hr == S_OK, "QueryInterface for IID_IAVIFile failed: %08lx\n", hr);
refcount = IAVIFile_AddRef(avif);
ok(refcount == unk_obj.ref, "WAVFile just pretends to support COM aggregation\n");
refcount = IAVIFile_Release(avif);
ok(refcount == unk_obj.ref, "WAVFile just pretends to support COM aggregation\n");
hr = IAVIFile_QueryInterface(avif, &IID_IPersistFile, (void**)&pf);
ok(hr == S_OK, "QueryInterface for IID_IPersistFile failed: %08lx\n", hr);
refcount = IPersistFile_Release(pf);
ok(refcount == unk_obj.ref, "WAVFile just pretends to support COM aggregation\n");
refcount = IAVIFile_Release(avif);
ok(refcount == 19, "Outer ref count should be back at 19 but is %ld\n", refcount);
refcount = IUnknown_Release(unk_obj.inner_unk);
ok(refcount == 0, "Inner ref count should be 0 but is %lu\n", refcount);
hr = CoCreateInstance(&CLSID_WAVFile, NULL, CLSCTX_INPROC_SERVER, &IID_IAVIStreaming,
(void**)&avif);
ok(hr == E_NOINTERFACE, "WAVFile create failed: %08lx, expected E_NOINTERFACE\n", hr);
hr = CoCreateInstance(&CLSID_WAVFile, NULL, CLSCTX_INPROC_SERVER, &IID_IAVIFile, (void**)&avif);
ok(hr == S_OK, "WAVFile create failed: %08lx, expected S_OK\n", hr);
refcount = IAVIFile_AddRef(avif);
ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
hr = IAVIFile_QueryInterface(avif, &IID_IPersistFile, (void**)&pf);
ok(hr == S_OK, "QueryInterface for IID_IPersistFile failed: %08lx\n", hr);
refcount = IPersistFile_AddRef(pf);
ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
refcount = IPersistFile_Release(pf);
hr = IAVIFile_QueryInterface(avif, &IID_IAVIStream, (void**)&avis);
ok(hr == S_OK, "QueryInterface for IID_IAVIStream failed: %08lx\n", hr);
refcount = IAVIStream_AddRef(avis);
ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
refcount = IAVIStream_Release(avis);
hr = IAVIFile_QueryInterface(avif, &IID_IUnknown, (void**)&unk);
ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %08lx\n", hr);
refcount = IUnknown_AddRef(unk);
ok(refcount == 6, "refcount == %lu, expected 6\n", refcount);
refcount = IUnknown_Release(unk);
while (IAVIFile_Release(avif));
}
static void test_COM_editstream(void)
{
IAVIEditStream *edit;
IAVIStream *stream;
IUnknown *unk;
ULONG refcount;
HRESULT hr;
hr = CreateEditableStream(&stream, NULL);
ok(hr == S_OK, "AVIEditStream create failed: %08lx, expected S_OK\n", hr);
refcount = IAVIStream_AddRef(stream);
ok(refcount == 2, "refcount == %lu, expected 2\n", refcount);
hr = IAVIStream_QueryInterface(stream, &IID_IAVIEditStream, (void**)&edit);
ok(hr == S_OK, "QueryInterface for IID_IAVIEditStream failed: %08lx\n", hr);
refcount = IAVIEditStream_AddRef(edit);
ok(refcount == 4, "refcount == %lu, expected 4\n", refcount);
refcount = IAVIEditStream_Release(edit);
hr = IAVIEditStream_QueryInterface(edit, &IID_IUnknown, (void**)&unk);
ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %08lx\n", hr);
refcount = IUnknown_AddRef(unk);
ok(refcount == 5, "refcount == %lu, expected 5\n", refcount);
IUnknown_Release(unk);
while (IAVIEditStream_Release(edit));
}
static void test_avifile_write(void)
{
WCHAR fn[MAX_PATH];
IPersistFile *persist;
PCMWAVEFORMAT afmt;
AVISTREAMINFOW si;
USHORT buffer[64];
PAVIFILE avifile;
PAVISTREAM stm;
HRESULT hr;
BOOL ret;
GetTempPathW(MAX_PATH, fn);
wcscat(fn, L"test.avi");
hr = CoCreateInstance(&CLSID_AVIFile, NULL, CLSCTX_INPROC, &IID_IAVIFile, (void **)&avifile);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IAVIFile_QueryInterface(avifile, &IID_IPersistFile, (void **)&persist);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IPersistFile_Load(persist, fn, STGM_CREATE);
ok(hr == S_OK, "got %#lx.\n", hr);
memset(&si, 0, sizeof(si));
si.fccType = streamtypeAUDIO;
si.dwScale = 1;
si.dwRate = 48000;
si.dwLength = 4;
si.dwQuality = ~0u;
si.dwSampleSize = 4;
hr = IAVIFile_CreateStream(avifile, &stm, &si);
ok(hr == AVIERR_READONLY, "got %#lx.\n", hr);
IPersistFile_Release(persist);
IAVIFile_Release(avifile);
ret = DeleteFileW(fn);
ok(ret, "got error %lu.\n", GetLastError());
hr = AVIFileOpenW(&avifile, fn, OF_CREATE, NULL);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = AVIFileCreateStreamW(avifile, &stm, &si);
ok(hr == S_OK, "got %#lx.\n", hr);
memset(&afmt, 0, sizeof(afmt));
afmt.wBitsPerSample = 16;
afmt.wf.wFormatTag = WAVE_FORMAT_PCM;
afmt.wf.nChannels = 2;
afmt.wf.nSamplesPerSec = 44800;
afmt.wf.nAvgBytesPerSec = afmt.wf.nSamplesPerSec * afmt.wf.nChannels;
afmt.wf.nBlockAlign = afmt.wf.nChannels * 2;
hr = AVIStreamSetFormat(stm, 0, &afmt, sizeof(afmt));
ok(hr == S_OK, "got %#lx.\n", hr);
memset(buffer, 0xcc, sizeof(buffer));
hr = IAVIStream_Info(stm, &si, sizeof(si));
ok(hr == S_OK, "got %#lx.\n", hr);
ok(!si.dwLength, "got %lu.\n", si.dwLength);
ok(!si.dwStart, "got %lu.\n", si.dwStart);
ok(!si.dwSuggestedBufferSize, "got %lu.\n", si.dwSuggestedBufferSize);
hr = AVIStreamWrite(stm, 0, 2, buffer, si.dwSampleSize * 2, 0, NULL, NULL);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IAVIStream_Info(stm, &si, sizeof(si));
ok(hr == S_OK, "got %#lx.\n", hr);
ok(si.dwLength == 2, "got %lu.\n", si.dwLength);
ok(!si.dwStart, "got %lu.\n", si.dwStart);
ok(si.dwSuggestedBufferSize == 8, "got %lu.\n", si.dwSuggestedBufferSize);
hr = AVIStreamWrite(stm, 2, 2, buffer, si.dwSampleSize * 2, 0, NULL, NULL);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IAVIStream_Info(stm, &si, sizeof(si));
ok(hr == S_OK, "got %#lx.\n", hr);
ok(si.dwLength == 4, "got %lu.\n", si.dwLength);
ok(!si.dwStart, "got %lu.\n", si.dwStart);
ok(si.dwSuggestedBufferSize == 8, "got %lu.\n", si.dwSuggestedBufferSize);
hr = AVIStreamWrite(stm, 4, 4, buffer, si.dwSampleSize * 4, 0, NULL, NULL);
ok(hr == S_OK, "got %#lx.\n", hr);
hr = IAVIStream_Info(stm, &si, sizeof(si));
ok(hr == S_OK, "got %#lx.\n", hr);
ok(si.dwLength == 8, "got %lu.\n", si.dwLength);
ok(!si.dwStart, "got %lu.\n", si.dwStart);
ok(si.dwSuggestedBufferSize == 16, "got %lu.\n", si.dwSuggestedBufferSize);
IAVIStream_Release(stm);
IAVIFile_Release(avifile);
ret = DeleteFileW(fn);
ok(ret, "got error %lu.\n", GetLastError());
}
START_TEST(api)
{
AVIFileInit();
test_EditStreamSetInfo();
test_AVISaveOptions();
test_default_data();
test_amh_corruption();
test_ash1_corruption();
test_ash1_corruption2();
test_COM();
test_COM_wavfile();
test_COM_editstream();
test_avifile_write();
AVIFileExit();
}