Oggi mi sono imbattuto in un problema nel mio codice in cui è stata provocata una violazione di accesso, AFAICT, eseguendo un mio oggetto COM su un IUnknown **. La funzione è stata passata in esecuzione senza problemi, ma quando si chiama una delle funzioni del mio oggetto, si eseguirà una funzione casuale e si corrompe lo stack, quindi morirà.Interfacce COM di trasmissione
codice indicativo (basta ignorare perché è fatto in questo modo - so che è male e so come risolvere il problema, ma questa è una questione del perché si possono verificare problemi come questo):
void MyClass2::func(IMyInterface* pMyObj)
{
CComPtr<IMyInterface2> pMyObj2;
HRESULT hRes = pMyObj->GetInternalObject((IUnknown**)&pMyObj2);
if (SUCCEEDED(hRes))
pMyObj2->Function(); // corrupt stack
}
void MyClass::GetInternalObject(IUnknown** lpUnknown)
{
pInternalObject->QueryInterface(IID_IMyInterface2, (void**)lpUnknown);
}
Ho sempre stato un po 'diffidente nell'usare cast di C/C++ su oggetti COM ma non ho mai incontrato (forse attraverso un comportamento indefinito) alcun problema fino ad ora.
ho avuto un rapido sguardo e da quello che posso dire colata a IUnknown è tecnicamente valida fino a quando non v'è alcuna interitance multipla nella catena di ereditarietà, tuttavia non è considerata best practice - io in realtà dovrebbe passare un IUnknown a MyClass::GetInternalObject(IUnknown** lpUnknown)
e quindi eseguire una query sul valore restituito per l'interfaccia desiderata.
La mia domanda è, ci sono regole su quando C/C++ calchi possono essere utilizzati su oggetti COM, ea parte l'ereditarietà multipla e le thunk regolatore che portano, come può colata oggetti COM causare sorprese come violazioni di accesso? Si prega di essere dettagliato.
Modifica: Sono tutti buoni esempi di come dovrebbe essere fatto correttamente, ma quello che speravo era una spiegazione tecnica del perché non dovresti lanciare oggetti COM (supponendo che ne esista uno) ad es. il cast restituirà pMyObj2-4 nella situazione x ma QueryInterface restituirà pMyObj2-8 a causa di y ... o sta lanciando oggetti COM semplicemente per una questione di cattiva pratica/stile?
TIA
Stai inseguendo il problema sbagliato. Questo tipo di problema è un risultato classico di un problema di versione, qualcuno non ha aggiornato l'IID dell'interfaccia dopo averne modificato la definizione. Quindi stai chiamando il metodo completo sbagliato o chiamandolo con gli argomenti sbagliati. Mettiti in contatto con l'autore di questo componente per risolvere questo problema. –
Di seguito sono riportate diverse risposte che dimostrano il modo corretto per eseguire questa operazione. Passa un indirizzo di interfaccia 'IUnknown' al tuo GetInternalObject() e interroga il risultato per l'interfaccia di cui hai bisogno. Spezzare il marshalling è uno dei tanti motivi per NON farlo in altro modo. Le regole della COM sono semplici. Si esegue una query per un'interfaccia da IID, si ottiene un puntatore a interfaccia per quello IID. Se è derivato da un'interfaccia di base (come IUnknown) puoi usare questi metodi. Se una funzione restituisce un indirizzo IUnknown per indirizzo, NON puoi fare ciò che il tuo codice sopra fa in modo sicuro. – WhozCraig
@Hans Non penso che sia un problema di versione - il problema che stavo avendo era piuttosto specifico e altrimenti avrei potuto usare le stesse interfacce COM senza problemi. – Sparkles