Inheriting from native C++ in C# and passing the i

2019-07-16 12:33发布

问题:

I've an engine in a native C++ dll and I need to use it in a C# project.

I'm totally new on doing that, but I've been googling for hours and now I know more or less how to achieve it. I know I've to write a C# or C++/CLI wrapper class.

But I haven't found how to wrap some aspects of the dll C++ class. The engine has class CEntity whith this important part:

class CEntity  
{  
    void SendMsg(CEntity *receiver);  
    virtual void ReceiveMsg(MSG msg);
}

That works as follows: A inherit class from CEntity overrides the ReceiveMsg function implementing what it whants, and Inheriting objects comunicate sending messages.

What I need is to use this functionality in C#: "Inheriting" from CEntity, overriding ReceiveMsg on a way that the C++ code can call it, and been able to send messages to other C# "Inheriting" CEntity objets throw the SendMsg C++ implementation. Or in other words I need that the C++ unmanaged code calls a C# managed code. The C++ code is calling ReceiveMessage() and I need to "override" it or redirect that call into C# code.

Is a way of doing that whithout changing the dll? I can't acces directly the C++ code, but if needed I can ask for dll modifications. If not, what'll be the minimum dll modifications?

Thanks a lot

回答1:

It is tricky:

ILogger.h

#pragma once

using namespace System;

namespace AlPDFGenV4 
{
    public interface class ILogger 
    {
    public:
        virtual void Log( String^ ltxt ) = 0;
    };
}

Then LRLog.h

#pragma once

#include "CMSysString.h"
#include "CLRILogger.h" 
#include <vcclr.h>

using namespace System;

class CNtvLogger;

namespace AlPDFGenV4 
{
    public ref class Logger
    {
    public:
        Logger(void);
        virtual ~Logger(void);

        ILogger^ extlogger;
            CNtvLogger *ntv;

            void Log( String^ txt )
            {
                extlogger->Log( txt );
            }
        };

    }

And LRLog.cpp

#include "StdAfx.h"
#include "LRLog.h"

using namespace AlPDFGenV4;

Logger::Logger(void)
{
    ntv = new CNtvLogger;
    ntv->clrlogger = this;
} 

Logger::~Logger(void)
{
    delete ntv;
}

class CNtvLogger : CMSysLogger
{
public:
    gcroot<AlPDFGenV4::Logger ^> clrlogger;

protected:
    void _InternalLog( LPCTSTR txt)
    {
        String ^str = gcnew String( txt );

        clrlogger->Log( str );
    }

public:
    bool Init(void * obj)
    {
        return true;
    }

}; 

Hope this helps.

In this example, the class Logger is a bridge tha allows to keep the link between the native logger (used by the native code) and the interface ILogger (used by managed code to pass the class that receives the log output).

You'll need a class like this in your C++/CLI, no need to change the dll with this approach.