ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 27776|回复: 13

[Office其他组件] SHELL命令在VBA中的妙用

[复制链接]

TA的精华主题

TA的得分主题

发表于 2009-6-13 09:24 | 显示全部楼层 |阅读模式
SHELL命令在VBA中的妙用
SHELL命令在VBA中的妙用  
想要文件关闭的时候进行备份?想要把DOS命令加入到日常中的应用中来?没问题,用SHELL就行了。
如你的前台一启动的时候就自动建立虚拟盘,可以在LOAD事件里加入:
shell "subst X: H:\ushare\MRP"
这样就可以在文件打开的时候自动把H:\ushare\MRP映射成X盘,有利于文件分发。
同理,也可以加入其它的如XCOPY命令来备份。
当然,你要是把DOS命令做成一个BAT文件执行,用SHEEL "PATH“,1 来执行.SHEEL语句后面的那个1的意思如下:

常数                   值   描述
vbHide          0 窗口是隐藏的,并且焦点被传递给隐藏窗口。
vbNormalFocus   1 窗口拥有焦点,并且恢复到原来的大小与位置。
vbMinimizedFocus  2 窗口缩小为图符并拥有焦点。
vbMaximizedFocus   3 窗口最大化并拥有焦点。
vbNormalNoFocus   4 窗口被恢复到最近一次的大小与位置。当前活动窗口仍为活动窗口。
vbMinimizedNoFocus   6 窗口缩小为图符。当前活动窗口仍为活动窗口。

TA的精华主题

TA的得分主题

 楼主| 发表于 2009-6-13 09:26 | 显示全部楼层

VBA SHELL语句用法心得--转录

一、关于Rundll32.exe
过去,你曾经为了自己编的文件管理器能Format 磁盘、浏览器能自动拨号连接而求助于那位高傲的 API。现在,Rundll32.exe向你提供了更为平易近人的 方法来实现这些功能。
例如,要调用关机程序则为:shell “rundll32.exe user.exe,exitwindOws”。
调用模块 命 令 结 果
  rundll32.exe shell32.dll,Control_RunDLL 打开控制面板
SHELL32.DLL    
  rundll32.exe shell32,SHHelpShortcuts_Rundll PrintersFolder 打开打印机文件夹
  rundll32.exe shell32,SHHelpShortcuts_Rundll FontsFolder 打开字体文件夹
  rundll32.exe shell32,SHHelpShortcuts_Rundll AddPrinter 添加新打印机向导
  rundll32.exe shell32,SHformatDrive 格式化软盘
SYSDM.CPL    
  rundll32.exe shell32,Control_RunDLL sysdm.cpl 系统属性,常规
  rundll32.exe shell32,Control_RunDLL sysdm.cpl,,l 系统属性,设备管理器
  rundll32.exe shell32,Control_RunDLL sysdm.cpl,,3 系统属性,性能
  rundll32.exe shell32,Control_RunDLL sysdm.cpl @1 添加新硬件向导
APPWIZ.CPL    
  rundll32.exe shell32,Control_RunDLL appwiz.cpl,,1 添加/删除程序
  rundll32.exe shell32,Control_RunDLL appwiz.cpl,,2 安装Windows部件
  rundll32.exe shell32,Control_RunDLL appwiz.cpl,,3 制作启动盘
DISKCOPY.DLL    
  rundll32.exe diskcopy.dll,DiskcopyRundll 复制磁盘
RNAUI.DLL    
  rundll32.exe rnaui.dll,RnaDial x (x为连接名称) 打开拨号边接对话框,若已连接,则显示连接状态对话框
  rundll32.exe rnaui.dll,RnaWizard 新建拨号连接向导
DESK.CPL    
  rundll32.exe shell32,Control_RunDLL desk.cpl,,0 选择桌面背景
  rundll32.exe shell32,Control_RunDLL desk.cpl,,1 选择屏幕保护
  rundll32.exe shell32,Control_RunDLL desk.cpl,,2 选择外观
  rundll32.exe shell32,Control_RunDLL desk.cpl,,3 设置显示属性
MAIN.CPL    
  rundll32.exe shell32,Control_RunDLL main.cpl @0 设置鼠标属性
  rundll32.exe shell32,Control_RunDLL main.cpl @1 设置键盘属性,速度
  rundll32.exe shell32,Control_RunDLL main.cpl @1,,1 设置键盘属性,语言
  rundll32.exe shell32,Control_RunDLL main.cpl @2 打开打印机文件夹
  rundll32.exe shell32,Control_RunDLL main.cpl @3 打开字体属性
  rundll32.exe shell32,Control_RunDLL main.cpl @4 设置输入法
MODEM.CPL    
  rundll32.exe shell32,Control_RunDLL modem.cpl,,add 添加调制解调器向导
MMSYS.CPL    
  rundll32.exe shell32,Control_RunDLL mmsys.cpl @1 设置声音属性(也可以加入,,0到,,4的参数以选择不同的标签)
UESR.EXE    
  rundll32.exe user.exe,exitwindows 关闭计算机
二、如何确定Shell语句调用的程序已经关闭
这个标题确实太长,但它确实概括了本节的内容。 当你需要等待由Shell启动的应用程序运行完毕时, 便会发现Shell语句只管调用,之后就撒手不管了,于 是我们不得不动用一下API函数了。当然我们可以用 API来完成全部的工作,但是如果那样的话,我们将要 面临CreateProcess这个非常复杂的函数,光写下它 和相关结构类型的宣告就超出一页纸了。别误会,我 说这些的目的只是为了让大家体会到下面我们将要做 的是多么简单的事。
只需按以下步骤step by step,便OK了。
1.新建一个项目,在窗体上放一个command1,再 添加一个Module。
2. 在Module中写入如下代码:
Option Explicit
以下声明了OpenProcess,GetExitCodeProcess 和Closeandle 三个API函数
Public Declare Function OpenProcess Lib"ker nel32"(ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long)As Long
Public Declare Function GetExitcodeProcess Lib “kernel32”(ByVal hProcess As Long, 1pExitcode As Long) As Long
Public Declare Function Closellandle Lib "Ker nel32”(ByVal hobject As Long) As Long
Publi Const PROCESS_QUERY_INFORMATION= &H400
Public Const STATUS_PENDING = &H103&
3.打开窗体的代码窗口,写入如下代码:
Option Explicit
Private Sub RunShell(cmdline As String) 这个自定义过程完成了所有工作
Dim hProcess As Long
Dim ProcessId As Long
Dim exitCode As Long
ProcessId = Shell(cmdline,1)'此处利用了 Shell当函数使用时返回的任务标识
hProcess=OpenProcess(PROCESS_QUERY_INFOR MATION,False,ProcessId)
Do
Ca11 GetExitCodeProcess(hProcess,exitcode)
DoEvents
Loop While exitCode = STATUS_PENDING
Call CloseHandle(hProcess)
MsgBox cmdline & "已经关闭。"
End Sub
Private Sub Command1_Click()
RunShell ”notepad.exe”
End Sub
4·按F5运行,单击Command1运行计事本,关闭 计事本将弹出对话框“notepad.exe 已经关闭。”
注意:由于本程序是用一个Do..Loop循环来侦测 进程的结束,所以那句DoEvents是绝不能少的,不然 你就只能用Ctrl+Break来退出了。

三、激活一个正在运行的程序
让我们来考虑这样一种情况:我们在程序中定义 了某一操作是用Shell语句调用Windows的计算器,当 用户重复这一操作时,计算器已经在运行了。如果简 单地再使用Shell语句将打开计算器的另一个进程。 这显然是不合理的。这时我们需要做的是激活已运行 的计算器,下面这段简单的代码帮我们达到了目的、 相信大家一看就懂。
Private Declare Function FindWindow Lib “user32”Alias “FindWindowA”(ByVal 1pClassName As String,ByVal 1pWindowName As String) As Long
Private Declare Function BringWindowToTop lib “user32” (ByVal hwnd As Long)As Long
'以上声明了FindWindow和BringWindowToTop两 个API函数
Private Sub Command1-Click()
Dim hCalcWnd As Long
hCalcwnd = Findwindow(“SciCalc”,”计算器”)
这里SciCalc是计算器的窗口类名,详见下一节
lf hCalcWnd=0 Then
Shell("CALC.EXE",vbNormalFocus)
Else:BringWindowToTop(hCalcWnd)
End lf
End sub

四、如何获得窗口的类名
只是看过上节的读者大部会对窗口的类名提出疑 问,本节就是针对这个问题的。通过本节的内容,你 还能了解到如何跟踪鼠标,并找出它正经过哪个窗口。 好,让我们一步一步地来,这回代码可能稍多一些。
1.建立一个新项目,在窗体的General Decla rations部分写入以下代码,这些语句定义了要用到 的API函数、常量以及结构。
Option Explicit
Dim gbCancel As Boolean
Private Type POINTAPI
X As Long
Y As Long
End Type
Private Declare Function GetCursorPos Lib “user32" (1pPoint As POINTAPI) As Long
Private Declare Function WindowFromPoint Lib "user32”(ByVal xPoint As Long,ByVal yPoint As long) As Long
Private DeClare Function GetClassName Lib “user32”Alias "GetClassNameA”(ByVal hwnd As Long,ByVal 1pClassName As String,ByVal aMaxCount As Long)As Long
2.在窗体上放一个Command1,把标题改成“开 始”,再放一个Label1,以下是事件的代码,也请大家 在相应位置写上。
Private Sub Command1_CliCk()
If Command1.Caption ="开始" Then
Command1.Caption = "停止"
Call Track
ElSe
Command1.Caption="开始"
gbCancel = True
End IF
End Sub
Private Sub Form_Load()
gbCancel = False '初始化循环取消变量
End Sub
Private Sub Form_QueryUnload(Cancel As In teger,UnloadMode As Integer)
gbCancel = True '确保循环中断
End Sub
3.最后是关键部分,自定义的过程Track。
Sub Track()
Dim PT_Mouse As POINTAPI
Dim 1CurHwnd As Long
Dim 1PrvHwnd As Long
Dim IX As Long,1Y As Long
Dim tClassName As String
Dim 1Result As Long
1PrvHwnd = 0
Do
Call GetCursorPos(PT_Mouse) '获得鼠标位置
1X =PT_Mouse.x
1Y=PT_Mouse.Y
1CurHwnd = WindowFromPolnt(1X,1Y) '获得鼠 标箭头下窗口的句柄
If gbCancel = True Then Exit Do
If 1CurHwnd <> 1PrvHWnd Then '若两值不等则 说明经过不同的窗口,保存新值
1PrvHwnd=1CurHwnd
tClassName = String$(256," ") '注意引号间 是空格
1Result = GetClassName(1CurHwnd,tClassName,255) '这两句取出类名
tClassName = Left$(tClassName, InStr (tClassName,vbNullChar) -1)
Labell,Caption = "鼠标通过:” & tClassName
'也可写1CurHwnd以获得窗口句柄
End lf
DoEvents '决不可少!切记,切记!
Loop
End sub
运行此程序,按下"开始”按钮后,鼠标所经过的 窗口的类名将在Labell中显示出来。

TA的精华主题

TA的得分主题

发表于 2009-6-13 09:45 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2009-6-13 10:29 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2009-6-13 11:05 | 显示全部楼层
谢谢LZ分享,当资料收藏起来,以备不时之需,呵呵

TA的精华主题

TA的得分主题

发表于 2010-9-25 14:57 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2010-9-27 21:21 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
下载备用谢谢分享

TA的精华主题

TA的得分主题

发表于 2010-12-30 13:24 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2011-5-28 12:09 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2011-10-10 20:02 | 显示全部楼层
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-24 02:19 , Processed in 0.033325 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表