Un logiciel sur lequel je travaille récemment, dont certains doivent être complétés en appelant d'autres logiciels, mais ce logiciel n'a que des fichiers exécutables et aucun code source du tout. Démarré après le démarrage de mon programme.
En parlant de cela, je crois que vous avez des idées préliminaires pour cette fonction.
1) Appelez CreateProcess () pour ouvrir le programme cible.
2) Utilisez FindWindow () pour trouver la poignée de fenêtre du programme cible.
3) Trouvez la poignée de la zone de texte et le MessageID du bouton, définissez le texte à l'aide de la méthode SendMessage () et déclenchez l'événement.
OK, c'est en effet très simple, mais lorsque je l'ai implémenté, j'ai trouvé que le résultat était: lorsque mon programme a démarré et ouvert le programme cible, sa fenêtre d'éclaboussure et la fenêtre principale seront affichées, même si j'utilise Findwindow () Pour trouver la poignée de fenêtre principale et appeler SendMessage (WindowHandle, SW_HIDE) pour masquer la fenêtre, la fenêtre principale sera affichée pendant un moment.
Alors, comment résoudre ce problème? , cela n'a aucun effet. . . . Continuez à rechercher le document. , et s'il y est affecté après un nom de bureau, le processus sera lancé sur le bureau spécifié.
1) Tout d'abord, créez un bureau virtuel.
const
DesktopName = 'MyDesk';
Fdesktop: = Createdesktop (DesktopName, nil, nil, 0, generic_all, nil);
Plusieurs ordinateurs de bureau peuvent être créés dans Windows, et SwitchDesktop () peut être utilisé pour changer quel bureau est affiché. Windows lui-même est implémenté par une fonction de bureau virtuelle. . matériel:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/enumdesktops.asp
2) Lorsque CreateProcess, spécifiez le programme pour s'exécuter sur mon bureau nouvellement généré:
var
StartInfo: tstartupinfo;
FillChar (startInfo, sizeof (startInfo), 0);
StartInfo.cb: = sizeof (startInfo);
StartInfo.lpdesktop: = pChar (DesktopName);
StartInfo.wshowwindow: = sw_hide;
StartInfo.dwflags: = startf_useshowwindow;
StartInfo.hstderror: = 0;
StartInfo.hstdinput: = 0;
StartInfo.hstdoutput: = 0;
Si ce n'est pas CreateProcess (pChar (nom de fichier), nil, nil, nil, nil, true, create_new_console + high_pririty_class, nil, phar (extractfilepath (filepath)), startinfo, fproceinfo) puis commencer
MessageBox (application.handle, 'Error When init Voice (5).', PCHA (Application.Title), MB_ICONWARNING);
sortie;
fin;
3) Utilisez Findwindow pour trouver la fenêtre principale du programme
Au début, j'ai écrit le code comme ceci:
pour i: = 0 à 60 do commence // attendez 30 secondes pour ouvrir la fenêtre principale
WindowHandle: = FindWindow (nil, 'WindowCaption');
Si WindowHandle <> 0 alors commencez
casser;
fin;
Sommeil (500);
fin;
Cependant, la pratique a prouvé que cette façon, la fenêtre qui n'est pas dans le bureau actuel ne peut être trouvée.
La réponse est que vous pouvez utiliser la fonction SetThreadDeskTop (), qui peut définir le bureau où fonctionne le thread, j'ai donc ajouté une autre phrase avant le code ci-dessus:
Si pas setThreadDeskTop (fdesktop) alors commencez
sortie;
fin;
Cependant, une fois le programme exécuté, la fonction renvoie false, indiquant que l'appel de la méthode a échoué après avoir examiné soigneusement MSDN, j'ai constaté qu'il y a une phrase:
La fonction SetThreadDesktop échouera si le fil d'appel a des fenêtres ou des crochets sur son bureau actuel (sauf si le paramètre HDESKTOP est une poignée pour le bureau actuel).
Oh, il s'avère qu'il n'y a pas de chose d'interface utilisateur dans le fil qui doit changer de bureau, mais j'ai appelé cette méthode dans le fil principal du programme, et bien sûr, il échouera. Besoin d'en utiliser un n'est-ce pas de lier le fil "propre" au nouveau bureau, puis d'utiliser la méthode findWindow () pour trouver le WindowHandle que je recherche? Le code est le suivant:
TFindwindowThread = class (tThread)
Privé
Fdesktop: Thandle;
Fwindowhandle: Thandle;
protégé
Procédure Execute (); Override;
publique
Concluteur Create (acreAsUspeded: booléen; constadesktop: thandle); réintroduce;
Propriété WindowHandle: Thandle Read FwindowHandle;
fin;
{TFindwindowThread}
procédure tFindwindowThread.Exécute ();
var
I: entier;
Commencer
// Faire la fenêtre de recherche de fil actuel sur le nouveau bureau!
Si pas setThreadDeskTop (fdesktop) alors commencez
sortie;
fin;
pour i: = 0 à 60 do commence // attendez 30 secondes pour ouvrir la fenêtre principale
Fwindowhandle: = findwindow (nil, pChar ('windowcaption'));
Si fwindowhandle <> 0 alors commencez
casser;
fin;
Sommeil (500);
fin;
fin;
Constructeur tFindwindowThread.Create (acrésexé: booléen; const adesktop: thandle);
Commencer
Hérité de création (acreAsuspeded);
Fdesktop: = adesktop;
fin;
Et le code du programme principal devient ceci:
Findwindowthread: = tFindwindowThread.create (false, fdesktop);
essayer
Findwindowthread.waitfor;
Fmainwindowhandle: = findwindowthread.windowHandle;
Enfin
Findwindowthread.free;
fin;
Si fmainwindowhandle = 0 alors commencez
MessageBox (application.handle, «Erreur quand init vocal (6)». », PChar (application.title), MB_ICONWARNING);
sortie;
fin;
Haha, c'est un succès, vous pouvez donc trouver la manche en douceur de la fenêtre.
4) Enfin, utilisez cette poignée de fenêtre principale pour trouver la poignée Editbox à l'intérieur, comme suit:
FeditWindow: = FindWindowEx (fmainwindowhandle, 0, pChar ('edit'), nil);
J'ai spécifié le nom de classe de cette zone de texte ici, et ce nom peut être obtenu avec SPY ++.
Le travail d'initialisation se termine ici. L'appel de fonction est donc le même que d'habitude:
if (fmainwindowhandle = 0) ou (feditwindow = 0) alors commencez
sortie;
fin;
SendMessage (FeditWindow, WM_SETTEXT, 0, Longint (@atext [1]));
SendMessage (fmainwindowhandle, WM_Command, 8012 $, 0 $);
Le nombre 8012 $ est également l'ID de ressource obtenu en utilisant SPY ++.
Enfin, n'oubliez pas de fermer le programme et de publier le bureau virtuel:
Si fproceinfo.hprocess <> 0 alors commencez
TermineProcess (fproceinfo.hprocess, 0);
fin;
Si fdesktop <> 0 alors commencez
CLOLESKTOP (FDESKTOP);
fin;
OK, cela implémente presque parfaitement la fonction d'un programme d'appel de fond, qui sera complètement transparent au client final, et le client ne pense tout simplement pas qu'il existe un autre programme qui fonctionne en arrière-plan. N'est-ce pas très bien?
Si vous avez des suggestions d'amélioration ou d'échange, vous pouvez envoyer un courrier à: Tonyki [à] citoyen.net