0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AssemblyのCustomAttributeを外側から取得する

0
Posted at

目的

自分自身のCutomAttributeなんかを取得するのは対して苦労はしないんですけど、全くの赤の他人にそこにあるexeファイルからCustomAttributeを引っこ抜かせようという試みです

何の役に立つかって?
……………

実装

いきなりです
一応方針としては、細かいところはブラックボックス化してメインの使い勝手は良いように、的な感じで…

細かいブラックボックス
static class Extensions {
	static public string CustomAttributeValue<T>(this PEReader peReader) {
		if (!peReader.HasMetadata) return null;

		MetadataReader metaDataReader = peReader.GetMetadataReader();
		CustomAttribute attributeHandle = metaDataReader.CustomAttributes
			.Select(h => metaDataReader.GetCustomAttribute(h))
			.FirstOrDefault(ca => IsAttribute<T>(metaDataReader, ca));
		if (attributeHandle.Equals(default(CustomAttribute))) return null;

		BlobReader reader = metaDataReader.GetBlobReader(attributeHandle.Value);
		if (reader.ReadInt16() != 1) return null;

		return reader.ReadSerializedString();



		static bool IsAttribute<T>(MetadataReader metaDataReader, CustomAttribute customAttribute) {
			EntityHandle ctorHandle = customAttribute.Constructor;
			EntityHandle typeHandle = default;
			string typeName = default;

			switch (ctorHandle.Kind) {
				case HandleKind.MemberReference:
				typeHandle = metaDataReader.GetMemberReference((MemberReferenceHandle)ctorHandle).Parent;
				typeName = metaDataReader.GetString(metaDataReader.GetTypeReference((TypeReferenceHandle)typeHandle).Name);
				break;

			case HandleKind.MethodDefinition:
				typeHandle = metaDataReader.GetMethodDefinition((MethodDefinitionHandle)ctorHandle).GetDeclaringType();
				typeName = metaDataReader.GetString(metaDataReader.GetTypeDefinition((TypeDefinitionHandle)typeHandle).Name);
				break;
			}

			return typeName == typeof(T).Name;
		}
	}
}

Extensionです

なので、本体の方はこれを使ってあげれば良いですね

使い勝手の良い方
string assemblyFilePath = @"MyApp.exe";
using (FileStream stream = File.OpenRead(assemblyFilePath))
using (PEReader peReader = new PEReader(stream)) {
	Console.WriteLine(peReader.CustomAttributeValue<GuidAttribute>());
}
Console.ReadKey(true);

こんな感じ
PEReaderをこっちに持たせたのは、CustomAttributeを複数回取得したいかも知れないから
つまりー

複数取得のケース
string assemblyFilePath = @"MyApp.exe";
using (FileStream stream = File.OpenRead(assemblyFilePath))
using (PEReader peReader = new PEReader(stream)) {
	Console.WriteLine(peReader.CustomAttributeValue<GuidAttribute>());
	Console.WriteLine(peReader.CustomAttributeValue<AssemblyFileVersionAttribute>());
	Console.WriteLine(peReader.CustomAttributeValue<AssemblyDescriptionAttribute>());
}
Console.ReadKey(true);

まぁ、若干効率は良い筈

結語

CustomAttributeと云ってもなんでも良いって訳じゃなくてー

  • 文字列として表現されているモノしかダメよ とか
  • PEだからと云ってNativeな奴はCustomAttribute持ってないから抜けない とか
  • エラーチェックがだいぶ甘い とか
  • 上手くCustomAttribute取れないケースは状況によらずnullが返る とか
  • こんなGenericの使い方はどうなん? とか

色々ありますけど、取敢えず(5年越し位に)目的は達成できたのでヨシとします

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?