Использование Winamp's in_midi.dll в.NET

Я пытаюсь загрузить плагин ввода Winamp и работать с ним в C#. Согласно Winamp SDK, это правильный способ загрузки плагина:

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

Итак, я создал похожий код в C#, узнав, как добавить зависимость msvcr90.dll в манифест:

[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? :)
}

Тем не менее, называя Init() функция вызывает AccessViolationException. Я сначала получаю структуру к In_Module объект в памяти, обновляя его, а затем помещая обратно, для обновления модуля. Исключение выдается без кода обновления, даже если я поставил [UnmanagedFunctionPointer(CallingConvention.Cdecl)] на всех делегатов.

0 ответов

Другие вопросы по тегам