调用C+时,C#IL如何通过Ref返回参数+;动态链接库

调用C+时,C#IL如何通过Ref返回参数+;动态链接库,c#,c++,dll,clr,cil,C#,C++,Dll,Clr,Cil,C#程序需要调用dll,但看起来参数out与in的值相同。所以我做了一个简短的样本来测试。 这里是C++ DLL代码: h .cpp #包括“Header.h” #包括 void uu fastcall WhyWrong(内部和维护){ m++; } int main(){ int m=0; WhyWrong(m); std::cout>y; } C#代码: .cs 使用系统; 使用System.Runtime.InteropServices; 运用系统反思; 使用System.Reflect

C#程序需要调用dll,但看起来参数out与in的值相同。所以我做了一个简短的样本来测试。 这里是C++ DLL代码: h

.cpp

#包括“Header.h”
#包括
void uu fastcall WhyWrong(内部和维护){
m++;
}
int main(){
int m=0;
WhyWrong(m);
std::cout>y;
}
C#代码: .cs

使用系统;
使用System.Runtime.InteropServices;
运用系统反思;
使用System.Reflection.Emit;
名称空间DllTest
{
一班{
[DllImport(“Kernel32.dll”)]
私有静态外部IntPtr加载库(字符串lpFileName);
[DllImport(“Kernel32.dll”)]
私有静态外部布尔自由库(IntPtr hModule);
[DllImport(“Kernel32.dll”)]
私有静态外部IntPtr GetProcAddress(IntPtr hModule,字符串lpProcName);
[DllImport(“Kernel32.dll”)]
私有静态外部int GetLastError();
私有静态IntPtr hModule=IntPtr.Zero;
私有静态程序集名称GbsAssemblyName;
私有静态汇编生成器GbsAssemblyBuilder;
私有静态模块生成器GbsModuleBuilder;
公共枚举模式通行证{
ByValue=0x0001,
ByRef=0x0002
}
私有IntPtr GFuncPtr=IntPtr.Zero;
私有类型[]GParaType;
私人ILGIL;
专用ModePass[]GMdPass;
公共对象[]对象;
私有字符串Mname;
私有静态类型GReturn=typeof(void);
静态void Main(){
类1.DllIni();
Class1 G_WhyW=new Class1(新类型[1]{typeof(int)},新Class1.ModePass[1]{Class1.ModePass.ByRef},新对象[1]{(int)0});
G_WhyW.LoadFunc(“WhyWrong”);
Class1.GCreateGlbFunc();
G_WhyW.GObject[0]=(int)1;//输入
G_WhyW.InvokeDllFunc();
Console.WriteLine((int)G_WhyW.GObject[0]);
Console.ReadLine();
Class1.UnLoadDll();
}
公共静态无效DllIni(){
hModule=LoadLibrary(“DllTest.dll”);
if(hModule==IntPtr.Zero){
Console.WriteLine(“未加载DLL”);
int e=GetLastError();
Console.WriteLine(“错误代码:+e”);
}
GbsAssemblyName=新程序集名称();
GbsAssemblyName.Name=“GbsCore”;
GbsAssemblyBuilder=AppDomain.CurrentDomain.DefinedDynamicAssembly(GbsAssemblyName,AssemblyBuilderAccess.Run);
GbsModuleBuilder=GbsAssemblyBuilder.DefinedDynamicModule(“FuncGrp”);
}
公共静态void GCreateGlbFunc(){
GbsModuleBuilder.CreateGlobalFunctions();
}
public void LoadFunc(字符串lpProcName){
GFuncPtr=GetProcAddress(hModule,lpProcName);
if(GFuncPtr==IntPtr.Zero){
Console.WriteLine(“函数”+lpProcName+“未加载”);
}
Mname=lpProcName+“\u T”;
MethodBuilder GbsMethodBuilder=GbsModuleBuilder.DefineGlobalMethod(Mname,MethodAttributes.Public | MethodAttributes.Static,GReturn,GParaType);
GIL=GbsMethodBuilder.GetILGenerator();
if(GObject!=null){
for(int i=0;i

在调用函数WhyWrong之前,参数的值是1,但是我在尝试时得到的结果也是1。它应该是2,不是吗?

动态方法的这个签名是
void(int)
,而不是
void(ref int)
,因为它是用
新类型[]{typeof(int)}
初始化的

支持使用反射来调用具有引用参数的方法(并修改参数数组),因此,完全摆脱ModePass枚举,并在定义方法时使用
typeof(int).MakeByRefType()

整个
开关(GMdPass[i])
是不必要的。由于参数是通过引用提供的,因此它将作为引用本身提供给被调用函数(
ldarg
就足够了)

顺便问一下,你为什么不直接使用?它与动态方法基本相同,但应该更快。您只需要定义委托类型(非泛型)


另外,FastCall不受支持吗?

问题-您使用
LoadLibrary
而不是JU有什么原因吗
#define EtrpDll extern "C" __declspec(dllexport)
EtrpDll void __fastcall WhyWrong(int &m);
#include"Header.h"
#include<iostream>
void __fastcall WhyWrong(int &m) {
    m++;
}

int main() {
    int m = 0;
    WhyWrong(m);
    std::cout << m;
    int y;
    std::cin >> y;
}
using System;

using System.Runtime.InteropServices;
using System.Reflection;
using System.Reflection.Emit;

namespace DllTest
{
    class Class1 {
        [DllImport("Kernel32.dll")]
        private static extern IntPtr LoadLibrary(string lpFileName);
        [DllImport("Kernel32.dll")]
        private static extern bool FreeLibrary(IntPtr hModule);
        [DllImport("Kernel32.dll")]
        private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
        [DllImport("Kernel32.dll")]
        private static extern int GetLastError();
        private static IntPtr hModule = IntPtr.Zero;
        private static AssemblyName GbsAssemblyName;
        private static AssemblyBuilder GbsAssemblyBuilder;
        private static ModuleBuilder GbsModuleBuilder;
        public enum ModePass {
            ByValue = 0x0001,
            ByRef = 0x0002
        }

        private IntPtr GFuncPtr = IntPtr.Zero;
        private Type[] GParaType;
        private ILGenerator GIL;
        private ModePass[] GMdPass;
        public object[] GObject;
        private string Mname;

        private static Type GReturn = typeof(void);




        static void Main() {
            Class1.DllIni();
            Class1 G_WhyW = new Class1(new Type[1] { typeof(int) }, new Class1.ModePass[1] { Class1.ModePass.ByRef }, new object[1] { (int)0 });
            G_WhyW.LoadFunc("WhyWrong");
            Class1.GCreateGlbFunc();
            G_WhyW.GObject[0] = (int)1;//Input
            G_WhyW.InvokeDllFunc();
            Console.WriteLine((int)G_WhyW.GObject[0]);
            Console.ReadLine();
            Class1.UnLoadDll();
        }


        public static void DllIni(){
            hModule = LoadLibrary("DllTest.dll");
            if (hModule == IntPtr.Zero) {
                Console.WriteLine("DLL Not Loaded");
                int e = GetLastError();
                Console.WriteLine("Error Code: " + e);
            }
            GbsAssemblyName = new AssemblyName();
            GbsAssemblyName.Name = "GbsCore";
            GbsAssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(GbsAssemblyName, AssemblyBuilderAccess.Run);
            GbsModuleBuilder = GbsAssemblyBuilder.DefineDynamicModule("FuncGrp");
        }
        public static void GCreateGlbFunc() {
            GbsModuleBuilder.CreateGlobalFunctions();
        }
        public void LoadFunc(string lpProcName) {
            GFuncPtr = GetProcAddress(hModule, lpProcName);
            if (GFuncPtr == IntPtr.Zero) {
                Console.WriteLine("Function " + lpProcName + " Not Loaded");
            }
            Mname = lpProcName + "_T";
            MethodBuilder GbsMethodBuilder = GbsModuleBuilder.DefineGlobalMethod(Mname, MethodAttributes.Public | MethodAttributes.Static, GReturn, GParaType);
            GIL = GbsMethodBuilder.GetILGenerator();
            if (GObject != null) {
                for (int i = 0; i < GObject.Length; i++) {
                    switch (GMdPass[i]) {
                        case ModePass.ByValue:
                            GIL.Emit(OpCodes.Ldarg, i);
                            break;
                        case ModePass.ByRef:
                            GIL.Emit(OpCodes.Ldarga, i);
                            break;
                        default:
                            Console.WriteLine("Pass Mode Error");
                            break;
                    }
                }
            }
            if (IntPtr.Size == 4) { GIL.Emit(OpCodes.Ldc_I4, GFuncPtr.ToInt32()); } //Platform
            else if (IntPtr.Size == 8) { GIL.Emit(OpCodes.Ldc_I8, GFuncPtr.ToInt64()); }
            else { throw new PlatformNotSupportedException(); }
            GIL.EmitCalli(OpCodes.Calli, CallingConvention.FastCall, GReturn, GParaType);
            GIL.Emit(OpCodes.Ret);
        }
        public void InvokeDllFunc() {
            MethodInfo GbsMethodInfo;
            if (GParaType == null) {
                GbsMethodInfo = GbsModuleBuilder.GetMethod(Mname);
            }
            else {
                GbsMethodInfo = GbsModuleBuilder.GetMethod(Mname, GParaType);
            }
            GbsMethodInfo.Invoke(null, GObject);//return void
        }
        public static void UnLoadDll() {
            FreeLibrary(hModule);
            hModule = IntPtr.Zero;
        }

        public Class1(Type[] T, ModePass[] MP, object[] OB) {
            GParaType = T;
            GMdPass = MP;
            GObject = OB;
        }
    }
}