从 C/C++ (VS 2010) 代码创建 MFC DLL,供 C# WCF Web 服务使用
我有一个用 C/C++ 编写的第三方组件(在 VS 2010 上),可以下载 这里.
I have a third party component written in C/C++ (on VS 2010) which can be downloaded here.
该组件接受 3 个参数作为输入(一个文件名和两个数字)并在控制台中输出一个结果,然后输出一个文件.
This component accepts 3 parameters as input (a filename and two numbers) and outputs a result in the console, and then outputs a file.
我在 C# WinForm 项目中使用 Process 和 ProcessStartInfo 来使用这个工作正常的组件.但是,现在我想在 WCF C# RESTful 服务中使用它,在这种情况下,我认为使用 WinForm 的解决方案将不起作用.有人建议我将其转换为 MFC DLL,然后使用 InterOp 通过我的 C# Web 服务调用非托管 DLL(欢迎其他建议).
I've used Process and ProcessStartInfo in a C# WinForm project to consume this component which works fine. However, now I want to consume this in a WCF C# RESTful service, in which case the solution I thought with WinForm will not work. It was suggested that I instead convert this to a MFC DLL and then use InterOp to call the unmanaged DLL through my C# web service (other suggestions are welcome).
不幸的是,我不知道如何做到这一点,而且我对 C/C++ 的了解相当一般.所以我的问题是:如何从接受这 3 个参数的组件创建一个 DLL(取自 main()):
Unfortunately, I have no idea on how to do that and my knowledge on C/C++ is fairly average. So my question is: How do I create a DLL from that component which accepts these 3 parameters (taken from main()):
cin >> fname;
cin >> minA;
cin >> minO;
然后做它应该做的任何计算并返回它(再次取自 main()):
then does whatever calculations it's supposed to do and return this (again taken from main()):
cout << "\nNumber is: " << num;
(显然仍然输出它应该输出的文件)?
(and obviously still output the file it's supposed to output) ?
任何帮助将不胜感激.提前致谢!
Any help would be HIGHLY appreciated. Thanks in advance!
更新:作为参考,这里是我上面提到的 WinForm 实现.
UPDATE: As a point of reference, here is my WinForm implementation mentioned above.
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.
- 将第三方.cpp 文件添加到项目中并编译.您应该会收到一些警告,但没关系.
- 创建一个名为 thirdparty.h 的新头文件,以便我们可以导出函数签名.
在第三方.h 文件中,执行:
- In VS2010, create a Win32 Project under Visual C++/Win32. For this purpose, call it MyWin32Lib.
- Add the thirdparty.cpp file to the project and compile. You should get some warnings, but it's ok.
- Create a new header file called thirdparty.h so we can export the function signature.
In the thirdparty.h file, do:
#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"
In the thirdparty.cpp file, add #include "stdafx.h" right before #include
更改主函数签名以匹配标题中的签名:
Change the main function signature to match the one in the header:
//int main()
// Instead of getting input from console, we're passing it the values
int concepts(char* szFileName, int nMinIntent, int nMinExtent)
注释掉所有输入请求,并将参数复制到本地变量:
Comment out all input requests, and just copy the args to the local vars:
//cout << "\n\n***** In-Close 3.0 Concept Miner *****";
//cout << "\n\nEnter 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 <<"\n数字...(不再需要)
Comment out cout << "\nNumber... (this is no longer needed)
在函数结束时,执行:
break;
}
//cout << "\n\nHit <enter> to finish";
//while ( !_kbhit());
return numcons;
}
我不知道为什么会有一段时间 (1) 因为无法摆脱它,但假设我们只会做一次.
- 确保编译正常.
- 创建一个新的 CPP 文件,命名为Concepts.cpp"
在 Concepts.cpp 中,输入:
- Make sure you compile ok.
- Create a new CPP file, call it "Concepts.cpp"
In Concepts.cpp, enter:
#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.
*You should now have a Win32 DLL that performs the work using arguments instead.
- 创建一个 C# 类库项目.
- 创建一个名为Concepts.cs"的 C# 类
在这个类中,输入:
- Create a C# Class Library project.
- Create a C# class called "Concepts.cs"
In this class, enter:
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,因为这是第三方.cpp 使用的内容.
*You have to marshal the filename input as ANSI since that's what thirdparty.cpp uses.
我想我得到了所有.您现在可以从网络服务引用您的 C# 库.
I think I got all of it. You can now reference your C# library from a web service.