fix: Windows native code bugs and dedup

- fix unsigned underflow in Utf8FromUtf16 when WideCharToMultiByte fails
- fix inverted freopen_s logic in console attach
- remove misleading WS_EX_APPWINDOW from GWL_STYLE mask
- close mutex handle on normal exit
- extract SetHDRStateForTarget, EnableComposition/DisableComposition, DisplayModeToMap helpers
- cache GetWindowsVersion result
This commit is contained in:
edde746
2026-04-02 15:02:07 +02:00
parent 29101c310b
commit da95901d39
8 changed files with 87 additions and 125 deletions
+1
View File
@@ -57,5 +57,6 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
}
::CoUninitialize();
CloseHandle(mutex);
return EXIT_SUCCESS;
}
+24 -59
View File
@@ -324,26 +324,7 @@ bool DisplayModeManager::SetHDREnabled(HWND window, bool enabled) {
EnumDisplaySettingsW(device_name.c_str(), ENUM_CURRENT_SETTINGS, &pre_toggle_dm);
// Toggle HDR.
LONG result;
if (IsWin11_24H2OrNewer()) {
DISPLAYCONFIG_SET_HDR_STATE state = {};
state.header.type = static_cast<DISPLAYCONFIG_DEVICE_INFO_TYPE>(
DISPLAYCONFIG_DEVICE_INFO_SET_HDR_STATE);
state.header.size = sizeof(state);
state.header.adapterId = target_id->adapter_id;
state.header.id = target_id->id;
state.enableHdr = enabled ? TRUE : FALSE;
result = DisplayConfigSetDeviceInfo(&state.header);
} else {
DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE state = {};
state.header.type = DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE;
state.header.size = sizeof(state);
state.header.adapterId = target_id->adapter_id;
state.header.id = target_id->id;
state.enableAdvancedColor = enabled ? TRUE : FALSE;
result = DisplayConfigSetDeviceInfo(&state.header);
}
LONG result = SetHDRStateForTarget(*target_id, enabled);
if (result != ERROR_SUCCESS) return false;
// Restore DEVMODEW after toggle — Windows may have changed the display mode.
@@ -378,26 +359,7 @@ bool DisplayModeManager::RestoreOriginalHDRState(HWND window) {
pre_toggle_dm.dmSize = sizeof(pre_toggle_dm);
EnumDisplaySettingsW(original_hdr_device_name_.c_str(), ENUM_CURRENT_SETTINGS, &pre_toggle_dm);
LONG result;
if (IsWin11_24H2OrNewer()) {
DISPLAYCONFIG_SET_HDR_STATE state = {};
state.header.type = static_cast<DISPLAYCONFIG_DEVICE_INFO_TYPE>(
DISPLAYCONFIG_DEVICE_INFO_SET_HDR_STATE);
state.header.size = sizeof(state);
state.header.adapterId = target_id->adapter_id;
state.header.id = target_id->id;
state.enableHdr = original_hdr_enabled_ ? TRUE : FALSE;
result = DisplayConfigSetDeviceInfo(&state.header);
} else {
DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE state = {};
state.header.type = DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE;
state.header.size = sizeof(state);
state.header.adapterId = target_id->adapter_id;
state.header.id = target_id->id;
state.enableAdvancedColor = original_hdr_enabled_ ? TRUE : FALSE;
result = DisplayConfigSetDeviceInfo(&state.header);
}
LONG result = SetHDRStateForTarget(*target_id, original_hdr_enabled_);
if (result != ERROR_SUCCESS) return false;
// Restore DEVMODEW after toggle.
@@ -414,6 +376,27 @@ bool DisplayModeManager::RestoreOriginalHDRState(HWND window) {
// --- Crash recovery (Windows Registry) ---
LONG DisplayModeManager::SetHDRStateForTarget(const DisplayConfigId& target, bool enabled) {
if (IsWin11_24H2OrNewer()) {
DISPLAYCONFIG_SET_HDR_STATE state = {};
state.header.type = static_cast<DISPLAYCONFIG_DEVICE_INFO_TYPE>(
DISPLAYCONFIG_DEVICE_INFO_SET_HDR_STATE);
state.header.size = sizeof(state);
state.header.adapterId = target.adapter_id;
state.header.id = target.id;
state.enableHdr = enabled ? TRUE : FALSE;
return DisplayConfigSetDeviceInfo(&state.header);
} else {
DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE state = {};
state.header.type = DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE;
state.header.size = sizeof(state);
state.header.adapterId = target.adapter_id;
state.header.id = target.id;
state.enableAdvancedColor = enabled ? TRUE : FALSE;
return DisplayConfigSetDeviceInfo(&state.header);
}
}
bool DisplayModeManager::WriteRegistryDWORD(const wchar_t* value_name, DWORD value) {
HKEY key;
if (RegCreateKeyExW(HKEY_CURRENT_USER, kRegistryPath, 0, nullptr,
@@ -552,25 +535,7 @@ bool DisplayModeManager::RecoverIfNeeded(HWND window) {
pre_dm.dmSize = sizeof(pre_dm);
EnumDisplaySettingsW(device_name.c_str(), ENUM_CURRENT_SETTINGS, &pre_dm);
LONG result;
if (IsWin11_24H2OrNewer()) {
DISPLAYCONFIG_SET_HDR_STATE state = {};
state.header.type = static_cast<DISPLAYCONFIG_DEVICE_INFO_TYPE>(
DISPLAYCONFIG_DEVICE_INFO_SET_HDR_STATE);
state.header.size = sizeof(state);
state.header.adapterId = target_id->adapter_id;
state.header.id = target_id->id;
state.enableHdr = hdr_was_enabled ? TRUE : FALSE;
result = DisplayConfigSetDeviceInfo(&state.header);
} else {
DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE state = {};
state.header.type = DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE;
state.header.size = sizeof(state);
state.header.adapterId = target_id->adapter_id;
state.header.id = target_id->id;
state.enableAdvancedColor = hdr_was_enabled ? TRUE : FALSE;
result = DisplayConfigSetDeviceInfo(&state.header);
}
LONG result = SetHDRStateForTarget(*target_id, hdr_was_enabled != 0);
if (result == ERROR_SUCCESS) {
recovered = true;
@@ -116,6 +116,9 @@ class DisplayModeManager {
// Check if running on Win11 24H2 or newer.
static bool IsWin11_24H2OrNewer();
// Toggle HDR via DisplayConfig (version-dispatched).
static LONG SetHDRStateForTarget(const DisplayConfigId& target, bool enabled);
// Registry helpers for crash recovery.
static bool WriteRegistryDWORD(const wchar_t* value_name, DWORD value);
static bool WriteRegistryString(const wchar_t* value_name, const std::wstring& value);
+24 -32
View File
@@ -36,8 +36,7 @@ void MpvCore::CreateMpvView(HWND mpv_hwnd, RECT rect,
// Remove window decorations.
auto style = ::GetWindowLongPtr(mpv_hwnd, GWL_STYLE);
style &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
WS_EX_APPWINDOW);
style &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
::SetWindowLongPtr(mpv_hwnd, GWL_STYLE, style);
device_pixel_ratio_ = device_pixel_ratio;
@@ -70,20 +69,9 @@ void MpvCore::SetVisible(bool visible) {
visible_ = visible;
if (container_) {
if (visible) {
// Batch all window operations, single DwmFlush at end
::SetWindowPos(flutter_window_, nullptr, 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
if (!composition_enabled_) {
SetWindowComposition(flutter_window_, 2, 0);
composition_enabled_ = true;
}
::ShowWindow(container_, SW_SHOWNOACTIVATE);
::DwmFlush(); // Single sync with DWM after all operations
EnableComposition();
} else {
SetWindowComposition(flutter_window_, 0, 0);
composition_enabled_ = false;
::ShowWindow(container_, SW_HIDE);
::DwmFlush(); // Sync with DWM after hiding
DisableComposition();
}
}
}
@@ -108,10 +96,7 @@ std::optional<HRESULT> MpvCore::WindowProc(HWND hwnd, UINT message,
last_wm_size_wparam_ == SIZE_MAXIMIZED ||
was_window_hidden_due_to_minimize_) {
was_window_hidden_due_to_minimize_ = false;
SetWindowComposition(flutter_window_, 0, 0);
composition_enabled_ = false;
::ShowWindow(container_, SW_HIDE);
::DwmFlush(); // Single sync after hiding
DisableComposition();
// Cancel any pending timer and set a new one.
::KillTimer(flutter_window_, kCompositionRestoreTimerId);
@@ -133,15 +118,7 @@ std::optional<HRESULT> MpvCore::WindowProc(HWND hwnd, UINT message,
// Restore transparency if video is visible
if (visible_) {
// Batch all operations, single DwmFlush at end
::SetWindowPos(flutter_window_, nullptr, 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
if (!composition_enabled_) {
SetWindowComposition(flutter_window_, 2, 0);
composition_enabled_ = true;
}
::ShowWindow(container_, SW_SHOWNOACTIVATE);
::DwmFlush(); // Single sync after all operations
EnableComposition();
// Force a redraw to ensure Flutter's render surface is correctly sized
::RedrawWindow(flutter_window_, nullptr, nullptr,
@@ -166,10 +143,7 @@ std::optional<HRESULT> MpvCore::WindowProc(HWND hwnd, UINT message,
// Window is minimized (negative coordinates).
if (window_rect.left < 0 && window_rect.top < 0 &&
window_rect.right < 0 && window_rect.bottom < 0) {
SetWindowComposition(flutter_window_, 0, 0);
composition_enabled_ = false;
::ShowWindow(container_, SW_HIDE);
::DwmFlush(); // Single sync after hiding
DisableComposition();
was_window_hidden_due_to_minimize_ = true;
}
}
@@ -215,6 +189,24 @@ RECT MpvCore::GetGlobalRect(int32_t left, int32_t top, int32_t right,
return rect;
}
void MpvCore::EnableComposition() {
::SetWindowPos(flutter_window_, nullptr, 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
if (!composition_enabled_) {
SetWindowComposition(flutter_window_, 2, 0);
composition_enabled_ = true;
}
::ShowWindow(container_, SW_SHOWNOACTIVATE);
::DwmFlush();
}
void MpvCore::DisableComposition() {
SetWindowComposition(flutter_window_, 0, 0);
composition_enabled_ = false;
::ShowWindow(container_, SW_HIDE);
::DwmFlush();
}
void MpvCore::SetPowerResumeCallback(PowerResumeCallback callback) {
power_resume_cb_ = std::move(callback);
}
+2
View File
@@ -51,6 +51,8 @@ class MpvCore {
private:
RECT GetGlobalRect(int32_t left, int32_t top, int32_t right, int32_t bottom);
void EnableComposition();
void DisableComposition();
HWND flutter_window_ = nullptr;
HWND container_ = nullptr;
+10 -10
View File
@@ -3,6 +3,14 @@
#include "mpv_container.h"
#include "mpv_core.h"
static flutter::EncodableMap DisplayModeToMap(const mpv::DisplayMode& mode) {
flutter::EncodableMap m;
m[flutter::EncodableValue("width")] = flutter::EncodableValue(static_cast<int32_t>(mode.width));
m[flutter::EncodableValue("height")] = flutter::EncodableValue(static_cast<int32_t>(mode.height));
m[flutter::EncodableValue("refreshRate")] = flutter::EncodableValue(static_cast<int32_t>(mode.refresh_rate));
return m;
}
void MpvPlayerPluginRegisterWithRegistrar(
FlutterDesktopPluginRegistrarRef registrar) {
mpv::MpvPlayerPlugin::RegisterWithRegistrar(
@@ -397,21 +405,13 @@ void MpvPlayerPlugin::HandleMethodCall(
auto modes = display_mode_manager_.EnumerateDisplayModes(hwnd);
flutter::EncodableList list;
for (const auto& mode : modes) {
flutter::EncodableMap m;
m[flutter::EncodableValue("width")] = flutter::EncodableValue(static_cast<int32_t>(mode.width));
m[flutter::EncodableValue("height")] = flutter::EncodableValue(static_cast<int32_t>(mode.height));
m[flutter::EncodableValue("refreshRate")] = flutter::EncodableValue(static_cast<int32_t>(mode.refresh_rate));
list.push_back(flutter::EncodableValue(m));
list.push_back(flutter::EncodableValue(DisplayModeToMap(mode)));
}
result->Success(flutter::EncodableValue(list));
} else if (method == "getCurrentDisplayMode") {
HWND hwnd = GetWindow();
auto mode = display_mode_manager_.GetCurrentMode(hwnd);
flutter::EncodableMap m;
m[flutter::EncodableValue("width")] = flutter::EncodableValue(static_cast<int32_t>(mode.width));
m[flutter::EncodableValue("height")] = flutter::EncodableValue(static_cast<int32_t>(mode.height));
m[flutter::EncodableValue("refreshRate")] = flutter::EncodableValue(static_cast<int32_t>(mode.refresh_rate));
result->Success(flutter::EncodableValue(m));
result->Success(flutter::EncodableValue(DisplayModeToMap(mode)));
} else if (method == "setDisplayMode") {
const auto* args = method_call.arguments();
if (!args || !std::holds_alternative<flutter::EncodableMap>(*args)) {
+3
View File
@@ -68,6 +68,7 @@ typedef LONG NTSTATUS, *PNTSTATUS;
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
static RTL_OSVERSIONINFOW GetWindowsVersion() {
static RTL_OSVERSIONINFOW cached = []() {
HMODULE hmodule = ::GetModuleHandleW(L"ntdll.dll");
if (hmodule) {
RtlGetVersionPtr rtl_get_version_ptr =
@@ -82,6 +83,8 @@ static RTL_OSVERSIONINFOW GetWindowsVersion() {
}
RTL_OSVERSIONINFOW rovi = {0};
return rovi;
}();
return cached;
}
void SetWindowComposition(HWND window, int32_t accent_state,
+8 -12
View File
@@ -10,12 +10,8 @@
void CreateAndAttachConsole() {
if (::AllocConsole()) {
FILE *unused;
if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
_dup2(_fileno(stdout), 1);
}
if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
_dup2(_fileno(stdout), 2);
}
freopen_s(&unused, "CONOUT$", "w", stdout);
freopen_s(&unused, "CONOUT$", "w", stderr);
std::ios::sync_with_stdio();
FlutterDesktopResyncOutputStreams();
}
@@ -45,15 +41,15 @@ std::string Utf8FromUtf16(const wchar_t* utf16_string) {
if (utf16_string == nullptr) {
return std::string();
}
unsigned int target_length = ::WideCharToMultiByte(
int raw_length = ::WideCharToMultiByte(
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
-1, nullptr, 0, nullptr, nullptr)
-1; // remove the trailing null character
-1, nullptr, 0, nullptr, nullptr);
if (raw_length <= 1) {
return std::string();
}
unsigned int target_length = raw_length - 1; // exclude trailing null
int input_length = (int)wcslen(utf16_string);
std::string utf8_string;
if (target_length == 0 || target_length > utf8_string.max_size()) {
return utf8_string;
}
utf8_string.resize(target_length);
int converted_length = ::WideCharToMultiByte(
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,