3
votes

The code below, compiled under Delphi XE2 Win32 and running under Win 7 64 bit, produces the following exception when executing the line "AudioSessionManager2.GetSessionEnumerator":

"Project22.exe raised exception class $C0000005 with message 'access violation at 0x7027edb2: write of address 0x0051ced6'"

My knowledge of exception classes or what they mean is lacking, so I have no idea as to what the exception means or how to go about fixing it.

Here is the code that raises the exception (asserts used to debug code):

var
  HRES: HRESULT;
  DeviceEnumerator: IMMDeviceEnumerator;
  DefaultDevice: IMMDevice;
  AudioSessionManager2: IAudioSessionManager2;
  Enumerator: IAudioSessionEnumerator;
begin

  CoInitialize( nil );

  HRES := CoCreateInstance( CLSID_MMDeviceEnumerator, nil, CLSCTX_ALL, IID_IMMDeviceEnumerator, DeviceEnumerator );
  Assert( Succeeded( HRES ) );

  HRES := DeviceEnumerator.GetDefaultAudioEndpoint( eRender, eMultimedia, DefaultDevice );
  Assert( Succeeded( HRES ) );

  HRES := DefaultDevice.Activate( IID_IAudioSessionManager2, CLSCTX_ALL, nil, IUnknown( AudioSessionManager2 ) );
  Assert( Succeeded( HRES ) );

  HRES := AudioSessionManager2.GetSessionEnumerator( Enumerator );  // <- EXCEPTION HERE
  Assert( Succeeded( HRES ) );

  [snip]

I'm using the Core Audio definitions from MFPack on Google Code, with the IAudioSessionManager2 and IAudioSessionEnumerator interfaces looking as follow:

IAudioSessionManager2 = interface(IUnknown)
['{77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F}']
  function GetSessionEnumerator(out SessionEnum: IAudioSessionEnumerator): HResult; stdcall;
  function RegisterSessionNotification(SessionNotification: IAudioSessionNotification): HResult; stdcall;
  function UnregisterSessionNotification(SessionNotification: IAudioSessionNotification): HResult; stdcall;
  function RegisterDuckNotification(const sessionID: LPCWSTR; const duckNotification: IAudioVolumeDuckNotification): HResult; stdcall;
  function UnregisterDuckNotification(const duckNotification: IAudioVolumeDuckNotification): HResult; stdcall;
end;

IAudioSessionEnumerator = interface(IUnknown)
['{E2F5BB11-0570-40CA-ACDD-3AA01277DEE8}']
  function GetCount(out SessionCount: integer): HResult; stdcall;
  function GetSession(const SessionCount: integer; out Session: IAudioSessionControl): HResult; stdcall;
end;

I believe the interfaces are properly defined and I also double-checked the GUIDs.

Since the same sequence of instructions execute as intended under Visual Studio 2012 (Win32 project), I suspect the problem is with my code (little doubt here), the Core Audio interfaces definitions or Delphi. The C++ code running in VS is the following:

IMMDeviceEnumerator *DeviceEnumerator = NULL;
IMMDevice* DefaultDevice = NULL;
IAudioSessionManager2* AudioSessionManager = NULL;
IAudioSessionEnumerator* Enumerator = NULL;
HRESULT HR;

HR = CoCreateInstance( __uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&DeviceEnumerator );
HR = DeviceEnumerator->GetDefaultAudioEndpoint( eRender, eMultimedia, &DefaultDevice );
HR = DefaultDevice->Activate( __uuidof(IAudioSessionManager2), CLSCTX_ALL, NULL,(void**)&AudioSessionManager );
HR = AudioSessionManager->GetSessionEnumerator( &Enumerator );

With the C++ code I can retrieve the session enumerator correctly and use GetCount, etc.

I spent countless hours trying to find out what was wrong with my code and I'm still clueless, so any help would greatly be appreciated.

1
You should not be type-casting the last parameter of DefaultDevice.Activate() to IUnknown, leave it as its original type just like you do with CoCreateInstance(). You should also be using OleCheck() instead of Assert(). - Remy Lebeau
Thanks for the suggestion, Remy. Activate() is declared as taking an IUnknown as its last parameters, which is why I cast it as such. I did try to change the declarations to various other types, including "out ppInterface" but nothing worked. I just tried the C++ code in C++ Builder and it does work as intended too. Days of working on this and I can't get it to work. I'm thinking doing a DLL in C++ might just be easier since I can't afford much more time on this. - Eric Fortier
The last parameter should be an untyped out, just like CoCreateInstance() uses. An alternative would be a PPointer, using the @ operator to pass in the variable, just like in C++. - Remy Lebeau

1 Answers

6
votes

According to MSDN, IAudioSessionManager2 should inherit from IAudioSessionManager:

type
  IAudioSessionManager2 = interface(IAudioSessionManager)
  ...