MessageBoxManager.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. #pragma warning disable 0618
  2. using System;
  3. using System.Text;
  4. using System.Runtime.InteropServices;
  5. using System.Security.Permissions;
  6. [assembly: SecurityPermission(SecurityAction.RequestMinimum, UnmanagedCode = true)]
  7. namespace System.Windows
  8. {
  9. public class MessageBoxManager
  10. {
  11. private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
  12. private delegate bool EnumChildProc(IntPtr hWnd, IntPtr lParam);
  13. private const int WH_CALLWNDPROCRET = 12;
  14. private const int WM_DESTROY = 0x0002;
  15. private const int WM_INITDIALOG = 0x0110;
  16. private const int WM_TIMER = 0x0113;
  17. private const int WM_USER = 0x400;
  18. private const int DM_GETDEFID = WM_USER + 0;
  19. private const int MBOK = 1;
  20. private const int MBCancel = 2;
  21. private const int MBAbort = 3;
  22. private const int MBRetry = 4;
  23. private const int MBIgnore = 5;
  24. private const int MBYes = 6;
  25. private const int MBNo = 7;
  26. [DllImport("user32.dll")]
  27. private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
  28. [DllImport("user32.dll")]
  29. private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
  30. [DllImport("user32.dll")]
  31. private static extern int UnhookWindowsHookEx(IntPtr idHook);
  32. [DllImport("user32.dll")]
  33. private static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam);
  34. [DllImport("user32.dll", EntryPoint = "GetWindowTextLengthW", CharSet = CharSet.Unicode)]
  35. private static extern int GetWindowTextLength(IntPtr hWnd);
  36. [DllImport("user32.dll", EntryPoint = "GetWindowTextW", CharSet = CharSet.Unicode)]
  37. private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int maxLength);
  38. [DllImport("user32.dll")]
  39. private static extern int EndDialog(IntPtr hDlg, IntPtr nResult);
  40. [DllImport("user32.dll")]
  41. private static extern bool EnumChildWindows(IntPtr hWndParent, EnumChildProc lpEnumFunc, IntPtr lParam);
  42. [DllImport("user32.dll", EntryPoint = "GetClassNameW", CharSet = CharSet.Unicode)]
  43. private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
  44. [DllImport("user32.dll")]
  45. private static extern int GetDlgCtrlID(IntPtr hwndCtl);
  46. [DllImport("user32.dll")]
  47. private static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);
  48. [DllImport("user32.dll", EntryPoint = "SetWindowTextW", CharSet = CharSet.Unicode)]
  49. private static extern bool SetWindowText(IntPtr hWnd, string lpString);
  50. [StructLayout(LayoutKind.Sequential)]
  51. public struct CWPRETSTRUCT
  52. {
  53. public IntPtr lResult;
  54. public IntPtr lParam;
  55. public IntPtr wParam;
  56. public uint message;
  57. public IntPtr hwnd;
  58. };
  59. private static HookProc hookProc;
  60. private static EnumChildProc enumProc;
  61. [ThreadStatic]
  62. private static IntPtr hHook;
  63. [ThreadStatic]
  64. private static int nButton;
  65. /// <summary>
  66. /// OK text
  67. /// </summary>
  68. public static string OK = "&OK";
  69. /// <summary>
  70. /// Cancel text
  71. /// </summary>
  72. public static string Cancel = "&Cancel";
  73. /// <summary>
  74. /// Abort text
  75. /// </summary>
  76. public static string Abort = "&Abort";
  77. /// <summary>
  78. /// Retry text
  79. /// </summary>
  80. public static string Retry = "&Retry";
  81. /// <summary>
  82. /// Ignore text
  83. /// </summary>
  84. public static string Ignore = "&Ignore";
  85. /// <summary>
  86. /// Yes text
  87. /// </summary>
  88. public static string Yes = "&Yes";
  89. /// <summary>
  90. /// No text
  91. /// </summary>
  92. public static string No = "&No";
  93. static MessageBoxManager()
  94. {
  95. hookProc = new HookProc(MessageBoxHookProc);
  96. enumProc = new EnumChildProc(MessageBoxEnumProc);
  97. hHook = IntPtr.Zero;
  98. }
  99. /// <summary>
  100. /// Enables MessageBoxManager functionality
  101. /// </summary>
  102. /// <remarks>
  103. /// MessageBoxManager functionality is enabled on current thread only.
  104. /// Each thread that needs MessageBoxManager functionality has to call this method.
  105. /// </remarks>
  106. public static void Register()
  107. {
  108. if (hHook != IntPtr.Zero)
  109. throw new NotSupportedException("One hook per thread allowed.");
  110. hHook = SetWindowsHookEx(WH_CALLWNDPROCRET, hookProc, IntPtr.Zero, AppDomain.GetCurrentThreadId());
  111. }
  112. /// <summary>
  113. /// Disables MessageBoxManager functionality
  114. /// </summary>
  115. /// <remarks>
  116. /// Disables MessageBoxManager functionality on current thread only.
  117. /// </remarks>
  118. public static void Unregister()
  119. {
  120. if (hHook != IntPtr.Zero)
  121. {
  122. UnhookWindowsHookEx(hHook);
  123. hHook = IntPtr.Zero;
  124. }
  125. }
  126. private static IntPtr MessageBoxHookProc(int nCode, IntPtr wParam, IntPtr lParam)
  127. {
  128. if (nCode < 0)
  129. return CallNextHookEx(hHook, nCode, wParam, lParam);
  130. CWPRETSTRUCT msg = (CWPRETSTRUCT)Marshal.PtrToStructure(lParam, typeof(CWPRETSTRUCT));
  131. IntPtr hook = hHook;
  132. if (msg.message == WM_INITDIALOG)
  133. {
  134. int nLength = GetWindowTextLength(msg.hwnd);
  135. StringBuilder className = new StringBuilder(10);
  136. GetClassName(msg.hwnd, className, className.Capacity);
  137. if (className.ToString() == "#32770")
  138. {
  139. nButton = 0;
  140. EnumChildWindows(msg.hwnd, enumProc, IntPtr.Zero);
  141. if (nButton == 1)
  142. {
  143. IntPtr hButton = GetDlgItem(msg.hwnd, MBCancel);
  144. if (hButton != IntPtr.Zero)
  145. SetWindowText(hButton, OK);
  146. }
  147. }
  148. }
  149. return CallNextHookEx(hook, nCode, wParam, lParam);
  150. }
  151. private static bool MessageBoxEnumProc(IntPtr hWnd, IntPtr lParam)
  152. {
  153. StringBuilder className = new StringBuilder(10);
  154. GetClassName(hWnd, className, className.Capacity);
  155. if (className.ToString() == "Button")
  156. {
  157. int ctlId = GetDlgCtrlID(hWnd);
  158. switch (ctlId)
  159. {
  160. case MBOK:
  161. SetWindowText(hWnd, OK);
  162. break;
  163. case MBCancel:
  164. SetWindowText(hWnd, Cancel);
  165. break;
  166. case MBAbort:
  167. SetWindowText(hWnd, Abort);
  168. break;
  169. case MBRetry:
  170. SetWindowText(hWnd, Retry);
  171. break;
  172. case MBIgnore:
  173. SetWindowText(hWnd, Ignore);
  174. break;
  175. case MBYes:
  176. SetWindowText(hWnd, Yes);
  177. break;
  178. case MBNo:
  179. SetWindowText(hWnd, No);
  180. break;
  181. }
  182. nButton++;
  183. }
  184. return true;
  185. }
  186. }
  187. }