ShellExecute API问题

Home Home
引用 | 编辑 sob790717
2013-11-26 20:45
楼主
推文 x0
ShellExecute API 程式码在VB6之下这样写是没问题的

模组
Public Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long


表单的一个按钮加入程式码
ShellExecute Me.hwnd, &q ..

访客只能看到部份内容,免费 加入会员



献花 x0
引用 | 编辑 ebolaman
2013-11-26 23:45
1楼
  
VB6 的 Me.hwnd 在 .NET 等同 Me.Handle

不过这个值如果和视窗没有关系,可以设为 0 (NULL)



.NET 比较习惯的 API 宣告用法是 DllImport 而且注意指标通常都是用 IntPtr (ㄧ种指标型态)

.NET style API 宣告:

复制程式
    <DllImport("shell32.dll")> _
    Private Shared Function ShellExecute(
            ByVal hwnd As IntPtr,
            ByVal lpOperation As String,
            ByVal lpFile As String,
            ByVal lpParameters As String,
            ByVal lpDirectory As String,
            ByVal nShowCmd As ShowCommands) As IntPtr
    End Function

呼叫:

复制程式
        ShellExecute(IntPtr.Zero,
                     "open",
                     "http://bbs.mychat.to/thread.php?fid=168",
                     "",
                     "",
                     ShowCommands.SW_SHOWNORMAL)

另外除了用 ShellExecute, 也可以用 .NET 内建的 Process.Start 达成同样效果

我会比较建议用 Process.Start 因为程式码更简短,也不用 API:

复制程式
Process.Start("http://bbs.mychat.to/thread.php?fid=168")

有关 ShellExecute 各个参数的含意,以及范例,请参考

PInvoke: http://www.pinvoke.net/default.aspx/shell32/ShellExecute.html

MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspx

本帖包含附件
档名: zip Form1-code.rar   (2022-06-09 14:21 / 2 KB)   下载次数:2


献花 x1
引用 | 编辑 sob790717
2013-11-27 14:26
2楼
  
下面是引用 ebolaman 于 2013-11-26 23:45 发表的 : 到引言文
VB6 的 Me.hwnd 在 .NET 等同 Me.Handle
不过这个值如果和视窗没有关系,可以设为 0 (NULL)

.NET 比较习惯的 API 宣告用法是 DllImport 而且注意指标通常都是用 IntPtr (ㄧ种指标型态)
.NET style API 宣告:
.......

感谢您的解答
我会选择使用ShellExecute是因为外部程式他自己存取档案上的问题
那个程式他会参照开始位置来存取档案
process.start好像没办法顺边帮他指定开始位置

所谓的开始位置是指


因为有些外部程式在执行时会参照他的开始位置来存取他的一些附属档案

例如" 111\A.exe" ShellExecute "222\B.exe" 之后
B.exe 会写入一些档案到跟他同级目录(222)之下

但是如果换成Shell (或是VB2010的processor.start)指令
就会变成B.exe 会往A.exe的所在目录(111)写入一些原本应该在(222)目录之下的档案
变成B.exe会发生找不到档案的问题,因为外部程序将档案存错资料夹了
所以不得不用此API

或是我听其他高手可以先将processor.start切换工作路径再执行外部程式
但是因为没经验所以不太明白

献花 x0
引用 | 编辑 ebolaman
2013-11-27 23:45
3楼
  
下面是引用 sob790717 于 2013-11-27 14:26 发表的 : 到引言文


感谢您的解答
我会选择使用ShellExecute是因为外部程式他自己存取档案上的问题
那个程式他会参照开始位置来存取档案
process.start好像没办法顺边帮他指定开始位置

所谓的开始位置是指


因为有些外部程式在执行时会参照他的开始位置来存取他的一些附属档案

例如" 111\A.exe" ShellExecute "222\B.exe" 之后
B.exe 会写入一些档案到跟他同级目录(222)之下

但是如果换成Shell (或是VB2010的processor.start)指令
就会变成B.exe 会往A.exe的所在目录(111)写入一些原本应该在(222)目录之下的档案
变成B.exe会发生找不到档案的问题,因为外部程序将档案存错资料夹了
所以不得不用此API

或是我听其他高手可以先将processor.start切换工作路径再执行外部程式
但是因为没经验所以不太明白

Process.Start() 也可以指定开始位置哦



Process.Start(...) 有许多呼叫方式,可以参考 MSDN 的这个方式

http://msdn.microsoft.com/en-us/library/0w4h05yb

Process.Start(psi)

psi 是一个 ProcessStartInfo 实例

除了你说的 开始位置 (Working Directory),还可以指定参数等

用法如下

复制程式
        Dim psi As New ProcessStartInfo


        With psi
            .FileName = "将被执行的档案"
            .WorkingDirectory = "开始位置"
        End With


        Process.Start(psi)

范例:

复制程式
Public Class Form1
    Private Sub Button1_Click() Handles Button1.Click
        Dim psi As New ProcessStartInfo


        With psi
            .FileName = Application.ExecutablePath
            .WorkingDirectory = IO.Path.GetTempPath()
        End With


        Process.Start(psi)
    End Sub


    Private Sub Form1_Load() Handles MyBase.Load
        MessageBox.Show(String.Format("Working directory: {0}",
                                      IO.Directory.GetCurrentDirectory()))
    End Sub


End Class

Application.ExecutablePath 是自己 .exe 的完整路径

IO.Path.GetTempPath() 是 Temp 暂存资料夹

以上程式呼叫自己,当表单载入时,用讯息显示目前程式的开始位置



本帖包含附件
档名: zip Form1-code.rar   (2022-06-09 14:21 / 2 KB)   下载次数:1


献花 x1
引用 | 编辑 sob790717
2013-11-28 20:26
4楼
  
只剩最后一个小小的问题

复制程式
        Dim TWN_GameClientStartInfo As New ProcessStartInfo


        With TWN_GameClientStartInfo
            .FileName = My.Settings.TWN_TR_GameClient_Path  '"将被执行的档案"
            Dim TWN_PathWithoutFileName As String
            TWN_PathWithoutFileName = My.Settings.TWN_TR_GameClient_Path
            TWN_PathWithoutFileName = Replace(TWN_PathWithoutFileName, "\talesrunner.exe", "")
            .WorkingDirectory = TWN_PathWithoutFileName  '"开始位置"

        End With

        MsgBox("dir  " & TWN_GameClientStartInfo.WorkingDirectory & vbCrLf & "file   " & TWN_GameClientStartInfo.FileName)


因为我自己的程式设计方法而遇到了一点 .WorkingDirectory 上的小问题
以上程式码我另外加入一行 Dim TWN_PathWithoutFileName As String 定义字串
然后把设定组态的一个字串读入到TWN_PathWithoutFileName
再使用Replace函式去除掉档案名之后再放入到.WorkingDirectory

请问以上作法是否有更简略化的写法呢?
还是已经是最好的了?

献花 x0
引用 | 编辑 ebolaman
2013-11-28 21:56
5楼
  
有关路径的处理,交给 .NET 内建的 IO.Path 底下的函式就对了

IO.Path.GetDirectoryName("C:\MyDir\MySubDir\myfile.ext") -> "C:\MyDir\MySubDir"

MSDN: http://msdn.microsoft.com/en-us/library/system.io.path.getdirectoryname.aspx

所以部分程式码可改成

复制程式
TWN_PathWithoutFileName = My.Settings.TWN_TR_GameClient_Path
.WorkingDirectory = IO.Path.GetDirectoryName(TWN_PathWithoutFileName)

其他小建议:

1. 小函式内 变数不宜太长,否则打字容易错,解读也容易错 -> 在宣告变数前用注解,这个变数是做什么的

2. 如果是一个实例 (例 Dim a As New ProcessStartInfo 那么 a 就是实例)
开头最好是小写,避免和大写开头的 Class 搞混 (ProcessStartInfo 就是一个 Class)

3. 可以开头用 Dim file As String = My.Settings.TWN_TR_GameClient_Path 
后面程式码都用 file 来写,未来如需修改,只需修改一处即可

4. 如需用 MsgBox 显示讯息,如果出现太长的连接 (例: "A" & var1 & "B" & var2 & "C")
可以考虑用 String.Format("A {0} B {1} C", var1, var2) 来达成,使程式码更有弹性

献花 x1