Executando um fixes 'GC.Collect' meu acidente, mas eu não entendo por que
Pergunta
Eu tenho este pedaço de código (a partir da conectividade 3.2 exemplo de código Nokia PC, em 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 eu executar GC.Collect()
no início deste, então eu não obter uma AccessViolationException
. Mas eu não quero abrandar esta função a menos que necessário. Eu tentei colocar GC.Keepalive
em vários lugares, mas sem sucesso.
CA_FOLDER_INFO
é definido como:
[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;
}
Não, neste caso, exigir quer das cordas, e alterando suas definições para IntPtr
parece fazer a exceção ir embora.
O que está acontecendo aqui, e qual é a maneira correta para evitar a exceção?
Solução
Seu problema é que você está passando fiel a Marshal.StructureToPtr por isso tenta libertar os dois ponteiros de cordas (que às vezes são inválidos). Você precisa passar falsa, neste caso, já que você só alocados que a memória no heap. (Ou seja, não há nada para libertar lá).
Outras dicas
Você tem certeza Marshal.SizeOf (bufItem) e Marshal.SizeOf (FolderInfo) são os mesmos?
E, talvez o fato de que você não está inicializando as cordas? Desde que você diz que você não obter o erro quando estão IntPtr (cujo padrão é IntPtr.Zero), eu tentaria colocá-los tanto para esvaziar cordas antes de tentar empacotamento o item buffer.
[Edit]
Talvez você deve tentar fixar a alça de buffer, e empacotamento que a estrutura, em vez de vis versa. Algo parecido com isto:
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
Use a palavra-chave fixa para obter um ponteiro para o seu folderInfo
originais.
Pode ser que recursos não gerenciados não estão sendo liberados por alguma coisa. Verifique para ver se alguma coisa que você está usando implementos IDisposable e em caso afirmativo, envolvê-la em um bloco using { }
.