按ProcessID获取流程路径和名称 - 不一致的结果(VB6,VBA)

时间:2011-06-13 02:56:25

标签: winapi vba vb6 access-vba

我正在使用下面的代码来获取给定进程的文件路径和名称。我只是将ProcessID传递给函数ExePathFromProcID,它应该返回完整路径。它将硬盘驱动器列为设备而不是使用驱动器号,但这不是我的抱怨。查看我的代码,然后在下面查看我的投诉。

Public Declare Function OpenProcess Lib "kernel32" ( _
    ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _
    ByVal dwProcessId As Long) As Long

Public Declare Function GetProcessImageFileName Lib "psapi.dll" Alias "GetProcessImageFileNameA" _
    (ByVal hProcess As Long, _
    ByVal lpImageFileName As String, _
    ByVal nSize As Long) As Long

Public Declare Function CloseHandle Lib "kernel32" ( _
    ByVal hObject As Long) As Long     

Private Function ExePathFromProcID(idProc As Long) As String
    Const MAX_PATH = 260
    Const PROCESS_QUERY_INFORMATION = &H400
    Const PROCESS_VM_READ = &H10

    Dim sBuf As String
    Dim sChar As Long, l As Long, hProcess As Long
    sBuf = String$(MAX_PATH, Chr$(0))
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_VM_READ, 0, idProc)
    If hProcess Then
        sChar = GetProcessImageFileName(hProcess, sBuf, MAX_PATH)
        If sChar Then
            sBuf = Left$(sBuf, sChar)
            ExePathFromProcID = sBuf
            Debug.Print sBuf
        End If
        CloseHandle hProcess
    End If
End Function

我的抱怨是,只要首先检索到较长的路径,返回较短路径时,仍会显示较长过程路径的某些部分。这是一个例子:

第一次通话(正确结果):
\ Device \ HarddiskVolume2 \ Program Files \ Portable Apps \ Notepad ++ Portable \ App \ Notepad ++ \ notepad ++。exe

第二次通话(意外结果):
\ Device \ HarddiskVolume2 \ Program Files \ Microsoft Office \ Office12 \ MSACCESS.EXE tepad ++ \ notepad ++。exe

请注意第二次通话结果的“tepad ++ \ notepad ++。exe”?不要被它落在第二行的事实所迷惑。它是同一个字符串的所有部分,并在第二次调用此函数时返回。

为什么我的功能会返回这个?看起来这是一个全局字符串变量没有被清除的问题,但我几乎完全按照我发布的方式使用代码。没有全局变量。

3 个答案:

答案 0 :(得分:1)

我认为用QueryFullProcessImageName替换GetProcessImageFileName将解决第一个问题。

第二个问题是GetProcessImageFileName只是在另一个上面写了一个以空字符结尾的字符串。我不是VB专家,但您可以在将缓冲区传递给GetProcessImageFileName之前清除缓冲区,也可以在返回后设置正确的长度。

答案 1 :(得分:1)

如果查看返回的缓冲区,正确的路径实际上是以null结尾,例如,如果我传递了我的ultramon.exe的PID:

\  D  e  v  i  c  e  \  H  a  r  d  d  i  s  k  V  o  l  u  m  e  1  \  P  r  o  g  r  a  m     F  i  l  e  s  \  U  l  t  r  a  M  o  n  \  U  l  t  r  a  M  o  n  .  e  x  e     x  .  e  x  e     3  9     3  8     5  C     5  6     4  2     3  6     2  E     4  5     5  8     4  5     0     6  1     7  2     4  E     6  F     7  4     6  9     6  
5C 44 65 76 69 63 65 5C 48 61 72 64 64 69 73 6B 56 6F 6C 75 6D 65 31 5C 50 72 6F 67 72 61 6D 20 46 69 6C 65 73 5C 55 6C 74 72 61 4D 6F 6E 5C 55 6C 74 72 61 4D 6F 6E 2E 65 78 65 0 78 2E 65 78 65 0 33 39 20 33 38 20 35 43 20 35 36 20 34 32 20 33 36 20 32 45 20 34 35 20 35 38 20 34 35 20 30 20 36 31 20 37 32 20 34 45 20 36 46 20 37 34 20 36 39 20 36 

文档没有明确说明返回值是路径的长度,只是复制缓冲区的长度,似乎不是同一个东西; 如果函数成功,则返回值指定复制到缓冲区的字符串的长度

这意味着你需要:

sBuf = Left$(sBuf, InStr(1, sBuf, ChrW$(0)))

答案 2 :(得分:0)

关于返回值的内容,有关于文档的评论: http://msdn.microsoft.com/en-us/library/ms683217(v=vs.85).aspx#3

即。返回的值不是路径的长度。所以你应该使用某种strlen函数。