C#64位程序调用32位C/C++库方法

本文介绍了如何在C#中通过编写32位控制台程序,实现与64位C库的交互,通过字符串传递参数,封装Process类库并获取进程调用的返回值,以解决因库文件32/64位不兼容问题。
摘要由CSDN通过智能技术生成


在实际的项目中经常使用一些第三方C/C++库,于历史原因,有的C库是32位的,由于没有源代码,所以一般很难修改为64位的类库,但又需要调用,怎么办呢,在参考了一些大神的博客后,总结出了一个独立进程访问的方法,来调取第三方库,获取返回值

1、编写32位控制台程序

编写一个32位的控制台程序,用于被主程调用

public class Program
{
	public static void Main(string[] args)
	{
		if(args.Length > 0 && !string.IsNullOrEmpty(args[0]))
		{
			string paramStr = args[0];//获取传递过来的参数
			//调用三方C/C++库逻辑
            /*
            ...................................
            */
			//将指定的字符串值(后跟当前行终止符)写入标准输出流。
			Console.WriteLine(result);
        }
	}
}

2、实现字符串传参

由于Main函数进程传参的参数类型只能是字符串,所以需要把C/C++库函数所需的byte[]类型参数转换成字符串类型,互转方法参数选择16进制字符串,代码如下:

// byte[]转16进制字符串
StringBuilder sb = new StringBuilder();
foreach (byte b in msgbuf)
{
	//{0:X2} 大写方式
	sb.AppendFormat("{0:x2}", b);
}
string argsStr = sb.ToString();

// 16进制字符串转byte[]
var msgbuf = new byte[hexStr.Length / 2];
for (var x = 0; x < msgbuf.Length; x++)
{
	var i = Convert.ToInt32(hexStr.Substring(x * 2, 2), 16);
	msgbuf[x] = (byte)i;
}

3、封装Process类库

封装一个简洁的ProcessCommandBase 帮助类来调用exe封装的第三方库进程,且可以返回被封装C库函数的返回值


public class ProcessCommandBase : IDisposable
{
	//程序名
	public string programe;
	//参数
	StringBuilder parameter = new StringBuilder();
	Process process = null;

	public ProcessCommandBase(string programe)
	{
		this.programe = programe;
	}

	public ProcessCommandBase AddParameter(string para)
	{
		parameter.Append($" {para} ");

		return this;
	}

	public string Exec(bool waitForExit = false)
	{
		//var baseDir = AppDomain.CurrentDomain.BaseDirectory;
		process = new Process();
		process.StartInfo.FileName = programe;
		process.StartInfo.Arguments = parameter.ToString();
		process.StartInfo.CreateNoWindow = true;
		process.StartInfo.UseShellExecute = false;

		//重定向标准输输出、标准错误流
		process.StartInfo.RedirectStandardError = true;
		process.StartInfo.RedirectStandardOutput = true;

		process.ErrorDataReceived += Process_ErrorDataReceived;
		process.Exited += Process_Exited;
		process.OutputDataReceived += Process_OutputDataReceived;
		Trace.WriteLine($"Exe:{programe}");
		Trace.WriteLine($"Parameter:{parameter.ToString()}");
		process.Start();
		process.BeginErrorReadLine();
		//process.BeginOutputReadLine();
		if (waitForExit)
		{
			string result = process.StandardOutput.ReadToEnd();
			process.WaitForExit();

			return result;
		}

		return string.Empty;
	}

	public void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
	{
		Trace.WriteLine(e.Data ?? string.Empty);
	}

	public void Process_Exited(object sender, EventArgs e)
	{
	}

	public void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
	{
		Trace.WriteLine(e.Data ?? string.Empty);
	}

	public void ClearParameter()
	{
		parameter.Clear();
	}

	public void Close()
	{
		process?.Close();
		process = null;
	}

	public void Kill()
	{
		process?.Kill();
		process?.Close();
		process = null;
	}

	public void Dispose()
	{
		Kill();
	}
}

4、获取进程调用的返回值

调用执行封装后的控制台程序后,需要获取被封装C库的返回值

var exec = new ProcessCommandBase("test.exe");
exec.AddParameter("xxxxxxxxxxxx");
var result = exec.Exec(true);

要在 C# 64 位应用程序调用 32 位 C++ 生成的 DLL 方法,你需要使用.NET Framework 的“可移植性”功能,以及平台调用(P/Invoke)功能。这个功能允许你在 64 位进程中加载 32 位 DLL,并使用其中的方法。 以下是一个简单的示例: 1. 首先,你需要在 C# 代码中声明你想调用的 32 位 C++ 生成的 DLL 方法。这需要使用 DllImport 属性。例如,如果你的 DLL 包含名为 "MyFunction" 的方法,你可以在 C# 中这样声明: ```csharp [DllImport("My32BitCPlusPlusDll.dll", EntryPoint="MyFunction")] public static extern int MyFunction32(int param1, int param2); ``` 这告诉 C# 编译器在 32 位 C++ 生成的 DLL 中查找一个名为 "MyFunction" 的方法,并将其导入到 C# 代码中。 2. 然后,你需要在 C# 应用程序的 app.config 文件中添加一个“可移植性”选项: ```xml <configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> </configuration> ``` 这将告诉应用程序使用“可移植性”功能来加载 32 位 DLL。 3. 接下来,你需要在 C# 代码中使用 Marshal 类来分配内存,以便在 64 位进程中使用 32 位 DLL: ```csharp IntPtr p = Marshal.AllocHGlobal(sizeof(int)); ``` 这将为一个 int 类型的变量分配 4 个字节的内存。请注意,你需要在使用完变量后释放它们: ```csharp Marshal.FreeHGlobal(p); ``` 4. 最后,你可以像调用任何其他 C# 方法一样调用该函数: ```csharp int result = MyFunction32(1, 2); ``` 这将调用 32 位 C++ 生成的 DLL 中的 "MyFunction" 方法,并将参数 1 和 2 传递给它。该方法的返回值将存储在 result 变量中。 注意,在使用“可移植性”功能时,你需要确保所有使用的 DLL 都是 32 位的,并且你的应用程序必须是 64 位的。如果你的 DLL 是 64 位的,你需要在 64 位应用程序使用常规的平台调用方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值