Запуск «GC.Collect» исправляет мой сбой, но я не понимаю, почему - PullRequest
1 голос
/ 15 июня 2009

У меня есть этот фрагмент кода (из примера кода подключения к ПК Nokia 3.2, в 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);

Если я запускаю GC.Collect() в начале этого, то я не получаю AccessViolationException. Но я не хочу замедлять эту функцию без необходимости. Я пытался поместить GC.Keepalive в разные места, но безуспешно.

CA_FOLDER_INFO определяется как:

    [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;
    }

В данном случае мне не нужна ни одна из строк, и изменение их определений на IntPtr, похоже, исключает исключение.

Что здесь происходит, и как правильно предотвратить исключение?

Ответы [ 4 ]

5 голосов
/ 16 июня 2009

Ваша проблема в том, что вы передаете true в Marshal.StructureToPtr, поэтому он пытается освободить два строковых указателя (которые иногда недопустимы). В этом случае вам нужно передать false, так как вы просто распределили эту память в куче. (то есть там нечего освобождать).

0 голосов
/ 15 июня 2009

Возможно, что неуправляемые ресурсы чем-то не высвобождаются. Убедитесь, что все, что вы используете, реализует IDisposable и, если да, оберните его в блок using { }.

0 голосов
/ 16 июня 2009

Вы уверены, что Marshal.Sizeof (bufItem) и Marshal.Sizeof (folderInfo) совпадают?

И, может быть, тот факт, что вы не инициализируете строки? Так как вы говорите, что не получаете ошибку, когда они IntPtr (по умолчанию IntPtr.Zero), я бы попробовал установить их обе на пустые строки, прежде чем пытаться маршалировать элемент буфера.

[Изменить]

Возможно, вам следует попробовать закрепить дескриптор буфера и маршалировать его в структуру, а не наоборот. Примерно так:

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
0 голосов
/ 15 июня 2009

Используйте фиксированное ключевое слово, чтобы получить указатель на ваш исходный folderInfo.

...