AutoUpdate VBA startup macro? - vba

I'm building some Word 2003 macro that have to be put in the %APPDATA%\Microsoft\Word\Startup folder.
I can't change the location of this folder (to a network share). How can I auto update this macros ?
I have tried to create a bootstrapper macro, with an AutoExec sub that copy newer version from a file share to this folder. But as Word is locking the file, I get a Denied Exception.
Any idea ?
FYI, I wrote this code. The code is working fine for update templates in templates directory, but not in startup directory :
' Bootstrapper module
Option Explicit
Sub AutoExec()
Update
End Sub
Sub Update()
MirrorDirectory MyPath.MyAppTemplatesPath, MyPath.WordTemplatesPath
MirrorDirectory MyPath.MyAppStartupTemplatesPath, MyPath.WordTemplatesStartupPath
End Sub
' IOUtilities Module
Option Explicit
Dim fso As New Scripting.FileSystemObject
Public Sub MirrorDirectory(sourceDir As String, targetDir As String)
Dim result As FoundFiles
Dim s As Variant
sourceDir = RemoveTrailingBackslash(sourceDir)
targetDir = RemoveTrailingBackslash(targetDir)
With Application.FileSearch
.NewSearch
.FileType = MsoFileType.msoFileTypeAllFiles
.LookIn = sourceDir
.SearchSubFolders = True
.Execute
Set result = .FoundFiles
End With
For Each s In result
Dim relativePath As String
relativePath = Mid(s, Len(sourceDir) + 1)
Dim targetPath As String
targetPath = targetDir + relativePath
CopyIfNewer CStr(s), targetPath
Next s
End Sub
Public Function RemoveTrailingBackslash(s As String)
If Right(s, 1) = "\" Then
RemoveTrailingBackslash = Left(s, Len(s) - 1)
Else
RemoveTrailingBackslash = s
End If
End Function
Public Sub CopyIfNewer(source As String, target As String)
Dim shouldCopy As Boolean
shouldCopy = False
If Not fso.FileExists(target) Then
shouldCopy = True
ElseIf FileDateTime(source) > FileDateTime(target) Then
shouldCopy = True
End If
If (shouldCopy) Then
If Not fso.FolderExists(fso.GetParentFolderName(target)) Then fso.CreateFolder (fso.GetParentFolderName(target))
fso.CopyFile source, target, True
Debug.Print "File copied : " + source + " to " + target
Else
Debug.Print "File not copied : " + source + " to " + target
End If
End Sub
' MyPath module
Property Get WordTemplatesStartupPath()
WordTemplatesStartupPath = "Path To Application Data\Microsoft\Word\STARTUP"
End Property
Property Get WordTemplatesPath()
WordTemplatesPath = "Path To Application Data\Microsoft\Templates\Myapp\"
End Property
Property Get MyAppTemplatesPath()
MyAppTemplatesPath = "p:\MyShare\templates"
End Property
Property Get XRefStartupTemplatesPath()
MyAppStartupTemplatesPath = "p:\MyShare\startup"
End Property
[Edit] I explored another way
Another way I'm thinking about, is to pilot the organizer :
Sub Macro1()
'
' Macro1 Macro
' Macro recorded 10/7/2011 by beauge
'
Application.OrganizerCopy source:="P:\MyShare\Startup\myapp_bootstrapper.dot", _
Destination:= _
"PathToApplication Data\Microsoft\Word\STARTUP\myapp_bootstrapper.dot" _
, Name:="MyModule", Object:=wdOrganizerObjectProjectItems
End Sub
This is working, but has limitations :
either I have to hard-code modules to organize
or I have to change the option "Trust VBA project" to autodiscover items like this (which is not acceptable as it requires to lower the security of the station) :
the code of the project enumeration is this one :
Public Sub EnumProjectItem()
Dim sourceProject As Document
Dim targetProject As Document
Set sourceProject = Application.Documents.Open("P:\MyShare\Startup\myapp_bootstrapper.dot", , , , , , , , , wdOpenFormatTemplate)
Set targetProject = Application.Documents.Open("PathToApplication Data\Microsoft\Word\STARTUP\myapp_bootstrapper.dot", , , , , , , , , wdOpenFormatTemplate)
Dim vbc As VBcomponent
For Each vbc In sourceProject.VBProject.VBComponents 'crash here
Application.ActiveDocument.Range.InsertAfter (vbc.Name + " / " + vbc.Type)
Application.ActiveDocument.Paragraphs.Add
Next vbc
End Sub
[Edit 2] Another unsuccessful try :
I put, in my network share, a .dot with all the logic.
In my STARTUP folder, I put a simple .Dot file, that references the former one, with a single "Call MyApp.MySub".
This is actually working, but as the target template is not in a trusted location, a security warning is popped up each time word is launched (even if not related to the current application macro)

At least, I succeed partially using these steps :
Create a setup package. I use a NSIS script
the package detect any instance of Winword.exe and ask the user to retry when word is closed
extract from the registry the word's option path
deploy the files into the word's startup folder
add an uninstaller in the local user add/remove programs
I put the package in the remote share. I also added a .ini file containing the last version of the package (in the form "1.0")
In the macro itself, I have a version number ("0.9" for example).
At the startup (AutoExec macro), I compare the local version to the remote version
I use shell exec to fire the setup if a newer version is found.
The setup will wait for Word to close
A bit tricky, but it works on Word 2K3 and Word 2K10.

Related

Moving Files From One Folder To Another VB.Net

I am trying to figure out how to move 5 files
settings.txt
settings2.txt
settings3.txt
settings4.txt
settings5.txt
from one folder to another.
Although I know what the file names will be and what folder Name they will be in, I don't know where that folder will be on the Users computer.
My thought process is to use a FolderBrowseDialog which the user can browse to where the Folder is, and then when OK is pressed, it will perform the File copy to the destination folder, overwriting what's there.
This is what I have so far.
Dim FolderPath As String
Dim result As Windows.Forms.DialogResult = FolderBrowserImport.ShowDialog()
If result = DialogResult.OK Then
FolderPath = FolderBrowserImport.SelectedPath & "\"
My.Computer.FileSystem.CopyFile(
FolderPath & "settings.txt", "c:\test\settings.txt", overwrite:=True)
ElseIf result = DialogResult.Cancel Then
Exit Sub
End If
Rather than run this 5 times, is there a way where it can copy all 5 files at once
I know why IdleMind recommended the approach they did, but it would probably make for a bit more readable code to just list out the file names:
Imports System.IO
...
Dim result = FolderBrowserImport.ShowDialog()
If result <> DialogResult.OK Then Exit Sub
For Each s as String in {"settings.txt", "settings2.txt", "settings3.txt", "settings4.txt", "settings5.txt" }
File.Copy( _
Path.Combine(FolderBrowserImport.SelectedPath, s), _
Path.Combine("c:\test", s), _
True _
)
Next s
You can swap this fixed array out for a list that VB prepares for you:
For Each s as String in Directory.GetFiles(FolderBrowserImport.SelectedPath, "settings*.txt", SearchOption.TopDirectoryOnly)
File.Copy(s, Path.Combine("c:\test", Path.GetFilename(s)), True)
Next s
Tips:
It's usually cleaner to do a If bad Then Exit Sub than a If good Then (big load of indented code) End If - test all your known failure conditions at the start and exit the sub if anything fails, rather than arranging a huge amount of indented code
Use Path.Combine to combine path and filenames etc; it knows how to deal with stray \ characters
Use Imports to import namespaces rather than spelling everything out all the time (System.Windows.Forms.DialogResult - a winforms app will probably have all the necessaries imported already in the partial class so you can just say DialogResult. If you get a red wiggly line, point to the adjacent lightbulb and choose to import System.WIndows/Forms etc)
Once you have the selected folder, use a For loop to build up the names of the files you're looking for. Use System.IO.File.Exists() to see if they are there. Use System.IO.Path.Combine() to properly combine your folders with the filenames.
Here's a full example (without exception handling, which should be added):
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If FolderBrowserImport.ShowDialog() = DialogResult.OK Then
Dim FolderPath As String = FolderBrowserImport.SelectedPath
For i As Integer = 1 To 5
Dim FileName As String = "settings" & If(i = 1, "", i) & ".txt"
Dim FullPathFileName As String = System.IO.Path.Combine(FolderPath, FileName)
If System.IO.File.Exists(FullPathFileName) Then
Dim DestinationFullPathFileName = System.IO.Path.Combine("c:\test", FileName)
My.Computer.FileSystem.CopyFile(FullPathFileName, DestinationFullPathFileName, True)
Else
' possibly do something in here if the file does not exist?
MessageBox.Show("File not found: " & FullPathFileName)
End If
Next
End If
End Sub

File extension validation

This searches for the end of a file name removes it's current file type of .docm and converts it to a .docx. Works great.
ActiveDocument.SaveAs2 Left(ActiveDocument.Name, InStrRev(ActiveDocument.Name, ".") - 1), WdSaveFormat.wdFormatXMLDocument
However, I noticed a little bug. If there is a . in the file name, it finds that first and obviously creates a file that is incorrect.
For example:
TestFileV1.2AlexTest.docm
Becomes the file
TestFileV.2AlextTest Where the new file type is a .2ALEXTEST file.
Kind of a funny error, but still a bug none the less.
Best course of action for validation?
Thanks!
Try the VBA.Strings.Split() function, which splits a string into an array.
Split the File name on '.' and the last element in the array will be your extension:
Public Function GetExtension(FileName As String) As String
'Returns a file's extension
' This does not go to the filesystem and get the file:
' The function parses out the string after the last '.'
' Useful for situations where a file does not yet exist
' Nigel Heffernan Excellerando.Blogspot.com
' **** THIS CODE IS IN THE PUBLIC DOMAIN ****
'Print GetExtension("C:\Temp\data.txt1.docx")
'Returns docx
Dim arrayX() As String
Dim iLast As Integer
arrayX = Split(FileName, ".")
iLast = UBound(arrayX)
GetExtension = arrayX(iLast)
Erase arrayX
End Function
If you don't care about readability, the quick-and-dirty answer is:
strExt = Split(strFile, ".")(UBound(Split(strFile, ".")))
However... I think you're looking for something more sophisticated than a string parser to extract the file extension.
Are you actually looking to validate the file extension?
I'm not coding up a registry lookup for the ShellExt application command to open your file, but I had a closely-related issue to yours a year or two ago, when I needed to populate a file dialog's filter list with a list of arbitrary file extensions.
It doesn't 'validate' as such, but unknown extensions will return a string containing 'unknown file type', and you can test for that:
VBA and the Registry: Returning a File Type from a File Extension
Public Function GetExtensionType(strExt As String) As String
' Return a file extension type descriptor, if the OS knows it
' Parses out the string after the last "." and reads the registry
' GetExtensionType("txt") Returns 'Text Document'
' GetExtensionType("SystemORA.user.config") 'XML Configuration File'
' GetExtensionType("Phishy.vbs") 'VBScript Script File'
' Nigel Heffernan Excellerando.Blogspot.com
' **** THIS CODE IS IN THE PUBLIC DOMAIN ****
On Error GoTo ErrSub
Dim strType As String
Dim strTyp1 As String
Dim strTyp2 As String
strExt = Trim(strExt)
' Set a default return: if an error is raised, return this value
GetExtensionType = Trim(strExt & " (unknown file type)")
strExt = Split(strExt, ".")(UBound(Split(strExt, "."))) '
If strExt = "" Then
Exit Function
End If
With CreateObject("WScript.Shell")
' This will go to error if there's no key for strExt in HKCR
strTyp1 = .RegRead("HKCR." & strExt & "\")
If strTyp1 = "" Then
strType = strExt & " File"
Else
' This value isn't very readable, eg: Access.ACCDEFile.14
' But we can use it to retrieve a descriptive string:
strTyp2 = .RegRead("HKCR\" & strTyp1 & "\")
If strTyp2 = "" Then
' So we didn't get a descriptive string:
' Parse some readability out of strType1:
strType = strTyp1
strType = Replace(strType, "File", " File")
strType = Replace(strType, ".", " ")
Else
strType = strTyp2
End If
End If
End With
If strType <> "" Then
GetExtensionType = strType
End If
ExitSub:
Exit Function
ErrSub:
Resume ExitSub
End Function
I made it error-tolerant but I didn't bother idiot-proofing it because someone, somewhere, is building a better idiot; and it's entirely possible that the user was actually right insofar as there really are files called that, and my system didn't have a registry entry for the file type in question.
There is an obvious source of errors in the code: GetExtensionType("docx") will give you 'Microsoft Word Document' on an English-Language workstation. If your user base are working with other languages and locales, they will see the descriptive name 'Microsoft Word Document' in their chosen language; and any validation logic you've coded up will fail to match that string (unless, of course, your string literals are internationalised in a conditional compiler block).
So any validation against a predefined application name or file type needs to be at the language-independent layer of the registry, using 'strTyp1' from the root instead of the locale-dependent strings passed into 'strTyp2'.
Use the FileSystemObject from the Scripting Runtime - it has a .GetBaseName() method to extract the basename from a file path:
'Early bound (reference to Microsoft Scripting Runtime):
Dim fso As New FileSystemObject
ActiveDocument.SaveAs2 fso.GetBaseName(ActiveDocument.Name), WdSaveFormat.wdFormatXMLDocument
'Late bound:
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
ActiveDocument.SaveAs2 fso.GetBaseName(ActiveDocument.Name), WdSaveFormat.wdFormatXMLDocument
You can also retrieve the extension with the .GetExtensionName() method, the path with .GetParentFolderName(), and the drive letter with GetDriveName() (which also works with UNC paths).
If you need to find the registered name of the extension in the current Windows install, you can either use the registry method #Nile answered with or an API call to AssocQueryStringA:
Const ASSOCSTR_FRIENDLYDOCNAME = 3
Private Declare Function AssocQueryString Lib "shlwapi.dll" _
Alias "AssocQueryStringA" ( _
ByRef Flags As Long, _
ByVal str As Long, _
ByVal pszAssoc As String, _
ByVal pszExtra As String, _
ByVal pszOut As String, _
ByRef pcchOut As Long) As Long
Sub Main()
Dim buffer As String
buffer = String$(255, " ")
Dim hresult As Long
hresult = AssocQueryString(0, ASSOCSTR_FRIENDLYDOCNAME, ".docm", _
vbNullString, buffer, 255)
If hresult = 0 Then
'Should be something like "Microsoft Word Macro-Enabled Document"
Debug.Print Trim$(buffer)
End If
End Sub
Note that you can also retrieve addition information about the associated file type by passing different values for the str parameter. See the ASSOCSTR enumeration.

Copy and Rename File VB Script Not Working For SSIS Script Task

I am dynamically creating reports using an Excel Template for an SSIS Package. I am attempting to copy the Excel template and rename it using VB 2010 in Script Task object.
The following is my code:
Public Sub Main()
Dim sourcePath As String = "\\server\Dir1\Dir2\Dir3\FileName_TEMPLATE.xlsx"
Dim destPath As String = "\\server\Dir1\Dir2\Dir3\FileName" + CDate(Date.Today.Date).ToString("yyyyMMdd") + ".xlsx"
If File.Exists(destPath) = True Then
File.Delete(destPath) 'delete existing file'
File.Copy(sourcePath, destPath) 'copy template file and rename'
End If
Dts.TaskResult = ScriptResults.Success
End Sub
End Class
I changed If File.Exists(destPath) = True Then... to If File.Exists(sourcePath) = True... to see if the sourcePath existed and then added a MessageBox("File doesn't exist") in an ELSE statement to so if even the source file exists and it is returning the MessageBox stating
"File doesn't exist"
The Template file is there and I copied and pasted the address from Windows Explorer window to the sourcePath string to ensure path accuracy.
The sourcePath is on a different server.
The file is in the source path.
What am I doing wrong?
Thanks

How to use addin interface in Visual Studio 2008

Following is a code sample of Addin I copied from MSDN(http://msdn.microsoft.com/en-us/library/vstudio/envdte.addin.aspx) and did some modifications to. I create a Add-in project by VS2008 and paste the following code into it.
But it seems that it does not work properly.
1> DTE Add-in count before and after the Update does not change
2> Guid of the added addin is all zeros
3> I get error: The parameter is incorrect, at code line: DTE.Solution.AddIns.Add
Public Sub OnConnection(ByVal application As Object, ByVal connectMode As ext_ConnectMode, ByVal addInInst As Object, ByRef custom As Array) Implements IDTExtensibility2.OnConnection
_applicationObject = CType(application, DTE2)
_addInInstance = CType(addInInst, AddIn)
Me.AddInExample(_applicationObject)
End Sub
Function BrowseFile() As String
Dim OpenFileDialog1 As New OpenFileDialog
OpenFileDialog1.Filter = "*.dll file (*.dll)|*.dll|All files (*.*)|*.*"
OpenFileDialog1.FilterIndex = 1dialog
OpenFileDialog1.RestoreDirectory = True
If OpenFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
'MsgBox(OpenFileDialog1.FileName)
Return OpenFileDialog1.FileName
End If
Return ""
End Function
Sub AddInExample(ByVal DTE As DTE2)
' For this example to work correctly, there should be an add-in
' available in the Visual Studio environment.
' Set object references.
Dim addincoll As AddIns
Dim addinobj As AddIn
' Register an add-in, check DTE Add-in count before and after the
' Update.
addincoll = DTE.AddIns
MsgBox("AddIns collection parent name: " & addincoll.Parent.Name)
MsgBox("Number of Add-ins: " & addincoll.Count)
' NOTE: Use regsvr32 for Visual C++, regasm for [Visual Basic
' and Visual C#. Also, the pathname used below is an example only.
'Shell("regasm F:\AddIns\RegExplore\Debug\regexplore.dll")
'Shell("C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm e:\AddinTest1.dll")
Shell("C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm " & BrowseFile())
addincoll.Update()
MsgBox("Number of Add-ins: " & addincoll.Count)
addinobj = addincoll.Item(1)
' Connect the add-in if it is not already connected
' and list its SatelliteDLLPath and Guid.
If addinobj.Connected = False Then
addinobj.Connected = True
End If
MsgBox("Satellite DLL Path: " & addinobj.SatelliteDllPath)
MsgBox("DLL GUID: " & addinobj.Guid)
' Activates a solution add-in so that it is available, then
'deactivates it.
MsgBox(addinobj.ProgID)
MsgBox(addinobj.Description)
MsgBox(addinobj.Name)
addinobj = DTE.Solution.AddIns.Add(addinobj.ProgID, addinobj.Description, addinobj.Name, False)
DTE.Solution.AddIns.Item(1).Remove()
End Sub
I would start at the begining if I were you: MSDN VS Addin
Doing it this way allows you to debug (step-through) your code and will give you a good start. The page you are on assumes you already know how to do this.

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.
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
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
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