Bug 3841 - ImageListStreamer writes incorrect header
Summary: ImageListStreamer writes incorrect header
Alias: None
Product: Class Libraries
Classification: Mono
Component: Windows.Forms ()
Version: 2.10.x
Hardware: PC Windows
: Lowest normal
Target Milestone: Untriaged
Assignee: Bugzilla
Depends on:
Reported: 2012-03-10 06:31 UTC by rick
Modified: 2014-06-19 11:39 UTC (History)
3 users (show)

Tags: mono-community
Is this bug a regression?: ---
Last known good build:

The patch I've applied to my local build to correct the problem (542 bytes, patch)
2012-03-10 06:48 UTC, rick
sample project with ImageList (14.88 KB, application/octet-stream)
2013-05-01 03:29 UTC, Timotheus Pokorra
patch for Mono 3.0.6 tar file (1.23 KB, patch)
2013-05-04 02:23 UTC, Timotheus Pokorra

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description rick 2012-03-10 06:31:32 UTC
static byte [] header = new byte []{ 77, 83, 70, 116, 73, 76, 3, 0 };

The final two bytes -- '3, 0' are the version of the image list data. This is incorrect. The correct version bytes are '1, 1'. Currently, Mono's implementation ignores this version when loading IL data, so there is no problem.

However, comctl32.dll's ImageList_Read() on Windows barfs if this version is invalid, and expects a value of 0x101 (1, 1), which means Microsoft.NET will throw an exception when trying to load a Mono built resources that contain ImageLists.
Comment 1 rick 2012-03-10 06:48:56 UTC
Created attachment 1492 [details]
The patch I've applied to my local build to correct the problem
Comment 2 rick 2012-03-10 08:44:59 UTC
Further research indicates more problems with ImageListStreamer.

The static value that gets written: writer.Write ((ushort) 0x1009);

Are flags (previously noted in source), bits 1-7 indicate the number of bits in the image, in this case, it's 8. This will cause ImageList_Read() to abort out if it does not match the biBitCount*biPlanes.

Since the Bitmap creation that follows will always create a Bitmap with PixelFormat.Format32bppArgb (I believe so anyway), it'd be ideal to change this to 0x1021 (or 0x21 -- I'm not certain what the upper 0x1000 flag is for, yet? It does not appear to be valid).
Comment 3 Miguel de Icaza [MSFT] 2012-03-13 12:22:15 UTC
Would you be so kind to point me to the file format documentation for ImageLists?

Comment 4 rick 2012-03-13 13:59:11 UTC
There isn't any official documentation as far as I can tell, but there has been a good amount of research done by the Wine developers, their implementation can be found here:

Comment 5 Timotheus Pokorra 2013-05-01 03:27:24 UTC
this is the exception that I get, when I compile a sample project with Mono and try to execute it with Microsoft .Net.
I took me a while to find this reported bug on Google, so maybe it is easier to find by others when the stack trace of the exception is included:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: Loading of the ImageList did not succeed.

   at System.Windows.Forms.ImageListStreamer..ctor(SerializationInfo info, StreamingContext context)

   --- End of inner exception stack trace ---

   at System.RuntimeMethodHandle._SerializationInvoke(IRuntimeMethodInfo method, Object target, SignatureStruct& declaringTypeSig, SerializationInfo info, StreamingContext context)

   at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context)

   at System.Runtime.Serialization.ObjectManager.FixupSpecialObject(ObjectHolder holder)

   at System.Runtime.Serialization.ObjectManager.DoFixups()

   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)

   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)

   at System.Resources.ResourceReader.DeserializeObject(Int32 typeIndex)

   at System.Resources.ResourceReader._LoadObjectV2(Int32 pos, ResourceTypeCode& typeCode)

   at System.Resources.ResourceReader.LoadObjectV2(Int32 pos, ResourceTypeCode& typeCode)

   at System.Resources.ResourceReader.LoadObject(Int32 pos, ResourceTypeCode& typeCode)

   at System.Resources.RuntimeResourceSet.GetObject(String key, Boolean ignoreCase, Boolean isString)

   at System.Resources.RuntimeResourceSet.GetObject(String key, Boolean ignoreCase)

   at System.Resources.ResourceManager.GetObject(String name, CultureInfo culture, Boolean wrapUnmanagedMemStream)

   at System.Resources.ResourceManager.GetObject(String name)

   at testimagestream.MainForm.InitializeComponent()

   at testimagestream.MainForm..ctor()
Comment 6 Timotheus Pokorra 2013-05-01 03:29:43 UTC
Created attachment 3902 [details]
sample project with ImageList

compile this with recent Mono, and try to execute the exe file on Windows, with Microsoft.Net. This will show the exception that I posted
Comment 7 Timotheus Pokorra 2013-05-04 02:23:17 UTC
Created attachment 3912 [details]
patch for Mono 3.0.6 tar file

this patch uses the comments from the discussion in this ticket, and works for me. If you compile the test case that I uploaded, it will work now.
Comment 8 Timotheus Pokorra 2014-06-18 10:06:39 UTC
here are the specific lines in the wine source, that deal with the fields in discussion:

ILHEAD struct, with usVersion and flags:

usVersion, in function ImageList_Write():
ilHead.usVersion = 0x101;

and for flags, in function ImageList_Create():
himl->flags     = flags;

There is a call of ImageList_Create: 
himl = ImageList_Create (cx, dib.dsBm.bmHeight, ILC_MASK | color, nImageCount, cGrow);

regarding the flags of ImageList, see 
Image List Creation Flags: http://msdn.microsoft.com/en-us/library/windows/desktop/bb775232(v=vs.85).aspx

The suggested value 0x21 would mean: ILC_MASK | ILC_COLOR32
Comment 9 Timotheus Pokorra 2014-06-19 08:37:12 UTC
this has been merged into master:

I cannot find how to change the status of this issue? probably I have no permissions...