添加了{APPTYPE CONSOLE}指令,现在我的应用程序运行速度非常慢。移动鼠标使其运行得更快

时间:2009-07-29 02:21:09

标签: delphi message-queue delphi-7 indy

我正在尝试扩展第三方应用程序,以便除了使用Windows窗体GUI(需要混合模式)之外,还可以通过命令行调用它。这是一个相当简单的程序,基本上加载一个文件然后你点击它开始发送UDP网络数据包的按钮。

我需要从另一个调用应用程序并希望传入一个参数,并且需要能够将ExitCode返回给调用应用程序。根据我的阅读,为了做到这一点,你需要添加编译器指令{APPTYPE CONSOLE}。

我做了这个,我的应用程序按照我的意愿工作,除了发送网络数据包减慢到爬行。 我发现每当我在表格上移动鼠标时。网络传输速率显着提高。我怀疑存在某种类型的Windows消息队列问题,移动鼠标是否会导致中断,从而导致消息队列被处理?

我已经google了一下,尝试在Timer中调用Application.ProcessMessages和PeekMessages,间隔为1毫秒,这根本没有帮助。我在这个user manual for some other application中发现它表示在APPTYPE CONSOLE和GUI类型中都支持Indy 10。坦率地说,这让我感到困惑,因为我认为所有网络库都可以在两种模式下工作......但就像我说我不熟悉Delphi一样。

我很肯定该问题在我的应用程序中被隔离到一行,即是否包含{APPTYPE CONSOLE}。

有人有什么想法吗?

版本信息:
Delphi 7 Personal(Build 4.453)
Indy 9.0.4

5 个答案:

答案 0 :(得分: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程序执行此操作实际上比从控制台程序执行此操作更容易。您需要使用命令行参数启动程序,所以为什么不给它一个临时文件的名称,等待应用程序完成,读入文件并在之后删除它?

答案 1 :(得分:2)

如果您希望应用程序返回“错误”代码,则无需将其作为控制台应用程序。您只需要设置ExitCode,例如

ExitCode := 10;

在批处理文件中

@Echo off
project1
echo %errorlevel%

将显示应用程序,然后显示10。

注意:也可以使用AllocConsole从Windows API动态创建控制台窗口,或使用AttachConsole进行附加。

我为此创建了一个对象包装器,但不再提供代码。从内存中它不支持重定向(因为我不需要它)。

答案 2 :(得分:1)

如果我理解正确,那么您希望您的应用有两种模式:

  1. 如果未传递任何参数,请以GUI模式运行
  2. 以非GUI模式运行,否则
  3. 最简单的方法是,如果您可以集中逻辑,那么可以从一个方法调用它(在我的示例中是 CoreLogic )。

    以下应用程序应该可以正常工作。

    两招:

    1. Application.ShowMainForm:= False; 根本不会显示主要节目。
    2. ExitCode:= 327; 将设置您的返回代码(例如已提及的mghieGerry)。
    3. 一些注意事项:

      • 因为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.
      

答案 3 :(得分:0)

1ms的定时器只会每40毫秒触发一次(由于Windows限制),所以它无济于事。我已经看到了你用混合控制台和GUI应用程序描述的效果,另一个是它们没有正确地最小化。

您可以使用CreateConsole API调用(不确定名称是否正确),而不是在项目中启用控制台,以便在程序启动后创建一个。我在一个(!)程序中看到没有任何不良影响。

但只有在您想要写入控制台时才需要这样做。如果您只想处理命令行参数并返回退出代码,则不需要控制台。只需为参数评估ParamCount / ParamStr函数,并设置ExitCode作为返回值。

答案 4 :(得分:0)

如果你的控制台应用程序中的某些线程调用Synchronize(我猜Indy的东西实际上是这样做的),你必须做一些准备工作:

WakeMainThread 变量指定方法。此方法必须具有TNotifyEvent的签名。

在此方法内部调用 CheckSynchronize

有关其他信息,请参阅这两个项目的Delphi帮助。