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



我有一个用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;
                }         
            }
        }
    }

让我们试一试。

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

    #pragma once
    // This will be the interface for third party file
    int concepts(char* szFileName, int nMinIntent, int nMinExtent);
    
  5. 在thirdparty.cpp文件中,在#include 之前添加#include"stdafx.h"

  6. 更改主功能签名以匹配标题中的签名:

    //int main()
    // Instead of getting input from console, we're passing it the values
    int concepts(char* szFileName, int nMinIntent, int nMinExtent)
    
  7. 注释掉所有输入请求,只需将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;
    
  8. 评论cout<lt;"\n编号…(不再需要)

  9. 在功能结束时,执行:

    break;
    }
    //cout << "nnHit <enter> to finish";
    //while ( !_kbhit());
      return numcons;
    }
    

我不知道为什么会有一段时间(1),因为没有办法摆脱它,但假设我们只做一次

  1. 确保编译正常
  2. 创建一个新的CPP文件,称之为"Concepts.CPP"
  3. 在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,它使用参数来执行工作。

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

    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#库了。

最新更新