从 CLI 启动进程与从任务管理器启动进程

从 CLI 启动进程与从任务管理器启动进程

所以,Windows 资源管理器又一次崩溃了,现在我的任务栏不见了。但我知道我所要做的就是再次运行资源管理器,任务栏就会重新出现。

如果我通过 启动 Explorer taskmgr,一切正常 - 任务栏将按照我的意愿重新出现。
但有时我会尝试通过 运行 Explorer cmd.exe。我这样做的原因并不重要。

不。什么都没发生。它只是在新窗口中打开“库”,并且不会恢复任务栏。

以下是在 GIF 上捕获的描述行为。我确保 explorer 没有运行,然后通过 CLI 运行它,之后通过 运行taskmgr。注意任务栏如何显示 (在屏幕顶部) 仅当我通过 运行资源管理器时taskmgr

在此处输入图片描述

问题是:为什么会发生这种情况?它是如何发生的?taskmgr允许我运行任意任务,这应该与cmd提供的任务相同。除非taskmgr专门检查我是否尝试运行explorer并在这种情况下添加一些神秘的命令行参数,否则它应该与我尝试通过 CLI 运行 Explorer 没有任何区别。然而,Explorer 以某种方式知道只有在通过运行时才恢复任务栏taskmgr,因此它的执行一定有所不同。在这种情况下,有什么不同 - 是 CLI 调用,还是完全不同的东西?

答案1

CLI 交换机并不是唯一可以控制 Windows 进程行为的东西。

通过 CLI 和通过任务管理器调用进程实际上是完全不同的,并且可以以多种方式使用这种足迹。

CWD(答案)

Explorer 不启动任务栏的原因是,从 CLI 执行时,其工作目录与从任务管理器执行时不同。在发布的 GIF 中,CWD 设置为Z:\,而 将taskmgr其设置为 C:\Windows。它知道应该将其设置为C:\Windows,因为 是环境变量中包含 的C:\Windows\第一个文件夹。这个细节足以产生差异 - 在 中模拟这一点:PATHexplorer.execmd

C:\> cd /d C:\windows
C:\windows> explorer

...确实按预期恢复了任务栏。

CreateProcess

进程的执行也可以通过STARTUPINFO Windows 结构来控制,该结构由 WinAPI 函数使用CreateProcess,该函数是在 Windows 中打开新进程的主要函数。

STARTUPINFO我编写了一个程序来测试CMD 启动的程序和任务管理器启动的程序之间的差异:

#include <stdio.h>
#include <Windows.h>

int main(int argc, char ** argv)
{
    STARTUPINFO si;
    memset(&si, 0, sizeof(si));
    GetStartupInfo(&si);

    FILE *fp = fopen("Z:\\output.txt",  "a");
    if (!fp) {
        return 1;
    }
    fprintf(fp, "cb:              %08x\n", si.cb);
    fprintf(fp, "lpDesktop:       %s\n", si.lpDesktop);
    fprintf(fp, "dwX:             %d\n", si.dwX);
    fprintf(fp, "dwY:             %d\n", si.dwY);
    fprintf(fp, "dwXSize:         %d\n", si.dwXSize);
    fprintf(fp, "dwYSize:         %d\n", si.dwYSize);
    fprintf(fp, "dwXCountChars:   %d\n", si.dwXCountChars);
    fprintf(fp, "dwYCountChars:   %d\n", si.dwYCountChars);
    fprintf(fp, "dwFillAttribute: %d\n", si.dwFillAttribute);
    fprintf(fp, "dwFlags:         %d\n", si.dwFlags);
    fprintf(fp, "wShowWindow:     %d\n", si.wShowWindow);
    fprintf(fp, "hStdInput:       %08x\n", si.hStdInput);
    fprintf(fp, "hStdOutput:      %08x\n", si.hStdOutput);
    fprintf(fp, "hStdError:       %08x\n", si.hStdError);
    fclose(fp);

    return 0;
}

我很快就得到了以下结果——通过 CMD 运行测试程序的结果如下:

cb:              00000044
lpDesktop:       Winsta0\Default
dwX:             0
dwY:             0
dwXSize:         0
dwYSize:         0
dwXCountChars:   0
dwYCountChars:   0
dwFillAttribute: 0
dwFlags:         256
wShowWindow:     0
hStdInput:       000001d8
hStdOutput:      000001dc
hStdError:       000001dc

运行taskmgr结果如下:

cb:              00000044
lpDesktop:       Winsta0\Default
dwX:             0
dwY:             0
dwXSize:         0
dwYSize:         0
dwXCountChars:   0
dwYCountChars:   0
dwFillAttribute: 0
dwFlags:         1
wShowWindow:     1
hStdInput:       ffffffff
hStdOutput:      ffffffff
hStdError:       ffffffff

我们可以看到它们之间明显存在差异 - 例如,CLI 不希望程序显示任何窗口,而 taskmgr 会关闭所有标准 I/O 句柄。任何程序都可以使用这些信息来控制其行为 - 即使这对最终用户来说并不直观,但完全有可能。

ShellExecute

运行进程的另一种标准方式是 WinAPIShellExecute函数。根据这个帖子ShellExecute执行以下操作:

  1. 通过搜索 Windows 注册表确定文件的类型。
  2. 枚举允许的 shell 命令(动词)。
  3. 检索指定动词的命令行。
  4. 构造命令行开关。
  5. 调用CreateProcess()以启动检索到的命令行指向的进程。

此功能完全能够操纵给定进程的 CLI 参数 - 事实上,您可以尝试为文本文件生成一个进程...并将ShellExecute运行负责打开文本文件的默认应用程序,使用 Windows 注册表指示的参数。这就是任务管理器所做的:如果您尝试运行指向文本文件的新任务,它会确定它应该打开您的默认文本编辑器。

相关内容