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

卷儿哥 2023年12月26日 429次浏览

在实际的项目中经常使用一些第三方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);