Seite 1 von 1

Softlinks von Verzeichnissen unter Vista

Verfasst: 07.04.2009 22:46
von ts-soft
Wie kann ich zu so einem Verzeichnis den echten Pfad ermitteln?

Das sind unter Vista z.B. Verzeichnisse wie: "Documents and Settings" oder
"Programme", die es als solche ja nicht mehr gibt.

Anhand der Namen kann ich nicht vorgehen, da es je nach Ländereinstellung
andere solcher Verzeichnisse geben kann.

Wäre schön wenn jemand da was weiß, ich selber habe bisher nichts
passendes gefunden

Gruß

Thomas

Verfasst: 07.04.2009 23:08
von RSBasic
@ts-soft
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders

Andere Orte kannst du mit Hilfe der Umgebungsvariablen ermitteln.

Meinst du das?

Kannst du nicht per spec_folder deine Pfade ermitteln?

Ansonsten habe ich keine Ahnung, ich benutze kein Vista.

Verfasst: 07.04.2009 23:26
von ts-soft
Nein, specialfolder nützt mir nichts, hab ja keine #CSIDL_bla zur Verfügung,
sondern nur den Pfad, dem ich folgen muß, leider funktioniert das nicht
autom., sondern es wird ein leeres Verzeichnis angezeigt :(
Ich erkenne die Ordner eigentlich nur am Attribut: #FILE_ATTRIBUTE_REPARSE_POINT
Jetzt muß ich irgendwie per API das zugehörige Verzeichnis ermitteln.
Ohne Vista wirste das auch nicht verstehen können. Selbst das
ExplorerListGadget kommt damit nicht klar, sondern zeigt darin nur eine
leere an :mrgreen:

Verfasst: 08.04.2009 03:09
von freak
Das ExplorerListGadget zeigt ein leeres Verzeichnis an, nicht weil es dem link nicht folgen kann sondern weil der Prozess nicht die Rechte dazu hat auf "C:\Documents and Settings" direkt zuzugreifen. Mit einem Unterordner wie "C:\Documents and Settings\<Username>" geht es wieder. Der Explorer lässt das browsen des Ordners auch nicht zu, desshalb ist es schon korrekt das das ExplorerListGadget nicht versucht selbst den link aufzulösen.


Der Code funktioniert auch mit 64bit:

Code: Alles auswählen

; WinIoCtl.h
;
#FILE_DEVICE_FILE_SYSTEM         = $00000009
#METHOD_BUFFERED                 = 0
#FILE_ANY_ACCESS                 = 0
#FILE_SPECIAL_ACCESS             = (#FILE_ANY_ACCESS)

Macro CTL_CODE( DeviceType, Function, Method, Access )
  (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
EndMacro

#FSCTL_SET_REPARSE_POINT         = CTL_CODE(#FILE_DEVICE_FILE_SYSTEM, 41, #METHOD_BUFFERED, #FILE_SPECIAL_ACCESS)
#FSCTL_GET_REPARSE_POINT         = CTL_CODE(#FILE_DEVICE_FILE_SYSTEM, 42, #METHOD_BUFFERED, #FILE_ANY_ACCESS)
#FSCTL_DELETE_REPARSE_POINT      = CTL_CODE(#FILE_DEVICE_FILE_SYSTEM, 43, #METHOD_BUFFERED, #FILE_SPECIAL_ACCESS)

; Winbase.h
;
#FILE_FLAG_OPEN_REPARSE_POINT    = $00200000

; WinNT.h
;
#IO_REPARSE_TAG_MOUNT_POINT  = $A0000003       
#IO_REPARSE_TAG_HSM          = $C0000004       
#IO_REPARSE_TAG_HSM2         = $80000006       
#IO_REPARSE_TAG_SIS          = $80000007       
#IO_REPARSE_TAG_DFS          = $8000000A       
#IO_REPARSE_TAG_SYMLINK      = $A000000C       
#IO_REPARSE_TAG_DFSR         = $80000012


; From Windows Driver Kit.
; http://msdn.microsoft.com/en-us/library/ms791514.aspx
;
Structure SymbolicLinkReparseBuffer
  SubstituteNameOffset.w
  SubstituteNameLength.w
  PrintNameOffset.w
  PrintNameLength.w
  Flags.l
  PathBuffer.w[1]
EndStructure

Structure MountPointReparseBuffer
  SubstituteNameOffset.w
  SubstituteNameLength.w
  PrintNameOffset.w
  PrintNameLength.w
  PathBuffer.w[1]
EndStructure

Structure GenericReparseBuffer
  DataBuffer.b[1]
EndStructure

Structure REPARSE_DATA_BUFFER
  ReparseTag.l
  ReparseDataLength.w
  Reserved.w
  StructureUnion
    SymbolicLinkReparseBuffer.SymbolicLinkReparseBuffer
    MountPointReparseBuffer.MountPointReparseBuffer
    GenericReparseBuffer.GenericReparseBuffer
  EndStructureUnion
EndStructure




; Tries to follow a directory link on Windows Vista (should also work for files)
;
; - If the directory is no link, the result is the original directory
; - If the target cannot be read, the result is ""
;
Procedure.s GetDirectoryTarget(Directory$)
  Protected TokenHandle, BufferSize, hDirectory, BytesReturned.l
  Protected Privileges.TOKEN_PRIVILEGES
  Protected *Buffer.REPARSE_DATA_BUFFER
  Protected Result$ = ""

  ; Check if the directory is a reparse point (link or mount point)
  ;
  If GetFileAttributes_(@Directory$) & #FILE_ATTRIBUTE_REPARSE_POINT

    ; The backup privilege is required to open a directory for io queries
    ; So try to set it on our process token. (usually it should be set already)
    ;
    If OpenProcessToken_(GetCurrentProcess_(), #TOKEN_ADJUST_PRIVILEGES, @TokenHandle)
      Privileges\PrivilegeCount = 1
      Privileges\Privileges[0]\Attributes = #SE_PRIVILEGE_ENABLED
    
      If LookupPrivilegeValue_(#Null, @"SeBackupPrivilege", @Privileges\Privileges[0]\Luid)       
        AdjustTokenPrivileges_(TokenHandle, #False, @Privileges, SizeOf(TOKEN_PRIVILEGES), #Null, #Null)
      EndIf    
      CloseHandle_(TokenHandle)
    EndIf
    
    ; Open the directory
    ;   Have to pass 0 as access right (not #GENERIC_READ), as it fails otherwise
    ;   http://www.codeproject.com/KB/vista/Windows_Vista.aspx
    ;
    hDirectory = CreateFile_(@Directory$, 0, #FILE_SHARE_READ|#FILE_SHARE_WRITE, #Null, #OPEN_EXISTING, #FILE_FLAG_OPEN_REPARSE_POINT | #FILE_FLAG_BACKUP_SEMANTICS, #Null)
    If hDirectory <> #INVALID_HANDLE_VALUE
    
      ; Allocate a buffer for the io query. 1000 bytes should be enough for the real path (in unicode)
      ;
      BufferSize = SizeOf(REPARSE_DATA_BUFFER) + 1000
      *Buffer = AllocateMemory(BufferSize)
      
      If *Buffer
        
        ; Query the directory for reparse point information
        ;
        If DeviceIoControl_(hDirectory, #FSCTL_GET_REPARSE_POINT, #Null, 0, *Buffer, BufferSize, @BytesReturned, #Null) <> 0
        
          ; Check the kind of reparse point (device drivers can create their own tags, so this is important)
          ; The "& $FFFFFFFF" is for 64bit, as the tags are negative when interpreted as quads
          ;
          If *Buffer\ReparseTag & $FFFFFFFF = #IO_REPARSE_TAG_MOUNT_POINT

            ; Read the result. The offset and length are in bytes. PeekS needs length in characters
            ;
            Result$ = PeekS(@*Buffer\MountPointReparseBuffer\PathBuffer[0] + *Buffer\MountPointReparseBuffer\SubstituteNameOffset, *Buffer\MountPointReparseBuffer\SubstituteNameLength / 2, #PB_Unicode)

          ElseIf *Buffer\ReparseTag & $FFFFFFFF = #IO_REPARSE_TAG_SYMLINK
          
            Result$ = PeekS(@*Buffer\SymbolicLinkReparseBuffer\PathBuffer[0] + *Buffer\SymbolicLinkReparseBuffer\SubstituteNameOffset, *Buffer\SymbolicLinkReparseBuffer\SubstituteNameLength / 2, #PB_Unicode)

          EndIf
        
        EndIf     
      
        FreeMemory(*Buffer)
      EndIf
    
      CloseHandle_(hDirectory)
    EndIf
  
  Else
  
    ; It is not a reparse point, so return the original path
    ;
    Result$ = Directory$
    
  EndIf
  
  ; Since the result is a unicode directory name, it can have the "\??\" prefix which allows a length of 32767 characters.
  ;
  If Left(Result$, 4) = "\??\"
    Result$ = Right(Result$, Len(Result$)-4)
  EndIf

  ProcedureReturn Result$
EndProcedure



; ----------------------------------------------------------------------------


Directory$ = "C:\Documents and Settings\"

Debug "Testing: " + Directory$
Debug "Target: " + GetDirectoryTarget(Directory$)

Verfasst: 08.04.2009 03:24
von ts-soft
:allright:

Genau was ich gesucht habe. Hatte eigentlich keine grosse Hoffnung, hier
Hilfe zu finden, aber versuch macht Klug.

Danke und Grüße

Thomas

Verfasst: 08.04.2009 04:04
von ts-soft
freak hat geschrieben:Das ExplorerListGadget zeigt ein leeres Verzeichnis an, nicht weil es dem link nicht folgen kann sondern weil der Prozess nicht die Rechte dazu hat auf "C:\Documents and Settings" direkt zuzugreifen. Mit einem Unterordner wie "C:\Documents and Settings\<Username>" geht es wieder. Der Explorer lässt das browsen des Ordners auch nicht zu, desshalb ist es schon korrekt das das ExplorerListGadget nicht versucht selbst den link aufzulösen.
Schon gelöst für mich :wink:
Ich löse immer nur den ersten auf und öffne das Resultat mit dem richtigen
Namen, schon komme ich weiter, wie in anderen Dateimanagern auch.
Lediglich der Explorer macht es anders, der erzeugt noch ein virtuelles
Verzeichnis Benutzer, das ein bissel irritiert :mrgreen:

Verfasst: 08.04.2009 12:45
von jpd
Hallo ts-soft,

ich habe auch einiger zeit her mit HardLink,Symboliclink,
ADS experimentiert..

der Source ist nicht so richtig übersichtig (total chaotisch)
aber für ein geübter programmierer wie du sollte es kein problem sein :-)

anbei den Link:

Link Manager + source

Ciao
jpd

Verfasst: 08.04.2009 18:35
von ts-soft
jpd hat geschrieben:ich habe auch einiger zeit her mit HardLink,Symboliclink,
ADS experimentiert..

Ciao
jpd
Sehr interessanter Code, werde ich wohl das eine oder anderen von
entwenden müssen :wink:
Die Phase, wo ich auch sowas in mein Projekt einbaue, wird kommen.

:allright:
Thomas

Verfasst: 08.04.2009 21:05
von Andesdaf
oh ja danke, das mit den Pfaden brauchte ich auch mal :allright:

Verfasst: 09.04.2009 11:15
von jpd
ts-soft hat geschrieben:Die Phase, wo ich auch sowas in mein Projekt einbaue, wird kommen.

:allright:
Thomas
das habe ich auch damals gedacht,

aber leider die zeit ist immer so knapp :-(

irgendwann werde ich das auch integrieren können.

aber erstmal wurde der code 4.30 kompatibel gemacht ...

die version ist über den gleichen Link erreichbar.

Ciao
jpd