51
Script / Go To Link Target v2
« on: August 02, 2017, 03:38:05 »
Hi,
As Mathias added new functions to MultiScript, I updated my script. Now it is much mor concise.
For the hardlink detection I use FindLinks from SysInternals on https://docs.microsoft.com/en-us/sysinternals/downloads/findlinks and put it on mcinstallpath\Tools\Links\Hardlinks
MultiScript:
// Junction, Symlink, MountPoint & Windows Shrtcut -> get link target with MultiComander - reliable
// Hardlink -> get link target with findlinks64.exe - communication via text file
@var $source_focus_path = GetSourceFocusPath();
@var $link_target;
@var $link_targets[];
@var $target_count;
@var $link_found;
@var $link_target_temp_file;
@var $temp_file_content;
@var $link_target_file_size;
@var $findlinks_path;
@var $aux[];
@var $aux2;
@var $n;
@var $mcinstallpath = GetTagValue("${mcinstallpath}");
//0 - Not a link (maybe a hardlink)
//1 - Junction
//2 - Symlink
//3 - MountPoint
@var $link_type = GetFSLinkType($source_focus_path);
if( $link_type == 0 )
{
$link_target = GetWinShortcutTarget($source_focus_path);
//LogAppInfo('shortcut to ' + $link_target);
if( !($link_target == '') )
{
$link_found = 1;
SetClipboardText($link_target);
}
else
{
// Hardlink
$link_target_temp_file = $mcinstallpath ^ 'Tools\Links\Hardlink\link_target.txt';
$findlinks_path = $mcinstallpath ^ 'Tools\Links\Hardlink\FindLinks.exe';
if (FileExists($link_target_temp_file) == 1)
{
$aux = {"NOPROGRESS", "NODIALOG", "SILENT"};
DeleteFile($link_target_temp_file, $aux);
}
LogAppInfo('C:\Windows\System32\wscript.exe "' + $mcinstallpath ^ 'Tools\run_invisible\run_invisible_bat_2_args.vbs" "' + $mcinstallpath ^ '\Tools\Links\Hardlink\bat_findlinks.bat" "' + $source_focus_path + '" "' + $link_target_temp_file + '"');
MC.Run CMD={'C:\Windows\System32\wscript.exe'} ARG={'"' + $mcinstallpath ^ 'Tools\run_invisible\run_invisible_bat_2_args.vbs" "' + $mcinstallpath ^ '\Tools\Links\Hardlink\bat_findlinks.bat" "' + $source_focus_path + '" "' + $link_target_temp_file + '"'} STARTIN={$mcinstallpath ^ '\Tools\Links\Hardlink'} WAIT
// Work on FindLinks' return
if (FileExists($link_target_temp_file) == 1)
{
//Sleep(100);
$link_target_file_size = GetFileSize($link_target_temp_file);
if ($link_target_file_size > 0)
{
$temp_file_content = LoadStringFromFile($link_target_temp_file);
//LogAppInfo($temp_file_content);
// Delete temp file
$aux = {"NOPROGRESS", "NODIALOG", "SILENT"};
DeleteFile($link_target_temp_file, $aux);
// Check/Parse link_target_temp_file content
@var $temp_file_lines[] = StrLines2Array($temp_file_content);
if( StrIsWildMatch($temp_file_lines[0], 'Error*') )
{
MessageBox('Resolve Link', 'Error logged by FindLinks.', 0);
break;
}
else
{
$target_count = arrayCount($temp_file_lines);
// 4 lines -> no links
// 7 lines -> 1 link
// 8 lines -> 2 links
// etc
if( $target_count >= 6 )
{
$link_found = 1;
$link_target = $temp_file_lines[5];
// More than 1 hardlink found
if( $target_count > 6 )
{
// Mount an array with all hardlinks targets, so the user can choose
for( $n=5; $n<$target_count; $n++ )
{
arrayAdd($link_targets, $temp_file_lines[$n]);
}
// Ask user
@var $link_targets_answer = AskOption('Select target', $link_targets, 0);
if ($link_targets_answer == -1)
{
// User cancelled
break;
}
$link_target = $link_targets[$link_targets_answer];
}
}
}
}
else
{
LogAppInfo('Error');
}
}
else
{
MessageBox('Resolve Link', 'Operation timeout', 0);
break;
}
}
}
else
{
// Junction, Symlink or MountPoint
$link_found = 1;
$link_target = GetFSLinkTarget($source_focus_path);
}
// Go to target
if( $link_found )
{
// Clear selected files in the case of the link target being on the same folder
arrayAdd($aux, '');
SetSourceSelected($aux, 1);
SetClipboardText($link_target);
// As Mathias said here http://forum.multicommander.com/forum/index.php/topic,1929.0.html
// "the UI can't be updated until the script is finished since the script is running in the same thread"
// So there's no way to break going to the folder, then selecting the file in 2 operations
// We can do it in 1 go using MC.RunCmd ID="Core.1312" that is CTRL+V with the target path on the clipboard
// Go To Link Target
MC.RunCmd ID="Core.1312"
}
else
{
MessageBox('Resolve Link', 'Not a link.', 0);
}
bat_findlinks.bat file:
FindLinks.exe %1 > %2
As Mathias added new functions to MultiScript, I updated my script. Now it is much mor concise.
For the hardlink detection I use FindLinks from SysInternals on https://docs.microsoft.com/en-us/sysinternals/downloads/findlinks and put it on mcinstallpath\Tools\Links\Hardlinks
MultiScript:
// Junction, Symlink, MountPoint & Windows Shrtcut -> get link target with MultiComander - reliable
// Hardlink -> get link target with findlinks64.exe - communication via text file
@var $source_focus_path = GetSourceFocusPath();
@var $link_target;
@var $link_targets[];
@var $target_count;
@var $link_found;
@var $link_target_temp_file;
@var $temp_file_content;
@var $link_target_file_size;
@var $findlinks_path;
@var $aux[];
@var $aux2;
@var $n;
@var $mcinstallpath = GetTagValue("${mcinstallpath}");
//0 - Not a link (maybe a hardlink)
//1 - Junction
//2 - Symlink
//3 - MountPoint
@var $link_type = GetFSLinkType($source_focus_path);
if( $link_type == 0 )
{
$link_target = GetWinShortcutTarget($source_focus_path);
//LogAppInfo('shortcut to ' + $link_target);
if( !($link_target == '') )
{
$link_found = 1;
SetClipboardText($link_target);
}
else
{
// Hardlink
$link_target_temp_file = $mcinstallpath ^ 'Tools\Links\Hardlink\link_target.txt';
$findlinks_path = $mcinstallpath ^ 'Tools\Links\Hardlink\FindLinks.exe';
if (FileExists($link_target_temp_file) == 1)
{
$aux = {"NOPROGRESS", "NODIALOG", "SILENT"};
DeleteFile($link_target_temp_file, $aux);
}
LogAppInfo('C:\Windows\System32\wscript.exe "' + $mcinstallpath ^ 'Tools\run_invisible\run_invisible_bat_2_args.vbs" "' + $mcinstallpath ^ '\Tools\Links\Hardlink\bat_findlinks.bat" "' + $source_focus_path + '" "' + $link_target_temp_file + '"');
MC.Run CMD={'C:\Windows\System32\wscript.exe'} ARG={'"' + $mcinstallpath ^ 'Tools\run_invisible\run_invisible_bat_2_args.vbs" "' + $mcinstallpath ^ '\Tools\Links\Hardlink\bat_findlinks.bat" "' + $source_focus_path + '" "' + $link_target_temp_file + '"'} STARTIN={$mcinstallpath ^ '\Tools\Links\Hardlink'} WAIT
// Work on FindLinks' return
if (FileExists($link_target_temp_file) == 1)
{
//Sleep(100);
$link_target_file_size = GetFileSize($link_target_temp_file);
if ($link_target_file_size > 0)
{
$temp_file_content = LoadStringFromFile($link_target_temp_file);
//LogAppInfo($temp_file_content);
// Delete temp file
$aux = {"NOPROGRESS", "NODIALOG", "SILENT"};
DeleteFile($link_target_temp_file, $aux);
// Check/Parse link_target_temp_file content
@var $temp_file_lines[] = StrLines2Array($temp_file_content);
if( StrIsWildMatch($temp_file_lines[0], 'Error*') )
{
MessageBox('Resolve Link', 'Error logged by FindLinks.', 0);
break;
}
else
{
$target_count = arrayCount($temp_file_lines);
// 4 lines -> no links
// 7 lines -> 1 link
// 8 lines -> 2 links
// etc
if( $target_count >= 6 )
{
$link_found = 1;
$link_target = $temp_file_lines[5];
// More than 1 hardlink found
if( $target_count > 6 )
{
// Mount an array with all hardlinks targets, so the user can choose
for( $n=5; $n<$target_count; $n++ )
{
arrayAdd($link_targets, $temp_file_lines[$n]);
}
// Ask user
@var $link_targets_answer = AskOption('Select target', $link_targets, 0);
if ($link_targets_answer == -1)
{
// User cancelled
break;
}
$link_target = $link_targets[$link_targets_answer];
}
}
}
}
else
{
LogAppInfo('Error');
}
}
else
{
MessageBox('Resolve Link', 'Operation timeout', 0);
break;
}
}
}
else
{
// Junction, Symlink or MountPoint
$link_found = 1;
$link_target = GetFSLinkTarget($source_focus_path);
}
// Go to target
if( $link_found )
{
// Clear selected files in the case of the link target being on the same folder
arrayAdd($aux, '');
SetSourceSelected($aux, 1);
SetClipboardText($link_target);
// As Mathias said here http://forum.multicommander.com/forum/index.php/topic,1929.0.html
// "the UI can't be updated until the script is finished since the script is running in the same thread"
// So there's no way to break going to the folder, then selecting the file in 2 operations
// We can do it in 1 go using MC.RunCmd ID="Core.1312" that is CTRL+V with the target path on the clipboard
// Go To Link Target
MC.RunCmd ID="Core.1312"
}
else
{
MessageBox('Resolve Link', 'Not a link.', 0);
}
bat_findlinks.bat file:
FindLinks.exe %1 > %2