从 C/C++ (VS 2010) 代码创建 MFC DLL,供 C# WCF Web 服务使用

从 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;
                }         

            }

        }
    }

让我们试一试.

  1. 在 VS2010 中,在 Visual C++/Win32 下创建一个 Win32 项目.为此,将其称为 MyWin32Lib.
  2. 将第三方.cpp 文件添加到项目中并编译.您应该会收到一些警告,但没关系.
  3. 创建一个名为 thirdparty.h 的新头文件,以便我们可以导出函数签名.
  4. 在第三方.h 文件中,执行:

  1. In VS2010, create a Win32 Project under Visual C++/Win32. For this purpose, call it MyWin32Lib.
  2. Add the thirdparty.cpp file to the project and compile. You should get some warnings, but it's ok.
  3. Create a new header file called thirdparty.h so we can export the function signature.
  4. 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) 因为无法摆脱它,但假设我们只会做一次.

    1. 确保编译正常.
    2. 创建一个新的 CPP 文件,命名为Concepts.cpp"
    3. 在 Concepts.cpp 中,输入:

    1. Make sure you compile ok.
    2. Create a new CPP file, call it "Concepts.cpp"
    3. 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.

    1. 创建一个 C# 类库项目.
    2. 创建一个名为Concepts.cs"的 C# 类
    3. 在这个类中,输入:

    1. Create a C# Class Library project.
    2. Create a C# class called "Concepts.cs"
    3. 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.