Ordonnancement des BSTR de C ++ à C # avec COM Interop

J’ai un serveur COM en dehors du processus écrit en C ++, appelé par un code client C #. Une méthode sur l’une des interfaces du serveur renvoie un gros BSTR au client, ce qui, selon moi, est à l’origine d’une fuite de mémoire. Le code fonctionne, mais je cherche de l’aide pour organiser les BSTR.

En simplifiant un peu, la méthode IDL pour le serveur est

HRESULT ProcessRequest([in] BSTR request, [out] BSTR* pResponse); 

et l’implémentation ressemble à:

 HRESULT MyClass::ProcessRequest(BSTR request, BSTR* pResponse) { USES_CONVERSION; char* pszRequest = OLE2A(request); char* pszResponse = BuildResponse(pszRequest); delete pszRequest; *pResponse = A2BSTR(pszResponse); delete pszResponse; return S_OK; } 

A2BSTR alloue en interne le BSTR à l’aide de SysAllocSsortingngLen ().

Dans le client C #, je fais simplement ce qui suit:

 ssortingng request = "something"; ssortingng response = ""; myserver.ProcessRequest(request, out response); DoSomething(response); 

Cela fonctionne car les chaînes de requête sont envoyées au serveur COM et les chaînes de réponse correctes sont renvoyées au client C #. Mais chaque aller-retour vers le serveur perd de la mémoire dans le processus du serveur . Le support de détection de fuite crt ne montre aucune fuite significative sur le tas de crt, donc je soupçonne que la fuite a été atsortingbuée à IMalloc.

Est-ce que je fais quelque chose de mal ici? J’ai trouvé de vagues commentaires selon lesquels “tous les parameters de sortie doivent être atsortingbués avec CoTaskMemAlloc, sinon le marshaller d’interopérabilité ne les libérera pas”, mais aucun détail.

Andy

anelson a très bien couvert la question, mais je voulais append quelques points;

  • CoTaskMemAlloc n’est pas le seul allocateur convivial pour COM: les BSTR sont reconnus par le marshaller par défaut et seront libérés / réaffectés à l’aide de SysAllocSsortingng & friends.

  • En évitant USES_CONVERSION (à cause des risques de débordement de stack – voir la réponse de anelson), votre code complet devrait ressembler à quelque chose comme ceci [1]

(notez que A2BSTR est sûr à utiliser car il appelle SysAllocSsortingng après la conversion et n’utilise pas l’allocation de stack dynamic. De plus, utilisez array-delete (delete []) car BuildResponse alloue probablement un tableau de caractères)

  • L’allocateur BSTR a un cache qui peut donner l’impression qu’il y a une fuite de mémoire. Consultez http://support.microsoft.com/kb/139071 pour plus de détails ou Google pour OANOCACHE. Vous pouvez essayer de désactiver le cache et voir si la «fuite» disparaît.

[1]

 HRESULT MyClass::ProcessRequest(BSTR request, BSTR* pResponse) { char* pszResponse = BuildResponse(CW2A(request)); *pResponse = A2BSTR(pszResponse); delete[] pszResponse; return S_OK; } 

Je ne vois pas de problème évident avec votre code. Vous suggérons de modifier la méthode ProcessRequest pour exclure l’interopérabilité COM en tant que source de la fuite:

 HRESULT MyClass::ProcessRequest(BSTR request, BSTR* pResponse) { *psResponse = ::SysAllocSsortingngLen(L"[suitably long ssortingng here]"); return S_OK; } 

Je soupçonne que cela ne coulera pas, auquel cas vous avez réduit la fuite à votre code.

Je voudrais également noter que OLE2A alloue de la mémoire sur la stack. Par conséquent, non seulement vous ne devez pas supprimer pszRequest, mais vous ne devez pas utiliser OLE2A du tout, en raison du risque de débordement de la stack. Voir cet article pour des alternatives plus sûres.

Je vous suggèrerais également de remplacer A2BSTR par :: SysAllocSsortingng (CA2W (pszResponse))

Je suppose que vous devez détruire la request avec ::SysFreeSsortingng() . Cette mémoire est allouée côté serveur.

En outre, OLE2A peut allouer de la mémoire en raison de la conversion (regardez). Vous ne le libérez pas aussi.