Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/9: Рейтинг темы: голосов - 9, средняя оценка - 4.67
7 / 7 / 1
Регистрация: 10.10.2012
Сообщений: 47

Маршалинг Waveform Audio

20.05.2013, 15:19. Показов 1768. Ответов 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
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru