2022-09-21 22:43:27 +03:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
2023-07-30 18:14:34 +03:00
|
|
|
|
using System.IO;
|
2023-08-06 23:45:49 +03:00
|
|
|
|
using System.Linq;
|
2022-09-21 22:43:27 +03:00
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
|
|
|
|
|
|
namespace PascalABCCompiler.NetHelper
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Will force the application domain to load passed assemblies when requested, while ignoring the assembly
|
|
|
|
|
|
/// versions. Handles <see cref="AppDomain.AssemblyResolve"/> until disposed.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class AssemblyResolveScope : IDisposable
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly AppDomain _appDomain;
|
2023-07-30 18:14:34 +03:00
|
|
|
|
private readonly Dictionary<string, Assembly> _assembliesByName = new Dictionary<string, Assembly>();
|
|
|
|
|
|
private readonly Dictionary<string, Assembly> _assembliesByPath = new Dictionary<string, Assembly>();
|
2022-09-21 22:43:27 +03:00
|
|
|
|
|
2023-08-08 23:57:50 +03:00
|
|
|
|
public ICollection<AssemblyName> CalculateBindingRedirects()
|
|
|
|
|
|
{
|
|
|
|
|
|
var redirectedAssemblies = new HashSet<string>();
|
|
|
|
|
|
foreach (var assembly in _assembliesByName.Values)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var referenceName in assembly.GetReferencedAssemblies())
|
|
|
|
|
|
{
|
|
|
|
|
|
var shortName = referenceName.Name;
|
|
|
|
|
|
if (_assembliesByName.TryGetValue(shortName, out var referenceAssembly)
|
|
|
|
|
|
&& referenceAssembly.GetName().Version != referenceName.Version)
|
|
|
|
|
|
{
|
|
|
|
|
|
redirectedAssemblies.Add(shortName);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-08-06 23:45:49 +03:00
|
|
|
|
|
2023-08-08 23:57:50 +03:00
|
|
|
|
return redirectedAssemblies.Select(a => _assembliesByName[a].GetName()).ToList();
|
|
|
|
|
|
}
|
2023-08-06 23:45:49 +03:00
|
|
|
|
|
2023-07-30 18:14:34 +03:00
|
|
|
|
public AssemblyResolveScope(AppDomain appDomain)
|
2022-09-21 22:43:27 +03:00
|
|
|
|
{
|
|
|
|
|
|
_appDomain = appDomain;
|
|
|
|
|
|
_appDomain.AssemblyResolve += OnAssemblyResolve;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-07-30 18:14:34 +03:00
|
|
|
|
public Assembly PreloadAssembly(string assemblyFilePath)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Convert to normalized form (slashes, name case, possible relative paths):
|
|
|
|
|
|
assemblyFilePath = Path.GetFullPath(assemblyFilePath);
|
|
|
|
|
|
|
|
|
|
|
|
if (_assembliesByPath.TryGetValue(assemblyFilePath, out var assembly))
|
|
|
|
|
|
return assembly;
|
|
|
|
|
|
|
|
|
|
|
|
assembly = NetHelper.LoadAssembly(assemblyFilePath);
|
|
|
|
|
|
_assembliesByName[assembly.GetName().Name] = assembly;
|
|
|
|
|
|
_assembliesByPath[assemblyFilePath] = assembly;
|
|
|
|
|
|
return assembly;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-09-21 22:43:27 +03:00
|
|
|
|
public void Dispose()
|
|
|
|
|
|
{
|
|
|
|
|
|
_appDomain.AssemblyResolve -= OnAssemblyResolve;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-11-12 14:17:38 +03:00
|
|
|
|
static string standartAssemblyPath = Path.GetDirectoryName(System.Reflection.Assembly.GetAssembly(typeof(string)).ManifestModule.FullyQualifiedName);
|
|
|
|
|
|
|
|
|
|
|
|
private string GetStandardAssemblyPath(string name)
|
|
|
|
|
|
{
|
|
|
|
|
|
name = name.Replace("%GAC%\\", "");
|
|
|
|
|
|
string ttn = System.IO.Path.GetFileNameWithoutExtension(name);
|
|
|
|
|
|
string tn = Path.Combine(standartAssemblyPath, name);
|
|
|
|
|
|
if (File.Exists(tn))
|
|
|
|
|
|
return tn;
|
|
|
|
|
|
if (Environment.OSVersion.Platform != PlatformID.Unix && Environment.OSVersion.Platform != PlatformID.MacOSX)
|
|
|
|
|
|
{
|
|
|
|
|
|
string windir = Path.Combine(Environment.GetEnvironmentVariable("windir"), "Microsoft.NET");
|
|
|
|
|
|
tn = windir + @"\assembly\GAC_MSIL\";
|
|
|
|
|
|
tn += ttn + "\\";
|
|
|
|
|
|
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(tn);
|
|
|
|
|
|
if (!di.Exists)
|
|
|
|
|
|
{
|
|
|
|
|
|
tn = windir + @"\assembly\GAC_64\";
|
|
|
|
|
|
tn += ttn + "\\";
|
|
|
|
|
|
di = new System.IO.DirectoryInfo(tn);
|
|
|
|
|
|
if (!di.Exists)
|
|
|
|
|
|
{
|
|
|
|
|
|
tn = windir + @"\assembly\GAC_32\";
|
|
|
|
|
|
tn += ttn + "\\";
|
|
|
|
|
|
di = new System.IO.DirectoryInfo(tn);
|
|
|
|
|
|
if (!di.Exists)
|
|
|
|
|
|
{
|
|
|
|
|
|
tn = windir + @"\assembly\GAC\";
|
|
|
|
|
|
tn += ttn + "\\";
|
|
|
|
|
|
di = new System.IO.DirectoryInfo(tn);
|
|
|
|
|
|
if (!di.Exists)
|
|
|
|
|
|
{
|
|
|
|
|
|
windir = Environment.GetEnvironmentVariable("windir");
|
|
|
|
|
|
tn = windir + @"\assembly\GAC_MSIL\";
|
|
|
|
|
|
tn += ttn + "\\";
|
|
|
|
|
|
di = new System.IO.DirectoryInfo(tn);
|
|
|
|
|
|
if (!di.Exists)
|
|
|
|
|
|
{
|
|
|
|
|
|
tn = windir + @"\assembly\GAC_64\";
|
|
|
|
|
|
tn += ttn + "\\";
|
|
|
|
|
|
di = new System.IO.DirectoryInfo(tn);
|
|
|
|
|
|
if (!di.Exists)
|
|
|
|
|
|
{
|
|
|
|
|
|
tn = windir + @"\assembly\GAC_32\";
|
|
|
|
|
|
tn += ttn + "\\";
|
|
|
|
|
|
di = new System.IO.DirectoryInfo(tn);
|
|
|
|
|
|
if (!di.Exists)
|
|
|
|
|
|
{
|
|
|
|
|
|
tn = windir + @"\assembly\GAC\";
|
|
|
|
|
|
tn += ttn + "\\";
|
|
|
|
|
|
di = new System.IO.DirectoryInfo(tn);
|
|
|
|
|
|
if (!di.Exists)
|
|
|
|
|
|
{
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
System.IO.DirectoryInfo[] diarr = di.GetDirectories();
|
|
|
|
|
|
tn = Path.Combine((diarr[0]).FullName, name);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
string gac_path = "/usr/lib/mono/4.0/gac";
|
|
|
|
|
|
DirectoryInfo di = new DirectoryInfo(Path.Combine(gac_path, ttn));
|
|
|
|
|
|
if (di.Exists)
|
|
|
|
|
|
{
|
|
|
|
|
|
System.IO.DirectoryInfo[] diarr = di.GetDirectories();
|
|
|
|
|
|
tn = Path.Combine((diarr[diarr.Length - 1]).FullName, name);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
return tn;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public List<string> missingAssemblies = new List<string>();
|
|
|
|
|
|
|
2023-08-08 23:57:50 +03:00
|
|
|
|
private Assembly OnAssemblyResolve(object obj, ResolveEventArgs args)
|
2022-09-21 22:43:27 +03:00
|
|
|
|
{
|
Linux/mono ide fixes (#3330)
* Update CodeCompletionActions.cs
Показ Code Completion Window по Ctrl-Space, если курсор находится сразу после точки (как сделано в Win версии). Текущее поведение - после точки ccw не показывать, только если курсор переместить на несколько символов вправо от точки.
* [LIN][IDE] Update TextView.cs - fix GetVisualColumn with empty content
На некоторых дистрибутивах Линукс (Убунту в частности) возникает ошибка времени выполнения IDE,
Описываю действия - открываю сохраненную на диске программу, запускаю, закрываю, копирую текст программы и вставляю в новую вкладку, не сохраняя, запускаю и закрываю -- в логах пошли ошибки.. но такое не всегда происходит, иногда ошибок нет.. но похоже всё таки, что проявляется, когда есть вкладка с не сохраненным кодом. Причем интересно дефолтный каталог не сохраненной программы зависит от того, из какого каталога загружалась "сохраненная" программа, но не некий "по умолчанию".
В результате иследований дошли до функции GetVisualColumn() которая подсчитывает количество столбцов текста в редактируемом документе на основе анализа графического отображения, но в случае если текст отсутствует (Document.Content == ""), на Linux/Mono происходит краш. Предлагаю избегать подсчёта столбцов при отсутствии текста, а сразу возвращать 9 (ноль)
* [LIN][IDE] AssemblyResolveScope.cs -- fix OnAssemblyResolve event
На некоторых дистрибутивах Linux (Ubuntu 22.04 в частности). При загрузке больших исходников, например GraphABC.pas или GraphABCHelper.pas в IDE на Linux/Mono могут перестать открываться новые вкладки редактора IDE и другие элементы интерфейса IDE. Было обнаружено, что в обработчик OnAssemblyResolve в этом случае приходит значиние поля входной переменной args.RequestingAssembly равное null. Это происходит по какой то причине и не всегда. Но если обрабатывать эту ситуацию, то IDE работает стабильно в этом случае.
2025-09-29 18:59:10 +03:00
|
|
|
|
if (args.RequestingAssembly == null) //fix Linux/Mono IDE missworking after loading a huge pas source such as GraphABC.pas or GraphABCHelper.pas
|
|
|
|
|
|
return null;
|
2022-09-21 22:43:27 +03:00
|
|
|
|
var requestedName = new AssemblyName(args.Name);
|
2023-07-30 18:14:34 +03:00
|
|
|
|
if (_assembliesByName.TryGetValue(requestedName.Name, out var assembly))
|
2022-09-21 22:43:27 +03:00
|
|
|
|
return assembly;
|
2023-08-06 23:45:49 +03:00
|
|
|
|
var dir = NetHelper.GetAssemblyDirectory(args.RequestingAssembly);
|
2023-07-30 15:54:49 +03:00
|
|
|
|
if (string.IsNullOrEmpty(dir))
|
|
|
|
|
|
return null;
|
2023-11-12 14:17:38 +03:00
|
|
|
|
string fileName = args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll";
|
|
|
|
|
|
string path = Path.Combine(dir, fileName);
|
|
|
|
|
|
if (!File.Exists(path))
|
|
|
|
|
|
{
|
|
|
|
|
|
string assmPath = GetStandardAssemblyPath(fileName);
|
|
|
|
|
|
if (assmPath != null)
|
|
|
|
|
|
path = assmPath;
|
|
|
|
|
|
}
|
2023-08-06 23:45:49 +03:00
|
|
|
|
if (File.Exists(path))
|
2023-07-30 15:54:49 +03:00
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2023-07-30 18:14:34 +03:00
|
|
|
|
return PreloadAssembly(path);
|
2023-07-30 15:54:49 +03:00
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2022-09-21 22:43:27 +03:00
|
|
|
|
|
2023-07-30 15:54:49 +03:00
|
|
|
|
}
|
2023-11-12 14:17:38 +03:00
|
|
|
|
if (!missingAssemblies.Contains(fileName))
|
|
|
|
|
|
missingAssemblies.Add(fileName);
|
2022-09-21 22:43:27 +03:00
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
Linux/mono ide fixes (#3330)
* Update CodeCompletionActions.cs
Показ Code Completion Window по Ctrl-Space, если курсор находится сразу после точки (как сделано в Win версии). Текущее поведение - после точки ccw не показывать, только если курсор переместить на несколько символов вправо от точки.
* [LIN][IDE] Update TextView.cs - fix GetVisualColumn with empty content
На некоторых дистрибутивах Линукс (Убунту в частности) возникает ошибка времени выполнения IDE,
Описываю действия - открываю сохраненную на диске программу, запускаю, закрываю, копирую текст программы и вставляю в новую вкладку, не сохраняя, запускаю и закрываю -- в логах пошли ошибки.. но такое не всегда происходит, иногда ошибок нет.. но похоже всё таки, что проявляется, когда есть вкладка с не сохраненным кодом. Причем интересно дефолтный каталог не сохраненной программы зависит от того, из какого каталога загружалась "сохраненная" программа, но не некий "по умолчанию".
В результате иследований дошли до функции GetVisualColumn() которая подсчитывает количество столбцов текста в редактируемом документе на основе анализа графического отображения, но в случае если текст отсутствует (Document.Content == ""), на Linux/Mono происходит краш. Предлагаю избегать подсчёта столбцов при отсутствии текста, а сразу возвращать 9 (ноль)
* [LIN][IDE] AssemblyResolveScope.cs -- fix OnAssemblyResolve event
На некоторых дистрибутивах Linux (Ubuntu 22.04 в частности). При загрузке больших исходников, например GraphABC.pas или GraphABCHelper.pas в IDE на Linux/Mono могут перестать открываться новые вкладки редактора IDE и другие элементы интерфейса IDE. Было обнаружено, что в обработчик OnAssemblyResolve в этом случае приходит значиние поля входной переменной args.RequestingAssembly равное null. Это происходит по какой то причине и не всегда. Но если обрабатывать эту ситуацию, то IDE работает стабильно в этом случае.
2025-09-29 18:59:10 +03:00
|
|
|
|
}
|