使用可变数量的函数

时间:2015-06-04 13:04:13

标签: c# dll unmanaged

Ex:在app1中,用户创建了function_1()和function_2()。然后在app2用户想要调用function_2()。我在google上搜索过,我发现的唯一一件事是编写这段代码:

    class Program
{
    [DllImport("functions.dll")]
    public static extern void function_1();


    static void Main(string[] args)
    {
        function_1();
    }
}

3 个答案:

答案 0 :(得分:3)

您必须使用一些PInvoke代码来加载DLL(LoadLibrary)并获取函数指针(GetProcAddess)和Marshal.GetDelegateForFunctionPointer以获取您可以使用的委托然后调用。

答案 1 :(得分:0)

Damien所写的完整示例...请注意,只有方法具有相同的签名(在此示例中为void function_X())时才有效。另外,探索一个dll以发现导出的方法是“困难的”,所以如果你已经知道dll中应该有哪些方法,那就更好了。

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

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

// Set the correct calling convention
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate void DllMethodDelegate();

IntPtr dll = LoadLibrary(@"PathToYourDll.DLL");

if (dll == IntPtr.Zero)
{
    throw new Exception();
}

string methodName = "function_1";

IntPtr method = GetProcAddress(dll, methodName);

if (method == IntPtr.Zero)
{
    throw new Exception();
}

DllMethodDelegate method2 = (DllMethodDelegate)Marshal.GetDelegateForFunctionPointer(method, typeof(DllMethodDelegate));

// Now you can do method2();

请注意,您必须在DllMethodDelegate()定义中设置正确的调用约定。通常,dll方法应为StdCall

您编写的方法的签名是:

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private delegate int DllMethodDelegate(char cmd, ref IntPtr out_address);

请注意,“填充”out_address非常复杂(头痛复杂)。

{
    // I case:
    IntPtr ret = IntPtr.Zero;
    int result = method2('I', ref ret);
}

{
    // R case:
    IntPtr ptr = IntPtr.Zero;

    int result = method2('R', ref ptr);

    int value = Marshal.ReadInt32(ptr);
}

{
    // W case:
    int value = 100;

    GCHandle handle = default(GCHandle);

    try
    {
        int[] value2 = new int[] { value };

        handle = GCHandle.Alloc(value2, GCHandleType.Pinned);
        IntPtr ptr = handle.AddrOfPinnedObject();

        int result = method2('W', ref ptr);
    }
    finally
    {
        if (handle.IsAllocated)
        {
            handle.Free();
        }
    }
}

有可能(但我不确定)对于第三个例子,你可以做

object value2 = value;

而不是

int[] value2 = new int[] { value };

拳击与GCHandle的互动并没有很好的记录,但似乎有效。 C#规范4.3似乎没问题......但我不相信它,这种技术似乎在“.NET和COM:完整互操作性指南”一书的“获取值类型的地址”一章中有所描述。 “(该章在谷歌中是可搜索的,请使用我给出的确切章节标题。示例在VB.NET中,但读起来很清楚)

答案 2 :(得分:0)

您可以使用dbghelp dll中的SymEnumerateSymbols64来获取DLL中现有函数的列表。然后用户可以选择要运行的功能。

您可以在此处找到更详细的说明: C# get the list of unmanaged C dll exports