Не удается обойти ошибку компиляции для буферов фиксированного размера в C # - PullRequest
0 голосов
/ 02 сентября 2011

Я пытаюсь создать некоторые структуры в C #, чтобы имитировать структуры из некоторых заголовочных файлов C ++ Microsoft.Мой код выглядит следующим образом:

[StructLayout(LayoutKind.Sequential)]
unsafe public struct _NotifyData
{
    fixed uint adwData[2];
    public struct Data
    {
        uint cbBuf;
        IntPtr pBuff;
    }
}

[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_NOTIFY_INFO_DATA
{
    public ushort Type;
    public ushort Field;
    public uint Reserved;
    public uint Id;
    public _NotifyData NotifyData;
}

[StructLayout(LayoutKind.Sequential)]
unsafe public struct PRINTER_NOTIFY_INFO
{
    public uint Version;
    public uint Flags;
    public uint Count;
    fixed PRINTER_NOTIFY_INFO_DATA aData[1];  //Compiler complains here!!!
}

Компилятор жалуется на мою переменную aData[1] в моем объявлении struct PRINTER_NOTIFY_INFO.Я столкнулся с несколькими из них и добавил fixed к рассматриваемой переменной, а unsafe к объявлению структуры, похоже, сработало.За исключением этой структуры.Я получаю следующую ошибку:

Тип буфера фиксированного размера должен быть одним из следующих: bool, byte, short, int, long, char, sbyte, ushort, uint, ulong, float или double

Теперь я вижу, что используемый мной тип не относится к числу перечисленных типов, но согласно this , размещение unsafe перед объявлением структуры должнопозвольте мне использовать типы, отличные от перечисленных.По какой-то причине это не позволяет мне.

Ответы [ 2 ]

3 голосов
/ 02 сентября 2011

У меня есть пара предложений.

Прежде всего _NotifyData - это объединение, которое должно выглядеть следующим образом:

[StructLayout(LayoutKind.Explicit)]
public struct _NotifyData
{
    [FieldOffset(0), MarshalAs(UnmanagedType.ByValArray, SizeConst=2)]
    public uint[] adwData;
    [FieldOffset(0)]
    public struct Data
    {
        uint cbBuf;
        IntPtr pBuff;
    }
}

Во-вторых, PRINTER_NOTIFY_INFO просто не может бытьобрабатывается маршаллером P / invoke.Вам придется использовать ручную сортировку, т. Е. Marshal.PtrToStructure(), чтобы добраться куда угодно.Документация для параметра ppPrinterNotifyInfo для FindNextPrinterChangeNotification() гласит:

Указатель на переменную-указатель, которая получает указатель на выделенный системой буфер только для чтения.Вызовите функцию FreePrinterNotifyInfo, чтобы освободить буфер, когда вы закончите с ним.Этот параметр может иметь значение NULL, если информация не требуется.

Вы должны передать IntPtr в качестве параметра out и затем использовать Marshal.PtrToStructure() для считывания содержимого в свои собственные структуры данных.Примерно так:

IntPtr PrinterNotifyInfo;
FindNextPrinterChangeNotification(..., out PrinterNotifyInfo);
IntPtr pCount = PrinterNotifyInfo + 2*Marshal.SizeOf(typeof(uint));
uint Count = (uint)Marshal.ReadInt32(pCount);
IntPtr pData = pCount + Marshal.SizeOf(typeof(uint));
for (int i=0; i<Count; i++)
{
    PRINTER_NOTIFY_INFO_DATA Data = (PRINTER_NOTIFY_INFO_DATA)Marshal.PtrToStructure(pData, typeof(PRINTER_NOTIFY_INFO_DATA));
    pData += Marshal.SizeOf(typeof(PRINTER_NOTIFY_INFO_DATA));
}

Я не пытался это скомпилировать, но, надеюсь, это поможет понять идею.

1 голос
/ 02 сентября 2011

Вы просто не можете объявить массив фиксированного размера пользовательских struct s в C #, как говорится в сообщении об ошибке и на странице, на которую вы ссылались (я предлагаю вам перечитать).

РЕДАКТИРОВАТЬ : Удалена неверная информация. См. Ответ Дэвида Хеффернана, чтобы узнать, как это решить.

...