c# - Cross-platform C code and preventing garbage collection -


i have set of c functions need use on arm target, in c++ , in c#. can wrap c c++ dll , c# dll , use c functions i've bound successfully. however, have debug function want able print c# gui , delegate uses being garbage collected rather left in place duration.

managed debugging assistant 'callbackoncollecteddelegate' has detected problem in 'c:\utm\pc\utm_win32_app\bin\debug\utm_win32_app.vshost.exe'.

additional information: callback made on garbage collected delegate of type 'utm_dll_wrapper_cs!messagecodec.messagecodec_dll+guiprinttoconsolecallback:: invoke'. may cause application crashes, corruption , data loss. when passing delegates unmanaged code, must kept alive managed application until guaranteed never called.

here's snippet of c code uses , sets callback mp_guiprinttoconsole:

#ifdef win32 static void (* mp_guiprinttoconsole) (const char*) = null;  void logmsg (const char * pformat, ...) {     char buffer[max_debug_message_len];      va_list args;     va_start (args, pformat);     vsnprintf (buffer, sizeof (buffer), pformat, args);     va_end (args); #ifdef win32     if (mp_guiprinttoconsole)     {         (*mp_guiprinttoconsole) (buffer);     } #else     // must on arm     printf (buffer); #endif }  void  initdll (void (*guiprinttoconsole) (const char *)) { #ifdef win32     mp_guiprinttoconsole = guiprinttoconsole;      // signal gui we're done initialisation     logmsg ("ready.\r\n"); #endif } 

here's c++ code, built dll along c code, can called c# , passes in function pointer printtoconsole:

void msinitdll (void (*printtoconsole) (const char *)) {     initdll (printtoconsole); } 

here's snippet code c# dll calls msinitdll(), passing in guiprinttoconsole(), , defines delegate onconsoletrace, guess thing disappearing:

[unmanagedfunctionpointer (callingconvention.cdecl)] public delegate void _msinitdll([marshalas (unmanagedtype.functionptr)] guiprinttoconsolecallback callbackpointer); public _msinitdll msinitdll;  public delegate void consoletrace(string data); public event consoletrace onconsoletrace;  public void guiprinttoconsole(stringbuilder data) {     if (onconsoletrace != null)     {         onconsoletrace (data.tostring ());     } }  public void binddll(string dlllocation) {     intptr ptrdll = loadlibrary (dlllocation);      if (ptrdll == intptr.zero) throw new exception (string.format ("cannot find {0}", dlllocation));      //...     // other dll function bindings here     //...      msinitdll = (_msinitdll)binditem(ptrdll, "msinitdll", typeof(_msinitdll));     msinitdll(guiprinttoconsole); } 

i've looked @ various answers here , promising seemed to create static variable in c# code:

static gchandle gch;

...and use reference onconsoletrace in c# binddll() function:

gch = gchandle.alloc(onconsoletrace);

however, doesn't me good. i've tried few other attempts @ declaring things static nothing seems me want be. can suggest approach fixing problem? have bug need fix , lack of debug proving quite annoying.

rob

the following line uses syntactic sugar:

msinitdll(guiprinttoconsole); 

the full syntax is:

msinitdll(new guiprinttoconsolecallback(guiprinttoconsole)); 

hopefully see why delegate can garbage-collected.

one simple workaround:

var callback = new guiprinttoconsolecallback(guiprinttoconsole); msinitdll(callback); // ... other code gc.keepalive(callback); 

now delegate guaranteed alive up gc.keepalive call.

but need delegate stay alive longer. error message says, keep reference it. if need full c# app lifetime duration, turn callback local static field in class. static fields treated gc roots values reachable.


Comments

Popular posts from this blog

How to show in django cms breadcrumbs full path? -

php - Invalid Cofiguration - yii\base\InvalidConfigException - Yii2 -

ruby on rails - npm error: tunneling socket could not be established, cause=connect ETIMEDOUT -