在制作跨平台游戏时,我发现需要一个跨平台的DLL链接器,我的DLL链接器类似乎符合标准"但它只能在Windows机器上运行,而它可以在Window和Linux机器上运行。
这是由于dlsym( IntPtr handle, string symbol )
返回IntPtr.Zero
而GetProcAddress( IntPtr hModule, string lpProcName )
返回指向所需符号的有效IntPtr
。
public static class DLL
{
#region DllImport
[DllImport( "kernel32.dll" )]
private static extern IntPtr LoadLibrary( string filename );
[DllImport( "kernel32.dll" )]
private static extern IntPtr GetProcAddress( IntPtr hModule, string procname );
[DllImport( "libdl.so" )]
private static extern IntPtr dlopen( string filename, int flags );
[DllImport( "libdl.so" )]
private static extern IntPtr dlsym( IntPtr handle, string symbol );
const int RTLD_NOW = 2;
#endregion
#region Abstracted
public static bool __linux__
{
get
{
int p = (int)Environment.OSVersion.Platform;
return ( p == 4 ) || ( p == 6 ) || ( p == 128 );
}
}
#endregion
#region Fields
private static Type _delegateType = typeof( MulticastDelegate );
#endregion
#region Methods
public static IntPtr Load( string filename )
{
IntPtr mHnd;
if ( __linux__ )
mHnd = dlopen( filename, RTLD_NOW );
else
mHnd = LoadLibrary( filename );
return mHnd;
}
public static IntPtr Symbol( IntPtr mHnd, string symbol )
{
IntPtr symPtr;
if ( __linux__ )
symPtr = dlsym( mHnd, symbol );
else
symPtr = GetProcAddress( mHnd, symbol );
return symPtr;
}
public static Delegate Delegate( Type delegateType, IntPtr mHnd, string symbol )
{
IntPtr ptrSym = Symbol( mHnd, symbol );
return Marshal.GetDelegateForFunctionPointer( ptrSym, delegateType );
}
public static void LinkAllDelegates( Type ofType, IntPtr mHnd )
{
FieldInfo[] fields = ofType.GetFields( BindingFlags.Public | BindingFlags.Static );
foreach ( FieldInfo fi in fields )
{
if ( fi.FieldType.BaseType == _delegateType )
{
fi.SetValue( null, Marshal.GetDelegateForFunctionPointer( Symbol( mHnd, fi.Name ), fi.FieldType ) );
}
}
}
#endregion
}
我使用这个自定义类来(部分)加载LZ4:
public static class LZ4
{
private static string _lib = "lz4.dll";
private static IntPtr _dllHnd;
#region Delegates
public delegate int PFNLZ4_COMPRESS_DEFAULTPROC( IntPtr source, IntPtr dest, int sourceSize, int maxDestSize );
public delegate int PFNLZ4_COMPRESS_FASTPROC( IntPtr source, IntPtr dest, int sourceSize, int maxDestSize, int acceleration );
public delegate int PFNLZ4_COMPRESS_HCPROC( IntPtr src, IntPtr dst, int srcSize, int dstCapacity, int compressionLevel );
public delegate int PFNLZ4_DECOMPRESS_FASTPROC( IntPtr source, IntPtr dest, int originalSize );
public delegate int PFNLZ4_COMPRESSBOUNDPROC( int inputSize );
#endregion
#region Methods
public static void LZ4_Link()
{
if ( DLL.__linux__ )
_lib = "./liblz4.so";
_dllHnd = DLL.Load( _lib );
Console.WriteLine( "LZ4_Link: OS is {0}", DLL.__linux__ ? "Linux" : "Windows" );
Console.WriteLine( "LZ4_Link: Linked {0}", _lib );
Console.WriteLine( "LZ4_Link: _dllHnd -> 0x{0}", _dllHnd.ToString( "X" ) );
DLL.LinkAllDelegates( typeof( LZ4 ), _dllHnd );
}
public static PFNLZ4_COMPRESS_DEFAULTPROC LZ4_compress_default;
public static PFNLZ4_COMPRESS_FASTPROC LZ4_compress_fast;
public static PFNLZ4_COMPRESS_HCPROC LZ4_compress_HC;
public static PFNLZ4_DECOMPRESS_FASTPROC LZ4_decompress_fast;
public static PFNLZ4_COMPRESSBOUNDPROC LZ4_compressBound;
#endregion
}
如上所述,每个dlsym
调用都会返回IntPtr.Zero
(NULL
),而Windows"等同于"工作得很好。
答案 0 :(得分:0)
似乎名称错误/发布差异是问题。
lz4.dll
导出LZ4_decompress_default
,而liblz4.so
导出LZ4_decompress
。