Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is warning CS1607 "The version specified for the 'product version' is not in the normal 'major.minor.build.revision' format" generated?

Today I'm getting a The version specified for the 'product version' is not in the normal 'major.minor.build.revision' format warning.

It's related to the use of AssemblyInformationalVersionAttribute.

My assembly attributes are:

[assembly: AssemblyInformationalVersion("XXX 1.1.0")]
[assembly: System.Runtime.InteropServices.ComVisible(false)]

Basically the compiler complains about XXX 1.1.0 that doesn't look like x.y.z.r. From MSDN:

The informational version provides additional version information for an assembly, in string format. It is for informational purposes only and is not used at run time. Although you can specify any text, a warning message appears on compilation if the string is not in the format used by the assembly version number, or if it is in that format but contains wildcard characters. This warning is harmless.

So they say a warning that is harmless can occur. The problem is, it breaks my build. I can't even suppress the CS1607 warning (I tried that at the project level, no effect) as suggested in the following bug http://connect.microsoft.com/VisualStudio/feedback/details/275197/assemblyinformationalversion-should-not-generate-cs1607

Actually, everything was fine (no warning) until I added localized resources to my project. I previously had a MyResources.resx file in the project. I added a localized MyResources.fr.resx file, and this resource is the source of the warning (or at least: if I remove this file from the project, it compiles without warning).

I don't see any link between CS1607 (related to x64 vs x86), AssemblyInformationalVersionAttribute and a localized resource file...

How could I fix my project so I can use XXX 1.1.0 as AssemblyInformationalVersionAttribute without any (even harmless) warning?

I'm not that OK with suppressing the CS1607 warning (that could be useful in case of wrong references), but I didn't even managed to suppress it.

Do note I found it was CS1607 by googling, the compiler never returned the actual warning code.

Also note my project targets .Net 2.0, and moving to .Net 4.0 fixes the issue (but of course I can't do this).

Any explanation is welcome.

PS: CS1607: The version specified for the 'file version' is not in the normal 'major.minor.build.revision' format in .NET is question is not related (not about AssemblyInformationalVersion)


EDIT: Thanks Hans Passant. From your answer, I understand AssemblyInformationalVersion is used to generate the two ProductVersion values available in the Win32 VersionInfo structure.

  • If the AssemblyInformationalVersion attributes is empty, then AssemblyVersion is used instead.
  • If AssemblyInformationalVersion is x.y.z, both ProductVersion values are x.y.z.
  • If AssemblyInformationalVersion is another string, the number value of ProductVersion is not set (0.0.0) and only the textual ProductVersion value is set.

What I do not understand, is why the CS1607 warning is only generated by the compiler under some specific circumstances: in my case only when the project contains localized resx files and targets .Net 2.0.

I used a string in AssemblyInformationalVersion for years without any warning until yesterday, when I added a localized resx to the project.

I'm OK with not having the number ProductVersion value set (as you said, only the textual and human-readable value is important for me), but is there a way to prevent the warning from being raised?


EDIT 2:

I've created a very small solution sample that demonstrates the issue: http://sharesend.com/mb371c3l

  • First compilation: expected CS1607 raised by the compiler.
  • Then remove Logon.aspx.fr.resx and rebuild all: no more warning on my machine, for an unknown reason.
like image 932
ken2k Avatar asked Nov 27 '13 11:11

ken2k


1 Answers

The C# compiler does apply an untrivial conversion to these attributes. It needs to generate the unmanaged resources for the executable. Necessary because Windows doesn't know anything about managed resources or attributes. This is normally done automagically. Like the [AssemblyInformationalAttribute] is auto-converted to generate the Version resource's Product version number. Do note the drastic naming mismatch, not a mistake.

The unmanaged product version is however pretty troublesome. Something you see back in the FileVersionInfo class, the one that lets you read back the unmanaged version resource from an executable file. Note how its ProductVersion property returns a string. But the ProductMajorPart (and minor, build and private) property return an int.

You probably see the friction by now. For some unfathomable reason long lost in the fog of time, the original spec of the Version resource included the Product version twice. Once as a binary number, again as a string. The string can be localized, the probable reason for this duplication. You can also see this back when you look at the resource with the unmanaged resource editor. Use File + Open + File and select the executable file. Double click the Version.1 resource. You'll see the Product version appear twice in this dialog as well. The top one only accepts numbers, the bottom one accepts any string.

Which leaves the C# compiler to up the creek without a paddle, it must convert the attribute string to integers so it can generate the binary number as well. Clearly it cannot just let that go wrong without at least generating a warning. The assertion in the MSDN doc for CS1607 that this is benign is not terribly accurate, you really do end up with a resource that doesn't have the binary product version set. The odds that this ends up causing trouble are however not that great, other programs don't usually read it back and it tends to only be looked at by humans. The "Details" property sheet in Explorer's Properties dialog for the file displays it. The string, not the binary number.

So workarounds you need to contemplate is to just specify a valid version number because it really is a version number. Or to take over generation of the unmanaged resource yourself so you have complete control over the content. Which you do by writing a resource script and compile with rc.exe. And tell the C# compiler about it with Project + Properties, Application tab, select the "Resource file" radio button. Do beware the considerable pain you'll inflict on yourself, you now also have the task to keep the resource script updated and in sync with the managed resources. Particularly painful for satellite assemblies I'd say.

like image 55
Hans Passant Avatar answered Sep 29 '22 09:09

Hans Passant