2009-11-22 5 views
11

Ho una funzione COM che dovrebbe restituire un SafeArray tramite un parametro out LPSAFEARRAY*. La funzione crea SafeArray utilizzando la classe di modello CComSafeArray di ATL. mio ingenuo attuazione utilizza CComSafeArray<T>::Detach() al fine di spostare la proprietà dalla variabile locale al parametro di uscita:Come si restituisce un CComSafeArray locale su un parametro di uscita LPSAFEARRAY?

void foo(LPSAFEARRAY* psa) 
{ 
    CComSafeArray<VARIANT> ret; 
    ret.Add(CComVariant(42)); 
    *psa = ret.Detach(); 
} 

int main() 
{ 
    CComSafeArray<VARIANT> sa; 
    foo(sa.GetSafeArrayPtr()); 

    std::cout << sa[0].lVal << std::endl; 
} 

Il problema è che CComSafeArray::Detach() esegue un'operazione Unlock in modo che quando il nuovo proprietario del SafeArray (principale sa in questo caso) viene distrutto il blocco non è zero e Destroy non riesce a sbloccare SafeArray con E_UNEXPECTED (questo porta a una perdita di memoria poiché SafeArray non è deallocato).

Qual è il modo corretto per trasferire la proprietà tra CComSafeArrays attraverso un limite del metodo COM?


Edit: Dalla sola risposta finora sembra che l'errore sia sul lato client (main) e non dal lato server (foo), ma trovo difficile credere che CComSafeArray wasn Progettato per questo banale caso d'uso, ci deve essere un modo elegante per ottenere un SafeArray da un metodo COM in uno CComSafeArray.

+0

Quale versione di Visual Studio stai utilizzando? –

+0

Questo accade sia per VS8 (2005) che per VS9 (2008) – Motti

+2

In base alla mia esperienza, credo che chiunque abbia progettato CComSafeArray non l'abbia mai effettivamente utilizzata. Puoi usare la tua classe di wrapper se vuoi. – Amnon

risposta

10

Il problema è che si imposta direttamente il puntatore interno di ricezione CComSafeArray. utilizzare il metodo Attach() per collegare un SAFEARRAY esistente a un CComSafeArray:

LPSAFEARRAY ar; 
foo(&ar); 
CComSafeArray<VARIANT> sa; 
sa.Attach(ar); 
+0

Sicuramente questo non è il modo in cui si suppone che si usi 'CComSafeArray', va contro la grana di' CComVariant' e 'CComBSTR'. – Motti

+0

Come visto nel codice, CComSafeArray si aspetta che SAFEARRAY sia bloccato. Devi bloccarlo in un modo o nell'altro. – Amnon

+0

E non esiste alcuna funzionalità simile a Attach che blocchi e non funzioni di tipo Detach che non sblocca, quindi il lavoro deve essere eseguito sul lato chiamante o sul lato di chiamata. –

1

Direi che dove non c'era l'intenzione di permettere un simile caso d'uso. Probabilmente non era lo stesso sviluppatore che ha scritto CComVariant & CComPtr :)

Credo che autore considerato semantica di valore CComSafeArray s' come obiettivo principale; Attaccare/Scollegare potrebbe semplicemente essere una funzione "bonus".

+1

E anche con questo motivo, mi sento ancora come il ctor predefinito di "CComSafeArray' e 'GetSafeArrayPtr' sono difetti di progettazione/soluzioni alternative ... – Andrey

5

Giusto per confermare che la risposta contrassegnata è quella corretta. I wrapper RAII non possono funzionare oltre i limiti COM.

L'implementazione del metodo pubblicato non è corretta, non è possibile presumere che il chiamante fornirà un SAFEARRAY valido. Just [out] non è un attributo valido in Automation, deve essere [out, retval] o [in, out]. Se è [out, retval], che è come appare, allora il metodo deve creare una nuova matrice da zero. Se è [in, out], il metodo deve distruggere l'array passato se non corrisponde al tipo di array previsto e ne crea uno nuovo.

Problemi correlati