juin
2007
Si vous êtes allé au bout du précédent billet, je vous félicite. Je rappelle que le but est de pouvoir utiliser un objet .net depuis notre exe natif pur et de passer des paramètres à son constructeur via un wrapper CLI.
Quand je re-regarde le code du billet, il me fait peur Tout ce code pour finalement si peu de choses…
N’y aurait-il pas moyen de faire plus simple ?
Forcément, si j’écris ca, c’est qu’il doit y avoir un moyen…
La solution est d’utiliser la capacité de visual studio à incorporer les tlb grâce à #import et à le convertir en classes C++.
Nous transformons notre précédente classe managée qui wrappe de manière simpliste le StreamReader pour faire en sorte que la classe implémente une interface :
using namespace System::IO;
namespace MonStreamReader
{
public interface class IClassWrap
{
void SetFile(String ^fileName);
bool Create();
String^ ReadLine();
};
public ref class ClassWrap : IClassWrap
{
private:
String ^_fileName;
StreamReader ^sr;
protected:
!ClassWrap()
{
if (sr)
sr->Close();
}
public:
ClassWrap() {}
~ClassWrap()
{
this->!ClassWrap();
}
virtual void SetFile(String ^fileName)
{
_fileName = fileName;
}
virtual bool Create()
{
if (!String::IsNullOrEmpty(_fileName))
{
try
{
sr = gcnew StreamReader(_fileName);
return true;
}
catch (Exception ^)
{
sr = nullptr;
return false;
}
}
return false;
}
virtual String^ ReadLine()
{
if (sr)
return sr->ReadLine();
return nullptr;
} };
}
On génère le tlb, et on l’importe dans notre programme natif. Visual C++ va générer des classes et notamment une qui nous interesse IClassWrapPtr. C’est un smart pointer qui permet d’accèder à l’objet COM.
Il ne reste plus qu’à utiliser ce smart pointer pour appeler directement les méthodes de notre classe. Notez que les fonctions ont été relookées à la mode COM. On récupère un HRESULT et le retour de fonction se fait par un paramètre en sortie [out].
#include <iostream>
#import "..\debug\MonStreamReader.tlb" raw_interfaces_only
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
MonStreamReader::IClassWrapPtr pClass(__uuidof(MonStreamReader::ClassWrap));
CComBSTR filePath = "c:\\test.txt";
if (SUCCEEDED(pClass->SetFile(filePath)))
{
unsigned char resultBool;
if (SUCCEEDED(pClass->Create(&resultBool)))
{
if (resultBool)
{
CComBSTR line;
if (SUCCEEDED(pClass->ReadLine(&line)))
{
while (line)
{
_bstr_t line_(line);
std::cout << line_ << std::endl;
if (FAILED(pClass->ReadLine(&line)))
break;
}
}
}
}
}
return 0;
}
C’est quand même plus digeste !!
Notez l’utilisation de CComBstr pour passer des chaines qui seront marshalées en String^.net. Par contre, mon retour booleen donne un unsigned char.
Pour l’affichage, j’utilise également la classe _bstr_t qui dispose d’une surcharge de char *.
Vous pouvez télécharger le projet exemple.
1 Commentaire + Ajouter un commentaire
Commentaires récents
- [Tests] Arrange Act Assert, une traduction ? dans
- [UnitTest][C#] Tester une méthode privée dans
- Récupérer une valeur d’un contrôle depuis une autre Form / inclusions croisées et déclaration anticipée dans
- Tutoriel : Utiliser la ListBox et l’Isolated Storage dans vos applications Windows Phone 7 avec Silverlight dans
- Tutoriel : Utiliser la ListBox et l’Isolated Storage dans vos applications Windows Phone 7 avec Silverlight dans
Archives
- janvier 2013
- avril 2012
- janvier 2012
- juin 2011
- janvier 2011
- décembre 2010
- novembre 2010
- septembre 2010
- juin 2010
- mars 2010
- février 2010
- janvier 2010
- décembre 2009
- novembre 2009
- octobre 2009
- septembre 2009
- août 2009
- juillet 2009
- mai 2009
- avril 2009
- mars 2009
- janvier 2009
- décembre 2008
- novembre 2008
- octobre 2008
- septembre 2008
- août 2008
- juillet 2008
- juin 2008
- mai 2008
- avril 2008
- mars 2008
- février 2008
- janvier 2008
- décembre 2007
- novembre 2007
- octobre 2007
- septembre 2007
- août 2007
- juillet 2007
- juin 2007
- mai 2007
n’oubliez pas d’exporter votre tlb avec la commande : RegAsm.exe MonStreamReader.dll /tlb:MonStreamReader.tlb