2009-07-29 18 views
3

我試圖擴展第三方應用程序,以便除了使用窗體窗體GUI(需要混合模式)外,還可以通過命令行調用它。這是一個相當簡單的程序,基本上加載一個文件,然後你點擊一個按鈕開始發送UDP網絡數據包。添加了{APPTYPE CONSOLE}指令,現在我的應用程序運行非常緩慢。移動鼠標使其運行速度更快

我需要調用另一個應用程序,並希望傳入參數,並且需要能夠將ExitCode返回給調用應用程序。從我讀過的,爲了做到這一點,你需要添加編譯器指令{APPTYPE CONSOLE}。

我做到了這一點,我的應用程序工作,因爲我想它,除了發送網絡數據包緩慢爬行。 我發現,只要我在窗體上移動鼠標。網絡傳輸速率顯着增加。我懷疑有某種類型的Windows消息隊列問題,並且移動的鼠標造成中斷,這反過來導致消息隊列被處理?

我搜索了一遍,並嘗試調用Application.ProcessMessages和PeekMessages在1ms間隔的計時器,並沒有任何幫助。我發現在這個user manual for some other application它說Indy 10在APPTYPE CONSOLE和GUI類型都支持。坦率地說,這只是讓我感到困惑,因爲我認爲所有的網絡庫都可以在兩種模式下工作......但就像我說的,我不熟悉Delphi。

我認爲這個問題在我的應用程序中被隔離到一行,並且是否包含{APPTYPE CONSOLE}。

任何人有任何想法?

版本信息:
德爾福7個人(編譯4.453)
印第9.0.4

回答

6

如果您將{APPTYPE CONSOLE}添加到您的應用程序中,即使您希望混合模式執行,那麼即使應用程序處於GUI模式下,您也必須使用控制檯。你當然可以關閉控制檯,但是這會導致一些閃爍,並且對我感覺有點ha ish。

你應該可以在沒有控制檯程序的情況下做你想做的事情。一個小的測試程序證明該退出代碼可以從GUI程序被讀取:

@echo off 
start /WAIT project1.exe 
echo %ERRORLEVEL% 

程序將顯示其主要形式1秒:

procedure TForm1.Timer1Timer(Sender: TObject); 
begin 
    Close; 
end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    ExitCode := 42; 
    Timer1.Interval := 1000; 
    Timer1.Enabled := TRUE; 
end; 

如果這是與以下CMD文件執行,關閉,並且腳本在控制檯窗口上打印42。

現在捕獲輸出 - 如果允許使用臨時文件,那麼從GUI程序執行此操作實際上比從控制檯程序執行更容易。您需要使用命令行參數啓動程序,爲什麼不給它一個臨時文件的名稱,等待應用程序完成,讀取文件並在之後刪除它?

2

如果你想要一個應用程序返回一個「錯誤」的代碼沒有必要讓它控制檯應用程序。您只需設置ExitCode,例如

ExitCode := 10; 
在批處理文件

@Echo off 
project1 
echo %errorlevel% 

將顯示應用

,然後顯示10時。

注意:也可以使用AllocConsole從Windows API動態創建控制檯窗口,或使用AttachConsole附加。

我爲此創建了一個對象包裝,但不再有可用的代碼。從內存中它不支持重定向(因爲我不需要它)。

+0

我試過了。它將回顯0.當應用程序不包含{APPTYPE CONSOLE}行時,從命令行調用應用程序時,它立即返回。然而...如果可能的工作是「開始/等待」。明天我會試一試。 – blak3r 2009-07-29 06:03:26

+0

@Gerry我首先給出了建議ExitCode方法的+1。我認爲mghie的回答比較完整,所以我選擇他作爲公認的解決方案。感謝您的貢獻! – blak3r 2009-07-30 05:35:49

0

一個1ms的計時器只會在每40毫秒時觸發一次(由於Windows的限制),所以它無濟於事。我已經看到了像混合控制檯和GUI應用程序一樣的效果,另一個原因是它們沒有正確地最小化。

而不是在項目中啓用控制檯,您可能可以使用CreateConsole API調用(不知道名稱是否正確)在程序啓動後創建一個。我沒有看到我已經完成了這個(!)程序的不利影響。

但是,這隻有在您想要寫入控制檯時纔有必要。如果您只想處理命令行參數並返回退出代碼,則不需要控制檯。只需評估參數的ParamCount/ParamStr函數併爲返回值設置ExitCode即可。

+0

@dummzeuch感謝您的建議。查看我剛剛添加到Gerry的帖子中的評論。我希望使用真正的控制檯窗口,以便調用應用程序可以捕獲它的標準輸出。至於計時器,我認爲即使在40ms運行它也會稍稍改善時間......但事實並非如此。每個樣本花了14s。如果它已經工作,我可能會添加20-40定時器作爲解決方法哈哈。但是,因爲它沒有 - 我認爲這是一個線索,Application.ProcessMessages不是開始的問題... – blak3r 2009-07-29 06:28:48

+1

而且一個計時器的功能是因爲Windows消息,所以嘗試驅動消息泵很有趣通過對來自同一個消息泵的消息作出反應。 – 2009-07-29 07:30:07

0

如果您的控制檯應用程序的某些線程調用同步(我猜印的東西實際上是這樣做),你必須做一些準備工作:

分配到WakeMainThread變量的方法。此方法必須具有TNotifyEvent的簽名。

該方法內部調用CheckSynchronize

欲瞭解更多信息,請參閱德爾福幫助這兩個項目。

1

如果我理解正確的話,那麼你希望你的應用程序有兩種模式:

  1. 如果沒有參數傳遞,在非GUI模式,否則在GUI模式下運行
  2. 運行

最簡單的是,如果您可以集中您的邏輯,以便可以從一種方法調用(CoreLogic在我的示例中)。

下面的應用程序應該工作正常。

兩個技巧:

  1. Application.ShowMainForm:= FALSE;根本不會使MainForm顯示。
  2. ExitCode:= 327;它將設置您的返回碼(如mghieGerry已經提到)。

的幾個注意事項:

  • 因爲CoreLogic不處理任何窗口消息,什麼都在你的應用程序依賴於Windows消息正在處理將停止。
  • ,如果你需要的窗口消息處理,然後就所有Application.ProcessMessages()您CoreLogic
  • 裏面,如果你需要你的表格是可見的,那麼你就改變你的MainForm內部的邏輯來測試命令行參數,並在完成工作後退出(通過調用Application.Terminate())。放入該邏輯的最佳位置是MainForm.OnShow事件的事件方法。

希望這有助於:-)

program VCLAppThatDoesNotShowMainForm; 

uses 
    Forms, 
    MainFormUnit in 'MainFormUnit.pas' {MainForm}, 
    Windows; 

{$R *.res} 

procedure CoreLogic; 
begin 
    Sleep(1000); 
    ExitCode := 327; 
end; 

procedure TestParams; 
begin 
    if ParamCount > 0 then 
    begin 
    MessageBox(0, CmdLine, PChar(Application.Title), MB_ICONINFORMATION or MB_OK); 
    CoreLogic(); 
    Application.ShowMainForm := False; 
    end; 
end; 

begin 
    Application.Initialize(); 
    Application.MainFormOnTaskbar := True; 
    TestParams(); 
    Application.CreateForm(TMainForm, MainForm); 
    Application.Run(); 
end. 
相關問題