c# – 导出非托管函数指针时访问冲突
过去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对象的函数指针. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |