diff --git a/src/Squirrel/NativeMethods.cs b/src/Squirrel/NativeMethods.cs
new file mode 100644
index 00000000..611f4d3b
--- /dev/null
+++ b/src/Squirrel/NativeMethods.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Squirrel
+{
+ static class NativeMethods
+ {
+ [DllImport("version.dll", SetLastError = true)]
+ public static extern bool GetFileVersionInfo(
+ string lpszFileName,
+ IntPtr dwHandleIgnored,
+ int dwLen,
+ [MarshalAs(UnmanagedType.LPArray)] byte[] lpData);
+
+ [DllImport("version.dll", SetLastError = true)]
+ public static extern int GetFileVersionInfoSize(
+ string lpszFileName,
+ IntPtr dwHandleIgnored);
+
+ [DllImport("version.dll")]
+ public static extern bool VerQueryValue(byte[] pBlock, string pSubBlock, out IntPtr pValue, out int len);
+ }
+}
diff --git a/src/Squirrel/Squirrel.csproj b/src/Squirrel/Squirrel.csproj
index 1adfd660..48ab0205 100644
--- a/src/Squirrel/Squirrel.csproj
+++ b/src/Squirrel/Squirrel.csproj
@@ -71,12 +71,14 @@
+
+
diff --git a/src/Squirrel/SquirrelAwareExecutableDetector.cs b/src/Squirrel/SquirrelAwareExecutableDetector.cs
new file mode 100644
index 00000000..a99d8d22
--- /dev/null
+++ b/src/Squirrel/SquirrelAwareExecutableDetector.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Squirrel
+{
+ static class SquirrelAwareExecutableDetector
+ {
+ public static int? GetPESquirrelAwareVersion(string executable)
+ {
+ if (!File.Exists(executable)) return null;
+ var fullname = Path.GetFullPath(executable);
+
+ return GetAssemblySquirrelAwareVersion(fullname) ?? GetVersionBlockSquirrelAwareValue(fullname);
+ }
+
+ static int? GetAssemblySquirrelAwareVersion(string executable)
+ {
+ try
+ {
+ var assembly = Assembly.ReflectionOnlyLoadFrom(executable);
+ var attrs = assembly.GetCustomAttributesData();
+ var attribute = attrs.FirstOrDefault(x =>
+ {
+ if (x.AttributeType != typeof(AssemblyMetadataAttribute)) return false;
+ if (x.ConstructorArguments.Count != 2) return false;
+ return x.ConstructorArguments[0].Value.ToString() == "SquirrelAwareVersion";
+ });
+
+ if (attribute == null) return null;
+
+ int result;
+ if (!Int32.TryParse(attribute.ConstructorArguments[1].Value.ToString(), NumberStyles.Integer, CultureInfo.CurrentCulture, out result))
+ {
+ return null;
+ }
+
+ return result;
+ }
+ catch (FileLoadException) { return null; }
+ catch (BadImageFormatException) { return null; }
+ }
+
+ static int? GetVersionBlockSquirrelAwareValue(string executable)
+ {
+ int size = NativeMethods.GetFileVersionInfoSize(executable, IntPtr.Zero);
+
+ // Nice try, buffer overflow
+ if (size <= 0 || size > 4096) return null;
+
+ var buf = new byte[size];
+ if (!NativeMethods.GetFileVersionInfo(executable, IntPtr.Zero, size, buf)) return null;
+
+ IntPtr result; int resultSize;
+ if (!NativeMethods.VerQueryValue(buf, "\\StringFileInfo\\040904B0\\SquirrelAwareVersion", out result, out resultSize))
+ {
+ return null;
+ }
+
+ int ret;
+ string resultData = Marshal.PtrToStringAnsi(result, resultSize-1 /* Subtract one for null terminator */);
+ if (!Int32.TryParse(resultData, NumberStyles.Integer, CultureInfo.CurrentCulture, out ret)) return null;
+
+ return ret;
+ }
+ }
+}