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  

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

 
			 
			
					
				
				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  
 
Die Phase, wo ich auch sowas in mein Projekt einbaue, wird kommen.
 
 
Thomas
 
			 
			
					
				
				Verfasst: 08.04.2009 21:05
				von Andesdaf
				oh ja danke, das mit den Pfaden brauchte ich auch mal  

 
			 
			
					
				
				Verfasst: 09.04.2009 11:15
				von jpd
				ts-soft hat geschrieben:Die Phase, wo ich auch sowas in mein Projekt einbaue, wird kommen.
 
 
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