diff --git a/Source/ExcelDna.Integration/DnaLibrarySerialization.cs b/Source/ExcelDna.Integration/DnaLibrarySerialization.cs index 8658542b..69f67368 100644 --- a/Source/ExcelDna.Integration/DnaLibrarySerialization.cs +++ b/Source/ExcelDna.Integration/DnaLibrarySerialization.cs @@ -227,6 +227,7 @@ public class XmlSerializationWriterDnaLibrary : System.Xml.Serialization.XmlSeri WriteAttribute(@"LoadFromBytes", @"", System.Xml.XmlConvert.ToString((global::System.Boolean)((global::System.Boolean)o.@LoadFromBytes))); WriteAttribute(@"ExplicitExports", @"", System.Xml.XmlConvert.ToString((global::System.Boolean)((global::System.Boolean)o.@ExplicitExports))); WriteAttribute(@"ExplicitRegistration", @"", System.Xml.XmlConvert.ToString((global::System.Boolean)((global::System.Boolean)o.@ExplicitRegistration))); + WriteAttribute(@"UseVersionAsOutputVersion", @"", System.Xml.XmlConvert.ToString((global::System.Boolean)((global::System.Boolean)o.@UseVersionAsOutputVersion))); WriteEndElement(o); } @@ -651,7 +652,7 @@ public class XmlSerializationReaderDnaLibrary : System.Xml.Serialization.XmlSeri if (isNull) return null; global::ExcelDna.Integration.ExternalLibrary o; o = new global::ExcelDna.Integration.ExternalLibrary(); - bool[] paramsRead = new bool[7]; + bool[] paramsRead = new bool[8]; while (Reader.MoveToNextAttribute()) { if (!paramsRead[0] && ((object) Reader.LocalName == (object)id16_Path && (object) Reader.NamespaceURI == (object)id2_Item)) { o.@Path = Reader.Value; @@ -681,8 +682,12 @@ public class XmlSerializationReaderDnaLibrary : System.Xml.Serialization.XmlSeri o.@ExplicitRegistration = System.Xml.XmlConvert.ToBoolean(Reader.Value); paramsRead[6] = true; } + else if (!paramsRead[7] && ((object) Reader.LocalName == (object)id25_UseVersionAsOutputVersion && (object) Reader.NamespaceURI == (object) id2_Item)) { + o.@UseVersionAsOutputVersion = System.Xml.XmlConvert.ToBoolean(Reader.Value); + paramsRead[7] = true; + } else if (!IsXmlnsAttribute(Reader.Name)) { - UnknownNode((object)o, @":Path, :TypeLibPath, :ComServer, :Pack, :LoadFromBytes, :ExplicitExports, :ExplicitRegistration"); + UnknownNode((object)o, @":Path, :TypeLibPath, :ComServer, :Pack, :LoadFromBytes, :ExplicitExports, :ExplicitRegistration, :UseVersionAsOutputVersion"); } } Reader.MoveToElement(); @@ -735,6 +740,7 @@ public class XmlSerializationReaderDnaLibrary : System.Xml.Serialization.XmlSeri string id4_RuntimeVersion; string id8_CompilerVersion; string id21_ComServer; + string id25_UseVersionAsOutputVersion; protected override void InitIDs() { id2_Item = Reader.NameTable.Add(@""); @@ -761,6 +767,7 @@ public class XmlSerializationReaderDnaLibrary : System.Xml.Serialization.XmlSeri id4_RuntimeVersion = Reader.NameTable.Add(@"RuntimeVersion"); id8_CompilerVersion = Reader.NameTable.Add(@"CompilerVersion"); id21_ComServer = Reader.NameTable.Add(@"ComServer"); + id25_UseVersionAsOutputVersion = Reader.NameTable.Add(@"UseVersionAsOutputVersion"); } } diff --git a/Source/ExcelDna.Integration/ExternalLibrary.cs b/Source/ExcelDna.Integration/ExternalLibrary.cs index 9d27bf15..14d0d8d7 100644 --- a/Source/ExcelDna.Integration/ExternalLibrary.cs +++ b/Source/ExcelDna.Integration/ExternalLibrary.cs @@ -76,6 +76,14 @@ public bool ExplicitRegistration set { _ExplicitRegistration = value; } } + private bool _UseVersionAsOutputVersion = false; + [XmlAttribute] + public bool UseVersionAsOutputVersion + { + get { return _UseVersionAsOutputVersion; } + set { _UseVersionAsOutputVersion = value; } + } + internal List GetAssemblies(string pathResolveRoot, DnaLibrary dnaLibrary) { List list = new List(); diff --git a/Source/ExcelDnaPack/PackProgram.cs b/Source/ExcelDnaPack/PackProgram.cs index 259040ab..524af9a9 100644 --- a/Source/ExcelDnaPack/PackProgram.cs +++ b/Source/ExcelDnaPack/PackProgram.cs @@ -236,11 +236,12 @@ static byte[] PackDnaLibrary(byte[] dnaContent, string dnaDirectory, ResourceHel } if (dna.ExternalLibraries != null) { + bool copiedVersion = false; foreach (ExternalLibrary ext in dna.ExternalLibraries) { + string path = dna.ResolvePath(ext.Path); if (ext.Pack) { - string path = dna.ResolvePath(ext.Path); Console.WriteLine(" ~~> ExternalLibrary path {0} resolved to {1}.", ext.Path, path); if (Path.GetExtension(path).Equals(".DNA", StringComparison.OrdinalIgnoreCase)) { @@ -292,7 +293,23 @@ static byte[] PackDnaLibrary(byte[] dnaContent, string dnaDirectory, ResourceHel } } } - + if (ext.UseVersionAsOutputVersion) + { + if (copiedVersion) + { + Console.WriteLine(" ~~> Assembly version already copied from previous ExternalLibrary; ignoring 'UseVersionAsOutputVersion' attribute."); + continue; + } + try + { + ru.CopyFileVersion(path); + copiedVersion = true; + } + catch (Exception e) + { + Console.WriteLine(" ~~> Error copying version to output version: {0}", e.Message); + } + } } } // Collect the list of all the references. diff --git a/Source/ExcelDnaPack/ResourceHelper.cs b/Source/ExcelDnaPack/ResourceHelper.cs index aad3dace..1e5f14d2 100644 --- a/Source/ExcelDnaPack/ResourceHelper.cs +++ b/Source/ExcelDnaPack/ResourceHelper.cs @@ -57,6 +57,28 @@ internal enum TypeName IntPtr lpData, uint cbData); + // This overload provides the resource type and name conversions that would be done by MAKEINTRESOURCE + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool UpdateResource( + IntPtr hUpdate, + uint lpType, + uint lpName, + ushort wLanguage, + IntPtr lpData, + uint cbData); + + [DllImport("version.dll", SetLastError = true)] + private static extern uint GetFileVersionInfoSize( + string lptstrFilename, + out uint lpdwHandle); + + [DllImport("version.dll", SetLastError = true)] + private static extern bool GetFileVersionInfo( + string lptstrFilename, + uint dwHandle, + uint dwLen, + byte[] lpData); + [DllImport("kernel32.dll")] private static extern uint GetLastError(); @@ -186,6 +208,48 @@ public void RemoveResource(string typeName, string name) } } + public void CopyFileVersion(string fromFile) + { + uint ignored; + uint versionSize = ResourceHelper.GetFileVersionInfoSize(fromFile, out ignored); + if (versionSize == 0) + { + throw new Win32Exception(); + } + + byte[] versionBuf = new byte[versionSize]; + bool result = ResourceHelper.GetFileVersionInfo(fromFile, ignored, versionSize, versionBuf); + if (!result) + { + throw new Win32Exception(); + } + + GCHandle versionBufHandle = GCHandle.Alloc(versionBuf, GCHandleType.Pinned); + try + { + lock (lockResource) + { + uint versionResourceType = 16; + uint versionResourceId = 1; + result = ResourceHelper.UpdateResource( + _hUpdate, + versionResourceType, + versionResourceId, + localeNeutral, + versionBufHandle.AddrOfPinnedObject(), + versionSize); + if (!result) + { + throw new Win32Exception(); + } + } + } + finally + { + versionBufHandle.Free(); + } + } + public void EndUpdate() { EndUpdate(false);