Click here to Skip to main content
Email Password   helpLost your password?

Introduction

Did you ever wish for a way to quickly peek inside a mystery DLL to see who wrote it and what it does? If the DLL has version information built in, you could browse to the DLL file in Windows Explorer and then click through the items in the Version tab of the Properties context menu dialog for the file. That's kind of a nuisance for me, so I wrote this handy program, ShowVer.exe. ShowVer will show you all the version info at once.

The source code for ShowVer will also show you how to traverse the tree of information that a VERSIONINFO resource contains, bypassing the need to use the VerQueryValue Win32 API to retrieve individual strings based on a particular hard-coded key name and language/locale ID that you might be expecting to be present.

ShowVer.exe is a command-line program that displays the complete VERSIONINFO contents of a named file. It works on EXE's and DLL's. It is useful for 3 reasons:

  1. It shows all the version info from a file, in all its languages. It does this by interpreting the raw data structures that compose a VERSIONINFO resource. The Win32 APIs (VerQueryValue) will only show you a value from the VERSIONINFO resource if you ask for it by name.
  2. It allows you to name the file whose information you want to see. Often the file you want to examine resides in the System32 directory, which is crowded and unpleasant to browse through using Windows Explorer.
  3. It is a standalone command-line utility that operates on external files, unlike DLLVersion which is a tool you incorporate into a running process.

The source code to ShowVer demonstrates how to load (using GetFileVersionInfo and GetFileVersionInfoSize), parse and traverse the tree of pseudo-structures that make up a VERSIONINFO resource (VS_VERSIONINFO, String, StringTable, StringFileInfo, Var, VarFileInfo).

It will also display a hex dump of the raw VERSIONINFO resource block if you rebuild it with '#define HDUMP 1'. One interesting observation from the hex dump feature is that GetFileVersionInfo never seems to fill up the whole memory buffer that GetFileVersionInfoSize requests.

Here is sample output from ShowVer.exe:

N:\work\ShowVer\Debug>ShowVer w:\winnt\system32\mshtml.dll
VERSIONINFO for file "w:\winnt\system32\mshtml.dll":  (type:0)
  Signature:       feef04bd
  StrucVersion:    1.0
  FileVersion:     6.0.2600.0
  ProductVersion:  6.0.2600.0
  FileFlagsMask:   0x3f
  FileFlags:       0
  FileOS:          VOS_NT_WINDOWS32
  FileType:        VFT_DLL
  FileDate:        0.0
 LangID: 040904B0
  CompanyName       : Microsoft Corporation
  FileDescription   : Microsoft (R) HTML Viewer
  FileVersion       : 6.00.2600.0000
  InternalName      : MSHTML
  LegalCopyright    : � Microsoft Corporation. All rights reserved.
  OriginalFilename  : MSHTML.DLL
  ProductName       : Microsoft� Windows� Operating System
  ProductVersion    : 6.00.2600.0000
  OleSelfRegister   :
 Translation: 040904b0
You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralResourceLib: same thing in C# with r/w
dB.
13:27 8 Oct '08  
If you're looking for a .NET library to do this, take a look at http://www.codeproject.com/KB/library/ResourceLib.aspx[^], it can both read and write version, string, icon and other resources.


GeneralSee also sigcheck from sysinternals
brofield
8:23 29 Jan '07  
Hi,

There is also the sigcheck utility from sysinternals that gives a summarized view of the file version. Not a complete dump like yours though.
http://www.microsoft.com/technet/sysinternals/FileAndDisk/Sigcheck.mspx

Regards,
Brodie

GeneralRelayer's comment - A fix for this
Anonymous
16:52 29 Sep '05  
The fix to this "problem" is not in the code, but in a setting on your PC. See this article. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/dynamic-link_library_search_order.asp
If you have no such entry, the DEFAULT behavior appears to be INCORRECT in the article. Create the key if it doesnt exist and set its value to 0.
GeneralRe: Relayer's comment - A fix for this
relayer_delirium
17:00 29 Sep '05  
Note that the search order ALWAYS will look for the target in the same directory that ShowVer was launched in ... so make sure its in the path, but isolated from other EXEs and DLLs. So, I solved my own problem ... and apologies to Mr. Peck for inferring that he programmed this badly!

GeneralUnderstanding the code
lstoumbos
6:09 7 Sep '05  
ConfusedI was wondering if someone could into detail for me on whats going on in the code with these 2 functions

#define roundoffs(a,b,r) (((byte*)(b) - (byte*)(a) + ((r)-1)) & ~((r)-1))
#define roundpos(b, a, r) (((byte*)(a))+roundoffs(a,b,r))

and why they are needed.
Any help is greatly appreciated.

Luke
GeneralLoading ALL strings from my stringtable
Alex Evans
16:05 4 May '05  
Hi there

How can I (using VC6 / MFC) load ALL strings from a stringtable, one-by-one, getting the IDS value as well as the actual text, for all strings in my program's stringtable?

Thanks

Alex
Generaldebug assertion failed
Karen Amstutz
12:03 13 Jul '04  

I have a delphi exe that I am running the showver against.
I am getting

Debug Assertion Failed
Expression 1== psfI >wtype

I have tried taking all my debug option out but I still get the error........Any suggetions

Generalincorrect search order
relayer_delirium
16:37 9 Mar '04  
Showver seems to find a file in the path before it finds one in the immediate directory. If for example file X.EXE is in the current directory and in c:\windows\system32, issuing the command "showver x.exe " gives me the version info of the copy in c:\windows\system32. To get the current folder I use "showver .\x.exe" ... but I shouldnt have to. Can this be fixed?
GeneralProblem vc to call VB form dll
chi-yuchan@rocketmail.com
0:26 1 Mar '04  
Hi all,

I have a problem about a VC Gui module to call a VB form module. When I click the button in VC UI to launch the VB form module. It works fine, but it causes problems when I close it.

The error is to trigger Window Auto send message:
VCClient MFC Application has encountered a problem and needs to close. We are sorry for the inconvenience.

=== VB Code ===
=== class clsdll ===
Public Function GetWindow() As Long
Load Form1
GetWindow = Form1.hWnd
'pid = GetCurrentProcessId()
End Function

====Form1 ====
Option Explicit

Dim AllowExit As Boolean

Private Sub cmdQuit_Click()
Unload Me
End Sub


Public Sub Form_Load()
'Download blank page
myWebBrowser.Navigate2 "about:blank"

End Sub




Private Sub Form_Unload(Cancel As Integer)
Unload Me
End Sub

Private Sub myWebBrowser_DocumentComplete(ByVal pDisp As Object, URL As Variant)

'Create HTML document inside WebBrowser control
Dim sHTML As String

sHTML = "

This is some text.

"
sHTML = sHTML & "

And here is a button.

"
sHTML = sHTML & "<BUTTON ID=btnMyButton>"
sHTML = sHTML & "Click this button.</BUTTON>"

myWebBrowser.Document.body.innerHTML = sHTML


End Sub

=== vc code ====
void CVCClientDlg::OnButton1(CWnd* pParent)
{
// TODO: Add your control notification handler code here
HRESULT hresult;
CLSID clsid;

CoInitialize(NULL);
hresult=CLSIDFromProgID(OLESTR("prjdll.clsdll"),&clsid);
_clsdll *t;
hresult=CoCreateInstance(clsid,NULL,CLSCTX_INPROC_SERVER,__uuidof(_clsdll),(LPVOID *) &t);
if(FAILED(hresult))
{
AfxMessageBox("Creation Failed");
return;
}


// _VBServerPtr vb(__uuidof(VBServer));

HWND hWnd,
hWindow=NULL;
DWORD dwID,dwIDWe;

dwIDWe = GetCurrentProcessId();
hWnd = (HWND) t->GetWindow();

while (hWnd != NULL)
{
GetWindowThreadProcessId(hWnd, &dwID);
CWnd pWnd;

pWnd.Attach(hWnd);

pWnd.SetWindowText("Hello World");
pWnd.ShowWindow(SW_SHOW);

pWnd.UpdateWindow();
pWnd.Detach();

if( dwID == dwIDWe )
{
hWindow = hWnd;
AfxMessageBox("pWnd exists...");
break;
}

// hWnd = GetWindow(hWnd, GW_HWNDNEXT);
}


Jeff
GeneralThis is exactly what i want, thanks.
t2di4u
0:27 18 Dec '03  
LaughLaughLaughLaughLaughLaughLaughLaugh
Generaldoes not run in win9X
Hae Moon, Kwon
16:12 25 Mar '03  
Thank you.

But this example is not run in Win9X.

Unicode problem?


GeneralRe: does not run in win9X
Renato Mauro
23:06 14 Apr '03  
I modified the original code as written below. It works on a win98 FIRST edition machine.

As you see, the structures don't have the wType field and use CHAR instead of WCHAR.

Please, note that I don't use the showFIXEDFILEINFO() method: maybe you have to modify something to use it.

Renato Mauro

struct VS_VERSIONINFO_98 {
WORD wLength;
WORD wValueLength;
// WORD wType;
CHAR szKey[1];
WORD Padding1[1];
VS_FIXEDFILEINFO Value;
WORD Padding2[1];
WORD Children[1];
};

struct String_98 {
WORD wLength;
WORD wValueLength;
// WORD wType;
CHAR szKey[1];
WORD Padding[1];
WORD Value[1];
};

struct StringTable_98 {
WORD wLength;
WORD wValueLength;
// WORD wType;
CHAR szKey[1];
WORD Padding[1];
String Children[1];
};

struct StringFileInfo_98 {
WORD wLength;
WORD wValueLength;
// WORD wType;
CHAR szKey[1];
WORD Padding[1];
StringTable Children[1];
};

struct Var_98 {
WORD wLength;
WORD wValueLength;
// WORD wType;
CHAR szKey[1];
WORD Padding[1];
DWORD Value[1];
};

struct VarFileInfo_98 {
WORD wLength;
WORD wValueLength;
// WORD wType;
CHAR szKey[1];
WORD Padding[1];
Var Children[1];
};

bool ShowVer98()
{
bool bRet = FALSE ;
char strExeName[_MAX_PATH] ;
CString sLocal ;
if ( GetModuleFileName( NULL, strExeName, _MAX_PATH ) )
{
DWORD dummy;
DWORD size = GetFileVersionInfoSize/*W*/( strExeName, &dummy ) ;
if (size)
{
void* pVer = _alloca(size);
memset(pVer, 0, size);
if ( GetFileVersionInfo/*W*/( strExeName, 0, size, pVer ) )
{
// Interpret the VS_VERSIONINFO header pseudo-struct
VS_VERSIONINFO_98 * pVS = (VS_VERSIONINFO_98 *)pVer;
#define roundoffs(a,b,r) (((byte*)(b) - (byte*)(a) + ((r)-1)) & ~((r)-1))
#define roundpos(b, a, r) (((byte*)(a))+roundoffs(a,b,r))
// byte* nEndRaw = roundpos((((byte*)pVer) + size), pVer, 4);
// byte* nEndNamed = roundpos((((byte*) pVS) + pVS->wLength), pVS, 4);
// ASSERT(nEndRaw == nEndNamed); // size reported from GetFileVersionInfoSize is much padded for some reason...

// comparazione con stringhe normali
ASSERT(!strcmp(pVS->szKey, "VS_VERSION_INFO"));

byte* pVt = (byte*) &pVS->szKey[strlen(pVS->szKey)+1];
VS_FIXEDFILEINFO* pValue = (VS_FIXEDFILEINFO*) roundpos(pVt, pVS, 4);
if (pVS->wValueLength)
{
// showFIXEDFILEINFO(pValue); // Show the 'Value' element
}
// Iterate over the 'Children' elements of VS_VERSIONINFO (either StringFileInfo or VarFileInfo)
StringFileInfo_98* pSFI = (StringFileInfo_98*) roundpos(((byte*)pValue) + pVS->wValueLength, pValue, 4);
for ( ; ((byte*) pSFI) < (((byte*) pVS) + pVS->wLength); pSFI = (StringFileInfo_98*)roundpos((((byte*) pSFI) + pSFI->wLength), pSFI, 4))
{ // StringFileInfo / VarFileInfo
if ( !strcmp( pSFI->szKey, "StringFileInfo") )
{
// The current child is a StringFileInfo element
ASSERT(!pSFI->wValueLength);
// Iterate through the StringTable elements of StringFileInfo
StringTable_98* pST = (StringTable_98*) roundpos(&pSFI->szKey[strlen(pSFI->szKey)+1], pSFI, 4);
for ( ; ((byte*) pST) < (((byte*) pSFI) + pSFI->wLength); pST = (StringTable_98*)roundpos((((byte*) pST) + pST->wLength), pST, 4))
{
printf(" LangID: %s\n", pST->szKey);
ASSERT(!pST->wValueLength);
// Iterate through the String elements of StringTable
String_98* pS = (String_98*) roundpos(&pST->szKey[strlen(pST->szKey)+1], pST, 4);
for ( ; ((byte*) pS) < (((byte*) pST) + pST->wLength); pS = (String_98*) roundpos((((byte*) pS) + pS->wLength), pS, 4))
{
char* psVal = (char*) roundpos(&pS->szKey[strlen(pS->szKey)+1], pS, 4);
printf(" %-18s: %.*s\n", pS->szKey, pS->wValueLength, psVal); // print :
bRet = TRUE ;
}
}
}
else
{
// The current child is a VarFileInfo element
VarFileInfo_98* pVFI = (VarFileInfo_98*) pSFI;
ASSERT(!strcmp(pVFI->szKey, "VarFileInfo"));
ASSERT(!pVFI->wValueLength);
// Iterate through the Var elements of VarFileInfo (there should be only one, but just in case...)
Var_98* pV = (Var_98*) roundpos(&pVFI->szKey[strlen(pVFI->szKey)+1], pVFI, 4);
for ( ; ((byte*) pV) < (((byte*) pVFI) + pVFI->wLength); pV = (Var_98*)roundpos((((byte*) pV) + pV->wLength), pV, 4))
{
printf(" %s: ", pV->szKey);
// Iterate through the array of pairs of 16-bit language ID values that make up the standard 'Translation' VarFileInfo element.
WORD* pwV = (WORD*) roundpos(&pV->szKey[strlen(pV->szKey)+1], pV, 4);
for (WORD* wpos = pwV ; ((byte*) wpos) < (((byte*) pwV) + pV->wValueLength); wpos+=2)
{
printf("%04x%04x ", (int)*wpos++, (int)(*(wpos+1)));
}
printf("\n");
}
}
}
ASSERT((byte*) pSFI == roundpos((((byte*) pVS) + pVS->wLength), pVS, 4));
//return pValue->dwFileVersionMS; // !!! return major version number
}
} // size
} // GetModuleFileName
return ( bRet ) ;
}


Renato Mauro
GeneralProblems
Mike C
9:17 19 Jun '02  
First off, great handy little utility.

The zip file is missing resource.h, but that's easily worked around.

This program will also crash if used on a program (VB Exe or DLL, for example) because of this line

#490 ASSERT(1 == pSFI->wType); // ?? it just seems to be this way...

Which if commented out, works fine. I think the sample exe distributed is the program compiled in Debug mode.

Thanks!
GeneralRe: Problems
tpeck
18:51 1 Jul '02  
Thanks for the feedback. This reply is delayed because I was just on vacation.

I'll re-post without the reference to resource.h in the ShowVer.rc. My resource.h has nothing in it; I meant to leave it out but I forgot to purge that reference to it.

I'll check out with some VB-generated files too. You're right, I included the Debug executable version because I wanted to see which assert's are valid. I figured most people here would be comfortable rebuilding it. I'm interested in your opinion about this assumption.

Thanks!


Ted Peck
GeneralFile Date in VS_FIXEDFILEINFO
Claudius Mokler
2:24 19 Jun '02  
I have been using version information resources in my applications since a long time ago.

What leaves me baffled are the two members of the VS_FIXEDFILEINFO structure named dwFileDateMS and dwFiledateLS.
Neither did I find a way to generate values for these members by using the resource compiler, nor have I ever seen anything but zero in these members.

The documentation (Platform SDK) states
dwFileDateMS
Specifies the most significant 32 bits of the file's 64-bit binary creation date and time stamp.
dwFileDateLS
Specifies the least significant 32 bits of the file's 64-bit binary creation date and time stamp.

but this does not seem to be the case.

Any clues?
GeneralRe: File Date in VS_FIXEDFILEINFO
tpeck
19:08 1 Jul '02  
In my tests I also saw only zero in these values. I was not able to discover any reference to either setting or reading them in my MSDN CD, other than printing out their values. I suspect this is something Microsoft put in but never supported.

For me it's generally enough to look at the file timestamp, but it would be nice to see the original date/time in the versioninfo data. Unfortunately it would have to be poked in after the link was complete by a separate binary editor in order to match the creation date/time from the linker. Either that or the linker would need to be made aware of Versioninfo resources and poke the time in there itself. This is probably something Microsoft didn't find to be worth the trouble.


Ted Peck
GeneralRe: File Date in VS_FIXEDFILEINFO
casanova_n77
5:22 9 Feb '04  
Hi,
I am not replying to this message in particular, but I could did not know how else to contact you. I was wondering, if there was a way to get something like a file listing functionality added to this utility. I mean if I do a showver.exe *.exe then it should list the file information of all the executables. Do you think this is possible to do in this. I am not too conversant with C++, and hence, I do not know how to work around this problem.
Would be grateful if you can help me with this.
GeneralRe: File Date in VS_FIXEDFILEINFO
DavidCrow
7:03 3 Mar '04  
Just use a for loop in a .bat file. Redirect the output to another file.


"The pointy end goes in the other man." - Antonio Banderas (Zorro, 1998)


Last Updated 19 Jun 2002 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010