Используйте строку:
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
public string dmDeviceName;
См .: http://pinvoke.net/default.aspx/Structures/DEVMODE.html
РЕДАКТИРОВАТЬ: Я не заметил, когда публиковал свой быстрый ответ, так как я сосредоточился на строках (и есть один в самом начале структуры, что означает, что остальные элементы структуры могут на вещи), но, как уже отмечали другие, у вас большая проблема с профсоюзами в структуре DEVMODE. Элементы в объединении не лежат последовательно, а занимают одно и то же пространство в памяти: одновременно может использоваться только один из элементов объединения. Например:
union {
DWORD dmDisplayFlags;
DWORD dmNup;
};
означает, что dmDisplayFlags и dmNup - это существенно разные имена для одного и того же блока памяти. То есть Как dmDisplayFlags, так и dmNup хранятся со смещением 116 байтов от начала структуры. Изменение dmNup также приводит к изменению значения dmDisplayFlags, и наоборот. Используя код C # как:
public Int32 dmDisplayFlags;
public Int32 dmNup;
означает, что они сохраняются последовательно, то есть со смещением 116 и 120. Это нарушает компоновку всей структуры. Чтобы это исправить, вам нужно использовать явный макет и вручную определить смещения полей. Посмотрите на ссылку, которую я ранее дал на pinvoke.net, для примера того, как это сделать на этой конкретной структуре. Обратите внимание, что dmDisplayFlags и dmNup имеют одинаковое смещение . Поскольку C # изначально не поддерживает объединения, это несколько неуклюжий способ обработки объединений для тех особых сценариев взаимодействия, как этот, для которых это требуется.
Я бы предложил исправить ваши проблемы с объединением, а затем использовать строки с ByValTStr, как первоначально предлагалось (в общем, используйте то, что есть на pinvoke.net). Посмотрите, принесет ли он вам лучшие результаты.
Другие предполагают, что это проблема Юникода, но я не думаю, что это так. В документации говорится, что FindNextPrinterChangeNotification недоступно в Юникоде. Если вы исследовали структуру на уровне байтов и сказали, что это не Unicode - я вам определенно верю.
Из документов:
" ByValTStr : Используется для встроенных символьных массивов фиксированной длины, которые появляются внутри структуры. Тип символов, используемый с ByValTStr, определяется аргументом System.Runtime.InteropServices.CharSet системы. .Runtime.InteropServices.StructLayoutAttribute, примененный к содержащей структуре. Всегда используйте поле MarshalAsAttribute.SizeConst, чтобы указать размер массива.
.NET Framework Типы ByValTStr ведут себя как строки C-стиля, фиксированного размера внутри структуры (например, char s [5]). Поведение в управляемом коде отличается от поведения в Microsoft Visual Basic 6.0, которое не завершается нулем (например, MyString As String * 5). "
Мне кажется довольно ясным, что это должен быть общепринятый "правильный" способ сделать это.