Skip to content

Commit

Permalink
Improve target framework detection
Browse files Browse the repository at this point in the history
Use .NET Core runtime directory for .NET Standard 2.1

Issue: #70
  • Loading branch information
MSDN-WhiteKnight committed Feb 24, 2023
1 parent 75613df commit 06c9125
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 43 deletions.
6 changes: 6 additions & 0 deletions CilView.Core/Common/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ public static bool StringEqualsIgnoreCase(string left, string right)
return String.Equals(left, right, StringComparison.InvariantCultureIgnoreCase);
}

public static bool StringStartsWith(string str, string start)
{
if (str == null) return false;
else return str.StartsWith(start, StringComparison.InvariantCulture);
}

public static bool PathEquals(string left, string right)
{
if (left == null)
Expand Down
121 changes: 78 additions & 43 deletions CilView/FileAssemblySource.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
/* CIL Tools
* Copyright (c) 2020, MSDN.WhiteKnight (https://github.com/MSDN-WhiteKnight)
* Copyright (c) 2023, MSDN.WhiteKnight (https://github.com/MSDN-WhiteKnight)
* License: BSD 2.0 */
using System;
using System.IO;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.InteropServices;
using CilTools.BytecodeAnalysis;
using CilTools.Metadata;
using CilTools.Reflection;
using CilView.FileSystem;
using CilView.Common;
using CilView.FileSystem;

namespace CilView
{
Expand Down Expand Up @@ -54,74 +51,107 @@ private Assembly Rd_AssemblyResolve(object sender, ResolveEventArgs args)
return ret;
}

public FileAssemblySource(string filepath)
static string GetTargetRuntimeDirectory(Assembly ass)
{
AssemblySource.TypeCacheClear();

this._path = Path.GetDirectoryName(filepath);
ObservableCollection<Assembly> ret = new ObservableCollection<Assembly>();

Assembly main=null;
this.rd = new AssemblyReader();
rd.AssemblyResolve += Rd_AssemblyResolve;
main = this.LoadAssembly(filepath);

if (main == null) throw new ApplicationException("Cannot load assembly " + filepath + " due to unknown error!");

ret.Add(main);
this.Assemblies = ret;
this.Types = new ObservableCollection<Type>();
this.Methods = new ObservableCollection<MethodBase>();

//check assembly TargetFramework attribute to determine runtime directory
object[] attrs = main.GetCustomAttributes(false);
object[] attrs = ass.GetCustomAttributes(false);

for (int i = 0; i < attrs.Length; i++)
{
if (!(attrs[i] is ICustomAttribute)) continue;

ICustomAttribute ica = (ICustomAttribute)attrs[i];

if (ica.Constructor.DeclaringType.Name.Equals(
"TargetFrameworkAttribute", StringComparison.InvariantCulture))

if (ica.Constructor == null) continue;

if (ica.Constructor.DeclaringType == null) continue;

if (Utils.StringEquals(ica.Constructor.DeclaringType.Name, "TargetFrameworkAttribute"))
{
string tfm = Encoding.ASCII.GetString(ica.Data);
string tfm = Encoding.ASCII.GetString(ica.Data);
tfm = Utils.GetReadableString(tfm);

if (tfm.Length == 0) break;

//only interested in .NET Core
if (!tfm.Contains(".NETCoreApp")) break;


string[] arr = tfm.Split(
new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries
);

if (arr.Length == 0) break;

string tfmid = arr[0]; //.NETCoreApp,Version=v3.1
if (!tfmid.StartsWith(".NETCoreApp",StringComparison.InvariantCulture)) break;
string tfmid = arr[0];
TargetFrameworkType tfmType = TargetFrameworkType.Unknown;

//parse target framework type
if (tfmid.StartsWith(".NETCoreApp", StringComparison.InvariantCulture))
{
tfmType = TargetFrameworkType.NetCore; //.NETCoreApp,Version=v3.1
}
else if (tfmid.StartsWith(".NETStandard", StringComparison.InvariantCulture))
{
tfmType = TargetFrameworkType.NetStandard; //.NETStandard,Version=v2.1
}
else break; //unknown target framework

int idx=tfmid.IndexOf("Version=");
string version = String.Empty;
//parse target framework version
int idx = tfmid.IndexOf("Version=");
string version = string.Empty;

if (idx > 0)
{
int ver_idx = idx + 9;
if (ver_idx >= tfmid.Length) ver_idx = tfmid.Length - 1;

version = tfmid.Substring(ver_idx);
version = tfmid.Substring(ver_idx);
}

version = "";
string path = RuntimeDir.GetNetCorePath(version);
if (path == null) break;
//find runtime path
string path = null;

if (tfmType == TargetFrameworkType.NetCore)
{
path = RuntimeDir.GetNetCorePath(version);
}
else if (tfmType == TargetFrameworkType.NetStandard && Utils.StringStartsWith(version, "2.1"))
{
//.NET Standard 2.1 does not support .NET Framework, so treat it as .NET Core 3.0
path = RuntimeDir.GetNetCorePath("3.0");
}

//set the runtime path for assembly resolving
this.rd.RuntimeDirectory = path;
break;
if (path != null) return path;
else return string.Empty;
}//end if
}//end for

return string.Empty; //default runtime directory
}

public FileAssemblySource(string filepath)
{
AssemblySource.TypeCacheClear();

this._path = Path.GetDirectoryName(filepath);
ObservableCollection<Assembly> ret = new ObservableCollection<Assembly>();

Assembly main=null;
this.rd = new AssemblyReader();
rd.AssemblyResolve += Rd_AssemblyResolve;
main = this.LoadAssembly(filepath);

if (main == null) throw new ApplicationException("Cannot load assembly " + filepath + " due to unknown error!");

ret.Add(main);
this.Assemblies = ret;
this.Types = new ObservableCollection<Type>();
this.Methods = new ObservableCollection<MethodBase>();

//check assembly TargetFramework attribute to determine runtime directory
string path = GetTargetRuntimeDirectory(main);

if (!string.IsNullOrEmpty(path))
{
this.rd.RuntimeDirectory = path; //set the runtime path for assembly resolving
}
}

public override bool HasProcessInfo
Expand All @@ -146,5 +176,10 @@ public override void Dispose()
this.Assemblies = new ObservableCollection<Assembly>();
this.rd.Dispose();
}

enum TargetFrameworkType
{
Unknown = 0, NetCore = 1, NetStandard = 2
}
}
}

0 comments on commit 06c9125

Please sign in to comment.