Using virtual function in VB.NET from C++ DLL

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


Answer this question

Using virtual function in VB.NET from C++ DLL

  • Mythran

    What's the purpose of the RefCounted interface IUnknown already has refcounting methods so I don't see why you need an extra pair.

    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

    You may be trying too hard :) - have you tried adding a reference to the C++ dll from a VB program VB tries to hide away most of the class factory and interface obtaining stuff - you should be able to just declare an instance of the class you want to use in your program.

  • Chris Dufour

    The only thing is the person who coded the library used VC++ 6.0 so it's all native code in the DLL. He said he used virtual function in the classes to make it COM compatible. I believe it since bindings are made in other languages easily.
  • Using virtual function in VB.NET from C++ DLL