/*

  LibraryLocal - used by the Library.nsh macros
  Get the version of local DLL and TLB files
  Written by Joost Verburg

*/

#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <fstream>

using namespace std;

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{

	// Parse the command line

	string cmdline;
	cmdline = lpCmdLine;

	string mode;
	string filename;
	string filepath;

	int filefound = 0;

	if (cmdline.length() >= 3)
	{

		// Get the full path of the local file

		mode = cmdline.substr(0, 1);
		filename = cmdline.substr(2);

		char buf[MAX_PATH];
		GetCurrentDirectory(MAX_PATH, buf);
		filepath = buf;

		if ((filename.substr(0, 1).compare("\\") != 0) && (filename.substr(1, 1).compare(":") != 0)) {
		  
			// Path is relative

			if (filepath.substr(filepath.length() - 1, 1).compare("\\") != 0)
				filepath.append("\\");
				
			filepath.append(filename);

		} else if (filename.substr(0, 1).compare("\\") == 0) {

			// Path is relative to current root

			if (filepath.substr(1, 1).compare(":") == 0) {

				// Standard path

				filepath = filepath.substr(0, filepath.find('\\'));
				filepath.append(filename);

			} else {

				// UNC path
				
				filepath = filepath.substr(0, filepath.find('\\', filepath.find('\\', 2) + 1));
				filepath.append(filename);
					
			}

		} else {
			
			// Absolute path

			filepath = filename;

		}

		// Validate filename

		WIN32_FIND_DATA wfd;
		HANDLE hFind = FindFirstFile(filepath.c_str(), &wfd);
		
		if (hFind != INVALID_HANDLE_VALUE)
		{
			filefound = 1;
			FindClose(hFind);
		}

	}
	
	int versionfound = 0;
	DWORD low = 0, high = 0;

	if (filefound)
	{

		// Get version
		
		// DLL
		
		if (mode.compare("D") == 0)
		{
			
			DWORD versionsize;
			DWORD temp;
			  
			versionsize = GetFileVersionInfoSize(filepath.c_str(), &temp);
			
			if (versionsize)
			{
			  
				void *buf;
				buf = (void *)GlobalAlloc(GPTR, versionsize);
			  
				if (buf)
				{
				
					UINT uLen;
					VS_FIXEDFILEINFO *pvsf;

					if (GetFileVersionInfo(filepath.c_str(), 0, versionsize, buf) && VerQueryValue(buf, "\\", (void**)&pvsf,&uLen))
					{
						high = pvsf->dwFileVersionMS;
						low = pvsf->dwFileVersionLS;

						versionfound = 1;
					} 

					GlobalFree(buf);

				}

			}

		}

		// TLB
		
		if (mode.compare("T") == 0)
		{
			
			wchar_t ole_filename[1024];
			MultiByteToWideChar(CP_ACP, 0, filepath.c_str(), filepath.length() + 1, ole_filename, 1024);
			
			ITypeLib* typeLib;
			HRESULT hr;
			
			hr = LoadTypeLib(ole_filename, &typeLib);
			
			if (SUCCEEDED(hr)) {

				TLIBATTR* typelibAttr;
				
				hr = typeLib->GetLibAttr(&typelibAttr);

				if (SUCCEEDED(hr)) {
					
					high = typelibAttr->wMajorVerNum;
					low = typelibAttr->wMinorVerNum;
					
					versionfound = 1;

				}

				typeLib->Release();

			}

		}

	}

	// Write the version to an NSIS header file

	char appfile[MAX_PATH];
    GetModuleFileName(0, appfile, MAX_PATH);

	string headerfile;
	headerfile = appfile;
	headerfile = headerfile.substr(0, headerfile.rfind('\\'));
	headerfile.append("\\LibraryLocal.nsh");
	
	ofstream header(headerfile.c_str(), ofstream::out);
	
	if (header)
	{

		if (!filefound)
		{

			header << "!define LIBRARY_VERSION_FILENOTFOUND" << endl;
		}
		else if (!versionfound)
		{
			header << "!define LIBRARY_VERSION_NONE" << endl;
		}
		else
		{
			header << "!define LIBRARY_VERSION_HIGH " << high << endl;
			header << "!define LIBRARY_VERSION_LOW " << low << endl;
		}
	  
	  header.close();

	}

	return 0;

}
