通过单击图标、在控制台中键入其名称或从批处理文件中区分程序是不是运行
Posted
技术标签:
【中文标题】通过单击图标、在控制台中键入其名称或从批处理文件中区分程序是不是运行【英文标题】:Distinguish if program runs by clicking on the icon, typing its name in the console, or from a batch file通过单击图标、在控制台中键入其名称或从批处理文件中区分程序是否运行 【发布时间】:2011-12-22 22:37:26 【问题描述】:我正在编写的程序是一个简单的控制台应用程序,它获取参数、计算,然后返回数据。
我之所以问这个问题是因为我正在尝试实现一个智能"press enter to exit"
消息,该消息只有在通过单击资源管理器中的图标调用控制台程序时才会运行。没有它,结果是程序只闪烁一秒钟,但如果程序是从已经打开的控制台的上下文中运行的,那么同样的事情就会变得烦人。当程序在 bat 或 cmd 文件中运行时也会出现类似的情况,然后在最后暂停也是不受欢迎的,因为 bat 文件具有应该执行的“暂停”命令。
所以,我们有两种模式:
程序说"press enter to exit"
何时由以下人员启动:
在资源管理器中直接点击
点击快捷方式
仅在以下情况下退出:
它的名字是在控制台输入的
它从 bat/cmd 文件运行
它从另一个控制台应用程序运行
【问题讨论】:
我也可以在程序中添加一个额外的参数,让它等待输入或停止等待,或者甚至有一个计时器,以便用户有时间阅读输出但程序仍然没有无限等待。 嗯,我认为正确的方法是获取正在使用控制台窗口的进程列表,如果它等于一个,则意味着我们有案例 1……我是对任何 C 语言都很陌生,所以我真的不知道。 除了从快捷方式 (.lnk) 文件或批处理文件中传递命令行参数外,无法检测到这一点。如果没有获取到参数,是直接运行或者在资源管理器中双击启动的。 Windows 不区分进程启动的不同方式;它才刚刚开始。 按 Ctrl+F5。 F5 旨在让您在您关心的调试代码上设置断点。 【参考方案1】:使用 Windows API:
您可以使用GetConsoleProcessList API 函数(仅适用于Windows XP/2003 及更高版本)。它返回附加到当前控制台的进程列表。当您的程序以“无控制台”模式启动时,您的程序是连接到当前控制台的唯一进程。当您的程序从另一个已经有控制台的进程启动时,将有多个进程附加到当前控制台。
在这种情况下,我们不关心函数返回的进程 ID 列表,我们只关心返回的计数。
示例程序(我使用带有控制台应用程序模板的 Visual C++):
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
DWORD procIDs[2];
DWORD maxCount = 2;
DWORD result = GetConsoleProcessList((LPDWORD)procIDs, maxCount);
cout << "Number of processes listed: " << result << endl;
if (result == 1)
system("pause");
return 0;
我们只需要列出最多2个进程,因为我们只关心是否有1
或more than 1
。
使用 Windows 2000 中的 Windows API:
GetConsoleWindow 返回与当前进程关联的控制台的窗口句柄(如果有)。 GetWindowThreadProcessId 可以告诉你哪个进程创建了一个窗口。最后,GetCurrentProcessId 告诉你当前进程的 id。你可以根据这些信息做出一些有用的推论:
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
HWND consoleWindow = GetConsoleWindow();
if (consoleWindow != NULL)
DWORD windowCreatorProcessId;
GetWindowThreadProcessId(consoleWindow, &windowCreatorProcessId);
if (windowCreatorProcessId == GetCurrentProcessId())
cout << "Console window was created by this process." << endl;
system("pause");
else
cout << "Console window was not created by this process." << endl;
else
cout << "No console window is associated with this process." << endl;
return 0;
这种技术似乎比第一种技术稍微不那么精确,但我认为在实践中它应该表现得一样好。
【讨论】:
这是一个不错的答案。但是有一个烦人的问题——函数 GetConsoleProcessList 不能在 windows 2000 上运行 @rsk82 是的,遗憾的是GetConsoleProcessList
直到 XP/2003 才添加。但是,我找到了一个仅使用 Windows 2000 API 调用的解决方案,它应该与 GetConsoleProcessList 方法一样工作。我更新了我的答案。
事实证明,这两种方法都是(以某种形式)在回答这个问题时提供的:***.com/questions/1482604/… 在那里,Windows API 调用是从 Delphi 进行的,但目标本质上是相同的在这个问题中。【参考方案2】:
我能想到的最简单的解决方案是要求第一个参数是一个标志,程序是否应该在最后暂停。如果参数不存在,即它是通过资源管理器启动的,而用户没有能力传入它,那么它应该暂停。
//Pseudo-code!!
int main(int argc, char** argv)
//...
if(argv[1] == SHOULD_PAUSE) system("pause");
return 0;
【讨论】:
【参考方案3】:有一种简单的方法可以做到这一点,当然还有一种更复杂的方法。更复杂的方式最终可能会更有趣,但可能比它的价值更麻烦。
对于简单的方法,在程序中添加一个命令行参数,--pause-on-exit
或类似的东西。传递额外的参数 whan 从批处理文件或启动器图标调用它。您当然可以检查环境变量以获得类似的效果。
对于更复杂(和自动)的方法,您可能会尝试找出谁是您的应用程序的父进程。您可能必须比您的直系父母更进一步,并且它可能不适用于所有情况。我会选择命令行参数。
【讨论】:
【参考方案4】:详细说明我的评论,而不是试图告诉程序是如何执行的(我什至不知道这是否可能,我认为根本没有区别/区别),我会实现一个 类似的 两种方式之一的功能:
向程序添加一个额外的参数,使其在结束前“暂停”或不终止。 IE。你可以有类似-w
的东西让它等待,或者-W
让它不等待,默认不等待(反之亦然)。您可以通过快捷方式添加参数。
在程序末尾添加一个计时器,以便您等待几秒钟,足够长的时间让用户读取输入,这样程序在批量使用时不会无限等待。
【讨论】:
以上是关于通过单击图标、在控制台中键入其名称或从批处理文件中区分程序是不是运行的主要内容,如果未能解决你的问题,请参考以下文章