J'ai un contrôle ActiveX dans une page HTML IE7/8 incorporée qui a l'événement suivant [id(1)] HRESULT MessageReceived([in] BSTR id, [in] BSTR json)
. Sous Windows, l'événement est enregistré avec OCX.attachEvent("MessageReceived", onMessageReceivedFunc)
.IE attachEvent sur la balise object provoque une corruption de la mémoire
Le code suivant déclenche l'événement dans la page HTML.
HRESULT Fire_MessageReceived(BSTR id, BSTR json)
{
CComVariant varResult;
T* pT = static_cast<T*>(this);
int nConnectionIndex;
CComVariant* pvars = new CComVariant[2];
int nConnections = m_vec.GetSize();
for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
{
pT->Lock();
CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
pT->Unlock();
IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
if (pDispatch != NULL)
{
VariantClear(&varResult);
pvars[1] = id;
pvars[0] = json;
DISPPARAMS disp = { pvars, NULL, 2, 0 };
pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
}
}
delete[] pvars; // -> Memory Corruption here!
return varResult.scode;
}
Après avoir permis à gflags.exe avec vérification de l'application, le comportement étrange suivantes se produisent: Après Invoke() qui exécute la fonction de rappel JavaScript, le BSTR de pvars [1] est copié dans pvars [0] pour une raison inconnue !? Le delete [] de pvars provoque un double gratuit de la même chaîne puis qui se termine par une corruption de tas.
Est-ce que quelqu'un a une idée de ce qui se passe ici? Est-ce un bug d'IE ou y at-il un truc dans l'implémentation d'OCX qui me manque?
Si j'utilise la balise comme:
<script for="OCX" event="MessageReceived(id, json)" language="JavaScript" type="text/javascript">
window.onMessageReceivedFunc(windowId, json);
</script>
... l'étrange opération de copie ne se produit pas.
Le code suivant semble également être correct en raison du fait que l'appelant de Fire_MessageReceived() est responsable de la libération des BSTR.
HRESULT Fire_MessageReceived(BSTR srcWindowId, BSTR json)
{
CComVariant varResult;
T* pT = static_cast<T*>(this);
int nConnectionIndex;
VARIANT pvars[2];
int nConnections = m_vec.GetSize();
for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
{
pT->Lock();
CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
pT->Unlock();
IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
if (pDispatch != NULL)
{
VariantClear(&varResult);
pvars[1].vt = VT_BSTR;
pvars[1].bstrVal = srcWindowId;
pvars[0].vt = VT_BSTR;
pvars[0].bstrVal = json;
DISPPARAMS disp = { pvars, NULL, 2, 0 };
pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
}
}
delete[] pvars;
return varResult.scode;
}
Merci!
Merci pour vos commentaires approfondis! Le "delete [] pvars;" dans mon deuxième exemple de code était une erreur de copie. Quelle que soit l'implémentation que nous utilisons, la racine du problème est celle avant que la mémoire Invoke() indique: pvars [0] = "a"; pvars [1] = "b"; ... après que la mémoire Invoke() indique ... pvars [0] = "b"; pvars [1] = "b"; ... alors quelqu'un a copié les chaînes dans le tableau. Je suppose que IE le fait. Oui, nous pouvons éviter une corruption de mémoire avec votre code ou mon second code (sans delete [] pvars) en utilisant VARIANT au lieu de CComVariant *. Cependant, les chaînes sont toujours incorrectement copiées uniquement lors de l'utilisation de attachEvent(). – Lars
Il semble que toutes les erreurs proviennent du livre suivant: "Developer's Workshop to COM and ATL 3.0" par Andrew W. Troelsen. Au moins un exemple dans le livre ressemble exactement au code du starter de sujet (et a tous les isses mentionnés ci-dessus). – vond