diff --git a/sources/OpenMcdf.Extensions/OLEProperties/OLEPropertiesContainer.cs b/sources/OpenMcdf.Extensions/OLEProperties/OLEPropertiesContainer.cs index fd962102..e3b66889 100644 --- a/sources/OpenMcdf.Extensions/OLEProperties/OLEPropertiesContainer.cs +++ b/sources/OpenMcdf.Extensions/OLEProperties/OLEPropertiesContainer.cs @@ -154,9 +154,10 @@ internal OLEPropertiesContainer(CFStream cfStream) UserDefinedProperties.properties.Add(op); } - UserDefinedProperties.PropertyNames = (Dictionary)pStream.PropertySet1.Properties + var existingPropertyNames = (Dictionary)pStream.PropertySet1.Properties .Where(p => p.PropertyType == PropertyType.DictionaryProperty).FirstOrDefault()?.Value; + UserDefinedProperties.PropertyNames = existingPropertyNames ?? new Dictionary (); } } diff --git a/sources/Test/OpenMcdf.Extensions.Test/OLEPropertiesExtensionsTest.cs b/sources/Test/OpenMcdf.Extensions.Test/OLEPropertiesExtensionsTest.cs index cb2a5e5b..eaa8b5f8 100644 --- a/sources/Test/OpenMcdf.Extensions.Test/OLEPropertiesExtensionsTest.cs +++ b/sources/Test/OpenMcdf.Extensions.Test/OLEPropertiesExtensionsTest.cs @@ -371,5 +371,74 @@ public void Test_Read_Unicode_User_Properties_Dictionary() Assert.AreEqual("XYZ!\0", propArray[5].Value); } } + + // Test that we can add user properties of various types and then read them back + [TestMethod] + public void Test_DOCUMENT_SUMMARY_INFO_ADD_CUSTOM() + { + if (File.Exists("test_add_user_defined_property.doc")) + File.Delete("test_add_user_defined_property.doc"); + + // Test value for a VT_FILETIME property + DateTime testNow = DateTime.Now; + + // english.presets.doc has a user defined property section, but no properties other than the codepage + using (CompoundFile cf = new CompoundFile("english.presets.doc")) + { + var dsiStream = cf.RootStorage.GetStream("\u0005DocumentSummaryInformation"); + var co = dsiStream.AsOLEPropertiesContainer(); + var userProperties = co.UserDefinedProperties; + + userProperties.PropertyNames[2] = "StringProperty"; + userProperties.PropertyNames[3] = "BooleanProperty"; + userProperties.PropertyNames[4] = "IntegerProperty"; + userProperties.PropertyNames[5] = "DateProperty"; + + var stringProperty = co.NewProperty(VTPropertyType.VT_LPSTR, 2); + stringProperty.Value = "Hello"; + userProperties.AddProperty(stringProperty); + + var booleanProperty = co.NewProperty(VTPropertyType.VT_BOOL, 3); + booleanProperty.Value = true; + userProperties.AddProperty(booleanProperty); + + var integerProperty = co.NewProperty(VTPropertyType.VT_I4, 4); + integerProperty.Value = 3456; + userProperties.AddProperty(integerProperty); + + var timeProperty = co.NewProperty(VTPropertyType.VT_FILETIME, 5); + timeProperty.Value = testNow; + userProperties.AddProperty(timeProperty); + + co.Save(dsiStream); + cf.SaveAs(@"test_add_user_defined_property.doc"); + } + + using (CompoundFile cf = new CompoundFile("test_add_user_defined_property.doc")) + { + var co = cf.RootStorage.GetStream("\u0005DocumentSummaryInformation").AsOLEPropertiesContainer(); + var propArray = co.UserDefinedProperties.Properties.ToArray(); + Assert.AreEqual(propArray.Length, 5); + + // CodePage prop + Assert.AreEqual(1u, propArray[0].PropertyIdentifier); + Assert.AreEqual("0x00000001", propArray[0].PropertyName); + Assert.AreEqual((short)-535, propArray[0].Value); + + // User properties + Assert.AreEqual("StringProperty\0", propArray[1].PropertyName); + Assert.AreEqual("Hello\0", propArray[1].Value); + Assert.AreEqual(VTPropertyType.VT_LPSTR, propArray[1].VTType); + Assert.AreEqual("BooleanProperty\0", propArray[2].PropertyName); + Assert.AreEqual(true, propArray[2].Value); + Assert.AreEqual(VTPropertyType.VT_BOOL, propArray[2].VTType); + Assert.AreEqual("IntegerProperty\0", propArray[3].PropertyName); + Assert.AreEqual(3456, propArray[3].Value); + Assert.AreEqual(VTPropertyType.VT_I4, propArray[3].VTType); + Assert.AreEqual("DateProperty\0", propArray[4].PropertyName); + Assert.AreEqual(testNow, propArray[4].Value); + Assert.AreEqual(VTPropertyType.VT_FILETIME, propArray[4].VTType); + } + } } }