Using Winamp's in_midi.dll in .NET

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-25 08:56:41

问题


I am trying to load a Winamp input plugin and work with it in C#. According to the Winamp SDK, this is the proper way to load a plugin:

in_mp3_lib = LoadLibraryW(path);
if (in_mp3_lib)
{
    PluginGetter pluginGetter = (PluginGetter)GetProcAddress(in_mp3_lib, "winampGetInModule2");
    if (pluginGetter)
    {
        in_mp3 = pluginGetter();
    }
}

So I've created a similar code in C#, after learning how to add a msvcr90.dll dependency to the manifest:

[DllImport("kernel32", SetLastError=true, CharSet=CharSet.Unicode)]
static extern IntPtr LoadLibrary(string lpFileName);

[DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

delegate IntPtr PluginGetter();

IntPtr hmod = LoadLibrary("in_midi.dll");
var getmod = (PluginGetter)Marshal.GetDelegateForFunctionPointer(GetProcAddress(hmod, "winampGetInModule2"), typeof(PluginGetter));
IntPtr modptr = getmod();

In_Module mod = (In_Module)Marshal.PtrToStructure(modptr, typeof(In_Module));
Form form = new Form();
IntPtr hwnd = form.Handle;
mod.hMainWindow = hwnd;
mod.hDllInstance = hmod;
Marshal.StructureToPtr(mod, modptr, false);
mod.Init(); //exception here

[StructLayout(LayoutKind.Sequential)]
public struct In_Module //ported from IN2.H in the Winamp SDK
{
    public int version;
    public string description;
    public IntPtr hMainWindow;
    public IntPtr hDllInstance;
    public string FileExtensions;
    public int is_seekable;
    public int UsesOutputPlug;
    public ConfigFunc Config;
    public AbountFunc About;
    public InitFunc Init;
    public QuitFunc Quit;
    public GetFileInfoFunc GetFileInfo;
    public InfoBoxFunc InfoBox;
    public IsOurFileFunc IsOurFile;
    public PlayFunc Play;
    public PauseFunc Pause;
    public UnPauseFunc UnPause;
    public IsPausedFunc IsPaused;
    public StopFunc Stop;
    public GetLengthFunc GetLength;
    public GetOutputTimeFunc GetOutputTime;
    public SetOutputTimeFunc SetOutputTime;
    public SetVolumeFunc SetVolume;
    public SetPanFunc SetPan;
    public SAVSAInitFunc SAVSAInit;
    public SAVSADeInitFunc SAVSADeInit;
    public SAAddPCMDataFunc SAAddPCMData;
    public SAGetModeFunc SAGetMode;
    public SAAddFunc SAAdd;
    public VSAAddPCMDataFunc VSAAddPCMData;
    public VSAGetModeFunc VSAGetMode;
    public VSAAddFunc VSAAdd;
    public VSASetInfoFunc VSASetInfo;
    public dsp_isactiveFunc dsp_isactive;
    public dsp_dosamplesFunc dsp_dosamples;
    public IntPtr EQSet;
    public SetInfoFunc SetInfo;
    public IntPtr outMod;

    public delegate void ConfigFunc(IntPtr hwndParent);
    public delegate void AbountFunc(IntPtr hwndParent);
    public delegate void InitFunc();
    public delegate void QuitFunc();
    public delegate void GetFileInfoFunc(string file, StringBuilder title, out int length_in_ms);
    public delegate int InfoBoxFunc(string file, IntPtr hwndParent);
    public delegate int IsOurFileFunc(string fn);
    public delegate int PlayFunc(string fn);
    public delegate void PauseFunc();
    public delegate void UnPauseFunc();
    public delegate int IsPausedFunc();
    public delegate void StopFunc();
    public delegate int GetLengthFunc();            // get length in ms
    public delegate int GetOutputTimeFunc();        // returns current output time in ms. (usually returns outMod->GetOutputTime()
    public delegate void SetOutputTimeFunc(int time_in_ms); // seeks to point in stream (in ms). Usually you signal your thread to seek, which seeks and calls outMod->Flush()..
    public delegate void SetVolumeFunc(int volume); // from 0 to 255.. usually just call outMod->SetVolume
    public delegate void SetPanFunc(int pan);   // from -127 to 127.. usually just call outMod->SetPan
    public delegate void SAVSAInitFunc(int maxlatency_in_ms, int srate);        // call once in Play(). maxlatency_in_ms should be the value returned from outMod->Open()
    public delegate void SAVSADeInitFunc(); // call in Stop()
    public delegate void SAAddPCMDataFunc(IntPtr PCMData, int nch, int bps, int timestamp); 
    public delegate int SAGetModeFunc();        // gets csa (the current type (4=ws,2=osc,1=spec))
    public delegate int SAAddFunc(IntPtr data, int timestamp, int csa); // sets the spec data, filled in by winamp
    public delegate void VSAAddPCMDataFunc(IntPtr PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data
    public delegate int VSAGetModeFunc(out int specNch, out int waveNch); // use to figure out what to give to VSAAdd
    public delegate int VSAAddFunc(IntPtr data, int timestamp); // filled in by winamp, called by plug-in
    public delegate void VSASetInfoFunc(int srate, int nch); // <-- Correct (benski, dec 2005).. old declaration had the params backwards
    public delegate int dsp_isactiveFunc(); 
    public delegate int dsp_dosamplesFunc(ref short samples, int numsamples, int bps, int nch, int srate);
    //public delegate void EQSetFunc(int on, [MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]byte[] data, int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore.
    public delegate void SetInfoFunc(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :)
}

However, calling the Init() function raises an AccessViolationException. I am first getting the structure to the In_Module object in the memory, updating it, and then putting it back, for the module to update. The exception is thrown without the update code, even if I put [UnmanagedFunctionPointer(CallingConvention.Cdecl)] on all delegates.

来源:https://stackoverflow.com/questions/30133014/using-winamps-in-midi-dll-in-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!