C# 导出非托管函数指针时发生访问冲突

C# 导出非托管函数指针时发生访问冲突,c#,.net,pointers,c++-cli,dllexport,C#,.net,Pointers,C++ Cli,Dllexport,在过去的4个小时里,我一直在试图解决一个非常神秘的问题 我正在为Notepad++编写一些插件。要实现语法高亮显示,必须导出这样一个函数: //this function is exported via exports.def file LexerFactoryFunction SCI_METHOD GetLexerFactory(unsigned int index) { return (index == 0) ? RTextLexer::LexerFactory : nullptr;

在过去的4个小时里,我一直在试图解决一个非常神秘的问题

我正在为Notepad++编写一些插件。要实现语法高亮显示,必须导出这样一个函数:

//this function is exported via exports.def file
LexerFactoryFunction SCI_METHOD GetLexerFactory(unsigned int index)
{
    return (index == 0) ? RTextLexer::LexerFactory : nullptr;
}
在哪里,

LexerFactoryFunction is typedef ILexer *(*LexerFactoryFunction)();
#define SCI_METHOD __stdcall

我已经成功地用C++完成了这个工作,但是插件的另一部分是用C语言编写的,所以我尝试用FoDy CuCuruluNuGET包将这两个包合并在一起(这样CLI.DLL被嵌入到主DLL中),但是没有成功。 我所尝试的:

public ref class RTextLexerCliWrapper
{
public:
    delegate ILexer * GetLexerFactoryDelegate();

IntPtr GetLexerFactory()
{
    return System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(_lexerFactoryPtr);
}

RTextLexerCliWrapper();
private:
    GetLexerFactoryDelegate ^ _lexerFactoryPtr;
    GCHandle gch;

    ~RTextLexerCliWrapper();
};

RTextLexerCliWrapper::RTextLexerCliWrapper()
{
    _lexerFactoryPtr = gcnew GetLexerFactoryDelegate(&RTextLexer::LexerFactory);
    gch = GCHandle::Alloc(_lexerFactoryPtr);
}


RTextLexerCliWrapper::~RTextLexerCliWrapper()
{
    gch.Free();
}
此CLI包装器在my main.dll中引用如下:

static RTextLexerCliWrapper _lexerWrapper = new RTextLexerCliWrapper();

[DllExport(CallingConvention = CallingConvention.Cdecl)]
static IntPtr GetLexerFactory(uint index)
{            
     return (index == 0) ? _lexerWrapper.GetLexerFactory() : IntPtr.Zero;
}
因此,实际上调用了我的.net函数,也调用了cli包装函数,并返回了函数指针。但是,任何调用该函数指针的尝试都会导致访问冲突。这意味着指针的类型是错误的,或者是我目前缺少的其他东西。我用
void*、StdCall
等尝试了无数.net导出函数的变体。所有这些都会导致相同的问题

有没有其他方法返回C++类的函数指针?还是我做了一些完全错误的事情


提前谢谢

所以我终于找到了解决问题的办法

第一步是导出具有正确调用约定的函数:

    static RTextLexerCliWrapper _lexerWrapper = new RTextLexerCliWrapper();

    [DllExport(CallingConvention = CallingConvention.StdCall)]
    static IntPtr GetLexerFactory(uint index)
    {            
        return (index == 0) ? _lexerWrapper.GetLexerFactory() : IntPtr.Zero;
    }
本案中的公约必须是StdCall。否则堆栈指针将无效,因此会出现异常

现在为了返回一个C++实例的函数指针,事情变得更棘手了。 我静态地存储CLI包装器类的一个实例,这样它就不会得到GCed。(
\u LexerRapper

此实例有一个名为GETLFLUCHITEFER的函数,它返回C++实例的函数指针(然后由其他的.DLL使用它来获取某个对象的实际实例)。 CLI包装器类如下所示:

    public ref class RTextLexerCliWrapper
    {
    public:

        delegate ILexer * GetLexerFactoryDelegate();

        IntPtr GetLexerFactory()
        {
            return System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(_lexerFactoryPtr);
        }

        RTextLexerCliWrapper();

    private:
        GetLexerFactoryDelegate ^ _lexerFactoryPtr;
        GCHandle gch;

        ~RTextLexerCliWrapper();
    };
其中,ILexer*是我们稍后将返回的对象类型

    RTextLexerCliWrapper::RTextLexerCliWrapper()
    {
        _lexerFactoryPtr = gcnew GetLexerFactoryDelegate(&RTextLexer::LexerFactory);
        gch = GCHandle::Alloc(_lexerFactoryPtr);
    }


    RTextLexerCliWrapper::~RTextLexerCliWrapper()
    {
        gch.Free();
    }

这样,我们在这里所管理的是通过.NET导出一个函数指针,它能够返回一个纯C++对象。

这是一个完整的动物园,你把老虎放在猴子房子里。@ HasSPASTAND就是这样,我不能改变API。