本文介绍了dlsym返回NULL,其中GetProcAddress返回有效的IntPtr的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在制作跨平台游戏时,我发现需要跨平台DLL链接器,但我的DLL链接器类似乎符合标准",但仅适用于Windows计算机,而设计用于两者Window和Linux机器.

While making a cross-platform game I found the need for a cross-platform DLL linker, my DLL linker class seems to be "up to standards" but it only works on Windows machines, while it is designed to work on both Window and Linux machines.

这是由于dlsym( IntPtr handle, string symbol )返回IntPtr.ZeroGetProcAddress( IntPtr hModule, string lpProcName )返回了指向所需符号的有效IntPtr.

This is due to dlsym( IntPtr handle, string symbol ) returning IntPtr.Zero whereas GetProcAddress( IntPtr hModule, string lpProcName ) returns a valid IntPtr pointing to the desired symbol.

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:

I used this custom class to (partially) load LZ4 as such:

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的等效"功能正常.

As said, every dlsym call returns IntPtr.Zero (NULL), whereas the Windows "equivalent" works just fine.

推荐答案

似乎是名称更改/发布差异之类的问题.lz4.dll导出了LZ4_decompress_default,而liblz4.so导出了LZ4_decompress.

Seems like name mangling/release differences were the issue.lz4.dll exported LZ4_decompress_default, whereas liblz4.so exported LZ4_decompress.

这篇关于dlsym返回NULL,其中GetProcAddress返回有效的IntPtr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 05:40