ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c# – 导出非托管函数指针时访问冲突

2019-07-08 11:17:12  阅读:226  来源: 互联网

标签:c net pointers c-cli dllexport


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

我正在为记事本写一些插件.要实现语法高亮,必须导出这样的函数:

//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 Costura NuGet包合并两个(因此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包装器在我的主.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. (_lexerWrapper).

这个实例有一个名为GetLexerFactory的函数,它返回一个C实例的函数指针(然后由其他一些.dll用来获取某个对象的实际实例).

CLI Wrapper类如下所示:

    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对象的函数指针.

标签:c,net,pointers,c-cli,dllexport
来源: https://codeday.me/bug/20190708/1401482.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有