This commit is contained in:
MistEO
2022-08-02 23:29:40 +08:00
3 changed files with 257 additions and 9 deletions

View File

@@ -0,0 +1,251 @@
// <copyright file="MessageBoxManager.cs" company="MaaAssistantArknights">
// MeoAsstGui - A part of the MeoAssistantArknights project
// Copyright (C) 2021 MistEO and Contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY
// </copyright>
#pragma warning disable 0618
#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释
#pragma warning disable SA1307 // Accessible fields should begin with upper-case letter
#pragma warning disable IDE1006 // 命名样式
#pragma warning disable SA1401 // Fields should be private
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text;
[assembly: SecurityPermission(SecurityAction.RequestMinimum, UnmanagedCode = true)]
namespace System.Windows.Forms
{
/// <summary>
/// 消息框弹窗格式管理
/// </summary>
public class MessageBoxManager
{
private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
private delegate bool EnumChildProc(IntPtr hWnd, IntPtr lParam);
private const int WHCALLWNDPROCRET = 12;
private const int WMDESTROY = 0x0002;
private const int WMINITDIALOG = 0x0110;
private const int WMTIMER = 0x0113;
private const int WMUSER = 0x400;
private const int DMGETDEFID = WMUSER + 0;
private const int MBOK = 1;
private const int MBCancel = 2;
private const int MBAbort = 3;
private const int MBRetry = 4;
private const int MBIgnore = 5;
private const int MBYes = 6;
private const int MBNo = 7;
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
[DllImport("user32.dll")]
private static extern int UnhookWindowsHookEx(IntPtr idHook);
[DllImport("user32.dll")]
private static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "GetWindowTextLengthW", CharSet = CharSet.Unicode)]
private static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "GetWindowTextW", CharSet = CharSet.Unicode)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int maxLength);
[DllImport("user32.dll")]
private static extern int EndDialog(IntPtr hDlg, IntPtr nResult);
[DllImport("user32.dll")]
private static extern bool EnumChildWindows(IntPtr hWndParent, EnumChildProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "GetClassNameW", CharSet = CharSet.Unicode)]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
private static extern int GetDlgCtrlID(IntPtr hwndCtl);
[DllImport("user32.dll")]
private static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);
[DllImport("user32.dll", EntryPoint = "SetWindowTextW", CharSet = CharSet.Unicode)]
private static extern bool SetWindowText(IntPtr hWnd, string lpString);
[StructLayout(LayoutKind.Sequential)]
public struct CWPRETSTRUCT
{
public IntPtr lResult;
public IntPtr lParam;
public IntPtr wParam;
public uint message;
public IntPtr hwnd;
}
private static readonly HookProc hookProc;
private static readonly EnumChildProc enumProc;
[ThreadStatic]
private static IntPtr hHook;
[ThreadStatic]
private static int nButton;
/// <summary>
/// OK text
/// </summary>
public static string OK = "OK";
/// <summary>
/// Cancel text
/// </summary>
public static string Cancel = "Cancel";
/// <summary>
/// Abort text
/// </summary>
public static string Abort = "Abort";
/// <summary>
/// Retry text
/// </summary>
public static string Retry = "Retry";
/// <summary>
/// Ignore text
/// </summary>
public static string Ignore = "Ignore";
/// <summary>
/// Yes text
/// </summary>
public static string Yes = "Yes";
/// <summary>
/// No text
/// </summary>
public static string No = "No";
static MessageBoxManager()
{
hookProc = new HookProc(MessageBoxHookProc);
enumProc = new EnumChildProc(MessageBoxEnumProc);
hHook = IntPtr.Zero;
}
/// <summary>
/// Enables MessageBoxManager functionality
/// </summary>
/// <remarks>
/// MessageBoxManager functionality is enabled on current thread only.
/// Each thread that needs MessageBoxManager functionality has to call this method.
/// </remarks>
public static void Register()
{
if (hHook != IntPtr.Zero)
{
throw new NotSupportedException("One hook per thread allowed.");
}
hHook = SetWindowsHookEx(WHCALLWNDPROCRET, hookProc, IntPtr.Zero, AppDomain.GetCurrentThreadId());
}
/// <summary>
/// Disables MessageBoxManager functionality
/// </summary>
/// <remarks>
/// Disables MessageBoxManager functionality on current thread only.
/// </remarks>
public static void Unregister()
{
if (hHook != IntPtr.Zero)
{
UnhookWindowsHookEx(hHook);
hHook = IntPtr.Zero;
}
}
private static IntPtr MessageBoxHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode < 0)
{
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
CWPRETSTRUCT msg = (CWPRETSTRUCT)Marshal.PtrToStructure(lParam, typeof(CWPRETSTRUCT));
IntPtr hook = hHook;
if (msg.message == WMINITDIALOG)
{
int nLength = GetWindowTextLength(msg.hwnd);
StringBuilder className = new StringBuilder(10);
GetClassName(msg.hwnd, className, className.Capacity);
if (className.ToString() == "#32770")
{
nButton = 0;
EnumChildWindows(msg.hwnd, enumProc, IntPtr.Zero);
if (nButton == 1)
{
IntPtr hButton = GetDlgItem(msg.hwnd, MBCancel);
if (hButton != IntPtr.Zero)
{
_ = SetWindowText(hButton, OK);
}
}
}
}
return CallNextHookEx(hook, nCode, wParam, lParam);
}
private static bool MessageBoxEnumProc(IntPtr hWnd, IntPtr lParam)
{
StringBuilder className = new StringBuilder(10);
GetClassName(hWnd, className, className.Capacity);
if (className.ToString() == "Button")
{
int ctlId = GetDlgCtrlID(hWnd);
switch (ctlId)
{
case MBOK:
SetWindowText(hWnd, OK);
break;
case MBCancel:
SetWindowText(hWnd, Cancel);
break;
case MBAbort:
SetWindowText(hWnd, Abort);
break;
case MBRetry:
SetWindowText(hWnd, Retry);
break;
case MBIgnore:
SetWindowText(hWnd, Ignore);
break;
case MBYes:
SetWindowText(hWnd, Yes);
break;
case MBNo:
SetWindowText(hWnd, No);
break;
}
nButton++;
}
return true;
}
}
}
#pragma warning restore IDE1006 // 命名样式
#pragma warning restore SA1307 // Accessible fields should begin with upper-case letter
#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释
#pragma warning restore SA1401 // Fields should be private

View File

@@ -109,6 +109,7 @@
<Compile Include="Helper\GenericCombData{TValueType}.cs" />
<Compile Include="Helper\Localization.cs" />
<Compile Include="Helper\LogItemViewModel.cs" />
<Compile Include="Helper\MessageBoxManager.cs" />
<Compile Include="Helper\ToastNotification.cs" />
<Compile Include="Helper\ScrollViewerBinding.cs" />
<Compile Include="Helper\ViewStatusStorage.cs" />

View File

@@ -1837,18 +1837,14 @@ namespace MeoAsstGui
var backup = _language;
ViewStatusStorage.Set("GUI.Localization", value);
var result = _windowManager.ShowMessageBox(
System.Windows.Forms.MessageBoxManager.Yes = Localization.GetString("Ok");
System.Windows.Forms.MessageBoxManager.No = Localization.GetString("ManualRestart");
System.Windows.Forms.MessageBoxManager.Register();
var result = MessageBox.Show(
Localization.GetString("LanguageChangedTip"),
Localization.GetString("Tip"),
MessageBoxButton.YesNo,
MessageBoxImage.Question,
MessageBoxResult.None,
MessageBoxResult.None,
new Dictionary<MessageBoxResult, string>
{
{ MessageBoxResult.Yes, Localization.GetString("Ok") },
{ MessageBoxResult.No, Localization.GetString("ManualRestart") },
});
MessageBoxImage.Question);
SetAndNotify(ref _language, value);
if (result == MessageBoxResult.Yes)
{