2011-11-20 12 views
6

Sto provando a scrivere un pinvoke per il metodo ITaskTrigger :: GetTriggerString (definito allo http://msdn.microsoft.com/en-us/library/windows/desktop/aa381866(v=vs.85).aspx). Se si guarda la pagina, si dice che il chiamante del metodo è responsabile della liberazione della memoria (tramite CoTaskMemFree) del LPWSTR a cui si fa riferimento tramite il primo argomento. Mentre potrei farlo manualmente in .NET o scrivere il mio gestore di marshalling personalizzato usando ICustomMarshaler, mi chiedevo se l'uso dell'attributo MarshalAs (UnmanagedType.LPWStr) per quel particolare argomento liberasse la memoria in modo appropriato.Userà la memoria di pulizia MarshalAs (UnmanagedType.LPWStr)?

Qualcuno può fornire qualche intuizione?

+0

Cerca di lavorare con il tipo dinamico con COM Interop - questo può rendere le cose molto più semplici della tipizzazione statica e si occupa anche della gestione della memoria. – weismat

+0

Hai qualche riferimento per l'ultimo bit? C# esegue già la gestione della memoria per l'interoperabilità COM, e lo ha sempre fatto. I tipi dinamici rendono le cose più facili quando si tratta, ad esempio, di un'interfaccia IDispatch, ma hanno effettivamente caratteristiche di gestione della memoria diverse rispetto ai tipi di interoperabilità statici? –

risposta

6

Per prima cosa: stai parlando di COM Interop qui (ITaskTrigger è un'interfaccia COM), non P/Invoke. Ci sono diverse regole di interoperabilità per i due, quindi è importante mantenerli dritti. Ad esempio, dovrai definire wrapper di interoperabilità C# per l'intera interfaccia, non solo il metodo che desideri. Questi dovrebbero iniziare: pinvoke.net

La risposta breve è, sei fortunato, perché il CLR dovrebbe prendersi cura delle cose correttamente per voi.

La risposta più lunga riguarda i diversi tipi di marshalling del codice di interoperabilità COM, a seconda dei tipi di parametri, delle direzioni e di quali attributi si aggiungono alle proprie firme di interoperabilità.

In questo caso, il tipo di parametro che si otterrà nella chiamata è un parametro "out string" con un attributo MarshalAs(UnmanagedType.LPWSTR). Quando un server COM espone una chiamata con un parametro "out" del tipo di stringa LPWSTR, supponendo che il server mantenga la sua posizione finale, allocherà un buffer di memoria con CoTaskMemAlloc() e lo restituirà all'utente. (Se si trattava di un tipo di stringa diverso, ad esempio BSTR, la chiamata di allocazione di memoria specifica potrebbe essere diversa, ma il concetto di base è lo stesso.) A questo punto, sei responsabile della pulizia di quella memoria quando non ne hai più bisogno, utilizzando la chiamata CoTaskMemFree() corrispondente.

Questo è un particolare tipo di operazione chiamata un "cambio di riferimento": il parametro che si sta inviando in è già un parametro di riferimento, ma il server COM sta per sostituirlo con un diverso di riferimento . Una buona spiegazione per questo processo si trova nella sezione "Proprietà della memoria" di this MSDN magazine article. Come puoi vedere da questo articolo, quando il CLR riceve i dati da un parametro "out" su un tipo di riferimento, riconosce che si sta assumendo la responsabilità di liberare quella memoria. Durante il marshalling che richiama il codice gestito, utilizza l'attributo MarshalAs per determinare che si tratta di un puntatore tipo stringa LPWSTR in COM e che pertanto è stato assegnato utilizzando CoTaskMemAlloc(). Dopo aver creato una stringa gestita dai dati, chiamerà lo CoTaskMemFree() sul buffer originale per conto dell'utente. I dati che riceverai saranno completamente gestiti e non dovrai affrontare alcun problema di proprietà.

+1

Grazie per la risposta! Questo lo chiarisce perfettamente. – wwahammy

+1

Davvero una buona spiegazione, grazie. –