2010-01-02 11 views
0

J'ai un client qui utilise une ancienne application ERP personnalisée pour laquelle il n'a pas de code source et la société qui l'a développé n'existe plus. L'application est développée en 2000 et est construite avec Delphi. Puisque le dernier exécutable date de 2003, il peut s'agir de D6 ou D7. Sur un formulaire important, il y a des champs dans lesquels le client souhaite afficher des données supplémentaires provenant d'autres bases de données et m'a demandé s'il était possible de "coller" des données sur un formulaire existant.Joindre une fenêtre à une application en cours d'exécution

idée d'abord, je suis arrivé est de construire l'application qui:

  • liste de navigation de Windows application cible crée et trouver des contrôles sur le formulaire
  • attach événement « un peu » quand pour être averti lorsque le formulaire cible est affiché
  • attach événement « certains » quand pour être averti lorsque le champ sur le formulaire cible est modifié
  • afficher des informations supplémentaires dans une petite fenêtre superposant forme cible

Y at-il des exemples sur la façon de faire quelque chose comme ça. J'ai cherché google avec des variations de ce titre de question, mais sans succès.

Remarque - la réécriture de l'application ERP n'est pas planifiée.

A propos de la langue - Je peux le faire avec C# ou Delphi.

+0

Ouf. Cela fait cinq ans que je n'ai pas développé de logiciel en Delphi, donc je ne suis pas complètement qualifié pour répondre, mais cela semble tout à fait impossible quand la seule chose que vous avez est le binaire. Et je ne veux pas être jubilatoire ou être un smartass, mais des choses comme ça sont des arguments pour l'Open Source - si ce n'est pas ouvert au public, alors au moins ouvert au client payant. –

+0

Dans quelle langue évoluez-vous? –

Répondre

4

Je vais répondre à cela d'un point de vue purement CWin32, parce que je ne connais pas Delphi ou ses bibliothèques. Convertir ceci en C# peut être accompli via p/invoke, mais certaines parties peuvent/devront être non gérées.

Tout d'abord, aucune garantie. Si l'application cible effectue des contrôles sans fenêtres (s'il n'y a pas de HWND sous chaque contrôle à l'écran), vous n'avez pas vraiment de chance. Ce n'est pas si rare, alors oui ...

Étape 1, inscrivez-vous un crochet de fenêtre d'écoute pour les nouvelles fenêtres créées par le processus cible *:

//dllHMod is an HMODULE that refers to the DLL containing ShellHookProc 
HHOOK hook = SetWindowsHookEx(WH_SHELL, ShellHookProc, dllHMod, 0); 
// error handling, stashing hook away for unregistering later, etc... 

LRESULT CALLBACK ShellHookProc(int nCode, WPARAM wParam, LPARAM lParam) 
{ 
    if(nCode < 0) return CallNextHookEx(NULL, nCode, wParam, lParam); 

    if(nCode == HSHELL_WINDOWCREATED) 
    { 
    WindowCreate((HWND)wParam); 
    } 

    return 0; 
} 

WindowCreated(HWND) devrait planquer HWND si le processus correct (déterminé par GetWindowThreadProcessId) le possède. À ce stade, vous serez en mesure d'obtenir toutes les fenêtres de niveau supérieur appartenant au processus cible. Notez que l'enregistrement d'un hook global entraîne une pénalité de performance notable, pas que cela ait vraiment de l'importance dans votre cas, mais vous devriez vous y attendre.

Maintenant, pour la partie amusante. Il n'y a pas de moyen fiable de savoir quand une fenêtre est entièrement construite, ou quand elle est terminée (il y a des façons de dire quand elle commence le rendu, mais cela n'aide pas vraiment). Mon conseil, devinez. Lancez simplement une attente arbitraire et essayez d'énumérer toutes les fenêtres enfants.

Enumérer les fenêtres enfants (si vous en savez assez sur la fenêtre cible, il y a de meilleures façons de le faire, mais je suppose une recherche est plus facile):

//targetHWND is an HWND of one of the top-level windows you've found 
EnumChildWindows(targetHWND, ChildWindowCallback, NULL); 
//more code... 

BOOL ChildWindowCallback(HWND window, LPARAM ignored) 
{ 
    if(IsTargetWindow(window)) { /* Do something */ } 

    return TRUE; 
} 

La mise en œuvre IsTargetWindow est une autre partie délicate .J'espère que vous trouverez un test fiable pour ce faire (comme vérifier le nom de la classe, le nom de la fenêtre, le style, quelque chose, regardez GetWindowInfo). Une fois que vous avez la fenêtre que vous voulez surveiller, vous pouvez utiliser SetWindowLongPtr et GWLP_WNDPROC pour voir tous les messages qu'il reçoit. Cela nécessitera l'injection de code (et donc le code non géré) et est terriblement bas niveau. Je vous le déconseille si vous pourriez l'éviter, mais manque la source ...

Je pense que cela répond à un point de départ décent, mais encore une fois cela va être incroyablement douloureux si son même possible du tout. Bonne chance. * Si vous savez que l'application cible ne crée pas de fenêtres, sauf au démarrage (ou à des moments détectables/prévisibles dans le temps), vous pouvez utiliser EnumWindows.

+0

Kevin, merci beaucoup pour cette réponse très détaillée. – zendar