Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

COM : Interface "custom" et smart pointers

4 réponses
Avatar
Bruno FREDERIC
Bonjour à tous,

Je développe un objet COM et un client COM en Visual C++6 SP6. L'objet COM
est généré grâce au "ATL COM AppWizard" et expose une interface de type
"custom".

Dans le client, je souhaite utiliser les SmartPointers de VC pour obtenir un
pointeur sur cette interface. Ce qui pose problème.

Lorsque j'implémente l'interface COM "custom" au sein d'une DLL, cela marche
très bien. Mais lorsque j'implémente cette même interface au sein d'un EXE
ou d'un service, je récupère systématiquement un pointeur "pCust" égal à
NULL dans mon client COM (code du client COM ci-dessous).

En revanche, une interface de type "dual" ne semble pas poser de problème :
j'ai rajouté un deuxième objet implémentant une interface "dual" à mon
serveur COM et je récupère bien le pointeur "pDual" sur cette interface
"dual" dans mon client ; que cet objet COM soit implémenté au sein d'une
DLL, d'un EXE ou d'un service.

J'ai inclus ci-dessous les définitions IDL des deux interfaces que j'ai
utilisées pour tous mes tests (elles ne comportent aucune méthode).

Les résultats de ces tests me laissent perplexe : quelque chose du
fonctionnement de COM doit m'échapper. Pourquoi est-ce que mon client
récupère un pointeur NULL sur une interface "custom" implémentée au sein
d'un EXE ou d'un service ?




------- Client COM (Win32 Console Application) -------

#import "..\ServeurCOM\ServeurCOM.tlb"
using namespace SERVEURCOMLib;

int main(int argc, char* argv[])
{
CoInitialize(NULL);

try {
// Objet avec interface "Custom" :
IObjetCustomPtr pCust(__uuidof(ObjetCustom));
printf("pCust=0x%X\n", pCust);

// Objet avec interface "Dual" :
IObjetDualPtr pDual(__uuidof(ObjetDual));
printf("pDual=0x%X\n", pDual);
}
catch (_com_error e) {
printf("%s\n", e.ErrorMessage());
}

CoUninitialize();
return 0;
}



------- Définitions IDL de IObjetCustom et IObjetDual -------

[
object,
uuid(18F1C4CF-3693-430A-8170-9733F7528F52),

helpstring("IObjetCustom Interface"),
pointer_default(unique)
]
interface IObjetCustom : IUnknown
{
};
[
object,
uuid(564B7B43-EFBA-45D6-864F-4457540409DD),
dual,
helpstring("IObjetDual Interface"),
pointer_default(unique)
]
interface IObjetDual : IDispatch
{
};

4 réponses

Avatar
adebaene
"Bruno FREDERIC" wrote in message news:<4177f582$0$27129$...
Bonjour à tous,

Je développe un objet COM et un client COM en Visual C++6 SP6. L'objet COM
est généré grâce au "ATL COM AppWizard" et expose une interface de type
"custom".

Dans le client, je souhaite utiliser les SmartPointers de VC pour obtenir un
pointeur sur cette interface. Ce qui pose problème.

Lorsque j'implémente l'interface COM "custom" au sein d'une DLL, cela marche
très bien. Mais lorsque j'implémente cette même interface au sein d'un EXE
ou d'un service, je récupère systématiquement un pointeur "pCust" égal à
NULL dans mon client COM (code du client COM ci-dessous).

En revanche, une interface de type "dual" ne semble pas poser de problème :
j'ai rajouté un deuxième objet implémentant une interface "dual" à mon
serveur COM et je récupère bien le pointeur "pDual" sur cette interface
"dual" dans mon client ; que cet objet COM soit implémenté au sein d'une
DLL, d'un EXE ou d'un service.

J'ai inclus ci-dessous les définitions IDL des deux interfaces que j'ai
utilisées pour tous mes tests (elles ne comportent aucune méthode).

Les résultats de ces tests me laissent perplexe : quelque chose du
fonctionnement de COM doit m'échapper. Pourquoi est-ce que mon client
récupère un pointeur NULL sur une interface "custom" implémentée au sein
d'un EXE ou d'un service ?



Il manque la définition de la CoClass dans ton IDL : elle s'appelle
comment? C'est son uuid qu'il faut passer au constructeur du
com_ptr_t, pas l'uuid de l'interface.

Dans le doute, vérifies le tlh généré par #import.

Arnaud


------- Client COM (Win32 Console Application) -------

#import "..ServeurCOMServeurCOM.tlb"
using namespace SERVEURCOMLib;

int main(int argc, char* argv[])
{
CoInitialize(NULL);

try {
// Objet avec interface "Custom" :
IObjetCustomPtr pCust(__uuidof(ObjetCustom));
printf("pCust=0x%Xn", pCust);

// Objet avec interface "Dual" :
IObjetDualPtr pDual(__uuidof(ObjetDual));
printf("pDual=0x%Xn", pDual);
}
catch (_com_error e) {
printf("%sn", e.ErrorMessage());
}

CoUninitialize();
return 0;
}



------- Définitions IDL de IObjetCustom et IObjetDual -------

[
object,
uuid(18F1C4CF-3693-430A-8170-9733F7528F52),

helpstring("IObjetCustom Interface"),
pointer_default(unique)
]
interface IObjetCustom : IUnknown
{
};
[
object,
uuid(564B7B43-EFBA-45D6-864F-4457540409DD),
dual,
helpstring("IObjetDual Interface"),
pointer_default(unique)
]
interface IObjetDual : IDispatch
{
};


Avatar
Bruno FREDERIC
Arnaud Debaene wrote:
"Bruno FREDERIC" wrote in message
news:<4177f582$0$27129$...
Bonjour à tous,

Je développe un objet COM et un client COM en Visual C++6 SP6.
L'objet COM est généré grâce au "ATL COM AppWizard" et expose une
interface de type "custom".

(...)

Les résultats de ces tests me laissent perplexe : quelque chose du
fonctionnement de COM doit m'échapper. Pourquoi est-ce que mon client
récupère un pointeur NULL sur une interface "custom" implémentée au
sein d'un EXE ou d'un service ?



Il manque la définition de la CoClass dans ton IDL : elle s'appelle
comment? C'est son uuid qu'il faut passer au constructeur du
com_ptr_t, pas l'uuid de l'interface.

Dans le doute, vérifies le tlh généré par #import.




Effectivement, les CoClass n'ont été pas mises par l'AppWizard ATL dans le
fichier IDL. Elles se nomment : ObjetCustom et ObjetDual.

Toutefois, elles figurent bien dans le .tlh généré par le #import du client
COM (joint ci-dessous). Et je pense utiliser leur GUID dans le code du
client COM lors des instructions :
IObjetCustomPtr pCust(__uuidof(ObjetCustom));
et
IObjetDualPtr pDual(__uuidof(ObjetDual));





------- ServeurCOM.tlh -------

(...)

//
// Forward references and typedefs
//

struct /* coclass */ ObjetCustom;
struct /* coclass */ ObjetDual;

(...)

//
// Type library items
//


struct __declspec(uuid("a0bbbda8-813f-4f9a-9966-befa55004373"))
ObjetCustom;
// [ default ] interface IObjetCustom

struct __declspec(uuid("18f1c4cf-3693-430a-8170-9733f7528f52"))
IObjetCustom : IUnknown
{};

struct __declspec(uuid("6ea9a117-d352-4af6-a27e-8113acce7567"))
ObjetDual;
// [ default ] interface IObjetDual

struct __declspec(uuid("564b7b43-efba-45d6-864f-4457540409dd"))
IObjetDual : IDispatch
{};


(...)
Avatar
adebaene
"Bruno FREDERIC" wrote in message news:<41790207$0$31763$...


Effectivement, les CoClass n'ont été pas mises par l'AppWizard ATL dans le
fichier IDL. Elles se nomment : ObjetCustom et ObjetDual.

Toutefois, elles figurent bien dans le .tlh généré par le #import du client
COM (joint ci-dessous).


??? Si elles ne sont pas dans l'IDL, elles ne peuvent pas être dans la
typelibrary et donc encore moins dans le TLH?

Et je pense utiliser leur GUID dans le code du
client COM lors des instructions :
IObjetCustomPtr pCust(__uuidof(ObjetCustom));
et
IObjetDualPtr pDual(__uuidof(ObjetDual));


Effectivement çà à l'air correct... Qu'et ce que ca donne si tu
essaies d'instancier l'objet "à la main" avec CoCreateInstance?

Arnaud
Avatar
Bruno FREDERIC
Arnaud Debaene wrote:
"Bruno FREDERIC" wrote in message
news:<41790207$0$31763$...


Effectivement, les CoClass n'ont été pas mises par l'AppWizard ATL
dans le fichier IDL. Elles se nomment : ObjetCustom et ObjetDual.

Toutefois, elles figurent bien dans le .tlh généré par le #import du
client COM (joint ci-dessous).


??? Si elles ne sont pas dans l'IDL, elles ne peuvent pas être dans la
typelibrary et donc encore moins dans le TLH?



Rectificatif : les coclass ont bien été mises dans le fichier IDL par le
wizard ATL. J'ai du regarder trop rapidement la dernière fois. Tu avais
raison d'être étonné ;-)


Et je pense utiliser leur GUID dans le code du
client COM lors des instructions :
IObjetCustomPtr pCust(__uuidof(ObjetCustom));
et
IObjetDualPtr pDual(__uuidof(ObjetDual));


Effectivement çà à l'air correct... Qu'et ce que ca donne si tu
essaies d'instancier l'objet "à la main" avec CoCreateInstance?




Afin de mieux cerner le problème, j'ai utilisé les fonctions
::CoGetClassObject(), IClassFactory::CreateInstance() et
IUnknown::QueryInterface() pour accéder à mes interfaces (code source en fin
de message).

Le premier appel à IUnknown::QueryInterface() pour récupérer l'interface
IObjetDual ne pose aucun problème.

L'instruction suivante est la seule qui échoue :
hr = pObject->QueryInterface(__uuidof(IObjetCustom),
(void**) &pCust);
Elle retourne un code d'erreur 0x80004002 correspondant au message d'erreur
"Cette interface n'est pas prise en charge".


Avec le débugueur, j'ai remarqué que la création d'un smart pointer
IObjetCustomPtr, échoue à la même étape, l'instruction suivante de
_com_ptr_t<>::CreateInstance() (fichier ComIP.h) retourne le même code
d'erreur :
hr = pIUnknown->QueryInterface(GetIID(),
reinterpret_cast<void**>(&m_pInterface));






------- Client COM (Win32 Console Application) -------

#import "..ServeurCOMServeurCOM.tlb"
using namespace SERVEURCOMLib;

int main(int argc, char* argv[])
{
CoInitialize(NULL);

LPCLASSFACTORY pClassFactory;
HRESULT hr;
hr = ::CoGetClassObject(__uuidof(ObjetDual),
CLSCTX_LOCAL_SERVER,
NULL,
IID_IClassFactory,
(void **) &pClassFactory);
if (hr != NOERROR)
return 2;

LPUNKNOWN pObject;
hr = pClassFactory->CreateInstance(NULL,
IID_IUnknown,
(void**) &pObject);
if (hr != NOERROR)
return 3;


IObjetDual* pDual = NULL;
hr = pObject->QueryInterface(__uuidof(IObjetDual),
(void**) &pDual);
if (hr != NOERROR)
return 4;

IObjetCustom* pCust = NULL;
hr = pObject->QueryInterface(__uuidof(IObjetCustom),
(void**) &pCust);
if (hr != NOERROR)
return 5;


pClassFactory->Release();
pObject->Release();
if (pCust != NULL)
pCust->Release();
if (pDual != NULL)
pDual->Release();

CoUninitialize();
return 0;
}