Visual Studio automatically creates the AssemblyInfo.cs for every project in the Properties directory. Initially the file looks like this:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ASMINFO")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ASMINFO")]
[assembly: AssemblyCopyright("Copyright ©  2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("3b474425-406a-4053-ab89-4cb4aafaf3b1")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version 
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers 
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
You commonly shrink it to only include fields that are needed.
[assembly: AssemblyTitle("Project title.")]
[assembly: AssemblyDescription("Project description.")]
[assembly: AssemblyCompany("My company.")]
[assembly: AssemblyProduct("Product name.")]
[assembly: AssemblyCopyright("Copyright © 2015 My Company Ltd")]
[assembly: AssemblyTrademark("XYZ™")]
[assembly: AssemblyVersion("1.0.*")]
This article is about reading these values from the assembly.

To do this let us start a class. I shall call it AssemblyInfo but if you dislike duplicate file names in the project feel free to call it AssemblyInfoReader.
public class AssemblyInfo
{
    private Assembly _assembly;

    public AssemblyInfo(Assembly assembly) { _assembly = assembly; }
}
The class contains a private assembly reference from which we would like to read the values and a constructor. You can pass it the executing assembly, the calling assembly, etc.
Think about prefixing the function which obtains the assembly reference with the [MethodImpl(MethodImplOptions.NoInlining)] attribute. Otherwise the body of the function might get inlined and return invalid reference.

Now that we have a class we can write functions to help us read the values. For some attributes this is easy as they are already exposed by existing classes. For example the assembly version /note: this is not the same as assembly file version/ can be read like this:
private Version ReadAssemblyVersion()
{
    if (_assembly != null)
        return _assembly.GetName().Version;
    else 
        return null;
}
The version structure will provide you with major version, minor version, build number and revision. Note that when you use "1.0.*" the build number will be equal to the number of days since Jan 1, 2000 local time, and the revision will be equal to the number of seconds since midnight local time, divided by 2. So to annoy the guy /or imaginary guy/ responsible for quality assurance in your company you could actually exploit this to obtain date and time of build.

Reading other values requires a bit of reflection. We must first obtain the correct assembly attribute and then read the correct property value. So here is a function to do just that. Provided attribute type as template parameter T and property name as string it returns property value.
private string ReadCustomAttributeValue<T>(string propertyName)
{
    if (_assembly != null) // Just in case.
    {
        object[] customAttributes = _assembly.GetCustomAttributes(typeof(T), false);
        // Don't try to understand this. :)
        if ((customAttributes != null) && (customAttributes.Length > 0))
            return typeof(T).GetProperty(propertyName).GetValue
                (customAttributes[0], null).ToString();
    }
    return string.Empty;
}
To read company name simply create a new property like this
public string Company { get { return ReadCustomAttributeValue<AssemblyCompanyAttribute>("Company"); } }
Here are one liners to read all values as properties.
public string Company { get { return ReadCustomAttributeValue<AssemblyCompanyAttribute>("Company"); } }
public string Version { get { return ReadAssemblyVersion() != null ? string.Format("{0}.{1}",ReadAssemblyVersion().Major,ReadAssemblyVersion().Minor) : string.Empty; } }
public string Build { get { return ReadAssemblyVersion() != null ? ReadAssemblyVersion().Build.ToString() : string.Empty; } }
public string Revision { get { return ReadAssemblyVersion() != null ? ReadAssemblyVersion().Revision.ToString() : string.Empty; } }
public string Product { get { return ReadCustomAttributeValue<AssemblyProductAttribute>("Product"); } }
public string Copyright { get { return ReadCustomAttributeValue<AssemblyCopyrightAttribute>("Copyright"); } }
public string Title { get { return ReadCustomAttributeValue<AssemblyTitleAttribute>("Title"); } }
public string Description { get { return ReadCustomAttributeValue<AssemblyDescriptionAttribute>("Description"); } }
public string Trademark { get { return ReadCustomAttributeValue<AssemblyTrademarkAttribute>("Trademark"); } }
We're almost done. Let us store some custom values to the assembly. For example: assembly service contact /an email/. The elegant way to do this is to create our own attribute.
[AttributeUsage(AttributeTargets.Assembly)]
public class AssemblyContactAttribute : Attribute
{
    private string _contact;
    public AssemblyContactAttribute() : this(string.Empty) {}
    public AssemblyContactAttribute(string contact) { _contact = contact; }
    public string Contact { get { return _contact; } }
}
Then include it into our AssemblyInfo.cs file.
[assembly: AssemblyTitle("Project title.")]
[assembly: AssemblyDescription("Project description.")]
[assembly: AssemblyCompany("My company.")]
[assembly: AssemblyProduct("Product name.")]
[assembly: AssemblyCopyright("Copyright © 2015 My Company Ltd")]
[assembly: AssemblyTrademark("XYZ™")]
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyContact("support@my-company.com")]
And finally; extend our class with a new property to read this value.
public string Contact { get { return ReadCustomAttributeValue<AssemblyContactAttribute>("Contact"); } }
There. Now we're done.

The issue is to size the picture to fit into given window without distorting it. I found many über complicated solutions on the internet so I ended up writing my own. Here's the algorithm in prose:

Find the factor by which you need to multiply your picture's width and height. Try using outer height / inner height and if the width doesn't fit, use outer width / inner width.
Here's the code fragment.
private float ScaleFactor(Rectangle outer, Rectangle inner)
{
    float factor = (float)outer.Height / (float)inner.Height;
    if ((float)inner.Width * factor > outer.Width) // Switch!
        factor = (float)outer.Width / (float)inner.Width;
    return factor;
}
To fit picture rectangle (pctRect) to window rectangle (wndRect) call it like this
float factor=ScaleFactor(wndRect, pctRect); // Outer, inner
RectangleF resultRect=new RectangleF(0,0,pctRect.Width*factor,pctRect.Height*Factor)

Newer Posts Older Posts Home

Blogger Syntax Highliter