What's new

Help w/ N64 Plugins & VB.Net...

Juggz

New member
Hello,

I started a new project yesterday as I’ve been sick the past couple of days :yucky: , so I have some free programming time on my hands. :bouncy:

For the fun of it I started to make a frontend for one of my N64 emulators & the 1st thing on my list was to conquer the plugins.

Accessing them is pretty simple with a couple of API’s, pretty much the same as if you were to load a PSX plugin, like so:

Code:
    <DllImport _
    ("kernel32.dll", CallingConvention:=CallingConvention.Winapi, _
     EntryPoint:="LoadLibraryA", CharSet:=CharSet.Ansi)> _
    Private Function LoadLibrary(ByVal lpLibFileName As String) As Integer
    End Function

    <DllImport _
     ("kernel32.dll", CallingConvention:=CallingConvention.Winapi, _
      EntryPoint:="GetProcAddress", CharSet:=CharSet.Ansi)> _
    Private Function GetProcAddress(ByVal hModule As Integer, ByVal lpProcName As String) As Integer
    End Function

    <DllImport _
    ("kernel32.dll", CallingConvention:=CallingConvention.Winapi, _
     EntryPoint:="FreeLibrary", CharSet:=CharSet.Ansi)> _
    Private Function FreeLibrary(ByVal hModule As Integer) As Integer
    End Function

    <DllImport("user32.dll", CallingConvention:=CallingConvention.Winapi, _
    EntryPoint:="CallWindowProcA", CharSet:=CharSet.Auto)> _
    Private Function CallWindowProc(ByVal lpPrevWndFunc As Integer, _
    ByVal hwnd As Integer, ByVal Msg As Integer, ByVal wParam As Integer, _
    ByVal lParam As Integer) As Integer
    End Function

    Public Sub PlugConfig(ByVal PlugPath As String)
        Dim hProc, hModule, hResult As Integer
        hModule = LoadLibrary(PlugPath)

        hProc = GetProcAddress(hModule, About)
        If hProc Then
            hResult = CallWindowProc(hProc, 0, 0, 0, 0)
        End If

        hProc = GetProcAddress(hModule, "DllConfig")
        FreeLibrary(hModule)
    End Sub

    Public Sub PlugAbout(ByVal PlugPath As String)
        Dim hProc, hModule, hResult As Integer
        hModule = LoadLibrary(PlugPath)

        hProc = GetProcAddress(hModule, About)

        If hProc Then
            hResult = CallWindowProc(hProc, 0, 0, 0, 0)
        End If

        hProc = GetProcAddress(hModule, "DllAbout")
        FreeLibrary(hModule)
    End Sub

Then on a button or your pref. of control call:

Code:
PlugConfig(“C:\YourPath\YourPluggin.dll”)

Or

Code:
PlugAbout(“C:\YourPath\YourPluggin.dll”)

However I am wondering how I might go about using “GetDllInfo” to gather all the information about the plugin. So far all my attempts to accomplish this have been unsuccessful, any ideas on accomplishing this in VB .NET?

This is my 1st time tackling an N64 EMU-based project & I am not finding too many technical docs on the subject, any recommendations?

Thanks much! :)
 

Warcon

New member
Here is the code that I use to talk to a plugin (this is converted from C#, so I'm not sure if the converter messed stuff).

Code:
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Text

Namespace CWDev.N64Emulator.Plugins

    Public Enum PluginType As Short
        RSP = 1
        Graphic = 2
        Audio = 3
        Controller = 4
    End Enum

    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
    Friend Structure PluginInfo
        Public Version As UInt16
        Public Type As PluginType

        <MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst:=100)> _
        Public Name As String

        Public NormalMemory As Boolean
        Public MemoryBswaped As Boolean
    End Structure

    Public Class Plugin
        Implements IDisposable

        Public Sub New(ByVal dllName As String)
            m_dllName = dllName
            m_dllWrapper = New UnmanagedDllWrapper(dllName)

            m_delegateGetDllInfo = CType(GetDelegate("GetDllInfo", GetType(DelegateGetPluginInfo)), DelegateGetPluginInfo)
            If m_delegateGetDllInfo Is Nothing Then
                Throw New Exception(String.Format("Cannot find function 'GetDllInfo' in '{0}'!", m_dllName))
            End If

            m_pluginInfo = New PluginInfo()
            GetDllInfo(m_pluginInfo)

            m_dllAboutDelegate = CType(GetDelegate("DllAbout", GetType(DllAboutDelegate)), DllAboutDelegate)
            m_dllConfigDelegate = CType(GetDelegate("DllConfig", GetType(DllConfigDelegate)), DllConfigDelegate)
            m_dllTestDelegate = CType(GetDelegate("DllTest", GetType(DllTestDelegate)), DllTestDelegate)
            m_closeDLLDelegate = CType(GetDelegate("CloseDLL", GetType(CloseDLLDelegate)), CloseDLLDelegate)

            m_romOpenDelegate = CType(GetDelegate("RomOpen", GetType(RomOpenDelegate)), RomOpenDelegate)
            m_romClosedDelegate = CType(GetDelegate("RomClosed", GetType(RomClosedDelegate)), RomClosedDelegate)
        End Sub

        Private m_dllName As String
        Private m_dllWrapper As UnmanagedDllWrapper

        Public Sub Dispose() Implements IDisposable.Dispose
            m_dllWrapper.Dispose()
        End Sub

        Private Delegate Sub DelegateGetPluginInfo(ByRef pluginInfo As PluginInfo)
        Private m_delegateGetDllInfo As DelegateGetPluginInfo
        Private Sub GetDllInfo(ByRef pluginInfo As PluginInfo)
            m_delegateGetDllInfo(pluginInfo)
        End Sub

        Private Delegate Sub DllAboutDelegate(ByVal parentWindow As IntPtr)
        Private m_dllAboutDelegate As DllAboutDelegate
        Friend Sub DllAbout(ByVal parentWindow As IntPtr)
            If Not m_dllAboutDelegate Is Nothing Then
                m_dllAboutDelegate(parentWindow)
            End If
        End Sub

        Private Delegate Sub DllTestDelegate(ByVal parentWindow As IntPtr)
        Private m_dllTestDelegate As DllTestDelegate
        Friend Sub DllTest(ByVal parentWindow As IntPtr)
            If Not m_dllTestDelegate Is Nothing Then
                m_dllTestDelegate(parentWindow)
            End If
        End Sub

        Private Delegate Sub DllConfigDelegate(ByVal parentWindow As IntPtr)
        Private m_dllConfigDelegate As DllConfigDelegate
        Friend Sub DllConfig(ByVal parentWindow As IntPtr)
            If Not m_dllConfigDelegate Is Nothing Then
                m_dllConfigDelegate(parentWindow)
            End If
        End Sub

        Private Delegate Sub CloseDLLDelegate()
        Private m_closeDLLDelegate As CloseDLLDelegate
        Friend Sub CloseDLL()
            If Not m_closeDLLDelegate Is Nothing Then
                m_closeDLLDelegate()
            End If
        End Sub

        Private Delegate Sub RomOpenDelegate()
        Private m_romOpenDelegate As RomOpenDelegate
        Friend Sub RomOpen()
            If Not m_romOpenDelegate Is Nothing Then
                m_romOpenDelegate()
            End If
        End Sub

        Private Delegate Sub RomClosedDelegate()
        Private m_romClosedDelegate As RomClosedDelegate
        Friend Sub RomClosed()
            If Not m_romClosedDelegate Is Nothing Then
                m_romClosedDelegate()
            End If
        End Sub

        Private m_pluginInfo As PluginInfo

        Public ReadOnly Property Name() As String
            Get
                Return m_pluginInfo.Name
            End Get
        End Property

        Public ReadOnly Property PluginType() As PluginType
            Get
                Return m_pluginInfo.Type
            End Get
        End Property

        Public ReadOnly Property Version() As Integer
            Get
                Return m_pluginInfo.Version
            End Get
        End Property

        Public ReadOnly Property IsNormalMemorySupported() As Boolean
            Get
                Return m_pluginInfo.NormalMemory
            End Get
        End Property

        Public ReadOnly Property IsBswapedMemorySupported() As Boolean
            Get
                Return m_pluginInfo.MemoryBswaped
            End Get
        End Property

        Protected Function GetDelegate( _
                    ByVal functionName As String, _
                    ByVal delegateType As Type _
                    ) As [Delegate]

            Dim pointer As IntPtr = m_dllWrapper.GetProcAddress(functionName)
            If pointer = IntPtr.Zero Then
                Return Nothing
            End If

            Return Marshal.GetDelegateForFunctionPointer(pointer, delegateType)
        End Function

        ' the nested private class that allocates and release the unmanaged resource
        Private Class UnmanagedDllWrapper
            Implements IDisposable

            Public Handle As IntPtr

            Public Sub New(ByVal dllName As String)
                Me.Handle = LoadLibrary(dllName)
                If Me.Handle = IntPtr.Zero Then
                    Throw New Win32Exception()
                End If
            End Sub

            ' the Dispose method can be invoked only by the parent class
            Public Sub Dispose() Implements System.IDisposable.Dispose
                Dispose(True)
                GC.SuppressFinalize(Me)
            End Sub

            ' the finalizer
            Protected Overrides Sub Finalize()
                Dispose(False)
            End Sub

            ' This is where the unmanaged resource is actually disposed of.
            ' Notice that it takes an argument only for compliance with .NET coding standards
            ' but the disposing argument is never used, because in all cases this class
            ' can access and release only the single unmanaged resource it wraps.
            Private Sub Dispose(ByVal disposing As Boolean)
                ' exit now if this object didn't completed its constructor correctly
                If Me.Handle = IntPtr.Zero Then
                    Return
                End If

                ' release the unmanaged resource
                FreeLibrary(Me.Handle)

                ' finally, invalidate the handle
                Me.Handle = IntPtr.Zero
            End Sub

            Public Function GetProcAddress(ByVal procName As String) As IntPtr
                Return GetProcAddress(Me.Handle, procName)
            End Function

            <DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
            Private Shared Function LoadLibrary(ByVal dllName As String) As IntPtr
            End Function

            <DllImport("kernel32.dll")> _
            Private Shared Function GetProcAddress(ByVal dllHandle As IntPtr, ByVal procName As String) As IntPtr
            End Function

            <DllImport("kernel32.dll")> _
            Private Shared Function FreeLibrary(ByVal dllHandle As IntPtr) As Integer
            End Function

        End Class

    End Class

End Namespace

To use the class, you can do something like this:

Code:
Using plugin As New Plugin("C:\YourPath\YourPluggin.dll")
    plugin.DllAbout(myform.Handle)

    Dim pluginType As String = plugin.PluginType
    Dim pluginName As String = plugin.Name
    ...

End Using ' End Using automaticly call the Dispose method, which release the handle on the loaded dll

You should know that some plugin cannot be loaded in .Net. By example, most of the Jabo plugin throw an "Invalid access to memory location" exception on LoadLibrary. My guess is that those plugin are doing stuff in their "DllMain" function that doesn't work with the .Net runtime.

Hope this help.
 

Top