juin
2007
Si la question est : « Peut-on passer des paramètres au constructeur d’un objet COM qui fait le wrapper d’une classe managée ? »
La réponse est non !
Alors, comment faire par exemple si je veux utiliser la classe System::IO::StreamReader (par exemple) depuis mon programme natif ?
Et bien, la solution est de décaler la construction dans une méthode en ayant préalablement passé les paramètres par méthode.
Et pour ce faire, il suffit d’encapsuler l’utilisation de la classe dans un wrapper qui respecte cette construction.
soit la classe ref suivante :
using namespace System::IO;
namespace assembly
{
public ref class WrapStreamReader
{
private:
String ^_filePath;
StreamReader ^sr;
protected:
!WrapStreamReader()
{
if (sr)
sr->Close();
}
public:
WrapStreamReader() {}
~WrapStreamReader()
{
this->!WrapStreamReader();
}
void SetFile(String ^filePath)
{
_filePath = filePath;
}
bool Create()
{
if (!String::IsNullOrEmpty(_filePath))
{
try
{
sr = gcnew StreamReader(_filePath);
return true;
}
catch (Exception ^)
{
sr = nullptr;
return false;
}
}
return false;
}
String^ ReadLine()
{
if (sr)
return sr->ReadLine();
return nullptr;
}
};
}
C’est un exemple tout simple qui encapsule la méthode ReadLine de StreamReader.
Une utilisation en C++/CLI pourrait être la suivante :
{
WrapStreamReader^w = gcnew WrapStreamReader();
w->SetFile("c:\\test.txt");
if (w->Create())
{
String ^s = w->ReadLine();
while (!String::IsNullOrEmpty(s))
{
Console::WriteLine(s);
s = w->ReadLine();
}
}
return 0;
}
C’est cet exemple que nous allons transformer en COM.
Le code pourrait être le suivant :
#include <iostream>
void BSTRtoASC (BSTR str, char * &strRet)
{
if ( str != NULL )
{
unsigned long length = WideCharToMultiByte (CP_ACP, 0, str, SysStringLen(str),
NULL, 0, NULL, NULL);
strRet = new char[length];
length = WideCharToMultiByte (CP_ACP, 0, str, SysStringLen(str),
reinterpret_cast <char *>(strRet), length, NULL, NULL);
strRet[length] = '\0';
}
}
int _tmain(int argc, _TCHAR* argv[])
{
DISPID dispid;
IDispatch *pDisp;
OLECHAR *methodSetFile = L"SetFile";
CLSID clsID;
VARIANT vntArgs[1], vntResult;
DISPPARAMS param;
param.cArgs = 1;
param.rgvarg = vntArgs;
param.cNamedArgs = 0;
param.rgdispidNamedArgs = NULL;
vntArgs[0].vt = VT_BSTR;
vntArgs[0].bstrVal = SysAllocString(L"c:\\test.txt");
CoInitialize(NULL);
if (SUCCEEDED(::CLSIDFromProgID(L"assembly.WrapStreamReader", &clsID)))
if (SUCCEEDED(CoCreateInstance(clsID, NULL, CLSCTX_ALL, IID_IDispatch, (void**)&pDisp)))
if (SUCCEEDED(pDisp->GetIDsOfNames(IID_NULL, &methodSetFile,1, GetUserDefaultLCID(), &dispid)))
if (SUCCEEDED(pDisp->Invoke(dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD, ¶m, NULL, NULL, NULL)))
{
OLECHAR *methodCreate = L"Create";
param.cArgs = 0;
param.rgvarg = NULL;
param.cNamedArgs = 0;
param.rgdispidNamedArgs = NULL;
vntResult.vt = VT_BOOL;
if (SUCCEEDED(pDisp->GetIDsOfNames(IID_NULL, &methodCreate,1, GetUserDefaultLCID(), &dispid)))
if (SUCCEEDED(pDisp->Invoke(dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD, ¶m, &vntResult, NULL, NULL)))
{
if (vntResult.boolVal != 0)
{
OLECHAR *methodReadLine = L"ReadLine";
vntResult.vt = VT_BSTR;
if (SUCCEEDED(pDisp->GetIDsOfNames(IID_NULL, &methodReadLine,1, GetUserDefaultLCID(), &dispid)))
if (SUCCEEDED(pDisp->Invoke(dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD, ¶m, &vntResult, NULL, NULL)))
{
char * retour;
BSTRtoASC(vntResult.bstrVal, retour);
while (strlen(retour) > 0 && vntResult.bstrVal)
{
std::cout << retour << std::endl;
if (FAILED(pDisp->Invoke(dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD, ¶m, &vntResult, NULL, NULL)))
break;
BSTRtoASC(vntResult.bstrVal, retour);
}
pDisp->Release();
}
}
}
}
CoUninitialize();
return 0;
}
Donc le principe est très simple, on appelle l’une après l’autre les méthodes SetFile, Create et ReadLine.
Je vous l’accorde, la syntaxe est un peu compliquée, et ca devient vite touffu.
Mais heureusement pour nous, il y a un moyen d’arriver à une syntaxe plus élégante grâce à visual studio.
C’est ce que nous verrons une prochaine fois.
A+
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