2011-08-11 16 views
9

Sto scrivendo scrivendo un'API in COM in C++ e anche scrivendo un programma che utilizza questa API in C#. La mia domanda riguarda la semantica di gestione della memoria BSTR quando si passano i BSTR alle funzioni COM. Di 'la mia IDL assomiglia:Convenzione per il passaggio di BSTR in funzioni COM da C# (interoperabilità COM)

HRESULT SomeFunction([in] BSTR input); 

Attualmente questa funzione è implementata in questo modo:

HRESULT SomeFunction(BSTR input) { 
    // Do stuff ..., then: 
    SysFreeString(input); 
} 

Quando chiamo da C# con qualcosa di simile SomeFunction(myString), sarà C# generare qualcosa come questo (pseudocodice):

myString = SysAllocString("string"); 
SomeFunction(myString); 

O meglio così:

myString = SysAllocString("string"); 
SomeFunction(myString); 
SysFreeString(myString); 

Cioè, C# libera il BSTR che genera per eseguire il marshall all'interfaccia COM, o dovrei liberarlo all'interno della mia funzione? Grazie!

risposta

14

Da Allocating and Releasing Memory for a BSTR:

Quando si chiama in una funzione che prevede un argomento BSTR, si necessario allocare la memoria per il BSTR prima della chiamata e rilascio in seguito. ...

Quindi non liberarlo se si tratta di un parametro di input. C# (e qualsiasi altro runtime che utilizza oggetti COM) deve rispettare la convenzione COM per la gestione della memoria passare dentro e fuori gli oggetti COM e quindi deve gestire la memoria per la stringa se si tratta di un parametro di input. Altrimenti, in che modo un oggetto COM sa che viene richiamato da C# o da un altro runtime di lingua?

aggiuntive google-fu alzato questo: Marshaling between Managed and Unmanaged Code

... Per quanto riguarda le questioni di proprietà, il CLR segue COM-style convenzioni:

  • memoria passata come [in] è di proprietà di il chiamante e deve essere sia
    assegnato dal chiamante e liberato dal chiamante. Il callee dovrebbe
    non provare a liberare o modificare quella memoria.
  • La memoria allocata dal destinatario e passata come [out] o restituita appartiene al chiamante e deve essere liberata dal chiamante.
  • Il callee può liberare la memoria passata come [in, out] dal chiamante, allocare nuova memoria per esso e sovrascrivere il vecchio valore del puntatore, quindi lo passa. La nuova memoria è di proprietà del chiamante. Questo richiede due livelli di riferimento indiretto, come char **.

Nel mondo di interoperabilità, il chiamante/chiamante diventa CLR/codice nativo.Le regole implicano che nel caso non sospeso, se nel codice nativo si
si riceve un puntatore a un blocco di memoria passato come [out] da
CLR, è necessario liberarlo. D'altra parte, se il CLR riceve
un puntatore che viene passato come [out] dal codice nativo, il CLR deve essere liberato da
. Chiaramente, nel primo caso, il codice nativo deve eseguire la dislocazione e nel secondo caso, il codice gestito deve eseguire la disallocazione
.

Quindi il CLR segue le regole COM per la proprietà della memoria. QED.

+1

Questa risposta non ha nulla a che fare con ciò che il CLR fa automaticamente per l'interoperabilità, che è tutto ciò che l'OP sta chiedendo. – ildjarn

+0

@ildjarn: al contrario, risponde esattamente alla domanda dell'OP. –

+0

@Alf: indicare la risposta corretta per le ragioni sbagliate e con il contesto ei collegamenti errati non è "corretto". – ildjarn

0

Intendi dal punto di vista dello sviluppatore C# o dallo sviluppatore C++.

Lo sviluppatore C# non dovrebbe preoccuparsi di alcuna gestione della memoria quando si ha a che fare con COM +.

Creazione di un componente COM + in C++, non si dovrebbe sapere chi ti sta chiamando, la semantica della memoria sono gli stessi. Se è un parametro in, il chiamante è responsabile della gestione della memoria, indipendentemente dal fatto che sia C++ o C#. In C#, il CLR si prende cura di esso per loro.

Problemi correlati