7

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.
Community
  • 1
  • 1
ken2k
  • 48,145
  • 10
  • 116
  • 176

1 Answers1

6

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.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Thanks a lot for the detailed answer. I edited the original question to add some more background about my understanding of the issue. Please have a look at the edit. – ken2k Nov 27 '13 at 15:10
  • I don't get it, it should be clear by now why you *should* get the warning. What is not clear is why you *didn't* get the warning before. Or maybe you did and you've done something inscrutable that made the build fail on the warning. That doesn't really matter, do what you need to do to not make the build fail. With using a true version number instead of "XXX 1.1.0" as the obvious solution. – Hans Passant Nov 27 '13 at 15:25
  • @HansPassant Yes it's perfectly clear why I should get the warning. What's not clear to me is why the warning suddenly appears _today_, and not in the past two years for the same code (see my question for the changes I made today). Unfortunately I can't fix "XXX 1.1.0" to be "1.1.0" for some reasons (I can't change the way the textual ProductVersion is displayed, because I've shipped a lot of my versions using this pattern). Want I try to achieve is to _hide_ this warning for this very specific assembly, so my build doesn't fail (I configured TFS so reject builds in case of a warning). – ken2k Nov 27 '13 at 15:32
  • I'm just not convinced that the warning didn't appear before, way to easy to miss. These kind of "somebody moved the cheese" questions are impossible to answer accurately when you don't describe the cheese. No idea why I have to guess at what "XXX" looks like for example. Plenty of ways to avoid this problem, it is up to you to decide which one you pick. – Hans Passant Nov 27 '13 at 15:50
  • @HansPassant I'm 100% sure the problem appeared today, thanks to the continuous integration offered by our TFS (the version before changeset YYY doesn't produce the warning, the version after does. The difference is a simple localized resx addition. Removing it removes the warning). I agree it's just not possible to resolve the problem only with the description I made of it, I'll try to build a small reproducible example. – ken2k Nov 27 '13 at 16:28
  • @HansPassant I've created a very small solution sample that demonstrates the issue. Please have a look: 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. – ken2k Nov 27 '13 at 17:06
  • 1
    It in an ALINK warning, the assembly linker. Which does treat satellite assemblies different. I don't have the time to burn on this, you can chase it down yourself by looking at the code. Download SSCLI20 and look at csharp/alink/dll/assembly.cpp, CAssembly::SetOption() method. Or call Microsoft support. – Hans Passant Nov 27 '13 at 17:34
  • 1
    @HansPassant A few last words to conclude: thanks for your diagnostic, I've managed to found the very same issue reported as a bug on [connect.microsoft.com](http://connect.microsoft.com/VisualStudio/feedback/details/611727/localized-build-with-free-form-assemblyinformationalversion-causes-alink-warning-al1053), and unfortunately this won't be fixed. I wish the linker would have given me the right warning code... Google returned me CS1607 for the warning message, but it wasn't CS1607. – ken2k Nov 27 '13 at 18:01