FAQ Win32

FAQ Win32Consultez toutes les FAQ
Nombre d'auteurs : 11, nombre de questions : 72, dernière mise à jour : 16 juin 2021

- Comment lancer un processus ?
- Comment lancer un processus avec les droits d'un utilisateur (Exécuter en tant que ...) ?
- Comment obtenir un handle vers un processus connaissant son nom ?
- Comment obtenir un handle vers un processus connaissant son PID ?
- Comment ajuster les privilèges d'un processus ?
- Comment obtenir la liste de tous les processus en cours ?
- Comment obtenir la liste de tous les modules chargés par un processus ?
- Que se passe-t-il si je ferme le handle d'un processus ou d'un thread avant que celui-ci s'est terminé ?
- Comment obtenir l'ID du thread (ainsi que celui du processus ayant créé ce thread) ayant créé une fenêtre ?
- Comment obtenir le chemin complet d'un processus ?
- Comment changer le répertoire courant ?
L'API CreateProcess permet de créer un nouveau processus en spécifiant le nom ou le chemin de l'exécutable à lancer.
#include <windows.h>
int
main
(
)
{
STARTUPINFO si; /* Requis par CreateProcess */
PROCESS_INFORMATION pi; /* Requis par CreateProcess */
/* La structure si est utilisée en entrée donc elle doit être mpérativement initialisée */
ZeroMemory
(&
si, sizeof
(
si));
/* Pas la peine d'initialiser la structure pi car elle sera écrite et non lue */
if
(
CreateProcess
(
"
c:
\\
developpez
\\
test.exe
"
, /* Nom de l'exécutable */
NULL
, /* Arguments de la ligne de commande */
NULL
, /* Attributs de sécurité du nouveau processus (processus fils) */
NULL
, /* Attributs de sécurité du thread principal */
FALSE, /* Le processus fils héritera t-il des handles du processus père */
0
, /* Flags de création */
NULL
, /* Variables d'environnement */
NULL
, /* Répertoire courant */
&
si, /* Paramètres d'initialisation du processus */
&
pi /* Informations sur le processus */
))
{
WaitForSingleObject
(
pi.hProcess, INFINITE); /* Attendre la fin du processus */
CloseHandle
(
pi.hProcess); /* Fermer le handle vers le processus */
CloseHandle
(
pi.hThread); /* Fermer le handle vers le thread principal du processus */
}
return
0
;
}
L'API ShellExecute permet d'ouvrir un fichier (pas nécessairement un exe) ou un dossier exactement
comme si on avait double-cliqué sur ce fichier ou dossier depuis l'explorateur. D'autres actions, par exemple
imprimer (si le document est imprimable), sont également possibles.
#include <windows.h>
int
main
(
)
{
ShellExecute
(
NULL
, /* Fenêtre parent */
"
open
"
, /* Action à faire */
"
c:
\\
developpez
\\
test.exe
"
, /* Nom du fichier */
NULL
, /* Arguments de la ligne de commande */
NULL
, /* Répertoire courant */
SW_SHOWNORMAL /* Comment afficher la fenêtre */
);
return
0
;
}
ShellExecute exécute l'opération demandée et retourne immédiatement. Pour plus de contrôle, utilisez ShellExecuteEx.
Le plus simple est d'utiliser CreateProcessWithLogonW qui s'utilise comme CreateProcess sauf qu'il faut également spécifier le nom et le mot de passe de l'utilisateur qui désire créer le processus. Si elle est susceptible d'être appelée assez souvent dans le programme, alors il sera peut-être interessant de créer un handle vers un objet qui représente un utilisateur en utilisant la fonction LogonUser et d'appeler ensuite CreateProcessAsUser en fournissant ce handle chaque fois qu'on veut lancer un programme avec les droits de cet utilisateur. Il ne faut pas oublier de fermer le handle (CloseHandle) avant de quitter le programme.
Cela n'est pas possible car plusieurs instances de l'application peuvent exister en mémoire au même moment. La seule information qui permet d'identifier un processus est le PID (Process ID), qui est un numéro unique attribué par Windows à chaque processus créé.
A l'aide de la fonction OpenProcess. Toujours fermer le handle à l'aide de la fonction CloseHandle lorsqu'on en a plus besoin.
Pour faire certaines opérations, par exemple lire ou écrire dans la mémoire d'un autre processus, il faut avoir certains privilèges. La fonction AdjustTokenPrivileges premet d'ajuster les privilèges d'un processus. Voici un exemple (éteindre l'ordinateur) :
#include <windows.h>
void
PowerOff
(
)
{
HANDLE hToken; /* Handle vers les privilèges du processus */
TOKEN_PRIVILEGES token_privileges; /* Structure permettant de représenter un groupe de privilèges */
LUID luid; /* Locally Unique ID (ID Local d'un privilège) */
/* Il faut obtenir un handle vers les privilèges du processus qui nous intéresse. */
OpenProcessToken
(
NULL
, /* Handle du processus */
TOKEN_ALL_ACCESS, /* Ce que nous souhaitons faire avec le Token Handle */
&
hToken /* Sortie */
);
/* SE_SHUTDOWN_NAME ("SeShutdownPrivilege") est requis pour pouvoir éteindre l'ordinateur. */
/* Récupérons le LUID de ce privilège. */
LookupPrivilegeValue
(
NULL
, /* Sur quelle machine ? */
SE_SHUTDOWN_NAME, /* Nom du privilège dont le LUID nous intéresse */
&
luid /* Sortie */
);
/* Composons les nouveaux privilèges du processus. */
token_privileges.PrivilegeCount =
1
;
token_privileges.Privileges[0
].Luid =
luid;
token_privileges.Privileges[0
].Attributes =
SE_PRIVILEGE_ENABLED;
/* Appliquons. */
AdjustTokenPrivileges
(
hToken, /* Token Handle */
FALSE, /* Désactiver tous les privilèges ? (DAP) */
&
token_privileges, /* Nouvel état (ignoré si DAP vaut TRUE) */
0
, /* sizeof(old_state) */
NULL
, /* &old_state */
NULL
/* &retun_length */
);
/* C'est fait. Fermons le Token Handle. */
CloseHandle
(
hToken);
/* On peut maintenant éteindre l'ordinateur. */
ExitWindowsEx
(
EWX_POWEROFF, 0
);
}
Il existe actuellement deux APIs permettant de lister, entre autres, tous les processus en cours.
La première est la Toolhelp API que les développeurs de Windows 9x/Me ont ajouté en "complément" à l'API Win32.
La deuxième est la PSAPI (Process Status helper API) qui est la réponse (tardive) des développeurs de WINNT
à la Toolhelp API. Cette API, implémentée par le fichier (redistribuable) psapi.dll, est incluse dans Windows
2000 et plus récents. En addition, la Toolhelp API a également été ajoutée à ces systèmes.
Voici un programme qui affiche la liste de tous les processus en cours en utilisant la Toolhelp API :
#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>
int
main
(
)
{
HANDLE hSnapShot;
PROCESSENTRY32 pe;
/* Demander une vue de tous les processus en cours */
hSnapShot =
CreateToolhelp32Snapshot
(
TH32CS_SNAPPROCESS, 0
);
/* Afficher les résultats */
if
(
Process32First
(
hSnapShot, &
pe))
{
do
printf
(
"
%-20s (pid = %4lu)
\n
"
, pe.szExeFile, pe.th32ProcessID);
while
(
Process32Next
(
hSnapShot, &
pe));
}
CloseHandle
(
hSnapShot);
return
0
;
}
Avec la PSAPI, on appelle EnumProcesses pour avoir les PIDs des différents processus en cours, esnuite
OpenProcess sur chaque PID pour avoir un handle vers ce processus et enfin GetModuleBaseName ou
GetModuleFileNameEx pour avoir le nom du processus (nom seulement avec la première et le chemin complet
avec la seconde). Inclure psapi.h et ajouter psapi.lib dans les entrées du linkeur.
Toujours faisable avec la Toolhelp API ou la PSAPI. Le programme suivant utilise la Toolhelp API pour lister tous les modules chargés par lui-même.
#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>
int
main
(
)
{
HANDLE hSnapShot;
MODULEENTRY32 me;
hSnapShot =
CreateToolhelp32Snapshot
(
TH32CS_SNAPMODULE,GetCurrentProcessId
(
));
me.dwSize =
sizeof
(
me); /* Il faut initialiser ce champ avant d'appeler Module32First. */
if
(
Module32First
(
hSnapShot, &
me))
{
do
printf
(
"
%s
\n
"
, me.szModule);
while
(
Module32Next
(
hSnapShot, &
me));
}
CloseHandle
(
hSnapShot);
return
0
;
}
Remplacez me.szModule par me.szExePath pour avoir le chemin complet du module au lieu de son nom uniquement.
Avec la PSAPI, on appelle EnumProcessModules suivi de GetModuleBaseName ou
GetModuleFileNameEx sur chaque module.
Rien de spécial. Fermer un handle vers un processus ou un thread ne le tue pas mais libère tout simplement le handle. Pour terminer un processus (respectivemet un thread), il faut appeler TerminateProcess (respectivement TerminateThread).
La fonction GetModuleFileName permet de connaître le chemin complet du processus courant. Pour obtenir le chemin complet d'un autre processus, on pourra utiliser la fonction GetModuleFileNameEx de la PSAPI. Il n'y a pas d'équivalent direct de cette fonction dans la Toolhelp API donc, avec cette API, on est obligé d'énumérer les modules chargés par le processus jusqu'à trouver l'exe lui-même.
SetCurrentDirectory(<nouveau répertoire courant>).