在Delphi XE2中调用“IAudioSessionManager2.GetSessionEnumerator()”时抛出异常

3
在Delphi XE2 Win32编译并在Win 7 64位系统下运行的以下代码,在执行“AudioSessionManager2.GetSessionEnumerator”这一行时会产生以下异常:"Project22.exe raised exception class $C0000005 with message 'access violation at 0x7027edb2: write of address 0x0051ced6'"。我对异常类或其含义的了解不足,因此不知道该异常意味着什么或如何修复它。以下是引发异常的代码(使用断言来调试代码):
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]

我正在使用来自Google Code上的MFPack的Core Audio定义,其中IAudioSessionManager2和IAudioSessionEnumerator接口如下:

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;

我相信接口已经被正确地定义了,我也仔细检查了GUIDs。
由于在Visual Studio 2012(Win32项目)下执行的同样指令序列按预期运行,所以我怀疑问题出现在我的代码(对此有些疑虑),Core Audio接口定义或Delphi上。在VS中运行的C++代码如下:
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 );

使用C++代码,我可以正确地检索会话枚举器并使用GetCount等方法。

我花费了无数个小时试图找出我的代码有什么问题,但我仍然毫无头绪,所以任何帮助都将不胜感激。


你不应该将 DefaultDevice.Activate() 的最后一个参数强制转换为 IUnknown,应该像在 CoCreateInstance() 中一样保留其原始类型。你还应该使用 OleCheck() 而不是 Assert() - Remy Lebeau
感谢您的建议,Remy。Activate()被声明为以IUnknown作为其最后一个参数,这就是为什么我将其强制转换为这样的原因。我尝试过将声明更改为各种其他类型,包括“out ppInterface”,但没有任何效果。我刚刚在C++ Builder中尝试了C++代码,它也按预期工作。我已经花了几天时间来解决这个问题,但我无法让它正常工作。我认为用C++编写DLL可能会更容易,因为我不能再花更多时间在这上面了。 - Eric Fortier
最后一个参数应该是未指定类型的 out,就像 CoCreateInstance() 使用的一样。另一种选择是使用 PPointer,使用 @ 运算符将变量传递进去,就像在 C++ 中一样。 - Remy Lebeau
1个回答

6

你是对的。根据你提供的MSDN页面,IAudioSessionManager2基于IAudioSessionManager,而IAudioSessionManager则基于IUnknown - Ken White
这个完美地解决了!我会检查其他接口是否有类似的疏忽,并希望能够联系维护它们的人。 - Eric Fortier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接