2010-07-12 3 views
0

Mon objectif est simple d'un point de vue conceptuel: je souhaite définir une fonction de connexion globale GetMessage qui utilise un descripteur de fichier partagé. Le problème se pose parce que d'après ma compréhension la DLL contenant la fonction de crochet est chargée plusieurs fois pour chaque processus, chacun avec leur propre "espace d'adressage". Pour cette raison, je suis amené à croire que je ne peux pas simplement gérer DLL_PROCESS_ATTACH de DllMain pour créer le fichier désiré, car plusieurs fichiers seraient créés avec des poignées différentes.Application aux DLL Global Hook

Une solution qui a été portée à mon attention est Named Pipes. Fondamentalement, l'application agirait comme la fin du serveur; il créerait le fichier une fois puis fournirait le handle de fichier aux clients DLL, donc chaque hook global utiliserait le même fichier.

Je n'arrive pas à faire fonctionner le code que j'ai recueilli. Dans l'application, je crée le fichier, définir la fonction globale de crochet, puis faire passer par cette boucle:

while(1) 
{ 
    HANDLE hPipe = CreateNamedPipe("\\\\.\\pipe\\pipename", PIPE_ACCESS_OUTBOUND, 
PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 32, 32, 5000, NULL); 
    if(hPipe == INVALID_HANDLE_VALUE) 
    return 42; 
    if(!ConnectNamedPipe(hPipe, NULL)) 
    return 43; 
    DWORD dwWritten; 
    WriteFile(hPipe, logFile, sizeof(logFile), &dwWritten, NULL); 
    FlushFileBuffers(hPipe); 
    DisconnectNamedPipe(hPipe); 
    CloseHandle(hPipe); 
} 

Je poignée la DLL_PROCESS_ATTACH de DllMain comme si:

case DLL_PROCESS_ATTACH: 
{ 
    HANDLE hPipe; 
    while(1) 
    { 
    hPipe = CreateFile("\\\\.\\pipe\\pipename", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); 
    if(hPipe != INVALID_HANDLE_VALUE) 
     break; 
    WaitNamedPipe("\\\\.\\pipe\\pipename", NMPWAIT_USE_DEFAULT_WAIT); 
    } 
    DWORD dwRead; 
    ReadFile(hPipe, logFile, sizeof(logFile), &dwRead, NULL); 
    CloseHandle(hPipe); 
    break; 
} 

En termes simples, il ne fonctionne pas, et je n'arrive pas à comprendre pourquoi. Y a-t-il quelque chose qui me manque ou qui ne va pas dans mon code?

Un autre problème que je n'arrive pas à comprendre est que l'application est bloquée dans une boucle infinie de service constant. Je veux configurer un événement que la DLL va définir dans certaines circonstances et amener l'application principale à décrocher le crochet global, fermer le fichier et quitter, cependant ConnectNamedPipe est une fonction bloquante. Quel est le moyen de déterminer quand tous les clients ont été servis pour que la boucle de service puisse se rompre?

Merci pour toute aide.

Répondre

1

Il existe des restrictions strictes quant aux API système que vous pouvez appeler pendant DLL_PROCESS_ATTACH ou DLL_THREAD_ATTACH. De l'MSDN documentation.

La fonction point d'entrée doit effectuer seulement simple initialisation ou tâches de terminaison. Il ne doit pas appeler la fonction LoadLibrary ou LoadLibraryEx (ou une fonction qui appelle ces fonctions), car cela peut créer des boucles de dépendance dans l'ordre de chargement DLL. Cela peut entraîner l'utilisation d'une DLL avant que le système ait exécuté son code d'initialisation. De même, la fonction point d'entrée ne doit pas appeler la fonction FreeLibrary (ou une fonction qui appelle FreeLibrary) pendant la fin du processus, car cela peut entraîner une DLL utilisé après que le système a exécuté son code de terminaison .

Parce que Kernel32.dll est garantie à être chargé dans l'espace d'adressage du processus lorsque la fonction point d'entrée est appelé , l'appel de fonctions dans Kernel32.dll ne se traduit pas dans la DLL utilisé avant son initialisation le code a été exécuté. Par conséquent, la fonction de point d'entrée peut appeler des fonctions dans Kernel32.dll qui ne chargent pas d'autres DLL.Par exemple, DllMain peut créer des objets de synchronisation tels que sections critiques et mutex, et utiliser TLS. Malheureusement, il n'y a pas une liste complète des fonctions de sécurité dans Kernel32.dll.

Windows 2000: Ne pas créer un nom objet de synchronisation dans DllMain parce que le système sera alors charger un DLL supplémentaire.

fonctions d'appel que autres que nécessitent les DLL Kernel32.dll peuvent entraîner des problèmes qui sont difficiles à diagnostiquer. Par exemple, appelant les fonctions utilisateur, Shell et COM peut provoquer des erreurs de violation d'accès, car certaines fonctions chargent d'autres composants système . Inversement, l'appel de telles fonctions pendant la terminaison peut entraîner des erreurs de violation d'accès car le composant correspondant peut déjà avoir été déchargé ou non initialisé.

Pour le travail en classe expérimentale, pensez à utiliser l'événement d'attachement de thread pour voir "ce qui se passe". Pour le travail de production, vous aurez besoin d'une approche complètement révisée qui ne fait aucun travail au sein de DllMain. Vous pouvez voir ci-dessus que l'histoire future inclura plus de bugs dans ce système d'exploitation.

+0

Avez-vous des suggestions quant à l'autre méthode que je peux utiliser qui ne concerne pas DllMain? – kaykun

+0

Je ne sais pas assez sur ce que vous essayez d'accomplir avec le message envoyé sur le tuyau nommé. Quel est votre plus grand objectif avec ceci? –

+0

L'application principale crée un fichier et définit un hook global GetMessage à l'aide de SetWindowsHookEx.Chaque processus (ou thread, je ne sais pas lequel) est injecté avec la fonction hook située dans une DLL. La fonction hook est supposée écrire dans le fichier créé dans l'application principale. Par conséquent j'ai besoin d'un moyen de passer le handle de fichier dans l'application à toutes les instances de la fonction de crochet. – kaykun

1

Il me semble que votre problème principal pourrait être le dernier paramètre de la fonction CreateNamedPipe (SECURITY_ATTRIBUTES) ou d'autres problèmes de sécurité (voir ci-dessous).

Je n'ai pas vraiment compris le type d'information que vous envisagez d'écrire dans logFile qui ne peut pas dépasser 32 octets (16 WCHAR). L'utilisation de sizeof() dans CreateNamedPipe serait aussi un peu mieux (pensez aussi aux systèmes d'exploitation 64 bits). Voulez-vous envoyer un handle à un fichier journal ouvert dans un processus à d'autres processus? Si vous faites cela, vous devez utiliser des fonctions telles que DuplicateHandle (voir http://msdn.microsoft.com/en-us/library/ms724251.aspx). En général, l'exemple de code pour la communication en ce qui concerne le tuyau nommé que vous avez posté, je trouve pas très bon. Je vous recommande tout d'abord de déboguer la communication canal nommé oufside de la DLL d'accrochage (avec au moins deux processus client distincts, qui s'exécutent mieux sous différentes références utilisateur et un processus serveur qui a créé le canal).

Il y a des restrictions de cause dans l'utilisation de Windows API dans DLL_THREAD_ATTACH, mais dans l'utilisation de Kernel32.dll dans votre cas me semble en toute sécurité.

Je ne sais pas quel genre de communication que vous souhaitez mettre en œuvre, mais en général l'utilisation du mode non bloqué comme l'utilisation de routines d'achèvement ou autre opération asynchrone (voir http://msdn.microsoft.com/en-us/library/aa365788.aspxhttp://msdn.microsoft.com/en-us/library/aa365788.aspx et http://msdn.microsoft.com/en-us/library/aa365601.aspx) à l'intérieur de DllMain pourrait être mieux. Une autre petite recommandation: vous devez utiliser DisableThreadLibraryCalls() dans le cas DLL_PROCESS_ATTACH et essayer de choisir une adresse de base raisonnable de la DLL (un commutateur de lien) qui réduira le déplacement de DLL pendant son chargement dans différents processus. Ceux-ci vont accélérer un peu votre programme et économiser de la mémoire.

Questions connexes