所以,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\
第一个文件夹。这个细节足以产生差异 - 在 中模拟这一点:PATH
explorer.exe
cmd
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
执行以下操作:
- 通过搜索 Windows 注册表确定文件的类型。
- 枚举允许的 shell 命令(动词)。
- 检索指定动词的命令行。
- 构造命令行开关。
- 调用
CreateProcess()
以启动检索到的命令行指向的进程。
此功能完全能够操纵给定进程的 CLI 参数 - 事实上,您可以尝试为文本文件生成一个进程...并将ShellExecute
运行负责打开文本文件的默认应用程序,使用 Windows 注册表指示的参数。这就是任务管理器所做的:如果您尝试运行指向文本文件的新任务,它会确定它应该打开您的默认文本编辑器。