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

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

How to show in django cms breadcrumbs full path? -

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