> I've written a java/JNI wrapper for an existing MFC program. Each MFC
> function that I want to be available to java has a corresponding JNI
> function.
Yikes! This sounds like a Bad Idea, and the Last Choice Only.
> On initialisation, the java code calls a JNI method which creates a
> CWinThread and starts the MFC application within it - pretty standard
[quoted text clipped - 6 lines]
>
> This all works fine.
Sure it does :-)
> As a result of a JNI call, the MFC application may make a callback into
> the java code to notify it of certain events (using GetMethodID,
[quoted text clipped - 23 lines]
> | /|
> | |
You really should have two message queues going on here. One for the MFC
app, and one for the Java app. Alternatively, you should have your JNI
detect if its in a call already, and directly call the function instead
of using PostMessage().
> func2() is called in the context of the MFC App.
>
> That's pretty much the crux of the problem, which made we wonder if the
> callback function can schedule a function call for when the original JNI
> call has finished; that way it will be executed after func() returns.
You'd be better off scheduling the callback function to execute in a
different Java thread or event queue.
> Another approach might be to avoid running the MFC application in its
> own thread, and instead periodically call a dummy JNI message pump from
> the java code. I don't know how responsive that would be, though, not
> to mention that making repeated JNI calls could be expensive.
Port the original MFC program to Java. You'll get a more portable,
cleaner, and probably much less buggy program.
Good luck,
Daniel.

Signature
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
spam@spam.com - 18 Oct 2007 20:27 GMT
>> I've written a java/JNI wrapper for an existing MFC program. Each MFC
>> function that I want to be available to java has a corresponding JNI
>> function.
> Yikes! This sounds like a Bad Idea, and the Last Choice Only.
I spent some time looking into methods to create java wrappers, and this way
seemed to be about the only method in use. What other approaches are there?
I need the java wrapper to be able to create and modify C++ objects that are
handled by the C++/MFC code (of course the java code doesn't interact with MFC
objects directly).
Please take my word that rewriting the whole application in java is not an
option in this case :-)
>> As a result of a JNI call, the MFC application may make a callback
>> into the java code to notify it of certain events (using GetMethodID,
[quoted text clipped - 25 lines]
> You really should have two message queues going on here. One for the MFC
> app, and one for the Java app. Alternatively, you should have your JNI
What exactly do you mean by 'message queue'? I'm picturing a thread that sits
and wait for tasks to be passed to it, with the calling thread waiting for the
result. Is this what you had in mind?
> detect if its in a call already, and directly call the function instead
> of using PostMessage().
That's an interesting idea, but looking at my code it would be a lot of work
to implement.
>> func2() is called in the context of the MFC App.
>>
[quoted text clipped - 4 lines]
> You'd be better off scheduling the callback function to execute in a
> different Java thread or event queue.
I ended up using invokeLater() to make the callback be, um, called in the
context of the EDT. It's not a perfect solution, but it covers all the cases
I need.
>> Another approach might be to avoid running the MFC application in its
>> own thread, and instead periodically call a dummy JNI message pump
[quoted text clipped - 3 lines]
> Port the original MFC program to Java. You'll get a more portable,
> cleaner, and probably much less buggy program.
See above :-)
> Good luck,
Thanks for your reply,
Regards,
--Jon
<snip prelude>
| Thanks for the reply, I'll look into those functions. I'll try and describe
| the issue I'm working on (please bear with me, it's a little complicated
[quoted text clipped - 21 lines]
| JNI call (the one that triggered the callback in the first place) has not
| returned, so trying to make another JNI call will cause a deadlock :-(
Ok, I get all that. I'm not familiar with JNI to MFC, so let me just
confirm what I think you're saying. Are you saying that a 2nd JNI call made
from the MFC callback thread will block, but that a 2nd call made from a new
thread will not? I think you mean something slightly different, as I would
expect the 2nd call to block even when made from a separate thread. I can't
quite follow your UML ascii art, but further below I think you say that the
callback does not need to wait for the 2nd JNI call to complete. If that's
so, I think what you mean is that the 2nd call on a different thread will
block but eventually be answered asynchronously after the callback and
original JNI request have completed.
If that's the case, I think all you need to do is to create a
single-threaded executor service in your Java wrapper. You only need one of
these--don't create one each time you make a request and hang onto it for
you application.
ExecutorService executor = Executors.newSingleThreadExecutor ();
Then have your callback fire off the request
executor.submit (new Runnable () {
public void run () {
// Do your stuff here.
}
});
(To simply fire off the request in a separate thread, you can just do)
Thread t = new Thread (new Runnable () {
public void run () {
// Do your stuff here
}});
t.start ();
You don't need to wait for the executor to finish. It will simply queue up
your request and as the MFC thread becomes available each will be processed
in turn. You can check out the API to see how to manage shutdown, etc. (A
thread on its own is not guaranteed to execute in order--you may get a 2nd
request that executes before the first one.)
If the 2nd JNI call must be synchronous, I think you're SOL. I don't think
it will matter which thread it comes from, it will just block and you'll get
deadlock. I don't know how the MFC access system is designed to operate in
that regard.
| That's pretty much the crux of the problem, which made we wonder if the
| callback function can schedule a function call for when the original JNI call
[quoted text clipped - 4 lines]
| code. I don't know how responsive that would be, though, not to mention that
| making repeated JNI calls could be expensive.
I have systems that use hundreds of interlocked, signalling threads and I
don't have a problem with performance on that aspect. The more you can make
all requests asynchronous, the easier it becomes. For synchronous requests
you need only figure out how to respond to request completion and where to
put results. You can use the executor above to receive all requests and let
each one handle its final update itself. You'll have to decide what's
appropriate for the data structures you're trying to manage.
Cheers,
Matt Humphrey http://www.iviz.com/