FAQ C++/CLI et VC++.NetConsultez toutes les FAQ

Nombre d'auteurs : 29, nombre de questions : 248, création le 22 février 2013 

 
OuvrirSommaireIntéraction du C++/CLI avec le framework .NetDivers

Cette définition est tirée de MSDN

Le .NET Compact Framework est un environnement indépendant du matériel permettant d'exécuter des programmes sur divers périphériques informatiques à ressources limitées : assistants numériques personnels (PDA, Personal Data Assistant) tels que le Pocket PC, téléphones mobiles, décodeurs, périphériques informatiques automobiles et périphériques personnalisés intégrés au système d'exploitation Windows CE .NET.

Le .NET Compact Framework est un sous-ensemble de la bibliothèque de classes du .NET Framework, mais contient également des classes spécialement conçues à son intention. Il hérite la totalité de l'architecture de Common Language Runtime et d'exécution de code managé du .NET Framework.

Malheureusement, à l'heure actuelle, il n'est pas possible d'utiliser le C++/CLI pour utiliser le Compact Framework. Les mécanismes d'intéropérabilités (It Just Works) n'étant pas disponibles dans le CF, il a été jugé inutile de permettre l'utilisation du C++/CLI, mettant en avant plutôt l'utilisation de C#.
Mais il n'est pas totalement exclu que les équipes VC++ et CF se mettent à travailler ensemble dans l'avenir, même si cela parait peu probable.

Créé le 27 mars 2007  par Jérôme Lambert, nico-pyright(c)

Lien : It Just Works

Grâce à la redéfinition de l'opérateur - (mais aussi de +, ==, !=, >, >=, <, <=) avec la classe TimeSpan, il est possible de faire la différence entre 2 objets DateTime

Calculons le nombre de jours écoulés depuis la création de cette question :

 
Sélectionnez

	DateTime DateCourante = DateTime::Now;
	DateTime DateCreationquestion = DateTime(2007, 1, 3);
 
	TimeSpan ^Ts = DateCourante - DateCreationquestion;
	Console::WriteLine("Il s'est écoulé {0} jour(s) depuis la création de cette question !", Ts->Days);
      
Créé le 27 mars 2007  par Jérôme Lambert

Avec la version 2 du Framework, il est apparu la classe StopWatch qui permet de mesurer un intervalle de temps avec grande précision :

 
Sélectionnez

	Stopwatch ^maMesureDeTemps = gcnew Stopwatch();
	// Démarrage de l'intervalle de temps
	maMesureDeTemps->Start();
	// ...
	// Fin de l'intervalle de temps
	maMesureDeTemps->Stop();
	Console::WriteLine("L'exécution du code a pris : {0}", maMesureDeTemps->Elapsed.ToString());      
Créé le 27 mars 2007  par Jérôme Lambert

Lien : Voir l'article de Webman
Lien : System.Diagnostics.StopWatch
Lien : Voir aussi avec l'API Win32

Pour une application Windows, c'est la propriété Text de la la classe Form qui contient le texte de la barre de titre :

 
Sélectionnez

      this->Text = "Mon titre";
      

Pour ce qui est d'une application console, il faut passer par la classe Console avec la propriété Title :

 
Sélectionnez

      Console::Title = "Mon titre";
      
Créé le 27 mars 2007  par Jérôme Lambert

Le framework.net fourni tout une série de classe pour faciliter le cryptage / décryptage de données.
Voici un exemple de génération de clé à partir d'une chaîne, ainsi que le cryptage et décryptage de fichiers.
Notez les méthodes pour crypter/décrypter des chaînes, ainsi que l'utilisation de BinaryReader et BinaryWritter pour crypter/décrypter un fichier.

 
Sélectionnez
using namespace System;
using namespace System::Text;
using namespace System::Security::Cryptography;
using namespace System::IO;
 
 
void GenerateKey(String ^SecretPhrase, array<unsigned char> ^&Key, array<unsigned char> ^&IV)
{
	array<unsigned char> ^bytePhrase = Encoding::ASCII->GetBytes(SecretPhrase);
	SHA384Managed ^sha384 = gcnew SHA384Managed();
	sha384->ComputeHash(bytePhrase);
	array<unsigned char> ^result = sha384->Hash;
	for (int loop = 0; loop < 24; loop++)
		Key[loop] = result[loop];
	for (int loop = 24; loop < 40; loop++)
		IV[loop - 24] = result[loop];
}
 
array<unsigned char> ^ Crypter(array<unsigned char> ^encrypted, String ^keyPhrase)
{
    array<unsigned char> ^Key = gcnew array<unsigned char>(24);
    array<unsigned char> ^IV = gcnew array<unsigned char>(16);
 
    GenerateKey(keyPhrase, Key, IV);
 
    ASCIIEncoding ^textConverter = gcnew ASCIIEncoding();
    RijndaelManaged ^myRijndael = gcnew RijndaelManaged();
 
    myRijndael->Key = Key;
    myRijndael->IV = IV;
 
    ICryptoTransform ^encryptor = myRijndael->CreateEncryptor(Key, IV);
    MemoryStream ^msEncrypt = gcnew MemoryStream();
	CryptoStream ^csEncrypt = gcnew CryptoStream(msEncrypt, encryptor, CryptoStreamMode::Write);
 
    csEncrypt->Write(encrypted, 0, encrypted->Length);
    csEncrypt->FlushFinalBlock();
 
    encrypted = msEncrypt->ToArray();
	return encrypted;
}
 
array<unsigned char> ^ Decrypter(array<unsigned char> ^encrypted, String ^keyPhrase)
{
    array<unsigned char> ^Key = gcnew array<unsigned char>(24);
    array<unsigned char> ^IV = gcnew array<unsigned char>(16);
    GenerateKey(keyPhrase, Key, IV);
 
    array<unsigned char> ^fromEncrypt;
    RijndaelManaged ^myRijndael = gcnew RijndaelManaged();
    ASCIIEncoding ^textConverter = gcnew ASCIIEncoding();
 
    myRijndael->Key = Key;
    myRijndael->IV = IV;
 
    ICryptoTransform ^decryptor = myRijndael->CreateDecryptor(Key, IV);
    MemoryStream ^msDecrypt = gcnew MemoryStream(encrypted);
	CryptoStream ^csDecrypt = gcnew CryptoStream(msDecrypt, decryptor, CryptoStreamMode::Read);
    fromEncrypt = gcnew array<unsigned char>(encrypted->Length);
 
    csDecrypt->Read(fromEncrypt, 0, fromEncrypt->Length);
 
	return fromEncrypt;
}
 
String ^ Crypter(String ^original, String ^keyPhrase)
{
    array<unsigned char> ^Key = gcnew array<unsigned char>(24);
    array<unsigned char> ^IV = gcnew array<unsigned char>(16);
 
    GenerateKey(keyPhrase, Key, IV);
 
    ASCIIEncoding ^textConverter = gcnew ASCIIEncoding();
    RijndaelManaged ^myRijndael = gcnew RijndaelManaged();
    array<unsigned char> ^encrypted;
    array<unsigned char> ^toEncrypt;
 
    myRijndael->Key = Key;
    myRijndael->IV = IV;
 
    ICryptoTransform ^encryptor = myRijndael->CreateEncryptor(Key, IV);
    MemoryStream ^msEncrypt = gcnew MemoryStream();
	CryptoStream ^csEncrypt = gcnew CryptoStream(msEncrypt, encryptor, CryptoStreamMode::Write);
 
    toEncrypt = textConverter->GetBytes(original);
 
    csEncrypt->Write(toEncrypt, 0, toEncrypt->Length);
    csEncrypt->FlushFinalBlock();
 
    encrypted = msEncrypt->ToArray();
	return Convert::ToBase64String(encrypted);
}
 
String ^ Decrypter(String ^ encryptedString, String ^keyPhrase)
{
    array<unsigned char> ^Key = gcnew array<unsigned char>(24);
    array<unsigned char> ^IV = gcnew array<unsigned char>(16);
    GenerateKey(keyPhrase, Key, IV);
 
	array<unsigned char> ^encrypted = Convert::FromBase64String(encryptedString);
    array<unsigned char> ^fromEncrypt;
    RijndaelManaged ^myRijndael = gcnew RijndaelManaged();
    ASCIIEncoding ^textConverter = gcnew ASCIIEncoding();
 
    myRijndael->Key = Key;
    myRijndael->IV = IV;
 
    ICryptoTransform ^decryptor = myRijndael->CreateDecryptor(Key, IV);
    MemoryStream ^msDecrypt = gcnew MemoryStream(encrypted);
	CryptoStream ^csDecrypt = gcnew CryptoStream(msDecrypt, decryptor, CryptoStreamMode::Read);
    fromEncrypt = gcnew array<unsigned char>(encrypted->Length);
 
    csDecrypt->Read(fromEncrypt, 0, fromEncrypt->Length);
 
    return textConverter->GetString(fromEncrypt);
}
 
int main(array<System::String ^> ^args)
{
	FileStream ^fs = gcnew FileStream("c:\\test.zip", FileMode::Open);
	BinaryReader ^br = gcnew BinaryReader(fs);
	FileStream ^fsw = gcnew FileStream("c:\\test.cry", FileMode::CreateNew);
	BinaryWriter ^bw = gcnew BinaryWriter(fsw);
	try
	{
		bw->Write(Crypter(br->ReadBytes((int)fs->Length), "code secret"));
	}
	catch (Exception^)
	{
	}
	finally
	{
		br->Close();
		fs->Close();
		bw->Close();
		fsw->Close();
	}
	fs = gcnew FileStream("c:\\test.cry", FileMode::Open);
	br = gcnew BinaryReader(fs);
	fsw = gcnew FileStream("c:\\test2.zip", FileMode::CreateNew);
	bw = gcnew BinaryWriter(fsw);
	try
	{
		bw->Write(Decrypter(br->ReadBytes((int)fs->Length), "code secret"));
	}
	catch (Exception^)
	{
	}
	finally
	{
		br->Close();
		fs->Close();
		bw->Close();
		fsw->Close();
	}
    return 0;
}
Créé le 20 novembre 2007  par nico-pyright(c)

Les fichiers de configuration sont des fichiers XML qui contiennent la configuration de notre exécutable. Ils doivent se situer dans le même répertoire que l'exécutable.
Visual C++ ne gère pas automatiquement les fichiers de configuration comme app.config. Tant est si bien que quand on essaie de les utiliser, à chaque chargement de valeur, on obtient une chaine vide.
Ceci est expliqué par le fait que Visual C++ ne copie pas automatiquement le fichier app.config dans le répertoire de l'exécutable (debug par exemple).
Il faut donc le faire manuellement ou bien se servir des événements après génération.
Aller dans les propriétés du projet -> événement de génération -> événement après génération. Et modifier la ligne de commande par :

 
Sélectionnez

copy app.config "$(TargetPath).config"
	
Créé le 20 novembre 2007  par nico-pyright(c)

Tout d'abord, il faut créer le fichier de configuration app.config. Le plus simple ensuite est de travailler avec la section appSettings qui est gérée par le ConfigurationManager.
Dans le fichier, ajouter des clés et des valeurs comme ceci :

 
Sélectionnez
<configuration>
  <appSettings>
    <add key="nom" value="pyright"/>
    <add key="prenom" value="nico"/>
  </appSettings>
</configuration>

Ensuite, on peut y accéder ainsi :

 
Sélectionnez

String ^nom = Configuration::ConfigurationManager::AppSettings["nom"];
String ^prenom = Configuration::ConfigurationManager::AppSettings["prenom"];
Console::WriteLine("Je m'appelle {0} {1}", prenom, nom);
 
	

N'oubliez pas d'ajouter la référence à System.Configuration.

Créé le 20 novembre 2007  par nico-pyright(c)

Il peut être utile de pouvoir modifier le fichier de configuration depuis son application. Voici comment faire :

 
Sélectionnez
	String ^prenom = Configuration::ConfigurationSettings::AppSettings["prenom"];
	Console::WriteLine(prenom);
 
	Configuration::Configuration ^config = Configuration::ConfigurationManager::OpenExeConfiguration(Configuration::ConfigurationUserLevel::None);
	config->AppSettings->Settings->Remove("prenom");
	config->AppSettings->Settings->Add("prenom", "Nouveau prenom");
	config->Save(Configuration::ConfigurationSaveMode::Modified);
	Configuration::ConfigurationManager::RefreshSection("appSettings");
 
	prenom = Configuration::ConfigurationSettings::AppSettings["prenom"];
	Console::WriteLine(prenom);
Créé le 20 novembre 2007  par nico-pyright(c)

On connait les fichiers de configuration d'application (app.config) (voir Comment lire une valeur dans un fichier de configuration).
Il est très pratique d'y stocker les informations de configuration de l'application. Il peut être tentant d'y stocker par exemple des informations sensibles (un login/mot de passe, ou une chaine de connexion de base de données par exemple).
Cependant, ces informations doivent être distribuées avec l'exécutable et donc librement consultable sous format XML.
Comment faire pour utiliser ce principe de configuration tout en conservant une sécurité adéquate ?

Plusieurs solutions viennent à l'esprit, comme d'implémenter un système de cryptage, à l'aide d'une clé d'encryption, comme par exemple grâce à l'algo de rijndael. Ceci implique d'avoir une méthode qui encrypte et qui décrypte les informations.

On peut également utiliser un mécanisme prévu par le framework.net pour un système d'encryption automatique en RSA.
Pour ce faire, on va déplacer l'écriture de la configuration dans le fichier machine.config. En utilisant toujours appsettings, ouvrez le fichier machine.config et si la section n'existe pas, créez la ainsi :

 
Sélectionnez
<appSettings> 
  <add key="login" value="nico"/> 
  <add key="pwd" value="abcd"/> 
</appSettings>

Pour lire ces informations, on peut utiliser ce bout de code :

 
Sélectionnez
	
  AppSettingsSection ^section = ConfigurationManager::OpenMachineConfiguration()->AppSettings; 
  String ^login = ""; 
  String ^pwd = ""; 
  if (section->Settings["login"] != nullptr) 
    login = section->Settings["login"]->Value; 
  if (section->Settings["pwd"] != nullptr) 
    pwd = section->Settings["pwd"]->Value; 
  Console::WriteLine("Login : {0} - Mot de passe : {1}", login, pwd);

La méthode statique OpenMachineConfiguration nous permet de lire dans le machine.config.
Lancez ensuite la commande :

 
Sélectionnez

aspnet_regiis.exe -pe "appSettings" -pkm

On se retrouve avec un fichier machine.config, dont la section appSettings ressemble désormais à ça :

 
Sélectionnez
<appSettings configProtectionProvider="RsaProtectedConfigurationProvider"> 
  <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" 
  xmlns="http://www.w3.org/2001/04/xmlenc#"> 
  <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" /> 
  <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> 
  <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#"> 
  <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" /> 
  <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> 
  <KeyName>Rsa Key</KeyName> 
  </KeyInfo> 
  <CipherData> 
  <CipherValue>mCMSEOwI/sofISqaMxpaRM53IsBizjlBfsSzDAkzrGihm41P6R072
	FdkTkurkKBmyMjsXAI5oXlwYno7Ob8jws5i75yOjYWcy6y+uqEDTwfgIFt4kguVpEPbMlo6iR3dC0ipwmk0Eoz/TenDnSCt/e+cmO2FEQXfqYulNRq9bDA=</CipherValue> 
  </CipherData> 
  </EncryptedKey> 
  </KeyInfo> 
  <CipherData> 
  <CipherValue>TE6AddoMEjIwcAPi/mF0BBZHXfN2DZbaXzqK3SajSlv++HvGGdB
	ohgRPCboO69d5PLxPo3NjgMB5rEzqiGL49CTeapUtfNAzffa1owXzAjzQJnH/2WP3nrRci8qLhzOUYU3urGokAbN1zwiGY2adkA==</CipherValue> 
  </CipherData> 
  </EncryptedData> 
  </appSettings>

qui est tout de suite moins compréhensible.
Et ce qui est très pratique, c'est que sans aucune modification de code, mon application va être capable de déchiffrer cette section, et retrouver mon mot de passe par exemple.
Relancez l'application, et le tour est joué.

Créé le 20 novembre 2007  par nico-pyright(c)
 
Sélectionnez
static String ^RemplaceCaracteresAccentues(String ^input)
{
	array<unsigned char>^ objBytes = System::Text::Encoding::GetEncoding(1251)->GetBytes(input);
	return System::Text::Encoding::ASCII->GetString(objBytes);
}
 
int main()
{
	Console::Write("Entrez votre chaîne de carcatères : ");
	String ^strResultat = RemplaceCaracteresAccentues(Console::ReadLine());
	Console::WriteLine("Résultat : " + strResultat);
	return 0;
}
Créé le 9 octobre 2008  par Jérôme Lambert, nico-pyright(c)
  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2006-2007 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.