我有一个用C/C++编写的第三方组件(在VS 2010上),可以在这里下载。
该组件接受3个参数作为输入(一个文件名和两个数字),并在控制台中输出结果,然后输出一个文件。
我在一个C#WinForm项目中使用了Process和ProcessStartInfo来使用这个组件,它运行良好。然而,现在我想在WCF C#RESTful服务中使用它,在这种情况下,我认为使用WinForm的解决方案将不起作用。有人建议我将其转换为MFC DLL,然后使用InterOp通过我的C#web服务调用非托管DLL(欢迎其他建议)。
不幸的是,我不知道如何做到这一点,而且我对C/C++的了解也相当一般。所以我的问题是:我如何从接受这3个参数的组件创建一个DLL(取自main()):
cin >> fname;
cin >> minA;
cin >> minO;
然后做它应该做的任何计算,并返回这个(再次取自main()):
cout << "nNumber is: " << num;
(显然仍然输出它应该输出的文件)?
如有任何帮助,我们将不胜感激。提前感谢!
更新:作为参考,这里是我上面提到的WinForm实现。
ProcessStartInfo cmdStartInfo = new ProcessStartInfo();
Process cmdProcess = new Process();
BackgroundWorker BWorker = new BackgroundWorker();
//is able to report progress
BWorker.WorkerReportsProgress = true;
//is able to be cancelled
BWorker.WorkerSupportsCancellation = true;
//attach events
BWorker.DoWork += worker_DoWork;
BWorker.RunWorkerCompleted += worker_RunWorkerCompleted;
BWorker.RunWorkerAsync();
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
if (firstTimeLoaded)
{
cmdStartInfo.FileName = Path.GetFullPath("../../Resources/thirdparty.exe");
cmdStartInfo.WorkingDirectory = Path.GetFullPath("../../Resources/");
cmdStartInfo.RedirectStandardOutput = true;
cmdStartInfo.RedirectStandardError = true;
cmdStartInfo.RedirectStandardInput = true;
cmdStartInfo.UseShellExecute = false;
cmdStartInfo.CreateNoWindow = true;
cmdProcess.StartInfo = cmdStartInfo;
cmdProcess.SynchronizingObject = this;
cmdProcess.ErrorDataReceived += cmd_Error;
cmdProcess.Exited += cmd_Exited;
cmdProcess.EnableRaisingEvents = true;
cmdProcess.Start();
cmdProcess.BeginErrorReadLine();
firstTimeLoaded = false;
}
while (!cmdProcess.HasExited)
{
if (use)
{
if (BWorker.CancellationPending)
{
e.Cancel = true;
}
StringBuilder builder = new StringBuilder();
//read unbuffered output
while (cmdProcess.StandardOutput.Peek() != -1)
{
char inputChar = (char)cmdProcess.StandardOutput.Read();
if (inputChar != 'r' && inputChar != 'n')
{
builder.Append(inputChar);
}
if (inputChar == 'n')
{
break;
}
}
if (cmdProcess.StandardOutput.Peek() == -1)
{
cmdProcess.StandardOutput.DiscardBufferedData();
}
//process the output
string output = builder.ToString();
//determine appropriate action
switch (output)
{
case "Enter file name: ":
cmdProcess.StandardInput.WriteLine(textBox1.Text);
break;
case "Enter minimum size of A: ":
cmdProcess.StandardInput.WriteLine(textBox2.Text);
break;
case "Enter minimum size of O: ":
cmdProcess.StandardInput.WriteLine(textBox3.Text);
break;
}
if (output.Contains("Number: "))
{
MessageBox.Show("Number is: " + output.Substring(output.LastIndexOf(" ") + 1));
use = false;
}
}
}
}
让我们试一试。
- 在VS2010中,在Visual C++/Win32下创建一个Win32项目。为此,请将其称为MyWin32Lib
- 将thirdparty.cpp文件添加到项目中并进行编译。你应该得到一些警告,但没关系
- 创建一个名为thirdparty.h的新头文件,这样我们就可以导出函数签名
-
在thirdparty.h文件中,执行:
#pragma once // This will be the interface for third party file int concepts(char* szFileName, int nMinIntent, int nMinExtent);
-
在thirdparty.cpp文件中,在#include 之前添加#include"stdafx.h"
-
更改主功能签名以匹配标题中的签名:
//int main() // Instead of getting input from console, we're passing it the values int concepts(char* szFileName, int nMinIntent, int nMinExtent)
-
注释掉所有输入请求,只需将args复制到本地vars:
//cout << "nn***** In-Close 3.0 Concept Miner *****"; //cout << "nnEnter cxt file name including extension: "; //cin >> fname; //cout << "nEnter minimum size of intent (no. attributes): "; //cin >> minIn; //cout << "nEnter minimum size of extent (no. objects): "; //cin >> minEx; strcpy_s(fname, _countof(fname), szFileName); minIn = nMinIntent; minEx = nMinExtent;
-
评论cout<lt;"\n编号…(不再需要)
-
在功能结束时,执行:
break; } //cout << "nnHit <enter> to finish"; //while ( !_kbhit()); return numcons; }
我不知道为什么会有一段时间(1),因为没有办法摆脱它,但假设我们只做一次
- 确保编译正常
- 创建一个新的CPP文件,称之为"Concepts.CPP"
-
在Concepts.cpp中,输入:
#include "stdafx.h" #include "thirdparty.h" extern "C" { __declspec(dllexport) int GetConcepts(char* szFileName, int nMinIntent, int nMinExtent) { return concepts(szFileName, nMinIntent, nMinExtent); } }
*您现在应该有一个Win32 DLL,它使用参数来执行工作。
- 创建一个C#类库项目
- 创建一个名为"Concepts.cs"的C#类
-
在此类中,输入:
public class Concepts { // Link to the Win32 library through InterOp [DllImport("MyWin32Lib.dll")] public static extern int GetConcepts( [MarshalAs( UnmanagedType.LPStr )] string fileName, int minIntent, int minExtent ); }
*您必须将文件名输入封送为ANSI,因为thirdparty.cpp使用ANSI。
我想我已经全部掌握了。你现在可以从网络服务中引用你的C#库了。