Re: [Mono-list] Re: Calling back from unmanaged code to managed code.

2004-12-17 Thread Cory Nelson
Would be good to note, on Windows, that your C code expecting a
__cdecl or __stdcall function pointer can make all the difference. 
Gave me a nice 2 day long headache with debugging :)


On Thu, 16 Dec 2004 21:04:15 -0500, Jonathan Pryor [EMAIL PROTECTED] wrote:
 Just for fun, I'll write the equivalent C# declarations inline with
 the C code.  Note that I haven't tried to compile this, but the basic
 idea should be seen...
 
 On Thu, 2004-12-16 at 13:32 -0500, Nigel Benns wrote:
  Here is a C example to do a DeleteEvent:
 
  void delete_cb(Ewl_Widget *w, void *event, void *data) {
  ewl_widget_destroy(w);
  ewl_main_quit();
  }
 
 delegate void EwlDeleteCallback (IntPtr w, IntPtr event, IntPtr data);
 
 class MyTest {
 
 private const string LIB = ewl;
 
 [DllImport (LIB)]
 private static extern void ewl_widget_destroy (IntPtr w);
 
 [DllImport (LIB)]
 private static extern void ewl_main_quit ();
 
 private void delete_cb (IntPtr w, IntPtr event, IintPtr data)
 {
 ewl_widget_destroy (w);
 ewl_main_quit ();
 }
 
  int main(int argc, char **argv) {
 ewl_init();
 
 [DllImport (LIB)] private static extern void ewl_init ();
 ...
 win = ewl_window_new();
 
 [DllImport (LIB)] private static extern IntPtr ewl_window_new();
 
 ...
 /*Where this function appends the callback to a calback list read
   by ewl_main().
 */
 ewl_callback_append(win, EWL_CALLBACK_DELETE_WINDOW, delete_cb, NULL);
 
 // Here's what you're interested in:
 [DllImport(LIB)]
 private static extern void ewl_callback_append (IntPtr win,
 int callback_type, EwlDeleteCallback cb, IntPtr data);
 
 // I'd assume that ewl_callback_append can take a variety of
 // function pointer types (the callback is probably void*),
 // so you could overload this function for each function
 // pointer type that ewl_callback_append accepts.
 
 // obviously, this needs to be set to the correct value.
 private const int EWL_CALLBACK_DELETE_WINDOW = 0xdeadbeef;
 
 /*The NULL is for the Data to pass */
 ...
 ewl_main();
 
 [DllImport(LIB)] private static extern void ewl_main ();
  }
 
  Ok, so what I'm trying figure out is how to add the ewl_callback_append as
  a delegate in C#.
 
 public static void Main ()
 {
 ewl_init ();
 IntPtr win = ewl_window_new ();
 EwlDeleteCallback cb = new EwlDeleteCallback (delete_cb);
 ewl_callback_append (win, EWL_CALLBACK_DELETE_WINDOW, 
 cb, IntPtr.Zero);
 ewl_main ();
 System.GC.KeepAlive (cb);
 }
 }
 
 Note that the System.GC.KeepAlive is necessary so that the GC doesn't
 collect your delegate before EWL is finished using the function pointer
 it has (the delegate is marshaled as a function pointer).  It would be
 bad to have the GC collect the delegate early.
 
  It doesn't seem write to me that I could pass a C# function to C, even if
  I could figure out how to do that?
 
 You can pass a delegate referring to a C# method to C.
 
 I would suggest reading my guide, Everything you (n)ever wanted to know
 about marshaling (and were afraid to ask!):
 
 http://www.jprl.com/~jon/interop.html
 
 It's also available through monodoc (though the above is more recent --
 I've been lazy about committing):
 
 http://www.go-mono.com/docs/[EMAIL PROTECTED]
 
 You may also want to look into Gtk#, just to see how the wrapper code
 can be used.
 
  - Jon
 
 
 ___
 Mono-list maillist  -  [EMAIL PROTECTED]
 http://lists.ximian.com/mailman/listinfo/mono-list
 


-- 
Cory Nelson
http://www.int64.org
___
Mono-list maillist  -  [EMAIL PROTECTED]
http://lists.ximian.com/mailman/listinfo/mono-list


[Mono-list] Re: Calling back from unmanaged code to managed code.

2004-12-16 Thread Nigel Benns
Ok, this is a little different, I think anyway,
mabey I just don't have it in my head right, so I'll give the example I'm
working on.

I'm trying to bind EWL (Enlightenment Widget Library) to C#.

I've got the windows working, but no events.
I've read your email... seems easy enough, but I think it does it a little
different.

Here is a C example to do a DeleteEvent:

void delete_cb(Ewl_Widget *w, void *event, void *data) {
ewl_widget_destroy(w);
ewl_main_quit();
}

int main(int argc, char **argv) {
   ewl_init();
   ...
   win = ewl_window_new();
   ...
   /*Where this function appends the callback to a calback list read
 by ewl_main().
   */
   ewl_callback_append(win, EWL_CALLBACK_DELETE_WINDOW, delete_cb, NULL);
   /*The NULL is for the Data to pass */
   ...
   ewl_main();
}

Ok, so what I'm trying figure out is how to add the ewl_callback_append as
a delegate in C#.

It doesn't seem write to me that I could pass a C# function to C, even if
I could figure out how to do that?

Is that where I need to add the glue, or is this different.

my C# Lib looks kinda like this:

namespace Ewl {

   public class Window : Embed {

  IntPtr Handle;

  public override IntPtr Raw {

 get {

return Handle;

 }

  }

  //I'm guessing I can't do this
  [DllImport(libewl)]
  static extern int ewl_callback_append(IntPtr wid, CallType
CallType.DeleteEvent, //however you would give a function?)


   }


Any one with a suggestion on this would be GREATLY appreciated.
Thanks


I REALLY HATE C, it makes my head hurt, and managed code to C is even
worse :).  But the challenge is half the reason I'm doing this.
___
Mono-list maillist  -  [EMAIL PROTECTED]
http://lists.ximian.com/mailman/listinfo/mono-list


Re: [Mono-list] Re: Calling back from unmanaged code to managed code.

2004-12-16 Thread Jonathan Pryor
Just for fun, I'll write the equivalent C# declarations inline with
the C code.  Note that I haven't tried to compile this, but the basic
idea should be seen...

On Thu, 2004-12-16 at 13:32 -0500, Nigel Benns wrote:
 Here is a C example to do a DeleteEvent:
 
 void delete_cb(Ewl_Widget *w, void *event, void *data) {
 ewl_widget_destroy(w);
 ewl_main_quit();
 }

delegate void EwlDeleteCallback (IntPtr w, IntPtr event, IntPtr data);

class MyTest {

private const string LIB = ewl;

[DllImport (LIB)] 
private static extern void ewl_widget_destroy (IntPtr w);

[DllImport (LIB)]
private static extern void ewl_main_quit ();

private void delete_cb (IntPtr w, IntPtr event, IintPtr data)
{
ewl_widget_destroy (w);
ewl_main_quit ();
}

 int main(int argc, char **argv) {
ewl_init();

[DllImport (LIB)] private static extern void ewl_init ();
...
win = ewl_window_new();

[DllImport (LIB)] private static extern IntPtr ewl_window_new();

...
/*Where this function appends the callback to a calback list read
  by ewl_main().
*/
ewl_callback_append(win, EWL_CALLBACK_DELETE_WINDOW, delete_cb, NULL);

// Here's what you're interested in:
[DllImport(LIB)]
private static extern void ewl_callback_append (IntPtr win, 
int callback_type, EwlDeleteCallback cb, IntPtr data);

// I'd assume that ewl_callback_append can take a variety of 
// function pointer types (the callback is probably void*),
// so you could overload this function for each function 
// pointer type that ewl_callback_append accepts.

// obviously, this needs to be set to the correct value.
private const int EWL_CALLBACK_DELETE_WINDOW = 0xdeadbeef;

/*The NULL is for the Data to pass */
...
ewl_main();

[DllImport(LIB)] private static extern void ewl_main ();
 }
 
 Ok, so what I'm trying figure out is how to add the ewl_callback_append as
 a delegate in C#.

public static void Main ()
{
ewl_init ();
IntPtr win = ewl_window_new ();
EwlDeleteCallback cb = new EwlDeleteCallback (delete_cb);
ewl_callback_append (win, EWL_CALLBACK_DELETE_WINDOW, 
cb, IntPtr.Zero);
ewl_main ();
System.GC.KeepAlive (cb);
}
}

Note that the System.GC.KeepAlive is necessary so that the GC doesn't
collect your delegate before EWL is finished using the function pointer
it has (the delegate is marshaled as a function pointer).  It would be
bad to have the GC collect the delegate early.

 It doesn't seem write to me that I could pass a C# function to C, even if
 I could figure out how to do that?

You can pass a delegate referring to a C# method to C.

I would suggest reading my guide, Everything you (n)ever wanted to know
about marshaling (and were afraid to ask!):

http://www.jprl.com/~jon/interop.html

It's also available through monodoc (though the above is more recent --
I've been lazy about committing):

http://www.go-mono.com/docs/[EMAIL PROTECTED]

You may also want to look into Gtk#, just to see how the wrapper code
can be used.

 - Jon


___
Mono-list maillist  -  [EMAIL PROTECTED]
http://lists.ximian.com/mailman/listinfo/mono-list


Re: [Mono-list] Re: Calling back from unmanaged code to managed code.

2004-12-14 Thread Paolo Molaro
On 12/12/04 Jonathan Pryor wrote:
  If so is it that difficult to add this feature to mono (say once the 
  work on code security is finished)
 
 It's not so much difficult, as questionable.  Questionable as in,
 should we do this?.

The answer is: yes, we need to implement the support for it.

 There are two requirements/changes lupus mentioned:
 
 1.  The native delegate should marshal the thread into the correct 
 AppDomain.  This probably wouldn't be too difficult (says the guy
 who hasn't done *any* runtime hacking).

It's not so much the issue of marshaling the thread object: this
belongs to point 2, IMHO.
The issue is to decide what application domain should be used 
when entering the new thread. This also means that the wrapper
method (the method that makes the transition from unmanaged to 
managed code) needs to be much more complex: it needs to do
a domain transition when entering and a domain restore when exiting
(if the domain was changed).

 2.  Setup/initialize non-mono threads so that mono can use them.  This
 includes determining the stack information so that the GC can 
 properly trace the entire GC heap.
 
 (2) is the problematic requirement.  Should mono take over all threads
 that enter mono?  *Can* mono do that?  (I don't know if it's possible to
 get the stack size from the pthreads API.)  Taking over any thread that

It's not possible to get the stack info for a thread portably, unless
we started the thread. This is part of the problem.

 A better approach is what mono already requires -- all threads that used
 by mono should call mono_thread_attach before entering or being used by
 mono.  Unfortunately this requires partitioning your application so that
 non-mono threads don't call into mono, directly or indirectly, but this
 is probably the only usable solution.

We can make the wrapper automatically call mono_thread_attach(),
but that's just part of the issue.

lupus

-- 
-
[EMAIL PROTECTED] debian/rules
[EMAIL PROTECTED] Monkeys do it better
___
Mono-list maillist  -  [EMAIL PROTECTED]
http://lists.ximian.com/mailman/listinfo/mono-list


Re: [Mono-list] Re: Calling back from unmanaged code to managed code.

2004-12-12 Thread Jonathan Pryor
On Fri, 2004-12-10 at 19:02 +, Gregory Bowyer wrote:
 Paolo Molaro wrote:
  We could easily remove this assert and instead add the code to setup
  the thread to execute managed code. This won't solve the whole issue,
  though: the GC needs to know about the thread and its stack limits or
  it won't work correctly.
  There is also the issue of deciding which application domain should be set
  for the new thread. We should probably add a call to a function that does
  all this setup to the wrapper methods used to go from unmanaged to
  managed code.
  
  lupus
  
 If i am reading this correctly, is the lack of support for unmanaged 
 code in mono a case of three incomplete features namely:
   1) Lack of Code access security stuff
   2) Bits of monos internal setup
   3) GC pinning and stack issues

To simplify greatly on Francis Brosnan Blzquez's response:

1)  No, Code Access Security has nothing to do with it
2)  Yes, it has to do with Mono's internal requirements, mostly from...
3)  The GC has it's own requirements.

 If so is it that difficult to add this feature to mono (say once the 
 work on code security is finished)

It's not so much difficult, as questionable.  Questionable as in,
should we do this?.

There are two requirements/changes lupus mentioned:

1.  The native delegate should marshal the thread into the correct 
AppDomain.  This probably wouldn't be too difficult (says the guy
who hasn't done *any* runtime hacking).

2.  Setup/initialize non-mono threads so that mono can use them.  This
includes determining the stack information so that the GC can 
properly trace the entire GC heap.

(2) is the problematic requirement.  Should mono take over all threads
that enter mono?  *Can* mono do that?  (I don't know if it's possible to
get the stack size from the pthreads API.)  Taking over any thread that
enters mono's runtime is questionable, at best -- these may be threads
created by Wine, or Xine, or Evolution, or...  Altering them to make
them suitable for use by mono may be a questionable tactic, at best.

A better approach is what mono already requires -- all threads that used
by mono should call mono_thread_attach before entering or being used by
mono.  Unfortunately this requires partitioning your application so that
non-mono threads don't call into mono, directly or indirectly, but this
is probably the only usable solution.

 - Jon


___
Mono-list maillist  -  [EMAIL PROTECTED]
http://lists.ximian.com/mailman/listinfo/mono-list


Re: [Mono-list] Re: Calling back from unmanaged code to managed code.

2004-12-11 Thread Francis Brosnan Blázquez

About this issue:

Finally I've found a solution. I think it's a litle complex, but really
integrated not only with mono but also with other .NET runtime and you
get lot of powerful features doing like I'm going to say.

Maybe mono still lacks support for this case, I mean, integrate
unmanaged threads with managed ones. But this exposes, not only a
not-easy-to-solve mono problem, but also a problem on how to bind this
type of libraries in a proper way which allows you to get better
results.

The whole problem comes from trying to bind a C API which callbacks
asynchronously to the caller as it is. Reading about what support should
give .NET runtime and how native .NET code can be translated into
asynchronous code I've realized that the best way to bind asynchronous
libraries is to keep unmanaged and managed code separated.

Try to think about every thread model we can find in every platform and
you'll realize that you should not really on mono to support this.
Microsoft .NET binding says that the runtime must detect newly
unmanaged created threads and support them [1], but, they talks from
its points of view: Microsoft Windows platforms. 

In short, if you have a library with a C API to bind like the follows:

// signature for the response callback
typedef void (*Callback) (SomeCStruct * response, gpointer data);

// request api
void my_async_func_to_bind (gint value, Callback cb, gpointer data);

In which your callback cb will be executed at the end of the
my_async_func_to_bind execution.
The response, with the user data provided, will be passed to cb, in a
newly unmanaged created thread appart from the main thread which have
call my_async_func_to_bind.

In this context, it won't be a good idea (and you should NOT) to bind
this C API directly because you are relaying on the runtime to get it
working as I say. 

Instead of that you need to create an litle c-glue to transfor your
asynchronous C API into a new synchronous C API. To do this, you can use
GAsyncQueues from glib in this way:

   // support function which only catch the response 
   void return_my_value_on_my_queue (SomeCStruct * response,
 gpointer data)
   {
  GAsyncQueue * queue = (GAsyncQueue *) data;

  g_async_queue_ref (queue);
  g_async_queue_push (queue, response);
  g_async_queue_unref (queue);

  return;
   } 
   
   // synchronous version of my_async_func_to_bind
   SomeCStruct * my_sync_func_to_bind (gint value) 
   {
  GAsyncQueue * queue= g_async_queue_new ();
  SomeCStruct * response = NULL;
  my_async_func_to_bind (value, return_my_value_on_my_queue, queue);
  
  response = g_async_queue_pop (queue);

  return response;  
   }

With the code above, the caller thread (in this context, a managed
thread with have entered into the unmanaged code) will be blocked on
g_async_queue_pop until reponse arrives and a g_async_queue_push occur.

Now, you have a really simple signature to bind. To bind this you only
need to declare all needed DllImport stuff as follows:

   [StructLayout(LayoutKind.Sequential)]
   public class SomeCStruct {
   // members declarations as they are ordered in the C API
   }
   
   
  
   public class YourLib {
  [DllImport(yourlib)]
  extern static SomeCStruct my_sync_func_to_bind (int value);

  public static SomeCStruct Get (int value) 
  {
  return my_sync_func_to_bind (value);
  }  
   }

You need to import SomeCStruct as a class and set that StructLayout.
Read the Jonathan Pryor document to get more information [3].

Okay, I know what your thinking at this moment: But, we are not talking
about asynchronous API? I need the same asynchronous functionality. With
this approach, we have only synchronous API. Keep on reading.

.NET have a really powerful support to create Asynchronous version from
synchronous method [2]. If you want to have an asynchronous version from
a synchronous method do as follows:

   1) Add a delegate into your class implementation file (not into the
  class itself) with the same signature as your wanted to make
  asynchronous class Method:
   
  public delegate SomeCStruct AsyncGet (int value);

   2) Now, the consumer class code must do something like this to
  invoke asynchronously your Get method:
 
  int value = // some value
  AsyncGet dlgt = new AsyncGet (YourLib.Get);

  dlgt.BeginInvoke (value, new AsyncCallback (ProcessGet),dlgt);

  // your code have invoke the Get method and it doesn't get
  // blocked. The response will be recieved at ProcessGet 

   3) Your ProcessGet method needs to implement the
  AsyncCallback interface and the IAsyncResult interface as follows:
 
  public void ProcessGet (IAsyncResult ar)
  {
  AsyncGet dlgt= ar.AsyncState as AsyncGet;
  SomeCStruct response = dlgt.EndInvoke (ar);

  // do all the stuff need with response
  } 

[Mono-list] Re: Calling back from unmanaged code to managed code.

2004-12-10 Thread Gregory Bowyer
Paolo Molaro wrote:
On 11/29/04 Francis Brosnan Blázquez wrote:
I'm trying to make the c# binding for some set of libraries which, in
sort, makes petitions to a remote server without blocking the caller. In
this context, the caller must suply a handler to manage the server
response.
Later, when server response arrives, these libraries initiate a thread
and execute on it the Caller's handler. 

The binding works fine until unmanaged code invoke the caller's handler
inside the newly thread create.
I've made a litle test to show more presiselly what I'm trying to do.
The follwing file is the unmanaged pice of code that has two ways to
notify the caller throught its handler: 1) by creating a new thread, 2)
by using the actual caller's thread.
[...]
When I execute this test I get the following:

$ ./Callback.exe
Test init..
Recieved call on unmanaged side..
Calling back to managed side..
Recieved callback on managed side
 Values: 2 and some text
Calling back finished..
Recieved call on unmanaged side..
Calling back to managed side..
** ERROR **: file mini.c: line 6558 (mono_get_lmf_addr): should not be
reached

We could easily remove this assert and instead add the code to setup
the thread to execute managed code. This won't solve the whole issue,
though: the GC needs to know about the thread and its stack limits or
it won't work correctly.
There is also the issue of deciding which application domain should be set
for the new thread. We should probably add a call to a function that does
all this setup to the wrapper methods used to go from unmanaged to
managed code.
lupus
If i am reading this correctly, is the lack of support for unmanaged 
code in mono a case of three incomplete features namely:
	1) Lack of Code access security stuff
	2) Bits of monos internal setup
	3) GC pinning and stack issues

If so is it that difficult to add this feature to mono (say once the 
work on code security is finished)

___
Mono-list maillist  -  [EMAIL PROTECTED]
http://lists.ximian.com/mailman/listinfo/mono-list