Regole di gestione della memoria

La durata dei puntatori alle interfacce viene sempre gestita tramite i metodi AddRef e Release in ogni interfaccia COM. Per altre informazioni, vedere regole di per la gestione dei conteggi dei riferimenti.

Per tutti gli altri parametri, è importante rispettare determinate regole per la gestione della memoria. Le regole seguenti si applicano a tutti i parametri dei metodi di interfaccia, incluso il valore restituito, che non vengono passati per valore:

  • I parametri in ingresso devono essere allocati e liberati dal chiamante.
  • I parametri out devono essere allocati da quello chiamato; vengono liberati dal chiamante usando l'allocatore di memoria dell'attività COM standard. Per altre informazioni, vedere L'allocatore di memoria OLE.
  • I parametri in/out vengono inizialmente allocati dal chiamante e quindi liberati e riallocati da quello chiamato, se necessario. Come è true per i parametri out, il chiamante è responsabile della liberazione del valore restituito finale. È necessario usare l'allocatore di memoria COM standard.

Negli ultimi due casi, in cui un frammento di codice alloca la memoria e un'altra parte di codice lo libera, l'uso dell'allocatore COM garantisce che le due parti di codice usino gli stessi metodi di allocazione.

Un'altra area che richiede particolare attenzione è il trattamento dei parametri out e out in condizioni di errore. Se una funzione restituisce un codice di errore, il chiamante in genere non ha modo di pulire i parametri out o in-out. Ciò comporta le regole aggiuntive seguenti:

  • In caso di condizione di errore, i parametri devono essere sempre impostati in modo affidabile su un valore che verrà pulito senza alcuna azione da parte del chiamante.
  • Tutti i parametri del puntatore di uscita devono essere impostati in modo esplicito su NULL. Questi vengono in genere passati in un parametro puntatore a puntatore, ma possono anche essere passati come membri di una struttura allocata dal chiamante e il cosiddetto riempimento del codice. Il modo più semplice per assicurarsi che questo sia (in parte) per impostare questi valori su null nella voce della funzione. Questa regola è importante perché promuove un'interoperabilità delle applicazioni più affidabile.
  • In condizioni di errore, tutti i parametri in uscita devono essere lasciati da soli dal codice chiamato (pertanto rimanenti al valore a cui sono stati inizializzati dal chiamante) o essere impostati in modo esplicito, come nel caso restituito dell'errore del parametro out.

Tenere presente che queste convenzioni di gestione della memoria per le applicazioni COM si applicano solo tra interfacce pubbliche e API; Non è necessario che l'allocazione di memoria sia strettamente interna a un'applicazione COM usando questi meccanismi.

Avvertimento

Errore comune nell'interoperabilità di .NET/codice gestito: quando si usano interfacce COM da .NET (C# o VB.NET), runtime Callable Wrapper (RCW) gestisce automaticamente la maggior parte della gestione della memoria. Tuttavia, se si esegue P/Invoke una funzione di tipo COM che restituisce una CoTaskMemAllocstringa allocata (out LPWSTR), è necessario liberarla con Marshal.FreeCoTaskMem . Il Garbage Collector non rilascia la memoria dell'attività COM:

// C# example — COM function returns a CoTaskMemAlloc'd string
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
static extern int SHGetKnownFolderPath(
    ref Guid rfid, uint dwFlags, IntPtr hToken, out IntPtr ppszPath);

// Caller must free the returned string
IntPtr pathPtr = IntPtr.Zero;
try
{
    Guid folderId = new("374DE290-123F-4565-9164-39C4925E467B"); // Downloads
    int hr = SHGetKnownFolderPath(ref folderId, 0, IntPtr.Zero, out pathPtr);
    Marshal.ThrowExceptionForHR(hr);
    string path = Marshal.PtrToStringUni(pathPtr)!;
}
finally
{
    if (pathPtr != IntPtr.Zero)
        Marshal.FreeCoTaskMem(pathPtr); // Required — prevents memory leak
}

Regola generale: Se una funzione COM nativa documenta che il chiamante deve liberare un parametro out con CoTaskMemFree, l'equivalente gestito è Marshal.FreeCoTaskMem. Non usare Marshal.FreeHGlobal mai per la memoria delle attività COM, perché si tratta di allocatori diversi.

COM usa internamente chiamate rpc (Remote Procedure Call) per comunicare tra client e server. Per altre informazioni sulla gestione della memoria negli stub del server RPC, vedere l'argomento gestione della memoria server-stub.