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:
AttributeError: 'Foo' object has no attribute '__name__'
So I've created a similar code in C#:
public class MultiSourcePaged {
public static void main(String[] args) {
Observable<String> localDatabase = Observable.empty();
PublishSubject<String> externalSource = PublishSubject.create();
Observable<String> serverDatabase = Observable.just("a", "b", "c");
Observable<String> messages = Observable.merge(
// use local database or switch to server
localDatabase.switchIfEmpty(serverDatabase),
// merge in messages from outside
externalSource.onBackpressureBuffer()
);
UISubscriber s = new UISubscriber();
messages.subscribe(s);
System.out.println("Retrieveing the first page...");
s.requestMore(2);
externalSource.onNext("d");
externalSource.onNext("e");
externalSource.onNext("f");
System.out.println("Retrieveing the second page...");
s.requestMore(2);
externalSource.onCompleted();
System.out.println("Retrieveing the third page...");
s.requestMore(2);
System.out.println("Retrieveing the fourth page...");
s.requestMore(2);
}
static final class UISubscriber extends Subscriber<String> {
@Override
public void onStart() {
request(0);
}
@Override
public void onNext(String t) {
System.out.println("Message: " + t);
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onCompleted() {
System.out.println("No more messages!");
}
public void requestMore(long n) {
request(n);
}
}
}
However, on the line with in_mp3_lib = LoadLibraryW(path);
if (in_mp3_lib)
{
PluginGetter pluginGetter = (PluginGetter)GetProcAddress(in_mp3_lib, "winampGetInModule2");
if (pluginGetter)
{
in_mp3 = pluginGetter();
}
}
, an error (not exception) window is shown:
[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();
And LoadLibrary
is null.
Apparently, the plugin tries to load msvcrt90.dll, but this error keeps showing even if I have it in the directory.
Problem solved, next one has arised.
答案 0 :(得分:3)
解决。
向项目添加清单。在清单贴的末尾:
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.30729.4926" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b" />
</dependentAssembly>
</dependency>
(应该已经有一个评论示例<dependency>
)
这将使用WinSxS中的Microsoft.VC90.CRT。转到项目的属性,然后在Application-&gt; Resources中选中您的Manifest。
现在进入项目的属性,然后停用 Enable the Visual Studio hosting project
。
您需要将in_midi.dll
放在.exe的同一个文件夹中。
现在应该可以了。
作为参考,我使用:
class Program
{
[DllImport("kernel32", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, EntryPoint = "LoadLibraryW", ExactSpelling = true, SetLastError = true)]
static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate IntPtr PluginGetter();
static void Main(string[] args)
{
IntPtr hmod = LoadLibrary("in_midi.dll");
if (hmod == IntPtr.Zero)
{
throw new Win32Exception();
}
IntPtr proc = GetProcAddress(hmod, "winampGetInModule2");
if (proc == IntPtr.Zero)
{
throw new Win32Exception();
}
PluginGetter getmod = (PluginGetter)Marshal.GetDelegateForFunctionPointer(proc, typeof(PluginGetter));
IntPtr modptr = getmod();
if (modptr == IntPtr.Zero)
{
throw new Win32Exception();
}
Console.WriteLine("Success");
}
}
如果您需要,我可以将整个项目压缩过来。
对于第二个问题......遗憾的是,该函数返回指向struct
的指针。这是C#中的一个问题。如果您只需要从该结构中读取,那将很容易,但您必须对其进行修改。您可以使用Marshal.PtrToStructure
+ Marshal.StructureToPtr
,但我认为这不是一个好主意(有代表和字符串需要编组......我不想要想想会发生什么)。我最后一次需要这样做,我做了全手动编组:
[StructLayout(LayoutKind.Sequential)]
public class In_Module //ported from IN2.H in the Winamp SDK, struct size 152
{
[DllImport("kernel32", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, EntryPoint = "LoadLibraryW", ExactSpelling = true, SetLastError = true)]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
private static readonly int OffsetOfMethodTable = sizeof(int) + IntPtr.Size + IntPtr.Size + IntPtr.Size + IntPtr.Size + sizeof(int) + sizeof(int);
IntPtr Ptr;
public void LoadMidiModule()
{
IntPtr hmod = LoadLibrary("in_midi.dll");
if (hmod == IntPtr.Zero)
{
throw new Win32Exception();
}
IntPtr proc = GetProcAddress(hmod, "winampGetInModule2");
if (proc == IntPtr.Zero)
{
throw new Win32Exception();
}
PluginGetter getmod = (PluginGetter)Marshal.GetDelegateForFunctionPointer(proc, typeof(PluginGetter));
Ptr = getmod();
if (Ptr == IntPtr.Zero)
{
throw new Exception();
}
hDllInstance = hmod;
config = GetDelegate<ConfigFunc>(0 * IntPtr.Size);
about = GetDelegate<AbountFunc>(1 * IntPtr.Size);
init = GetDelegate<InitFunc>(2 * IntPtr.Size);
quit = GetDelegate<QuitFunc>(3 * IntPtr.Size);
getFileInfo = GetDelegate<GetFileInfoFunc>(4 * IntPtr.Size);
infoBox = GetDelegate<InfoBoxFunc>(5 * IntPtr.Size);
isOurFile = GetDelegate<IsOurFileFunc>(6 * IntPtr.Size);
play = GetDelegate<PlayFunc>(7 * IntPtr.Size);
pause = GetDelegate<PauseFunc>(8 * IntPtr.Size);
unPause = GetDelegate<UnPauseFunc>(9 * IntPtr.Size);
isPaused = GetDelegate<IsPausedFunc>(10 * IntPtr.Size);
stop = GetDelegate<StopFunc>(11 * IntPtr.Size);
getLength = GetDelegate<GetLengthFunc>(12 * IntPtr.Size);
getOutputTime = GetDelegate<GetOutputTimeFunc>(13 * IntPtr.Size);
setOutputTime = GetDelegate<SetOutputTimeFunc>(14 * IntPtr.Size);
setVolume = GetDelegate<SetVolumeFunc>(15 * IntPtr.Size);
setPan = GetDelegate<SetPanFunc>(16 * IntPtr.Size);
savsaInit = GetDelegate<SAVSAInitFunc>(17 * IntPtr.Size);
savsaDeInit = GetDelegate<SAVSADeInitFunc>(18 * IntPtr.Size);
saAddPCMData = GetDelegate<SAAddPCMDataFunc>(19 * IntPtr.Size);
saGetMode = GetDelegate<SAGetModeFunc>(20 * IntPtr.Size);
saAdd = GetDelegate<SAAddFunc>(21 * IntPtr.Size);
vsaAddPCMData = GetDelegate<VSAAddPCMDataFunc>(22 * IntPtr.Size);
vsaGetMode = GetDelegate<VSAGetModeFunc>(23 * IntPtr.Size);
vsaAdd = GetDelegate<VSAAddFunc>(24 * IntPtr.Size);
vsaSetInfo = GetDelegate<VSASetInfoFunc>(25 * IntPtr.Size);
dsp_isactive = GetDelegate<DSP_isactiveFunc>(26 * IntPtr.Size);
dsp_dosamples = GetDelegate<DSP_dosamplesFunc>(27 * IntPtr.Size);
eqSet = GetDelegate<EQSetFunc>(28 * IntPtr.Size);
setInfo = GetDelegate<SetInfoFunc>(29 * IntPtr.Size);
}
private TDelegate GetDelegate<TDelegate>(int offset)
{
IntPtr ptr = Marshal.ReadIntPtr(Ptr, OffsetOfMethodTable + offset);
if (ptr == IntPtr.Zero)
{
return default(TDelegate);
}
return (TDelegate)(object)Marshal.GetDelegateForFunctionPointer(ptr, typeof(TDelegate));
}
private void SetDelegate<TDelegate>(TDelegate del, ref TDelegate field, int offset)
{
field = del;
IntPtr ptr = Marshal.GetFunctionPointerForDelegate((Delegate)(object)del);
Marshal.WriteIntPtr(Ptr, OffsetOfMethodTable + offset, ptr);
}
public int version
{
get
{
return Marshal.ReadInt32(Ptr, 0);
}
}
public string description
{
get
{
return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(Ptr, sizeof(int)));
}
}
public IntPtr hMainWindow
{
get
{
return Marshal.ReadIntPtr(Ptr, sizeof(int) + IntPtr.Size);
}
set
{
Marshal.WriteIntPtr(Ptr, sizeof(int) + IntPtr.Size, value);
}
}
public IntPtr hDllInstance
{
get
{
return Marshal.ReadIntPtr(Ptr, sizeof(int) + IntPtr.Size + IntPtr.Size);
}
set
{
Marshal.WriteIntPtr(Ptr, sizeof(int) + IntPtr.Size + IntPtr.Size, value);
}
}
public string FileExtensions
{
get
{
return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(Ptr, sizeof(int) + IntPtr.Size + IntPtr.Size + IntPtr.Size));
}
}
public int is_seekable
{
get
{
return Marshal.ReadInt32(Ptr, sizeof(int) + IntPtr.Size + IntPtr.Size + IntPtr.Size + IntPtr.Size);
}
}
public int UsesOutputPlug
{
get
{
return Marshal.ReadInt32(Ptr, sizeof(int) + IntPtr.Size + IntPtr.Size + IntPtr.Size + IntPtr.Size + sizeof(int));
}
}
private ConfigFunc config;
public ConfigFunc Config
{
get
{
return config;
}
}
private AbountFunc about;
public AbountFunc About
{
get
{
return about;
}
}
private InitFunc init;
public InitFunc Init
{
get
{
return init;
}
}
private QuitFunc quit;
public QuitFunc Quit
{
get
{
return quit;
}
}
private GetFileInfoFunc getFileInfo;
public GetFileInfoFunc GetFileInfo
{
get
{
return getFileInfo;
}
}
private InfoBoxFunc infoBox;
public InfoBoxFunc InfoBox
{
get
{
return infoBox;
}
}
private IsOurFileFunc isOurFile;
public IsOurFileFunc IsOurFile
{
get
{
return isOurFile;
}
}
private PlayFunc play;
public PlayFunc Play
{
get
{
return play;
}
}
private PauseFunc pause;
public PauseFunc Pause
{
get
{
return pause;
}
}
private UnPauseFunc unPause;
public UnPauseFunc UnPause
{
get
{
return unPause;
}
}
private IsPausedFunc isPaused;
public IsPausedFunc IsPaused
{
get
{
return isPaused;
}
}
private StopFunc stop;
public StopFunc Stop
{
get
{
return stop;
}
}
private GetLengthFunc getLength;
public GetLengthFunc GetLength
{
get
{
return getLength;
}
}
private GetOutputTimeFunc getOutputTime;
public GetOutputTimeFunc GetOutputTime
{
get
{
return getOutputTime;
}
}
private SetOutputTimeFunc setOutputTime;
public SetOutputTimeFunc SetOutputTime
{
get
{
return setOutputTime;
}
}
private SetVolumeFunc setVolume;
public SetVolumeFunc SetVolume
{
get
{
return setVolume;
}
}
private SetPanFunc setPan;
public SetPanFunc SetPan
{
get
{
return setPan;
}
}
private SAVSAInitFunc savsaInit;
public SAVSAInitFunc SAVSAInit
{
get
{
return savsaInit;
}
set
{
SetDelegate(value, ref savsaInit, 17 * IntPtr.Size);
}
}
private SAVSADeInitFunc savsaDeInit;
public SAVSADeInitFunc SAVSADeInit
{
get
{
return savsaDeInit;
}
set
{
SetDelegate(value, ref savsaDeInit, 18 * IntPtr.Size);
}
}
private SAAddPCMDataFunc saAddPCMData;
public SAAddPCMDataFunc SAAddPCMData
{
get
{
return saAddPCMData;
}
set
{
SetDelegate(value, ref saAddPCMData, 19 * IntPtr.Size);
}
}
private SAGetModeFunc saGetMode;
public SAGetModeFunc SAGetMode
{
get
{
return saGetMode;
}
set
{
SetDelegate(value, ref saGetMode, 20 * IntPtr.Size);
}
}
private SAAddFunc saAdd;
public SAAddFunc SAAdd
{
get
{
return saAdd;
}
set
{
SetDelegate(value, ref saAdd, 21 * IntPtr.Size);
}
}
private VSAAddPCMDataFunc vsaAddPCMData;
public VSAAddPCMDataFunc VSAAddPCMData
{
get
{
return vsaAddPCMData;
}
set
{
SetDelegate(value, ref vsaAddPCMData, 22 * IntPtr.Size);
}
}
private VSAGetModeFunc vsaGetMode;
public VSAGetModeFunc VSAGetMode
{
get
{
return vsaGetMode;
}
set
{
SetDelegate(value, ref vsaGetMode, 23 * IntPtr.Size);
}
}
private VSAAddFunc vsaAdd;
public VSAAddFunc VSAAdd
{
get
{
return vsaAdd;
}
set
{
SetDelegate(value, ref vsaAdd, 24 * IntPtr.Size);
}
}
private VSASetInfoFunc vsaSetInfo;
public VSASetInfoFunc VSASetInfo
{
get
{
return vsaSetInfo;
}
set
{
SetDelegate(value, ref vsaSetInfo, 25 * IntPtr.Size);
}
}
private DSP_isactiveFunc dsp_isactive;
public DSP_isactiveFunc DSP_isactive
{
get
{
return dsp_isactive;
}
set
{
SetDelegate(value, ref dsp_isactive, 26 * IntPtr.Size);
}
}
private DSP_dosamplesFunc dsp_dosamples;
public DSP_dosamplesFunc DSP_dosamples
{
get
{
return dsp_dosamples;
}
set
{
SetDelegate(value, ref dsp_dosamples, 27 * IntPtr.Size);
}
}
private EQSetFunc eqSet;
public EQSetFunc EQSet
{
get
{
return eqSet;
}
}
private SetInfoFunc setInfo;
public SetInfoFunc SetInfo
{
get
{
return setInfo;
}
set
{
SetDelegate(value, ref setInfo, 29 * IntPtr.Size);
}
}
public IntPtr OutMod
{
get
{
return Marshal.ReadIntPtr(Ptr, OffsetOfMethodTable + 30 * IntPtr.Size);
}
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate IntPtr PluginGetter();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ConfigFunc(IntPtr hwndParent);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void AbountFunc(IntPtr hwndParent);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void InitFunc();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void QuitFunc();
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public delegate void GetFileInfoFunc(string file, string title, out int length_in_ms);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int InfoBoxFunc(string file, IntPtr hwndParent);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int IsOurFileFunc(string fn);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int PlayFunc(string fn);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void PauseFunc();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void UnPauseFunc();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int IsPausedFunc();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void StopFunc();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int GetLengthFunc(); // get length in ms
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int GetOutputTimeFunc(); // returns current output time in ms. (usually returns outMod->GetOutputTime()
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
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()..
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void SetVolumeFunc(int volume); // from 0 to 255.. usually just call outMod->SetVolume
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void SetPanFunc(int pan); // from -127 to 127.. usually just call outMod->SetPan
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
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()
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void SAVSADeInitFunc(); // call in Stop()
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void SAAddPCMDataFunc(IntPtr PCMData, int nch, int bps, int timestamp);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int SAGetModeFunc(); // gets csa (the current type (4=ws,2=osc,1=spec))
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int SAAddFunc(IntPtr data, int timestamp, int csa); // sets the spec data, filled in by winamp
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void VSAAddPCMDataFunc(IntPtr PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int VSAGetModeFunc(out int specNch, out int waveNch); // use to figure out what to give to VSAAdd
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int VSAAddFunc(IntPtr data, int timestamp); // filled in by winamp, called by plug-in
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void VSASetInfoFunc(int srate, int nch); // <-- Correct (benski, dec 2005).. old declaration had the params backwards
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int DSP_isactiveFunc();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int DSP_dosamplesFunc(ref short samples, int numsamples, int bps, int nch, int srate);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void EQSetFunc(int on, byte[] data, int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void SetInfoFunc(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :)
}
我已经为你需要实施的功能设置了一个setter。
使用它像:
var mod = new In_Module();
mod.LoadMidiModule();
//var form = new Form1();
// Doesn't work, but looking at
// http://dolphin-emu.googlecode.com/svn-history/r3174/trunk/Externals/MusicMod/Player/Src/InputPlugin.cpp
// it seems that the plugins often try to hook the WindowProc.
// I'm not sure if it is ok in Winforms
//mod.hMainWindow = form.Handle;
mod.Init();
// Note that you will have to implement:
//SAVSAInit
//SAVSADeInit
//SAAddPCMData
//SAGetMode
//SAAdd
//VSAAddPCMData
//VSAGetMode
//VSAAdd
//VSASetInfo
//dsp_dosamples
//dsp_isactive
//SetInfo
注意评论!