ウィンドウを探すスレッドを作成しています。ウィンドウが見つかると、windowproc をオーバーライドし、WM_COMMAND と WM_CLOSE を処理します。
ウィンドウを探してサブクラス化するコードは次のとおりです。
public void DetectFileDialogProc()
{
Window fileDialog = null;
// try to find the dialog twice, with a delay of 500 ms each time
for (int attempts = 0; fileDialog == null && attempts < 2; attempts++)
{
// FindDialogs enumerates all windows of class #32770 via an EnumWindowProc
foreach (Window wnd in FindDialogs(500))
{
IntPtr parent = NativeMethods.User32.GetParent(wnd.Handle);
if (parent != IntPtr.Zero)
{
// we're looking for a dialog whose parent is a dialog as well
Window parentWindow = new Window(parent);
if (parentWindow.ClassName == NativeMethods.SystemWindowClasses.Dialog)
{
fileDialog = wnd;
break;
}
}
}
}
// if we found the dialog
if (fileDialog != null)
{
OldWinProc = NativeMethods.User32.GetWindowLong(fileDialog.Handle, NativeMethods.GWL_WNDPROC);
NativeMethods.User32.SetWindowLong(fileDialog.Handle, NativeMethods.GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(new WindowProc(WndProc)).ToInt32());
}
}
そしてwindowproc:
public IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
lock (this)
{
if (!handled)
{
if (msg == NativeMethods.WM_COMMAND || msg == NativeMethods.WM_CLOSE)
{
// adding to a list. i never access the window via the hwnd from this list, i just treat it as a number
_addDescriptor(hWnd);
handled = true;
}
}
}
return NativeMethods.User32.CallWindowProc(OldWinProc, hWnd, msg, wParam, lParam);
}
これはすべて、通常の条件下ではうまく機能します。しかし、悪い動作の 2 つのインスタンスが、悪い順に見られます。
1 分ほどでダイアログを閉じないと、アプリがクラッシュします。これは、スレッドがガベージ コレクションを取得しているためですか? スレッドが完了したことを GC が判断できる限り、これは理にかなっていますか? これが事実である場合 (そして、私はそうであるとは知りません)、ダイアログが存在する限りスレッドを存続させるにはどうすればよいですか?
「X」ボタン (WM_CLOSE) でダイアログをすぐに閉じると、アプリがクラッシュします。windowprocでクラッシュすると思いますが、そこにブレークポイントを取得できません。AccessViolationException が発生しました。この例外には、「保護されたメモリを読み書きしようとしました。これは、多くの場合、他のメモリが破損していることを示しています。」それは競合状態ですが、私にはわかりません。参考までに、コマンドを処理したら古いwindowprocをリセットしていましたが、それはさらに頻繁にクラッシュしていました!
これらの問題をどのように解決できるかについてのアイデアはありますか?