【问题标题】:Executing Win Forms executable from delphi. Task not working after launch从 delphi 执行 Win Forms 可执行文件。启动后任务不起作用
【发布时间】:2014-05-27 15:24:35
【问题描述】:

我正在尝试从 Codegear Delphi 2007 中编写的代码启动可执行文件。我已经成功地这样做了,但是一旦启动可执行文件(这是一个 winforms 应用程序),它就不会启动它的 Task被编程为。

这是我用来从 Delphi 启动进程的代码:

procedure TfrmMain.OpenDatabase1Click(Sender: TObject);
var filename: string;
var parameters: string;
var
    sei: TShellExecuteInfo;
    ExitCode: DWORD;
begin
  if (OpenDatabaseDialog.Execute)then begin
    //Connect to mysql, check for new data and insert data into sdb file before opening.
    filename := 'C:\mysqlhelper\SSOAP Mysql Helper.exe';
    parameters := '"' + OpenDatabaseDialog.FileName + '"';
    ZeroMemory(@sei, SizeOf(sei));
    sei.cbSize := SizeOf(TShellExecuteInfo);
    sei.fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI or SEE_MASK_NOCLOSEPROCESS;
    sei.lpVerb := PChar('runas');
    sei.lpFile := PChar(filename); // PAnsiChar;
    if parameters <> '' then
      sei.lpParameters := PChar(parameters); // PAnsiChar;
    sei.nShow := SW_SHOWNORMAL; //Integer;

    if ShellExecuteEx(@sei) then begin
      repeat
        Application.ProcessMessages;
        GetExitCodeProcess(sei.hProcess, ExitCode) ;
      until (ExitCode <> STILL_ACTIVE) or  Application.Terminated;
    end;

    OpenDatabase(OpenDatabaseDialog.Filename);
  end;
end;

这是 C# 中的代码,可以作为独立运行良好:

public Form1()
{
    InitializeComponent();

    //get command line arguments (should be ssoap database filename
    string[] args = Environment.GetCommandLineArgs();

    //open connections
    OpenMySQLConnection();
    OpenAccessConnection(args[1]);

    //init the lists for FM's and RG's
    flowMeters = new List<FlowMeter>();
    rainGauges = new List<RainGauge>();
    Task t = new Task(new Action(DoWork));
    t.Start();
}

我已经调试到我只是觉得Task 没有启动。我在整个过程中都放置了MessageBox.Show() 点,它弥补了它的t.Start(); 部分。

澄清一下,我的问题是,我到底为什么可以启动可执行文件,给它预期的参数,而它只是不启动Task

【问题讨论】:

  • 是什么让您认为Task 没有执行?向我们展示DoWork 方法
  • 在调用执行任务之前放置MessageBox.Show("Blah")。与DoWork() 方法的第一行相同的放置不起作用。该方法太大,无法在此处发布,我认为此时它无关紧要。
  • 我不太喜欢你在 Delphi 程序中的繁忙循环,但这是你的问题。同样,您泄漏的进程句柄。我想知道当您独立运行 C# 应用程序时如何启动它。我相信您使用“以管理员身份运行”来匹配您从 Delphi 程序启动它的方式。
  • 好吧,我对 Delphi 很陌生,这是我能够找到等待另一个程序执行完成的唯一方法。我完全愿意接受更好的做法的建议。是的,我既以管理员身份运行,又以正常身份运行。结果相同。
  • 那你为什么用runas呢?

标签: c# delphi winapi


【解决方案1】:

从 Delphi 程序启动进程与作为独立应用程序启动进程之间最明显的区别是工作目录的状态。

  1. 在 Delphi 代码中,您没有指定工作目录。所以新进程继承了它的父进程的工作目录,你的 Delphi 程序。你没有说 Delphi 程序的工作目录是什么,所以我们无法分辨。
  2. 在 Delphi 程序之外启动 C# 程序时,工作目录将由您启动 C# 程序的方式决定。你没有说你是如何启动 C# 程序的,所以我们不能再告诉你工作目录是什么。

我建议您在 C# 程序中添加一些诊断代码以显示工作目录是什么。如果两种运行程序的方式不同,请在调用ShellExecuteEx时指定工作目录。

如果这证明工作目录是问题所在,那么您需要找出程序依赖工作目录的原因。这是故意的吗?如果是这样,那么您需要注意指定它。更有可能的是,程序不应该依赖于工作目录。

另一个可能的差异原因是传递给程序的参数。再次使用诊断输出来检查程序在两种启动模式下是否确实接收到相同的参数。

最后,我注意到您使用了 Delphi 代码中的 runas 动词。也许这就是问题所在。也许你不应该升职。


几个旁白:

  1. Delphi 程序中的繁忙循环很浪费。您应该等待进程句柄而不是运行繁忙的循环。您可能希望为此运行一个单独的线程以保持 UI 活跃。
  2. 您泄露了进程句柄。

【讨论】:

  • 你成功了。仅阅读几行答案后,它就是工作目录。我在 C# 应用程序中使用相对路径来指向我正在解析的文本文件。 File.ReadAllLines("C:\\mysqlhelper\\mapping.txt"); 暂时修复了它,尽管它们最终都会驻留在同一个目录中。呃,它总是那么愚蠢。但是,您的“旁白”。我对德尔福很陌生。您能否建议如何重写或提供链接?
  • 对于第 1 项,您可以创建一个线程并使用 WaitForSingleObject 传递进程句柄和 INFINITE 用于超时。然后让线程在完成后向主线程发出信号。或者使用 WaitForSingleObject 并在短时间内调用 ProcessMessages,所有这些都在一个循环中。啊!或使用MsgWaitForMultipleObjects。相当整洁但更难做对。并使用可怕的ProcessMessages。对于句柄泄漏,您必须调用CloseHandle
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-02
  • 1970-01-01
  • 2021-04-12
  • 1970-01-01
相关资源
最近更新 更多