C#实现动态调用Windows DLL

本文介绍了一种在C#中动态调用Windows DLL的方法。通过使用P/Invoke机制,可以实现从托管代码到本地Windows API函数的调用。具体包括加载DLL、获取函数地址、构建调用方法模型等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

调用方法: 
 
object obj = WinDllInvoke("Kernel32.dll", "Beep", 
             new object[] { 750, 300 }, typeof(void));


函数代码: 
[System.Runtime.InteropServices.DllImport("kernel32")]
private static extern IntPtr LoadLibrary(string lpLibFileName);

[System.Runtime.InteropServices.DllImport("kernel32")]
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);

[System.Runtime.InteropServices.DllImport("kernel32")]
private static extern IntPtr FreeLibrary(IntPtr hLibModule);

/// <summary>
/// 动态调用Windows DLL
/// </summary>
/// <param name="fileName">Dll文件名</param>
/// <param name="funName">待调用的函数名</param>
/// <param name="objParams">函数参数</param>
/// <param name="returnType">返回值</param>
/// <returns>调用结果</returns>
private static object WinDllInvoke(string fileName, string funName, 
     object[] objParams, Type returnType)
{
    IntPtr libHandle = IntPtr.Zero;

    try
    {
        //获取函数地址
        libHandle = LoadLibrary(fileName);
        if (libHandle == IntPtr.Zero)
            return null;
        IntPtr procAddres = GetProcAddress(libHandle, funName);
        if (procAddres == IntPtr.Zero)
            return null;

        //获取参数类型
        Type[] paramTypes = new Type[objParams.Length];
        for (int i = 0; i < objParams.Length; ++i)
        {
            paramTypes[i] = objParams[i].GetType();
        }

        //构建调用方法模型
        AssemblyName asembyName = new AssemblyName();
        asembyName.Name = "WinDllInvoke_Assembly";
        AssemblyBuilder asembyBuilder = 
             AppDomain.CurrentDomain.DefineDynamicAssembly(asembyName,
             AssemblyBuilderAccess.Run);
        ModuleBuilder moduleBuilder = asembyBuilder.DefineDynamicModule("WinDllInvoke");
        MethodBuilder methodBuilder = moduleBuilder.DefineGlobalMethod("InvokeFun",
             MethodAttributes.Public | MethodAttributes.Static, returnType, paramTypes);

        //获取一个 ILGenerator ,用于发送所需的 IL 
        ILGenerator IL = methodBuilder.GetILGenerator();
        for (int j = 0; j < paramTypes.Length; ++j)
        {
            //将参数压入堆栈
            if (paramTypes[j].IsValueType)
            {
                IL.Emit(OpCodes.Ldarg, j); //By Value
            }
            else
            {
                IL.Emit(OpCodes.Ldarga, j); //By Addrsss
            }
        }

        // 判断处理器类型
        if (IntPtr.Size == 4)
        {
            IL.Emit(OpCodes.Ldc_I4, procAddres.ToInt32());
        }
        else if (IntPtr.Size == 8)
        {
            IL.Emit(OpCodes.Ldc_I8, procAddres.ToInt64());
        }
        else
        {
            throw new PlatformNotSupportedException("不好意思,偶不认得你哦!");
        }

        IL.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, returnType, paramTypes);
        IL.Emit(OpCodes.Ret); // 返回值 
        moduleBuilder.CreateGlobalFunctions();

        // 取得方法信息 
        MethodInfo methodInfo = moduleBuilder.GetMethod("InvokeFun");

        return methodInfo.Invoke(null, objParams);// 调用方法,并返回其值
    }
    catch { return null; }
    finally
    {
        if (libHandle != IntPtr.Zero)
            FreeLibrary(libHandle); //释放资源
    }
}

 

转载于:https://www.cnblogs.com/jordan2009/p/3696372.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值