Richard Harrison
Richard Harrison

Reputation: 385

Extracting Filename and Path from a running process

I'm writing a screen capture application for a client. The capture part is fine, but he wants to get the name and path of the file that the capture is of.

Using system.diagnostics.process I am able to get the process that the capture is of, and can get the full path of the EXE, but not the file that is open.

ie. Notepad is open with 'TextFile1.txt' as its document. I can get from the process the MainWindowTitle which would be 'TextFile1.txt - Notepad' but what I need is more like 'c:\users....\TextFile1.txt'

Is there a way of getting more information from the process?

I'm sure there is a way, but I can't figure it out

Any help greatly appreciated.

Upvotes: 5

Views: 4299

Answers (3)

Tom Nighy
Tom Nighy

Reputation: 11

I know this post is old, but since I've searched for this two days ago, I'm sure others would be interested. My code below will get you the file paths from Notepad, Wordpad, Excel, Microsoft Word, PowerPoint, Publisher, Inkscape, and any other text or graphic editor's process, as long as the filename and extension is in the title bar of the opened window.

Instead of searching, it obtains the file's target path from Windows' hidden Recent Items directory, which logs recently opened and saved files as shortcuts. I discovered this hidden directory in Windows 7. You're gonna have to check if Windows 10 or 11 has this:

C:\Users\ "username" \AppData\Roaming\Microsoft\Windows\Recent

I slapped this code together under Framework 4, running as 64bit. The COM dlls that must be referenced in order for the code to work are Microsoft Word 14.0 Object Library, Microsoft Excel 14.0 Object Library, Microsoft PowerPoint 14.0 Object Library, and Microsoft Shell Controls And Automation.

For testing, the code below needs a textbox, a listbox, a button, and 3 labels (Label1, FilenameLabel, Filepath).

Once you have this working, after submitting a process name, you will have to click the filename item in the ListBox to start the function to retrieve it's directory path.

Option Strict On
Option Explicit On

Imports System.Runtime.InteropServices
Imports Microsoft.Office.Interop.Excel
Imports Microsoft.Office.Interop.Word
Imports Microsoft.Office.Interop.PowerPoint
Imports Shell32

Public Class Form1


    'function gets names of all opened Excel workbooks, adding them to the ListBox
    Public Shared Function ExcelProcess(ByVal strings As String) As String
        Dim Excel As Microsoft.Office.Interop.Excel.Application = CType(Marshal.GetActiveObject("Excel.Application"), Microsoft.Office.Interop.Excel.Application)
        For Each Workbook As Microsoft.Office.Interop.Excel.Workbook In Excel.Workbooks
            Form1.ListBox1.Items.Add(Workbook.Name.ToString() & " - " & Form1.TextBox1.Text)
        Next
        Return strings
    End Function

    'function gets names of all opened Word documents, adding them to the ListBox
    Public Shared Function WordProcess(ByVal strings As String) As String
        Dim Word As Microsoft.Office.Interop.Word.Application = CType(Marshal.GetActiveObject("Word.Application"), Microsoft.Office.Interop.Word.Application)
        For Each Document As Microsoft.Office.Interop.Word.Document In Word.Documents
            Form1.ListBox1.Items.Add(Document.Name.ToString() & " - " & Form1.TextBox1.Text)
        Next
        Return strings
    End Function

    'function gets names of all opened PowerPoint presentations, adding them to the ListBox
    Public Shared Function PowerPointProcess(ByVal strings As String) As String
        Dim PowerPoint As Microsoft.Office.Interop.PowerPoint.Application = CType(Marshal.GetActiveObject("PowerPoint.Application"), Microsoft.Office.Interop.PowerPoint.Application)
        For Each Presentation As Microsoft.Office.Interop.PowerPoint.Presentation In PowerPoint.Presentations
            Form1.ListBox1.Items.Add(Presentation.Name.ToString() & " - " & Form1.TextBox1.Text)
        Next
        Return strings
    End Function


    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'clears listbox to prepare for new process items
        ListBox1.Items.Clear()

        'gets process title from TextBox1
        Dim ProcessName As String = TextBox1.Text

        'prepare string's case format for
        ProcessName = ProcessName.ToLower

        'corrects Office process names
        If ProcessName = "microsoft excel" Then
            ProcessName = "excel"
        Else
            If ProcessName = "word" Or ProcessName = "microsoft word" Then
                ProcessName = "winword"
            Else
                If ProcessName = "powerpoint" Or ProcessName = "microsoft powerpoint" Then
                    ProcessName = "powerpnt"
                Else
                End If
            End If

        End If
        'get processes by name (finds only one instance of Excel or Microsoft Word)
        Dim proclist() As Process = Process.GetProcessesByName(ProcessName)

        'adds window titles of all processes to a ListBox
        For Each prs As Process In proclist

            If ProcessName = "excel" Then
                'calls function to add all Excel process instances' workbook names to the ListBox
                ExcelProcess(ProcessName)
            Else
                If ProcessName = "winword" Then
                    'calls function to add all Word process instances' document names to the ListBox
                    WordProcess(ProcessName)
                Else
                    If ProcessName = "powerpnt" Then
                        'calls function to add all Word process instances' document names to the ListBox
                        PowerPointProcess(ProcessName)
                    Else
                        'adds all Notepad or Wordpad process instances' filenames
                        ListBox1.Items.Add(prs.MainWindowTitle)
                    End If
                End If
            End If

        Next
    End Sub


    Private Sub ListBox1_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListBox1.MouseClick
        Try
            'add ListBox item (full window title) to string
            Dim ListBoxSelection As String = String.Join(Environment.NewLine, ListBox1.SelectedItems.Cast(Of String).ToArray)

            'get full process title after "-" from ListBoxSelection
            Dim GetProcessTitle As String = ListBoxSelection.Split("-"c).Last()

            'create string to remove from ListBoxSelection
            Dim Remove As String = " - " & GetProcessTitle

            'Extract filename from ListBoxSelection string, minus process full name
            Dim Filename As String = ListBoxSelection.Substring(0, ListBoxSelection.Length - Remove.Length + 1)

            'display filename
            FilenameLabel.Text = "Filename:  " & Filename

            'for every file opened and saved via savefiledialogs and openfiledialogs in editing software
            'Microsoft Windows always creates and modifies shortcuts of them in Recent Items directory:
            'C:\Users\ "Username" \AppData\Roaming\Microsoft\Windows\Recent
            'so the below function gets the target path from files's shortcuts Windows created
            FilePathLabel.Text = "File Path:  " & GetLnkTarget("C:\Users\" & Environment.UserName & "\AppData\Roaming\Microsoft\Windows\Recent\" & Filename & ".lnk")

        Catch ex As Exception
            'no file path to show if nothing was saved yet
            FilePathLabel.Text = "File Path:  Not saved yet."
        End Try

    End Sub


    'gets file's shortcut's target path
    Public Shared Function GetLnkTarget(ByVal lnkPath As String) As String
        Dim shl = New Shell32.Shell()
        lnkPath = System.IO.Path.GetFullPath(lnkPath)
        Dim dir = shl.NameSpace(System.IO.Path.GetDirectoryName(lnkPath))
        Dim itm = dir.Items().Item(System.IO.Path.GetFileName(lnkPath))
        Dim lnk = DirectCast(itm.GetLink, Shell32.ShellLinkObject)
        Return lnk.Target.Path
    End Function

End Class

Upvotes: 1

TOM
TOM

Reputation: 881

i think it is the simplest way

For Each prog As Process In Process.GetProcesses
    If prog.ProcessName = "notepad" Then
          ListBox1.Items.Add(prog.ProcessName)
     End If
Next

Upvotes: 1

flipgish
flipgish

Reputation: 46

You can use ManagementObjectSearcher to get the command line arguments for a process, and in this notepad example, you can parse out the file name. Here's a simple console app example that writes out the full path and file name of all open files in notepad..

Imports System
Imports System.ComponentModel
Imports System.Management
Module Module1
    Sub Main()
        Dim cl() As String
        For Each p As Process In Process.GetProcessesByName("notepad")
            Try
                Using searcher As New ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " & p.Id)
                    For Each mgmtObj As ManagementObject In searcher.Get()
                        cl = mgmtObj.Item("CommandLine").ToString().Split("""")
                        Console.WriteLine(cl(cl.Length - 1))
                    Next
                End Using
            Catch ex As Win32Exception
                'handle error
            End Try
        Next
        System.Threading.Thread.Sleep(1000000)
    End Sub
End Module

I had to add a reference to this specific dll:

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Managment.dll

Upvotes: 3

Related Questions