#include <errno.h>
#include <stdio.h>
#include <windows.h>

void WinErr(const char *Msg)
{
	LPVOID lpMsgBuf;
	DWORD ErrorCode = GetLastError ();
	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
		FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_ALLOCATE_BUFFER,
        NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPTSTR) &lpMsgBuf, 0, NULL);
	printf("%s: Windows error %ld: %s\n", Msg, ErrorCode, lpMsgBuf);
	LocalFree(lpMsgBuf);
}

#define LODWORD(l)   ((DWORD)((DWORDLONG)(l)))

char *fullpath (const char *path)
{
	LPTSTR lpFilePart;
	DWORD nBufferLength = 0;
	LPTSTR lpBuffer = NULL;
	nBufferLength = GetFullPathName (path, 0, lpBuffer, &lpFilePart);
	if (!nBufferLength)
		return path;
	lpBuffer = (LPTSTR) malloc (nBufferLength + 1);
	if (!lpBuffer)
		return path;
	if (GetFullPathName (path, nBufferLength, lpBuffer, &lpFilePart))
		return lpBuffer;
	else {
		free (lpBuffer);
		return path;
	}
}
	
char *searchpath (const char *path, const char *ext)
{
	LPTSTR lpFilePart, lpExt = NULL;
	DWORD nBufferLength = 0;
	LPTSTR lpBuffer = NULL;
	if (!strchr (path, '.'))
		lpExt = ext;
	nBufferLength = SearchPath (NULL, path, lpExt, 0, lpBuffer, &lpFilePart);
	if (!nBufferLength)
		return path;
	lpBuffer = (LPTSTR) malloc (nBufferLength + 1);
	if (!lpBuffer)
		return path;
	if (SearchPath (NULL, path, lpExt, nBufferLength, lpBuffer, &lpFilePart))
		return lpBuffer;
	else {
		free (lpBuffer);
		return path;
	}
}
	
int main (int argc, char **argv)
{
    DWORD dwHandle, dwLen;
	UINT BufLen;
	LPTSTR lpData, lpBuffer, LibName = argv[1];
	VS_FIXEDFILEINFO *pFileInfo;
	
	LibName = fullpath (argv[1]); /* try first the current directory */
	dwLen = GetFileVersionInfoSize (LibName, &dwHandle);
	if (!dwLen) {
		free (LibName);
		LibName = searchpath(argv[1], ".dll");
		dwLen = GetFileVersionInfoSize (LibName, &dwHandle);
	}
	if (!dwLen)	{
		free (LibName);
		LibName = argv[1];
		dwLen = GetFileVersionInfoSize (LibName, &dwHandle);
	}
	printf ("Library:              %s\n", LibName);
	if (!dwLen)	{
		printf ("VersionInfo           not found\n");
		return -1;
	}
	lpData = (LPTSTR) malloc (dwLen);
	if (!lpData) {
		perror ("malloc");
		return -1;
	}
	if (!GetFileVersionInfo (LibName, dwHandle, dwLen, lpData)) {
		free (lpData);
		printf ("VersionInfo:          not found\n");
		return -1;
	}
	if (!VerQueryValue (lpData, "\\", (LPVOID) &pFileInfo, (PUINT) &BufLen)) {
		printf ("VersionInfo:          not found\n");
	}
	else {
		printf ("MajorVersion:         %d\n", HIWORD(pFileInfo->dwFileVersionMS));
		printf ("MinorVersion:         %d\n", LOWORD(pFileInfo->dwFileVersionMS));
		printf ("BuildNumber:          %d\n", HIWORD(pFileInfo->dwFileVersionLS));
		printf ("RevisionNumber (QFE): %d\n", LOWORD(pFileInfo->dwFileVersionLS));
	}
	
	if (!VerQueryValue (lpData, TEXT("\\StringFileInfo\\040904E4\\FileVersion"),
			(LPVOID) &lpBuffer, (PUINT) &BufLen)) {
	    /* language ID 040904E4: U.S. English, char set = Windows, Multilingual */
		printf ("FileVersion:          not found\n");
	}
	else
		printf ("FileVersion:          %s\n", lpBuffer);

	if (!VerQueryValue (lpData, TEXT("\\StringFileInfo\\040904E4\\PrivateBuild"),
			(LPVOID) &lpBuffer, (PUINT) &BufLen)) {
	    /* language ID 040904E4: U.S. English, char set = Windows, Multilingual */
		printf ("PrivateBuild:         not found\n");
	}
	else
		printf ("PrivateBuild:         %s\n", lpBuffer);

	if (!VerQueryValue (lpData, TEXT("\\StringFileInfo\\040904E4\\LibToolFileVersion"),
			(LPVOID) &lpBuffer, (PUINT) &BufLen)) {
	    /* language ID 040904E4: U.S. English, char set = Windows, Multilingual */
		printf ("LibToolFileVersion:   not found\n");
	}
	else
		printf ("LibToolFileVersion:   %s\n", lpBuffer);
	if (!VerQueryValue (lpData, TEXT("\\StringFileInfo\\040904E4\\ProductVersion"),
			(LPVOID) &lpBuffer, (PUINT) &BufLen)) {
	    /* language ID 040904E4: U.S. English, char set = Windows, Multilingual */
		printf ("ProductVersion:       not found\n");
	}
	else
		printf ("ProductVersion:       %s\n", lpBuffer);

	free (lpData);
	return 0;
}