Pergunta

Estou criando um tópico que procura uma janela. Quando encontra a janela, ele substitui seu WindowProc e lida com WM_COMMAND e WM_CLOSE.

Aqui está o código que procura a janela e a subclasse:

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());
   }
}

E o 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);
}        

Tudo isso funciona bem em condições normais. Mas estou vendo dois casos de mau comportamento em ordem de maldade:

  1. Se eu não fechar a caixa de diálogo em um minuto, o aplicativo trava. Isso é porque o fio está recebendo lixo? Isso faria sentido, tanto quanto o GC pode dizer que o tópico é feito? Se for esse o caso, (e eu não sei se é), como posso fazer o tópico permanecer enquanto a caixa de diálogo estiver por perto?

  2. Se eu fechar imediatamente a caixa de diálogo com o botão 'X' (wm_close), o aplicativo trava. Acredito que está batendo no WindowProc, mas não consigo um ponto de interrupção lá. Estou recebendo uma AccessViolationException, a exceção diz "tentou ler ou escrever memória protegida. Isso geralmente é uma indicação de que outra memória é corrupta". É uma condição de corrida, mas do que eu não sei. Para sua informação, eu estava redefinindo o antigo WindowProc depois de processar os comandos, mas isso estava batendo com mais frequência!

Alguma idéia de como posso resolver esses problemas?

Foi útil?

Solução 2

Finalmente, criou uma solução, atacando o problema de um ângulo diferente. Consegui definir um gancho em todo o sistema no código gerenciado usando o SetWineStentHook e a opção winevent_outofcontext, que surpreendentemente tem a propriedade: a função de retorno de chamada não é mapeada no espaço de endereço do processo que gera o evento. Eu prendi o evento event_system_dialogstart para receber notificações sempre que uma caixa de diálogo é criada e event_system_dialogend quando ela é destruída.

Outras dicas

Dois pontos de observação que eu posso fazer ....

  • Na tua DetectFileDialogProc, você está comparando wnd para nulo, isso é um IntPtr digite sim? Nesse caso, essa verificação para a comparação deve ser if (wnd > IntPtr.Zero){ .... }
  • Na tua WndProc, você está usando o this variável para o lock o que é uma coisa ruim de se fazer ... você deve fazer algo assim private readonly object objLock = new object(); e dentro do seu WndProc usa isto lock (objLock){....}

E veja se isso resolve o problema ....

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top