FAQ C++/CLI et VC++.Net
FAQ C++/CLI et VC++.NetConsultez toutes les FAQ
Nombre d'auteurs : 29, nombre de questions : 248, création le 22 février 2013
- Comment obtenir la version de mon application ?
- Comment obtenir la version du .NET Framework en cours ?
- Comment obtenir la version de l'OS en cours ?
- Comment obtenir le nom de l'utilisateur dont la session est en cours ?
- Comment obtenir le nom de la machine ?
- Comment obtenir la quantité de mémoire physique allouée à mon application ?
- Comment obtenir la ligne de commande de l'application ?
- Comment obtenir les variables d'environnement ?
- Comment générer des nombres aléatoires ?
- Comment lire et écrire des données sur la console ?
- Comment fonctionne le Garbage Collector ?
- Comment forcer la libération de la mémoire par le Garbage Collector ?
- Comment puis-je appeler une fonction présente dans une DLL win32 ?
- Comment mesurer précisément le temps d'exécution d'une partie de votre code?
- Comment remplacer un mot (insensible à la casse) par un autre grâce aux expressions régulières ?
- Comment utiliser une ressource dans mon exécutable ?
- Comment écrire dans le journal des évènements des services Windows ?
- Comment connaître le nombre d'écrans connectés à l'ordinateur ?
- Comment connaître le nombre de processeurs que possède la machine ?
- Comment tester si l'utilisateur de la session fait partie du groupe d'un domaine ?
- Comment déterminer le mode de démarrage de la machine ?
- Comment créer une exception personnalisée ?
- Comment obtenir la description d'une extension, comme dans l'explorateur de Windows ?
- Comment ajouter le numéro de version à mon exécutable/assembly ?
Pour obtenir la version de mon application, on utilise la classe System::Diagnostics::FileVersionInfo.
FileVersionInfo ^
ver =
FileVersionInfo::
GetVersionInfo(Environment::
GetCommandLineArgs()[0
]);
String ^
myVer =
ver->
FileMajorPart +
"."
+
ver->
FileMinorPart +
"."
+
ver->
FileBuildPart +
"."
+
ver->
FilePrivatePart;
Pour obtenir la version d'un fichier (EXE, DLL, OCX, etc..) quelconque, il suffit de passer le chemin du fichier à la fonction GetVersionInfo.
On utilise la propriété Version de la classe System::Environment.
Version ^
ver =
Environment::
Version;
Console::
WriteLine("Version Framework = {0}"
, ver);
On utilise la propriété OSVersion de la classe System::Environment.
OperatingSystem ^
os =
Environment::
OSVersion;
Console::
WriteLine("Version OS = {0}"
, os);
On utilise la propriété UserName de la classe Environment.
Console::
WriteLine("Nom utilisateur : {0}"
, Environment::
UserName);
On utilise la propriété MachineName de la classe System::Environment :
// Nom de la machine
String ^
MachineName =
Environment::
MachineName;
Console::
WriteLine("Nom de la machine = {0}"
, MachineName);
Lien : Classe Environment
On utilise la propriété WorkingSet de la classe Environment.
Console::
WriteLine("Mémoire allouée au process en cours : {0}"
, Environment::
WorkingSet);
On utilise la propriété CommandLine de la classe Environment pour avoir la ligne entière dans une chaîne de caractères.
Console::
WriteLine("La ligne de commande est : {0}"
, Environment::
CommandLine);
On utilise GetCommandLineArgs pour obtenir un tableau de chaînes de caractères contenant chaque argument.
// Arguments de ligne de commande
Console::
WriteLine("Arguments de ligne de commande"
);
cli::
array<
String ^>
^
args =
Environment::
GetCommandLineArgs();
for
(int
i =
0
; i<
args->
Length; i++
)
Console::
WriteLine("Args({0}) = {1}"
, i, args[i]);
Remarque : Ce même tableau est passé en paramètre de la fonction main :
int
main(array<
System::
String ^>
^
args)
On utilise la fonction GetEnvironmentVariables de la classe Environment.
IDictionary ^
env =
Environment::
GetEnvironmentVariables();
// Pour afficher une variable dont on connait le nom
Console::
WriteLine("USERNAME = {0}"
, env["USERNAME"
]);
// Pour lister toutes les variables
for
each (String ^
s in env->
Keys)
Console::
WriteLine("{0} = {1}"
, s, env[s]);
La classe System::Random nous permet de générer des nombres aléatoires.
Il s'agit en fait de nombres pseudo-aléatoires, car la séquence générée dépend de l'initialisation.
// Pour générer toujours la même séquence,
// on passe la même valeur au constructeur.
// Random rnd = new Random(100);
// Initialisation par défaut basée sur le temps.
// La séquence est différente à chaque fois.
Random ^
rnd =
gcnew Random();
// Génération de 15 nombres aléatoires compris entre 0 et 255
cli::
array<
unsigned
char
>
^
rndNumbers =
gcnew cli::
array<
unsigned
char
>
(15
);
rnd->
NextBytes(rndNumbers);
this
->
listBox1->
Items->
Clear();
for
(int
i=
0
; i<
15
; i++
)
// On peut aussi faire un modulo pour n'obtenir que
// des nombres entre 0 et 100 par exemples
if
(rndNumbers[i] >
100
)
listBox1->
Items->
Add(rndNumbers[i] %
100
);
else
listBox1->
Items->
Add(rndNumbers[i]);
// Pour générer des nombres aléatoire de type Integer
int
i =
rnd->
Next();
int
j =
rnd->
Next(500
, 1000
); // j sera compris entre 500 et 999 inclu
// Pour générer des nombre aléatoire de type Double
// d sera compris entre 0,0 et 1,0.
// Il suffit de combiner cet appel à celui de Next()
// pour avoir des doubles supérieurs à 1,0
double
d =
rnd->
NextDouble();
Il vous faut utiliser la classe System::Console et les méthodes qui la composent.
Console::
WriteLine ("Saisissez un texte: "
);
String ^
_Texte =
Console::
ReadLine ();
Console::
WriteLine ("Vous avez écrit : "
+
_Texte);
Console::Writeline écrit par défaut sur
- La console si il y en a une active
- La fenêtre de debug (onglet Sortie - Déboguer) si l'application ne possède pas de console. Une application WinForm par exemple.
Ce qui suit est extrait d'un échange sur le forum dotnet.
C'est très shématique mais cela résume bien comment le .NET Framework s'y prend pour gérer la mémoire
Le .NET Framework : Salut OS, j'ai des trucs à lancer, j'peux te prendre de la ram ?
L'OS : Hé Salut ! Je t'en pris, sers-toi !
Le .NET Framework : Sympa mec. J't'en prend 50Mo maintenant, j'ai besoin que de 15 Mo,
mais comme ça je te dérange pas si j'ai besoin de plus.
...
Le .NET Framework : Hé l'OS, t'es short niveau mémoire ?
L'OS : Non non, tout va bien.
Le .NET Framework : Bon, alors je garde mes 50 Mo encore un peu.
L'OS : Oki.
...
SQL Server : Bonjour M. l'OS, j'ai un gros besoin de mémoire...au moins 200 Mo.
L'OS : Ben sers-toi donc.
SQL Server : Ouais mais y a plus que 180Mo !
L'OS : Ah OK, attend 2 millisecondes stp...
L'OS : Hé Framework, tu peux me rendre un peu de RAM ?
Le .NET Framework : No problemo, j'te fais ça tout de suite...
Le .NET Framework : Garbage Collector, soit un amour et va rendre de la mémoire à l'OS.
Garbage Collector : J'y cours patron.
C'est clair non ?
Pour forcer le Garbage Collector à libérer la mémoire inutilisée par le .NET Framework, on peut appeller la méthode Collect de la classe GC.
System::GC::
Collect();
Par contre, pour des raisons qui justifieraient à elles seules un article, il n'est pas conseillé d'appeller GC::Collect() directement.
Par conséquent, ne le faites pas à moins d'être un expert du garbage collector.
Grâce à It Just Work, il est très facile d'appeler une fonction d'une API Win32. Il suffit d'inclure les entêtes nécessaires (comme windows.h) et de lier la librairie par pragma si ce n'est pas déjà le cas.
Le mode de compilation ne pourra pas être /clr:safe.
#include
<windows.h>
#pragma comment(lib,
"Kernel32.lib"
)
....
GetModuleFileName(0
, nom, MAX_PATH);
Tout d'abord, ajoutez en entête de votre classe :
using
namespace
System::
Diagnostics;
Ensuite, ajoutez ceci dans la partie de code qui vous intéresse :
//Instanciation d'un objet StopWatch
Stopwatch ^
monStopWatch =
gcnew Stopwatch();
// Déclenchement du "chronomètre"
monStopWatch->
Start();
// ///////////////////////////////
// Placez ici le code que vous voulez évaluer, cela peut être par exemple du code 'brut' ou
// alors l'appel d'un méthode...
// ///////////////////////////////
// Arrêt du "chronomètre"
monStopWatch->
Stop();
// Le temps écoulé peut être récupéré très facilement avec un membre de StopWatch,
// de la façon suivante. Le résultat est exprimé en millisecondes
long
tempsExecution;
tempsExecution =
safe_cast<
long
>
(monStopWatch->
ElapsedMilliseconds);
Tout d'abord, ajoutez en entête de votre classe :
using
namespace
System::Text::
RegularExpressions;
Un exemple vaut mieux qu'un long discours :
String ^
monTexte =
"Une astuce de dvp.com ! Une astuce de Dvp.Com !"
;
// Paramétrage de notre expression régulière :
// Ici on spécifie que l'on ne veut pas tenir compte dela casse du
// texte dans nos remplacements.
Regex ^
maRegEx =
gcnew Regex("
\\
bdvp.com
\\
b"
, RegexOptions::
IgnoreCase);
// Remplacement des occurences de "dvp.com" par "Developpez.com"
monTexte =
maRegEx->
Replace(monTexte, "Developpez.com"
);
Il faut dans un premier temps dire au linker d'intégrer un ou plusieurs fichiers de ressources :
- Click droit sur le projet --> Properties --> Linker --> Input --> Embed Managed Resource File
- Indiquer le path complet du fichier à intégrer (exemple : e:\abc.bmp).
Il faut ensuite utiliser le namespace Reflection::Assembly pour récupérer l'assembly et ensuite, invoquer la méthode qui récupère le flux du fichier en ressources. Exemple pour afficher une image dans un pictureBox.
pictureBox1->
Image =
Image::
FromStream(Reflection::Assembly::
GetExecutingAssembly()->
GetManifestResourceStream("abc.bmp"
));
Tout simplement en utilisant les fonctionnalités offertes par l'espace de noms System::Diagnostics. Notamment la classe EventLog et sa méthode WriteEntry qui dispose d'une dizaine de surcharges.
if
(!
EventLog::
SourceExists("MonApplication"
))
EventLog::
CreateEventSource("MonApplication"
, "MonJournal"
);
EventLog^
MonJournal =
gcnew EventLog();
MonJournal->
Source =
"MonApplication"
;
try
{
// instructions à exécuter (ex : division par zéro;
int
i =
0
;
Console::
WriteLine(2
/
i);
}
catch
(Exception^
ex)
{
// écrire l'erreur
MonJournal->
WriteEntry(ex->
Message,EventLogEntryType::
Error);
}
Lien : System.Diagnostics.EventLog
Lien : EventLog.WriteEntry
Lien : EventLogEntryType
On utilise la propriété MonitorCount de la classe SystemInformation :
// Nombre d'écrans connectés
int
MonitorCount =
SystemInformation::
MonitorCount;
Console::
WriteLine("Nombre d'écrans connectés à l'ordinateur = {0}"
, MonitorCount);
On n'oubliera pas de référencer l'assembly :
#using
"System.Windows.Forms.dll"
using
namespace
System::Windows::
Forms;
Lien : Classe SystemInformation
On utilise la propriété ProcessorCount de la classe System::Environment :
// Nombre de processeurs de la machine
int
countProc =
Environment::
ProcessorCount;
Console::
WriteLine("Nombre processeurs = {0}"
, countProc);
Lien : Classe Environment
On utilisera la méthode IsInRole de la classe WindowsPrincipal afin de déterminer si l'utilisateur courant fait bien partie ou pas d'un groupe x du domaine auquel il est rattaché :
// Vérification si un utilisateur appartient à un groupe de domaine donné
WindowsPrincipal ^
wp =
gcnew WindowsPrincipal(WindowsIdentity::
GetCurrent());
if
(wp->
IsInRole("Developpez
\\
Moderateur"
) ==
true
)
Console::
WriteLine("L'utilisateur fait bien partie du groupe Developpez
\\
Moderateur"
);
else
Console::
WriteLine("L'utilisateur ne fait pas partie du groupe Developpez
\\
Moderateur"
);
Lien : Classe WindowsPrincipal
On utilise la propriété BootMode de la classe SystemInformation. On obtient une des valeurs de l'énumération BootMode : FailSafe, FaileSafeWithNetwork ou Normal.
#using
"System.Windows.Forms.dll"
// ......
switch
(SystemInformation::
BootMode)
{
case
BootMode::
Normal:
Console::
WriteLine("Démarrage normal !"
);
break
;
case
BootMode::
FailSafe:
Console::
WriteLine("Attention, on est en mode sans echec !"
);
break
;
case
BootMode::
FailSafeWithNetwork:
Console::
WriteLine("Attention, on est en mode sans échec mais on a accès au réseau !"
);
break
;
}
Toute exception dérive de la classe Exception. Cependant, il est conseillé de faire dériver vos exceptions personnalisées de la classe ApplicationException. Un tiers développeur qui utilisera votre assembly pourra donc facilement reconnaître une exception du framework à une exception métier/applicative (dérivée de ApplicationExeption).
ref class
MonExceptionApplication : ApplicationException
{
public
:
MonExceptionApplication() : ApplicationException("Exception personnalisée"
)
{
}
MonExceptionApplication(String ^
p_message) : ApplicationException("Exception personnalisée : "
+
p_message)
{
}
}
;
int
main(array<
System::
String ^>
^
args)
{
try
{
throw
gcnew MonExceptionApplication("rien à faire"
);
}
catch
(MonExceptionApplication^
ex)
{
Console::
WriteLine(ex->
Message);
}
return
0
;
}
Tout est dans le titre ...
Il faut rajouter dans les usings
using
namespace
Microsoft::
Win32;
et voici le code ...
String ^
AGetExtentionDescription(String ^
ext)
{
String ^
description =
GetExtentionDescription(ext);
if
(description ==
nullptr
||
description ==
""
)
return
String::
Format("Fichier {0}"
, ext);
else
return
description;
}
String ^
GetExtentionDescription(String ^
ext)
{
if
(ext ==
nullptr
||
ext ==
""
||
ext ==
"."
)
return
nullptr
;
String ^
description =
""
;
try
{
RegistryKey ^
keyDesc =
Registry::
ClassesRoot->
OpenSubKey(ext, false
);
if
(keyDesc ==
nullptr
)
return
nullptr
;
else
{
try
{
if
(keyDesc->
GetValueKind(""
) !=
RegistryValueKind::
String)
return
nullptr
;
else
{
description =
(String^
)keyDesc->
GetValue(""
);
if
(description ==
nullptr
||
description ==
""
)
return
nullptr
;
RegistryKey ^
optionnalRedirection =
Registry::
ClassesRoot->
OpenSubKey(description, false
);
if
(optionnalRedirection ==
nullptr
)
return
description;
else
{
try
{
if
(optionnalRedirection->
GetValueKind(""
) !=
RegistryValueKind::
String)
return
description;
else
return
(String ^
)optionnalRedirection->
GetValue(""
);
}
finally
{
if
(optionnalRedirection !=
nullptr
)
optionnalRedirection->
Close();
}
}
}
}
finally
{
if
(keyDesc !=
nullptr
)
keyDesc->
Close();
}
}
}
catch
(Exception ^
)
{
return
nullptr
;
}
}
System::
Void Form1_Load(System::
Object^
sender, System::
EventArgs^
e)
{
MessageBox::
Show(AGetExtentionDescription(".exe"
));
MessageBox::
Show(AGetExtentionDescription(".jpg"
));
MessageBox::
Show(AGetExtentionDescription(".dat"
));
MessageBox::
Show(AGetExtentionDescription(".iso"
));
MessageBox::
Show(AGetExtentionDescription(".bmp"
));
}
Pour ajouter la version à son projet C++/CLI, on utilise une ressource de type version.
Explorateur de ressources -> bouton droit -> Add resource -> Version