3

WindowsフォームのGUIを使用するだけでなく、コマンドラインから呼び出すことができるようにサードパーティのアプリケーションを拡張しようとしています(混合モードが望ましい)。これは、基本的にファイルをロードし、ボタンをクリックしてUDPネットワークパケットの送信を開始する非常に単純なプログラムです。

別のアプリケーションからアプリケーションを呼び出す必要があり、引数を渡したいので、ExitCodeを呼び出し元のアプリに返すことができる必要があります。私が読んだことから、そうするためには、コンパイラ指令{APPTYPECONSOLE}を追加する必要があります。

私はこれを行い、ネットワークパケットの送信速度が低下してクロールすることを除いて、アプリケーションは希望どおりに機能しました。 フォーム上でマウスを動かすたびに気づきました。ネットワーク転送速度が大幅に増加したこと。ある種のWindowsメッセージキューの問題があり、マウスを動かすと割り込みが発生し、メッセージキューが処理されるのではないかと思います。

私はグーグルで検索し、1ms間隔のタイマーでApplication.ProcessMessagesとPeekMessagesを呼び出してみましたが、まったく役に立ちませんでした。他のアプリケーションのこのユーザーマニュアルで、Indy10はAPPTYPECONSOLEタイプとGUIタイプの両方でサポートされていると書かれていることがわかりました。率直に言って、すべてのネットワークライブラリが両方のモードで動作すると想定していたので、これは私を混乱させます...しかし、私が言ったように、私はDelphiに精通していません。

この問題は私のアプリケーションでは1行に限定されており、それは{APPTYPECONSOLE}が含まれているかどうかに関係していると確信しています。

誰かアイデアはありますか?

バージョン情報:
Delphi 7 Personal(ビルド4.453)
Indy 9.0.4

4

5 に答える 5

6

{APPTYPE CONSOLE}混合モードでの実行が必要な場合でもアプリケーションに追加する場合は、アプリケーションがGUIモードの場合でも、コンソールを使用する必要があります。もちろんコンソールを閉じることもできますが、これはちらつきを引き起こし、私には少しハックな感じがします。

コンソールプログラムがなくても、やりたいことができるはずです。小さなテストプログラムは、GUIプログラムから終了コードを読み取ることができることを証明します。

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

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

これが次のcmdファイルで実行される場合:

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

プログラムはメインフォームを1秒間表示して閉じ、スクリプトはコンソールウィンドウに42を出力します。

出力をキャプチャするために、一時ファイルの使用を許可している場合、GUIプログラムからこれを行うことは、コンソールプログラムから行うよりも実際には簡単です。とにかくコマンドラインパラメータでプログラムを起動する必要があるので、一時ファイルの名前を付けて、アプリケーションが終了するのを待って、ファイルを読み込んでから削除してみませんか?

于 2009-07-29T07:41:22.777 に答える
2

アプリケーションが「エラー」コードを返すようにしたい場合は、それをコンソールアプリケーションにする必要はありません。ExitCodeを設定するだけで済みます。例:

ExitCode := 10;

バッチファイルで

@Echo off
project1
echo %errorlevel%

アプリケーションを表示し、次に10を表示します。

注:AllocConsoleを使用してWindows APIから動的にコンソールウィンドウを作成したり、AttachConsoleを使用してアタッチしたりすることもできます。

このためのオブジェクトラッパーを一度作成しましたが、コードを使用できなくなりました。メモリからはリダイレクトをサポートしていませんでした(私はそれを必要としなかったため)。

于 2009-07-29T03:25:44.197 に答える
1

私があなたを正しく理解しているなら、あなたはあなたのアプリに2つのモードを持たせたいと思います:

  1. 引数が渡されない場合は、GUIモードで実行します
  2. それ以外の場合は、非GUIモードで実行します

最も簡単なのは、ロジックを一元化して、1つのメソッド(私の例ではCoreLogic )から呼び出すことができる場合です。

以下のアプリは正常に動作するはずです。

2つのトリック:

  1. Application.ShowMainForm:= False; MainFormはまったく表示されません。
  2. ExitCode:= 327; これにより、リターンコードが設定されます(すでに述べたmghieGerryなど)。

いくつかの注意:

  • CoreLogicはWindowsメッセージを処理しないため、処理中のWindowsメッセージに依存するアプリケーション内のすべてが停止します。
  • Windowsメッセージ処理が必要な場合は、CoreLogic内のすべてのApplication.ProcessMessages()のみ
  • フォームを表示する必要がある場合は、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.
于 2009-07-30T08:53:35.497 に答える
0

1msのタイマーは、(Windowsの制限により)約40 msごとにのみ起動するため、役に立ちません。コンソールアプリとGUIアプリが混在している場合に説明するような効果を見てきましたが、もう1つは、適切に最小化されないことです。

プロジェクトでコンソールを有効にする代わりに、プログラムの開始後にCreateConsole API呼び出し(名前が正しいかどうかわからない)を使用してコンソールを作成することもできます。私がこれを行った1つの(!)プログラムで悪影響は見られませんでした。

ただし、これはコンソールに書き込みたい場合にのみ必要です。コマンドラインパラメータを処理して終了コードを返すだけの場合は、コンソールは必要ありません。パラメータのParamCount/ParamStr関数を評価し、戻り値のExitCodeを設定するだけです。

于 2009-07-29T05:48:24.970 に答える
0

コンソールアプリケーションの一部のスレッドがSynchronizeを呼び出す場合(そしてIndyのものが実際にそれを行っていると思います)、いくつかの準備をする必要があります。

WakeMainThread変数にメソッドを割り当てます。このメソッドには、TNotifyEventの署名が必要です。

このメソッド内でCheckSynchronizeを呼び出します。

詳細については、これら2つの項目に関するDelphiヘルプを参照してください。

于 2009-07-29T11:45:24.423 に答える