Domanda

Ecco il mio problema: devo chiudere un processo, già in esecuzione, da un programma C #. Il problema è che il processo ora viene eseguito come icona (ridotto a icona sulla barra delle applicazioni) e, a meno che l'utente non lo apra almeno una volta (cosa che non accadrà mai su macchine incustodite), non lo farà mai avere una finestra principale.

L'altro requisito che ho è che l'applicazione sia chiusa non uccisa . Ne ho bisogno per scrivere i suoi buffer di memoria su disco - e ucciderlo causa la perdita di dati.

Ecco cosa ho provato finora:

        foreach (Process proc in Process.GetProcesses())
        {
            if (proc.ProcessName.ToLower().StartsWith("myapp"))
            {
                if (proc.MainWindowHandle.ToInt32() != 0)
                {
                    proc.CloseMainWindow();
                    proc.Close();
                    //proc.Kill();  <--- not good!
                }
            }
        }

Ho aggiunto la clausola if , dopo aver scoperto che MainWindowHandle == 0 quando la finestra era ridotta a icona. Rimuovere se non aiuta. Né CloseMainWindow () Chiudi () funzionano. Il Kill () lo fa, ma come detto sopra - non è quello di cui ho bisogno.

Qualsiasi idea sarebbe accettata, incluso l'uso delle arcane funzioni dell'API Win32 :)

È stato utile?

Soluzione 3

Ecco alcune risposte e chiarimenti:

rpetrich : Ho provato il tuo metodo prima e il problema è che non conosco il nome della finestra, differisce da utente a utente, da versione a versione - solo il nome exe rimane costante. Tutto quello che ho è il nome del processo. E come puoi vedere nel codice sopra MainWindowHandle del processo è 0.

Roger : Sì, intendevo l'area di notifica sulla barra delle applicazioni, grazie per il chiarimento. HO BISOGNO di chiamare PostQuitMessage. Semplicemente non so come, dato solo un processo, e non una finestra.

Craig : Sarei felice di spiegare la situazione: l'applicazione ha un'interfaccia a riga di comando, che consente di specificare parametri che determinano cosa farebbe e dove salverà i risultati. Ma una volta che è in esecuzione, l'unico modo per fermarlo e ottenere i risultati è fare clic con il pulsante destro del mouse nella notifica sulla barra delle applicazioni e selezionare 'esci'.

Ora i miei utenti vogliono creare script / batch dell'app. Non hanno avuto alcun problema a avviarlo da un batch (basta specificare il nome exe e un gruppo di flag) ma poi si sono bloccati con un processo in esecuzione. Supponendo che nessuno cambierà il processo per fornire un'API per fermarlo durante l'esecuzione (è piuttosto vecchio), ho bisogno di un modo per chiuderlo artificialmente.

Allo stesso modo, su computer non presidiati, lo script per avviare il processo può essere avviato da un programma di pianificazione delle attività o di controllo delle operazioni, ma non è possibile arrestare il processo.

Spero che questo chiarisca la mia situazione e, ancora una volta, grazie a tutti coloro che stanno cercando di aiutare!

Altri suggerimenti

Questo dovrebbe funzionare:

[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr FindWindow(string className, string windowName);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

private const int WM_CLOSE = 0x10;
private const int WM_QUIT = 0x12;

public void SearchAndDestroy(string windowName) 
{
    IntPtr hWnd = FindWindow(null, windowName);
    if (hWnd == IntPtr.Zero)
        throw new Exception("Couldn't find window!");
    SendMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}

Poiché alcune finestre non rispondono a WM_CLOSE , potrebbe essere necessario inviare invece WM_QUIT . Queste dichiarazioni dovrebbero funzionare sia a 32 bit che a 64 bit.

Se si trova sulla barra delle applicazioni, avrà una finestra. O intendevi dire che si trova nell'area di notifica della barra delle applicazioni (aka SysTray)? In tal caso, avrà ancora una finestra.

Le applicazioni Win32 in realtà non hanno una "finestra principale", tranne che per convenzione (la finestra principale è quella che chiama PostQuitMessage in risposta a WM_DESTROY, causando la chiusura del ciclo di messaggi).

Con il programma in esecuzione, eseguire Spy ++. Per trovare tutte le finestre di proprietà di un processo, devi selezionare Spia - > Processi dal menu principale. Questo mostrerà un albero di processi. Da lì, puoi eseguire il drill-down dei thread e quindi di Windows. Questo ti dirà quali finestre ha il processo. Annota la classe e la didascalia della finestra. Con questi, puoi usare FindWindow (o EnumWindows) per trovare l'handle della finestra in futuro.

Con l'handle della finestra, puoi inviare un messaggio WM_CLOSE o WM_SYSCOMMAND / SC_CLOSE (equivalente a fare clic sulla "X" nella didascalia della finestra). Ciò dovrebbe causare l'arresto corretto del programma.

Nota che sto parlando da un punto di vista di Win32 qui. Potrebbe essere necessario utilizzare P / Invoke o altri trucchi per farlo funzionare da un programma .NET.

Domanda per chiarire il motivo per cui stai tentando questo: se l'unica interfaccia utente sul processo è l'icona nella barra delle applicazioni, perché dovresti volerlo uccidere e lasciare il processo in esecuzione? In che modo l'utente accederà al processo? E se la macchina è "incustodita", perché preoccuparsi dell'icona del vassoio?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top