Why doesn’t the Version tab show up for very large files?


If you have a really large file and try to view its properties in Explorer, you may find that the Version tab doesn't appear. What's going on?

The Version tab uses the GetFileVersionInfo family of functions to obtain version information from files. It so happens that the GetFileVersionInfo function works by calling LoadLibraryEx(LOAD_LIBRARY_AS_DATAFILE) and then using functions like FindResource to locate the version resource so it can allocate a buffer to hold the version resource plus additional data to assist in character set translation.

If the file is larger than the available address space in the Explorer process, then the call to LoadLibraryEx will fail due to lack of address space into which to map the image. Library not loaded means no version resource to show you.

When we explained this behavior to a customer, the customer wanted to know the exact file size at which the problem occurs.

There is no single exact file size at which the problem occurs because the amount of available address space is determined by large numbers of factors which cannot be boiled down to a simple description. It depends on the pattern of memory allocation that took place inside Explorer, which shell extensions and DLLs got loaded at what point in time, where they got relocated to, which ones got unloaded relative to others loading, how much memory they allocated and where those allocations ended up.

It's like asking the airline, "I know that the later I make my reservation, the less likely I'm going to get the exact seat I want. What is the cutover point before which I will get a window seat and after which I won't?" There is no specific point in time where "all reservations before this point will definitely get a window seat, and all reservations after this point will definitely not get one." It all depends on the pattern of requests before you make your reservations. Indeed, it's even possible that if you had made your reservation later, you would have gotten that window seat, because somebody who had a window seat called in a cancellation.

One customer apparently didn't understand the unpredictability of the cutover point and asked, "Is there a way to change this limit?"

Comments (40)
  1. acq says:

    Wait, did I understand it correctly, the whole frigging file is mapped into the process' memory only for version info that's certainly only a few kilobytes to be read? Then, no wonder customers can't understand.

  2. John says:

    @acq:  GetFileVersionInfo() dates back to at least Windows 3.1, probably further.  Those were simpler times.

  3. acq says:

    To be more precise, there's this nice Win32 API function called MapViewOfFile with which only some small portion of the large file can be mapped. I'm sorry but I don't understand the necessity to map the whole file except that it was easier to write that code without thinking too much.

  4. Raphael says:

    Well, mapping a file into memory is one of the faster methods of opening large files, so why not?

  5. Jonathan says:

    easier-to-write code + not thinking much ==> win!

    And it it creates an edge case where you can't see the version of a huge file, it's totally worth it IMO.

  6. me2 says:

    Makes you wonder how they get the icon from the resource section, doesn't it?

  7. Joshua says:

    Which is why when I have giant resources, I use my own resource format. Bytes 124-127 point to my custom resource descriptor (These bytes are padding in the MS-DOS stub program). LoadLobraryEx doesn't try to map beyond the end of the PE file, but my data starts after it.

  8. dave says:

    One customer apparently didn't understand the unpredictability of the cutover point and asked, "Is there a way to change this limit?"

    Sure.  Write yourself a plug-in which allocates a large part of the address space and holds onto it forever.  Now your limit is much lower.  Thanks for asking.

  9. Patje says:

    Was this behavior changed in Windows Vista?  If it is, then this might explain a very specific problem I have.

    I always link my application with the /SWAPRUN:NET option, to make sure that if my customer runs the executable over the network, that the whole executable is loaded in memory (just in case the network connection drops out, or the file server is rebooted while the application is running).  However, since Windows Vista, this flag also causes the Windows Explorer to load the whole executable into memory, just to get the version information.

    The end result is that with a folder filled with large (20MB) executables: In Windows versions before Vista, the Explorer immediately showed all icons; Since Windows Vista, you see the icons appearing slowly one by one (about 1 icon every 3 seconds).

  10. xpclient says:

    There is no Version tab. There is a Details tab that omits custom version information strings that the Version tab showed, does not show all of the same information as the Version tab and does not support quickly copying any of the displayed information to the clipboard. The status bar and Details pane also no longer show version information, although fortunately, the Details pane can be made to show version info by tweaking the registry.

  11. John says:

    @xpclient:  Yep, this is one of those seemingly small things that really bugs me about Vista and beyond (especially the inability to copy to clipboard).  Alas the trend seems to be favoring simplification over functionality.

  12. alegr1 says:

    Patje:

    Vista+ Explorer, it finds so many wretched ways to be a sloth… I think it's because underprogrammers are mindlessly executing the marketroids' orders…

  13. Rob says:

    @xpclient – you forget that Raymond writes some/all of these posts well in advance. When this post was written it could've been referencing XP/2003/2003R2.

    That aside, do you ever tire of posting off-topic rants?

  14. jon says:

    Has the bug been fixed where GetFileVersionInfo(Size) left a lock on any file that failed in this manner (too large to be mapped in)?

  15. Mark says:

    In "normal" circumstances, surely this shouldn't happen unless the file is hundreds of megabytes, right?

  16. AC says:

    @Rob

    That aside, do you ever tire of posting off-topic rants?

    Huh?? That's the sole reason for his existence. He even registered for maximum troll impact.

  17. @patje – not sure if you're the same Patrick who asked this question on ServerFault…  serverfault.com/…/performance-problem-in-vista-windows-explorer-if-swaprunnet-is-set-on-an-execu

    Makes sense that LoadLibrary would follow the flags.  

    It's not unreasonable for LoadLibrary to have been used for this purpose back when the resource extraction code was written.  Yes it could be improved upon now – Raymond doesn't write about "why things are perfect and needn't change" after all :)  As a maintainer of an app that first started 9 years ago I can appreciate how reasonable architecture decisions made back then (fortunately they've dated fairly well in my case) can affect things today.

  18. Craig says:

    If you need to load the entire file into memory, then you're doing it wrong. The algorithm needs to be improved.

  19. "Is there a way to change this limit?"

    "Well, use 64bit Windows."

  20. xpclient says:

    @Rob

    How well in advance do you think this post may have been written? Even earlier than 2006?

    @AC

    Offtopic? You must be blind or it's a case of pot calling the kettle black.

  21. Dave says:

    You must be blind or it's a case of pot calling the kettle black.

    Samovar is silver and zavarka pot is also silver. I understand not this saying.

  22. Ooh says:

    @Craig:

    If you need to load the entire file into memory, then you're doing it wrong.

    I fail to see where Raymond wrote that the entire file is loaded into memory, sorry. LoadLibrary does not mean that the entire file is loaded from disk immediately.

  23. asdbsd says:

    @John: "Alas the trend seems to be favoring simplification over functionality."

    Don't worry, they changed it in Windows 8. Functionality and simplicity are equally wrecked now.

  24. voo says:

    @John If you want functionality over simplicity why are you using a GUI instead of the much more versatile and powerful commandline? Sigcheck should do all that stuff just fine. See, problem solved.

  25. Raphael says:

    @Craig:

    The file isn't *loaded* into memory. It's *mapped* into memory. Loading happens on demand.

  26. Neil says:

    I'm surprised that LOAD_LIBRARY_AS_DATAFILE would still go ahead and load all the code segments, seeing as the handle is only useful for Find/LoadResource.

  27. 640k says:

    The same problems must have existed with >16MB files in windows 3.1. Ouch.

    [You mean 16-bit Windows? 16-bit Windows didn't have memory-mapped files! -Raymond]
  28. Neil says:

    I mean map all the code, not load, of course.

  29. John says:

    @voo:  Because the GUI was sufficiently functional until it was changed.  Functionality and simplicity do not have to be mutually exclusive.

  30. Joshua says:

    [You mean 16-bit Windows? 16-bit Windows didn't have memory-mapped files! -Raymond]

    I think it also can't run that big of executable.

  31. 640k says:

    [You mean 16-bit Windows? 16-bit Windows didn't have memory-mapped files! -Raymond]

    Are you saying that perfectly working code was replaced by new code which couldn't load large files?

    [News flash: 16-bit Windows did not contain any code to parse Win32 binaries. -Raymond]
  32. cheong00 says:

    [News flash: 16-bit Windows did not contain any code to parse Win32 binaries. -Raymond]

    Emmm… I think I was able to install Win32s to Win3.1 and run certain Win32 binaries…

    Okay… I know it's a limited library and doesn't likely to provide such feature, and it doesn't come with Win3.1 as well… :X

  33. AndyCadley says:

    The truly shocking thing, highlighted by the commenters here, is just how few developers understand the difference between memory mapping a file and actually fetching any of those bits from disk.

  34. @AndyCadley says:

    I would also claim that this entry hints us that the whole concept of memory-mapped files is somewhat wrong: It gives the developer the impression that they can aviod bufferering and positioned reads/writes by mapping in the file and do simple pointer arithmetic. But as this topic shows, this does not even work flawlessly for things like reading ressources. In many cases, File Mapping seems to be the wrong solution.

  35. Joshua says:

    [News flash: 16-bit Windows did not contain any code to parse Win32 binaries. -Raymond]

    Once Win32s is installed, 16 bit programs such as progman.exe are able to extract icons from 32 bit binaries. I have no idea what is involved except it was not a change to progman.exe. I would indeed wonder if 640k is correct.

    [Plain vanilla Windows 3.1 could not parse Win32 binaries. Or are you saying that Win32s should have been a required component in Windows 3.1? -Raymond]
  36. Joshua says:

    Let's try this again.

    Win32s contains a parser for PE files that is somehow able to load resources from a 32 bit .EXE or .DLL for access by a 16 bit process. As you already stated, Win16 does not have any memory mapping API. Therefore, there exists a kernel routine for extracting resources that does not use memory mapping.

    Since at that time, it was popular to write such code as would compile and run correctly on both Win16 and Win32, there is a decent chance the code in question would run correctly if compiled for Win32. I can't see the code history, but it is plausible the code was adapted from WinNT 3.1's resource parser. If that is the case, than 640k's apparently nonsensical question suddenly makes a lot of sense.

    [The Win32s loader is almost certainly a completely unrelated code base from the standard Windows NT loader, since the underlying kernel services are totally different. (Win32s supports memory-mapped files, and the Win32s loader probably used that underlying functionality. As far as I'm aware, standard resource extraction has always been done by memory-mapping, custom extractors notwithstanding.) -Raymond]
  37. @AndyCadley: yup, it's like they've never heard of virtual memory and a memory hierarchy…

  38. @@AndyCadley: other than the limited address space, I fail to see why memory mapping is not a valid solution?

    If the operating system provides adequate buffering under-the-covers so that performance doesn't suffer, why not do this?  Using simple pointer arithmetic seems a lot simpler than having to deal with your own buffers, calling ReadFile repeatedly, and keeping track of that arithmetic!  Let the kernel handle it all…

    This post originated because of the limited 32-bit address space, which these days is a problem for a lot of applications – not just this one.  (It's starting to feel like the artificial "640k conventional memory" limit from back in the MS-DOS days…)  The best solution is just to switch to 64-bit, rather than engineer over-complicated solutions to fix edge cases like this.

  39. @AndyCadley says:

    @JamesJohnston: I think, 32 bit systems in general (not only Windows) will no die that fast, because of the many "smart" phones, tablets and the whole world of embedded devices.

    Also, as far as I know, even 64 bit Windows does not offer the full 64 bit address range to processes. Also in 64 bit Windows, you have such strange things like Address Space Layout Randomization (spelling?) and lots of heaps, allocated by all sorts of libraries and plug-ins. On the other hand, video files and such are growing larger and larger.

    Also, more than one part of the application can try to map in very large files (for example, multiple Explorer plug-ins). So sometimes in the future, even this huge address space may become fragmented, and the fragments may become too small. Your argument sounds a bit like the infamous "640k is enough for everybody", only at a much higher level.

Comments are closed.

Skip to main content