7 / 7 / 1
Регистрация: 10.10.2012
Сообщений: 47

Маршалинг Waveform Audio

20.05.2013, 15:19. Показов 1771. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет.
Возникла необходимость сделать wrapper для c# библиотеки Windows Waveform Audio.

Пока работаю пока только с одной структурой и одной функцией и уже получаю ошибку:
В среде выполнения обнаружена критическая ошибка. Ошибка произошла по адресу 0x5e815fb7 в потоке 0x1a84. Код ошибки 0xc0000005...

Код c++:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
typedef UINT MMRESULT;
typedef UINT        MMVERSION;  /* major (high byte), minor (low byte) */
typedef UINT       *LPUINT;
#define MAXPNAMELEN      32     /* max product name length (including NULL) */
 
typedef struct {
WORD      wMid;
WORD      wPid;
MMVERSION vDriverVersion;
TCHAR     szPname[MAXPNAMELEN];
DWORD     dwFormats;
WORD      wChannels;
WORD      wReserved1;
} WAVEINCAPS;
 
MMRESULT waveInGetDevCaps(
  UINT_PTR uDeviceID,
  LPWAVEINCAPS pwic,
  UINT cbwic
);
Код c#:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[StructLayout(LayoutKind.Sequential), CharSet = CharSet.Auto]
        public class WaveInCaps
        {
            public UInt16 wMid;
            public UInt16 wPid;
            public /*MMVERSION*/UInt16 vDriverVersion;
            //TCHAR
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string szPname;
            public UInt32 dwFormats;
            public UInt16 wChannels;
            public UInt16 wReserved1;
        }
 
    private const string mmdll = "winmm.dll";
 
        [DllImport(mmdll), CharSet = CharSet.Auto]
        public static extern int waveInGetDevCaps(UInt16 uDeviceID, ref WaveInCaps pwic, UInt16 cbwic);
Вызов функции:
C#
1
2
3
4
5
6
7
private void GetDevNames()
        {
            WaveLib.WaveNative.WaveInCaps cap = new WaveLib.WaveNative.WaveInCaps();
            int size = Marshal.SizeOf(cap);
            int j = WaveLib.WaveNative.waveInGetDevCaps((UInt16)0, ref cap, (UInt16)size);
            label2.Text += cap.szPname;
        }

Вот не могу понять в чем дело и все! Вроде делаю все согласно статье "Класс Marshal, использование PInvoke, небезопасный код (unsafe)".
Кстати в результате эксперимента:
Когда убрал CharSet = и вызывал waveInGetDevCapsW, то работало, но метод выдавал код ошибки в переменную j. Ошибка: некорректные параметры.

P.S. С маршалингом сталкиваюсь первый раз, так что очень плохо тут ориентируюсь.

Добавлено через 10 минут
И еще наблюдение:
Почему то размер структуры на 2 байта больше чем надо.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
20.05.2013, 15:19
Ответы с готовыми решениями:

Управление Audio Source, полями AudioClip (Audio Clip) и Output (Audio Mixer Group) через скрипт
Ребята, мне опять нужна Ваша помощь! Помогите дописать скрипт управления\воспроизведения аудио клипов Есть пустой объект, на нём...

Multimedia Audio Adapfer Realtek ALC655@SiS 7012 Audio Device
материнка типа P4S8X-MX ,Multimedia Audio Adapfer Realtek ALC655@SiS 7012 Audio Device ПРОБЛЕМА!Были подключены динамики к компу...

Не работает звук - нет драйвера на Audio Device on High Definition Audio Bus
Переустановил систему на компе на виндуоз XP. Звука нет Диспетчер устройств говорит, что нет драйвера на Audio Device on High Definition...

8
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
20.05.2013, 15:47
mib383, может потому что у вас строка в С++ включает символ \0, судя по вашему же комменту:
C++
1
#define MAXPNAMELEN      32     /* max product name length (including NULL) */
при этом в шарпе 32 это будет только полезный размер строки. sizeof(char) == 2 как раз

Добавлено через 1 минуту
Хотя я с этим мало работал и не уверен что в этом проблема) Просто предположение
1
7 / 7 / 1
Регистрация: 10.10.2012
Сообщений: 47
20.05.2013, 17:15  [ТС]
Нет, дело не в этом.
Но все равно спасибо, вы меня на мысль натолкнули, что надо добавить pack=1 с структуре, чтоб убрать выравнивание, теперь размер адекватный. Но проблема все равно, увы, не решилась.

Добавлено через 1 час 6 минут
Проблему решил так:
1. waveInGetDevCapsW
2. struct pack(1)
3. charset = unicode

Но это решение не красивое! Надо как-то по-другому.
0
 Аватар для Lasur
267 / 257 / 43
Регистрация: 18.03.2012
Сообщений: 506
21.05.2013, 06:48
Цитата Сообщение от mib383 Посмотреть сообщение
И еще наблюдение:
Почему то размер структуры на 2 байта больше чем надо.
CLR выравнивает поля структуры в памяти для более быстрого доступа к ним. В данном случае, вероятно, 2 лишних байта будут после vDriverVersion, дабы адрес поля szPname был кратен восьми. Во избежание подобного используют LayoutKind.Explicit, но обычно выравнивание CLR совпадает с требуемым Windows библиотеками.

Касательно
C#
1
2
[DllImport(mmdll, CharSet = CharSet.Auto)]
public static extern int waveInGetDevCaps(UInt16 uDeviceID, ref WaveInCaps pwic, UInt16 cbwic);
Согласно описанию функции первый параметр - указатель на uint. Указатель занимает 4 байта в x32 процессе и 8 в x64, но никак не 2 байта.
Далее, класс WaveInCaps и так передается по ссылке, т.е. ref там лишний.
Наконец, третий параметр - WINAPI uint == C# uint == UInt32. При чем тут UInt16?
1
7 / 7 / 1
Регистрация: 10.10.2012
Сообщений: 47
21.05.2013, 09:21  [ТС]
Цитата Сообщение от Lasur Посмотреть сообщение
CLR выравнивает поля структуры в памяти для более быстрого доступа к ним. В данном случае, вероятно, 2 лишних байта будут после vDriverVersion, дабы адрес поля szPname был кратен восьми. Во избежание подобного используют LayoutKind.Explicit, но обычно выравнивание CLR совпадает с требуемым Windows библиотеками.

Касательно
C#
1
2
[DllImport(mmdll, CharSet = CharSet.Auto)]
public static extern int waveInGetDevCaps(UInt16 uDeviceID, ref WaveInCaps pwic, UInt16 cbwic);
Согласно описанию функции первый параметр - указатель на uint. Указатель занимает 4 байта в x32 процессе и 8 в x64, но никак не 2 байта.
Далее, класс WaveInCaps и так передается по ссылке, т.е. ref там лишний.
Наконец, третий параметр - WINAPI uint == C# uint == UInt32. При чем тут UInt16?
Я уже потом разобрался.
UInt16 или 32 почти не влияет. А вот насчет ссылки это интересно.
Делаю вместо class WaveInCaps - struct WaveInCaps и передаю по ссылке. Ошибку выдает уже не среда, а сама функция: не верно заданы параметры.
На c++ этот код выглядит:
C++
1
2
WAVEINCAPS caps;
int result = waveInGetDevCaps(0, &caps, sizeof(WAVEINCAPS));
на шарпе пытаюсь:
C#
1
2
3
WaveLib.WaveNative.WaveInCaps cap
int size = Marshal.SizeOf(cap);
int j = WaveLib.WaveNative.waveInGetDevCapsW(0, ref cap, size);
где WaveInCaps - структура (не класс) описанная выше. На c++ работает, на c# - нет!

Добавлено через 16 минут
Ребят! Спасибо большое - разобрался. Ключевой момент действительно оказался UINT(c++) = uint(c#). Главная ошибка была с MMVERSION = UINT.
В итоге год выглядит так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/// <summary>
        /// typedef struct {
        /// WORD      wMid;
        /// WORD      wPid;
        /// MMVERSION vDriverVersion;
        /// TCHAR     szPname[MAXPNAMELEN];
        /// DWORD     dwFormats;
        /// WORD      wChannels;
        /// WORD      wReserved1;
        /// } WAVEINCAPS;
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct WaveInCaps
        {
            public ushort wMid;
            public ushort wPid;
            public /*MMVERSION*/uint vDriverVersion;
            //TCHAR
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string szPname;
            public uint dwFormats;
            public ushort wChannels;
            public ushort wReserved1;
        }
        /// <summary>
        /// MMRESULT waveInGetDevCaps(UINT_PTR uDeviceID,LPWAVEINCAPS pwic,UINT cbwic);
        /// </summary>
        [DllImport(mmdll, CharSet=CharSet.Auto)]
        public static extern int waveInGetDevCaps(uint uDeviceID, ref WaveInCaps pwic, uint cbwic);
0
 Аватар для Lasur
267 / 257 / 43
Регистрация: 18.03.2012
Сообщений: 506
21.05.2013, 09:46
Цитата Сообщение от mib383 Посмотреть сообщение
UInt16 или 32 почти не влияет
Не знаю как оно может не влиять. Передача 2 байт вместо 4 это - дисбаланс стека.

Цитата Сообщение от mib383 Посмотреть сообщение
C#
1
2
3
WaveLib.WaveNative.WaveInCaps cap
int size = Marshal.SizeOf(cap);
int j = WaveLib.WaveNative.waveInGetDevCapsW(0, ref cap, size);
Вы ведь знаете, что в .Net структуру следует инициализировать явно?
C#
1
WaveLib.WaveNative.WaveInCaps cap = new WaveLib.WaveNative.WaveInCaps()
Добавлено через 7 минут
Цитата Сообщение от mib383 Посмотреть сообщение
Ребят! Спасибо большое - разобрался.
Рад был помочь, обращайтесь.
0
7 / 7 / 1
Регистрация: 10.10.2012
Сообщений: 47
21.05.2013, 11:05  [ТС]
Цитата Сообщение от Lasur Посмотреть сообщение
Не знаю как оно может не влиять. Передача 2 байт вместо 4 это - дисбаланс стека.


Вы ведь знаете, что в .Net структуру следует инициализировать явно?
C#
1
WaveLib.WaveNative.WaveInCaps cap = new WaveLib.WaveNative.WaveInCaps()
Добавлено через 7 минут

Рад был помочь, обращайтесь.
Здесь написано:
При создании объекта структуры с помощью оператора new объект создается и вызывается соответствующий конструктор. В отличие от классов структуры можно создавать без использования оператора new. В таком случае вызов конструктора отсутствует, что делает выделение более эффективным. Однако поля остаются без значений и объект нельзя использовать до инициализации всех полей.

Так что мой вариант тоже вроде как правильный.

Насчет uint: согласен с вами, просто оно работало и так (пока дело не коснулось поля структуры), видимо оно само преобразовывалось в нужный формат.

Еще раз спасибо.
0
 Аватар для Lasur
267 / 257 / 43
Регистрация: 18.03.2012
Сообщений: 506
21.05.2013, 13:24
Цитата Сообщение от mib383 Посмотреть сообщение
Так что мой вариант тоже вроде как правильный.
Структуры инициализируются без вызова конструктора при их использовании как поля класса или при создании массива. В случае
C#
1
WaveLib.WaveNative.WaveInCaps cap
компилятор потребует явного вызова оператора new (и преобразует в il инструкцию initobj). Просто попробуйте скомпилировать приведенный вами код.

Цитата Сообщение от mib383 Посмотреть сообщение
Насчет uint: согласен с вами, просто оно работало и так (пока дело не коснулось поля структуры), видимо оно само преобразовывалось в нужный формат.
PInvoke работает точно так как вы ему сказали, ничего не преобразовывается автоматом. Но раз проблема решена, искать причины успешной работы я, пожалуй, не буду.
0
7 / 7 / 1
Регистрация: 10.10.2012
Сообщений: 47
21.05.2013, 14:36  [ТС]
Цитата Сообщение от Lasur Посмотреть сообщение
Структуры инициализируются без вызова конструктора при их использовании как поля класса или при создании массива. В случае
C#
1
WaveLib.WaveNative.WaveInCaps cap
компилятор потребует явного вызова оператора new (и преобразует в il инструкцию initobj). Просто попробуйте скомпилировать приведенный вами код.


PInvoke работает точно так как вы ему сказали, ничего не преобразовывается автоматом. Но раз проблема решена, искать причины успешной работы я, пожалуй, не буду.
На самом деле я действительно использую структуру как поле класса. В качестве локальной переменной - не работает.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
21.05.2013, 14:36
Помогаю со студенческими работами здесь

Javafx создания waveform
Всем привет. Разрабаываю плеер. Хочу чтобы отображалось waveform(спектрограмма) . Как это реализовать на JavaFX?

Посчитать количество точек на Waveform Graph
Всем привет. Можете помочь посчитать количество точек на Waveform Graph, таким образом, что при вводе числа в поле Limit в поле Points...

Waveform Визуализация на базе Bass.dll
Привет народ. Кто шарит в Bass.dll? у меня версия 2.4 Пытаюсь сделать waveform визуализацию для программы по документации...

Драйвер на Realtek AC'97 Audio for VIA (R) Audio Controller
помогите, первый раз такая проблема! Переустановил Виндовс на своем компе старом (он у меня только для инета и для просмотра видео/фото)...

Поместить данные из текстового файла в Waveform chart
Помогите поместить данные не менее 100 из текстового файла в Waveform chart Необходимо реализовать Диалог Windows при выборе имени...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Опции темы

Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Программа принимает математическое выражение в виде строки и выдаёт его производную в виде строки и вычисляет значение производной при заданном х Логарифм записывается как: (x-2)log(x^2+2) -. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru