简体   繁体   English

通过托管C ++包装程序从非托管C ++ dll运行C#函数

[英]Run a C# function from an unmanaged C++ dll through a managed C++ Wrapper

I am working on a C# project that uses some unmanaged C++ code encapsulated in a dll. 我正在一个C#项目中,该项目使用一些封装在dll中的非托管C ++代码。 I have to load that dll as a Reference (not DllImport), so I'm writing a managed C++ Wrapper as a bridge between C# and the dll. 我必须将该dll作为参考(而不是DllImport)加载,因此我正在编写托管C ++包装程序,作为C#和dll之间的桥梁。

I can easily call the dll functions from C#, just calling the equivalent functions in the wrapper from C#, and then calling the dll functions from the wrapper. 我可以轻松地从C#调用dll函数,只需从C#调用包装中的等效函数,然后从包装中调用dll函数。 However, there are some callback functions in the dll that should call C# functions, and that part doesn't work. 但是,dll中有一些回调函数应调用C#函数,并且该部分不起作用。 I have studied several tutorials about this kind of interop (stackoverflow, microsoft, codeproject), but they are quite old and I can't make them work. 我研究了几种有关这种互操作的教程(stackoverflow,microsoft,codeproject),但是它们已经很老了,我无法使它们工作。

The idea is that the dll is processing real time data, and everytime the dll generates some results, it should call a function in Program.cs, which uses those results. 这个想法是dll正在处理实时数据,并且每当dll生成一些结果时,它都应该在Program.cs中调用一个使用这些结果的函数。

The code I'm working on is huge, so I've made a very simple scenario that includes everything that doesn't work. 我正在处理的代码非常庞大,因此我做了一个非常简单的场景,其中包括所有无效的内容。

In Program.cs I'm trying to tell the dll: "take this function Test and call it when you are done". 在Program.cs中,我试图告诉dll:“进行此功能测试并在完成后调用它”。 Then, to test it, I force it to run the callback function. 然后,为了测试它,我强迫它运行回调函数。 But I find several errors. 但是我发现了几个错误。

Although wrapper compiles and generates wrapper.dll, when I load it in the C# project, the function M_setCallback isn't there ¿?. 尽管wrapper会编译并生成wrapper.dll,但是当我在C#项目中加载wrapper.dll时,函数M_setCallback并不存在?

I wonder if somebody could give me a hand or show me a tutorial that explains how to do that (the tutorials I found don't have the 3 projects I must use, and I can't make them work). 我想知道是否有人可以帮我或给我看一个讲解如何做的教程(我发现这些教程没有我必须使用的3个项目,而且我无法使它们正常工作)。 I have tried using delegates, but the program crashes. 我尝试使用委托,但是程序崩溃。

Or maybe there is a simpler way to do this. 或者,也许有一种更简单的方法可以做到这一点。

Thanks! 谢谢!

Here is the code, it's very simple: 这是代码,非常简单:

First, I have the unmanaged dll : C++ Project, Win32 Console Application, compiled into a dll 首先,我有非托管dll :C ++项目,Win32控制台应用程序,已编译为dll。

defs.h defs.h

namespace JJLibrary
{
    typedef void (__stdcall *MYCALLBACK) (bool mybool, int myint);
}

unmanaged_dll.h unmanaged_dll.h

#ifndef JJAPI_H
#define JJAPI_H

#ifdef UNMANAGED_EXPORTS
#define JJ_API __declspec(dllexport)
#else
#define JJ_API __declspec(dllimport)
#endif

#include "defs.h"

namespace JJLibrary
{
    JJ_API void U_helloWorld();
    JJ_API void U_setCallback( MYCALLBACK theCallback );
    JJ_API void U_runCallback();
}
#endif //JJAPI_H

unmanaged_dll.cpp unmanaged_dll.cpp

#include "unmanaged_dll.h"
#include <iostream>
using namespace std;

namespace JJLibrary
{

    MYCALLBACK m_callback = 0;

    JJ_API void U_helloWorld()
    {
        cout << "Unmanaged: Hello world" << endl;
    }

    JJ_API void U_setCallback( MYCALLBACK theCallback )
    {
        cout << "Unmanaged: Setting callback" << endl;
        m_callback = theCallback;
    }

    JJ_API void U_runCallback()
    {
        bool b = true;
        int  i = 25;
        cout << "Unmanaged: Running callback: " << b << " " << i << endl;
        if (m_callback)
            m_callback(b, i);
        // In the final application b and i are generated here after processing data, I give them values for testing
        // When they are generated, call the function in C#
    }   

}

Wrapper: C++ CLR Class Project 包装: C ++ CLR类项目

wrapper.h 包装器

#include "defs.h"
#include <iostream>

using namespace System;
using namespace System::Runtime::InteropServices;
using namespace JJLibrary;
using namespace std;

namespace wrapper { 

    public ref class Wrapper
    {

    public:

        void M_helloWorld();
        void M_setCallback( MYCALLBACK theCallback );
        void M_runCallback( bool mybool, int myint );

    };
}

wrapper.cpp 包装器

#include "stdafx.h"
#include "wrapper.h"
#include "defs.h"
#include <iostream>
using namespace wrapper;
using namespace JJLibrary;
using namespace std;

void Wrapper::M_helloWorld()
{
    cout << "Managed: Hello World" << endl;
    U_helloWorld();
}

void Wrapper::M_setCallback( MYCALLBACK theCallback )
{
    cout << "Managed: Setting callback" << endl;
    U_setCallback( theCallback);
}

void Wrapper::M_runCallback(bool mybool, int myint)
{
    cout << "Managed: Running callback" << endl;
    U_runCallback(mybool, myint);
}

And finally, Program.cs 最后, Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using wrapper;

namespace CS
{
    class Program
    {

        void Test(bool mybool, int myint)
        {
            Console.WriteLine(!mybool);
            Console.WriteLine(2*myint);
        }


        static void Main(string[] args)
        {
            Wrapper myWrapper = new Wrapper();
            myWrapper.M_helloWorld();
            myWrapper.M_setCallback(Test);
            myWrapper.M_runCallback(true, 25);  // --> false 50

            string s = Console.ReadLine();  // Pause
        }
    }
}

Too much code to really understand, but my solution to a similar problem involved a delegate that looks like this. 太多的代码无法真正理解,但是我对类似问题的解决方案涉及一个看起来像这样的委托。

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void UserFunctionCallback(IntPtr context, int nvalues,
  [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]IntPtr[] values);

If that helps I can add some more code. 如果有帮助,我可以添加更多代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM