Подтвердить что ты не робот

Как выбрать поток AWT-EventQueue, когда есть несколько из них

Я успешно ввел свой собственный Java-код в запущенное приложение Oracle Forms, используя DLL Injection и некоторые jni-обманки. (Windows 7, 32 бита, Oracle Forms 11, JRE Java 8)

Я могу пересекать дерево Компонентов и запрашивать и устанавливать значения в некоторых базовых объектах Java, например, из класса oracle.forms.ui.VTextField

Я застреваю при попытке имитировать пользователя, нажмите oracle.apps.fnd.ui.Button

Я пробовал 2 вещи:

  • вызывать метод simulatePush класса AbstractButton
  • вызов метода activate класса PushButton

(2 класса находятся в иерархии классов для Button)

Результаты были идентичны:  1. Сначала он работает нормально: когда кнопка является кнопкой "Поиск", поиск выполняется, и результаты отображаются.  2. Затем он немедленно разрывает приложение с всплывающим высказыванием FRM-92100 Your connection to the Server was interrupted.

Оттуда приложение висит.

Update: Похоже, что ошибка, вызывающая отсоединение от Сервера:

java.lang.SecurityException: этот KeyboardFocusManager не является установленный в текущем контексте потока в java.awt.KeyboardFocusManager.checkCurrentKFMSecurity(Неизвестный источник)   на java.awt.KeyboardFocusManager.getGlobalFocusOwner(Неизвестный источник)   в java.awt.KeyboardFocusManager.processSynchronousLightweightTransfer(Неизвестно Источник) в sun.awt.windows.WComponentPeer.processSynchronousLightweightTransfer(Native Метод) на sun.awt.windows.WComponentPeer.requestFocus(Неизвестно Источник) в java.awt.Component.requestFocusHelper(Неизвестный источник) в java.awt.Component.requestFocusHelper(Неизвестный источник) в java.awt.Component.requestFocus(Неизвестный источник) в oracle.forms.handler.UICommon.updateFocus(Неизвестный источник) в oracle.forms.handler.UICommon.setFVP(Неизвестный источник) в oracle.forms.handler.UICommon.setFVP(Неизвестный источник) в oracle.forms.handler.UICommon.onUpdate(Неизвестный источник) в oracle.forms.handler.ComponentItem.onUpdate(Неизвестный источник) в oracle.forms.handler.JavaContainer.onUpdate(Неизвестный источник) в oracle.forms.handler.UICommon.onUpdate(Неизвестный источник) в oracle.forms.engine.Runform.onUpdateHandler(Неизвестный источник) в oracle.forms.engine.Runform.processMessage(Неизвестный источник) в oracle.forms.engine.Runform.processSet(Неизвестный источник) в oracle.forms.engine.Runform.onMessageReal(Неизвестный источник) в oracle.forms.engine.Runform.onMessage(Неизвестный источник) в oracle.forms.engine.Runform.processEventEnd(Неизвестный источник) в oracle.ewt.lwAWT.LWComponent.redispatchEvent(Неизвестный источник) в oracle.ewt.lwAWT.LWComponent.processEvent(Неизвестный источник) в oracle.ewt.button.PushButton.activate(Неизвестный источник) в sun.reflect.NativeMethodAccessorImpl.invoke0 (собственный метод) в sun.reflect.NativeMethodAccessorImpl.invoke(Неизвестный источник) в sun.reflect.DelegatingMethodAccessorImpl.invoke(Неизвестный источник) в java.lang.reflect.Method.invoke(Неизвестный источник) в CustomAWT.run(CustomAWT.java:34) в java.awt.event.InvocationEvent.dispatch(Неизвестный источник) в java.awt.EventQueue.dispatchEventImpl(Неизвестный источник) в java.awt.EventQueue.access $400 (Неизвестный источник) в java.awt.EventQueue $2.run(Неизвестный источник) в java.awt.EventQueue $2.run(Неизвестный источник) в java.security.AccessController.doPrivileged(собственный метод) в java.security.AccessControlContext $1.doIntersectionPrivilege(Неизвестно Источник) в java.awt.EventQueue.dispatchEvent(Неизвестный источник) в java.awt.EventDispatchThread.pumpOneEventForFilters(Неизвестный источник)   в java.awt.EventDispatchThread.pumpEventsForFilter(Неизвестный источник)   в java.awt.EventDispatchThread.pumpEventsForHierarchy(Неизвестно Источник) в java.awt.EventDispatchThread.pumpEvents(Неизвестный источник)   в java.awt.EventDispatchThread.pumpEvents(Неизвестный источник) в java.awt.EventDispatchThread.run(Неизвестный источник)

Мой код здесь: CustomAWT.run(CustomAWT.java:34) и вызывается с invokeLater. Вероятно, проблема заключается в том, что при вызове метода oracle.ewt.button.PushButton.activate я НЕ прав в EDT.

Используя "Список потоков" в консоли Java, я получил:

Dump thread list ...
Group main,ac=30,agc=2,pri=10
    main,5,alive
    traceMsgQueueThread,5,alive,daemon
    Timer-0,5,alive
    Java Plug-In Pipe Worker Thread (Client-Side),5,alive,daemon
    AWT-Shutdown,5,alive
    AWT-Windows,6,alive,daemon
    AWT-EventQueue-0,6,alive
    SysExecutionTheadCreator,5,alive,daemon
    CacheMemoryCleanUpThread,5,alive,daemon
    CacheCleanUpThread,5,alive,daemon
    Browser Side Object Cleanup Thread,5,alive
    JVM[id=0]-Heartbeat,5,alive,daemon
    Windows Tray Icon Thread,5,alive
    Thread-13,5,alive
Group Plugin Thread Group,ac=3,agc=0,pri=10
    AWT-EventQueue-1,6,alive
    TimerQueue,5,alive,daemon
    ConsoleWriterThread,6,alive,daemon
Group http://xxxx.xxxx.xxxxx.xx:8001/OA_JAVA/-threadGroup,ac=13,agc=0,pri=4
    Applet 1 LiveConnect Worker Thread,4,alive
    AWT-EventQueue-2,4,alive
    thread applet-oracle/apps/fnd/formsClient/FormsLauncher.class-1,4,alive
    Applet 2 LiveConnect Worker Thread,4,alive
    thread applet-oracle.forms.engine.Main-2,4,alive
    Forms-StreamMessageReader,4,alive
    Forms-StreamMessageWriter,4,alive
    HeartBeat,4,alive
    Busy indicator,1,alive,daemon
    TaskScheduler timer,4,alive
    CursorIdler,4,alive
    Thread-14,4,alive
    Flush Queue,4,alive
Done.

Итак, есть потоки THREE AWT-EventQueue... Вопрос теперь: как выполнить запрос/получить правильный и как сделать Runnable пройденный invokeLater для запуска в "Хорошей теме" (я думаю, что хороший является последним (AWT-EventQueue-2)

4b9b3361

Ответ 1

После большого количества экспериментов и поиска в Google с такими ключевыми словами, как EventQueue и ThreadGroup, я наконец нашел решение (в категории "Работы для меня", заметьте).

Я использую класс sun.awt.AppContext. Некоторые документы и источники здесь (grepcode.com)

  • Получить коллекцию запущенного AppContext с помощью метода getAppContexts.
  • Для каждого полученного AppContext получить его ThreadGroup с помощью метода getThreadGroup.
  • С объектом ThreadGroup используйте метод getName.
  • Когда имя группы потоков начинается с http: address вашего приложения Forms, извлеките свойство Object с именем ключа sun.awt.AppContext.EVENT_QUEUE_KEY, используя метод get AppContext.
  • Восстановленный объект - EventQueue. Создайте объект java.awt.event.InvocationEvent, передав Runnable в CTOR и используйте метод postEvent EventQueue.
  • Ваш метод run будет выполнен в нужном потоке.

Примечания:

  • Этот ответ является конкретным, работает для меня, решением для приложения Oracle Forms, запущенным через ссылку Internet Explorer, и работает в процессе java.exe. В этой ситуации 3 группы тем, как показано в вопросе: main, Plugin Thread Group и http://xxxx.xxxx.xxxxx.xx:8001/OA_JAVA/-threadGroup Ваш пробег может отличаться.
  • Если вы не используете полное отражение, но вместо этого импортируете sun.awt.AppContext, компилятор может выдать предупреждения в форме warning: sun.awt.AppContext is Sun proprietary API and may be removed in a future release Это не очень здорово, но пока я буду жить с этим.
  • В методе run я протестировал ОК с помощью метода simulatePush oracle.ewt.lwAWT.AbstractButton.
  • Эмулируемый здесь метод invokeLater. Для invokeAndWait требуется больше кода вокруг вызова postEvent. См. Некоторые источники для класса EventQueue в качестве отправной точки.

Ответ 2

Чтобы получить правильный поток EDT независимо от вашей группы потоков, вы можете использовать SunToolkit.targetToAppContext(Object target), а для параметра вы можете подать ему компонент AWT, на который вы намереваетесь действовать. Пример источник.

Затем получите EventQueue с помощью EventQueue eq = SunToolkit.getSystemEventQueueImplPP(appContext);

Наконец, создайте новый InvocationEvent с вашим runnable и вызовите postEvent в эквалайзе.

Ответ 3

Вы должны расширить класс VButton Определение вашего класса должно быть примерно таким:

public class AmazingButton extends VButton implements FocusListener

Затем вам понадобится класс init, например:

public void init(IHandler handler)
  {
    m_handler = handler;
    super.init(handler);
    addMouseListener(new ButtonMouseAdapter());
    addFocusListener(this);
  }  

И после этого вам нужно реализовать слушателей и сделать что-то в нем:

public void focusGained(FocusEvent e)
     {
         if (e.getComponent() == this)
         {
             // put the focus on the component
             e.getComponent().requestFocus();
             bFocus = true ;
         }
     }

  public void focusLost(FocusEvent e)
     {     
       bFocus = false ;
     }

  /**
   * Private class to handle user mouse actions
   */
  class ButtonMouseAdapter extends MouseAdapter
  {
    /**
     * User moved the mouse over the button
     */
    public void mouseEntered(MouseEvent me)
    {
      bFocus=true ;
      mouseON();
    }

    /**
     * User moved the mouse out of the button
     */
    public void mouseExited(MouseEvent me)
    {
      bFocus=false ;
      mouseOFF();
    }
    /**
     * User moved the mouse out of the button
     */
    public void mousePressed(MouseEvent me)
    {
      bPressed = true ;
    }
    /**
     * User moved the mouse out of the button
     */
    public void mouseReleased(MouseEvent me)
    {
      bPressed = false ;
    }

  }

Я надеюсь, что этот код работает для вас.

Привет

Ответ 4

Я успешно ввел свой собственный Java-код в запущенное приложение Oracle Forms, используя DLL Injection и некоторые jni-обманки.

Это реальная проблема здесь, ИМО.

Вы страдаете от фиксации цели, а это значит, что у вас, программиста, есть четкая мысленная идея о том, какое решение они хотят, и это ослепляет вас во всем остальном. Целевая фиксация привела к авиационным авариям, так как даже опытные и умные пилоты (на самом деле целые кабины!) Стали настолько зацикленными на одной проблеме в одном сознании, что позволили другим бедствиям проскользнуть прямо.

Выйдите из этого настроения.

Ваше желаемое решение не работает, поэтому перейдите и попробуйте что-то еще. Как и разумный вариант, уже представленный вам by @nightfox79 и варианты этого.

Вы пытаетесь обойти сложный класс объектов, когда вам, вероятно, просто нужно расширить существующий класс, который вы пытаетесь взломать. Что вся основа развития ООП.

DLL/JNI Trickery не имеет места в разумном решении IMO.

И я жалею того, кто должен поддерживать и исправлять любое решение кода на основе взлома DLL/JNI. В этом безумие лежит.

Ваша теория о том, что invokeLater() не работает под правильным EDT, вероятно, неверна. invokeLater() будет, согласно документации, всегда ставить очередь запрошенного кода в список ожидающих кодов для обработчика события AWT, который именно там и должен быть. Попытка обойти это почти наверняка вызовет ужасные проблемы. Вся цель invokeLater() состоит в том, чтобы отложить обработку тяжеловеса в EDT, с которой вы его вызываете, и запустить его позже в том же потоке. Это ошибка в invokeLater(), если это не так, IMO.

Если, однако, вы хотите проверить, какой код потока запущен, тогда единственным тестом, который я знаю, является использование этого в вашем коде;

if (SwingUtilities.isEventDispatchThread())
{
    System.err.println("Is running on EDT");
}
else
{
    System.err.println("Is not running on EDT");
}

Ответ 5

Я также пытаюсь подтолкнуть свой Java-код к запущенному приложению Oracle Forms, в основном я пытаюсь автоматизировать поток форматов oracle через пользовательский интерфейс, из комментариев выше кажется, что вы сделали фантастическую работу, чтобы сделать это, можете ли вы мне помочь это, я создал java-агент, проблема заключается в том, как добавить, что при запуске апплета создается апплет, который работает в web.and вторая проблема заключается в работе над методом premain в моем java-агенте, что я должен использовать для идентификации объекта формы оракула, для normal applet Я использую Toolkit tk = Toolkit.getDefaultToolkit(); и затем я слушаю рассылаемое событие из окон. Вслух расскажу мне об этом, я серьезно столкнулся с проблемой автоматизации этого