| ■86798 / ) |
Re[4]: メッセージボックスが出ない |
□投稿者/ 魔界の仮面弁士 (1594回)-(2018/03/16(Fri) 21:58:21)
|
■No86795 (にゃるら さん) に返信 > Enterキーを押しっぱなしにしてみてください。 > メッセージ2が出るとは思いますが、勝手に閉じるのが見えると思います。
勝手に閉じたというよりは、メッセージボックスの default button が Enter キーによって押下されたということではないでしょうか。
■No86796 (にゃるら さん) に返信 > うーん、こういうことなのでしょうか?
以下、私の認識。(多分に推測を含みます)
.NET Framework のソースコードを読んでみると明らかですが、 MessageBox.Show メソッドの内部実装は、最終的に MessageBox API を呼び出します。
そして MessageBox API は、第一引数にオーナーウィンドウの ハンドルを渡す 仕様になっています。(ただし、この第一引数は NULL でも構いません) https://msdn.microsoft.com/en-us/library/windows/desktop/ms645505.aspx
そして、今回問題になっているコードですが、試しに var ret1 = MessageBox.Show("1"); var e1 = Marshal.GetLastWin32Error(); var ret2 = MessageBox.Show("2 ret1=" + ret1.ToString()); var e2 = Marshal.GetLastWin32Error(); として実行すると、"1" が表示されない場合には、 e1 が 6 (すなわち ERROR_INVALID_HANDLE) e2 が 0 (すなわち NO_ERROR) という値が返される状況になっていました。
MessageBox.Show の内部実装を見る限りでは、owner を null にした場合、 GetActiveWindow API で得られたウィンドウが使われるようなので、今回の場合、 おそらくこの段階で invalid な HWND が使われてしまったのではないでしょうか。
そしてその結果、既に破棄されたウィンドウハンドルが MessageBox API の第一引数に渡されることになり、この P/Invoke が ERROR_INVALID_HANDLE を理由に失敗していたのだと推察します。 親ハンドルが不正のため、"1" のメッセージはそもそも表示されません。
また、呼び出しが失敗した場合、MessageBox API は固定値 0 を返す仕様になっています。 ですから、呼び出されなかった場合には var ret1 = (DialogResult)0; に相当する処理結果になりそうなのですが…実際には DialogResult.None ではなく、DialogResult.No が返されています。
何故、この段階で None ではなく No が返されるのかといえば、 var ret1 = Win32ToDialogResult(0); という処理が行われるためのようです。 このメソッドの実装は下記をご覧ください。 https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/MessageBox.cs,bbe9ce90a8f7d475
この推察が正しいなら、回避策としては、正しいオーナーを渡せば良いわけですから、 Azulean さんの No86789 のコードが、解決策の一つになるかと思います。
もしくは、MessageBox API は、オーナーの HWND を NULL にすることを認めていますので、 API の第一引数に対して、意図的に IntPtr.Zero が渡るようにすることでも、 今回の問題を回避することができます。
private class NullWindow : IWin32Window { // IntPtr IWin32Window.Handle => IntPtr.Zero; IntPtr IWin32Window.Handle { get { return IntPtr.Zero; } } } public UserControl1() { var nw = new NullWindow(); var ret1 = MessageBox.Show(nw, "1"); var ret2 = MessageBox.Show(nw, "2 ret1=" + ret1.ToString()); Controls.Add(new Button()); }
とはいえ、NULL ハンドルな IWin32Window を作るだけなら、 わざわざ上記のようなクラスを自作せずとも、 No86791 に書いた NativeWindow を利用できます。
|
|