11
votes

FindWindowex de user32.dll renvoie une poignée de zéro et code d'erreur de 127 en utilisant dllimport

J'ai besoin de gérer une autre application Windows de manière programmative, de rechercher Google J'ai trouvé un échantillon qui gère la calculatrice Windows à l'aide de Dllimport Attribut et important les fonctions User32.dll dans les fonctions gérées en C #.

L'application est en cours d'exécution, je reçois le Poignée pour la fenêtre principale, c'est-à-dire la calculatrice elle-même, mais le code par la suite ne fonctionne pas. La méthode FindwindowEX ne renvoie pas les poignées des enfants de la calculatrice comme des boutons et une zone de texte.

J'ai essayé d'utiliser le SetlasterRor = true sur dllimport et j'ai constaté que je reçois un code d'erreur de 127 qui est " Procédure non trouvée ".

Ceci est le lien de l'endroit où j'ai eu l'exemple d'application:

http://www.codeproject.com/script/articles/articleverversion.aspx?aid=14519&av=34503

s'il vous plaît aide si quelqu'un sait le résoudre.

mise à jour: le Dllimport est: xxx

Le code qui ne fonctionne pas est: < Pré> xxx


4 commentaires

Quelle version de Windows utilisez-vous?


Si vous rencontrez un problème avec P / Invoke, postez votre déclaration avec l'attribut dllimport . Si vous rencontrez un problème avec un code, postez le code qui ne fonctionne pas.


@Codygray, je suis professionnel de Windows 7.


@Gabe j'ai mis à jour ma question et inclus le code qui ne fonctionne pas.


3 Réponses :


13
votes

Le code que vous essayez repose sur les légendes des boutons individuels pour les identifier. Par exemple, il utilise le code suivant pour obtenir une poignée sur le bouton "1": xxx

qui spécifie "bouton" pour le nom de la classe de la fenêtre et "1" pour le nom de la fenêtre (dans le cas d'une touche, c'est la même chose que le texte de la légende affiché sur le bouton lui-même).

Ce code a fonctionné bien sous Windows XP (et versions précédentes), où les boutons de la calculatrice ont été identifiés avec des légendes textuelles. Le bouton "1" avait un nom de fenêtre de "1" et "1" a donc été affiché comme légende du bouton.

Cependant, il semble que les choses ont changé sous Windows 7 (éventuellement sous Vista aussi , bien que je ne puisse pas vérifier cela parce que je n'ai pas accès à un tel système). En utilisant SPY ++ pour étudier la fenêtre de calculatrice confirme que le bouton "1" n'a plus de nom de fenêtre de "1". En fait, il n'a pas de nom de fenêtre du tout; La légende est nulle. Vraisemblablement, le nouveau look fantaisie de la calculatrice nécessitait que les boutons soient personnalisés, les légendes ne sont donc plus nécessaires pour indiquer quel bouton correspond à la fonction. Les routines de peinture personnalisées prennent soin de dessiner les légendes nécessaires.

car aucune touche ne peut être trouvée avec le texte de la fenêtre que vous avez spécifié, une valeur 0 ( null ) est renvoyé pour le Poignée de fenêtre.

le Documentation pour le Findwindowex < / code> fonction indique que vous pouvez spécifier null pour le paramètre lpszwindow , mais que cela correspondra bien sûr tous tous fenêtres de la classe spécifiée. Probablement pas ce que vous voulez dans ce cas, car l'application de calculatrice a une bande de boutons.

Je ne sais pas une bonne solution de contournement. La calculatrice n'a pas été conçue pour être "automatisée" de cette façon et Microsoft n'a jamais garanti qu'il ne changerait pas son fonctionnement interne. C'est un risque que vous utilisez à l'aide de cette approche pour désordre avec les fenêtres d'autres applications.


EDIT: Le code que vous avez lié est également faux dans un autre Gratuit sérieux, même sur des versions antérieures de Windows. Il déclare la variable hwnd comme type int , plutôt que comme type intPTR . Étant donné qu'une poignée de fenêtre est un pointeur , vous devez toujours le stocker en tant que type intPTR . Qui fixe également la création laid dans l'appel de la fonction FindWindowex qui aurait dû envoyer des drapeaux rouges.

Vous devez également corriger la déclaration de sendMessage Pour que son premier paramètre est de type intPTR .

Le code aurait dû être écrit comme ceci: xxx


7 commentaires

Connaissez-vous un moyen d'énumérer des fenêtres enfants à l'aide d'EnumChildWindows et de vérifier dans le rappel si c'est la fenêtre que nous devons capturer? J'utilise Winapi pour la première fois et je ne sais pas comment écrire du code pour utiliser EnumchildWindows.


@Puneet: Pour ce faire, vous devrez déterminer un moyen d'identifier de manière unique les boutons de la calculatrice. Comme je l'ai expliqué dans ma réponse, je ne sais pas d'un bon moyen de le faire. Tous les boutons ont un titre de fenêtre (légende) de "" ou null . Programmatiquement, il sera difficile de trouver un moyen d'identifier les boutons individuels, compte tenu de leurs poignées.


Sur ma boîte Win7, les boutons de la calculatrice ont toutes des légendes Standard Unicode selon SPY ++ (j'ai essayé tous les 4 modes dans le menu Affichage). De plus, pour la compatibilité 32 bits, toutes les poignées de fenêtre peuvent s'adapter dans 32 bits. Un hwnd doit être convertimé vers un int et de retour tout simplement bien.


@Gabe: intéressant. J'ai vérifié le mien sur le serveur 2008 R2 64 bits et ils n'ont définitivement pas de légendes unicodes standard. Je viens de vérifier la vue standard, mais les autres ne semblent pas avoir des légendes non plus. Et oui, même si vous utilisez int fonctionnera souvent pour les poignées, ce n'est pas la bonne façon de faire les choses. Vous êtes censé utiliser intPTR , pas profiter de la compatibilité en arrière. :-)


J'ai compris le problème. J'ai des thèmes, ce qui provoque l'utilisation des légendes de boutons Unicode. Vous devez avoir des thèmes sur (qui n'est pas la valeur par défaut pour le serveur), ce qui provoque le calcul de CALC d'utiliser des boutons thématiques avec des légendes vierges.


@Gabe: Ouais, je cours avec des thèmes pour que mes applications se ressemblent comme elles le devraient. Souvent que la plupart des utilisateurs ne sont pas d'accord avec mes préférences esthétiques pour le mode classique.


Il est facile de calculer quel bouton est lequel est lequel! Juste obtenir leurs positions!



2
votes

J'ai pu reproduire cela sur Win7 Pro. Votre problème est probable que les étiquettes sur les boutons soient dessinées via le thème de la calculatrice et non comme une légende. Lorsque le service thématiques est en cours d'exécution, la calculatrice de démarrage le fera d'avoir des boutons sans légende.

Pour obtenir des légendes de bouton appropriées, vous devez:

  1. Arrêtez le service thématiques (Exécuter NET STOP THEMES à partir d'une invite de commande élevée ou utilisez l'outil d'administration des services).
  2. Démarrer la calculatrice.

    Si vous avez la calculatrice en cours d'exécution lorsque vous arrêtez le service de thèmes, vous remarquerez que tous ses boutons deviennent vides.


4 commentaires

Ah, vous utilisiez donc le mode classique. Je suis certainement d'accord avec ce choix. La désactivation des thèmes semble en effet être la solution de contournement, mais pas très bonne. Vous travaillez simplement autour d'hypothèses effectuées dans le code, plutôt que de fixer ces hypothèses. Il est difficile d'imaginer l'utilité d'une application qui ne fonctionnera que correctement sur une configuration non par défaut de Windows.


@Cody: Voyant comme il est inutile d'automatiser une calculatrice de C #, je devrais supposer que cela ne fait qu'un exercice. Il est difficile d'imaginer que quelqu'un crée réellement une application qui s'appuie sur l'automatisation de CALC!


@Cody: Finalement, mon besoin est de ne pas automatiser la calculatrice via C #, j'ai écrit dans ma question que j'ai trouvé une demande d'échantillon pour comprendre comment faire le travail réel. Enfin, je dois la mettre en œuvre pour AOTTER Windows Application, un système de réservation de billets et un outil de rapport.


Même après avoir arrêté les thèmes sur ma Win7, je ne suis pas en mesure d'automatiser la calculatrice à travers cette application. Je reçois toujours la poignée des boutons d'enfant comme zéro.



2
votes

Le code suivant fonctionne correctement dans la calculatrice de Windows 7 dans le thème classique (ne fonctionnera pas dans le thème de base ou Aero):

=================== ================================ P>

IntPtr hwndFrame = FindWindowEx(hwnd, IntPtr.Zero, "CalcFrame", null); 
IntPtr hwndDialog = FindWindowEx(hwndFrame, IntPtr.Zero, "#32770", null); 
IntPtr hwndDialog2 = FindWindowEx(hwndFrame, (IntPtr)hwndDialog, "#32770", null);


IntPtr hwndThree = FindWindowEx(hwndDialog2, IntPtr.Zero, "Button", "3"); 
SendMessage((int)hwndThree, BN_CLICKED, 0, IntPtr.Zero);

IntPtr hwndPlus = FindWindowEx(hwndDialog2, IntPtr.Zero, "Button", "+");
SendMessage((int)hwndPlus, BN_CLICKED, 0, IntPtr.Zero);

IntPtr hwndOne = FindWindowEx((IntPtr)hwndDialog2, IntPtr.Zero, "Button", "1");
SendMessage((int)hwndOne, BN_CLICKED, 0, IntPtr.Zero);

IntPtr hwndEqual = FindWindowEx(hwndDialog2, IntPtr.Zero, "Button", "=");
SendMessage((int)hwndEqual, BN_CLICKED, 0, IntPtr.Zero);


0 commentaires