Board logo

标题: 【练习-032】让批处理自行判断是否被双击运行 [打印本页]

作者: pusofalse    时间: 2008-11-12 18:46     标题: 【练习-032】让批处理自行判断是否被双击运行

出题目的:了解批处理运行机制。

加分规则:
        思路新颖8分
        无临时文件3分
        代码简洁3分
        完美代码15分

题目内容:
让批处理自行判断是否被双击运行还是在CMD中手动输入运行。
如同tasklist.exe、net.exe、ping.exe,当我们双击这些文件时,会一闪而过,看不到这些命令的帮助信息。只有在CMD中手动输入之后才能看到。现在的题目是编写一个批处理文件,当我们双击运行时(不带任何参数),显示“双击运行”并暂停,如果是在CMD中手动输入运行(同样不带任何参数),显示“CMD中手动输入运行”之后不暂停,直接返回到命令提示符。
作者: qingfengzhixia    时间: 2008-11-13 09:42     标题: 我不知道 这样符不符合题意

  1. @echo off
  2. tasklist | find /i "ping.exe">nul && echo 双击运行 &&pause>nul&&exit|| echo CMD中手动输入运行&&ping /n 3 127.1>nul&&cmd
复制代码

[ 本帖最后由 qingfengzhixia 于 2008-11-13 10:02 编辑 ]
作者: pusofalse    时间: 2008-11-13 10:45     标题: 回复 2楼 的帖子

双击时不会先运行PING命令,所以tasklist |findstr的结果总是失败的,所以不管如何运行,总是输出“CMD中手动输入运行”。
作者: sylovanas    时间: 2008-11-13 11:02

  1. @IF NOT DEFINED DEBUG @ECHO OFF
  2. FINDSTR ":\\" %~0 >NUL 2>&1 && (
  3.         ECHO 双击运行
  4.         PAUSE
  5.         EXIT
  6.         ) || (
  7.         ECHO CMD中手动输入运行
  8.         PAUSE
  9.         )
复制代码
不是很好的做法,要命令行打完整路径文件名称就失效

[ 本帖最后由 sylovanas 于 2008-11-13 11:04 编辑 ]
作者: wxcute    时间: 2008-11-13 12:21     标题: 回复楼主 [ 很难 ]

这个题目我个人觉得不是一般的难阿!
作者: pusofalse    时间: 2008-11-13 13:00     标题: 回复 6楼 的帖子

也是着实想了好一阵,就是钻了%0、%~n0的空子。我的代码也不通用,同4楼一样的问题。
作者: pusofalse    时间: 2008-11-13 13:02     标题: 回复 5楼 的帖子

可以把不垃圾的程序发来看下吗?、、、我想delphi的精髓你已经学到了吧。
作者: BBCC    时间: 2008-11-13 13:09

还是lxmxn的方法强大,可惜需要用到wmic
作者: everest79    时间: 2008-11-13 18:07

异同之处在于cmd的启动参数
双击时是/c参数启动的,而手动输入时是默认工作状态,也就是没参数或参数为/k
作者: everest79    时间: 2008-11-13 18:41

  1. @ECHO OFF
  2. title 标题
  3. For /f "tokens=2" %%i in ('tasklist /fi "windowtitle eq 标题" /nh') Do set handle=%%i
  4. wmic process where handle='%handle%' get commandline|findstr /i /c:"cmd \/c"&&set HH=PAUSE
  5. %HH%
复制代码

作者: BBCC    时间: 2008-11-13 19:24

双击时是/c参数启动的,而手动输入时是默认工作状态,也就是没参数或参数为/k


原来start/?中的 command/program 是这个意思。。。
作者: slore    时间: 2008-11-14 12:01     标题: 麻烦……

不管是路径,标题的都是有空钻的……多开的话,检测就有问题。

如何能得到当前cmd的pid是关键。

Microsoft Windows XP [版本 5.1.2600]
(C) 版权所有 1985-2001 Microsoft Corp.

C:\Documents and Settings\Administrator>"C:\Documents and Settings\Administrator
\桌面\1.bat"
C:\Documents and Settings\Administrator>"C:\Documents and Settings\Administrator
\桌面\1.bat"
cmd /c ""C:\Documents and Settings\Administrator\桌面\1.bat" "
作者: qingfengzhixia    时间: 2008-11-14 20:52

原帖由 everest79 于 2008-11-13 18:41 发表
@ECHO OFF
title 标题
For /f "tokens=2" %%i in ('tasklist /fi "windowtitle eq 标题" /nh') Do set handle=%%i
wmic process where handle='%handle%' get commandline|findstr /i /c:"cmd \/c"&&set HH=PAUSE ...




有没有人能解释一下。
两处不懂
1。“'tasklist /fi "windowtitle eq 标题" /nh'
2。wmic
作者: more    时间: 2008-11-14 21:32

有没有人能解释一下。
两处不懂
1。“'tasklist /fi "windowtitle eq 标题" /nh'
2。wmic

1.请运行下面的代码
  1. @echo off
  2. title 标题
  3. echo 以下是加上/nh的结果:
  4. tasklist /fi "windowtitle eq 标题" /nh
  5. echo.&echo 以下是不加/nh的结果:
  6. tasklist /fi "windowtitle eq 标题"
  7. echo.&pause
复制代码
2.wmic不懂?==>看教程
作者: shqf    时间: 2008-11-14 22:39

各位试试行吗?我在本机上试符合要求了
  1. @echo off
  2. if "%0"=="%~0" (echo CMD中手动输入运行) else (echo 双击运行)
  3. pause
  4. exit
复制代码

[ 本帖最后由 shqf 于 2008-11-14 22:41 编辑 ]
作者: pusofalse    时间: 2008-11-15 04:44     标题: 回复 16楼 的帖子

如果路径中有空格时会出错,因为%0会自动在路径首尾加上引号。
作者: everest79    时间: 2008-11-15 04:56

原帖由 qingfengzhixia 于 2008-11-14 20:52 发表




有没有人能解释一下。
两处不懂
1。“'tasklist /fi "windowtitle eq 标题" /nh'
2。wmic


tasklist中的/fi参数是一个筛选器,随后的 "windowtitle eq 标题"是这个筛选器的条件,指窗口标题为‘标题’的即符合要求,/nh参数去掉了表头,方便在for中提取数据

wmic 是windows wmi标准的一个简化工具,在这里使用wmic查询了当前PID为%handle%的进程的启动命令行
作者: everest79    时间: 2008-11-15 05:00

原帖由 slore 于 2008-11-14 12:01 发表
不管是路径,标题的都是有空钻的……多开的话,检测就有问题。

如何能得到当前cmd的pid是关键。

Microsoft Windows XP [版本 5.1.2600]
(C) 版权所有 1985-2001 Microsoft Corp.

C:\Documents and Setting ...


根据你要求改了下
  1. @ECHO OFF&Set /A _wt=%random%/2
  2. title 标题%_wt%
  3. For /f "tokens=2" %%i in ('tasklist /fi "windowtitle eq 标题%_wt%" /nh') Do set handle=%%i
  4. wmic process where handle='%handle%' get commandline|findstr /i /c:"cmd \/c"&&set HH=PAUSE
  5. %HH%
复制代码

作者: everest79    时间: 2008-11-15 05:02

原帖由 shqf 于 2008-11-14 22:39 发表
各位试试行吗?我在本机上试符合要求了
@echo off
if "%0"=="%~0" (echo CMD中手动输入运行) else (echo 双击运行)
pause
exit


"%0"有一半的可能会出现两重引号,这在IF里会被识别为非法并且中断命令行

例如你的批处理文件名为:bath title.cmd
那么你的判断就不能成立
作者: slore    时间: 2008-11-15 20:42

原帖由 everest79 于 2008-11-15 05:00 发表


根据你要求改了下

@ECHO OFF&Set /A _wt=%random%/2
title 标题%_wt%
For /f "tokens=2" %%i in ('tasklist /fi "windowtitle eq 标题%_wt%" /nh') Do set handle=%%i
wmic process where handle='%handle ...


……

加随机标题只是……
我可以取一个文件夹名为标题XXX
不一定是那个BAT……

所以要搞一个不重复的标题……

当然加了随机或者起很奇怪的名字,99%也许都可以通过……

但是从原理上分析就只要这样是不行的,总能找出不匹配的。
作者: everest79    时间: 2008-11-16 00:36

要得到切实可靠的PID理论上是可行的,但为了让批处理执行是更人性化一点添加过多代码有顾此失彼的歉疑

以cscript.exe执行这个脚本即可得到cmd的PID
  1. Dim Wsh,Wmi
  2. Set Wsh=CreateObject("WScript.Shell")
  3. Set Wmi=GetObject("winmgmts:\\.\root\cimv2")
  4. Set Hta=Wsh.Exec("mshta 1")
  5. For Each i In Wmq(Hta.ProcessID)
  6.     WScript.Echo "脚本PID       :" & i.ParentProcessID
  7.     For Each j In Wmq(i.ParentProcessID)
  8.         WScript.Echo "脚本命令行    :" & j.CommandLine & vbCrLf &_
  9.                      "脚本父进程PID :" & j.ParentProcessID
  10.         For Each k In Wmq(j.ParentProcessID)
  11.             WScript.Echo "脚本父进程名称:" & k.Name & vbCrLf &_
  12.                          "脚本父进程命令:" & k.CommandLine
  13.         Next
  14.     Next
  15. Next
  16. Hta.Terminate
  17. Function Wmq(Pid)
  18. Set Wmq=Wmi.ExecQuery("Select * From Win32_Process Where ProcessID='" & Pid & "'")
  19. End Function
复制代码

作者: slore    时间: 2008-11-16 18:27

。。。

VBS方便……

但是貌似题目是P处理哦
作者: everest79    时间: 2008-11-16 18:52

勉为其难调用下吧,嘿嘿
作者: 523066680    时间: 2008-11-23 09:24     标题: 回复 5楼 的帖子

嘿嘿 这个不是太难的东西,反倒是我觉得其做他题目 有些吃力不讨好了
学了点vbs后觉得很多东西用vbs解只需要一个函数就可以了。
所以啊还是学习它的优点好了。

不过。楼主这样的题目可以做什么呢?很 有用的
可以利用这个原理防止用户双击批处理运行,只有经过调用才能运行批处理
这不是很有用么

还有其他用处的吧  我们只是缺少发现美的眼睛
作者: yzlsc    时间: 2012-3-17 14:41

新手迷糊,测试后怎么感觉没一个正确答案?
作者: find    时间: 2012-3-17 17:06

回复 25# yzlsc


感觉你的测试方法不对头
作者: lincc0519    时间: 2012-12-16 22:49

本帖最后由 lincc0519 于 2012-12-16 22:52 编辑

我也发一个,这个代码能解决start命令调用的情况,但在start /b这种情况下会出现2个进程共用一个窗口,本来想结束一个进程,但这样就失去了start /b命令的原意,同时新窗口下要求pause的情况,所以也就没用处理,要真处理还真是个麻烦事!代码只在windows xp下测试过!
  1. @echo off&setlocal enabledelayedexpansion
  2. doskey /history|findstr .>nul
  3. if !errorlevel! equ 0 echo cmd命令调用执行&exit/b
  4. set str=
  5. for /l %%a in (1,1,10) do set str=!str!!random!
  6. if [%1]==[] (
  7.     start /b "" "%~nx0" !str!>nul
  8.     set com=echo.
  9. ) else (
  10.     set com=pause
  11. )
  12. !com!>nul
  13. for /f "skip=1 tokens=1,2" %%a in ('wmic process where "commandline='c:\\windows\\system32\\cmd.exe  /k "%~nx0"  !str!'" get processid^,parentprocessid') do (
  14.     set /a pid=%%b,ppid=%%a
  15. )
  16. taskkill /pid !pid! /t /f 1>nul 2>nul
  17. set pid=!ppid!
  18. for /f "skip=1" %%a in ('wmic process where "processid=!pid!" get parentprocessid') do set ppid=%%a
  19. for /f "skip=1" %%a in ('wmic process where "processid=!ppid!" get caption') do set name=%%a
  20. if /i !name!==explorer.exe echo windows操作界面执行&pause>nul&exit/b
  21. if /i !name!==cmd.exe echo cmd命令调用执行&exit/b
  22. echo !name!程序执行&exit/b
复制代码





欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2