c++ - 如何从命令行或其他应用程序打开桌面应用程序并将其置于最前面?

标签 c++ windows delphi desktop-application

有时需要从命令行打开新程序(例如,Windows Powerpoint 演示文稿作为幻灯片可以通过命令行“powerpnt.exe/s”打开),将此程序最大化并将其置于最前面桌面作为用户可以看到和使用的第一个程序。如果用户直接在命令提示符中输入命令,默认情况下会发生这种情况,因为命令提示符是事件窗口。

但问题是 - 如果命令行是从后台进程执行的,如何做到这一点 - 例如来自 Windows Task Scehduler 的自定义 Windows 服务应用程序 - 在这两种情况下,新窗口都不会作为第一个窗口出现。

目前我只能想象非常困难的解决方案(其缺点是它们需要编码并且不能从任务计划程序中使用):

  1. 可以尝试获取已打开程序主窗口的句柄并操纵该窗口 - 例如最大化等等;
  2. 可以尝试完全放弃命令行,而是将 Windows Office 应用程序作为 COM 对象进行操作。

也许有更简单的方法?

最佳答案

您可以创建一个小型(非图形用户界面)启动器应用程序,它将为您调用新程序(我知道,这就是您所说的硬解决方案),然后在任务计划程序上安排此启动器。

此启动器应用程序必须创建 de 进程(CreateProcess function),然后从 pID 获取窗口句柄...使用窗口句柄,您可以使用 SetForegroundWindow 来执行您需要的操作,或调用其他函数来处理事情比如最大化等

由于您标记了 delphi,我发布了一个可能的 delphi 实现。

function WindowFromPID(pID: Cardinal; VisibleWindow: Boolean): Cardinal;
type
  TProcData = record
    pID: Cardinal;
    pHandle: Cardinal;

    VisibleWindow: Boolean;
  end;

var 
  wPData: TProcData;

  function EnumProc(Handle: HWND; var pProcData: TProcData): Bool; stdcall;
  var pID: DWORD;
  begin
    Result := True;
    if pProcData.VisibleWindow then
      if not IsWindowVisible(Handle) then
        Exit;

    GetWindowThreadProcessId(Handle, @pID);
    if pID = pProcData.pID then begin
      if GetWindow(Handle, GW_OWNER) = 0 then begin
        pProcData.pHandle := Handle;
        Result := false;
      end;
    end;
  end;
begin
  wPData.pHandle := 0;
  wPData.pID := pID;
  wPData.VisibleWindow := VisibleWindow;

  EnumWindows(@EnumProc, Integer(@wPData));
  while (wPData.pHandle = 0) do begin
    Sleep(50);
    EnumWindows(@EnumProc, Integer(@wPData));
  end;

  Result := wPData.pHandle;
end;

procedure RunAndGetWindowHandle(const FileName, Params: String; const WindowState: Word): Cardinal;
var 
  SUInfo: TStartupInfo;
  CmdLine: String;
  ProcInfo: TProcessInformation
begin
  CmdLine := '"' + Filename + '"' + Params;
  FillChar(SUInfo, SizeOf(SUInfo), #0);
  with SUInfo do begin
    cb := SizeOf(SUInfo);
    dwFlags := StartF_UseShowWindow;
    wShowWindow := WindowState;
  end;

  if not CreateProcess(Nil, PChar(CmdLine), nil, nil, False, Create_New_Console Or Normal_Priority_Class, nil, PChar(ExtractFilePath(Filename)), SUInfo, ProcInfo) then
    raise Exception.Create('Error running process');

  if WaitForSingleObject(ProcInfo.hProcess, 50) <> WAIT_TIMEOUT then
    raise Exception.Create('Error running process!');

  CloseHandle(ProcInfo.hThread);
  while Result = 0 do begin
    Sleep(50);
    Result := WindowFromPID(ProcInfo.dwProcessId, true);
  end;
end;

...

var WindowHandle: Cardinal;
begin
  WindowHandle := RunAndGetWindowHandle("powerpnt.exe", " /s", SW_SHOWNORMAL);
  SetForegroundWindow(WindowHandle);
end;

希望这就是您所需要的。如果不是,我们深表歉意。

最好的问候。

关于c++ - 如何从命令行或其他应用程序打开桌面应用程序并将其置于最前面?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14297934/

相关文章:

c++ - 未定义对 `WinMain' : When using Cygwin, SDL2 和 Netbeans 的引用

c++ - `#include <iostream>` 和 `-std=c++0x` 坏了

c++ - 搜索进程内存

Delphi:测试事件处理程序分配

c++ - 如何在编译时生成嵌套循环

c++ - 将 32 位地址的类型转换为 (BYTE *) 和 (DWORD *) 有什么区别

windows - 窗口区域与分层窗口

linux - go 是否有特定于操作系统的软件包不能在其他操作系统上使用?

file - 从 avi 文件中提取正确的创建日期

delphi - 发送附有内存流的电子邮件