Bug 907 - Add Dispatch Thread for Windows DummyWindow's allowing 3rd party applications to retrieve window names (send events)
Summary: Add Dispatch Thread for Windows DummyWindow's allowing 3rd party applications...
Status: RESOLVED FIXED
Alias: None
Product: Jogl
Classification: JogAmp
Component: windows (show other bugs)
Version: 2
Hardware: pc_all windows
: --- major
Assignee: Sven Gothel
URL:
: 899 (view as bug list)
Depends on:
Blocks:
 
Reported: 2013-11-20 10:13 CET by Randolf Schultz
Modified: 2013-11-29 03:21 CET (History)
0 users

See Also:
Type: ---
SCM Refs:
e9c711a86aa05f4f24c69972532833f5a98911a3 52c95c19dbd69a7fc6b307d2b2db357ceb43ddf5 f52c89e36cccd5eb141882a4b3378efe54aa9576 586446311ea1ba87f98236d5347955bf99b465d6 efc158abbb2c282029aaa746e032ec678e374d7b
Workaround: ---


Attachments
modified source (11.02 KB, application/octet-stream)
2013-11-20 10:13 CET, Randolf Schultz
Details
modified source (5.65 KB, application/octet-stream)
2013-11-20 10:14 CET, Randolf Schultz
Details
GDIMisc.c revised to use only one thread (12.41 KB, application/octet-stream)
2013-11-22 10:11 CET, Randolf Schultz
Details
test program (636 bytes, application/octet-stream)
2013-11-27 11:23 CET, Randolf Schultz
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Randolf Schultz 2013-11-20 10:13:32 CET
Created attachment 544 [details]
modified source

Greetings,

our application (using Jogl in a GLJPanel) blocks third party software that
use the EnumWindows()/GetWindowText() Win32 functions to discover/retrieve
window title names.

The problem is that the dummy windows created by Jogl do not process any
messages. The attached files modify the window creation process to occur
each in its own thread that then falls into a message processing loop for
this window.
The dummy window destruction also needed to change to not use
DestroyWindow() but to send a WM_CLOSE message instead.
See the attached files.

With these changes in place, our application no longer blocks
other applications.

regards,
Randolf
Comment 1 Randolf Schultz 2013-11-20 10:14:22 CET
Created attachment 545 [details]
modified source
Comment 2 Sven Gothel 2013-11-20 19:37:12 CET
*** Bug 899 has been marked as a duplicate of this bug. ***
Comment 3 Sven Gothel 2013-11-20 19:39:55 CET
Dear Randolf, what is 'your application' you mention as 3rd party software .. ?

I dislike the idea of creating one native thread per dummy-window - of course,
since it would explode the number of used resources even if they are almost sleeping.

I will look at this issue later on, but also would like to learn about this test case of yours.
Such knowledge might help to find another solution for the issue.
Comment 4 Randolf Schultz 2013-11-22 10:11:45 CET
Created attachment 547 [details]
GDIMisc.c revised to use only one thread

I have revised the code to use only one extra thread.
The thread is created/destroyed with the window class.
Window creation/destruction is done via user-defined
messages. The ugly volatile stuff to communicate/sync
is still there and could be replaced by events.

This probably breaks NEWT unless the creation of the
message processing thread is confined to AWT by another
if statement (you are probably more qualified than I to
insert this one).
Comment 5 Randolf Schultz 2013-11-22 10:39:37 CET
(In reply to comment #3)
> Dear Randolf, what is 'your application' you mention as 3rd party software

it is actually a whole application scenario, in a hospital, where the
blocked application tries to connect a patient information system and
yet another system. The connecting application is probably continually
sending messages to wait for a certain window to appear.
Needless to say: all three applications are completely beyond our control.

When we run with OpenGL activated, the connecting application is
blocked. The only real solution is to start processing messages.

For testing purposes, I can provide a Win32 executable that just does
the EnumWindows()/GetWindowText() in an endless loop (just like the
connecting app) and that we also successfully block/unblock depending
on the changes to GDImisc.c...

regards,
Randolf
Comment 6 Sven Gothel 2013-11-22 11:51:27 CET
(In reply to comment #4)
> Created attachment 547 [details]
> GDIMisc.c revised to use only one thread
> 
> I have revised the code to use only one extra thread.
> The thread is created/destroyed with the window class.
> Window creation/destruction is done via user-defined
> messages. The ugly volatile stuff to communicate/sync
> is still there and could be replaced by events.

Reads much better now, thank you!

Please provide a git patch (email or pull request from a repo)
if possible. Otherwise I would need to apply your patch 
using your author name.

What I don't understand - why should we use WM_CLOSE
for destruction ? AFAIK we do not use such mechanism
in NEWT, but simply destroy the window - will double check.

> 
> This probably breaks NEWT unless the creation of the
> message processing thread is confined to AWT by another
> if statement (you are probably more qualified than I to
> insert this one).

Yes.
So this must be made optional for creating the 'window class'.

Note: All this has nothing todo w/ AWT!
Comment 7 Sven Gothel 2013-11-22 11:52:39 CET
(In reply to comment #5)
> (In reply to comment #3)
> > Dear Randolf, what is 'your application' you mention as 3rd party software
> 
> it is actually a whole application scenario, in a hospital, where the
> blocked application tries to connect a patient information system and
> yet another system. The connecting application is probably continually
> sending messages to wait for a certain window to appear.
> Needless to say: all three applications are completely beyond our control.
> 
> When we run with OpenGL activated, the connecting application is
> blocked. The only real solution is to start processing messages.
> 
> For testing purposes, I can provide a Win32 executable that just does
> the EnumWindows()/GetWindowText() in an endless loop (just like the
> connecting app) and that we also successfully block/unblock depending
> on the changes to GDImisc.c...
> 

Thank you for sharing the rational.

Pls do attach a test case (ANSI-C source code - ofc).
I will add it to the test-native folder.

It is mandatory to have this test to validate against it.

> regards,
> Randolf
Comment 8 Sven Gothel 2013-11-22 11:53:31 CET
(In reply to comment #7)
> Pls do attach a test case (ANSI-C source code - ofc).

We must be able to compile the ANSI-C source code 
w/ MINGW-64.
Comment 9 Sven Gothel 2013-11-23 21:15:32 CET
Dear Randolf,

I would appreciate your input/results,
so we can add the solution into 2.1.3 release.

If we fail 2.1.3, 2.2.0 is next and is planned to 'take a while'.

At least - pls provide the test case, to validate changes. 
Thank you!
Comment 10 Randolf Schultz 2013-11-27 11:23:21 CET
Created attachment 561 [details]
test program

Dear Sven,

sorry for getting back to you so late.

I have attached a simple test program as source.
It prints "SUCCESS!"/"FAILURE!" to the console
depending on whether there are windows that do
not process the WM_GETTEXT message.

Regarding your questions:
Sending WM_CLOSE was necessary in my first version
of the patch as this was a multi-thread scenario
and you can not use DestroyWindow() over a thread
boundary. In the one-thread version we can use
DestroyWindow() directly again, as it is called
from the ThreadFunc().

Thanks for clarification wrt. AWT, I used the term
to distinguish between NEWT and "the other integration"
we use. :)

Randolf
Comment 11 Sven Gothel 2013-11-28 14:33:06 CET
(In reply to comment #10)
> Created attachment 561 [details]
> test program
> 
> Dear Sven,
> 
> sorry for getting back to you so late.
still in time for 2.1.3 - thank you for getting back at all

> 
> I have attached a simple test program as source.
> It prints "SUCCESS!"/"FAILURE!" to the console
> depending on whether there are windows that do
> not process the WM_GETTEXT message.

Great.

> 
> Regarding your questions:
> Sending WM_CLOSE was necessary in my first version
> of the patch as this was a multi-thread scenario
> and you can not use DestroyWindow() over a thread
> boundary. In the one-thread version we can use
> DestroyWindow() directly again, as it is called
> from the ThreadFunc().

Perfect.

> 
> Thanks for clarification wrt. AWT, I used the term
> to distinguish between NEWT and "the other integration"
> we use. :)

Since you have not provided a git patch or git pull request,
[1] I need to merge your changes and hence need your 
full name  and your email address for the git commit.

Either I take your credentials as known from this bug report,
or [2] you provide a git patch (email, pull request, ..).

Regardless, I test your changes now
and hence may already performed [1].

~Sven

> 
> Randolf
Comment 12 Randolf Schultz 2013-11-28 20:52:13 CET
(In reply to comment #11)

Dear Sven,

> Since you have not provided a git patch or git pull request,
> [1] I need to merge your changes and hence need your 
> full name  and your email address for the git commit.

you can use the information from Bugzilla.

Note, that there is still some work left to do:
a) The creation of the thread must not take place for NEWT.
b) The original CreateDummyWindow0() can probably be
removed altogether (but I did not check for potential
references besides the one from GDIUtil and so left it in).

regards,
Randolf
Comment 13 Sven Gothel 2013-11-29 02:28:24 CET
e9c711a86aa05f4f24c69972532833f5a98911a3
   Initial patch allowing Jogl to respond to other applications that try to retrieve window names


52c95c19dbd69a7fc6b307d2b2db357ceb43ddf5
    Cleanup Commit e9c711a86aa05f4f24c69972532833f5a98911a3:
      - Fix while loop in SendCloseMessage (native)
    
      - static 'threadid' must be volatile
    
      - Whitespace
    
      - Redundancy
        - CreateDummyWindow
    
      - Scope (java, move JNI funcs back to private)
    
      - Remove [invalid] pointer usage (native)
        - ThreadParam's threadReady and hWndPtr shall not be pointers - invalid
        - No need to use a threadReady pointer.
    
      - Validate threadid (native)
    
    TODO:
      - Make 'native dispatch thread' optional
      - Store 'native dispatch thread' in window class


f52c89e36cccd5eb141882a4b3378efe54aa9576
    Bug 907 - Fix regression of 'cleanup' Commit 52c95c19dbd69a7fc6b307d2b2db357ceb43ddf5


586446311ea1ba87f98236d5347955bf99b465d6
    Refine DummyDispatchThread (DDT) Handling ...


586446311ea1ba87f98236d5347955bf99b465d6
    Proper OO integration of DDT in RegisteredClass
      - DDT is optional to RegisteredClass[Factory],
        i.e. NEWT without DDT and DummyWindow with DDT.
    
      - Using native type DummyThreadContext per DDT
        passed as DDT handle to java referenced in RegisteredClass
    
      - Passing DDT handle to related native methods,
        if not null use DDT - otherwise work on current thread.
        The latter impacts CreateDummyWindow0 and DestroyWindow0.
    
    Safe DDT Post/WaitForReady handling and error cases ; ...
      - Wait until command it complete using a 3s timeout
      - Terminate thread if errors occur and throw an exception
    
    +++
    
    Discussion: DDT Native Implementation
    
    Due to original code, the DDT is implemented in native code.
    Usually we should favor running the DDT from a java thread.
    However, since it's main purpose is _not_ to interact w/ java
    and the native implementation has less footprint (performance and memory)
    we shall be OK w/ it for now - as long the implementation IS SAFE.
Comment 14 Sven Gothel 2013-11-29 03:19:25 CET
efc158abbb2c282029aaa746e032ec678e374d7b
  Add native Windows test sending WM_GETTEXT to all windows and dumping the result. 
  If working, Bug907 is fixed and hence DDT is working.