Откуда взялся лишний аргумент у метода - PlaySegmentEx

Тема в разделе "WASM.BEGINNERS", создана пользователем assch, 3 июл 2018.

  1. assch

    assch Member

    Публикаций:
    0
    Регистрация:
    17 мар 2011
    Сообщения:
    192
    Есть книга Горнакова С. про DirectX 9 у книги есть примеры на C++
    один из примеров показывает реализацию воспроизведения музыки в приложении
    при помощи интерфейса - DirectMusic

    Я решил попробывать перекинуть этот пример на - masm32
    сама функция в примере для мызыки:

    Код (C):
    1.  
    2. //-----------------------------------------------------------------------------
    3. // Функция
    4. // Music()
    5. // Воспроизводит музыку в приложении
    6. //-----------------------------------------------------------------------------
    7. HRESULT Music()
    8. {
    9. // Инициализируем СОМ
    10.    CoInitialize(NULL);
    11. // Инициалезируем главный интерфейс
    12.    CoCreateInstance( CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC,
    13.                       IID_IDirectMusicPerformance8, (void**)&pPerform);
    14. // Инициалезируем загрузчик
    15.    CoCreateInstance( CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC,
    16.                       IID_IDirectMusicLoader8, (void**)&pLoad );
    17. // Инициалезируем аудио-систему
    18.    pPerform->InitAudio( NULL, NULL, NULL,
    19.                         DMUS_APATH_SHARED_STEREOPLUSREVERB,
    20.                          64,DMUS_AUDIOF_ALL, NULL );
    21. // Загружаем музыкальный файл
    22.    WCHAR Name[] = L"Stanislav_Gornakov.wav";  
    23.    if( FAILED( pLoad->LoadObjectFromFile( CLSID_DirectMusicSegment,
    24.                                             IID_IDirectMusicSegment8,
    25.                                            Name,(LPVOID*) &pSegment ) ) )
    26.        return E_FAIL;
    27. // Загрузка сигмента
    28.    pSegment->Download( pPerform );
    29. // Повтор
    30.    pSegment->SetRepeats(DMUS_SEG_REPEAT_INFINITE);
    31. // Проигрываем сегмент
    32.    pPerform->PlaySegmentEx( pSegment,NULL ,NULL ,0 , 0,NULL ,NULL ,NULL );
    33. return 0;
    34. }
    35.  
    Я переделал эту функцию под - masm32
    но при тестах программа стала вылетать с ошибкой
    я выяснил что ошибка происходит на последнем этапе
    Код (C):
    1.  
    2. pPerform->PlaySegmentEx( pSegment,NULL ,NULL ,0 , 0, NULL ,NULL ,NULL );
    3.  
    то есть алгоритм входит в виртуальную функцию - PlaySegmentEx
    и программа тут же вылетает с ошибкой

    По некоторому опыту я знал что подобная ошибка может возникнуть
    если возврат функции происходит по неправильному адресу
    а это чаще всего происходит из за того что в стек положили
    неправильное количество аргументов
    но в примере показано восемь аргументов и у меня прописано столько же
    тогда почему происходит ошибка

    Я решил дизасемблировать экзешник этого примера из книги
    и в конечном итоге я был очень удивлён когда увидел
    дизасемблированное место метода - PlaySegmentEx
    и в нём было чётко показано что у метода - PlaySegmentEx
    прописано (оказывается) не восемь а девять аргументов

    Код (ASM):
    1.  
    2. push 0
    3. push 0
    4. push 0
    5. push 0
    6. push 0
    7. push 0
    8. push 0
    9. push 0
    10. mov eax, dword_59BBBC
    11. push eax
    12. mov ecx, ppv
    13. mov edx, [ecx]
    14. mov eax, ppv
    15. push eax
    16. call dword ptr [edx+0B4h]
    17.  
    Я тут же в своём коде у метода - PlaySegmentEx
    добавил ещё один аргумент (то есть прописал ещё один ноль)
    и мой пример тут же прекрасно заработал

    Первое что мне пришло в голову так это то что автор книги
    случайно не дописал ещё один аргумент у этого метода
    но когда я ради интереса полез в MSDN
    я увидел что автор не ошибался
    и в справке MSDN у этого метода чётко прописано восемь аргументов

    Код (C):
    1.  
    2. HRESULT PlaySegmentEx(
    3.   IUnknown* pSource,
    4.   WCHAR *pwzSegmentName,
    5.   IUnknown* pTransition,
    6.   DWORD dwFlags,
    7.   __int64 i64StartTime,
    8.   IDirectMusicSegmentState** ppSegmentState,
    9.   IUnknown* pFrom,
    10.   IUnknown* pAudioPath
    11. );
    12.  
    Если автор как и положено прописал у себя в листинге восемь аргументов
    тогда почему компилятор C++ под капотом дописал этому методу
    ещё один девятый аргумент (и как оказалось он правильно сделал)

    Я не силён в C++ и могу только догадыватся
    что дело тут в синтаксисе прописанных аргументов у метода
    вроде бы их восемь но на самом деле их девять

    Кто в теме, не разъясните?
     
  2. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    861
    Потому что первым аргументом в COM передается ссылка на объект (на указатель на интерфейс). В данном случае первым аргументом передается IDirectMusicPerformance8* this.
     
  3. assch

    assch Member

    Публикаций:
    0
    Регистрация:
    17 мар 2011
    Сообщения:
    192
    Если вы посмотрите дизасемблированный код то вы увидите тот параметр о чём вы пишите (ссылка на объект - this) это не девятый а уже десятый параметр

    девять аргументов метода

    push 0
    push 0
    push 0
    push 0
    push 0
    push 0
    push 0
    push 0
    mov eax, dword_59BBBC
    push eax

    плюс десятый ссылка на объект - this

    mov ecx, ppv
    mov edx, [ecx]
    mov eax, ppv
    push eax
    call dword ptr [edx+0B4h]
     
  4. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    861
    Листинг не смотрел, но там еще __int64 - 2 DWORD'а
     
    assch нравится это.
  5. assch

    assch Member

    Публикаций:
    0
    Регистрация:
    17 мар 2011
    Сообщения:
    192
    А вот это скорее всего ближе к истине
    поэтому я примерно так и подозревал что всё дело в синтаксисе типизации аргументов
    теперь хотя бы буду знать что если встретится такой тип __int64
    то придётся закладывать в стек второй DWORD

    В Ассемблере типизация это формальность в отличии от языков высокого уровня
    по этому просто нужно знать про этот подводный камень
    и соответственно ручками добавлять в стек второй DWORD

    Спасибо за подсказку Thetrik

    Век живи век учись
     
  6. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    assch,

    Скрытые параметры. Во многих яп аргументы можно опустить, транслятор сам сформирует корректный вызов и допишет что где нужно. Это значит что языковое выражение(скрипта) никак не связано с машинным(осевым, реальным") интерфейсом. По нормальному нужно было посмотреть как организованы эти интерфейсы, а ошибку решать штатным путём - машинное исключение при разыменовании указателя => аргумент указатель на структуру и опять же смотреть конвенцию. А в данном случае получаются танцы с бубном. Да и в целом ооп кодить на асм идея не из лучших, вы запутаетесь в макросах и поймёте какой это изврат.