[RESOLVED] [2005] PInvoke on a function declared with __declspec-VBForums
Results 1 to 7 of 7

Thread: [RESOLVED] [2005] PInvoke on a function declared with __declspec

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Jun 1999
    Location
    California, USA
    Posts
    662

    Resolved [RESOLVED] [2005] PInvoke on a function declared with __declspec

    I'm getting this exception when I try to get the address of a function in a dll written in vc++ 6.0. The dll is a compiled winamp plugin and I can't change the plugin source.

    Code:
    System.Runtime.InteropServices.MarshalDirectiveException was unhandled
      Message="Method's type signature is not PInvoke compatible."
      Source="Winamp Plugin Host"
      StackTrace:
           at Winamp_Plugin_Host.OutputPlugin.GetProcAddress(Int32 hModule, String& lpProcName)
           at Winamp_Plugin_Host.OutputPlugin..ctor(String FromFile) in C:\Documents and Settings\Jack Schitt\Desktop\design\programming\Winamp Plugin Host\PluginClasses.vb:line 76
    Is there any way in vb.net 2005 to call a function declared as:

    Code:
    __declspec( dllexport ) Out_Module * winampGetOutModule()
    ...hopefully using LoadLibraryEX, GetProcAddress, and FreeLibrary...

  2. #2
    Moderator
    Join Date
    Jan 2005
    Location
    Sydney
    Posts
    13,630

    Re: [2005] PInvoke on a function declared with __declspec

    VB Code:
    1. <DllImport("dll_name", CallingConvention:=CallingConvention.Cdecl)> _
    2. Private Function WinampGetOutModule() As [...]
    3. End Function

  3. #3

    Thread Starter
    Fanatic Member
    Join Date
    Jun 1999
    Location
    California, USA
    Posts
    662

    Re: [2005] PInvoke on a function declared with __declspec

    Quote Originally Posted by penagate
    VB Code:
    1. <DllImport("dll_name", CallingConvention:=CallingConvention.Cdecl)> _
    2. Private Function WinampGetOutModule() As [...]
    3. End Function
    I was using the LoadLibrary, GetProcAddress, and FreeLibrary functions before as they allow me to dynamically specify the dll. (The dll to load varies and there are multiple dlls to load).

    Can this be done with either DllImport or Declare?

  4. #4
    Moderator
    Join Date
    Jan 2005
    Location
    Sydney
    Posts
    13,630

    Re: [2005] PInvoke on a function declared with __declspec

    Dynamic DLLImport

    Hope you can convert C# to VB.

  5. #5

    Thread Starter
    Fanatic Member
    Join Date
    Jun 1999
    Location
    California, USA
    Posts
    662

    Re: [2005] PInvoke on a function declared with __declspec

    Quote Originally Posted by penagate
    Dynamic DLLImport

    Hope you can convert C# to VB.

    It looks a little complicated for what I'm trying to do and seems to apply to .Net 1.x.

    I'm including the unfinished class I'm working on. If you have winamp, create a new instance of the class and provide the full path to any dll file in the plugins folder of winamp who's filename begins with "OUT".

    The test in this case would be to run the About method of the class and see if you get an 'About This Plugin...' type window. I haven't been able to test any of the delegates in the OutModule structure as the problem I'm having occures before this is returned.

    You can get winamp free at winamp.com. The sdk is available free at http://www.winamp.com/nsdn/winamp/sdk/index.php

    VB Code:
    1. Public Class OutputPlugin
    2.     Implements IDisposable
    3.  
    4.     Private Declare Function LoadLibraryEx Lib "kernel32.dll" Alias "LoadLibraryExA" (ByVal lpLibFileName As String, ByVal hFile As Int32, ByVal dwFlags As Int32) As Int32
    5.     Private Declare Function FreeLibrary Lib "kernel32.dll" (ByVal hLibModule As Integer) As Integer
    6.     Private Declare Function GetProcAddress Lib "kernel32.dll" (ByVal hModule As Integer, ByVal lpProcName As String) As ptrwinampGetOutModule
    7.  
    8.     Private Const LOAD_WITH_ALTERED_SEARCH_PATH As Int32 = &H8
    9.  
    10.     'Main delegate. The declare above for GetProcAddress returns this type
    11.     Private Delegate Function ptrwinampGetOutModule() As OutModule
    12.  
    13.     Private _Lib As Integer 'holds HMODULE for dll file
    14.     Private _OutModule As OutModule 'holds the plugin info
    15.  
    16.     Sub New(ByVal FromFile As String)
    17.         MyBase.New()
    18.  
    19.         'load the library. FreeLibrary is called in Dispose
    20.         _Lib = LoadLibraryEx(FromFile, 0, LOAD_WITH_ALTERED_SEARCH_PATH)
    21.  
    22.         'Get the address for function winampGetOutModule...
    23.         Dim tmp As ptrwinampGetOutModule = GetProcAddress(_Lib, "winampGetOutModule")
    24.  
    25.         '...and call it
    26.         _OutModule = tmp.Invoke
    27.  
    28.     End Sub
    29.  
    30. #Region " IDisposable Support "
    31.     Private disposedValue As Boolean = False        ' To detect redundant calls
    32.  
    33.     ' IDisposable
    34.     Protected Overridable Sub Dispose(ByVal disposing As Boolean)
    35.         If Not Me.disposedValue Then
    36.             If disposing Then
    37.                 ' TODO: free unmanaged resources when explicitly called
    38.             End If
    39.  
    40.             ' TODO: free shared unmanaged resources
    41.             FreeLibrary(_Lib)
    42.         End If
    43.         Me.disposedValue = True
    44.     End Sub
    45.  
    46.     ' This code added by Visual Basic to correctly implement the disposable pattern.
    47.     Public Sub Dispose() Implements IDisposable.Dispose
    48.         ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
    49.         Dispose(True)
    50.         GC.SuppressFinalize(Me)
    51.     End Sub
    52. #End Region
    53.  
    54. #Region "OutModule Structure"
    55.     '"Slightly" modified def of the structure. See OUT.H in the sdk for the original version
    56.     <StructLayout(LayoutKind.Sequential)> _
    57.     Public Structure OutModule
    58.         Public version As Integer               '// module version (OUT_VER)
    59.         Public description As String            '// description of module, with version string
    60.         Public id As Integer                    '// module id. each input module gets its own. non-nullsoft modules should
    61.         '// be >= 65536.
    62.  
    63.         Public hMainWindow As Integer           '// winamp's main window (filled in by winamp)
    64.         Public hDllInstance As Integer         '// DLL instance handle (filled in by winamp)
    65.  
    66.         Public Delegate Sub ptrConfig(ByVal hwndParent As Integer)
    67.         <MarshalAs(UnmanagedType.FunctionPtr)> _
    68.         Public Config As ptrConfig '(HWND hwndParent); '// configuration dialog
    69.  
    70.         Public Delegate Sub ptrAbout(ByVal hwndParent As Integer)
    71.         <MarshalAs(UnmanagedType.FunctionPtr)> _
    72.         Public About As ptrAbout '(HWND hwndParent);  '// about dialog
    73.  
    74.         Public Delegate Sub ptrInit()
    75.         <MarshalAs(UnmanagedType.FunctionPtr)> _
    76.         Public Init As ptrInit '();             '// called when loaded
    77.  
    78.         Public Delegate Sub ptrQuit()
    79.         <MarshalAs(UnmanagedType.FunctionPtr)> _
    80.         Public Quit As ptrQuit '();             '// called when unloaded
    81.  
    82.         Public Delegate Function ptrOpen(ByVal SampleRate As Integer, ByVal NumChannels As Integer, ByVal BitsPerSamp As Integer, ByVal BufferLenMS As Integer, ByVal PreBufferMS As Integer) As Integer
    83.         <MarshalAs(UnmanagedType.FunctionPtr)> _
    84.         Public Open As ptrOpen '(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms);
    85.         '// returns >=0 on success, <0 on failure
    86.         '// NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins.
    87.         '//    ... so don't expect the max latency returned to be what you asked for.
    88.         '// returns max latency in ms (0 for diskwriters, etc)
    89.         '// bufferlenms and prebufferms must be in ms. 0 to use defaults.
    90.         '// prebufferms must be <= bufferlenms
    91.  
    92.         Public Delegate Sub ptrClose()
    93.         <MarshalAs(UnmanagedType.FunctionPtr)> _
    94.         Public Close As ptrClose '();   '// close the ol' output device.
    95.  
    96.         Public Delegate Function ptrWrite(ByRef buf As Byte(), ByVal len As Integer) As Integer
    97.         <MarshalAs(UnmanagedType.FunctionPtr)> _
    98.         Public Write As ptrWrite '(char *buf, int len); 
    99.         '// 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data.
    100.         '// 1 returns not able to write (yet). Non-blocking, always.
    101.  
    102.         Public Delegate Function ptrCanWrite() As Integer
    103.         <MarshalAs(UnmanagedType.FunctionPtr)> _
    104.         Public CanWrite As ptrCanWrite '(); '// returns number of bytes possible to write at a given time.
    105.         '// Never will decrease unless you call Write (or Close, heh)
    106.  
    107.         Public Delegate Function ptrIsPlaying() As Integer
    108.         <MarshalAs(UnmanagedType.FunctionPtr)> _
    109.         Public IsPlaying As ptrIsPlaying '(); '// non0 if output is still going or if data in buffers waiting to be
    110.         '// written (i.e. closing while IsPlaying() returns 1 would truncate the song
    111.  
    112.         Public Delegate Function ptrPause(ByVal Pause As Integer) As Integer
    113.         <MarshalAs(UnmanagedType.FunctionPtr)> _
    114.         Public Pause As ptrPause '(int pause); '// returns previous pause state
    115.  
    116.         Public Delegate Sub ptrSetVolume(ByVal volume As Integer)
    117.         <MarshalAs(UnmanagedType.FunctionPtr)> _
    118.         Public SetVolume As ptrSetVolume '(int volume); '// volume is 0-255
    119.  
    120.         Public Delegate Sub ptrSetPan(ByVal pan As Integer)
    121.         <MarshalAs(UnmanagedType.FunctionPtr)> _
    122.         Public SetPan As ptrSetPan '(int pan); '// pan is -128 to 128
    123.  
    124.         Public Delegate Sub ptrFlush(ByVal t As Integer)
    125.         <MarshalAs(UnmanagedType.FunctionPtr)> _
    126.         Public Flush As ptrFlush '(int t);  '// flushes buffers and restarts output at time t (in ms)
    127.         '// (used for seeking)
    128.  
    129.         Public Delegate Function ptrGetOutputTime() As Integer
    130.         <MarshalAs(UnmanagedType.FunctionPtr)> _
    131.         Public GetOutputTime As ptrGetOutputTime '(); '// returns played time in MS
    132.  
    133.         Public Delegate Function ptrGetWrittenTime() As Integer
    134.         <MarshalAs(UnmanagedType.FunctionPtr)> _
    135.         Public GetWrittenTime As ptrGetWrittenTime '(); '// returns time written in MS (used for synching up vis stuff)
    136.     End Structure
    137. #End Region
    138.  
    139. #Region "Methods"
    140.     'these call the pointers to the various functions of the plugin.
    141.     'Note: this section is not yet complete
    142.  
    143.     'Plugin loads settings, etc.
    144.     Public Sub Init()
    145.         _OutModule.Init()
    146.     End Sub
    147.  
    148.     'Plugin saves settings, closes devices
    149.     Public Sub Quit()
    150.         _OutModule.Quit()
    151.     End Sub
    152.  
    153.     'Show the about window
    154.     Public Sub About(ByVal Owner As Form)
    155.         _OutModule.About(Owner.Handle)
    156.     End Sub
    157.  
    158.     'Show the config window
    159.     Public Sub Config(ByVal Owner As Form)
    160.         _OutModule.Config(Owner.Handle)
    161.     End Sub
    162. #End Region
    163.  
    164. End Class

  6. #6

    Thread Starter
    Fanatic Member
    Join Date
    Jun 1999
    Location
    California, USA
    Posts
    662

    Re: [2005] PInvoke on a function declared with __declspec

    Not for the faint at heart...

    I took my previous code and added a dynamic binder as suggested by penagate. Everything, including the dynamic binding works un until the point where it calls the function in the dll. Then I get the same exception (signature not PInvoke compatible).

    This is the entire contents of the plugin file... (The exception occurs on the bolded line near the bottom)
    The second code section is the function template I'm using. This file should have its build action set to none. Additionally, add it as a resource via the resource manager. The resource should be named 'Template'

    WinampPluginClasses.vb
    VB Code:
    1. Imports System.Runtime.InteropServices
    2. Imports System.CodeDom
    3.  
    4. Public Class OutputPlugin
    5.     'function name = winampGetOutModule
    6.  
    7.     'Main delegate. The declare above for GetProcAddress returns this type
    8.     Private Delegate Function ptrwinampGetOutModule() As OutModule
    9.  
    10.     Private _OutModule As OutModule 'holds the plugin info
    11.  
    12.     Sub New(ByVal FromFile As String)
    13.         MyBase.New()
    14.  
    15.         _OutModule = DynamicBinding(Of OutModule).CallFunction(FromFile, "winampGetOutModule")
    16.  
    17.     End Sub
    18.  
    19. #Region "Methods"
    20.     'these call the pointers to the various functions of the plugin.
    21.     'Note: this section is not yet complete
    22.  
    23.     'Plugin loads settings, etc.
    24.     Public Sub Init()
    25.         _OutModule.Init()
    26.     End Sub
    27.  
    28.     'Plugin saves settings, closes devices
    29.     Public Sub Quit()
    30.         _OutModule.Quit()
    31.     End Sub
    32.  
    33.     'Show the about window
    34.     Public Sub About(ByVal Owner As Form)
    35.         _OutModule.About(Owner.Handle)
    36.     End Sub
    37.  
    38.     'Show the config window
    39.     Public Sub Config(ByVal Owner As Form)
    40.         _OutModule.Config(Owner.Handle)
    41.     End Sub
    42. #End Region
    43.  
    44. End Class
    45.  
    46. #Region "OutModule Structure"
    47. '"Slightly" modified def of the structure. See OUT.H in the sdk for the original version
    48. <StructLayout(LayoutKind.Sequential)> _
    49. Public Structure OutModule
    50.     Public version As Integer               '// module version (OUT_VER)
    51.     Public description As String            '// description of module, with version string
    52.     Public id As Integer                    '// module id. each input module gets its own. non-nullsoft modules should
    53.     '// be >= 65536.
    54.  
    55.     Public hMainWindow As Integer           '// winamp's main window (filled in by winamp)
    56.     Public hDllInstance As Integer         '// DLL instance handle (filled in by winamp)
    57.  
    58.     Public Delegate Sub ptrConfig(ByVal hwndParent As Integer)
    59.     <MarshalAs(UnmanagedType.FunctionPtr)> _
    60.     Public Config As ptrConfig '(HWND hwndParent); '// configuration dialog
    61.  
    62.     Public Delegate Sub ptrAbout(ByVal hwndParent As Integer)
    63.     <MarshalAs(UnmanagedType.FunctionPtr)> _
    64.     Public About As ptrAbout '(HWND hwndParent);  '// about dialog
    65.  
    66.     Public Delegate Sub ptrInit()
    67.     <MarshalAs(UnmanagedType.FunctionPtr)> _
    68.     Public Init As ptrInit '();             '// called when loaded
    69.  
    70.     Public Delegate Sub ptrQuit()
    71.     <MarshalAs(UnmanagedType.FunctionPtr)> _
    72.     Public Quit As ptrQuit '();             '// called when unloaded
    73.  
    74.     Public Delegate Function ptrOpen(ByVal SampleRate As Integer, ByVal NumChannels As Integer, ByVal BitsPerSamp As Integer, ByVal BufferLenMS As Integer, ByVal PreBufferMS As Integer) As Integer
    75.     <MarshalAs(UnmanagedType.FunctionPtr)> _
    76.     Public Open As ptrOpen '(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms);
    77.     '// returns >=0 on success, <0 on failure
    78.     '// NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins.
    79.     '//    ... so don't expect the max latency returned to be what you asked for.
    80.     '// returns max latency in ms (0 for diskwriters, etc)
    81.     '// bufferlenms and prebufferms must be in ms. 0 to use defaults.
    82.     '// prebufferms must be <= bufferlenms
    83.  
    84.     Public Delegate Sub ptrClose()
    85.     <MarshalAs(UnmanagedType.FunctionPtr)> _
    86.     Public Close As ptrClose '();   '// close the ol' output device.
    87.  
    88.     Public Delegate Function ptrWrite(ByRef buf As Byte(), ByVal len As Integer) As Integer
    89.     <MarshalAs(UnmanagedType.FunctionPtr)> _
    90.     Public Write As ptrWrite '(char *buf, int len); 
    91.     '// 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data.
    92.     '// 1 returns not able to write (yet). Non-blocking, always.
    93.  
    94.     Public Delegate Function ptrCanWrite() As Integer
    95.     <MarshalAs(UnmanagedType.FunctionPtr)> _
    96.     Public CanWrite As ptrCanWrite '(); '// returns number of bytes possible to write at a given time.
    97.     '// Never will decrease unless you call Write (or Close, heh)
    98.  
    99.     Public Delegate Function ptrIsPlaying() As Integer
    100.     <MarshalAs(UnmanagedType.FunctionPtr)> _
    101.     Public IsPlaying As ptrIsPlaying '(); '// non0 if output is still going or if data in buffers waiting to be
    102.     '// written (i.e. closing while IsPlaying() returns 1 would truncate the song
    103.  
    104.     Public Delegate Function ptrPause(ByVal Pause As Integer) As Integer
    105.     <MarshalAs(UnmanagedType.FunctionPtr)> _
    106.     Public Pause As ptrPause '(int pause); '// returns previous pause state
    107.  
    108.     Public Delegate Sub ptrSetVolume(ByVal volume As Integer)
    109.     <MarshalAs(UnmanagedType.FunctionPtr)> _
    110.     Public SetVolume As ptrSetVolume '(int volume); '// volume is 0-255
    111.  
    112.     Public Delegate Sub ptrSetPan(ByVal pan As Integer)
    113.     <MarshalAs(UnmanagedType.FunctionPtr)> _
    114.     Public SetPan As ptrSetPan '(int pan); '// pan is -128 to 128
    115.  
    116.     Public Delegate Sub ptrFlush(ByVal t As Integer)
    117.     <MarshalAs(UnmanagedType.FunctionPtr)> _
    118.     Public Flush As ptrFlush '(int t);  '// flushes buffers and restarts output at time t (in ms)
    119.     '// (used for seeking)
    120.  
    121.     Public Delegate Function ptrGetOutputTime() As Integer
    122.     <MarshalAs(UnmanagedType.FunctionPtr)> _
    123.     Public GetOutputTime As ptrGetOutputTime '(); '// returns played time in MS
    124.  
    125.     Public Delegate Function ptrGetWrittenTime() As Integer
    126.     <MarshalAs(UnmanagedType.FunctionPtr)> _
    127.     Public GetWrittenTime As ptrGetWrittenTime '(); '// returns time written in MS (used for synching up vis stuff)
    128. End Structure
    129. #End Region
    130.  
    131. Friend Class DynamicBinding(Of ReturnStructure As Structure)
    132.     'replacements in template
    133.     Private Const DLLName As String = "DLLName"
    134.     Private Const [Structure] As String = "Integer"
    135.     Private Const FunctionName As String = "FunctionName"
    136.  
    137.     'name of module
    138.     Private Const ClassName As String = "CallDll"
    139.  
    140.     Public Shared Function CallFunction(ByVal DLL As String, ByVal Funct As String) As ReturnStructure
    141.         'Code is loaded from a resource. see Template.VB
    142.         Dim TemplateCode As String = My.Resources.Template
    143.  
    144.         'Replace parts of the code with the constants above
    145.         TemplateCode = Replace(TemplateCode, DLLName, DLL)
    146.         TemplateCode = Replace(TemplateCode, FunctionName, Funct)
    147.         TemplateCode = Replace(TemplateCode, [Structure], GetType(ReturnStructure).FullName)
    148.  
    149.         'Compile the code
    150.         Dim CompileUnit As New CodeSnippetCompileUnit(TemplateCode)
    151.         Dim TemplateCodeArray As String() = {TemplateCode}
    152.         Dim Params As New Compiler.CompilerParameters()
    153.  
    154.         With Params
    155.             .GenerateExecutable = False
    156.             .GenerateInMemory = True
    157.             .IncludeDebugInformation = False
    158.             .ReferencedAssemblies.Add(Application.ExecutablePath)
    159.         End With
    160.  
    161.         Dim CodeProvider As New Microsoft.VisualBasic.VBCodeProvider()
    162.  
    163.         'this is the line that compiles it
    164.         Dim CompilerResaults As Compiler.CompilerResults = CodeProvider.CompileAssemblyFromSource(Params, TemplateCodeArray)
    165.  
    166.         'if there are errors, let me see what they are
    167.         If CompilerResaults.Errors.Count > 0 Then
    168.             Dim ce As Object = CompilerResaults.Errors
    169.             Dim item As Object
    170.  
    171.             For Each item In ce
    172.                 'cheap and simple way of debugging compiler errors:
    173.                 'hover the mouse over 'item' in the code window while stopped
    174.                 'it will tell you what error occured.
    175.                 Stop
    176.             Next
    177.         End If
    178.  
    179.         'now it should be compiled, use relfection to call the code
    180.         Dim Assembly As System.Reflection.Assembly = CompilerResaults.CompiledAssembly
    181.         Dim [class] As System.Type = Assembly.GetType(ClassName)
    182.         Dim method As Reflection.MethodInfo = [class].GetMethod(Funct, Reflection.BindingFlags.Static Or Reflection.BindingFlags.Public Or Reflection.BindingFlags.FlattenHierarchy)
    183.  
    184.         [b]Return DirectCast(method.Invoke(Nothing, Nothing), ReturnStructure)[/b]
    185.  
    186.     End Function
    187. End Class

    Template.vb
    VB Code:
    1. Public Class CallDll
    2.     <System.Runtime.InteropServices.DllImport("DLLName", CallingConvention:=System.Runtime.InteropServices.CallingConvention.StdCall)> _
    3.     Public Shared Function FunctionName() As Integer
    4.     End Function
    5. End Class

  7. #7

    Thread Starter
    Fanatic Member
    Join Date
    Jun 1999
    Location
    California, USA
    Posts
    662

    Re: [2005] PInvoke on a function declared with __declspec

    Looks like I got it working. I'll post the working code after optimizing it a bit. I knew dynamically compiling code was a little overkill. I'm switching it back to LoadLibrary, GetProcAddress, and FreeLibrary.

    The problem was that (apparently) you can't PInvoke something if the return value isn't something standard (i.e. a number or a boolean.)

    Now, I simply take the number returned and use that as the first param of Marshal.PtrToStructure

    Now the test works properly and it looks like I don't need to compile code from my program.

    (If you found this post by doing a search for compiling code or executing scripts from your app, the above source code does do that, btw)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width

Survey posted by VBForums.