9
votes

Pourquoi ne peut-il pas obtenir la poignée principale pour un processus démarré?

J'ai une situation où je démarre un processus dans mon code afin de configurer une chaîne IPC. Le processus que je démarre est une application MFC sans support CLR. L'application à partir de laquelle je commence ce processus est un module C # dans une application WPF (pensée que je ne pense pas que cela est consécutif à mon problème). Cela fonctionne avec une version de l'application qui prend en charge CLR et fonctionne sur chaque ordinateur, à l'exception de la cible de déploiement, un ordinateur tactile avec Windows 7. Mais pour une raison quelconque, lorsque je l'essaie avec ce scénario exact, l'objet de processus jamais résout une poignée de fenêtre principale ( processus.mainwindowhandle code>). Y a-t-il une autre méthode (peut-être même pinvoke) de faire cela? Est-ce une chose de sécurité? Je suis celui qui regarde le processus. La poignée de la fenêtre principale du processus existe. Je ne vois pas ce qui pourrait être faux.

Si cela aide, voici mon code. p>

        _applicationProcess = new Process();
        _applicationProcess.StartInfo.FileName = _strProcessPath;
        _applicationProcess.StartInfo.Arguments = _strProcessArguments;
        _applicationProcess.Start();

        long nTicks = Environment.TickCount;
        if (_applicationProcess.WaitForInputIdle(1 /*minute(s)*/ * 60000))
        {
            try
            {
                do
                {
                    // Don't let total processing take more than 1 minute(s).
                    if (Environment.TickCount > nTicks + 1 /*minute(s)*/ * 60000)
                        throw new ApplicationException("MFCApplication.Startup failed! The main window handle is zero!");

                    _applicationProcess.Refresh();
                }
                while (_applicationProcess.MainWindowHandle.ToInt32() == 0);

                _applicationHandle = new IntPtr(_applicationProcess.MainWindowHandle.ToInt32());
            }
            catch (Exception ex)
            {
                //Do some stuff...
                throw;
            }
        }
        else
        {
            // Do exception handling.
        }


10 commentaires

Avez-vous fatigué avec waitforinputidle comme suggéré par les documents MSDN? Il est également préférable d'utiliser lancer au lieu de lancer ex , car vous perdrez des informations de trace de pile avec jette ex ( jette ex < / code> redémarre le lancer d'exception et donc la trace de la pile).


@jordan je vois votre édition. Vous devez inclure @Asername dans vos commentaires afin que l'autre utilisateur que vous répondiez est notifié.


@jordan dans votre fusion \ tandis que la boucle, je pense que vous confondez des tiques avec des millisecondes. Une tique est un 100 nanosecondes. Il est probablement plus simple d'utiliser un chronomètre pour cela.


@jordan, il vaut probablement la peine d'être envisagé de mettre un thread.sleep dans votre boucle pour accélérer votre Actualiser les appels .


@chibity Nope Aucun de cela fonctionne. Et je ne pensais pas que le @ était nécessaire depuis que vous étiez le seul commentateur.


Est-ce une version 64 bits de Windows?


J'ai une théorie, je cache la fenêtre principale peu de temps après sa charge. L'acte de cacher une fenêtre la modifier de l'état de la fenêtre principale? Juste une pensée. @Hans oui c'est.


Connexes: Stackoverflow.com/Questtions/3276439/...


@chibacité, pour l'enregistrement, selon la documentation Environnement.TickCount est en millisecondes pas de ticks. Nom confus, mais les tiques étaient des millisecondes. Je fais comme chronomètre cependant.


@Jordon I Stand corrigé, Environnement.TickCount est en effet en millisecondes et non des tiques. C'est déroutant. À votre santé.


4 Réponses :


3
votes

Mon habitude consiste à appeler Enumwindows dans une boucle combinée à GetWindowTheadProcessid pour trouver la poignée de la fenêtre.

C Code, adapt to your language


DWORD TargetHWND;

//...
    while (EnumWindows(EnumWndProc, (LPARAM)(DWORD)pid)) {
        Sleep(100);
    }


//...

BOOL EnumWndProc(HWND hWnd, LPARAM lParam) {
    DWORD pid = (DWORD)-1;
    GetWindowThreadProcessId(hWnd, &pid);
    if (pid == (DWORD)lParam) {
        TargetHWND = hWnd;
        return FALSE;
    }
    return TRUE;
}


2 commentaires

Comment cela m'aide-t-il exactement? J'essaie d'obtenir une poignée de fenêtre d'un autre processus. Pouvez-vous me fournir un code?


Donc, fondamentalement, cela obtient toutes les fenêtres de l'ID de processus donné, intéressant.



1
votes

Je ne sais pas pourquoi cela pourrait être différent, mais après avoir créé le processus, essayez de faire:

Process[] allProcesses = Process.GetProcessesByName("YourWindowTitle");


1 commentaires

C'est différent, mais de la manière opposée. Obtenir un processus de cette façon, vous n'avez pas de confiance enbout et vous ne pouvez donc rien faire de rien, et certainement pas sa poignée. Ce n'est que lorsque vous démarrez un processus, pouvez-vous interagir avec elle dans un sens significatif.



6
votes

La valeur que vous sortez du processus.MainWindowhandle est malheureusement une supposition. Il n'y a pas de fonction API disponible pour un programme qui le permet de dire Windows "Ceci est ma fenêtre principale". La règle qu'elle utilise est documentée, c'est la première fenêtre créée par un processus lorsqu'il est démarré. Cela provoque des problèmes si cette première fenêtre est, disons, une fenêtre de connexion ou un écran éclaboussure.

Pas grand chose que vous pouvez faire à ce sujet, vous devez en savoir plus sur la manière dont le programme se comporte pour trouver que la fenêtre principale réelle . Enumérant Windows avec EnumthreadWindows () pourrait vous aider à trouver, tant que la première fenêtre a été créée sur le même fil que la fenêtre principale. Un Enumwindows plus élaboré () sera nécessaire si ce n'est pas le cas.


0 commentaires

2
votes

Pour obtenir mainwindowhandle code> au moyen de votre processus, assurez-vous que votre application WPF est affichée dans la barre des tâches, c'est-à-dire showintaskbar = "vrai" code> et définir Application.Currrent.MainWindow code> Propriété à la fenêtre que vous souhaitez définir comme fenêtre principale.

Si j'exécute du code ci-dessous dans ma fenêtre principale WPF sans réglage showintaskbar = "vrai" Code> J'ai toujours 0 en tant que Mainwindowhandle code> car ma fenêtre WPF était en plein écran et non affichée dans la barre des tâches. P>

    Application.Current.MainWindow = this;
    var Query = System.Diagnostics.Process.GetProcessesByName("ProcessName");

    if (Query.Any())
    {
        Query.FirstOrDefault().Refresh();
        MessageBox.Show(Query.FirstOrDefault().MainWindowHandle.ToInt32().ToString());
    }


0 commentaires