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