Sottoclasse di una finestra da un thread in C #
-
22-09-2019 - |
Domanda
Sto creando un filo conduttore che cerca di una finestra. Quando trova la finestra, si sostituisce la sua WindowProc e gestisce WM_COMMAND e WM_CLOSE.
Ecco il codice che cerca la finestra e le sottoclassi che:
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 il 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);
}
Tutto questo funziona bene in condizioni normali. Ma sto vedendo due istanze di cattivo comportamento in ordine di cattiveria:
-
Se non si chiude la finestra di dialogo in un minuto o poco più, l'applicazione si blocca. È questo perché il filo si sta garbage collection? Questo tipo di senso, per quanto GC può dire il filo è fatto? Se questo è il caso, (e non so che sia), come posso fare il filo rimanere intorno fino a quando la finestra di dialogo è di circa?
-
Se ho subito chiudere la finestra con il tasto 'X' (WM_CLOSE) l'applicazione si blocca. Credo che il suo fragore nel WindowProc, ma non riesco a ottenere un punto di interruzione in là. Ricevo un AccessViolationException, L'eccezione dice: "Tentativo di lettura o scrittura della memoria protetta. Ciò è spesso un'indicazione che l'altra memoria è danneggiata." La sua una condizione di competizione, ma di ciò che non lo so. Cordiali saluti, ero stato resettare il vecchio WindowProc una volta ho elaborato i comandi, ma che stava arrestando anche più spesso!
Tutte le idee su come posso risolvere questi problemi?
Soluzione 2
Infine si avvicinò con una soluzione, attaccando il problema da una diversa angolazione. Sono stato in grado di impostare un hook al livello di sistema nel codice gestito utilizzando SetWinEventHook, e l'opzione WINEVENT_OUTOFCONTEXT, che ha sorprendentemente proprietà: La funzione di richiamata non è mappato nello spazio di indirizzi del processo che genera l'evento. Ho intrappolare l'EVENT_SYSTEM_DIALOGSTART evento di ricevere notifiche ogni volta che viene creata una finestra di dialogo, e quando il suo EVENT_SYSTEM_DIALOGEND distrutti.
Altri suggerimenti
Due punti di osservazione che posso fare ....
- Nella tua
DetectFileDialogProc
, si confrontanownd
su null, che è un tipo diIntPtr
sì? in caso affermativo, che di controllo per il confronto dovrebbe essereif (wnd > IntPtr.Zero){ .... }
- Nella tua
WndProc
, si utilizza la variabilethis
per lalock
che è una brutta cosa da fare ... si dovrebbe fare qualcosa di simileprivate readonly object objLock = new object();
ed entro l'utilizzoWndProc
questolock (objLock){....}
e vedere se questo risolve il problema ....