OVH Cloud OVH Cloud

COM SafeArray

5 réponses
Avatar
Boblemar
Bonjour,

Je suis en train de réaliser un Wrapper en c# pour simplifier
l'utilisation d'un composant COM.
Tout se passait plutôt (en presque...) bien jusqu'à ce que je veuille
utiliser une méthode dont l'un des paramètres est VARIANT * Values. Dans
la documentation, il est écrit que Values pointe vers un SAFEARRAY de
string.
J'ai trouvé sur Internet que le type correspondant à VARIANT était
object en C#.

J'ai donc essayé un truc du style :

string[] tsString = new string[2]
tsString[0] = "toto";
tsString[1] = "titi";

object objMonTable = (object)tsString;

objMonCOMObject.MaFonction(ref(objMonTable));

Et là, j'obtiens une exception COM : Le type ne correspond pas.
(Exception de HRESULT : 0x80020005 (DISP_E_TYPEMISMATCH))

Est-ce que quelqu'un aurait une idée ?

Bob

5 réponses

Avatar
Paul Bacelar
"Boblemar" wrote in message
news:Ox7b%
Bonjour,

Je suis en train de réaliser un Wrapper en c# pour simplifier
l'utilisation d'un composant COM.
Tout se passait plutôt (en presque...) bien jusqu'à ce que je veuille
utiliser une méthode dont l'un des paramètres est VARIANT * Values. Dans
la documentation, il est écrit que Values pointe vers un SAFEARRAY de
string.
J'ai trouvé sur Internet que le type correspondant à VARIANT était object
en C#.

J'ai donc essayé un truc du style :

string[] tsString = new string[2]
tsString[0] = "toto";
tsString[1] = "titi";

object objMonTable = (object)tsString;

objMonCOMObject.MaFonction(ref(objMonTable));

Et là, j'obtiens une exception COM : Le type ne correspond pas. (Exception
de HRESULT : 0x80020005 (DISP_E_TYPEMISMATCH))

Est-ce que quelqu'un aurait une idée ?

Bob



C'est légèrement plus compliqué ;-)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpcondefaultmarshalingforarrays.asp
--
Paul Bacelar
MVP VC++
Avatar
Boblemar
Paul Bacelar a écrit :
"Boblemar" wrote in message
news:Ox7b%
Bonjour,

Je suis en train de réaliser un Wrapper en c# pour simplifier
l'utilisation d'un composant COM.
Tout se passait plutôt (en presque...) bien jusqu'à ce que je veuille
utiliser une méthode dont l'un des paramètres est VARIANT * Values. Dans
la documentation, il est écrit que Values pointe vers un SAFEARRAY de
string.
J'ai trouvé sur Internet que le type correspondant à VARIANT était object
en C#.

J'ai donc essayé un truc du style :

string[] tsString = new string[2]
tsString[0] = "toto";
tsString[1] = "titi";

object objMonTable = (object)tsString;

objMonCOMObject.MaFonction(ref(objMonTable));

Et là, j'obtiens une exception COM : Le type ne correspond pas. (Exception
de HRESULT : 0x80020005 (DISP_E_TYPEMISMATCH))

Est-ce que quelqu'un aurait une idée ?

Bob



C'est légèrement plus compliqué ;-)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpcondefaultmarshalingforarrays.asp



Merci !

C'est effectivement bien plus compliqué : Je ne comprends absolument
rien. L'article en question expose des signatures de méthodes... mais
j'avous ne pas savoir quoi en faire : Dois-je créer un objet dont le
contructeur est la signature en question ?
Avatar
Paul Bacelar
"Boblemar" wrote in message
news:
Paul Bacelar a écrit :
"Boblemar" wrote in message
news:Ox7b%
Bonjour,

Je suis en train de réaliser un Wrapper en c# pour simplifier
l'utilisation d'un composant COM.
Tout se passait plutôt (en presque...) bien jusqu'à ce que je veuille
utiliser une méthode dont l'un des paramètres est VARIANT * Values. Dans
la documentation, il est écrit que Values pointe vers un SAFEARRAY de
string.
J'ai trouvé sur Internet que le type correspondant à VARIANT était
object en C#.

J'ai donc essayé un truc du style :

string[] tsString = new string[2]
tsString[0] = "toto";
tsString[1] = "titi";

object objMonTable = (object)tsString;

objMonCOMObject.MaFonction(ref(objMonTable));

Et là, j'obtiens une exception COM : Le type ne correspond pas.
(Exception de HRESULT : 0x80020005 (DISP_E_TYPEMISMATCH))

Est-ce que quelqu'un aurait une idée ?

Bob



C'est légèrement plus compliqué ;-)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpcondefaultmarshalingforarrays.asp



Merci !

C'est effectivement bien plus compliqué : Je ne comprends absolument rien.
L'article en question expose des signatures de méthodes... mais j'avous ne
pas savoir quoi en faire : Dois-je créer un objet dont le contructeur est
la signature en question ?



C'est bizarre, Je ne vois pas ma réponse du 14/02, je la reposte, au cas où.


<ARTICLE>
<COM>
HRESULT New3([in, out] SAFEARRAY( BSTR ) *ar);
</COM>
<.NET>
void New3([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_BSTR)]
ref String[] ar);
</.NET>
</ARTICLE>

donc

<code d'appel>
string[] tsString = new string[2];
tsString[0] = "toto";
tsString[1] = "titi";
objMonCOMObject.MaFonction(ref tsString);
</code d'appel>

<Dans le code du proxy généré par tlbimpl.exe>
... objMonCOMObject(..., [MarshalAs(UnmanagedType.SafeArray,
SafeArraySubType=VT_BSTR)] ref String[] ar ,...)
</Dans le code du proxy généré par tlbimpl.exe>

PS: il est très probable que tlbimpl.exe n'ait pas eut assez d'infos pour
générer correctement le proxy

--
Paul Bacelar
MVP VC++
Avatar
Herve Chapalain
Voici un exemple complet qui marche. Si malgrés ca, cela ne marche toujours
pas dans ton cas, peux-tu partager ton objet COM?
Merci,
-herve

private void button1_Click(object sender, System.EventArgs e)
{
string [] arString = new string[3];
arString[0] = "hello";
arString[1] = "world";
arString[2] = "this is a test";
object objarray = (object)arString;

safear.CMyObjClass obj = new safear.CMyObjClass();
obj.DoSomething(ref objarray);
Marshal.ReleaseComObject(obj);
obj = null;
}


STDMETHODIMP CMyObj::DoSomething(VARIANT* vArray)
{
if (vArray == NULL)
return E_INVALIDARG;

SAFEARRAY* psa = NULL;
psa = V_ARRAY(vArray);
if (SafeArrayGetDim(psa) != 1)
return E_INVALIDARG;

HRESULT hr = E_FAIL;
LONG cElements, lLBound, lUBound;
hr = SafeArrayGetLBound(psa, 1, &lLBound);
if (FAILED(hr))
return E_INVALIDARG;

hr = SafeArrayGetUBound(psa, 1, &lUBound);
if (FAILED(hr))
return E_INVALIDARG;

BSTR HUGEP *pbstr;
hr = SafeArrayAccessData(psa, (void HUGEP* FAR*)&pbstr);

cElements = lUBound-lLBound+1;
for (int i = 0; i < cElements; i++)
{
if (pbstr[i]!=NULL)
MessageBox(NULL, pbstr[i], L"DoSomething", MB_SETFOREGROUND);
}

hr = SafeArrayUnaccessData(psa);
if (FAILED(hr))
return hr;

return S_OK;
}
Avatar
Boblemar
Je te remercie de t'intéresser à mon problème.
Je ne vois pas vraiment la différence entre ton exemple et celui que
j'ai donné dans mon premier message (mis à part la syntaxe de ref())...
J'ai testé... mais sans succès.
Je ne peux malheureusement pas te transmettre l'objet COM qui pose
problème : il s'agit du programme d'accès client à IBM Content Manager
OnDemand... pour le faire fonctionner, il est nécessaire d'installer un
serveur Content Manager OnDemand.

Merci encore


Herve Chapalain a écrit :
Voici un exemple complet qui marche. Si malgrés ca, cela ne marche toujours
pas dans ton cas, peux-tu partager ton objet COM?
Merci,
-herve

private void button1_Click(object sender, System.EventArgs e)
{
string [] arString = new string[3];
arString[0] = "hello";
arString[1] = "world";
arString[2] = "this is a test";
object objarray = (object)arString;

safear.CMyObjClass obj = new safear.CMyObjClass();
obj.DoSomething(ref objarray);
Marshal.ReleaseComObject(obj);
obj = null;
}


STDMETHODIMP CMyObj::DoSomething(VARIANT* vArray)
{
if (vArray == NULL)
return E_INVALIDARG;

SAFEARRAY* psa = NULL;
psa = V_ARRAY(vArray);
if (SafeArrayGetDim(psa) != 1)
return E_INVALIDARG;

HRESULT hr = E_FAIL;
LONG cElements, lLBound, lUBound;
hr = SafeArrayGetLBound(psa, 1, &lLBound);
if (FAILED(hr))
return E_INVALIDARG;

hr = SafeArrayGetUBound(psa, 1, &lUBound);
if (FAILED(hr))
return E_INVALIDARG;

BSTR HUGEP *pbstr;
hr = SafeArrayAccessData(psa, (void HUGEP* FAR*)&pbstr);

cElements = lUBound-lLBound+1;
for (int i = 0; i < cElements; i++)
{
if (pbstr[i]!=NULL)
MessageBox(NULL, pbstr[i], L"DoSomething", MB_SETFOREGROUND);
}

hr = SafeArrayUnaccessData(psa);
if (FAILED(hr))
return hr;

return S_OK;
}