2013-09-19 1 views
1

Согласно MSDN информация здесь:Использование IShellLink интерфейса для разрешения ярлыка, который изменил свою букву диска

http://msdn.microsoft.com/en-us/library/windows/desktop/bb774952%28v=vs.85%29.aspx

И здесь:

http://msdn.microsoft.com/en-us/library/windows/desktop/bb774944%28v=vs.85%29.aspx

Как я могу разрешить FULLPATH из ссылку, которая изменила буквенный указатель на ярлыке Target?

Windows делает это автоматически менее чем за одну секунду, но мне нужно работать с большим количеством файлов ярлыков (.lnk-файлов) в моем приложении, и я всегда получаю исходный старый путь, я не могу разрешить путь, как окна делает.

Так, например, если у меня есть файл ярлыка в этом пути:

C:\Test.lnk 

И цель файла ярлыка это

D:\Directory\Test.txt 

Затем Если переименовать букву диска жесткого диск от «D:» до «F:» (жесткий диск, а не целевой ярлык). Windows все еще может распознать ярлык как действительный и может мгновенно разрешить путь ярлыка, поэтому я знаю, что это возможно, возможно, сделать это с помощью IShellInterface, но проблема в том, что я не знаю, как это сделать.

Я не понимаю, что мне нужно сделать, чтобы разрешить ярлык, я не знаю, нужно ли мне использовать метод GetPath или метод Resolve, или оба, также я не знаю, какой дескриптор окна мне нужно перейти к методу разрешения ... тогда для запуска msgbox в окне или метод вернет строку с reoslved пути ?, все это сводит меня с ума, мне нужен пример кода.

Я использую этот класс:

Imports System.Runtime.InteropServices 
Imports System.Text 

Public Class Form1 

Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load 
    Dim TargetFilename As String = ResolveShortcut("C:\Test.lnk") 
End Sub 

<DllImport("shfolder.dll", CharSet:=CharSet.Auto)> 
Friend Shared Function SHGetFolderPath(hwndOwner As IntPtr, nFolder As Integer, hToken As IntPtr, dwFlags As Integer, lpszPath As StringBuilder) As Integer 
End Function 

<Flags()> 
Private Enum SLGP_FLAGS 
    ''' <summary>Retrieves the standard short (8.3 format) file name</summary> 
    SLGP_SHORTPATH = &H1 
    ''' <summary>Retrieves the Universal Naming Convention (UNC) path name of the file</summary> 
    SLGP_UNCPRIORITY = &H2 
    ''' <summary>Retrieves the raw path name. A raw path is something that might not exist and may include environment variables that need to be expanded</summary> 
    SLGP_RAWPATH = &H4 
End Enum 

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> 
Private Structure WIN32_FIND_DATAW 
    Public dwFileAttributes As UInteger 
    Public ftCreationTime As Long 
    Public ftLastAccessTime As Long 
    Public ftLastWriteTime As Long 
    Public nFileSizeHigh As UInteger 
    Public nFileSizeLow As UInteger 
    Public dwReserved0 As UInteger 
    Public dwReserved1 As UInteger 
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> 
    Public cFileName As String 
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=14)> 
    Public cAlternateFileName As String 
End Structure 

<Flags()> 
Private Enum SLR_FLAGS 
    ''' <summary> 
    ''' Do not display a dialog box if the link cannot be resolved. When SLR_NO_UI is set, 
    ''' the high-order word of fFlags can be set to a time-out value that specifies the 
    ''' maximum amount of time to be spent resolving the link. The function returns if the 
    ''' link cannot be resolved within the time-out duration. If the high-order word is set 
    ''' to zero, the time-out duration will be set to the default value of 3,000 milliseconds 
    ''' (3 seconds). To specify a value, set the high word of fFlags to the desired time-out 
    ''' duration, in milliseconds. 
    ''' </summary> 
    SLR_NO_UI = &H1 
    ''' <summary>Obsolete and no longer used</summary> 
    SLR_ANY_MATCH = &H2 
    ''' <summary>If the link object has changed, update its path and list of identifiers. 
    ''' If SLR_UPDATE is set, you do not need to call IPersistFile::IsDirty to determine 
    ''' whether or not the link object has changed.</summary> 
    SLR_UPDATE = &H4 
    ''' <summary>Do not update the link information</summary> 
    SLR_NOUPDATE = &H8 
    ''' <summary>Do not execute the search heuristics</summary> 
    SLR_NOSEARCH = &H10 
    ''' <summary>Do not use distributed link tracking</summary> 
    SLR_NOTRACK = &H20 
    ''' <summary>Disable distributed link tracking. By default, distributed link tracking tracks 
    ''' removable media across multiple devices based on the volume name. It also uses the 
    ''' Universal Naming Convention (UNC) path to track remote file systems whose drive letter 
    ''' has changed. Setting SLR_NOLINKINFO disables both types of tracking.</summary> 
    SLR_NOLINKINFO = &H40 
    ''' <summary>Call the Microsoft Windows Installer</summary> 
    SLR_INVOKE_MSI = &H80 
End Enum 

''' <summary>The IShellLink interface allows Shell links to be created, modified, and resolved</summary> 
<ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")> 
Private Interface IShellLinkW 
    ''' <summary>Retrieves the path and file name of a Shell link object</summary> 
    Sub GetPath(<Out(), MarshalAs(UnmanagedType.LPWStr)> pszFile As StringBuilder, cchMaxPath As Integer, ByRef pfd As WIN32_FIND_DATAW, fFlags As SLGP_FLAGS) 
    ''' <summary>Retrieves the list of item identifiers for a Shell link object</summary> 
    Sub GetIDList(ByRef ppidl As IntPtr) 
    ''' <summary>Sets the pointer to an item identifier list (PIDL) for a Shell link object.</summary> 
    Sub SetIDList(pidl As IntPtr) 
    ''' <summary>Retrieves the description string for a Shell link object</summary> 
    Sub GetDescription(<Out(), MarshalAs(UnmanagedType.LPWStr)> pszName As StringBuilder, cchMaxName As Integer) 
    ''' <summary>Sets the description for a Shell link object. The description can be any application-defined string</summary> 
    Sub SetDescription(<MarshalAs(UnmanagedType.LPWStr)> pszName As String) 
    ''' <summary>Retrieves the name of the working directory for a Shell link object</summary> 
    Sub GetWorkingDirectory(<Out(), MarshalAs(UnmanagedType.LPWStr)> pszDir As StringBuilder, cchMaxPath As Integer) 
    ''' <summary>Sets the name of the working directory for a Shell link object</summary> 
    Sub SetWorkingDirectory(<MarshalAs(UnmanagedType.LPWStr)> pszDir As String) 
    ''' <summary>Retrieves the command-line arguments associated with a Shell link object</summary> 
    Sub GetArguments(<Out(), MarshalAs(UnmanagedType.LPWStr)> pszArgs As StringBuilder, cchMaxPath As Integer) 
    ''' <summary>Sets the command-line arguments for a Shell link object</summary> 
    Sub SetArguments(<MarshalAs(UnmanagedType.LPWStr)> pszArgs As String) 
    ''' <summary>Retrieves the hot key for a Shell link object</summary> 
    Sub GetHotkey(ByRef pwHotkey As Short) 
    ''' <summary>Sets a hot key for a Shell link object</summary> 
    Sub SetHotkey(wHotkey As Short) 
    ''' <summary>Retrieves the show command for a Shell link object</summary> 
    Sub GetShowCmd(ByRef piShowCmd As Integer) 
    ''' <summary>Sets the show command for a Shell link object. The show command sets the initial show state of the window.</summary> 
    Sub SetShowCmd(iShowCmd As Integer) 
    ''' <summary>Retrieves the location (path and index) of the icon for a Shell link object</summary> 
    Sub GetIconLocation(<Out(), MarshalAs(UnmanagedType.LPWStr)> pszIconPath As StringBuilder, cchIconPath As Integer, ByRef piIcon As Integer) 
    ''' <summary>Sets the location (path and index) of the icon for a Shell link object</summary> 
    Sub SetIconLocation(<MarshalAs(UnmanagedType.LPWStr)> pszIconPath As String, iIcon As Integer) 
    ''' <summary>Sets the relative path to the Shell link object</summary> 
    Sub SetRelativePath(<MarshalAs(UnmanagedType.LPWStr)> pszPathRel As String, dwReserved As Integer) 
    ''' <summary>Attempts to find the target of a Shell link, even if it has been moved or renamed</summary> 
    Sub Resolve(hwnd As IntPtr, fFlags As SLR_FLAGS) 
    ''' <summary>Sets the path and file name of a Shell link object</summary> 
    Sub SetPath(<MarshalAs(UnmanagedType.LPWStr)> pszFile As String) 

End Interface 

<ComImport(), Guid("0000010c-0000-0000-c000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> 
Public Interface IPersist 
    <PreserveSig()> 
    Sub GetClassID(ByRef pClassID As Guid) 
End Interface 


<ComImport(), Guid("0000010b-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> 
Public Interface IPersistFile 
    Inherits IPersist 
    Shadows Sub GetClassID(ByRef pClassID As Guid) 
    <PreserveSig()> 
    Function IsDirty() As Integer 

    <PreserveSig()> 
    Sub Load(<[In](), MarshalAs(UnmanagedType.LPWStr)> pszFileName As String, dwMode As UInteger) 

    <PreserveSig()> 
    Sub Save(<[In](), MarshalAs(UnmanagedType.LPWStr)> pszFileName As String, <[In](), MarshalAs(UnmanagedType.Bool)> fRemember As Boolean) 

    <PreserveSig()> 
    Sub SaveCompleted(<[In](), MarshalAs(UnmanagedType.LPWStr)> pszFileName As String) 

    <PreserveSig()> 
    Sub GetCurFile(<[In](), MarshalAs(UnmanagedType.LPWStr)> ppszFileName As String) 
End Interface 

Const STGM_READ As UInteger = 0 
Const MAX_PATH As Integer = 260 

' CLSID_ShellLink from ShlGuid.h 
<ComImport(), Guid("00021401-0000-0000-C000-000000000046")> Public Class ShellLink 
End Class 


Public Shared Function ResolveShortcut(filename As String) As String 
    Dim link As New ShellLink() 
    DirectCast(link, IPersistFile).Load(filename, STGM_READ) 
    ' TODO: if I can get hold of the hwnd call resolve first. This handles moved and renamed files. 
    ' ((IShellLinkW)link).Resolve(hwnd, 0) 
    Dim sb As New StringBuilder(MAX_PATH) 
    Dim data As New WIN32_FIND_DATAW() 
    DirectCast(link, IShellLinkW).GetPath(sb, sb.Capacity, data, 0) 
    Return sb.ToString() 
End Function 

End Class 

EDIT:

Если вы знаете, простой, но эффективный способ получить FULLPATH когда изменения DriveLetter тогда только я приму ответ ,

Но я не хочу использовать старые методы vb6 или vbs или использовать внешние приложения или для циклов For, поэтому я попытался использовать apis, я думаю, что это лучший способ для производительности.

ответ

1

Это тестируется только с подключенным сетевым диском (я won`t изменить свои локальные driveletters для тестирования):

Public Shared Function ResolveShortcut(filename As String,hwnd As IntPtr) As String 
    Dim link As New ShellLink() 
    DirectCast(link, IPersistFile).Load(filename, STGM_READ) 

    DirectCast(link, IShellLinkW).Resolve(hwnd, SLR_FLAGS.SLR_UPDATE) 

    Dim sb As New StringBuilder(MAX_PATH) 
    Dim data As New WIN32_FIND_DATAW() 
    DirectCast(link, IShellLinkW).GetPath(sb, sb.Capacity, data, 0) 
    Return sb.ToString() 
End Function 

Чтобы называться как:

Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load 
    Dim TargetFilename As String = ResolveShortcut("C:\Test.lnk",Me.Handle) 
End Sub 

Как документации , вы указали, что:

SLR_UPDATE (0x0004)
Если объект ссылки изменился, обновите его путь и список идентификаторов. Если установлен SLR_UPDATE, вам не нужно вызывать IPersistFile :: IsDirty, чтобы определить, был ли объект ссылки изменен.

Так передавая ручку формы (которую Shell будет нужно, если это необходимо для отображения какой-то диалог) для вызова метода Resolve и передавая SLR_UPDATE в качестве второго параметра, результаты для подключенного networkdrive в правильном пути (в по крайней мере, на моем сайте).

Смежные вопросы