wine/dlls/msvfw32/tests/mciwnd.c
Alexandros Frantzis 97e018f9a5 msvfw32: Use window name to determine if window is created using MCIWndCreate.
The current version of the code incorrectly assumes that the lpszClass
member of CREATESTRUCT passed with WM_CREATE will point to the same
memory used for the CreateWindowEx class name parameter. MCIWND_Create
uses this assumption to perform a pointer comparison on the class name
to determine whether the MCI window is being created using
MCIWndCreateA/W and should therefore expect a unicode path parameter.

As a side effect of commit e41c255be6
"win32u: Use send_message_timeout for WM_CREATE and WM_NCCREATE" the
CREATESTRUCT lpszClass member started pointing to different memory,
breaking the current implementation of MCIWND_Create().

This commit fixes the problem by changing MCIWndCreateA/W to use an
internal window name, unlikely to be used by normal applications, which
can then be checked in MCIWND_Create to determine if the MCI window is
being created using MCIWndCreateA/W.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53578
2022-09-05 18:53:06 +02:00

324 lines
11 KiB
C

/*
* Unit tests for MCIWnd
*
* Copyright 2019 Sven Baars
*
* 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
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <vfw.h>
#include "wine/heap.h"
#include "wine/test.h"
static const DWORD file_header[] = /* file_header */
{
FOURCC_RIFF, 0x8c0 /* file size */,
formtypeAVI,
FOURCC_LIST, 0xc0 /* list length */,
listtypeAVIHEADER, ckidAVIMAINHDR, sizeof(MainAVIHeader),
};
static const MainAVIHeader main_avi_header =
{
0x0001046b, /* dwMicroSecPerFrame */
0x00000000, /* dwMaxBytesPerSec */
0x00000000, /* dwPaddingGranularity */
0x00000810, /* dwFlags */
2, /* dwTotalFrames */
0, /* dwInitialFrames */
1, /* dwStreams */
0x48, /* dwSuggestedBufferSize*/
5, /* dwWidth */
5, /* dwHeight */
{ 0, 0, 0, 0 } /* dwReserved[4] */
};
static const DWORD stream_list[] =
{
FOURCC_LIST, 0x74 /* length */,
listtypeSTREAMHEADER, ckidSTREAMHEADER, 0x38 /* length */,
};
static const AVIStreamHeader avi_stream_header =
{
streamtypeVIDEO, /* fccType */
0, /* fccHandler */
0, /* dwFlags */
0, /* wPriority */
0, /* wLanguage */
0, /* dwInitialFrames */
1, /* dwScale */
0xf, /* dwRate */
0, /* dwStart */
2, /* dwLength */
0x48, /* dwSuggestedBufferSize*/
0, /* dwQuality */
0, /* dwSampleSize */
{ 0, 0, 0, 0 } /* short left right top bottom */
};
static const DWORD video_stream_format[] =
{
ckidSTREAMFORMAT,
0x28 /* length */,
0x28 /* length */,
5 /* width */,
5 /* height */,
0x00180001 ,
mmioFOURCC('c', 'v', 'i', 'd'),
0x245a,
0, 0, 0, 0,
};
static const DWORD padding[] =
{
ckidAVIPADDING, 0x718 /* length */,
};
static const DWORD data[] =
{
FOURCC_LIST, 0xa4 /* length */, listtypeAVIMOVIE,
mmioFOURCC('0', '0', 'd', 'b'), 0x48, 0x48000000, 0x08000800,
0x00100100, 0x00003e00, 0x08000000, 0x00200800,
0x00001600, 0x00000000, 0x00003a00, 0x22e306f9,
0xfc120000, 0x0a000022, 0x00000000, 0x00300000,
0x00c01200, 0x00000000, 0x02010000, 0x00000000,
mmioFOURCC('0', '0', 'd', 'b'), 0x48, 0x48000000, 0x08000800,
0x00100100, 0x00003e00, 0x08000000, 0x00200800,
0x00001600, 0x00000000, 0x00003a00, 0x22e306f9,
0xfc120000, 0x0a000022, 0x00000000, 0x00300000,
0x00c01200, 0x00000000, 0x02010000, 0x00000000,
mmioFOURCC('i', 'd', 'x', '1'), 0x20, mmioFOURCC('0', '0', 'd', 'b'), 0x10,
0x04, 0x48, mmioFOURCC('0', '0', 'd', 'b'), 0x10,
0x54, 0x48,
};
static BOOL create_avi_file(char *fname)
{
HANDLE hFile;
DWORD written;
char temp_path[MAX_PATH];
BOOL ret;
BYTE *buffer;
ULONG buffer_length;
ret = GetTempPathA(sizeof(temp_path), temp_path);
ok(ret, "Failed to get a temp path, err %ld\n", GetLastError());
if (!ret)
return FALSE;
ret = GetTempFileNameA(temp_path, "mci", 0, fname);
ok(ret, "Failed to get a temp name, err %ld\n", GetLastError());
if (!ret)
return FALSE;
DeleteFileA(fname);
lstrcatA(fname, ".avi");
hFile = CreateFileA(fname, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
ok(hFile != INVALID_HANDLE_VALUE, "Failed to create a file, err %ld\n", GetLastError());
if (hFile == INVALID_HANDLE_VALUE) return FALSE;
buffer_length = padding[1];
buffer = heap_alloc_zero(buffer_length);
WriteFile(hFile, file_header, sizeof(file_header), &written, NULL);
WriteFile(hFile, &main_avi_header, sizeof(MainAVIHeader), &written, NULL);
WriteFile(hFile, stream_list, sizeof(stream_list), &written, NULL);
WriteFile(hFile, &avi_stream_header, sizeof(AVIStreamHeader), &written, NULL);
WriteFile(hFile, video_stream_format, sizeof(video_stream_format), &written, NULL);
WriteFile(hFile, padding, sizeof(padding), &written, NULL);
WriteFile(hFile, buffer, buffer_length, &written, NULL);
WriteFile(hFile, data, sizeof(data), &written, NULL);
heap_free(buffer);
CloseHandle(hFile);
return ret;
}
/* expected information for window creation */
static struct {
/* input */
const char* expectedA;
const WCHAR* expectedW;
/* output */
unsigned open_msg;
enum {NO_MATCH, PTR_ANSI_MATCH, PTR_UNICODE_MATCH, ANSI_MATCH, UNICODE_MATCH } match;
} wnd_creation;
static WNDPROC old_MCIWndProc;
static LRESULT WINAPI proxy_MCIWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
switch (wMsg)
{
case WM_CREATE:
{
CREATESTRUCTW* cs = (CREATESTRUCTW*)lParam;
if (cs->lpCreateParams)
{
if (cs->lpCreateParams == wnd_creation.expectedA)
wnd_creation.match = PTR_ANSI_MATCH;
else if (cs->lpCreateParams == wnd_creation.expectedW)
wnd_creation.match = PTR_UNICODE_MATCH;
else if (!strcmp(cs->lpCreateParams, wnd_creation.expectedA))
wnd_creation.match = ANSI_MATCH;
else if (!wcscmp(cs->lpCreateParams, wnd_creation.expectedW))
wnd_creation.match = UNICODE_MATCH;
}
}
break;
case MCIWNDM_OPENA:
case MCIWNDM_OPENW:
wnd_creation.open_msg = wMsg;
break;
default:
break;
}
return old_MCIWndProc(hWnd, wMsg, wParam, lParam);
}
static LRESULT CALLBACK hook_proc( int code, WPARAM wp, LPARAM lp )
{
if (code == HCBT_CREATEWND && lp)
{
CREATESTRUCTW* cs = ((CBT_CREATEWNDW *)lp)->lpcs;
if (cs && ((ULONG_PTR)cs->lpszClass >> 16) && !wcsicmp(cs->lpszClass, L"MCIWndClass"))
{
old_MCIWndProc = (WNDPROC)SetWindowLongPtrW((HWND)wp, GWLP_WNDPROC, (LPARAM)proxy_MCIWndProc);
ok(old_MCIWndProc != NULL, "No wnd proc\n");
}
}
return CallNextHookEx( NULL, code, wp, lp );
}
static void test_window_create(unsigned line, const char* fname, HWND parent,
BOOL with_mci, BOOL call_ansi, unsigned match)
{
HMODULE hinst = GetModuleHandleA(NULL);
WCHAR fnameW[MAX_PATH];
HWND window;
char error[200];
LRESULT ret;
BOOL expect_ansi = match == PTR_ANSI_MATCH || match == ANSI_MATCH;
MultiByteToWideChar(CP_ACP, 0, fname, -1, fnameW, ARRAY_SIZE(fnameW));
wnd_creation.expectedA = fname;
wnd_creation.expectedW = fnameW;
wnd_creation.open_msg = 0;
wnd_creation.match = NO_MATCH;
if (call_ansi)
{
if (with_mci)
window = MCIWndCreateA(parent, hinst, MCIWNDF_NOERRORDLG, fname);
else
window = CreateWindowExA(0, "MCIWndClass", NULL,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | MCIWNDF_NOERRORDLG,
0, 0, 300, 0,
parent, 0, hinst, expect_ansi ? (LPVOID)fname : (LPVOID)fnameW);
}
else
{
if (with_mci)
window = MCIWndCreateW(parent, hinst, MCIWNDF_NOERRORDLG, fnameW);
else
window = CreateWindowExW(0, L"MCIWndClass", NULL,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | MCIWNDF_NOERRORDLG,
0, 0, 300, 0,
parent, 0, hinst, expect_ansi ? (LPVOID)fname : (LPVOID)fnameW);
}
ok_(__FILE__, line)(window != NULL, "Failed to create an MCIWnd window\n");
ok_(__FILE__, line)(wnd_creation.match == match, "unexpected match %u\n", wnd_creation.match);
ok_(__FILE__, line)((expect_ansi && wnd_creation.open_msg == MCIWNDM_OPENA) ||
(!expect_ansi && wnd_creation.open_msg == MCIWNDM_OPENW),
"bad open message %u %s%u\n", match,
wnd_creation.open_msg >= WM_USER ? "WM_USER+" : "",
wnd_creation.open_msg >= WM_USER ? wnd_creation.open_msg - WM_USER : wnd_creation.open_msg);
ret = SendMessageA(window, MCIWNDM_GETERRORA, sizeof(error), (LPARAM)error);
ok_(__FILE__, line)(!ret || broken(ret == ERROR_INVALID_HANDLE) /* w2003std, w2008s64 */,
"Unexpected error %Id\n", ret);
DestroyWindow(window);
}
static void test_MCIWndCreate(void)
{
HWND parent, window;
HMODULE hinst = GetModuleHandleA(NULL);
char fname[MAX_PATH];
char invalid_fname[] = "invalid.avi";
char error[200];
HHOOK hook;
LRESULT ret;
create_avi_file(fname);
hook = SetWindowsHookExW( WH_CBT, hook_proc, NULL, GetCurrentThreadId() );
test_window_create( __LINE__, fname, NULL, TRUE, TRUE, UNICODE_MATCH );
test_window_create( __LINE__, fname, NULL, TRUE, FALSE, PTR_UNICODE_MATCH );
test_window_create( __LINE__, fname, NULL, FALSE, TRUE, PTR_ANSI_MATCH );
test_window_create( __LINE__, fname, NULL, FALSE, FALSE, PTR_ANSI_MATCH );
parent = CreateWindowExA(0, "static", "msvfw32 test",
WS_POPUP, 0, 0, 100, 100,
0, 0, 0, NULL);
ok(parent != NULL, "Failed to create a window\n");
ok(!IsWindowUnicode(parent), "Expecting ansi parent window\n");
test_window_create( __LINE__, fname, parent, TRUE, TRUE, UNICODE_MATCH );
test_window_create( __LINE__, fname, parent, TRUE, FALSE, PTR_UNICODE_MATCH );
test_window_create( __LINE__, fname, parent, FALSE, TRUE, PTR_ANSI_MATCH );
test_window_create( __LINE__, fname, parent, FALSE, FALSE, PTR_ANSI_MATCH );
DestroyWindow(parent);
parent = CreateWindowExW(0, L"static", L"msvfw32 test",
WS_POPUP, 0, 0, 100, 100,
0, 0, 0, NULL);
ok(parent != NULL, "Failed to create a window\n");
ok(IsWindowUnicode(parent), "Expecting unicode parent window\n");
test_window_create( __LINE__, fname, parent, TRUE, TRUE, UNICODE_MATCH );
test_window_create( __LINE__, fname, parent, TRUE, FALSE, PTR_UNICODE_MATCH );
test_window_create( __LINE__, fname, parent, FALSE, TRUE, PTR_UNICODE_MATCH );
test_window_create( __LINE__, fname, parent, FALSE, FALSE, PTR_UNICODE_MATCH );
DestroyWindow(parent);
UnhookWindowsHookEx( hook );
window = MCIWndCreateA(NULL, hinst, MCIWNDF_NOERRORDLG, invalid_fname);
ok(window != NULL, "Failed to create an MCIWnd window\n");
ret = SendMessageA(window, MCIWNDM_GETERRORA, sizeof(error), (LPARAM)error);
todo_wine ok(ret == MCIERR_FILE_NOT_FOUND, "Unexpected error %Id\n", ret);
DestroyWindow(window);
DeleteFileA(fname);
}
START_TEST(mciwnd)
{
test_MCIWndCreate();
}