Managed delegate handling in unmanaged code

I know that I can achieve this in order to technically work, but I would like to implement the cleanest possible solution. Here's the situation:

I have a managed library that wraps an unmanaged C-style library. The C-style library library that I am currently processing is doing some processing, including a list of strings. The client code of the library can be provided by the delegate, so that during the processing of the list, if an "invalid" script is encountered, the library can contact the client through this delegate and allow them to choose the strategy used (throw an exception, replace invalid characters, etc.)

Ideally, I would like all managed C ++ to be isolated in one function, and then able to call a separate function that accepts only unmanaged parameters, so that all native C ++ and unmanaged code are isolated at the same time. Providing a callback mechanism to this unmanaged code turns out to be a braking point for me.

#pragma managed public delegate string InvalidStringFilter(int lineNumber, string text); ... public IList<Result> DoListProcessing(IList<string> listToProcess, InvalidStringFilter filter) { // Managed code goes here, translate parameters etc. } #pragma unmanaged // This should be the only function that actually touches the C-library directly std::vector<NativeResult> ProcessList(std::vector<char*> list, ?? callback); 

In this snippet, I want to keep all access to the C-library in ProcessList, but during processing it will need to make callbacks, and this callback is provided as an InvalidStringFilter delegate, which is transferred from some client of my managed library.

+4
source share
3 answers

.NET can automatically convert a delegate to a function pointer if it is declared correctly. There are two caveats.

  • C function must be built STDCALL
  • A pointer to a function does not count as a reference to an object, so you must arrange the link so that it remains so that the underlying object is not garbage collected

http://www.codeproject.com/KB/mcpp/FuncPtrDelegate.aspx?display=Print

+2
source

If I understand the problem correctly, you need to declare an unmanaged callback function in your C ++ / CLI assembly that acts as a bridge between your C library and the managed delegate.

 #pragma managed public delegate string InvalidStringFilter(int lineNumber, string text); ... static InvalidStringFilter sFilter; public IList<Result> DoListProcessing(IList<string> listToProcess, InvalidStringFilter filter) { // Managed code goes here, translate parameters etc. SFilter = filter; } #pragma unmanaged void StringCallback(???) { sFilter(????); } // This should be the only function that actually touches the C-library directly std::vector<NativeResult> ProcessList(std::vector<char*> list, StringCallback); 

As written, this code is clearly not thread safe. If you need thread safety, you need some other mechanism to either find the right managed delegate in the callback, either ThreadStatic, or maybe the callback gets a user-passed variable that you could use.

+2
source

You want to do something like this:

 typedef void (__stdcall *w_InvalidStringFilter) (int lineNumber, string message); GCHandle handle = GCHandle::Alloc(InvalidStringFilter); w_InvalidStringFilter callback = static_cast<w_InvalidStringFilter>( Marshal::GetFunctionPointerForDelegate(InvalidStringFilter).ToPointer() ); std::vector<NativeResult> res = ProcessList(list, callback); 
0
source

Source: https://habr.com/ru/post/1277454/


All Articles