Hi, I'm running into a problem when trying to use class interfaces from this library called Audiere. The library was written in C++ as virtual functions that were COM compatible. To use the interface you call a function in the DLL that returns a pointer to the interface (Factory ). They are bindings for Purebasic and Delphi that use the interfaces directly. I made a binding for the D language using interfaces that inherited from the IUnknown interface and it worked. Since .NET supports COM interop I thought this should work easily. I created the interfaces and marshaled them as IUnknown(I had to inherit from IUnknown to get it to work in D). I declared the functions in the DLL and had it return the interface. I tried to run it but it gives me a fatal error code. I tried to marshal the return type as UnmanagedType.IUnknown and UnmanagedType.Interface but it still fails. Is the interface code in .NET using a non standard vtable or something
I've included the code.
VB Audiere Header
-----------------
'audiere.vb
Imports System.Runtime.InteropServices
Module Audiere
' <ComVisible(True), ComImport()> _
Interface RefCounted
Sub ref() ' int
Sub unref() ' int
End Interface
' <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface File : Inherits RefCounted
Function read(ByVal pbuffer As Integer, ByVal size As Integer) As Integer ' int
Function seek(ByVal position As Integer, ByVal SeekMode As Integer) As Boolean ' bool
Function tell() As Integer ' int
End Interface
' <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface SampleBuffer : Inherits RefCounted
Sub getFormat(ByVal channel_count As Integer, ByVal sample_rate As Integer, ByVal lsample_format As Integer) ' Sub
Function getLength() As Integer ' int
Function getSamples() As Integer ' int
Function openStream() As SampleSource ' pSampleSource
End Interface
' <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface SampleSource : Inherits RefCounted
Sub getFormat(ByVal v As Integer, ByVal v2 As Integer) ' Sub
Function Read(ByVal v As Integer, ByVal v2 As Integer) As Integer ' int
Sub reset() ' Sub
Function isSeekable() As Boolean ' bool
Function getLength() As Integer ' int
Sub setPosition(ByVal v As Integer) ' Sub
Function getPosition() As Integer ' int
Function getRepeat() As Boolean ' bool
Sub setRepeat(ByVal v As Integer) ' Sub
End Interface
' <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface LoopPointSource : Inherits SampleSource
Sub addLoopPoint(ByVal location As Integer, ByVal target As Integer, ByVal loopCount As Integer) ' Sub
Sub removeLoopPoint(ByVal index As Integer) ' Sub
Function getLoopPointCount() As Integer ' int
Function getLoopPoint(ByVal index As Integer, ByVal plocation As Integer, ByVal ptarget As Integer, ByVal ploopCount As Integer) As Boolean ' bool
End Interface
' <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface OutputStream : Inherits RefCounted
Function play() As Boolean
Function _stop() As Boolean ' bool
Function isPlaying() As Boolean ' bool
Sub reset() ' Sub
Sub setRepeat(ByVal v As Boolean) ' Sub
Function getRepeat() As Boolean ' bool
Sub setVolume(ByVal v As Single) ' Sub
Function getVolume() As Single ' float
Sub setPan(ByVal v As Single) ' Sub
Function getPan() As Single ' float
Sub setPitchShift(ByVal v As Single) ' Sub
Function getPitchShift() As Single ' float
Function isSeekable() As Boolean ' bool
Function getLength() As Integer ' int
Sub setPosition(ByVal v As Integer) ' Sub
Function getPosition() As Integer ' int
End Interface
'<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface AudioDevice : Inherits RefCounted
Sub update() ' Sub
Function openStream(ByVal pSampleSource As SampleSource) As OutputStream 'OutputStream ' pAudOutputStream
Function openBuffer(ByRef pSamples As IntPtr, ByVal frame_count As Integer, ByVal channel_count As Integer, ByVal sample_rate As Integer, ByVal sample_format As Integer) As OutputStream ' pAudOutputStream
Function getName() As String ' char.l
End Interface
<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface SoundEffect : Inherits RefCounted
Sub play() ' Sub
Sub _stop() ' Sub
Sub setVolume(ByVal volume As Single) ' Sub
Function getVolume() As Single ' float
Sub setPan(ByVal pan As Single) ' Sub
Function getPan() As Single ' float
Sub setPitchShift(ByVal shift As Single) ' Sub
Function getPitchShift() As Single ' float
End Interface
Enum SampleFormat
SF_U8 ' unsigned 8-bit integer [0,255]
SF_S16 ' signed 16-bit integer in host end Interface ianness [-32768,32767]
End Enum
Enum FileFormat
FF_AUTODETECT
FF_WAV
FF_OGG
FF_FLAC
FF_MP3
FF_MOD
FF_AIFF
End Enum
Enum SoundEffectType
SE_SINGLE
SE_MULTIPLE
End Enum
Enum SeekMode
SM_Begin
SM_Current
SM_end
End Enum
'Functions
'char* AdrGetVersion()
'char* AdrGetSupportedFileFormats()
'char* AdrGetSupportedAudioDevices()
Declare Function GetSupportedAudioDevices Lib "audiere" Alias "_AdrGetSupportedAudioDevices@0" () As String
'int AdrGetSampleSize(SampleFormat format)
'AudioDevice AdrOpenDevice(char* name = null, char* parameters = null)
Declare Function OpenDevice Lib "audiere" Alias "_AdrOpenDevice@8" (Optional ByVal name As String = Nothing, Optional ByVal parameters As String = Nothing) As AudioDevice
'SampleSource AdrOpenSampleSource(char* filename, FileFormat file_format)
'SampleSource AdrOpenSampleSourceFromFile(File file, FileFormat file_format)
'SampleSource AdrCreateTone(double frequency)
'SampleSource AdrCreateSquareWave(double frequency)
'SampleSource AdrCreateWhiteNoise()
'SampleSource AdrCreatePinkNoise()
'LoopPointSource AdrCreateLoopPointSource(SampleSource source)
'OutputStream AdrOpenSound(AudioDevice device, SampleSource source, bool streaming)
'SampleBuffer AdrCreateSampleBuffer(Sub* samples, int frame_count, int channel_count, int sample_rate, SampleFormat sample_format)
'SampleBuffer AdrCreateSampleBufferFromSource(SampleSource source)
'SoundEffect AdrOpenSoundEffect(AudioDevice device, SampleSource source, SoundEffectType type)
'File AdrOpenFile(char* name, bool writeable)
'File AdrCreateMemoryFile(Sub* buffer, int size)
End Module
--------------------
VB Test Code
--------------------
'main.vb
Module Main
Sub Main()
Dim dev As AudioDevice = OpenDevice() 'fatal error when initializing interface
'dev.getName()
Inkey()
End Sub
End Module
I've included the code.VB Audiere Header
-----------------
'audiere.vb
Imports System.Runtime.InteropServices
Module Audiere
' <ComVisible(True), ComImport()> _
Interface RefCounted
Sub ref() ' int
Sub unref() ' int
End Interface
' <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface File : Inherits RefCounted
Function read(ByVal pbuffer As Integer, ByVal size As Integer) As Integer ' int
Function seek(ByVal position As Integer, ByVal SeekMode As Integer) As Boolean ' bool
Function tell() As Integer ' int
End Interface
' <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface SampleBuffer : Inherits RefCounted
Sub getFormat(ByVal channel_count As Integer, ByVal sample_rate As Integer, ByVal lsample_format As Integer) ' Sub
Function getLength() As Integer ' int
Function getSamples() As Integer ' int
Function openStream() As SampleSource ' pSampleSource
End Interface
' <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface SampleSource : Inherits RefCounted
Sub getFormat(ByVal v As Integer, ByVal v2 As Integer) ' Sub
Function Read(ByVal v As Integer, ByVal v2 As Integer) As Integer ' int
Sub reset() ' Sub
Function isSeekable() As Boolean ' bool
Function getLength() As Integer ' int
Sub setPosition(ByVal v As Integer) ' Sub
Function getPosition() As Integer ' int
Function getRepeat() As Boolean ' bool
Sub setRepeat(ByVal v As Integer) ' Sub
End Interface
' <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface LoopPointSource : Inherits SampleSource
Sub addLoopPoint(ByVal location As Integer, ByVal target As Integer, ByVal loopCount As Integer) ' Sub
Sub removeLoopPoint(ByVal index As Integer) ' Sub
Function getLoopPointCount() As Integer ' int
Function getLoopPoint(ByVal index As Integer, ByVal plocation As Integer, ByVal ptarget As Integer, ByVal ploopCount As Integer) As Boolean ' bool
End Interface
' <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface OutputStream : Inherits RefCounted
Function play() As Boolean
Function _stop() As Boolean ' bool
Function isPlaying() As Boolean ' bool
Sub reset() ' Sub
Sub setRepeat(ByVal v As Boolean) ' Sub
Function getRepeat() As Boolean ' bool
Sub setVolume(ByVal v As Single) ' Sub
Function getVolume() As Single ' float
Sub setPan(ByVal v As Single) ' Sub
Function getPan() As Single ' float
Sub setPitchShift(ByVal v As Single) ' Sub
Function getPitchShift() As Single ' float
Function isSeekable() As Boolean ' bool
Function getLength() As Integer ' int
Sub setPosition(ByVal v As Integer) ' Sub
Function getPosition() As Integer ' int
End Interface
'<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface AudioDevice : Inherits RefCounted
Sub update() ' Sub
Function openStream(ByVal pSampleSource As SampleSource) As OutputStream 'OutputStream ' pAudOutputStream
Function openBuffer(ByRef pSamples As IntPtr, ByVal frame_count As Integer, ByVal channel_count As Integer, ByVal sample_rate As Integer, ByVal sample_format As Integer) As OutputStream ' pAudOutputStream
Function getName() As String ' char.l
End Interface
<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface SoundEffect : Inherits RefCounted
Sub play() ' Sub
Sub _stop() ' Sub
Sub setVolume(ByVal volume As Single) ' Sub
Function getVolume() As Single ' float
Sub setPan(ByVal pan As Single) ' Sub
Function getPan() As Single ' float
Sub setPitchShift(ByVal shift As Single) ' Sub
Function getPitchShift() As Single ' float
End Interface
Enum SampleFormat
SF_U8 ' unsigned 8-bit integer [0,255]
SF_S16 ' signed 16-bit integer in host end Interface ianness [-32768,32767]
End Enum
Enum FileFormat
FF_AUTODETECT
FF_WAV
FF_OGG
FF_FLAC
FF_MP3
FF_MOD
FF_AIFF
End Enum
Enum SoundEffectType
SE_SINGLE
SE_MULTIPLE
End Enum
Enum SeekMode
SM_Begin
SM_Current
SM_end
End Enum
'Functions
'char* AdrGetVersion()
'char* AdrGetSupportedFileFormats()
'char* AdrGetSupportedAudioDevices()
Declare Function GetSupportedAudioDevices Lib "audiere" Alias "_AdrGetSupportedAudioDevices@0" () As String
'int AdrGetSampleSize(SampleFormat format)
'AudioDevice AdrOpenDevice(char* name = null, char* parameters = null)
Declare Function OpenDevice Lib "audiere" Alias "_AdrOpenDevice@8" (Optional ByVal name As String = Nothing, Optional ByVal parameters As String = Nothing) As AudioDevice
'SampleSource AdrOpenSampleSource(char* filename, FileFormat file_format)
'SampleSource AdrOpenSampleSourceFromFile(File file, FileFormat file_format)
'SampleSource AdrCreateTone(double frequency)
'SampleSource AdrCreateSquareWave(double frequency)
'SampleSource AdrCreateWhiteNoise()
'SampleSource AdrCreatePinkNoise()
'LoopPointSource AdrCreateLoopPointSource(SampleSource source)
'OutputStream AdrOpenSound(AudioDevice device, SampleSource source, bool streaming)
'SampleBuffer AdrCreateSampleBuffer(Sub* samples, int frame_count, int channel_count, int sample_rate, SampleFormat sample_format)
'SampleBuffer AdrCreateSampleBufferFromSource(SampleSource source)
'SoundEffect AdrOpenSoundEffect(AudioDevice device, SampleSource source, SoundEffectType type)
'File AdrOpenFile(char* name, bool writeable)
'File AdrCreateMemoryFile(Sub* buffer, int size)
End Module
--------------------
VB Test Code
--------------------
'main.vb
Module Main
Sub Main()
Dim dev As AudioDevice = OpenDevice() 'fatal error when initializing interface
'dev.getName()
Inkey()
End Sub
End Module

Using virtual function in VB.NET from C++ DLL
Mythran
Interface inheritance doesn't work the same in COM and .NET. You actually have to repeat the base type's methods in the derived interface in .NET to make it match a COM interface.
You should also have the Guid and ComImport attributes on all COM imported interfaces. And if they derive from IUnknown you also need the InterfaceType(ComInterfaceType.InterfaceIsIUnknown) attribute.
Just having a COM-like interface layout with virtual methods isn't enough to make it work, the implementation must adhere to the IUnknown rules as well. If the implementation doesn't do that, it will most likely fail when used via COM interop from .NET.
Padrick
Chris Dufour