Что нового

[Файловая система] Получить полный путь из ярлыка

glax24

Знающий
Сообщения
72
Репутация
14
Появилась проблема при использование функции FileGetShortcut, если скрипт скомпилирован под х86. При проверке ярлыка на осх64 не правильно возвращался путь, например в ярлыке указан путь C:\Program Files\Internet Explorer\iexplore.exe то функция вернет C:\Program Files(х86)\Internet Explorer\iexplore.exe
Нашел такую функцию на C#
Код:
string GetFullPath(FileInfo file)
	{
	if (file.Extension == ".lnk") {
	using (var fstream = File.Open(file.FullName, FileMode.Open, FileAccess.Read)) {
	using (var reader = new BinaryReader(fstream)) {
	fstream.Seek(0x14, SeekOrigin.Begin);
	var flags = reader.ReadUInt32();
	if (( flags & 0x01 ) == 1) {
	fstream.Seek(0x4c, SeekOrigin.Begin);
	var itemIdLength = reader.ReadUInt16();
	fstream.Seek(itemIdLength, SeekOrigin.Current);
	}
	var start = fstream.Position;
	var length = reader.ReadUInt32();
	fstream.Seek(0x0c, SeekOrigin.Current);
	var offset = reader.ReadUInt32();
	fstream.Seek(start + offset, SeekOrigin.Begin);
	return new string(reader.ReadChars((int)( start + length - fstream.Position )));
	}
	}
	} else
	return file.FullName;
	}

Перевел её на AutoIt, вроде путь возвращается правильный. Может есть уже проверенный способ?
Код:
$sStr = _GetFullPathLnk('Internet Explorer (64-bit).lnk')
MsgBox(4096, "Path", $sStr)

Func _GetFullPathLnk($sPathLnk)

	Local $iflags, $itemIdLength, $istart, $ilength, $ioffset, $ilength_path
	Local $sPathFull, $aPathFull
	Local $hFile = FileOpen($sPathLnk, 16)
	; Проверяет, является ли файл открытым, перед тем как использовать функции чтения/записи в файл
	If $hFile = -1 Then
		MsgBox(4096, "Ошибка", "Невозможно открыть файл.")
		Return SetError(1, 0, '')
	EndIf

	If Not FileSetPos($hFile, 0x14, 0) Then ;begin
		FileClose($hFile)
		Return SetError(2, 0, '')
	EndIf
	$iflags = FileRead($hFile, 4)

	If BitAND($iflags, 0x01) = 1 Then
		If Not FileSetPos($hFile, 0x4c, 0) Then ;begin
			FileClose($hFile)
			Return SetError(2, 0, '')
		EndIf
		$itemIdLength = FileRead($hFile, 2)
		$itemIdLength = Int($itemIdLength)
		If Not FileSetPos($hFile, $itemIdLength, 1) Then ;current
			FileClose($hFile)
			Return SetError(2, 0, '')
		EndIf
	EndIf

	$istart = FileGetPos($hFile)
	$ilength = FileRead($hFile, 4)
	$ilength = Int($ilength)
	If Not FileSetPos($hFile, 0x0c, 1) Then ;current
		FileClose($hFile)
		Return SetError(2, 0, '')
	EndIf
	$ioffset = FileRead($hFile, 4)
	$ioffset = Int($ioffset)
	If Not FileSetPos($hFile, $istart + $ioffset, 0) Then ;begin
		FileClose($hFile)
		Return SetError(2, 0, '')
	EndIf
	$ilength_path = ($istart + $ilength) - FileGetPos($hFile)
	$sPathFull = FileRead($hFile, $ilength_path)
	FileClose($hFile)
	$sPathFull = BinaryToString($sPathFull)
	$aPathFull = StringRegExp($sPathFull, '(.+?\.\w+)', 1)
	If @error Then
		Return SetError(3, 0, '')
	EndIf
	$sPathFull = $aPathFull[0]
	If $sPathFull Then
		Return $sPathFull
	Else
		Return SetError(4, 0, '')
	EndIf
EndFunc   ;==>_GetFullPathLnk
 

erlik

Продвинутый
Сообщения
317
Репутация
84
glax24
Путь возвращается тот, который система считает верным для 32-битного приложения.
Про файловый редирект на 64-битных осях никогда не слышал? На форуме целая тема по нему есть.
Обходится он примерно так:
Код:
#include <WinAPIEx.au3>

If _WinAPI_IsWow64Process() Then _WinAPI_Wow64EnableWow64FsRedirection (0)
FileGetShortcut ("lnk")
If _WinAPI_IsWow64Process() Then _WinAPI_Wow64EnableWow64FsRedirection (1)
 
Автор
G

glax24

Знающий
Сообщения
72
Репутация
14
erlik
Отключение перенаправления в данном случае не помогает. Хотел это в первом сообщение еще написать.
И прежде чем писать про редирект проверил бы сначала.
 

erlik

Продвинутый
Сообщения
317
Репутация
84
glax24
Проверю. У меня его отключение не работало только для функций диалогов выбора файла.
Я думал - это единственное исключение.


Добавлено:
Сообщение автоматически объединено:

glax24
Действительно - путь возвращается перенаправленный. Однако рабочий каталог (даже без отключения редиректа) - правильный. (проверял на ярлыке 64-битного winrar).
Т.о. можно из каталога и имени файла составить правильный путь. Хотя, конечно, это и не очень красиво :smile:
 
Автор
G

glax24

Знающий
Сообщения
72
Репутация
14
erlik
Из рабочего каталога не получится. Посмотри хотябы ярлык ие. Остается только компилить скрипт в х64 или читать из файла.
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
наверное нужно копать сюда http://rsdn.ru/article/winshell/shortcuts.xml
 
Автор
G

glax24

Знающий
Сообщения
72
Репутация
14
В первом сообщение инфа отсюда http://msdn.microsoft.com/en-us/library/dd871375.aspx
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
ну, как я понял, разные методы. по ссылке, которую я дал, используется работа с объектами.
ну а вобщем, метод, который ты указал тоже вполне. все работает
 

erlik

Продвинутый
Сообщения
317
Репутация
84
COM-класс ShellLink скорей всего так же возвращает перенаправленый путь. Я проверил на
Код:
Local $oShell=ObjCreate("WScript.Shell")
Local $WshURLShortcut = $oShell.CreateShortcut("C:\Users\Garry\Desktop\WinRAR.lnk")
Local $sPath=$WshURLShortcut.TargetPath

На отключение редиректа также ноль реакции. Похоже, что нативная функция AutoiIT внутренне реализована на этом же объекте. А ShellLink просто еще одна обертка для приложений.
Так что выходит единственный вариант - прямое чтение внутренней структуры файла ярлыка, что, собственно, в первом посте и реализовано.
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
а если запустить через vbs, то все показывает как надо
Код:
Set WshShell = CreateObject("WScript.Shell")
Set WshShortcut = WshShell.CreateShortcut("Полный путь к ярлыку")
MsgBox WshShortcut.TargetPath
 

erlik

Продвинутый
Сообщения
317
Репутация
84
joiner
а если запустить через vbs, то все показывает как надо
И я даже знаю почему :smile: Wscript.exe запускается 64-битный. А если запустить скрипт вот так:
C:\Windows\SysWOW64\wscript.exe "I:\1.vbs"
то получим опять "C:\Program Files (x86)".
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
да да :smile:
все зависит от исполняемого модуля. ядра
вся эта тема завязалась чтобы подтвердить, что самый первый вариант - самый универсальный. я пошарил по инету. та же информация. так что ТС не стоит заморачиваться. чтение из файла и анализ будет самым надежным способом
а отключение "редиректа" весьма противная вещь..даже трогать его не хочу. все равно : или не работает или работает не всегда
 

Diskretor

Новичок
Сообщения
2
Репутация
0
Отключение переадресации не срабатывает потому, что она применима только к папкам System32 и SysWow64.

А если запустить скрипт вот так: C:\Windows\SysWOW64\wscript.exe "I:\1.vbs" то получим опять "C:\Program Files (x86)".
Здесь все логично. Вы запускаете 32-битный процесс, на который действуют все означенные перенаправления.
 

erlik

Продвинутый
Сообщения
317
Репутация
84
Отключение переадресации не срабатывает потому, что она применима только к папкам System32 и SysWow64.
Гениально. Вы это только что сами придумали? Значит замена пути 'C:\Program Files' на 'C:\Program Files (x86)' как то без участия Windows происходит?
File System Redirector, к вашему сведению, работает в обе стороны (в плане включения\отключения) и касается не только System32 и SysWow64.
А вот почему в некоторых случаях не работает - здесь вам пальцем вам в небо ткнуть не получилось.

Здесь все логично.
А я разве выразил сомнение, что нелогично - Капитан Очевидность?
 
Автор
G

glax24

Знающий
Сообщения
72
Репутация
14
Заменил на другую функцию + предыдущая с исправлениями
Код:
#include-Once
;ReadLnkFile.au3
; версия 1.0 от 17.09.2014
;*****************************************************************************
; Author AU3.............: glax24
;*****************************************************************************
;_FileGetPathTargetLnk_Example()
;_FileGetPathTargetLnk($sPathFullLnk)
;_FileGetPathTargetLnk_($sPathFullLnk);

Func _FileGetPathTargetLnk_Example()
	Local $sPathLnk = 'c:\Users\Public\Desktop\Git Bash.lnk'
	Local $sPathTarget = _FileGetPathTargetLnk($sPathLnk)
	MsgBox(0, 'PathTarget', $sPathTarget & @CRLF & 'error = ' & @error)
EndFunc   ;==>_ReadLnkFile_Example

; #FUNCTION# ;=================================================================================
; Function Name ...: _ReadLnkFile
; AutoIt Version ....: 3.3.8.1+
; Description ........: Get target file (full local path) from a link file (.lnk)
; Syntax................: _ReadLnkFile($sPathFullLnk)
; Parameters........: $sPathFullLnk - Full path and file name of the shortcut.
; Return values:
;					|Success -  Shortcut target path
;					|Failure - @error>0
; Author(s) ..........: glax24
; ============================================================================================
; Имя функции ...: _ReadLnkFile
; Версия AutoIt ..: 3.3.8.1+
; Описание ........: Возвращает полный путь объекта запуска ярлыка (.lnk)
; Синтаксис.......: _ReadLnkFile($sPathFullLnk)
; Параметры.....: $sPathFullLnk - Полный путь и имя файла ярлыка.
; Возвращаемое значение:
;					|Успешно -  Путь к объекту запуска
;					|Неудачно - @error>0
; Автор ..........: glax24
; ============================================================================================
Func _FileGetPathTargetLnk($sPathFullLnk)
	;-------------------------------------------------------------------------
	; Get the .lnk-file content:
	;-------------------------------------------------------------------------

	Local $hFile = FileOpen($sPathFullLnk, 16); rb
	If $hFile = -1 Then
		Return SetError(1, 0, '')
	EndIf
	Local $iSizeFile, $i
	Local $bByte
	Local $bDataFile = FileRead($hFile)
	If @error = 1 Then
		Return SetError(2, 0, '')
	EndIf
	FileClose($hFile)
	$iSizeFile = BinaryLen($bDataFile)

	;-------------------------------------------------------------------------
	; Check the magic value (first byte) and the GUID (16 byte from 5th byte):
	;-------------------------------------------------------------------------
	; The GUID is telling the version of the .lnk-file format. We expect the
	; following GUID (HEX): 01 14 02 00 00 00 00 00 C0 00 00 00 00 00 00 46.
	;-------------------------------------------------------------------------

	If ($iSizeFile < 20) Then
		Return SetError(3, 0, '')
	EndIf

	$bByte = BinaryMid($bDataFile, 1, 1)
	;test the magic value 'L'
	If $bByte <> 0x4C Then
		Return SetError(4, 0, '')
	EndIf

	;test the GUID
	$bByte = BinaryMid($bDataFile, 5, 16)
	If $bByte <> Binary('0x0114020000000000C000000000000046') Then
		Return SetError(5, 0, '')
	EndIf

	;-------------------------------------------------------------------------
	; Get the flags (4 byte from 21st byte):
	;-------------------------------------------------------------------------
	; Check if it points to a file or directory!
	;-------------------------------------------------------------------------
	; Flags (4 byte little endian):
	;        Bit 0 -> has shell item id list
	;        Bit 1 -> points to file or directory
	;        Bit 2 -> has description
	;        Bit 3 -> has relative path
	;        Bit 4 -> has working directory
	;        Bit 5 -> has commandline arguments
	;        Bit 6 -> has custom icon
	;-------------------------------------------------------------------------

	$i = 20
	If $iSizeFile < ($i + 4) Then
		Return SetError(6, 0, '')
	EndIf

	$bByte = BinaryMid($bDataFile, $i + 1, 4)
	Local $idwFlags = Int($bByte); //little endian format
	;ConsoleWrite("$idwFlags = " & $idwFlags & @CRLF)

	Local $bHasShellItemIdList = BitAND($idwFlags, 0x00000001)
	Local $bPointsToFileOrDir = BitAND($idwFlags, 0x00000002)

	;ConsoleWrite("$bHasShellItemIdList = " & $bHasShellItemIdList & @CRLF)
	;ConsoleWrite("$bPointsToFileOrDir = " & $bPointsToFileOrDir & @CRLF)

	If Not $bPointsToFileOrDir Then
		Return SetError(7, 0, '')
	EndIf

	;-------------------------------------------------------------------------
	; Shell item id list (starts at 76 with 2 byte length -> so we can skip):
	;-------------------------------------------------------------------------

	Local $iA = -6
	If $bHasShellItemIdList Then
		$i = 76
		If $iSizeFile < ($i + 2) Then
			Return SetError(8, 0, '')
		EndIf
		$bByte = BinaryMid($bDataFile, $i + 1, 2)
		$iA = Int($bByte); //little endian format
	EndIf

	;ConsoleWrite("$iA = " & $iA & @CRLF)

	;-------------------------------------------------------------------------
	; File location info:
	;-------------------------------------------------------------------------
	; Follows the shell item id list and starts with 4 byte structure length,
	; followed by 4 byte offset for skipping.
	;-------------------------------------------------------------------------

	$i = 78 + 4 + $iA
	If $iSizeFile < ($i + 4) Then
		Return SetError(9, 0, '')
	EndIf

	$bByte = BinaryMid($bDataFile, $i + 1, 4)
	Local $iB = Int($bByte); //little endian format
	;ConsoleWrite("$iB = " & $iB & @CRLF)

	;-------------------------------------------------------------------------
	; Local volume table:
	;-------------------------------------------------------------------------
	; Follows the file location info and starts with 4 byte table length for
	; skipping the actual table and moving to the local path string.
	;-------------------------------------------------------------------------

	$i = 78 + $iA + $iB
	If $iSizeFile < ($i + 4) Then
		Return SetError(10, 0, '')
	EndIf
	$bByte = BinaryMid($bDataFile, $i + 1, 4)
	Local $iC = Int($bByte) ; //little endian format
	;ConsoleWrite("$iC = " & $iC & @CRLF)

	;-------------------------------------------------------------------------
	; Local path string (ending with 0x00):
	;-------------------------------------------------------------------------

	$i = 78 + $iA + $iB + $iC
	If $iSizeFile < ($i + 1) Then
		Return SetError(11, 0, '')
	EndIf

	Local $strLinkedTarget = ''

	While $i < $iSizeFile
		$bByte = BinaryMid($bDataFile, $i + 1, 1)
		If $bByte = 0x00 Then
			ExitLoop
		EndIf
		$strLinkedTarget &= Chr($bByte)
		$i += 1
	WEnd

	;Return if empty:
	If Not $strLinkedTarget Then
		Return SetError(12, 0, '')
	EndIf

	If StringInStr($strLinkedTarget, '~') Then
		Local $strLinkedTargetLong = FileGetLongName($strLinkedTarget)
		If Not @error Then
			$strLinkedTarget = $strLinkedTargetLong
		EndIf
	EndIf

	;ConsoleWrite('strLinkedTarget = [' & $strLinkedTarget & ']' & @CRLF)
	Return $strLinkedTarget
EndFunc   ;==>_ReadLnkFile


Func _FileGetPathTargetLnk_($sPathFullLnk)

	Local $iSizeFile, $iCountByteRead = 0, $bDataFile
	Local $iflags, $itemIdLength, $istart, $ilength, $ioffset, $ilength_path
	Local $sPathFull, $aPathFull, $sPathChar, $bByte
	Local $sPathFullLong
	Local $hFile = FileOpen($sPathFullLnk, 16)
	; Проверяет, является ли файл открытым, перед тем как использовать функции чтения/записи в файл
	If $hFile = -1 Then
		Return SetError(1, 0, '')
	EndIf
	;--------------------------------------------
	$bDataFile = FileRead($hFile)
	If @error = 1 Then
		Return SetError(1, 0, '')
	EndIf
	$iSizeFile = BinaryLen($bDataFile)
	;ConsoleWrite('$iSizeFile ' & $iSizeFile & @CRLF)
	FileSetPos($hFile, 0, 0) ;begin
	;--------------------------------------------

	If Not FileSetPos($hFile, 0x14, 0) Then ;begin
		FileClose($hFile)
		Return SetError(2, 0, '')
	EndIf
	$iCountByteRead += 4
	If $iSizeFile < $iCountByteRead Then
		Return SetError(6, 0, '')
	EndIf
	$iflags = FileRead($hFile, 4)
	If BitAND($iflags, 0x01) = 1 Then
		If Not FileSetPos($hFile, 0x4c, 0) Then ;begin
			FileClose($hFile)
			Return SetError(2, 0, '')
		EndIf
		$iCountByteRead += 2
		If $iSizeFile < $iCountByteRead Then
			Return SetError(6, 0, '')
		EndIf
		$itemIdLength = FileRead($hFile, 2)
		$itemIdLength = Int($itemIdLength)
		If Not FileSetPos($hFile, $itemIdLength, 1) Then ;current
			FileClose($hFile)
			Return SetError(2, 0, '')
		EndIf
	EndIf

	$istart = FileGetPos($hFile)
	$iCountByteRead += 4
	If $iSizeFile < $iCountByteRead Then
		Return SetError(6, 0, '')
	EndIf
	$ilength = FileRead($hFile, 4)

	$ilength = Int($ilength)

	If Not FileSetPos($hFile, 0x0c, 1) Then ;current
		FileClose($hFile)
		Return SetError(2, 0, '')
	EndIf
	$iCountByteRead += 4
	If $iSizeFile < $iCountByteRead Then
		Return SetError(6, 0, '')
	EndIf
	$ioffset = FileRead($hFile, 4)
	$ioffset = Int($ioffset)
	If Not FileSetPos($hFile, $istart + $ioffset, 0) Then ;begin
		FileClose($hFile)
		Return SetError(2, 0, '')
	EndIf

	$ilength_path = Int(($istart + $ilength) - FileGetPos($hFile))
	If $ilength_path < 0 Or Not $ilength_path Or ($iCountByteRead + $ilength_path) > $iSizeFile Then
		Return SetError(3, 0, '')
	EndIf
	$sPathFull = FileRead($hFile, $ilength_path)
	FileClose($hFile)

	For $i = 1 To $ilength_path
		$bByte = BinaryMid($sPathFull, $i, 1)
		If $bByte = 0x00 Then
			ExitLoop
		EndIf
		$sPathChar &= Chr($bByte)
	Next
	$sPathFull = $sPathChar
	;ConsoleWrite('$sPathFull [' & $sPathFull & ']' & @CRLF)
	If StringInStr($sPathFull, '~') Then
		$sPathFullLong = FileGetLongName($sPathFull)
		If Not @error Then
			$sPathFull = $sPathFullLong
		EndIf
	EndIf

	If $sPathFull Then
		Return $sPathFull
	Else
		Return SetError(5, 0, '')
	EndIf
EndFunc   ;==>_GetPathTargetLnk

; Original func _FileGetPathTargetLnk
#cs
	//*****************************************************************************
	// File ..................: ReadLnkFile.cpp
	// Description ...........: Decoder for .lnk files on WINDOWS
	// Author ................: Peter Thoemmes (http://www.notes-about-cpp.com/)
	//-----------------------------------------------------------------------------
	// #                  !!! Disclaimer !!!                                      #
	// # This source code is provided "AS-IS" basis, without any warranties or    #
	// # representations express, implied or statutory; including, without        #
	// # limitation, warranties of quality, performance, non-infringement,        #
	// # merchantability or fitness for a particular purpose. Peter Thoemmes      #
	// # does not warrant that this source code will meet your needs or be free   #
	// # from errors.                                                             #
	//-----------------------------------------------------------------------------
	// Many thanks to Jesse Hager ([email protected]) for reverse engineering
	// the shortcut file format and publishing the document 'The Windows Shortcut
	// File Format'.
	//-----------------------------------------------------------------------------
	// Copyright (c) 2008 Peter Thoemmes, Weinbergstr. 3a, D-54441 Ockfen/Germany
	//*****************************************************************************

	#define WINVER          0x0501
	#define _WIN32_WINNT    0x0501
	#define _WIN32_WINDOWS  0x0501
	#define _WIN32_IE       0x0600


	#include <string>
	#include <vector>
	#include <iostream>
	#include <Windows.h>
	#include <Shlwapi.h>

	#pragma comment(lib, "shlwapi.lib")

	using namespace std;



	string ReadLnkFile(const string&);
	void using_();



	int main(int argc, char *argv[]) {
	if (argc == 1) {
	using_();
	return EXIT_FAILURE;
	}
	string Lnk = (const char*) argv[1];
	string strFullTargetPath = ReadLnkFile(Lnk);
	cout << strFullTargetPath << endl;
	return EXIT_SUCCESS;
	}

	void using_() {
	char pBuffer[256];
	GetModuleFileName(GetModuleHandle(NULL), pBuffer, sizeof(pBuffer) );
	PathStripPath(pBuffer);

	cout << "ReadLnkFile by Peter Thoemmes" << endl << endl;
	cout << "Using: " << pBuffer << " [Shortcut file name (.LNK)]" << endl << endl;
	}

	//-----------------------------------------------------------------------------
	// Get target file (full local path) from a link file (.lnk):
	//-----------------------------------------------------------------------------

	string ReadLnkFile(const string& strFullLinkFileName)
	{
	//-------------------------------------------------------------------------
	// How to read the target's path from a .lnk-file:
	//-------------------------------------------------------------------------
	// Problem:
	//
	//    The COM interface to shell32.dll IShellLink::GetPath() fails!
	//
	// Solution:
	//
	//   We need to parse the file manually. The path can be found like shown
	//   here, if the shell item id list is present. In case it is not present
	//   we have to assume A = -6, but not to parse/decode byte 76 and 77.
	//
	//  +---------------------+-----------------------------------------------+
	//  | Index               | Description                                   |
	//  +---------------------+-----------------------------------------------+
	//  |                   0 | 'L' (magic value)                             |
	//  +---------------------+-----------------------------------------------+
	//  |                 ... | ...                                           |
	//  +---------------------+-----------------------------------------------+
	//  |                  76 | A_0                                           |
	//  +---------------------+-----------------------------------------------+
	//  |                  77 | A_1 (16 bit) [w/o shell item id list: A = -6] |
	//  +---------------------+-----------------------------------------------+
	//  |                 ... | ...                                           |
	//  +---------------------+-----------------------------------------------+
	//  |         78 + 16 + A | B_0                                           |
	//  +---------------------+-----------------------------------------------+
	//  |     78 + 16 + A + 1 | B_1                                           |
	//  +---------------------+-----------------------------------------------+
	//  |     78 + 16 + A + 2 | B_2                                           |
	//  +---------------------+-----------------------------------------------+
	//  |     78 + 16 + A + 3 | B_3 (32 bit)                                  |
	//  +---------------------+-----------------------------------------------+
	//  |                 ... | ...                                           |
	//  +---------------------+-----------------------------------------------+
	//  |          78 + A + B | PATH_STR_0                                    |
	//  +---------------------+-----------------------------------------------+
	//  |      78 + A + B + 1 | PATH_STR_1                                    |
	//  +---------------------+-----------------------------------------------+
	//  |      78 + A + B + 2 | PATH_STR_2                                    |
	//  +---------------------+-----------------------------------------------+
	//  |                 ... | ...                                           |
	//  +---------------------+-----------------------------------------------+
	//  |                 ... | 0x00                                          |
	//  +---------------------+-----------------------------------------------+
	//-------------------------------------------------------------------------

	//-------------------------------------------------------------------------
	// Get the .lnk-file content:
	//-------------------------------------------------------------------------

	FILE* pFile = fopen(strFullLinkFileName.c_str(),"rb");
	if(!pFile)
	return string("");
	vector<unsigned char> vectBuffer;
	unsigned char byte = '?';
	while((byte = (unsigned char) fgetc(pFile)) != (unsigned char) EOF)
	vectBuffer.push_back(byte);
	fclose(pFile);

	//-------------------------------------------------------------------------
	// Check the magic value (first byte) and the GUID (16 byte from 5th byte):
	//-------------------------------------------------------------------------
	// The GUID is telling the version of the .lnk-file format. We expect the
	// following GUID (HEX): 01 14 02 00 00 00 00 00 C0 00 00 00 00 00 00 46.
	//-------------------------------------------------------------------------

	if(vectBuffer.size() < 20)
	return string("");
	if(vectBuffer[0] != (unsigned char) 'L') //test the magic value
	return string("");
	if((vectBuffer[4] != 0x01) || //test the GUID
	(vectBuffer[5] != 0x14) ||
	(vectBuffer[6] != 0x02) ||
	(vectBuffer[7] != 0x00) ||
	(vectBuffer[8] != 0x00) ||
	(vectBuffer[9] != 0x00) ||
	(vectBuffer[10] != 0x00) ||
	(vectBuffer[11] != 0x00) ||
	(vectBuffer[12] != 0xC0) ||
	(vectBuffer[13] != 0x00) ||
	(vectBuffer[14] != 0x00) ||
	(vectBuffer[15] != 0x00) ||
	(vectBuffer[16] != 0x00) ||
	(vectBuffer[17] != 0x00) ||
	(vectBuffer[18] != 0x00) ||
	(vectBuffer[19] != 0x46))
	{
	return string("");
	}

	//-------------------------------------------------------------------------
	// Get the flags (4 byte from 21st byte):
	//-------------------------------------------------------------------------
	// Check if it points to a file or directory!
	//-------------------------------------------------------------------------
	// Flags (4 byte little endian):
	//        Bit 0 -> has shell item id list
	//        Bit 1 -> points to file or directory
	//        Bit 2 -> has description
	//        Bit 3 -> has relative path
	//        Bit 4 -> has working directory
	//        Bit 5 -> has commandline arguments
	//        Bit 6 -> has custom icon
	//-------------------------------------------------------------------------

	unsigned int i = 20;
	if(vectBuffer.size() < (i + 4))
	return string("");
	unsigned int dwFlags = (unsigned int) vectBuffer[i]; //little endian format
	dwFlags |= (((unsigned int) vectBuffer[++i]) << 8);
	dwFlags |= (((unsigned int) vectBuffer[++i]) << 16);
	dwFlags |= (((unsigned int) vectBuffer[++i]) << 24);

	bool bHasShellItemIdList = (dwFlags & 0x00000001) ? true : false;
	bool bPointsToFileOrDir = (dwFlags & 0x00000002) ? true : false;

	if(!bPointsToFileOrDir)
	return string("");

	//-------------------------------------------------------------------------
	// Shell item id list (starts at 76 with 2 byte length -> so we can skip):
	//-------------------------------------------------------------------------

	int A = -6;
	if(bHasShellItemIdList)
	{
	i = 76;
	if(vectBuffer.size() < (i + 2))
	return string("");
	A = (unsigned char) vectBuffer[i]; //little endian format
	A |= (((unsigned char) vectBuffer[++i]) << 8);
	}

	//-------------------------------------------------------------------------
	// File location info:
	//-------------------------------------------------------------------------
	// Follows the shell item id list and starts with 4 byte structure length,
	// followed by 4 byte offset for skipping.
	//-------------------------------------------------------------------------

	i = 78 + 4 + A;
	if(vectBuffer.size() < (i + 4))
	return string("");
	unsigned int B = (unsigned int) vectBuffer[i]; //little endian format
	B |= (((unsigned int) vectBuffer[++i]) << 8);
	B |= (((unsigned int) vectBuffer[++i]) << 16);
	B |= (((unsigned int) vectBuffer[++i]) << 24);

	//-------------------------------------------------------------------------
	// Local volume table:
	//-------------------------------------------------------------------------
	// Follows the file location info and starts with 4 byte table length for
	// skipping the actual table and moving to the local path string.
	//-------------------------------------------------------------------------

	i = 78 + A + B;
	if(vectBuffer.size() < (i + 4))
	return string("");
	unsigned int C = (unsigned int) vectBuffer[i]; //little endian format
	C |= (((unsigned int) vectBuffer[++i]) << 8);
	C |= (((unsigned int) vectBuffer[++i]) << 16);
	C |= (((unsigned int) vectBuffer[++i]) << 24);

	//-------------------------------------------------------------------------
	// Local path string (ending with 0x00):
	//-------------------------------------------------------------------------

	i = 78 + A + B + C;
	if(vectBuffer.size() < (i + 1))
	return string("");

	string strLinkedTarget = "";
	for(;i < vectBuffer.size();++i)
	{
	strLinkedTarget.append(1,(char) vectBuffer[i]);
	if(!vectBuffer[i])
	break;
	}

	//Return if empty:
	if(strLinkedTarget.empty())
	return string("");

	//-------------------------------------------------------------------------
	// Convert the target path into the long format (format without ~):
	//-------------------------------------------------------------------------
	// GetLongPathNameA() fails it the target file doesn't exist!
	//-------------------------------------------------------------------------

	char* szLinkedTargetLongFormat = new char[MAX_PATH + 1];
	if(!szLinkedTargetLongFormat)
	return string("");
	if(!::GetLongPathNameA(
	strLinkedTarget.c_str(),
	szLinkedTargetLongFormat,
	MAX_PATH))
	{
	return strLinkedTarget; //file doesn't exist
	}
	string strLinkedTargetLongFormat(szLinkedTargetLongFormat);
	delete[] szLinkedTargetLongFormat;

	return strLinkedTargetLongFormat;
	}
#ce

; Original func _FileGetPathTargetLnk_
#cs
	string GetFullPath(FileInfo file)
	{
	if (file.Extension == ".lnk") {
	using (var fstream = File.Open(file.FullName, FileMode.Open, FileAccess.Read)) {
	using (var reader = new BinaryReader(fstream)) {
	fstream.Seek(0x14, SeekOrigin.Begin);
	var flags = reader.ReadUInt32();
	if (( flags & 0x01 ) == 1) {
	fstream.Seek(0x4c, SeekOrigin.Begin);
	var itemIdLength = reader.ReadUInt16();
	fstream.Seek(itemIdLength, SeekOrigin.Current);
	}
	var start = fstream.Position;
	var length = reader.ReadUInt32();
	fstream.Seek(0x0c, SeekOrigin.Current);
	var offset = reader.ReadUInt32();
	fstream.Seek(start + offset, SeekOrigin.Begin);
	return new string(reader.ReadChars((int)( start + length - fstream.Position )));
	}
	}
	} else
	return file.FullName;
	}
#ce
 
Верх