Wine-Devel
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 7 participants
- 84546 discussions
Jan. 21, 2022
These tests show that DefDlgProcA/W() are hooked to implemented dialog theming, using a pattern
brush created from the tab body part. For dialogs that need theming, EnableThemeDialogTexture(ETDT_USETABTEXTURE)
or EnableThemeDialogTexture(ETDT_USEAEROWIZARDTABTEXTURE) is called for the dialog. And then
static or button controls in comctl32 v6 call EnableThemeDialogTexture(ETDT_ENABLE) to activate it.
A WM_ERASEBKGND is also needed to activate dialog theming. test_WM_CTLCOLORSTATIC() in dlls/comctl32/tests/static.c
doesn't send this message after EnableThemeDialogTexture() calls, which misdirected me to think that
DefDlgProcA/W() are not hooked.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/uxtheme/tests/system.c | 658 ++++++++++++++++++++++++++++++++++++
dlls/uxtheme/tests/v6util.h | 131 +++++++
2 files changed, 789 insertions(+)
create mode 100644 dlls/uxtheme/tests/v6util.h
diff --git a/dlls/uxtheme/tests/system.c b/dlls/uxtheme/tests/system.c
index 0385af663e3..3f8f32a9a7b 100644
--- a/dlls/uxtheme/tests/system.c
+++ b/dlls/uxtheme/tests/system.c
@@ -1,6 +1,7 @@
/* Unit test suite for uxtheme API functions
*
* Copyright 2006 Paul Vriens
+ * Copyright 2021-2022 Zhiyi Zhang for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -33,6 +34,8 @@
#include "msg.h"
#include "wine/test.h"
+#include "v6util.h"
+
static HTHEME (WINAPI * pOpenThemeDataEx)(HWND, LPCWSTR, DWORD);
static HTHEME (WINAPI *pOpenThemeDataForDpi)(HWND, LPCWSTR, UINT);
static HPAINTBUFFER (WINAPI *pBeginBufferedPaint)(HDC, const RECT *, BP_BUFFERFORMAT, BP_PAINTPARAMS *, HDC *);
@@ -1545,8 +1548,656 @@ static void test_DrawThemeParentBackground(void)
UnregisterClassA("TestDrawThemeParentBackgroundClass", GetModuleHandleA(0));
}
+struct test_EnableThemeDialogTexture_param
+{
+ const CHAR *class_name;
+ DWORD style;
+};
+
+static const struct message empty_seq[] =
+{
+ {0}
+};
+
+static HWND dialog_child;
+static DWORD dialog_init_flag;
+static BOOL handle_WM_CTLCOLORSTATIC;
+
+static INT_PTR CALLBACK test_EnableThemeDialogTexture_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
+{
+ struct test_EnableThemeDialogTexture_param *param;
+ struct message message = {0};
+
+ message.message = msg;
+ message.flags = sent | wparam | lparam;
+ message.wParam = wp;
+ message.lParam = lp;
+ add_message(sequences, PARENT_SEQ_INDEX, &message);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ param = (struct test_EnableThemeDialogTexture_param *)lp;
+ dialog_child = CreateWindowA(param->class_name, "child",
+ param->style | WS_CHILD | WS_VISIBLE, 1, 2, 50, 50, hwnd,
+ (HMENU)100, 0, NULL);
+ ok(dialog_child != NULL, "CreateWindowA failed, error %d.\n", GetLastError());
+ if (dialog_init_flag)
+ EnableThemeDialogTexture(hwnd, dialog_init_flag);
+ return TRUE;
+
+ case WM_CTLCOLORSTATIC:
+ return (INT_PTR)(handle_WM_CTLCOLORSTATIC ? GetSysColorBrush(COLOR_MENU) : 0);
+
+ case WM_CLOSE:
+ DestroyWindow(dialog_child);
+ dialog_child = NULL;
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+static void test_EnableThemeDialogTexture(void)
+{
+ struct test_EnableThemeDialogTexture_param param;
+ HWND dialog, child, hwnd, hwnd2;
+ int mode, old_mode, count, i, j;
+ COLORREF color, old_color;
+ HBRUSH brush, brush2;
+ HDC child_hdc, hdc;
+ LOGBRUSH log_brush;
+ ULONG_PTR proc;
+ WNDCLASSA cls;
+ HTHEME theme;
+ DWORD error;
+ BITMAP bmp;
+ HRESULT hr;
+ LRESULT lr;
+ POINT org;
+ SIZE size;
+ BOOL ret;
+
+ struct
+ {
+ DLGTEMPLATE template;
+ WORD menu;
+ WORD class;
+ WORD title;
+ } temp = {{0}};
+
+ static const DWORD flags[] =
+ {
+ ETDT_DISABLE,
+ ETDT_ENABLE,
+ ETDT_USETABTEXTURE,
+ ETDT_USEAEROWIZARDTABTEXTURE,
+ ETDT_ENABLETAB,
+ ETDT_ENABLEAEROWIZARDTAB,
+ /* Bad flags */
+ 0,
+ ETDT_DISABLE | ETDT_ENABLE,
+ ETDT_ENABLETAB | ETDT_ENABLEAEROWIZARDTAB
+ };
+
+ static const struct invalid_flag_test
+ {
+ DWORD flag;
+ BOOL enabled;
+ BOOL todo;
+ }
+ invalid_flag_tests[] =
+ {
+ {0, FALSE},
+ {ETDT_DISABLE | ETDT_ENABLE, FALSE},
+ {ETDT_ENABLETAB | ETDT_ENABLEAEROWIZARDTAB, TRUE},
+ {ETDT_USETABTEXTURE | ETDT_USEAEROWIZARDTABTEXTURE, TRUE, TRUE},
+ {ETDT_VALIDBITS, FALSE},
+ {~ETDT_VALIDBITS, FALSE},
+ {~ETDT_VALIDBITS | ETDT_DISABLE, FALSE}
+ };
+
+ static const struct class_test
+ {
+ struct test_EnableThemeDialogTexture_param param;
+ BOOL texture_enabled;
+ }
+ class_tests[] =
+ {
+ {{ANIMATE_CLASSA}},
+ {{WC_BUTTONA, BS_PUSHBUTTON}, TRUE},
+ {{WC_BUTTONA, BS_DEFPUSHBUTTON}, TRUE},
+ {{WC_BUTTONA, BS_CHECKBOX}, TRUE},
+ {{WC_BUTTONA, BS_AUTOCHECKBOX}, TRUE},
+ {{WC_BUTTONA, BS_RADIOBUTTON}, TRUE},
+ {{WC_BUTTONA, BS_3STATE}, TRUE},
+ {{WC_BUTTONA, BS_AUTO3STATE}, TRUE},
+ {{WC_BUTTONA, BS_GROUPBOX}, TRUE},
+ {{WC_BUTTONA, BS_USERBUTTON}, TRUE},
+ {{WC_BUTTONA, BS_AUTORADIOBUTTON}, TRUE},
+ {{WC_BUTTONA, BS_PUSHBOX}, TRUE},
+ {{WC_BUTTONA, BS_OWNERDRAW}, TRUE},
+ {{WC_BUTTONA, BS_SPLITBUTTON}, TRUE},
+ {{WC_BUTTONA, BS_DEFSPLITBUTTON}, TRUE},
+ {{WC_BUTTONA, BS_COMMANDLINK}, TRUE},
+ {{WC_BUTTONA, BS_DEFCOMMANDLINK}, TRUE},
+ {{WC_COMBOBOXA}},
+ {{WC_COMBOBOXEXA}},
+ {{DATETIMEPICK_CLASSA}},
+ {{WC_EDITA}},
+ {{WC_HEADERA}},
+ {{HOTKEY_CLASSA}},
+ {{WC_IPADDRESSA}},
+ {{WC_LISTBOXA}},
+ {{WC_LISTVIEWA}},
+ {{MONTHCAL_CLASSA}},
+ {{WC_NATIVEFONTCTLA}},
+ {{WC_PAGESCROLLERA}},
+ {{PROGRESS_CLASSA}},
+ {{REBARCLASSNAMEA}},
+ {{WC_STATICA, SS_LEFT}, TRUE},
+ {{WC_STATICA, SS_ICON}, TRUE},
+ {{WC_STATICA, SS_BLACKRECT}, TRUE},
+ {{WC_STATICA, SS_OWNERDRAW}, TRUE},
+ {{WC_STATICA, SS_BITMAP}, TRUE},
+ {{WC_STATICA, SS_ENHMETAFILE}, TRUE},
+ {{WC_STATICA, SS_ETCHEDHORZ}, TRUE},
+ {{STATUSCLASSNAMEA}},
+ {{"SysLink"}},
+ {{WC_TABCONTROLA}},
+ {{TOOLBARCLASSNAMEA}},
+ {{TOOLTIPS_CLASSA}},
+ {{TRACKBAR_CLASSA}},
+ {{WC_TREEVIEWA}},
+ {{UPDOWN_CLASSA}},
+ {{WC_SCROLLBARA}},
+ };
+
+ if (!IsThemeActive())
+ {
+ skip("Theming is inactive.\n");
+ return;
+ }
+
+ memset(&cls, 0, sizeof(cls));
+ cls.lpfnWndProc = DefWindowProcA;
+ cls.hInstance = GetModuleHandleA(NULL);
+ cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
+ cls.hbrBackground = GetStockObject(GRAY_BRUSH);
+ cls.lpszClassName = "TestEnableThemeDialogTextureClass";
+ RegisterClassA(&cls);
+
+ temp.template.style = WS_CHILD | WS_VISIBLE;
+ temp.template.cx = 100;
+ temp.template.cy = 100;
+ param.class_name = cls.lpszClassName;
+ param.style = 0;
+ dialog = CreateDialogIndirectParamA(NULL, &temp.template, GetDesktopWindow(),
+ test_EnableThemeDialogTexture_proc, (LPARAM)¶m);
+ ok(dialog != NULL, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
+ child = GetDlgItem(dialog, 100);
+ ok(child != NULL, "Failed to get child control, error %d.\n", GetLastError());
+ child_hdc = GetDC(child);
+
+ /* Test that dialog procedure is unchanged */
+ proc = GetWindowLongPtrA(dialog, DWLP_DLGPROC);
+ ok(proc == (ULONG_PTR)test_EnableThemeDialogTexture_proc, "Unexpected proc %#lx.\n", proc);
+
+ /* Test dialog texture is disabled by default. EnableThemeDialogTexture() needs to be called */
+ ret = IsThemeDialogTextureEnabled(dialog);
+ todo_wine
+ ok(!ret, "Expected theme dialog texture disabled.\n");
+ ok(GetWindowTheme(dialog) == NULL, "Expected NULL theme handle.\n");
+
+ /* Test ETDT_ENABLE | ETDT_USETABTEXTURE doesn't take effect immediately */
+ hr = EnableThemeDialogTexture(dialog, ETDT_ENABLE | ETDT_USETABTEXTURE);
+ ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
+ ret = IsThemeDialogTextureEnabled(dialog);
+ ok(ret, "Expected theme dialog texture enabled.\n");
+
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected brush %p, got %p.\n",
+ GetSysColorBrush(COLOR_BTNFACE), brush);
+ ret = GetBrushOrgEx(child_hdc, &org);
+ ok(ret, "GetBrushOrgEx failed, error %u.\n", GetLastError());
+ ok(org.x == 0 && org.y == 0, "Expected (0,0), got %s.\n", wine_dbgstr_point(&org));
+
+ /* Test WM_THEMECHANGED doesn't make ETDT_ENABLE | ETDT_USETABTEXTURE take effect */
+ lr = SendMessageA(dialog, WM_THEMECHANGED, 0, 0);
+ ok(lr == 0, "WM_THEMECHANGED failed.\n");
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected brush %p, got %p.\n",
+ GetSysColorBrush(COLOR_BTNFACE), brush);
+
+ /* Test WM_ERASEBKGND make ETDT_ENABLE | ETDT_USETABTEXTURE take effect */
+ lr = SendMessageA(dialog, WM_ERASEBKGND, (WPARAM)child_hdc, 0);
+ ok(lr != 0, "WM_ERASEBKGND failed.\n");
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ todo_wine
+ ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected brush changed.\n");
+
+ /* Test disabling theme dialog texture should change the brush immediately */
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ hr = EnableThemeDialogTexture(dialog, ETDT_DISABLE);
+ ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
+ brush2 = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ todo_wine
+ ok(brush2 != brush, "Expected a different brush.\n");
+ ok(brush2 == GetSysColorBrush(COLOR_BTNFACE), "Expected brush %p, got %p.\n",
+ GetSysColorBrush(COLOR_BTNFACE), brush2);
+
+ /* Test re-enabling theme dialog texture with ETDT_ENABLE doesn't change the brush */
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ hr = EnableThemeDialogTexture(dialog, ETDT_ENABLE);
+ ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
+ brush2 = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ ok(brush2 == brush, "Expected the same brush.\n");
+ ok(brush2 == GetSysColorBrush(COLOR_BTNFACE), "Expected brush %p, got %p.\n",
+ GetSysColorBrush(COLOR_BTNFACE), brush2);
+
+ /* Test adding ETDT_USETABTEXTURE should change the brush immediately */
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ hr = EnableThemeDialogTexture(dialog, ETDT_USETABTEXTURE);
+ ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
+ brush2 = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ todo_wine
+ ok(brush2 != brush, "Expected a different brush.\n");
+
+ /* Test ETDT_ENABLE | ETDT_USEAEROWIZARDTABTEXTURE should change the brush immediately */
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ hr = EnableThemeDialogTexture(dialog, ETDT_ENABLE | ETDT_USEAEROWIZARDTABTEXTURE);
+ ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
+ brush2 = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ /* ETDT_USEAEROWIZARDTABTEXTURE is supported only on Vista+ */
+ if (LOBYTE(LOWORD(GetVersion())) < 6)
+ ok(brush2 == brush, "Expected the same brush.\n");
+ else
+ todo_wine
+ ok(brush2 != brush, "Expected a different brush.\n");
+
+ hr = EnableThemeDialogTexture(dialog, ETDT_DISABLE);
+ ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
+ hr = EnableThemeDialogTexture(dialog, ETDT_ENABLE | ETDT_USETABTEXTURE);
+ ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
+
+ /* Test that the dialog procedure should take precedence over DefDlgProc() for WM_CTLCOLORSTATIC */
+ handle_WM_CTLCOLORSTATIC = TRUE;
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ ok(brush == GetSysColorBrush(COLOR_MENU), "Expected brush %p, got %p.\n",
+ GetSysColorBrush(COLOR_MENU), brush);
+ handle_WM_CTLCOLORSTATIC = FALSE;
+
+ /* Test that WM_CTLCOLORSTATIC changes brush origin when dialog texture is on */
+ ret = SetBrushOrgEx(child_hdc, 0, 0, NULL);
+ ok(ret, "SetBrushOrgEx failed, error %u.\n", GetLastError());
+ SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ ret = GetBrushOrgEx(child_hdc, &org);
+ ok(ret, "GetBrushOrgEx failed, error %u.\n", GetLastError());
+ todo_wine
+ ok(org.x == -1 && org.y == -2, "Expected (-1,-2), got %s.\n", wine_dbgstr_point(&org));
+
+ /* Test that WM_CTLCOLORSTATIC changes background mode when dialog texture is on */
+ old_mode = SetBkMode(child_hdc, OPAQUE);
+ ok(old_mode != 0, "SetBkMode failed.\n");
+ SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ mode = SetBkMode(child_hdc, old_mode);
+ todo_wine
+ ok(mode == TRANSPARENT, "Expected mode %#x, got %#x.\n", TRANSPARENT, mode);
+
+ /* Test that WM_CTLCOLORSTATIC changes background color when dialog texture is on */
+ old_color = SetBkColor(child_hdc, 0xaa5511);
+ ok(old_color != CLR_INVALID, "SetBkColor failed.\n");
+ SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ color = SetBkColor(child_hdc, old_color);
+ ok(color == GetSysColor(COLOR_BTNFACE), "Expected background color %#x, got %#x.\n",
+ GetSysColor(COLOR_BTNFACE), color);
+
+ /* Test that dialog doesn't have theme handle opened for itself */
+ ok(GetWindowTheme(dialog) == NULL, "Expected NULL theme handle.\n");
+
+ /* Test that the returned brush is a pattern brush created from the tab body */
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ memset(&log_brush, 0, sizeof(log_brush));
+ count = GetObjectA(brush, sizeof(log_brush), &log_brush);
+ ok(count == sizeof(log_brush), "GetObjectA failed, error %u.\n", GetLastError());
+ todo_wine
+ ok(log_brush.lbColor == 0, "Expected brush color %#x, got %#x.\n", 0, log_brush.lbColor);
+ todo_wine
+ ok(log_brush.lbStyle == BS_PATTERN, "Expected brush style %#x, got %#x.\n", BS_PATTERN,
+ log_brush.lbStyle);
+
+ memset(&bmp, 0, sizeof(bmp));
+ count = GetObjectA((HBITMAP)log_brush.lbHatch, sizeof(bmp), &bmp);
+ todo_wine
+ ok(count == sizeof(bmp), "GetObjectA failed, error %u.\n", GetLastError());
+
+ theme = OpenThemeData(NULL, L"Tab");
+ ok(theme != NULL, "OpenThemeData failed.\n");
+
+ size.cx = 0;
+ size.cy = 0;
+ hr = GetThemePartSize(theme, NULL, TABP_BODY, 0, NULL, TS_TRUE, &size);
+ ok(hr == S_OK, "GetThemePartSize failed, hr %#x.\n", hr);
+ todo_wine
+ ok(bmp.bmWidth == size.cx, "Expected width %d, got %d.\n", size.cx, bmp.bmWidth);
+ todo_wine
+ ok(bmp.bmHeight == size.cy, "Expected height %d, got %d.\n", size.cy, bmp.bmHeight);
+
+ CloseThemeData(theme);
+
+ /* Test that DefDlgProcA/W() are hooked for WM_CTLCOLORSTATIC */
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ todo_wine
+ ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected a different brush.\n");
+ brush2 = (HBRUSH)DefDlgProcW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ ok(brush2 == brush, "Expected the same brush.\n");
+ brush2 = (HBRUSH)DefDlgProcA(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ ok(brush2 == brush, "Expected the same brush.\n");
+
+ /* Test that DefWindowProcA/W() are also hooked for WM_CTLCOLORSTATIC */
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ todo_wine
+ ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected a different brush.\n");
+ brush2 = (HBRUSH)DefWindowProcW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ ok(brush2 == brush, "Expected the same brush.\n");
+ brush2 = (HBRUSH)DefWindowProcA(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ ok(brush2 == brush, "Expected the same brush.\n");
+
+ /* Test that DefWindowProcA/W() are not hooked for WM_ERASEBKGND. So the background is still
+ * drawn with hbrBackground, which in this case, is GRAY_BRUSH.
+ *
+ * This test means it could be that both DefWindowProc() and DefDlgProc() are hooked for
+ * WM_CTLCOLORSTATIC and only DefDlgProc() is hooked for WM_ERASEBKGND. Or it could mean
+ * DefWindowProc() is hooked for WM_CTLCOLORSTATIC and DefDlgProc() is hooked for WM_ERASEBKGND.
+ * Considering the dialog theming needs a WM_ERASEBKGND to activate, it would be weird for let
+ * only DefWindowProc() to hook WM_CTLCOLORSTATIC. For example, what's the point of hooking
+ * WM_CTLCOLORSTATIC in DefWindowProc() for a feature that can only be activated in
+ * DefDlgProc()? So I tend to believe both DefWindowProc() and DefDlgProc() are hooked for
+ * WM_CTLCOLORSTATIC */
+ hwnd = CreateWindowA(cls.lpszClassName, "parent", WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, 0, 0,
+ 0, NULL);
+ ok(hwnd != NULL, "CreateWindowA failed, error %d.\n", GetLastError());
+ hwnd2 = CreateWindowA(WC_STATICA, "child", WS_CHILD | WS_VISIBLE, 10, 10, 20, 20, hwnd, NULL, 0,
+ NULL);
+ hr = EnableThemeDialogTexture(hwnd, ETDT_ENABLETAB);
+ ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
+ ret = IsThemeDialogTextureEnabled(hwnd);
+ ok(ret, "Wrong dialog texture status.\n");
+ flush_events();
+
+ hdc = GetDC(hwnd);
+ color = GetPixel(hdc, 0, 0);
+ ok(color == 0x808080 || broken(color == 0xffffffff), /* Win 7 may report 0xffffffff */
+ "Expected color %#x, got %#x.\n", 0x808080, color);
+ color = GetPixel(hdc, 50, 50);
+ ok(color == 0x808080 || broken(color == 0xffffffff), /* Win 7 may report 0xffffffff */
+ "Expected color %#x, got %#x.\n", 0x808080, color);
+ color = GetPixel(hdc, 99, 99);
+ ok(color == 0x808080 || broken(color == 0xffffffff), /* Win 7 may report 0xffffffff */
+ "Expected color %#x, got %#x.\n", 0x808080, color);
+ ReleaseDC(hwnd, hdc);
+
+ /* Test EnableThemeDialogTexture() doesn't work for non-dialog windows */
+ hdc = GetDC(hwnd2);
+ brush = (HBRUSH)SendMessageW(hwnd, WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd2);
+ ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected a different brush.\n");
+ ReleaseDC(hwnd2, hdc);
+
+ DestroyWindow(hwnd);
+
+ /* Test that the brush is not a system object and has only one reference and shouldn't be freed */
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ ret = DeleteObject(brush);
+ ok(ret, "DeleteObject failed, error %u.\n", GetLastError());
+ SetLastError(0xdeadbeef);
+ ret = GetObjectA(brush, sizeof(log_brush), &log_brush);
+ error = GetLastError();
+ todo_wine
+ ok(!ret || broken(ret) /* XP */, "GetObjectA succeeded.\n");
+ todo_wine
+ ok(error == ERROR_INVALID_PARAMETER || broken(error == 0xdeadbeef) /* XP */,
+ "Expected error %u, got %u.\n", ERROR_INVALID_PARAMETER, error);
+ ret = DeleteObject(brush);
+ todo_wine
+ ok(!ret || broken(ret) /* XP */, "DeleteObject succeeded.\n");
+
+ /* Should still report the same brush handle after the brush handle was freed */
+ brush2 = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ ok(brush2 == brush, "Expected the same brush.\n");
+
+ /* Test WM_THEMECHANGED can update the brush now that ETDT_ENABLE | ETDT_USETABTEXTURE is in
+ * effect. This test needs to be ran last as it affect other tests for the same dialog for
+ * unknown reason, causing the brush not to update */
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ lr = SendMessageA(dialog, WM_THEMECHANGED, 0, 0);
+ ok(lr == 0, "WM_THEMECHANGED failed.\n");
+ brush2 = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ todo_wine
+ ok(brush2 != brush, "Expected a different brush.\n");
+
+ ReleaseDC(child, child_hdc);
+ EndDialog(dialog, 0);
+
+ /* Test invalid flags */
+ for (i = 0; i < ARRAY_SIZE(invalid_flag_tests); ++i)
+ {
+ winetest_push_context("%d flag %#x", i, invalid_flag_tests[i].flag);
+
+ dialog = CreateDialogIndirectParamA(NULL, &temp.template, GetDesktopWindow(),
+ test_EnableThemeDialogTexture_proc, (LPARAM)¶m);
+ ok(dialog != NULL, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
+ hr = EnableThemeDialogTexture(dialog, invalid_flag_tests[i].flag);
+ ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
+ ret = IsThemeDialogTextureEnabled(dialog);
+ todo_wine_if(invalid_flag_tests[i].todo)
+ ok(ret == invalid_flag_tests[i].enabled, "Wrong dialog texture status.\n");
+ EndDialog(dialog, 0);
+
+ winetest_pop_context();
+ }
+
+ /* Test different flag combinations */
+ for (i = 0; i < ARRAY_SIZE(flags); ++i)
+ {
+ for (j = 0; j < ARRAY_SIZE(flags); ++j)
+ {
+ /* ETDT_USEAEROWIZARDTABTEXTURE is supported only on Vista+ */
+ if (LOBYTE(LOWORD(GetVersion())) < 6
+ && ((flags[i] | flags[j]) & ETDT_USEAEROWIZARDTABTEXTURE))
+ continue;
+
+ winetest_push_context("%#x to %#x", flags[i], flags[j]);
+
+ dialog = CreateDialogIndirectParamA(NULL, &temp.template, GetDesktopWindow(),
+ test_EnableThemeDialogTexture_proc, (LPARAM)¶m);
+ ok(dialog != NULL, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
+ flush_events();
+ flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+ hr = EnableThemeDialogTexture(dialog, flags[i]);
+ ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
+ ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
+ "EnableThemeDialogTexture first flag", TRUE);
+ ret = IsThemeDialogTextureEnabled(dialog);
+ /* Non-zero flags without ETDT_DISABLE enables dialog texture */
+ todo_wine_if(flags[i] == ETDT_USETABTEXTURE || flags[i] == ETDT_USEAEROWIZARDTABTEXTURE)
+ ok(ret == (!(flags[i] & ETDT_DISABLE) && flags[i]), "Wrong dialog texture status.\n");
+
+ child = GetDlgItem(dialog, 100);
+ ok(child != NULL, "Failed to get child control, error %d.\n", GetLastError());
+ child_hdc = GetDC(child);
+ lr = SendMessageA(dialog, WM_ERASEBKGND, (WPARAM)child_hdc, 0);
+ ok(lr != 0, "WM_ERASEBKGND failed.\n");
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ if (flags[i] == ETDT_ENABLETAB || flags[i] == ETDT_ENABLEAEROWIZARDTAB)
+ todo_wine
+ ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture enabled.\n");
+ else
+ ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture disabled.\n");
+ flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+ hr = EnableThemeDialogTexture(dialog, flags[j]);
+ ok(hr == S_OK, "EnableThemeDialogTexture failed, hr %#x.\n", hr);
+ ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
+ "EnableThemeDialogTexture second flag", TRUE);
+ ret = IsThemeDialogTextureEnabled(dialog);
+ /* If the flag is zero, it will have previous dialog texture status */
+ if (flags[j])
+ todo_wine_if(flags[j] == ETDT_USETABTEXTURE || flags[j] == ETDT_USEAEROWIZARDTABTEXTURE)
+ ok(ret == !(flags[j] & ETDT_DISABLE), "Wrong dialog texture status.\n");
+ else
+ todo_wine_if((!(flags[i] & ETDT_DISABLE) && flags[i]))
+ ok(ret == (!(flags[i] & ETDT_DISABLE) && flags[i]), "Wrong dialog texture status.\n");
+ lr = SendMessageA(dialog, WM_ERASEBKGND, (WPARAM)child_hdc, 0);
+ ok(lr != 0, "WM_ERASEBKGND failed.\n");
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ /* Dialog texture is turned on when the flag contains ETDT_ENABLETAB or
+ * ETDT_ENABLEAEROWIZARDTAB. The flag can be turned on in multiple steps, but you can't
+ * do things like set ETDT_ENABLETAB and then ETDT_USEAEROWIZARDTABTEXTURE */
+ if (((flags[j] == ETDT_ENABLETAB || flags[j] == ETDT_ENABLEAEROWIZARDTAB)
+ || ((((flags[i] | flags[j]) & ETDT_ENABLETAB) == ETDT_ENABLETAB
+ || ((flags[i] | flags[j]) & ETDT_ENABLEAEROWIZARDTAB) == ETDT_ENABLEAEROWIZARDTAB)
+ && !((flags[i] | flags[j]) & ETDT_DISABLE)))
+ && (((flags[i] | flags[j]) & (ETDT_ENABLETAB | ETDT_ENABLEAEROWIZARDTAB)) != (ETDT_ENABLETAB | ETDT_ENABLEAEROWIZARDTAB)))
+ todo_wine
+ ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture enabled.\n");
+ else
+ ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture disabled.\n");
+
+ ReleaseDC(child, child_hdc);
+ EndDialog(dialog, 0);
+
+ winetest_pop_context();
+ }
+ }
+
+ /* Test that the dialog procedure should set ETDT_USETABTEXTURE/ETDT_USEAEROWIZARDTABTEXTURE and
+ * find out which comctl32 class should set ETDT_ENABLE to turn on dialog texture */
+ for (i = 0; i < ARRAY_SIZE(class_tests); ++i)
+ {
+ winetest_push_context("%s %#x", wine_dbgstr_a(class_tests[i].param.class_name),
+ class_tests[i].param.style);
+
+ dialog = CreateDialogIndirectParamA(NULL, &temp.template, GetDesktopWindow(),
+ test_EnableThemeDialogTexture_proc,
+ (LPARAM)&class_tests[i].param);
+ ok(dialog != NULL, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
+ /* GetDlgItem() fails to get the child control if the child is a tooltip */
+ child = dialog_child;
+ ok(child != NULL, "Failed to get child control, error %d.\n", GetLastError());
+ child_hdc = GetDC(child);
+
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture disabled.\n");
+
+ ReleaseDC(child, child_hdc);
+ EndDialog(dialog, 0);
+
+ dialog_init_flag = ETDT_ENABLE;
+ dialog = CreateDialogIndirectParamA(NULL, &temp.template, GetDesktopWindow(),
+ test_EnableThemeDialogTexture_proc,
+ (LPARAM)&class_tests[i].param);
+ ok(dialog != NULL, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
+ child = dialog_child;
+ ok(child != NULL, "Failed to get child control, error %d.\n", GetLastError());
+ child_hdc = GetDC(child);
+
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture disabled.\n");
+
+ ReleaseDC(child, child_hdc);
+ EndDialog(dialog, 0);
+
+ dialog_init_flag = ETDT_USETABTEXTURE;
+ dialog = CreateDialogIndirectParamA(NULL, &temp.template, GetDesktopWindow(),
+ test_EnableThemeDialogTexture_proc,
+ (LPARAM)&class_tests[i].param);
+ ok(dialog != NULL, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
+ child = dialog_child;
+ ok(child != NULL, "Failed to get child control, error %d.\n", GetLastError());
+ child_hdc = GetDC(child);
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ if (class_tests[i].texture_enabled)
+ todo_wine
+ ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture enabled.\n");
+ else
+ ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture disabled.\n");
+ ReleaseDC(child, child_hdc);
+ EndDialog(dialog, 0);
+
+ if (LOBYTE(LOWORD(GetVersion())) < 6)
+ {
+ dialog_init_flag = 0;
+ winetest_pop_context();
+ continue;
+ }
+
+ dialog_init_flag = ETDT_USEAEROWIZARDTABTEXTURE;
+ dialog = CreateDialogIndirectParamA(NULL, &temp.template, GetDesktopWindow(),
+ test_EnableThemeDialogTexture_proc,
+ (LPARAM)&class_tests[i].param);
+ ok(dialog != NULL, "CreateDialogIndirectParamA failed, error %d.\n", GetLastError());
+ child = dialog_child;
+ ok(child != NULL, "Failed to get child control, error %d.\n", GetLastError());
+ child_hdc = GetDC(child);
+ brush = (HBRUSH)SendMessageW(dialog, WM_CTLCOLORSTATIC, (WPARAM)child_hdc, (LPARAM)child);
+ if (class_tests[i].texture_enabled)
+ todo_wine
+ ok(brush != GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture enabled.\n");
+ else
+ ok(brush == GetSysColorBrush(COLOR_BTNFACE), "Expected tab texture disabled.\n");
+ ReleaseDC(child, child_hdc);
+ EndDialog(dialog, 0);
+ dialog_init_flag = 0;
+
+ winetest_pop_context();
+ }
+
+ /* Test that EnableThemeDialogTexture() is called from child controls for its parent */
+ hwnd = CreateWindowA(cls.lpszClassName, "parent", WS_POPUP | WS_VISIBLE, 100, 100, 200, 200, 0,
+ 0, 0, NULL);
+ ok(hwnd != NULL, "CreateWindowA failed, error %d.\n", GetLastError());
+ ret = IsThemeDialogTextureEnabled(hwnd);
+ todo_wine
+ ok(!ret, "Wrong dialog texture status.\n");
+ child = CreateWindowA(WC_STATICA, "child", WS_CHILD | WS_VISIBLE, 0, 0, 50, 50, hwnd, 0, 0,
+ NULL);
+ ok(child != NULL, "CreateWindowA failed, error %d.\n", GetLastError());
+ ret = IsThemeDialogTextureEnabled(hwnd);
+ ok(ret, "Wrong dialog texture status.\n");
+
+ /* Test that if you move the child control to another window, it doesn't enables tab texture for
+ * the new parent */
+ hwnd2 = CreateWindowA(cls.lpszClassName, "parent", WS_POPUP | WS_VISIBLE, 100, 100, 200, 200, 0,
+ 0, 0, NULL);
+ ok(hwnd2 != NULL, "CreateWindowA failed, error %d.\n", GetLastError());
+ ret = IsThemeDialogTextureEnabled(hwnd2);
+ todo_wine
+ ok(!ret, "Wrong dialog texture status.\n");
+
+ SetParent(child, hwnd2);
+ ok(GetParent(child) == hwnd2, "Wrong parent.\n");
+ ret = IsThemeDialogTextureEnabled(hwnd2);
+ todo_wine
+ ok(!ret, "Wrong dialog texture status.\n");
+ InvalidateRect(child, NULL, TRUE);
+ flush_events();
+ ret = IsThemeDialogTextureEnabled(hwnd2);
+ todo_wine
+ ok(!ret, "Wrong dialog texture status.\n");
+
+ DestroyWindow(hwnd2);
+ DestroyWindow(hwnd);
+
+ UnregisterClassA(cls.lpszClassName, GetModuleHandleA(NULL));
+}
+
START_TEST(system)
{
+ ULONG_PTR ctx_cookie;
+ HANDLE ctx;
+
init_funcs();
init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
@@ -1568,6 +2219,13 @@ START_TEST(system)
test_GetThemeTransitionDuration();
test_DrawThemeParentBackground();
+ if (load_v6_module(&ctx_cookie, &ctx))
+ {
+ test_EnableThemeDialogTexture();
+
+ unload_v6_module(ctx_cookie, ctx);
+ }
+
/* Test EnableTheming() in the end because it may disable theming */
test_EnableTheming();
}
diff --git a/dlls/uxtheme/tests/v6util.h b/dlls/uxtheme/tests/v6util.h
new file mode 100644
index 00000000000..626f6e61255
--- /dev/null
+++ b/dlls/uxtheme/tests/v6util.h
@@ -0,0 +1,131 @@
+/*
+ * Utility routines for comctl32 v6 tests
+ *
+ * Copyright 2006 Mike McCormack for CodeWeavers
+ * Copyright 2007 George Gov
+ * Copyright 2009 Owen Rudge for CodeWeavers
+ *
+ * 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
+ */
+
+#ifdef __i386__
+#define ARCH "x86"
+#elif defined __x86_64__
+#define ARCH "amd64"
+#elif defined __arm__
+#define ARCH "arm"
+#elif defined __aarch64__
+#define ARCH "arm64"
+#else
+#define ARCH "none"
+#endif
+
+static const CHAR manifest_name[] = "cc6.manifest";
+
+static const CHAR manifest[] =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
+ "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n"
+ " <assemblyIdentity\n"
+ " type=\"win32\"\n"
+ " name=\"Wine.ComCtl32.Tests\"\n"
+ " version=\"1.0.0.0\"\n"
+ " processorArchitecture=\"" ARCH "\"\n"
+ " />\n"
+ "<description>Wine comctl32 test suite</description>\n"
+ "<dependency>\n"
+ " <dependentAssembly>\n"
+ " <assemblyIdentity\n"
+ " type=\"win32\"\n"
+ " name=\"microsoft.windows.common-controls\"\n"
+ " version=\"6.0.0.0\"\n"
+ " processorArchitecture=\"" ARCH "\"\n"
+ " publicKeyToken=\"6595b64144ccf1df\"\n"
+ " language=\"*\"\n"
+ " />\n"
+ "</dependentAssembly>\n"
+ "</dependency>\n"
+ "</assembly>\n";
+
+static void unload_v6_module(ULONG_PTR cookie, HANDLE hCtx)
+{
+ DeactivateActCtx(0, cookie);
+ ReleaseActCtx(hCtx);
+
+ DeleteFileA(manifest_name);
+}
+
+static BOOL load_v6_module(ULONG_PTR *pcookie, HANDLE *hCtx)
+{
+ ACTCTX_SECTION_KEYED_DATA data;
+ DWORD written;
+ HMODULE hmod;
+ ACTCTXA ctx;
+ HANDLE file;
+ BOOL ret;
+
+ /* create manifest */
+ file = CreateFileA( manifest_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
+ if (file != INVALID_HANDLE_VALUE)
+ {
+ ret = (WriteFile( file, manifest, sizeof(manifest)-1, &written, NULL ) &&
+ written == sizeof(manifest)-1);
+ CloseHandle( file );
+ if (!ret)
+ {
+ DeleteFileA( manifest_name );
+ skip("Failed to fill manifest file. Skipping comctl32 V6 tests.\n");
+ return FALSE;
+ }
+ else
+ trace("created %s\n", manifest_name);
+ }
+ else
+ {
+ skip("Failed to create manifest file. Skipping comctl32 V6 tests.\n");
+ return FALSE;
+ }
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.cbSize = sizeof(ctx);
+ ctx.lpSource = manifest_name;
+
+ *hCtx = CreateActCtxA(&ctx);
+ ok(*hCtx != 0, "Expected context handle\n");
+
+ hmod = GetModuleHandleA("comctl32.dll");
+
+ ret = ActivateActCtx(*hCtx, pcookie);
+ ok(ret, "Failed to activate context, error %d.\n", GetLastError());
+
+ if (!ret)
+ {
+ win_skip("A problem during context activation occurred.\n");
+ DeleteFileA(manifest_name);
+ }
+
+ data.cbSize = sizeof(data);
+ ret = FindActCtxSectionStringA(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
+ "comctl32.dll", &data);
+ ok(ret, "failed to find comctl32.dll in active context, %u\n", GetLastError());
+ if (ret)
+ {
+ FreeLibrary(hmod);
+ LoadLibraryA("comctl32.dll");
+ }
+
+ return ret;
+}
+
+#undef ARCH
--
2.32.0
1
0
[PATCH] msdasql: Connect to DSN in IDBInitialize Initialize.
by Alistair Leslie-Hughes Jan. 21, 2022
by Alistair Leslie-Hughes Jan. 21, 2022
Jan. 21, 2022
Signed-off-by: Alistair Leslie-Hughes <leslie_alistair(a)hotmail.com>
---
dlls/msdasql/Makefile.in | 2 +-
dlls/msdasql/msdasql_main.c | 63 ++++++++++++++++++++++++++++++++++++-
2 files changed, 63 insertions(+), 2 deletions(-)
diff --git a/dlls/msdasql/Makefile.in b/dlls/msdasql/Makefile.in
index ee8fa672623..0f5453131f6 100644
--- a/dlls/msdasql/Makefile.in
+++ b/dlls/msdasql/Makefile.in
@@ -1,5 +1,5 @@
MODULE = msdasql.dll
-IMPORTS = uuid ole32 oleaut32
+IMPORTS = uuid ole32 oleaut32 odbc32
EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/msdasql/msdasql_main.c b/dlls/msdasql/msdasql_main.c
index bc208a74cc5..cf69195baf7 100644
--- a/dlls/msdasql/msdasql_main.c
+++ b/dlls/msdasql/msdasql_main.c
@@ -30,6 +30,9 @@
#include "initguid.h"
#include "msdasql.h"
+#include "odbcinst.h"
+#include "sqlext.h"
+#include "sqlucode.h"
#include "msdasql_private.h"
@@ -40,6 +43,22 @@ DEFINE_GUID(DBPROPSET_DBINIT, 0xc8b522bc, 0x5cf3, 0x11ce, 0xad, 0xe5, 0x00, 0
DEFINE_GUID(DBGUID_DEFAULT, 0xc8b521fb, 0x5cf3, 0x11ce, 0xad, 0xe5, 0x00, 0xaa, 0x00, 0x44, 0x77, 0x3d);
+static void dump_sql_diag_records(SQLSMALLINT type, SQLHANDLE handle)
+{
+ SQLCHAR state[6], msg[SQL_MAX_MESSAGE_LENGTH];
+ SQLINTEGER native;
+ SQLSMALLINT i = 1, len;
+
+ if (!TRACE_ON(msdasql))
+ return;
+
+ while(SQLGetDiagRec(type, handle, i, state, &native, msg, sizeof(msg), &len) != SQL_SUCCESS)
+ {
+ WARN("%d: %s: %s\n", i, state, msg);
+ i++;
+ }
+}
+
static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
{
*ppv = NULL;
@@ -210,6 +229,10 @@ struct msdasql
LONG ref;
struct msdasql_prop properties[14];
+
+ /* ODBC Support */
+ HENV henv;
+ HDBC hdbc;
};
static inline struct msdasql *impl_from_IUnknown(IUnknown *iface)
@@ -294,6 +317,10 @@ static ULONG WINAPI msdsql_Release(IUnknown *iface)
if (!ref)
{
+ SQLDisconnect(provider->hdbc);
+
+ SQLFreeHandle(SQL_HANDLE_DBC, provider->hdbc);
+ SQLFreeHandle(SQL_HANDLE_ENV, provider->henv);
free(provider);
}
@@ -502,8 +529,33 @@ static ULONG WINAPI dbinit_Release(IDBInitialize *iface)
static HRESULT WINAPI dbinit_Initialize(IDBInitialize *iface)
{
struct msdasql *provider = impl_from_IDBInitialize(iface);
+ int i;
+ SQLRETURN ret;
- FIXME("%p stub\n", provider);
+ FIXME("%p semi-stub\n", provider);
+
+ for(i=0; i < sizeof(provider->properties); i++)
+ {
+ if (provider->properties[i].id == DBPROP_INIT_DATASOURCE)
+ break;
+ }
+
+ if (i >= sizeof(provider->properties))
+ {
+ ERR("Datasource not found\n");
+ return E_FAIL;
+ }
+
+ ret = SQLConnectW( provider->hdbc, (SQLWCHAR *)V_BSTR(&provider->properties[i].value),
+ SQL_NTS, (SQLWCHAR *)NULL, SQL_NTS, (SQLWCHAR *)NULL, SQL_NTS );
+ TRACE("SQLConnectW ret %d\n", ret);
+ if (ret != SQL_SUCCESS)
+ {
+ dump_sql_diag_records(SQL_HANDLE_DBC, provider->hdbc);
+
+ if (ret != SQL_SUCCESS_WITH_INFO)
+ return E_FAIL;
+ }
return S_OK;
}
@@ -653,6 +705,15 @@ static HRESULT create_msdasql_provider(REFIID riid, void **ppv)
}
}
+ SQLAllocHandle(SQL_HANDLE_ENV, NULL, &provider->henv );
+ if (SQLSetEnvAttr(provider->henv, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3_80, 0) == SQL_ERROR)
+ {
+ WARN("Falling back to SQL_OV_ODBC3\n");
+ SQLSetEnvAttr(provider->henv, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0);
+ }
+
+ SQLAllocHandle(SQL_HANDLE_DBC, provider->henv, &provider->hdbc);
+
hr = IUnknown_QueryInterface(&provider->MSDASQL_iface, riid, ppv);
IUnknown_Release(&provider->MSDASQL_iface);
return hr;
--
2.34.1
1
0
[PATCH v2 1/2] winmm: Test that a callback passed to `waveOutOpen` can call `waveOutWrite` without getting called reentrantly.
by Liam Murphy Jan. 21, 2022
by Liam Murphy Jan. 21, 2022
Jan. 21, 2022
This behaviour is relied upon by Teardown, see https://github.com/ValveSoftware/Proton/issues/4332.
Signed-off-by: Liam Murphy <liampm32(a)gmail.com>
---
v2: Add `todo_wine` to avoid test failure
---
dlls/winmm/tests/wave.c | 159 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 159 insertions(+)
diff --git a/dlls/winmm/tests/wave.c b/dlls/winmm/tests/wave.c
index 2f0c8443363..05e5e3b2d71 100644
--- a/dlls/winmm/tests/wave.c
+++ b/dlls/winmm/tests/wave.c
@@ -865,6 +865,163 @@ EXIT:
HeapFree(GetProcessHeap(), 0, frags);
}
+struct reentrancy_callback_data {
+ HANDLE hevent;
+ // Which thread is currently running the callback, or 0 if it isn't.
+ DWORD running_thread;
+ // How many times the callback's been called.
+ BOOL call_num;
+};
+
+static void CALLBACK reentrancy_callback_func(HWAVEOUT hwo, UINT uMsg,
+ DWORD_PTR dwInstance,
+ DWORD_PTR dwParam1, DWORD_PTR dwParam2)
+{
+ struct reentrancy_callback_data *data = (struct reentrancy_callback_data *)dwInstance;
+
+ data->call_num += 1;
+
+ todo_wine_if(data->call_num == 3)
+ ok(data->running_thread != GetCurrentThreadId(), "winmm callback called reentrantly, with message %u\n", uMsg);
+ if (data->running_thread) {
+ if (data->running_thread != GetCurrentThreadId()) trace("Callback running on two threads simultaneously\n");
+
+ // Don't mess with what the original call was doing.
+ return;
+ }
+ data->running_thread = GetCurrentThreadId();
+
+ // We have to wait for a `WOM_DONE` event rather than just using the `WOM_OPEN` event
+ // so that we're running on the winmm audio thread, so that we can block it
+ // to prevent the next `WOM_DONE` event just getting fired in the background
+ // (and then presumably calling the callback on another thread?)
+ if (uMsg == WOM_DONE) {
+ if (data->call_num == 2) {
+ MMRESULT rc;
+ // Since this is the first `WOM_DONE`, and the first frame is always `frags[0]`, we know that this is actually a pointer to `frags`.
+ WAVEHDR *frags = (WAVEHDR *)dwParam1;
+
+ rc = waveOutWrite(hwo, &frags[0], sizeof(frags[0]));
+ ok(rc==MMSYSERR_NOERROR,"waveOutWrite(): rc=%s\n", wave_out_error(rc));
+
+ // Each frame is supposed to last 100ms, so 150ms should be enough to guarantee that the last one has finished.
+ Sleep(150);
+
+ // This is needed to trigger the bug in wine,
+ // since winmm checks for `WOM_DONE` within `WINMM_PushData`, which this calls.
+ rc = waveOutWrite(hwo, &frags[1], sizeof(frags[0]));
+ ok(rc==MMSYSERR_NOERROR,"waveOutWrite(): rc=%s\n", wave_out_error(rc));
+ }
+ }
+
+ data->running_thread = 0;
+ // Only do this at the end of the function so that it isn't possible for the main thread
+ // to mistakenly call `waveOutClose` while the test is running.
+ SetEvent(data->hevent);
+}
+
+// Test whether the callback gets called reentrantly when `waveOutWrite` is called
+// from within the callback passed to `waveOutOpen`.
+static void wave_out_test_no_reentrancy(int device)
+{
+ HWAVEOUT wout;
+ HANDLE hevent = CreateEventW(NULL, FALSE, FALSE, NULL);
+ WAVEHDR *frags = 0;
+ MMRESULT rc;
+ int headers = 2;
+ int loops = 0;
+ WAVEFORMATEX format;
+ WAVEFORMATEX* pwfx = &format;
+ DWORD flags = CALLBACK_FUNCTION;
+ double duration = 0.2;
+ DWORD_PTR callback = 0;
+ struct reentrancy_callback_data callback_data;
+ DWORD_PTR callback_instance = 0;
+ char * buffer;
+ DWORD length;
+ DWORD frag_length;
+ int i;
+ BOOL done;
+
+ format.wFormatTag=WAVE_FORMAT_PCM;
+ format.nChannels=1;
+ format.wBitsPerSample=8;
+ format.nSamplesPerSec=22050;
+ format.nBlockAlign=format.nChannels*format.wBitsPerSample/8;
+ format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign;
+ format.cbSize=0;
+
+ callback = (DWORD_PTR)reentrancy_callback_func;
+ callback_data.hevent = hevent;
+ callback_data.running_thread = 0;
+ callback_data.call_num = 0;
+ callback_instance = (DWORD_PTR)(&callback_data);
+
+ wout=NULL;
+ rc=waveOutOpen(&wout,device,pwfx,callback,callback_instance,flags);
+ if (rc!=MMSYSERR_NOERROR) {
+ trace("`waveOutOpen` failed with rc %s, skipping", mmsys_error(rc));
+ goto EXIT;
+ }
+
+ rc=WaitForSingleObject(hevent,9000);
+ ok(rc==WAIT_OBJECT_0, "missing WOM_OPEN notification\n");
+
+ frags = HeapAlloc(GetProcessHeap(), 0, headers * sizeof(WAVEHDR));
+
+ buffer=wave_generate_silence(pwfx,duration / (loops + 1),&length);
+
+ /* make sure fragment length is a multiple of block size */
+ frag_length = ((length / headers) / pwfx->nBlockAlign) * pwfx->nBlockAlign;
+
+ for (i = 0; i < headers; i++) {
+ frags[i].lpData=buffer + (i * frag_length);
+ if (i != (headers-1))
+ frags[i].dwBufferLength=frag_length;
+ else {
+ /* use remainder of buffer for last fragment */
+ frags[i].dwBufferLength=length - (i * frag_length);
+ }
+ frags[i].dwFlags=0;
+ frags[i].dwLoops=0;
+ rc=waveOutPrepareHeader(wout, &frags[i], sizeof(frags[0]));
+ ok(rc==MMSYSERR_NOERROR,
+ "waveOutPrepareHeader(%s): rc=%s\n",dev_name(device),wave_out_error(rc));
+ }
+
+ if (rc==MMSYSERR_NOERROR) {
+ // Queue up the first fragment.
+ rc=waveOutWrite(wout, &frags[0], sizeof(frags[0]));
+ ok(rc==MMSYSERR_NOERROR,"waveOutWrite(%s): rc=%s\n",
+ dev_name(device),wave_out_error(rc));
+ }
+
+ done = FALSE;
+ while (!done) {
+ rc=WaitForSingleObject(hevent,8000);
+ ok(rc==WAIT_OBJECT_0, "missing WOM_DONE notification\n");
+
+ done = TRUE;
+ for (i = 0; i < headers; i++) {
+ if (!(frags[i].dwFlags & WHDR_DONE)) {
+ done = FALSE;
+ }
+ }
+ }
+
+ // Calling `waveOutClose` from within the callback hangs on Windows, so we have to make sure to do it here instead.
+ rc = waveOutClose(wout);
+ ok(rc==MMSYSERR_NOERROR,"waveOutClose(): rc=%s\n", wave_out_error(rc));
+
+ rc=WaitForSingleObject(hevent,1500);
+ ok(rc==WAIT_OBJECT_0, "missing WOM_CLOSE notification\n");
+
+ HeapFree(GetProcessHeap(), 0, buffer);
+EXIT:
+ CloseHandle(hevent);
+ HeapFree(GetProcessHeap(), 0, frags);
+}
+
static void wave_out_test_device(UINT_PTR device)
{
WAVEOUTCAPSA capsA;
@@ -984,6 +1141,8 @@ static void wave_out_test_device(UINT_PTR device)
trace(" %s\n",wave_out_caps(capsA.dwSupport));
HeapFree(GetProcessHeap(), 0, nameA);
+ wave_out_test_no_reentrancy(device);
+
if (winetest_interactive && (device != WAVE_MAPPER))
{
trace("Playing a 5 seconds reference tone.\n");
--
2.34.1
1
1
[PATCH] gdiplus: Handle NULL elementdata.combine.left/right in delete_element
by Konstantin Romanov Jan. 21, 2022
by Konstantin Romanov Jan. 21, 2022
Jan. 21, 2022
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52423
Signed-off-by: Konstantin Romanov <incubusrk(a)gmail.com>
---
dlls/gdiplus/gdiplus.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/dlls/gdiplus/gdiplus.c b/dlls/gdiplus/gdiplus.c
index 7c4c68f162f..7b0592c184c 100644
--- a/dlls/gdiplus/gdiplus.c
+++ b/dlls/gdiplus/gdiplus.c
@@ -473,10 +473,14 @@ void delete_element(region_element* element)
case RegionDataInfiniteRect:
break;
default:
- delete_element(element->elementdata.combine.left);
- delete_element(element->elementdata.combine.right);
- heap_free(element->elementdata.combine.left);
- heap_free(element->elementdata.combine.right);
+ if(element->elementdata.combine.left){
+ delete_element(element->elementdata.combine.left);
+ heap_free(element->elementdata.combine.left);
+ }
+ if(element->elementdata.combine.right){
+ delete_element(element->elementdata.combine.right);
+ heap_free(element->elementdata.combine.right);
+ }
break;
}
}
--
2.33.0.windows.1
3
3
[PATCH 1/2] winmm: Test that a callback passed to `waveOutOpen` can call `waveOutWrite` without getting called reentrantly.
by Liam Murphy Jan. 21, 2022
by Liam Murphy Jan. 21, 2022
Jan. 21, 2022
This behaviour is relied upon by Teardown, see https://github.com/ValveSoftware/Proton/issues/4332.
Signed-off-by: Liam Murphy <liampm32(a)gmail.com>
---
dlls/winmm/tests/wave.c | 158 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 158 insertions(+)
diff --git a/dlls/winmm/tests/wave.c b/dlls/winmm/tests/wave.c
index 2f0c8443363..986714bcbde 100644
--- a/dlls/winmm/tests/wave.c
+++ b/dlls/winmm/tests/wave.c
@@ -865,6 +865,162 @@ EXIT:
HeapFree(GetProcessHeap(), 0, frags);
}
+struct reentrancy_callback_data {
+ HANDLE hevent;
+ // Which thread is currently running the callback, or 0 if it isn't.
+ DWORD running_thread;
+ // Whether we've finished our test.
+ BOOL test_done;
+};
+
+static void CALLBACK reentrancy_callback_func(HWAVEOUT hwo, UINT uMsg,
+ DWORD_PTR dwInstance,
+ DWORD_PTR dwParam1, DWORD_PTR dwParam2)
+{
+ struct reentrancy_callback_data *data = (struct reentrancy_callback_data *)dwInstance;
+
+ ok(data->running_thread != GetCurrentThreadId(), "winmm callback called reentrantly, with message %u\n", uMsg);
+ if (data->running_thread) {
+ if (data->running_thread != GetCurrentThreadId()) trace("Callback running on two threads simultaneously\n");
+
+ // Don't mess with what the original call was doing.
+ return;
+ }
+ data->running_thread = GetCurrentThreadId();
+
+ // We have to wait for a `WOM_DONE` event rather than just using the `WOM_OPEN` event
+ // so that we're running on the winmm audio thread, so that we can block it
+ // to prevent the next `WOM_DONE` event just getting fired in the background
+ // (and then presumably calling the callback on another thread?)
+ if (uMsg == WOM_DONE) {
+ if (!data->test_done) {
+ MMRESULT rc;
+ // Since this is the first `WOM_DONE`, and the first frame is always `frags[0]`, we know that this is actually a pointer to `frags`.
+ WAVEHDR *frags = (WAVEHDR *)dwParam1;
+
+ rc = waveOutWrite(hwo, &frags[0], sizeof(frags[0]));
+ ok(rc==MMSYSERR_NOERROR,"waveOutWrite(): rc=%s\n", wave_out_error(rc));
+
+ // Each frame is supposed to last 100ms, so 150ms should be enough to guarantee that the last one has finished.
+ Sleep(150);
+
+ // This is needed to trigger the bug in wine,
+ // since winmm checks for `WOM_DONE` within `WINMM_PushData`, which this calls.
+ rc = waveOutWrite(hwo, &frags[1], sizeof(frags[0]));
+ ok(rc==MMSYSERR_NOERROR,"waveOutWrite(): rc=%s\n", wave_out_error(rc));
+
+ data->test_done = TRUE;
+ }
+ }
+
+ data->running_thread = 0;
+ // Only do this at the end of the function so that it isn't possible for the main thread
+ // to mistakenly call `waveOutClose` while the test is running.
+ SetEvent(data->hevent);
+}
+
+// Test whether the callback gets called reentrantly when `waveOutWrite` is called
+// from within the callback passed to `waveOutOpen`.
+static void wave_out_test_no_reentrancy(int device)
+{
+ HWAVEOUT wout;
+ HANDLE hevent = CreateEventW(NULL, FALSE, FALSE, NULL);
+ WAVEHDR *frags = 0;
+ MMRESULT rc;
+ int headers = 2;
+ int loops = 0;
+ WAVEFORMATEX format;
+ WAVEFORMATEX* pwfx = &format;
+ DWORD flags = CALLBACK_FUNCTION;
+ double duration = 0.2;
+ DWORD_PTR callback = 0;
+ struct reentrancy_callback_data callback_data;
+ DWORD_PTR callback_instance = 0;
+ char * buffer;
+ DWORD length;
+ DWORD frag_length;
+ int i;
+ BOOL done;
+
+ format.wFormatTag=WAVE_FORMAT_PCM;
+ format.nChannels=1;
+ format.wBitsPerSample=8;
+ format.nSamplesPerSec=22050;
+ format.nBlockAlign=format.nChannels*format.wBitsPerSample/8;
+ format.nAvgBytesPerSec=format.nSamplesPerSec*format.nBlockAlign;
+ format.cbSize=0;
+
+ callback = (DWORD_PTR)reentrancy_callback_func;
+ callback_data.hevent = hevent;
+ callback_data.running_thread = 0;
+ callback_data.test_done = FALSE;
+ callback_instance = (DWORD_PTR)(&callback_data);
+
+ wout=NULL;
+ rc=waveOutOpen(&wout,device,pwfx,callback,callback_instance,flags);
+ if (rc!=MMSYSERR_NOERROR) {
+ trace("`waveOutOpen` failed with rc %s, skipping", mmsys_error(rc));
+ goto EXIT;
+ }
+
+ rc=WaitForSingleObject(hevent,9000);
+ ok(rc==WAIT_OBJECT_0, "missing WOM_OPEN notification\n");
+
+ frags = HeapAlloc(GetProcessHeap(), 0, headers * sizeof(WAVEHDR));
+
+ buffer=wave_generate_silence(pwfx,duration / (loops + 1),&length);
+
+ /* make sure fragment length is a multiple of block size */
+ frag_length = ((length / headers) / pwfx->nBlockAlign) * pwfx->nBlockAlign;
+
+ for (i = 0; i < headers; i++) {
+ frags[i].lpData=buffer + (i * frag_length);
+ if (i != (headers-1))
+ frags[i].dwBufferLength=frag_length;
+ else {
+ /* use remainder of buffer for last fragment */
+ frags[i].dwBufferLength=length - (i * frag_length);
+ }
+ frags[i].dwFlags=0;
+ frags[i].dwLoops=0;
+ rc=waveOutPrepareHeader(wout, &frags[i], sizeof(frags[0]));
+ ok(rc==MMSYSERR_NOERROR,
+ "waveOutPrepareHeader(%s): rc=%s\n",dev_name(device),wave_out_error(rc));
+ }
+
+ if (rc==MMSYSERR_NOERROR) {
+ // Queue up the first fragment.
+ rc=waveOutWrite(wout, &frags[0], sizeof(frags[0]));
+ ok(rc==MMSYSERR_NOERROR,"waveOutWrite(%s): rc=%s\n",
+ dev_name(device),wave_out_error(rc));
+ }
+
+ done = FALSE;
+ while (!done) {
+ rc=WaitForSingleObject(hevent,8000);
+ ok(rc==WAIT_OBJECT_0, "missing WOM_DONE notification\n");
+
+ done = TRUE;
+ for (i = 0; i < headers; i++) {
+ if (!(frags[i].dwFlags & WHDR_DONE)) {
+ done = FALSE;
+ }
+ }
+ }
+
+ // Calling `waveOutClose` from within the callback hangs on Windows, so we have to make sure to do it here instead.
+ rc = waveOutClose(wout);
+ ok(rc==MMSYSERR_NOERROR,"waveOutClose(): rc=%s\n", wave_out_error(rc));
+
+ rc=WaitForSingleObject(hevent,1500);
+ ok(rc==WAIT_OBJECT_0, "missing WOM_CLOSE notification\n");
+
+ HeapFree(GetProcessHeap(), 0, buffer);
+EXIT:
+ CloseHandle(hevent);
+ HeapFree(GetProcessHeap(), 0, frags);
+}
+
static void wave_out_test_device(UINT_PTR device)
{
WAVEOUTCAPSA capsA;
@@ -984,6 +1140,8 @@ static void wave_out_test_device(UINT_PTR device)
trace(" %s\n",wave_out_caps(capsA.dwSupport));
HeapFree(GetProcessHeap(), 0, nameA);
+ wave_out_test_no_reentrancy(device);
+
if (winetest_interactive && (device != WAVE_MAPPER))
{
trace("Playing a 5 seconds reference tone.\n");
--
2.34.1
2
1
[PATCH 2/2] winmm: Buffer any WOM_DONE/WIM_DATA events triggered from within a waveOut/waveIn callback.
by Liam Murphy Jan. 21, 2022
by Liam Murphy Jan. 21, 2022
Jan. 21, 2022
The events are then fired after the callback completes.
Signed-off-by: Liam Murphy <liampm32(a)gmail.com>
---
dlls/winmm/waveform.c | 165 +++++++++++++++++++++++++++++++-----------
1 file changed, 124 insertions(+), 41 deletions(-)
diff --git a/dlls/winmm/waveform.c b/dlls/winmm/waveform.c
index 1159b48b483..55b18b3e4dd 100644
--- a/dlls/winmm/waveform.c
+++ b/dlls/winmm/waveform.c
@@ -67,12 +67,20 @@ WINE_DEFAULT_DEBUG_CHANNEL(winmm);
#define AC_BUFLEN (10 * 100000)
#define MAX_DEVICES 256
#define MAPPER_INDEX 0x3F
+#define CB_RUNNING 0x10
typedef struct _WINMM_CBInfo {
DWORD_PTR callback;
DWORD_PTR user;
+ // Layout: 0b00000000_000r0ttt
+ // where t: callback type (`DCB_*` constants)
+ // r: Whether the callback is currently running, to avoid reentrancy.
+ // The 0 in the middle is `DCB_NOSWITCH`.
DWORD flags;
HWAVE hwave;
+ // Used to buffer data from `WIM_DATA` or `WOM_DONE` if the callback is still running,
+ // depending on whether this is an input or output device respectively.
+ WAVEHDR *first, *last;
} WINMM_CBInfo;
struct _WINMM_MMDevice;
@@ -169,6 +177,12 @@ typedef struct _WINMM_OpenInfo {
WAVEFORMATEX *format;
DWORD_PTR callback;
DWORD_PTR cb_user;
+ // The high half of the bits are the same as `WINMM_CBInfo.flags`,
+ // and the low half have the layout 0b00000000_0000dmaq,
+ // where d: `WAVE_FORMAT_DIRECT`,
+ // m: `WAVE_MAPPED`,
+ // a: `WAVE_ALLOWSYNC`,
+ // q: `WAVE_FORMAT_QUERY`.
DWORD flags;
BOOL reset;
} WINMM_OpenInfo;
@@ -370,13 +384,103 @@ static WINMM_Device *WINMM_GetDeviceFromHWAVE(HWAVE hwave)
return device;
}
+// Note: the lock on `device` must already have been acquired before calling this function.
+static inline void WINMM_SendBufferedMessages(WINMM_Device *device) {
+ WINMM_CBInfo* info = &device->cb_info;
+ // Make a copy of this to pass to the callback while within the critical section,
+ // since it can be mutated once we leave the critical section.
+ DWORD cb_type = info->flags;
+
+ while (info->first) {
+ WAVEHDR* hdr;
+ WORD new_msg;
+
+ if (device->render) {
+ new_msg = WOM_DONE;
+ } else {
+ new_msg = WIM_DATA;
+ }
+
+ hdr = info->first;
+ info->first = hdr->lpNext;
+ hdr->lpNext = NULL;
+
+ LeaveCriticalSection(&device->lock);
+
+ DriverCallback(info->callback, cb_type, (HDRVR)info->hwave,
+ new_msg, info->user, (DWORD_PTR)hdr, 0);
+
+ EnterCriticalSection(&device->lock);
+ }
+}
+
/* Note: NotifyClient should never be called while holding the device lock
- * since the client may call wave* functions from within the callback. */
-static inline void WINMM_NotifyClient(WINMM_CBInfo *info, WORD msg, DWORD_PTR param1,
- DWORD_PTR param2)
+ * since the client may call wave* functions from within the callback.
+ *
+ * Any `WAVEHDR`s passed to this function must no longer be referenced by any other `WAVEHDR`s,
+ * so that their linked list can be reused to buffer them when this is called from within the callback. */
+static inline void WINMM_NotifyClient(WINMM_Device *device, WORD msg, WAVEHDR* param1,
+ WAVEHDR* param2)
{
- DriverCallback(info->callback, info->flags, (HDRVR)info->hwave,
- msg, info->user, param1, param2);
+ WINMM_CBInfo *info;
+ DWORD cb_type;
+
+ EnterCriticalSection(&device->lock);
+ info = &device->cb_info;
+ // Make a copy of this to pass to the callback while within the critical section,
+ // since it can be mutated once we leave the critical section.
+ cb_type = info->flags;
+
+ if (info->flags & CB_RUNNING) {
+ switch (msg) {
+ case WIM_DATA:
+ case WOM_DONE:
+ param1->lpNext = NULL;
+ if (!info->first) {
+ info->first = info->last = param1;
+ } else {
+ info->last->lpNext = param1;
+ info->last = param1;
+ }
+ break;
+ case WIM_CLOSE:
+ case WOM_CLOSE:
+ // If this device is closing, it might get reopened as another kind of device
+ // with all the buffered messages wiped, causing them to never get sent.
+ // So we need to send them all now.
+ //
+ // On Windows, calling `waveOutClose` from within `DriverCallback` hangs anyway,
+ // so this causing reentrancy isn't really a problem.
+ WINMM_SendBufferedMessages(device);
+
+ LeaveCriticalSection(&device->lock);
+
+ DriverCallback(info->callback, cb_type, (HDRVR)info->hwave,
+ msg, info->user, (DWORD_PTR)param1, (DWORD_PTR)param2);
+
+ EnterCriticalSection(&device->lock);
+ break;
+ }
+ } else {
+ if ((info->flags & DCB_TYPEMASK) == DCB_FUNCTION) {
+ info->flags |= CB_RUNNING;
+ }
+
+ LeaveCriticalSection(&device->lock);
+
+ DriverCallback(info->callback, cb_type, (HDRVR)info->hwave,
+ msg, info->user, (DWORD_PTR)param1, (DWORD_PTR)param2);
+
+ EnterCriticalSection(&device->lock);
+
+ if ((info->flags & DCB_TYPEMASK) == DCB_FUNCTION) {
+ WINMM_SendBufferedMessages(device);
+
+ info->flags &= ~CB_RUNNING;
+ }
+ }
+
+ LeaveCriticalSection(&device->lock);
}
static MMRESULT hr2mmr(HRESULT hr)
@@ -1202,6 +1306,8 @@ static LRESULT WINMM_OpenDevice(WINMM_Device *device, WINMM_OpenInfo *info,
device->cb_info.callback = info->callback;
device->cb_info.user = info->cb_user;
device->cb_info.hwave = device->handle;
+ device->cb_info.first = NULL;
+ device->cb_info.last = NULL;
info->handle = device->handle;
@@ -1623,7 +1729,6 @@ static WAVEHDR *WOD_MarkDoneHeaders(WINMM_Device *device)
static void WOD_PushData(WINMM_Device *device)
{
- WINMM_CBInfo cb_info;
HRESULT hr;
UINT32 pad, bufsize, avail_frames, queue_frames, written, ofs;
UINT32 queue_bytes, nloops;
@@ -1752,15 +1857,13 @@ static void WOD_PushData(WINMM_Device *device)
device->played_frames += avail_frames;
exit:
- cb_info = device->cb_info;
-
LeaveCriticalSection(&device->lock);
while(first){
WAVEHDR *next = first->lpNext;
first->dwFlags &= ~WHDR_INQUEUE;
first->dwFlags |= WHDR_DONE;
- WINMM_NotifyClient(&cb_info, WOM_DONE, (DWORD_PTR)first, 0);
+ WINMM_NotifyClient(device, WOM_DONE, first, 0);
first = next;
}
}
@@ -1860,7 +1963,6 @@ static void WID_PullACMData(WINMM_Device *device)
static void WID_PullData(WINMM_Device *device)
{
- WINMM_CBInfo cb_info;
WAVEHDR *queue, *first = NULL, *last = NULL;
HRESULT hr;
@@ -1926,8 +2028,6 @@ static void WID_PullData(WINMM_Device *device)
}
exit:
- cb_info = device->cb_info;
-
LeaveCriticalSection(&device->lock);
if(last){
@@ -1936,7 +2036,7 @@ exit:
WAVEHDR *next = first->lpNext;
first->dwFlags &= ~WHDR_INQUEUE;
first->dwFlags |= WHDR_DONE;
- WINMM_NotifyClient(&cb_info, WIM_DATA, (DWORD_PTR)first, 0);
+ WINMM_NotifyClient(device, WIM_DATA, first, 0);
first = next;
}
}
@@ -1985,7 +2085,6 @@ static LRESULT WINMM_Pause(WINMM_Device *device)
static LRESULT WINMM_Reset(HWAVE hwave)
{
- WINMM_CBInfo cb_info;
WINMM_Device *device = WINMM_GetDeviceFromHWAVE(hwave);
BOOL is_out;
WAVEHDR *first;
@@ -2012,7 +2111,6 @@ static LRESULT WINMM_Reset(HWAVE hwave)
device->last_clock_pos = 0;
IAudioClient_Reset(device->client);
- cb_info = device->cb_info;
is_out = device->render != NULL;
LeaveCriticalSection(&device->lock);
@@ -2022,9 +2120,9 @@ static LRESULT WINMM_Reset(HWAVE hwave)
first->dwFlags &= ~WHDR_INQUEUE;
first->dwFlags |= WHDR_DONE;
if(is_out)
- WINMM_NotifyClient(&cb_info, WOM_DONE, (DWORD_PTR)first, 0);
+ WINMM_NotifyClient(device, WOM_DONE, first, 0);
else
- WINMM_NotifyClient(&cb_info, WIM_DATA, (DWORD_PTR)first, 0);
+ WINMM_NotifyClient(device, WIM_DATA, first, 0);
first = next;
}
@@ -2732,7 +2830,7 @@ MMRESULT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID,
{
LRESULT res;
WINMM_OpenInfo info;
- WINMM_CBInfo cb_info;
+ WINMM_Device* device;
TRACE("(%p, %u, %p, %lx, %lx, %08x)\n", lphWaveOut, uDeviceID, lpFormat,
dwCallback, dwInstance, dwFlags);
@@ -2763,12 +2861,9 @@ MMRESULT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID,
if(lphWaveOut)
*lphWaveOut = (HWAVEOUT)info.handle;
- cb_info.flags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
- cb_info.callback = dwCallback;
- cb_info.user = dwInstance;
- cb_info.hwave = info.handle;
+ device = WINMM_GetDeviceFromHWAVE(info.handle);
- WINMM_NotifyClient(&cb_info, WOM_OPEN, 0, 0);
+ WINMM_NotifyClient(device, WOM_OPEN, 0, 0);
return res;
}
@@ -2780,7 +2875,6 @@ UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
{
UINT res;
WINMM_Device *device;
- WINMM_CBInfo cb_info;
TRACE("(%p)\n", hWaveOut);
@@ -2789,14 +2883,12 @@ UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
if(!WINMM_ValidateAndLock(device))
return MMSYSERR_INVALHANDLE;
- cb_info = device->cb_info;
-
LeaveCriticalSection(&device->lock);
res = SendMessageW(g_devices_hwnd, WODM_CLOSE, (WPARAM)hWaveOut, 0);
if(res == MMSYSERR_NOERROR)
- WINMM_NotifyClient(&cb_info, WOM_CLOSE, 0, 0);
+ WINMM_NotifyClient(device, WOM_CLOSE, 0, 0);
return res;
}
@@ -3388,7 +3480,7 @@ MMRESULT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
{
LRESULT res;
WINMM_OpenInfo info;
- WINMM_CBInfo cb_info;
+ WINMM_Device* device;
TRACE("(%p, %x, %p, %lx, %lx, %08x)\n", lphWaveIn, uDeviceID, lpFormat,
dwCallback, dwInstance, dwFlags);
@@ -3419,12 +3511,9 @@ MMRESULT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
if(lphWaveIn)
*lphWaveIn = (HWAVEIN)info.handle;
- cb_info.flags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
- cb_info.callback = dwCallback;
- cb_info.user = dwInstance;
- cb_info.hwave = info.handle;
+ device = WINMM_GetDeviceFromHWAVE(info.handle);
- WINMM_NotifyClient(&cb_info, WIM_OPEN, 0, 0);
+ WINMM_NotifyClient(device, WIM_OPEN, 0, 0);
return res;
}
@@ -3435,7 +3524,6 @@ MMRESULT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
UINT WINAPI waveInClose(HWAVEIN hWaveIn)
{
WINMM_Device *device;
- WINMM_CBInfo cb_info;
UINT res;
TRACE("(%p)\n", hWaveIn);
@@ -3445,14 +3533,12 @@ UINT WINAPI waveInClose(HWAVEIN hWaveIn)
if(!WINMM_ValidateAndLock(device))
return MMSYSERR_INVALHANDLE;
- cb_info = device->cb_info;
-
LeaveCriticalSection(&device->lock);
res = SendMessageW(g_devices_hwnd, WIDM_CLOSE, (WPARAM)hWaveIn, 0);
if(res == MMSYSERR_NOERROR)
- WINMM_NotifyClient(&cb_info, WIM_CLOSE, 0, 0);
+ WINMM_NotifyClient(device, WIM_CLOSE, 0, 0);
return res;
}
@@ -3568,7 +3654,6 @@ UINT WINAPI waveInStart(HWAVEIN hWaveIn)
*/
UINT WINAPI waveInStop(HWAVEIN hWaveIn)
{
- WINMM_CBInfo cb_info;
WINMM_Device *device;
WAVEHDR *buf;
HRESULT hr;
@@ -3593,14 +3678,12 @@ UINT WINAPI waveInStop(HWAVEIN hWaveIn)
}else
buf = NULL;
- cb_info = device->cb_info;
-
LeaveCriticalSection(&device->lock);
if(buf){
buf->dwFlags &= ~WHDR_INQUEUE;
buf->dwFlags |= WHDR_DONE;
- WINMM_NotifyClient(&cb_info, WIM_DATA, (DWORD_PTR)buf, 0);
+ WINMM_NotifyClient(device, WIM_DATA, buf, 0);
}
return MMSYSERR_NOERROR;
--
2.34.1
1
0
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51850
Signed-off-by: Mohamad Al-Jaf <mohamadaljaf(a)gmail.com>
---
v3: - Swap operands for arm and aarch64 (Credit: Jinoh Kang)
- Use void * instead of int for CurrentIP
- Add useful test (Credit: Giovanni Mascellani)
- Remove unnecessary #include <stdint.h>
Note: In the test I had to remove WINAPI from the declaration
because it would result in an 'undefined reference' error only
in the 32-bit build of Wine. The 64-bit build compiled without
any problems.
I don't understand why this happens.
---
configure.ac | 1 +
dlls/wdscore/Makefile.in | 3 ++
dlls/wdscore/main.c | 54 ++++++++++++++++++++++++++++++++++
dlls/wdscore/tests/Makefile.in | 5 ++++
dlls/wdscore/tests/main.c | 41 ++++++++++++++++++++++++++
dlls/wdscore/wdscore.spec | 2 +-
6 files changed, 105 insertions(+), 1 deletion(-)
create mode 100644 dlls/wdscore/main.c
create mode 100644 dlls/wdscore/tests/Makefile.in
create mode 100644 dlls/wdscore/tests/main.c
diff --git a/configure.ac b/configure.ac
index b42cb8a5346..a50881cc2fb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3347,6 +3347,7 @@ WINE_CONFIG_MAKEFILE(dlls/wbemdisp/tests)
WINE_CONFIG_MAKEFILE(dlls/wbemprox)
WINE_CONFIG_MAKEFILE(dlls/wbemprox/tests)
WINE_CONFIG_MAKEFILE(dlls/wdscore)
+WINE_CONFIG_MAKEFILE(dlls/wdscore/tests)
WINE_CONFIG_MAKEFILE(dlls/webservices)
WINE_CONFIG_MAKEFILE(dlls/webservices/tests)
WINE_CONFIG_MAKEFILE(dlls/websocket)
diff --git a/dlls/wdscore/Makefile.in b/dlls/wdscore/Makefile.in
index 20ba1d3b1c9..2020e72c7bb 100644
--- a/dlls/wdscore/Makefile.in
+++ b/dlls/wdscore/Makefile.in
@@ -1,3 +1,6 @@
MODULE = wdscore.dll
EXTRADLLFLAGS = -Wb,--prefer-native
+
+C_SRCS = \
+ main.c
diff --git a/dlls/wdscore/main.c b/dlls/wdscore/main.c
new file mode 100644
index 00000000000..24371068980
--- /dev/null
+++ b/dlls/wdscore/main.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2022 Mohamad Al-Jaf
+ *
+ * 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>
+
+#include "windef.h"
+#include "winbase.h"
+
+#include "wine/asm.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wdscore);
+
+/***********************************************************************
+ * CurrentIP (wdscore.@)
+ */
+#ifdef __i386__
+__ASM_STDCALL_FUNC(CurrentIP, 0,
+ "movl 0(%esp), %eax\n\t"
+ "ret" )
+#elif defined(__x86_64__)
+__ASM_STDCALL_FUNC(CurrentIP, 0,
+ "movq 0(%rsp), %rax\n\t"
+ "ret" )
+#elif defined(__arm__)
+__ASM_STDCALL_FUNC(CurrentIP, 0,
+ "mov r0, lr\n\t"
+ "bx lr" )
+#elif defined(__aarch64__)
+__ASM_STDCALL_FUNC(CurrentIP, 0,
+ "mov x0, lr\n\t"
+ "ret" )
+#else
+void *WINAPI CurrentIP(void)
+{
+ FIXME( "not implemented\n" );
+ return 0;
+}
+#endif
diff --git a/dlls/wdscore/tests/Makefile.in b/dlls/wdscore/tests/Makefile.in
new file mode 100644
index 00000000000..f0606d902d5
--- /dev/null
+++ b/dlls/wdscore/tests/Makefile.in
@@ -0,0 +1,5 @@
+TESTDLL = wdscore.dll
+IMPORTS = wdscore
+
+C_SRCS = \
+ main.c
diff --git a/dlls/wdscore/tests/main.c b/dlls/wdscore/tests/main.c
new file mode 100644
index 00000000000..71de31a1a0a
--- /dev/null
+++ b/dlls/wdscore/tests/main.c
@@ -0,0 +1,41 @@
+/*
+ * Unit test suite for wdscore
+ *
+ * Copyright 2022 Mohamad Al-Jaf
+ *
+ * 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 "wine/test.h"
+#include "winbase.h"
+
+extern void *CurrentIP(void);
+
+static void test_CurrentIP(void)
+{
+ char *cur;
+ char *ret;
+
+ cur = (char*)&test_CurrentIP;
+ ret = (char*)CurrentIP();
+
+ ok(cur <= ret && ret < (cur + 0x100), "Address %p not in function starting at %p.\n", ret, cur);
+}
+
+START_TEST(main)
+{
+ test_CurrentIP();
+}
diff --git a/dlls/wdscore/wdscore.spec b/dlls/wdscore/wdscore.spec
index 15958b86aba..8b6febe6b3b 100644
--- a/dlls/wdscore/wdscore.spec
+++ b/dlls/wdscore/wdscore.spec
@@ -71,7 +71,7 @@
@ stub ConstructPartialMsgIfW
@ stub ConstructPartialMsgVA
@ stub ConstructPartialMsgVW
-@ stub CurrentIP
+@ stdcall CurrentIP()
@ stub EndMajorTask
@ stub EndMinorTask
@ stub GetMajorTask
--
2.34.1
3
4
[PATCH] server: Allocate enough space for the backslash in dup_nt_name() (Valgrind).
by Zebediah Figura Jan. 20, 2022
by Zebediah Figura Jan. 20, 2022
Jan. 20, 2022
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
server/fd.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/server/fd.c b/server/fd.c
index c9a21186722..1b4b98b0e76 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1867,7 +1867,7 @@ static WCHAR *dup_nt_name( struct fd *root, struct unicode_str name, data_size_t
name.str++;
name.len -= sizeof(WCHAR);
}
- if ((ret = malloc( retlen + name.len + 1 )))
+ if ((ret = malloc( retlen + name.len + sizeof(WCHAR) )))
{
memcpy( ret, root->nt_name, root->nt_namelen );
if (name.len && name.str[0] != '\\' &&
--
2.34.1
1
0
[PATCH v8 1/2] kernel32/tests: Test module refcounting with forwarded exports.
by Jinoh Kang Jan. 20, 2022
by Jinoh Kang Jan. 20, 2022
Jan. 20, 2022
Signed-off-by: Jinoh Kang <jinoh.kang.kr(a)gmail.com>
---
Notes:
v3 -> v4:
- iatgas.h
- LLVM(Clang), ARM, ARM64 support
- Use __ASM_NAME macro
- Don't fail test on MSVC
- Don't end asm macros with "\n\t"
v4 -> v5:
- iatgas.h
- mark idata sections as RO
- loader.c
- test for forward export itself
v5 -> v6:
- loader.c
- Fix compilation warning in format string
v6 -> v7:
- forward4.c
- fix building without MinGW
v7 -> v8:
- forward[1-3].c
- Call DisableThreadLibraryCalls in DllMain
- forward4.c: removed
- iatgas.h: removed
- sforward.c: new file
- loader.c
- test static forwarded import using shlwapi -> userenv forward
dlls/kernel32/tests/Makefile.in | 14 ++-
dlls/kernel32/tests/forward1.c | 19 ++++
dlls/kernel32/tests/forward1.spec | 2 +
dlls/kernel32/tests/forward2.c | 9 ++
dlls/kernel32/tests/forward2.spec | 2 +
dlls/kernel32/tests/forward3.c | 9 ++
dlls/kernel32/tests/forward3.spec | 2 +
dlls/kernel32/tests/loader.c | 177 ++++++++++++++++++++++++++++++
dlls/kernel32/tests/sforward.c | 16 +++
dlls/kernel32/tests/sforward.spec | 1 +
10 files changed, 249 insertions(+), 2 deletions(-)
create mode 100644 dlls/kernel32/tests/forward1.c
create mode 100644 dlls/kernel32/tests/forward1.spec
create mode 100644 dlls/kernel32/tests/forward2.c
create mode 100644 dlls/kernel32/tests/forward2.spec
create mode 100644 dlls/kernel32/tests/forward3.c
create mode 100644 dlls/kernel32/tests/forward3.spec
create mode 100644 dlls/kernel32/tests/sforward.c
create mode 100644 dlls/kernel32/tests/sforward.spec
diff --git a/dlls/kernel32/tests/Makefile.in b/dlls/kernel32/tests/Makefile.in
index e9516603ce9..1f8dd3b86a0 100644
--- a/dlls/kernel32/tests/Makefile.in
+++ b/dlls/kernel32/tests/Makefile.in
@@ -1,5 +1,7 @@
TESTDLL = kernel32.dll
-IMPORTS = user32 advapi32
+
+# shlwapi is for testing export forwarding (to userenv)
+IMPORTS = user32 advapi32 shlwapi
SOURCES = \
actctx.c \
@@ -37,4 +39,12 @@ SOURCES = \
toolhelp.c \
version.c \
virtual.c \
- volume.c
+ volume.c \
+ forward1.c \
+ forward1.spec \
+ forward2.c \
+ forward2.spec \
+ forward3.c \
+ forward3.spec \
+ sforward.c \
+ sforward.spec
diff --git a/dlls/kernel32/tests/forward1.c b/dlls/kernel32/tests/forward1.c
new file mode 100644
index 00000000000..6419d95eaea
--- /dev/null
+++ b/dlls/kernel32/tests/forward1.c
@@ -0,0 +1,19 @@
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved)
+{
+ if (reason == DLL_PROCESS_ATTACH)
+ DisableThreadLibraryCalls( instance_new );
+ return TRUE;
+}
+
+unsigned long forward_test_func(void)
+{
+ return 0x00005678UL;
+}
+
+unsigned long forward_test_func2(void)
+{
+ return 0x12340000UL;
+}
diff --git a/dlls/kernel32/tests/forward1.spec b/dlls/kernel32/tests/forward1.spec
new file mode 100644
index 00000000000..bf19fa7e011
--- /dev/null
+++ b/dlls/kernel32/tests/forward1.spec
@@ -0,0 +1,2 @@
+1 cdecl forward_test_func()
+2 cdecl -noname forward_test_func2()
diff --git a/dlls/kernel32/tests/forward2.c b/dlls/kernel32/tests/forward2.c
new file mode 100644
index 00000000000..d1e77f45f3c
--- /dev/null
+++ b/dlls/kernel32/tests/forward2.c
@@ -0,0 +1,9 @@
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved)
+{
+ if (reason == DLL_PROCESS_ATTACH)
+ DisableThreadLibraryCalls( instance_new );
+ return TRUE;
+}
diff --git a/dlls/kernel32/tests/forward2.spec b/dlls/kernel32/tests/forward2.spec
new file mode 100644
index 00000000000..374156d8d06
--- /dev/null
+++ b/dlls/kernel32/tests/forward2.spec
@@ -0,0 +1,2 @@
+1 cdecl forward_test_func() forward1.forward_test_func
+2 cdecl -noname forward_test_func2() forward1.#2
diff --git a/dlls/kernel32/tests/forward3.c b/dlls/kernel32/tests/forward3.c
new file mode 100644
index 00000000000..d1e77f45f3c
--- /dev/null
+++ b/dlls/kernel32/tests/forward3.c
@@ -0,0 +1,9 @@
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved)
+{
+ if (reason == DLL_PROCESS_ATTACH)
+ DisableThreadLibraryCalls( instance_new );
+ return TRUE;
+}
diff --git a/dlls/kernel32/tests/forward3.spec b/dlls/kernel32/tests/forward3.spec
new file mode 100644
index 00000000000..31d019aa071
--- /dev/null
+++ b/dlls/kernel32/tests/forward3.spec
@@ -0,0 +1,2 @@
+1 cdecl forward_test_func() forward2.forward_test_func
+2 cdecl -noname forward_test_func2() forward2.#2
diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c
index f990d632f73..1efd5a7fa5d 100644
--- a/dlls/kernel32/tests/loader.c
+++ b/dlls/kernel32/tests/loader.c
@@ -1642,6 +1642,180 @@ static void test_ImportDescriptors(void)
}
}
+static void extract_resource(const char *name, const char *type, const char *path)
+{
+ DWORD written;
+ HANDLE file;
+ HRSRC res;
+ void *ptr;
+
+ file = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
+ ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", path, GetLastError());
+
+ res = FindResourceA(NULL, name, type);
+ ok( res != 0, "couldn't find resource\n" );
+ ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res ));
+ WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL );
+ ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" );
+ CloseHandle( file );
+}
+
+static void test_static_forwarded_import_refs(void)
+{
+ CHAR temp_path[MAX_PATH], dir_path[MAX_PATH], sforward_path[MAX_PATH];
+ HMODULE userenv, shlwapi, sforward;
+ FARPROC test_func_stub;
+
+ if (GetModuleHandleA( "userenv.dll" ))
+ {
+ skip("cannot test since userenv.dll is already loaded\n");
+ return;
+ }
+
+ GetTempPathA( ARRAY_SIZE(temp_path), temp_path );
+ GetTempFileNameA( temp_path, "ldr", GetTickCount() | 1UL, dir_path );
+ ok( CreateDirectoryA( dir_path, NULL ), "failed to create dir %s, error %u\n",
+ dir_path, GetLastError() );
+
+ snprintf( sforward_path, MAX_PATH, "%s\\sforward.dll", dir_path );
+ extract_resource( "sforward.dll", "TESTDLL", sforward_path );
+
+ userenv = LoadLibraryA( "userenv.dll" );
+ ok( !!userenv, "couldn't find userenv.dll: %u\n", GetLastError() );
+ shlwapi = LoadLibraryA( "shlwapi.dll" );
+ ok( !!shlwapi, "couldn't find shlwapi.dll: %u\n", GetLastError() );
+ sforward = LoadLibraryA( sforward_path );
+ ok( !!sforward, "couldn't find %s: %u\n", sforward_path, GetLastError() );
+
+ test_func_stub = GetProcAddress( sforward, "test_func_stub" );
+ ok( !!test_func_stub, "sforward!test_func_stub not found\n" );
+
+ FreeLibrary( userenv );
+ FreeLibrary( shlwapi );
+
+ todo_wine
+ ok( !!GetModuleHandleA( "userenv.dll" ), "userenv.dll unexpectedly unloaded\n" );
+ ok( !!GetModuleHandleA( "shlwapi.dll" ), "shlwapi.dll unexpectedly unloaded\n" );
+
+ FreeLibrary( sforward );
+
+ ok( !GetModuleHandleA( "userenv.dll" ), "userenv.dll unexpectedly kept open\n" );
+ ok( !GetModuleHandleA( "shlwapi.dll" ), "shlwapi.dll unexpectedly kept open\n" );
+ ok( !GetModuleHandleA( "sforward.dll" ), "sforward.dll unexpectedly kept open\n" );
+
+ DeleteFileA( sforward_path );
+ RemoveDirectoryA( dir_path );
+}
+
+static void test_dynamic_forwarded_import_refs(void)
+{
+ CHAR temp_path[MAX_PATH], dir_path[MAX_PATH];
+ CHAR forward1_path[MAX_PATH];
+ CHAR forward2_path[MAX_PATH];
+ CHAR forward3_path[MAX_PATH];
+ HMODULE forward1, forward2, forward3;
+ FARPROC proc1, proc2, proc3, oproc1, oproc2, oproc3;
+
+ GetTempPathA( ARRAY_SIZE(temp_path), temp_path );
+ GetTempFileNameA( temp_path, "ldr", GetTickCount() | 1UL, dir_path );
+ ok( CreateDirectoryA( dir_path, NULL ), "failed to create dir %s, error %u\n",
+ dir_path, GetLastError() );
+
+ snprintf( forward1_path, MAX_PATH, "%s\\forward1.dll", dir_path );
+ snprintf( forward2_path, MAX_PATH, "%s\\forward2.dll", dir_path );
+ snprintf( forward3_path, MAX_PATH, "%s\\forward3.dll", dir_path );
+ extract_resource( "forward1.dll", "TESTDLL", forward1_path );
+ extract_resource( "forward2.dll", "TESTDLL", forward2_path );
+ extract_resource( "forward3.dll", "TESTDLL", forward3_path );
+
+ forward1 = LoadLibraryA( forward1_path );
+ ok( !!forward1, "couldn't find %s: %u\n", forward1_path, GetLastError() );
+ forward2 = LoadLibraryA( forward2_path );
+ ok( !!forward2, "couldn't find %s: %u\n", forward2_path, GetLastError() );
+ forward3 = LoadLibraryA( forward3_path );
+ ok( !!forward3, "couldn't find %s: %u\n", forward3_path, GetLastError() );
+
+ proc1 = GetProcAddress(forward1, "forward_test_func");
+ ok( !!proc1, "cannot resolve forward1!forward_test_func\n");
+ proc2 = GetProcAddress(forward2, "forward_test_func");
+ ok( !!proc2, "cannot resolve forward2!forward_test_func\n");
+ proc3 = GetProcAddress(forward3, "forward_test_func");
+ ok( !!proc3, "cannot resolve forward3!forward_test_func\n");
+ ok( proc1 == proc3, "forward1!forward_test_func is not equal to forward3!forward_test_func\n");
+ ok( proc2 == proc3, "forward2!forward_test_func is not equal to forward3!forward_test_func\n");
+
+ oproc1 = GetProcAddress(forward1, (LPSTR)2);
+ ok( !!oproc1, "cannot resolve forward1!#2 (forward_test_func2)\n");
+ oproc2 = GetProcAddress(forward2, (LPSTR)2);
+ ok( !!oproc2, "cannot resolve forward2!#2 (forward_test_func2)\n");
+ oproc3 = GetProcAddress(forward3, (LPSTR)2);
+ ok( !!oproc3, "cannot resolve forward3!#2 (forward_test_func2)\n");
+ ok( oproc1 == oproc3, "forward1!forward_test_func2 is not equal to forward3!forward_test_func2\n");
+ ok( oproc2 == oproc3, "forward2!forward_test_func2 is not equal to forward3!forward_test_func2\n");
+
+ FreeLibrary( forward1 );
+ FreeLibrary( forward2 );
+
+ todo_wine
+ ok( !!GetModuleHandleA( "forward1.dll" ), "forward1.dll unexpectedly unloaded\n" );
+ todo_wine
+ ok( !!GetModuleHandleA( "forward2.dll" ), "forward2.dll unexpectedly unloaded\n" );
+
+ FreeLibrary( forward3 );
+
+ ok( !GetModuleHandleA( "forward1.dll" ), "forward1.dll unexpectedly kept open\n" );
+ ok( !GetModuleHandleA( "forward2.dll" ), "forward2.dll unexpectedly kept open\n" );
+ ok( !GetModuleHandleA( "forward3.dll" ), "forward3.dll unexpectedly kept open\n" );
+
+ DeleteFileA( forward1_path );
+ DeleteFileA( forward2_path );
+ DeleteFileA( forward3_path );
+ RemoveDirectoryA( dir_path );
+}
+
+static void test_dynamic_forward_export_norefs(void)
+{
+ CHAR temp_path[MAX_PATH], dir_path[MAX_PATH];
+ CHAR forward1_path[MAX_PATH];
+ CHAR forward2_path[MAX_PATH];
+ CHAR forward3_path[MAX_PATH];
+ HMODULE forward1, forward2, forward3;
+
+ GetTempPathA( ARRAY_SIZE(temp_path), temp_path );
+ GetTempFileNameA( temp_path, "ldr", GetTickCount() | 1UL, dir_path );
+ ok( CreateDirectoryA( dir_path, NULL ), "failed to create dir %s, error %u\n",
+ dir_path, GetLastError() );
+
+ snprintf( forward1_path, MAX_PATH, "%s\\forward1.dll", dir_path );
+ snprintf( forward2_path, MAX_PATH, "%s\\forward2.dll", dir_path );
+ snprintf( forward3_path, MAX_PATH, "%s\\forward3.dll", dir_path );
+ extract_resource( "forward1.dll", "TESTDLL", forward1_path );
+ extract_resource( "forward2.dll", "TESTDLL", forward2_path );
+ extract_resource( "forward3.dll", "TESTDLL", forward3_path );
+
+ forward1 = LoadLibraryA( forward1_path );
+ ok( !!forward1, "couldn't find %s: %u\n", forward1_path, GetLastError() );
+ forward2 = LoadLibraryA( forward2_path );
+ ok( !!forward2, "couldn't find %s: %u\n", forward2_path, GetLastError() );
+ forward3 = LoadLibraryA( forward3_path );
+ ok( !!forward3, "couldn't find %s: %u\n", forward3_path, GetLastError() );
+
+ FreeLibrary( forward1 );
+ FreeLibrary( forward3 );
+
+ ok( !GetModuleHandleA( "forward1.dll" ), "forward1.dll unexpectedly kept open\n" );
+ ok( !GetModuleHandleA( "forward3.dll" ), "forward3.dll unexpectedly kept open\n" );
+
+ FreeLibrary( forward2 );
+
+ ok( !GetModuleHandleA( "forward2.dll" ), "forward2.dll unexpectedly kept open\n" );
+
+ DeleteFileA( forward1_path );
+ DeleteFileA( forward2_path );
+ DeleteFileA( forward3_path );
+ RemoveDirectoryA( dir_path );
+}
+
static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL is_dll)
{
HANDLE hfile, hmap;
@@ -4119,9 +4293,12 @@ START_TEST(loader)
return;
}
+ test_static_forwarded_import_refs(); /* Must be first; other tests may load userenv.dll */
test_filenames();
test_ResolveDelayLoadedAPI();
test_ImportDescriptors();
+ test_dynamic_forwarded_import_refs();
+ test_dynamic_forward_export_norefs();
test_section_access();
test_import_resolution();
test_ExitProcess();
diff --git a/dlls/kernel32/tests/sforward.c b/dlls/kernel32/tests/sforward.c
new file mode 100644
index 00000000000..17f79fb5a74
--- /dev/null
+++ b/dlls/kernel32/tests/sforward.c
@@ -0,0 +1,16 @@
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+DECLSPEC_IMPORT BOOL WINAPI SHExpandEnvironmentStringsForUserW(HANDLE,LPCWSTR,LPWSTR,DWORD);
+
+void test_func_stub(void)
+{
+ SHExpandEnvironmentStringsForUserW(NULL, NULL, NULL, 0);
+}
+
+BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved)
+{
+ if (reason == DLL_PROCESS_ATTACH)
+ DisableThreadLibraryCalls( instance_new );
+ return TRUE;
+}
diff --git a/dlls/kernel32/tests/sforward.spec b/dlls/kernel32/tests/sforward.spec
new file mode 100644
index 00000000000..cb6d4add796
--- /dev/null
+++ b/dlls/kernel32/tests/sforward.spec
@@ -0,0 +1 @@
+@ cdecl test_func_stub()
--
2.31.1
3
7
[PATCH 4/4] dmusic: Remove SynthPortImpl from the method and vtbl names
by Michael Stefaniuc Jan. 20, 2022
by Michael Stefaniuc Jan. 20, 2022
Jan. 20, 2022
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/dmusic/port.c | 163 +++++++++++++++++++++++----------------------
1 file changed, 83 insertions(+), 80 deletions(-)
diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c
index c51b33ce9c3..a17e399ee17 100644
--- a/dlls/dmusic/port.c
+++ b/dlls/dmusic/port.c
@@ -149,8 +149,7 @@ static HRESULT DMUSIC_CreateDirectMusicDownloadedInstrumentImpl(IDirectMusicDown
return S_OK;
}
-/* SynthPortImpl IDirectMusicPort IUnknown part follows: */
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_QueryInterface(LPDIRECTMUSICPORT iface, REFIID riid, LPVOID *ret_iface)
+static HRESULT WINAPI synth_port_QueryInterface(IDirectMusicPort *iface, REFIID riid, void **ret_iface)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
@@ -175,7 +174,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_QueryInterface(LPDIRECTMUSI
return S_OK;
}
-static ULONG WINAPI SynthPortImpl_IDirectMusicPort_AddRef(LPDIRECTMUSICPORT iface)
+static ULONG WINAPI synth_port_AddRef(IDirectMusicPort *iface)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
ULONG ref = InterlockedIncrement(&This->ref);
@@ -187,7 +186,7 @@ static ULONG WINAPI SynthPortImpl_IDirectMusicPort_AddRef(LPDIRECTMUSICPORT ifac
return ref;
}
-static ULONG WINAPI SynthPortImpl_IDirectMusicPort_Release(LPDIRECTMUSICPORT iface)
+static ULONG WINAPI synth_port_Release(IDirectMusicPort *iface)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
ULONG ref = InterlockedDecrement(&This->ref);
@@ -214,8 +213,7 @@ static ULONG WINAPI SynthPortImpl_IDirectMusicPort_Release(LPDIRECTMUSICPORT ifa
return ref;
}
-/* SynthPortImpl IDirectMusicPort interface follows: */
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_PlayBuffer(LPDIRECTMUSICPORT iface, LPDIRECTMUSICBUFFER buffer)
+static HRESULT WINAPI synth_port_PlayBuffer(IDirectMusicPort *iface, IDirectMusicBuffer *buffer)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
HRESULT hr;
@@ -242,7 +240,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_PlayBuffer(LPDIRECTMUSICPOR
return hr;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_SetReadNotificationHandle(LPDIRECTMUSICPORT iface, HANDLE event)
+static HRESULT WINAPI synth_port_SetReadNotificationHandle(IDirectMusicPort *iface, HANDLE event)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
@@ -251,7 +249,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_SetReadNotificationHandle(L
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_Read(LPDIRECTMUSICPORT iface, LPDIRECTMUSICBUFFER buffer)
+static HRESULT WINAPI synth_port_Read(IDirectMusicPort *iface, IDirectMusicBuffer *buffer)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
@@ -260,7 +258,8 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_Read(LPDIRECTMUSICPORT ifac
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_DownloadInstrument(LPDIRECTMUSICPORT iface, IDirectMusicInstrument* instrument, IDirectMusicDownloadedInstrument** downloaded_instrument, DMUS_NOTERANGE* note_ranges, DWORD num_note_ranges)
+static HRESULT WINAPI synth_port_DownloadInstrument(IDirectMusicPort *iface, IDirectMusicInstrument *instrument,
+ IDirectMusicDownloadedInstrument **downloaded_instrument, DMUS_NOTERANGE *note_ranges, DWORD num_note_ranges)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
IDirectMusicInstrumentImpl *instrument_object;
@@ -346,7 +345,8 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_DownloadInstrument(LPDIRECT
return E_FAIL;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_UnloadInstrument(LPDIRECTMUSICPORT iface, IDirectMusicDownloadedInstrument *downloaded_instrument)
+static HRESULT WINAPI synth_port_UnloadInstrument(IDirectMusicPort *iface,
+ IDirectMusicDownloadedInstrument *downloaded_instrument)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
IDirectMusicDownloadedInstrumentImpl *downloaded_object = unsafe_impl_from_IDirectMusicDownloadedInstrument(downloaded_instrument);
@@ -366,7 +366,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_UnloadInstrument(LPDIRECTMU
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetLatencyClock(LPDIRECTMUSICPORT iface, IReferenceClock** clock)
+static HRESULT WINAPI synth_port_GetLatencyClock(IDirectMusicPort *iface, IReferenceClock **clock)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
@@ -378,7 +378,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetLatencyClock(LPDIRECTMUS
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetRunningStats(LPDIRECTMUSICPORT iface, LPDMUS_SYNTHSTATS stats)
+static HRESULT WINAPI synth_port_GetRunningStats(IDirectMusicPort *iface, DMUS_SYNTHSTATS *stats)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
@@ -387,7 +387,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetRunningStats(LPDIRECTMUS
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_Compact(LPDIRECTMUSICPORT iface)
+static HRESULT WINAPI synth_port_Compact(IDirectMusicPort *iface)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
@@ -396,7 +396,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_Compact(LPDIRECTMUSICPORT i
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetCaps(LPDIRECTMUSICPORT iface, LPDMUS_PORTCAPS port_caps)
+static HRESULT WINAPI synth_port_GetCaps(IDirectMusicPort *iface, DMUS_PORTCAPS *port_caps)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
@@ -407,8 +407,9 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetCaps(LPDIRECTMUSICPORT i
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_DeviceIoControl(LPDIRECTMUSICPORT iface, DWORD io_control_code, LPVOID in_buffer, DWORD in_buffer_size,
- LPVOID out_buffer, DWORD out_buffer_size, LPDWORD bytes_returned, LPOVERLAPPED overlapped)
+static HRESULT WINAPI synth_port_DeviceIoControl(IDirectMusicPort *iface, DWORD io_control_code,
+ void *in_buffer, DWORD in_buffer_size, void *out_buffer, DWORD out_buffer_size,
+ DWORD *bytes_returned, OVERLAPPED *overlapped)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
@@ -417,7 +418,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_DeviceIoControl(LPDIRECTMUS
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_SetNumChannelGroups(LPDIRECTMUSICPORT iface, DWORD channel_groups)
+static HRESULT WINAPI synth_port_SetNumChannelGroups(IDirectMusicPort *iface, DWORD channel_groups)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
@@ -428,7 +429,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_SetNumChannelGroups(LPDIREC
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetNumChannelGroups(LPDIRECTMUSICPORT iface, LPDWORD channel_groups)
+static HRESULT WINAPI synth_port_GetNumChannelGroups(IDirectMusicPort *iface, DWORD *channel_groups)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
@@ -439,7 +440,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetNumChannelGroups(LPDIREC
return S_OK;
}
-static HRESULT WINAPI synth_dmport_Activate(IDirectMusicPort *iface, BOOL active)
+static HRESULT WINAPI synth_port_Activate(IDirectMusicPort *iface, BOOL active)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
@@ -468,7 +469,8 @@ static HRESULT WINAPI synth_dmport_Activate(IDirectMusicPort *iface, BOOL active
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_SetChannelPriority(LPDIRECTMUSICPORT iface, DWORD channel_group, DWORD channel, DWORD priority)
+static HRESULT WINAPI synth_port_SetChannelPriority(IDirectMusicPort *iface, DWORD channel_group,
+ DWORD channel, DWORD priority)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
@@ -483,7 +485,8 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_SetChannelPriority(LPDIRECT
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetChannelPriority(LPDIRECTMUSICPORT iface, DWORD channel_group, DWORD channel, LPDWORD priority)
+static HRESULT WINAPI synth_port_GetChannelPriority(IDirectMusicPort *iface, DWORD channel_group,
+ DWORD channel, DWORD *priority)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
@@ -494,7 +497,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetChannelPriority(LPDIRECT
return S_OK;
}
-static HRESULT WINAPI synth_dmport_SetDirectSound(IDirectMusicPort *iface, IDirectSound *dsound,
+static HRESULT WINAPI synth_port_SetDirectSound(IDirectMusicPort *iface, IDirectSound *dsound,
IDirectSoundBuffer *dsbuffer)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
@@ -525,7 +528,8 @@ static HRESULT WINAPI synth_dmport_SetDirectSound(IDirectMusicPort *iface, IDire
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetFormat(LPDIRECTMUSICPORT iface, LPWAVEFORMATEX pWaveFormatEx, LPDWORD pdwWaveFormatExSize, LPDWORD pdwBufferSize)
+static HRESULT WINAPI synth_port_GetFormat(IDirectMusicPort *iface, WAVEFORMATEX *pWaveFormatEx,
+ DWORD *pdwWaveFormatExSize, DWORD *pdwBufferSize)
{
struct synth_port *This = synth_from_IDirectMusicPort(iface);
WAVEFORMATEX format;
@@ -570,33 +574,32 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPort_GetFormat(LPDIRECTMUSICPORT
return S_OK;
}
-static const IDirectMusicPortVtbl SynthPortImpl_DirectMusicPort_Vtbl = {
+static const IDirectMusicPortVtbl synth_port_vtbl = {
/**** IDirectMusicPort IUnknown part methods ***/
- SynthPortImpl_IDirectMusicPort_QueryInterface,
- SynthPortImpl_IDirectMusicPort_AddRef,
- SynthPortImpl_IDirectMusicPort_Release,
+ synth_port_QueryInterface,
+ synth_port_AddRef,
+ synth_port_Release,
/**** IDirectMusicPort methods ***/
- SynthPortImpl_IDirectMusicPort_PlayBuffer,
- SynthPortImpl_IDirectMusicPort_SetReadNotificationHandle,
- SynthPortImpl_IDirectMusicPort_Read,
- SynthPortImpl_IDirectMusicPort_DownloadInstrument,
- SynthPortImpl_IDirectMusicPort_UnloadInstrument,
- SynthPortImpl_IDirectMusicPort_GetLatencyClock,
- SynthPortImpl_IDirectMusicPort_GetRunningStats,
- SynthPortImpl_IDirectMusicPort_Compact,
- SynthPortImpl_IDirectMusicPort_GetCaps,
- SynthPortImpl_IDirectMusicPort_DeviceIoControl,
- SynthPortImpl_IDirectMusicPort_SetNumChannelGroups,
- SynthPortImpl_IDirectMusicPort_GetNumChannelGroups,
- synth_dmport_Activate,
- SynthPortImpl_IDirectMusicPort_SetChannelPriority,
- SynthPortImpl_IDirectMusicPort_GetChannelPriority,
- synth_dmport_SetDirectSound,
- SynthPortImpl_IDirectMusicPort_GetFormat
+ synth_port_PlayBuffer,
+ synth_port_SetReadNotificationHandle,
+ synth_port_Read,
+ synth_port_DownloadInstrument,
+ synth_port_UnloadInstrument,
+ synth_port_GetLatencyClock,
+ synth_port_GetRunningStats,
+ synth_port_Compact,
+ synth_port_GetCaps,
+ synth_port_DeviceIoControl,
+ synth_port_SetNumChannelGroups,
+ synth_port_GetNumChannelGroups,
+ synth_port_Activate,
+ synth_port_SetChannelPriority,
+ synth_port_GetChannelPriority,
+ synth_port_SetDirectSound,
+ synth_port_GetFormat
};
-/* SynthPortImpl IDirectMusicPortDownload IUnknown part follows: */
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_QueryInterface(LPDIRECTMUSICPORTDOWNLOAD iface, REFIID riid, LPVOID *ret_iface)
+static HRESULT WINAPI synth_port_download_QueryInterface(IDirectMusicPortDownload *iface, REFIID riid, void **ret_iface)
{
struct synth_port *This = synth_from_IDirectMusicPortDownload(iface);
@@ -605,7 +608,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_QueryInterface(LPDI
return IDirectMusicPort_QueryInterface(&This->IDirectMusicPort_iface, riid, ret_iface);
}
-static ULONG WINAPI SynthPortImpl_IDirectMusicPortDownload_AddRef (LPDIRECTMUSICPORTDOWNLOAD iface)
+static ULONG WINAPI synth_port_download_AddRef(IDirectMusicPortDownload *iface)
{
struct synth_port *This = synth_from_IDirectMusicPortDownload(iface);
@@ -614,7 +617,7 @@ static ULONG WINAPI SynthPortImpl_IDirectMusicPortDownload_AddRef (LPDIRECTMUSIC
return IDirectMusicPort_AddRef(&This->IDirectMusicPort_iface);
}
-static ULONG WINAPI SynthPortImpl_IDirectMusicPortDownload_Release(LPDIRECTMUSICPORTDOWNLOAD iface)
+static ULONG WINAPI synth_port_download_Release(IDirectMusicPortDownload *iface)
{
struct synth_port *This = synth_from_IDirectMusicPortDownload(iface);
@@ -623,8 +626,8 @@ static ULONG WINAPI SynthPortImpl_IDirectMusicPortDownload_Release(LPDIRECTMUSIC
return IDirectMusicPort_Release(&This->IDirectMusicPort_iface);
}
-/* SynthPortImpl IDirectMusicPortDownload Interface follows: */
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_GetBuffer(LPDIRECTMUSICPORTDOWNLOAD iface, DWORD DLId, IDirectMusicDownload** IDMDownload)
+static HRESULT WINAPI synth_port_download_GetBuffer(IDirectMusicPortDownload *iface, DWORD DLId,
+ IDirectMusicDownload **IDMDownload)
{
struct synth_port *This = synth_from_IDirectMusicPortDownload(iface);
@@ -636,7 +639,8 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_GetBuffer(LPDIRECTM
return DMUSIC_CreateDirectMusicDownloadImpl(&IID_IDirectMusicDownload, (LPVOID*)IDMDownload, NULL);
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_AllocateBuffer(LPDIRECTMUSICPORTDOWNLOAD iface, DWORD size, IDirectMusicDownload** IDMDownload)
+static HRESULT WINAPI synth_port_download_AllocateBuffer(IDirectMusicPortDownload *iface, DWORD size,
+ IDirectMusicDownload **IDMDownload)
{
struct synth_port *This = synth_from_IDirectMusicPortDownload(iface);
@@ -645,7 +649,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_AllocateBuffer(LPDI
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_GetDLId(LPDIRECTMUSICPORTDOWNLOAD iface, DWORD* start_DLId, DWORD count)
+static HRESULT WINAPI synth_port_download_GetDLId(IDirectMusicPortDownload *iface, DWORD *start_DLId, DWORD count)
{
struct synth_port *This = synth_from_IDirectMusicPortDownload(iface);
@@ -654,7 +658,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_GetDLId(LPDIRECTMUS
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_GetAppend (LPDIRECTMUSICPORTDOWNLOAD iface, DWORD* append)
+static HRESULT WINAPI synth_port_download_GetAppend(IDirectMusicPortDownload *iface, DWORD *append)
{
struct synth_port *This = synth_from_IDirectMusicPortDownload(iface);
@@ -663,7 +667,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_GetAppend (LPDIRECT
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_Download(LPDIRECTMUSICPORTDOWNLOAD iface, IDirectMusicDownload* IDMDownload)
+static HRESULT WINAPI synth_port_download_Download(IDirectMusicPortDownload *iface, IDirectMusicDownload *IDMDownload)
{
struct synth_port *This = synth_from_IDirectMusicPortDownload(iface);
@@ -672,7 +676,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_Download(LPDIRECTMU
return S_OK;
}
-static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_Unload(LPDIRECTMUSICPORTDOWNLOAD iface, IDirectMusicDownload* IDMDownload)
+static HRESULT WINAPI synth_port_download_Unload(IDirectMusicPortDownload *iface, IDirectMusicDownload *IDMDownload)
{
struct synth_port *This = synth_from_IDirectMusicPortDownload(iface);
@@ -681,22 +685,21 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicPortDownload_Unload(LPDIRECTMUSI
return S_OK;
}
-static const IDirectMusicPortDownloadVtbl SynthPortImpl_DirectMusicPortDownload_Vtbl = {
+static const IDirectMusicPortDownloadVtbl synth_port_download_vtbl = {
/*** IDirectMusicPortDownload IUnknown part methods ***/
- SynthPortImpl_IDirectMusicPortDownload_QueryInterface,
- SynthPortImpl_IDirectMusicPortDownload_AddRef,
- SynthPortImpl_IDirectMusicPortDownload_Release,
+ synth_port_download_QueryInterface,
+ synth_port_download_AddRef,
+ synth_port_download_Release,
/*** IDirectMusicPortDownload methods ***/
- SynthPortImpl_IDirectMusicPortDownload_GetBuffer,
- SynthPortImpl_IDirectMusicPortDownload_AllocateBuffer,
- SynthPortImpl_IDirectMusicPortDownload_GetDLId,
- SynthPortImpl_IDirectMusicPortDownload_GetAppend,
- SynthPortImpl_IDirectMusicPortDownload_Download,
- SynthPortImpl_IDirectMusicPortDownload_Unload
+ synth_port_download_GetBuffer,
+ synth_port_download_AllocateBuffer,
+ synth_port_download_GetDLId,
+ synth_port_download_GetAppend,
+ synth_port_download_Download,
+ synth_port_download_Unload
};
-/* SynthPortImpl IDirectMusicThru IUnknown part follows: */
-static HRESULT WINAPI SynthPortImpl_IDirectMusicThru_QueryInterface(LPDIRECTMUSICTHRU iface, REFIID riid, LPVOID *ret_iface)
+static HRESULT WINAPI synth_port_thru_QueryInterface(IDirectMusicThru *iface, REFIID riid, void **ret_iface)
{
struct synth_port *This = synth_from_IDirectMusicThru(iface);
@@ -705,7 +708,7 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicThru_QueryInterface(LPDIRECTMUSI
return IDirectMusicPort_QueryInterface(&This->IDirectMusicPort_iface, riid, ret_iface);
}
-static ULONG WINAPI SynthPortImpl_IDirectMusicThru_AddRef(LPDIRECTMUSICTHRU iface)
+static ULONG WINAPI synth_port_thru_AddRef(IDirectMusicThru *iface)
{
struct synth_port *This = synth_from_IDirectMusicThru(iface);
@@ -714,7 +717,7 @@ static ULONG WINAPI SynthPortImpl_IDirectMusicThru_AddRef(LPDIRECTMUSICTHRU ifac
return IDirectMusicPort_AddRef(&This->IDirectMusicPort_iface);
}
-static ULONG WINAPI SynthPortImpl_IDirectMusicThru_Release(LPDIRECTMUSICTHRU iface)
+static ULONG WINAPI synth_port_thru_Release(IDirectMusicThru *iface)
{
struct synth_port *This = synth_from_IDirectMusicThru(iface);
@@ -723,9 +726,9 @@ static ULONG WINAPI SynthPortImpl_IDirectMusicThru_Release(LPDIRECTMUSICTHRU ifa
return IDirectMusicPort_Release(&This->IDirectMusicPort_iface);
}
-/* SynthPortImpl IDirectMusicThru Interface follows: */
-static HRESULT WINAPI SynthPortImpl_IDirectMusicThru_ThruChannel(LPDIRECTMUSICTHRU iface, DWORD source_channel_group, DWORD source_channel, DWORD destination_channel_group,
- DWORD destination_channel, LPDIRECTMUSICPORT destination_port)
+static HRESULT WINAPI synth_port_thru_ThruChannel(IDirectMusicThru *iface, DWORD source_channel_group,
+ DWORD source_channel, DWORD destination_channel_group, DWORD destination_channel,
+ IDirectMusicPort *destination_port)
{
struct synth_port *This = synth_from_IDirectMusicThru(iface);
@@ -734,13 +737,13 @@ static HRESULT WINAPI SynthPortImpl_IDirectMusicThru_ThruChannel(LPDIRECTMUSICTH
return S_OK;
}
-static const IDirectMusicThruVtbl SynthPortImpl_DirectMusicThru_Vtbl = {
+static const IDirectMusicThruVtbl synth_port_thru_vtbl = {
/*** IDirectMusicThru IUnknown part methods */
- SynthPortImpl_IDirectMusicThru_QueryInterface,
- SynthPortImpl_IDirectMusicThru_AddRef,
- SynthPortImpl_IDirectMusicThru_Release,
+ synth_port_thru_QueryInterface,
+ synth_port_thru_AddRef,
+ synth_port_thru_Release,
/*** IDirectMusicThru methods ***/
- SynthPortImpl_IDirectMusicThru_ThruChannel
+ synth_port_thru_ThruChannel
};
static HRESULT WINAPI IKsControlImpl_QueryInterface(IKsControl *iface, REFIID riid,
@@ -827,9 +830,9 @@ HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_param
if (!obj)
return E_OUTOFMEMORY;
- obj->IDirectMusicPort_iface.lpVtbl = &SynthPortImpl_DirectMusicPort_Vtbl;
- obj->IDirectMusicPortDownload_iface.lpVtbl = &SynthPortImpl_DirectMusicPortDownload_Vtbl;
- obj->IDirectMusicThru_iface.lpVtbl = &SynthPortImpl_DirectMusicThru_Vtbl;
+ obj->IDirectMusicPort_iface.lpVtbl = &synth_port_vtbl;
+ obj->IDirectMusicPortDownload_iface.lpVtbl = &synth_port_download_vtbl;
+ obj->IDirectMusicThru_iface.lpVtbl = &synth_port_thru_vtbl;
obj->IKsControl_iface.lpVtbl = &ikscontrol_vtbl;
obj->ref = 1;
obj->parent = parent;
--
2.31.1
1
0