Есть книга Горнакова С. про DirectX 9 у книги есть примеры на C++ один из примеров показывает реализацию воспроизведения музыки в приложении при помощи интерфейса - DirectMusic Я решил попробывать перекинуть этот пример на - masm32 сама функция в примере для мызыки: Код (C): //----------------------------------------------------------------------------- // Функция // Music() // Воспроизводит музыку в приложении //----------------------------------------------------------------------------- HRESULT Music() { // Инициализируем СОМ CoInitialize(NULL); // Инициалезируем главный интерфейс CoCreateInstance( CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC, IID_IDirectMusicPerformance8, (void**)&pPerform); // Инициалезируем загрузчик CoCreateInstance( CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC, IID_IDirectMusicLoader8, (void**)&pLoad ); // Инициалезируем аудио-систему pPerform->InitAudio( NULL, NULL, NULL, DMUS_APATH_SHARED_STEREOPLUSREVERB, 64,DMUS_AUDIOF_ALL, NULL ); // Загружаем музыкальный файл WCHAR Name[] = L"Stanislav_Gornakov.wav"; if( FAILED( pLoad->LoadObjectFromFile( CLSID_DirectMusicSegment, IID_IDirectMusicSegment8, Name,(LPVOID*) &pSegment ) ) ) return E_FAIL; // Загрузка сигмента pSegment->Download( pPerform ); // Повтор pSegment->SetRepeats(DMUS_SEG_REPEAT_INFINITE); // Проигрываем сегмент pPerform->PlaySegmentEx( pSegment,NULL ,NULL ,0 , 0,NULL ,NULL ,NULL ); return 0; } Я переделал эту функцию под - masm32 но при тестах программа стала вылетать с ошибкой я выяснил что ошибка происходит на последнем этапе Код (C): pPerform->PlaySegmentEx( pSegment,NULL ,NULL ,0 , 0, NULL ,NULL ,NULL ); то есть алгоритм входит в виртуальную функцию - PlaySegmentEx и программа тут же вылетает с ошибкой По некоторому опыту я знал что подобная ошибка может возникнуть если возврат функции происходит по неправильному адресу а это чаще всего происходит из за того что в стек положили неправильное количество аргументов но в примере показано восемь аргументов и у меня прописано столько же тогда почему происходит ошибка Я решил дизасемблировать экзешник этого примера из книги и в конечном итоге я был очень удивлён когда увидел дизасемблированное место метода - PlaySegmentEx и в нём было чётко показано что у метода - PlaySegmentEx прописано (оказывается) не восемь а девять аргументов Код (ASM): push 0 push 0 push 0 push 0 push 0 push 0 push 0 push 0 mov eax, dword_59BBBC push eax mov ecx, ppv mov edx, [ecx] mov eax, ppv push eax call dword ptr [edx+0B4h] Я тут же в своём коде у метода - PlaySegmentEx добавил ещё один аргумент (то есть прописал ещё один ноль) и мой пример тут же прекрасно заработал Первое что мне пришло в голову так это то что автор книги случайно не дописал ещё один аргумент у этого метода но когда я ради интереса полез в MSDN я увидел что автор не ошибался и в справке MSDN у этого метода чётко прописано восемь аргументов Код (C): HRESULT PlaySegmentEx( IUnknown* pSource, WCHAR *pwzSegmentName, IUnknown* pTransition, DWORD dwFlags, __int64 i64StartTime, IDirectMusicSegmentState** ppSegmentState, IUnknown* pFrom, IUnknown* pAudioPath ); Если автор как и положено прописал у себя в листинге восемь аргументов тогда почему компилятор C++ под капотом дописал этому методу ещё один девятый аргумент (и как оказалось он правильно сделал) Я не силён в C++ и могу только догадыватся что дело тут в синтаксисе прописанных аргументов у метода вроде бы их восемь но на самом деле их девять Кто в теме, не разъясните?
Потому что первым аргументом в COM передается ссылка на объект (на указатель на интерфейс). В данном случае первым аргументом передается IDirectMusicPerformance8* this.
Если вы посмотрите дизасемблированный код то вы увидите тот параметр о чём вы пишите (ссылка на объект - 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]
А вот это скорее всего ближе к истине поэтому я примерно так и подозревал что всё дело в синтаксисе типизации аргументов теперь хотя бы буду знать что если встретится такой тип __int64 то придётся закладывать в стек второй DWORD В Ассемблере типизация это формальность в отличии от языков высокого уровня по этому просто нужно знать про этот подводный камень и соответственно ручками добавлять в стек второй DWORD Спасибо за подсказку Thetrik Век живи век учись
assch, Скрытые параметры. Во многих яп аргументы можно опустить, транслятор сам сформирует корректный вызов и допишет что где нужно. Это значит что языковое выражение(скрипта) никак не связано с машинным(осевым, реальным") интерфейсом. По нормальному нужно было посмотреть как организованы эти интерфейсы, а ошибку решать штатным путём - машинное исключение при разыменовании указателя => аргумент указатель на структуру и опять же смотреть конвенцию. А в данном случае получаются танцы с бубном. Да и в целом ооп кодить на асм идея не из лучших, вы запутаетесь в макросах и поймёте какой это изврат.