2015-12-11 67 views
10

我成功地在正在運行的Oracle Forms應用程序中使用DLL注入和一些jni技巧注入自己的Java代碼。 (Windows 7中,32位,的Oracle Forms 11,JRE爪哇8)如何選擇AWT-EventQueue線程,其中有幾個線程

我能夠遍歷組件的樹和查詢,並且在一些基本的Java對象,如那些從類設定值oracle.forms.ui.VTextField

試圖模擬一個oracle.apps.fnd.ui.Button

用戶點擊我想兩兩件事,當我卡住:

  1. 通話AbstractButton
  2. simulatePush方法
  3. 呼叫的PushButton

(2類在類層次結構Button)的activate方法

結果是相同的: 1.首先,它正常工作:當按鈕是「搜索」按鈕,搜索完成並顯示結果。 2.然後,它立即中斷應用程序,彈出窗口說FRM-92100 Your connection to the Server was interrupted

從那裏,應用程序被掛起。

更新: 看來,從服務器會導致斷線的錯誤是:

java.lang.SecurityException異常:此KeyboardFocusManager不是在 的Java安裝在當前線程的上下文 。 (未知源) at java.awt.KeyboardFocusManager.processSynchronousLightweightTransfer(Unknown Source)在在 java.awt.Component中 sun.awt.windows.WComponentPeer.processSynchronousLightweightTransfer(本地 法)以sun.awt.windows.WComponentPeer.requestFocus(未知 來源)在java.awt.Component.requestFocusHelper(來源不明) .requestFocusHelper(Unknown Source)at java.awt.Component.requestFocus(Unknown Source)at oracle.forms.handler.UICommon.updateFocus(Unknown Source)at oracle.forms.handler.UICommon.setFVP(Unknown Source)at oracle.forms.handler.UICommon.setFVP(未知來源)處 oracle.forms.handler.ComponentItem.onUpdate(未知來源) oracle.forms.handler.UICommon.onUpdate(未知來源)在 oracle.forms。 handler.JavaContaine r.onUpdate(Unknown Source)at oracle.forms.handler.UICommon.onUpdate(Unknown Source)at oracle.forms.engine.Runform.onUpdateHandler(Unknown Source)at oracle.forms.engine.Runform.processMessage(Unknown來源)at oracle.forms.engine.Runform.processSet(Unknown Source)at oracle.forms.engine.Runform.onMessageReal(Unknown Source)at oracle.forms.engine.Runform.onMessage(Unknown Source)at oracle .forms.engine.Runform.processEventEnd(Unknown Source)at oracle.ewt.lwAWT.LWComponent。redispatchEvent完成(來源不明)處 oracle.ewt.lwAWT.LWComponent.processEvent(來源不明)在 oracle.ewt.button.PushButton.activate(來源不明)在 sun.reflect.NativeMethodAccessorImpl.invoke0(本機方法) sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)at java.lang.reflect.Method.invoke(Unknown Source)at CustomAWT.run(CustomAWT.java:34 )at java.awt.event.InvocationEvent.dispatch(Unknown Source)at java.awt.EventQueue.dispatchEventImpl(Unknown Source)at java.awt.EventQueue.access $ 400(Unknown Source)at 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.run(未知來源)java.awt.EventDispatchThread.pumpEvents(未知來源)

我的代碼在這裏: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. 

因此,有AWT-EventQueue線程。問題是現在:如何查詢/檢索正確的,以及如何傳遞給invokeLater在「好線程」運行Runnable(我猜的不錯的一個是最後一個(AWT-EventQueue-2

+0

你試過'separateFrame =「True」applet參數嗎? – dan

+0

@dan我無法更改服務器上的任何內容。不知道我明白你的建議。 Oracle Forms應用程序(Oracle應用程序電子商務中心)已經作爲Window Desktop的子窗口運行。 – manuell

回答

1

了很多實驗和谷歌的搜索後與像EventQueueThreadGroup我終於找到了解決方案(在對我的作品類別,請注意)關鍵字。

我使用sun.awt.AppContext類。一些文件和源代碼here(grepcode.com)

  1. 獲取使用getAppContexts方法運行AppContext的集合。
  2. 對於每個檢索到的AppContext,使用getThreadGroup方法得到他的ThreadGroup
  3. 對於ThreadGroup對象,請使用getName方法。
  4. 當線程組的名稱以表單應用程序的http:地址開頭時,使用AppContextget方法檢索密鑰名稱爲sun.awt.AppContext.EVENT_QUEUE_KEYObject屬性。
  5. 檢索到的對象是EventQueue。創建一個java.awt.event.InvocationEvent對象,將Runnable傳遞給CTOR,並使用EventQueuepostEvent方法。
  6. 您的run方法將在右側線程中執行。

備註:

  • 這個答案是具體的,對我的作品中,Oracle的解決方案通過表格的Internet Explorer中的鏈接啓動的應用程序,並在java.exe的進程中運行。在這種情況下,3個線程組如下面的問題所示:main,Plugin Thread Grouphttp://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方法測試了OK。
  • 此處模擬的方法是invokeLater。對於invokeAndWait,在postEvent呼叫周圍需要更多代碼。作爲起點,請參閱EventQueue類的一些源。
0

你應該能夠延長VButton類 您的類定義應作爲s omething像:

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 ; 
    } 

    } 

希望這段代碼適合你。

問候

+0

我不明白爲什麼這應該是我的問題的答案,對不起。請仔細閱讀這個問題。我的問題是在正確的EDT線程中調用GUI方法。 – manuell

0

我成功注入自己的Java代碼在運行Oracle Forms應用程序,使用DLL注入和一些JNI掛羊頭賣狗肉。

這裏是真正的問題,IMO。

您患有目標固定,這意味着程序員對於他們想要什麼樣的解決方案有一個固定的心理想法,並且這會讓您將其視爲一切。目標固定導致飛機失事,因爲即使是經驗豐富和智能化的飛行員(實際上是整個駕駛艙!)也已經在一個問題上變得如此固執,以至於讓其他災難滑向右邊。

擺脫這種心態。

您所需的解決方案沒有解決,所以繼續前進並嘗試其他方法。就像@ nightfox79已經提供給您的明智選項以及其中的變體一樣。

你試圖繞過一個複雜的對象類,當你應該簡單地擴展現有的類,你試圖破解你的方式。這是面向對象開發的整個基礎。

DLL/JNI Trickery在合理的解決方案,IMO中沒有任何地方。

我很遺憾那些必須維護和修復任何基於DLL/JNI hack的代碼解決方案的人。這樣瘋狂的謊言。

您的理論認爲invokeLater()未在正確的EDT下運行可能是錯誤的。 invokeLater()將根據文檔總是將您請求的代碼排入AWT事件處理程序的待處理代碼列表中,這正是它應該在的位置。試圖繞過這幾乎肯定會導致可怕的問題。 invokeLater()的全部目的是推遲您調用EDT中的重量級處理,並稍後在完全相同的線程上運行它。如果不是,IMO就是invokeLater()中的一個bug。但是,如果你想檢查哪些線程代碼正在運行,那麼我知道的唯一的測試就是在你的代碼中使用它;

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

我無法修改Oracle Forms應用程序。當我的注入代碼使用'involkeLater'時,'Runnable'最終運行在名爲'AWT-EventQueue-0'的線程中。當我使用'getSystemEventQueue'和'postEvent'以及'InvocationEvent'時,同樣的事情。請參閱問題中的線索列表。我應該使用的EDT命名爲'AWT-EventQueue-2',這實際上是我安裝'AWTEventListener'時調用的那個。問題是如何選擇正確的'EventQueue' /'EDT'。 – manuell

+0

本質上,您試圖繞過聽起來非常像安全屏障的東西 - 畢竟,您的代碼會拋出SecurityException。如果你不允許或不能在正確的線程上安裝事件監聽器,那麼你可能不應該這樣做。你應該接受這一點,並找到一個不同的解決方案,無論你實際上試圖提供的功能方式。有時候這是唯一的解決方案。 – StephenG

+0

我被允許並能夠安裝我自己的'AWTEventListener',並且我正確地接收'AWT-EventQueue-2' Java線程中的所有事件。 「模擬按鈕動作」的請求是與另一個進程異步的,這就是爲什麼我需要一種方法來獲取好的EventQueue(因爲如果我只使用'getSystemEventQueue',我的'Runnable'將運行在'AWT-EventQueue- 0')。 – manuell

0

我也試圖在正在運行的Oracle Forms應用程序中推送我的Java代碼,基本上我試圖通過UI自動化Oracle表單流,從上面的評論看來,您似乎做得太棒了,能不能指導我爲此,我創建了Java代理,問題是如何注入運行在web.and中運行的oracle窗體小程序,第二個問題是在我的java代理中使用premain方法時,我應該如何使用oracle窗體對象識別,爲正常的小程序,我使用Toolkit tk = Toolkit.getDefaultToolkit();然後我正在收聽窗口派發的事件。在此引導我,我嚴重地面臨着自動化這個問題

1

要獲得正確的EDT線程,無論您的線程組是什麼,可以使用SunToolkit.targetToAppContext(Object target),並且對於參數可以提供您打算採取行動的AWT組件。示例source

然後使用EventQueue eq = SunToolkit.getSystemEventQueueImplPP(appContext);

終於搞定EventQueue中,創建您可運行一個新的InvocationEvent,並呼籲EQ事件後。

相關問題