在 REALbasic 中,如果需要执行 cmd 命令,可以直接使用 Shell 类,但是这样的话,编译成 Windows 程序时会额外需要一个 Shell.dll 的动态链接库,这对于我这样的 1exe 爱好者是不能忍受的。但是对于 Mac OS X 和 Linux 的生成目标来说,是不存在这个问题的,因为 Mac OS X 的应用程序本身就是一个文件夹,而 Linux 的目标不会生成额外的链接库。因此,需要针对 Windows 进行特殊处理。于是在网上搜索解决方案,找到了 VB 中执行程序的几种方法:
1. 使用 CreateProcess
通过 CreateProcess 以及使用管道,可以执行外部程序并获取输出,但是这个方法过于烦琐,并且我也不需要外部进程执行完毕后的输出结果,因此不采用。
2. 使用 Shell 方法
VB 里有一个 Shell 方法,但是在 RB 中并没有,所以此路不通。
3. 使用 ShellExecute
这个方法同样是一个系统 API,可以直接通过 RB 的 declare 声明并调用它,在测试之后,使用 declare 来使用系统 API 不会生成额外的 dll,正是我需要的。
首先在 RB 的某个模块中添加一个方法 ShellExecute,用来封装对系统 API 的请求:
function ShellExecute(hWnd as Integer, lpOperation as String, _
lpFile as String, lpParameters as String, lpDirectory as String, nShowCmd as Integer)
注意,在 RB 中添加方法时,参数列表中的 _ 需要去掉,这里是为了排版的需要而加上的。
这个 API 是定义在 shell32.dll 中的,在 ShellExecute 方法中先需要声明:
soft declare function ShellExecuteA Lib "shell32.dll" _
(ByVal hWnd As Integer, ByVal lpOperation As CString, _
ByVal lpFile As CString, ByVal lpParameters As CString, _
ByVal lpDirectory As CString, ByVal nShowCmd As Integer) As Integersoft declare function ShellExecuteW Lib "shell32.dll" _
(ByVal hWnd As Integer, ByVal lpOperation As CString, _
ByVal lpFile As CString, ByVal lpParameters As CString, _
ByVal lpDirectory As CString, ByVal nShowCmd As Integer) As Integer
然后来调用这个 API:
dim ret as Integer
Try
ret = ShellExecuteW(hWnd, ConvertEncoding(lpOperation, Encodings.UTF16), _
ConvertEncoding(lpFile, Encodings.UTF16), _
ConvertEncoding(lpParameters, Encodings.UTF16), _
ConvertEncoding(lpDirectory, Encodings.UTF16), nShowCmd)
Catch
ret = ShellExecuteA(hWnd, lpOperation, lpFile, lpParameters, lpDirectory, nShowCmd)
End
return ret
把 ShellExecuteW 放在 Try ... Catch 中是为了兼容的需要,因为像 Windows 98 这样比较老的系统中,系统内部编码还不是 Unicode,还没有 ShellExecuteW 这样结尾是 W 的 API。
另外,因为 RB 内部是使用的 UTF-8 编码,而系统 API ShellExecuteW 使用的编码是 Unicode,所以参数在传递前需要进行转码,将字符串参数值转换为 Unicode 编码,否则在执行一个明明正确的命令时,会出现“找不到文件”的错误。
好了,这样就可以使用 ShellExecute 方法来执行外部程序了,例如:
#if TargetWin32
dim ret as Integer
ret = Win32Helper.ShellExecute(hWnd, "open", "cmd.exe", _
"/c shutdown -t 10", "", 0)
#endif
上面的代码就调用 cmd.exe 执行了命令 shutdown -s -t 10,也就是 10 秒后关机。
其实这个方法也可以用来打开文档或者网址,具体的用法可以去 MSDN 找一找。
当然,如果不在乎生成的 Windows 目标还有额外的 dll 的话,完全可以使用 RB 自带的 Shell 类,功能也强上不少。
请问博主,REALBasic中我想用一个按钮打开软件所在根目录下的某个目录。请问可以怎么实现?、我是想做一个光盘自启动导航程序。
是不是1exe没关系。。。。初学,RB的语言参考没找到。
这个应该是很方便的,直接用 FolderItem 的 Launch 方法就可以了,取当前目录的话,可以用 App.ExecutableFile 取得当前执行文件的路径,App 是一个 Application 对象。
谢谢,我试一下。。。
有完整的例子吗?
初学不是很懂。呵呵
文章里就差不多是一个完整的例子了。在 REALbasic 里给模块或者类添加一个方法,方法名为 ShellExecute,参数为:
hWnd as Integer, lpOperation as String, lpFile as String, lpParameters as String, lpDirectory as String, nShowCmd as Integer
返回类型为 Integer,然后方法的代码如下:
按文章里的说明来调用就可以了
ret = Win32Helper.ShellExecute(hWnd, “open”, “cmd.exe”, “/c shutdown -t 10”, “”, 0)
这句是调用的是吧,参数hWnd填写什么值啊
ret = Win32Helper.ShellExecute(1000, “open”, “cmd.exe”,”/c shutdown -t 1000″, “”, 0)
那个shutdown后面我写的1000啊,怎么一下就注销了,不是关机