确定当前应用程序的父进程

8

我编写了一个可从主机应用程序内部调用的实用程序(exe)。我希望这个实用程序只能从主机应用程序中调用,如果从外部或其他主机运行它,应该立即终止实用程序。

有没有办法找出是哪个进程启动了我的实用程序?

谢谢回复。


我有SysInternals ProcessExplorer,它向我展示了所有当前正在运行的进程的树形结构以及每个进程是由哪个程序启动的,所以这些信息绝对是可用的。问题是如何访问这些信息,不幸的是我不知道。我将在您的帖子中添加“winapi”标签,并使其更清晰,表明这就是您要寻找的内容。 - Mason Wheeler
我看到的最佳答案是 https://dev59.com/HnRC5IYBdhLWcg3wJNqf#3346055 - Wade Hatler
5个回答

9
你可以使用CreateToolhelp32Snapshot函数枚举正在运行的进程列表,然后使用Process32First函数获取th32ParentProcessID,该标识符是创建此进程(其父进程)的进程的标识符。请参见此示例。
uses
  Psapi,
  Windows,
  tlhelp32,
  SysUtils;

function GetTheParentProcessFileName(): String;
const
  BufferSize = 4096;
var
  HandleSnapShot  : THandle;
  EntryParentProc : TProcessEntry32;
  CurrentProcessId: DWORD;
  HandleParentProc: THandle;
  ParentProcessId : DWORD;
  ParentProcessFound  : Boolean;
  ParentProcPath      : String;

begin
  ParentProcessFound := False;
  HandleSnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);   //enumerate the process
  if HandleSnapShot <> INVALID_HANDLE_VALUE then
  begin
    EntryParentProc.dwSize := SizeOf(EntryParentProc);
    if Process32First(HandleSnapShot, EntryParentProc) then    //find the first process
    begin
      CurrentProcessId := GetCurrentProcessId(); //get the id of the current process
      repeat
        if EntryParentProc.th32ProcessID = CurrentProcessId then
        begin
          ParentProcessId := EntryParentProc.th32ParentProcessID; //get the id of the parent process
          HandleParentProc := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, ParentProcessId);
          if HandleParentProc <> 0 then
          begin
              ParentProcessFound := True;
              SetLength(ParentProcPath, BufferSize);
              GetModuleFileNameEx(HandleParentProc, 0, PChar(ParentProcPath),BufferSize);
              ParentProcPath := PChar(ParentProcPath);
              CloseHandle(HandleParentProc);
          end;
          break;
        end;
      until not Process32Next(HandleSnapShot, EntryParentProc);
    end;
    CloseHandle(HandleSnapShot);
  end;

  if ParentProcessFound then
    Result := ParentProcPath
  else
    Result := '';
end;

2

我建议添加一个额外的参数(可以是唯一标识符),只有你知道这个参数。如果该参数不是传递给你的工具参数之一...立即终止应用程序。


我已经走过那条路。问题在于,传递给实用程序的参数可以通过主机应用程序的设置屏幕或设置屏幕进行查看。而且我也无法指示主机应用程序在其他地方寻找某些魔术密钥。谢谢! - Rick

2
你的问题的简短回答是:“不能防止应用程序被执行”。如果它是可执行文件,那么它就可以被执行。无法阻止这种情况发生。如果你不能控制应用程序(正如你的评论所示),那么Gs的建议将行不通,对吗?你没有任何办法控制应用程序的操作,并且也无法控制其对你的特殊命令行的反应。因此,这确实是一个有趣的情况。唯一的解决方法是完全防止访问EXE,或者至少使其难以找到。你可以这样做:1. 将EXE嵌入到主机EXE中作为资源;2. 在运行EXE时,使用TResourceStream提取它;3. 使用TFileStream将其写出;4. 执行它;5. 完成后删除它。虽然不美观,但这是我能想到的唯一方法,可以按照你的条件来防止EXE被运行。

3
他似乎在询问是否有可能验证启动应用程序的进程身份,如果是错误的进程,则立即终止。这应该是可能的。 - Mason Wheeler

2
我们使用一种相当简单的技术,只需要几行代码即可。父应用程序和实用程序应用程序在代码中使用一些常见的GUIID字符串,并调用RegisterWindowMessage创建一种“Hello”握手协议。当实用程序应用程序首次启动时,它会发布该消息。如果父应用程序正在运行并启动了实用程序,则会发布响应消息,实用程序看到后就正常运行。否则,实用程序会超时并退出。

父应用程序将需要进行修改/重写以实现这种方式。这正确吗? - Rick
是的。在我写下那句话之前,我并没有意识到一个第三方应用程序正在运行该实用程序。我的失误。 - Brian D. Coryell

1
如果此应用程序仅在主机内运行,为什么不将应用程序的表单包含在主应用程序中,并像激活其他表单一样激活它呢?

2
我们没有编写这个主机应用程序。只有执行另一个应用程序的能力。我碰巧知道他们是如何执行它的。 谢谢Tim! - Rick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接