Esecuzione di un 'GC.Collect' corregge il mio incidente, ma io non capisco perché
Domanda
Ho questo pezzo di codice (dalla connettività PC Nokia Codice 3.2 esempio, in C #):
DAContentAccessDefinitions.CA_FOLDER_INFO folderInfo =
new DAContentAccessDefinitions.CA_FOLDER_INFO();
folderInfo.iSize = Marshal.SizeOf(folderInfo); //(32)
IntPtr bufItem = Marshal.AllocHGlobal(folderInfo.iSize);
//I often get a AccessViolationException on the following line
Marshal.StructureToPtr(folderInfo, bufItem, true);
Se corro GC.Collect()
all'inizio di questo, allora non ottengo un AccessViolationException
. Ma io non voglio rallentare questa funzione solo se necessario. Ho provato a mettere GC.Keepalive
in vari luoghi, ma senza successo.
CA_FOLDER_INFO
è definito come:
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct CA_FOLDER_INFO
{
public int iSize;
public int iFolderId;
public int iOptions;
public string pstrName;
public string pstrPath;
public int iSubFolderCount;
public IntPtr pSubFolders;
public IntPtr pParent;
}
Non, in questo caso, richiedono una delle due corde, e cambiando le loro definizioni di IntPtr
sembra rendere l'eccezione andare via.
Che cosa sta succedendo qui, e qual è il modo corretto per evitare che l'eccezione?
Soluzione
Il problema è che si sta passando fedele alla Marshal.StructureToPtr così tenta di liberare i due puntatori di stringa (che a volte sono validi). È necessario passare falso in questo caso dal momento che hai appena assegnato che la memoria sul mucchio. (Vale a dire non c'è niente per liberare lì).
Altri suggerimenti
Sei sicuro Marshal.SizeOf (bufItem) e Marshal.SizeOf (FolderInfo) sono la stessa cosa?
E, forse il fatto che non si inizializza le corde? Dal momento che tu dici non si ottiene l'errore quando sono IntPtr (che per default è IntPtr.Zero), mi piacerebbe provare entrambi impostazione stringhe vuote, prima di provare a marshalling la voce di buffer.
[Edit]
Forse si dovrebbe provare appuntare la maniglia del buffer, e marshalling che alla struttura, piuttosto che nei versa. Qualcosa di simile a questo:
DAContentAccessDefinitions.CA_FOLDER_INFO folderInfo;
GCHandle pinnedHandle = GCHandle.Alloc(buffItem, GCHandleType.Pinned);
folderInfo = (DAContentAccessDefinitions.CA_FOLDER_INFO)Marshal.PtrToStructure(pin.AddrOfPinnedObject(), typeof(DAContentAccessDefinitions.CA_FOLDER_INFO));
pin.Free();
//folderInfo should contain the data from buffItem
Usa la parola chiave fissa per ottenere un puntatore al folderInfo
originale.
E 'possibile che le risorse non gestite non vengono rilasciate da qualcosa. Controllare per vedere se qualcosa si sta utilizzando attrezzi IDisposable in caso affermativo, avvolgerlo in un blocco using { }
.