Solved

Application's version, copyright, etc

Posted on 1998-05-18
16
321 Views
Last Modified: 2013-11-20
Is it possible to use the version resources in VC++ to insert the likes of the application's version, copyright, name, etc into a string? Or, must one declare that elsewhere? The goal is to display that and keep only one version control.

If it is possible, how?

Thanks for your input in advance!

RJV
0
Comment
Question by:RJV
  • 7
  • 5
  • 4
16 Comments
 
LVL 2

Accepted Solution

by:
SamratAshok earned 100 total points
ID: 1312415
This is exactly the same problem I asked here sometime ago.

I initially decided to use sourcesafe to automatically up the version numbers, but later on came to something very simple.

This is the logic

  Basically what you want to do is write a small little console app that will read your .RC file by doing some straight forward text parsing, figure out the last digit and increment
the last digit and add timestamps. I also add the same basic information with the
source safe keywords in one of my .cpp files

you then run this app as a custom build step so your .rc version info gets updated everytime

For Major releases, I still go and change the major digits myself.

Then I have a wrapper class around the VersionINFO structure and associated
function which I use in the about box.

If you have any further queries lemme know.



0
 

Author Comment

by:RJV
ID: 1312416
Thanks, Samra.

I gather from your explanation that you update the version info according to the build, or else the build. What I'd like to do is ideally use what is in the resource file in the likes of the splash screen, the about screen. Thus I needn't think of updating more than one location.

How to do that -- unless, that is, I didn't understand your explanation.

RJV

0
 
LVL 2

Expert Comment

by:SamratAshok
ID: 1312417
Thats precisely what I described. I want the version number to be updated in the RC file.
but I dont want to do it manually. This is very the console application comes in. It parses
.RC file as a regular text file, and increments the necessary digits in the .RC file.
Compiler than recompiles it, causing updated versioninfo to be stamped into your project.

I used to update it everytime, but you could easily make it dependant on some key file
of your project.

Unfortunately I cannot give you the source of console app, because I lost the code,
(I still have executable which adds my companys name, my name and several such trivia)

I can however send you the CVersion class that wraps around the VERSIONINFO
structure. You can use this class in aboutbox, splash screen or even in your other part of
application that may be version dependant.

send me your email address if you need it.
0
 

Author Comment

by:RJV
ID: 1312418
Hi,

Yes, I'd be interested in your CVersion class as this is my goal. Namely, take info from one place, where it already exists, rather than having to keep extra headers just for this purpose. The extra header concept doesn't seem very efficient, particularly as the information already exists.

You can email me at rjv@dispro.com.br.

RJV


0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1312419
I was about to offer my code for access to resources as well.

What the heck .. this is the sort of thing I do...

0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1312420
class CMyWinApp : public CWinApp {
  // ...
private:
  CString m_ProgramPathAndName;
  int m_fv[4];      // file version
  int m_pv[4];      // product version
  CString m_Comments;
  CString m_CompanyName;
  CString m_CompanyName;
  CString m_FileDescription;
  CString m_InternalName;
  CString m_LegalCopyright;
  CString m_LegalTrademarks;
  CString m_OriginalFilename;
  CString m_PrivateBuild;
  CString m_ProductName;
  CString m_SpecialBuild;
};

const CString& CMyWinApp::ProgramPathAndName() {
  if (m_ProgramPathAndName.IsEmpty()) {
    char *buffer = m_ProgramPathAndName.GetBuffer(_MAX_PATH);
    bool ok = ::GetModuleFileName(0,buffer,_MAX_PATH) != 0;
    m_ProgramPathAndName.ReleaseBuffer();
  }
  return m_ProgramPathAndName;
}

CString CMyWinApp::GetVersionInfoField (LPCTSTR name, void* bufVersionInfo, WORD* pLanguage) {
  CString key;
  key.Format("\\StringFileInfo\\%04X%04x\\%s",*((WORD*)pLanguage),*(((WORD*)pLanguage)+1),name);
  UINT ulen;
  char* bufString;
  if (! ::VerQueryValue(bufVersionInfo, const_cast<char*>(LPCTSTR(key)), reinterpret_cast<LPVOID*>(&bufString), &ulen)) return CString();
  return CString(bufString, ulen+1);
}

void CMyWinApp::GetVersionInfo () {
  char* path = const_cast<char*>(LPCTSTR(ProgramPathAndName()));
  DWORD hVerDummy;
  DWORD dwVersionInfoSize = ::GetFileVersionInfoSize(path,&hVerDummy);
  if (dwVersionInfoSize == 0L) return;
  void* bufVersionInfo = malloc(dwVersionInfoSize);
  if (! bufVersionInfo) return;
  if (::GetFileVersionInfo(path,hVerDummy,dwVersionInfoSize,bufVersionInfo)) {
    UINT ulen;
    // Get Version Info
    VS_FIXEDFILEINFO *bufFixedFileInfo;
    if (::VerQueryValue(bufVersionInfo,"\\",reinterpret_cast<LPVOID*>(&bufFixedFileInfo), &ulen)){
      m_fv[0] = HIWORD(bufFixedFileInfo->dwFileVersionMS);
      m_fv[1] = LOWORD(bufFixedFileInfo->dwFileVersionMS);
      m_fv[2] = HIWORD(bufFixedFileInfo->dwFileVersionLS);
      m_fv[3] = LOWORD(bufFixedFileInfo->dwFileVersionLS);
      m_pv[0] = HIWORD(bufFixedFileInfo->dwProductVersionMS);
      m_pv[1] = LOWORD(bufFixedFileInfo->dwProductVersionMS);
      m_pv[2] = HIWORD(bufFixedFileInfo->dwProductVersionLS);
      m_pv[3] = LOWORD(bufFixedFileInfo->dwProductVersionLS);
    }
    WORD* pLanguage;
    if(::VerQueryValue(bufVersionInfo, "\\VarFileInfo\\Translation", reinterpret_cast<LPVOID*>(&pLanguage), &ulen) && ulen != 0) {
      m_Comments = GetVersionInfoField ("Comments",bufVersionInfo,pLanguage);
      m_CompanyName = GetVersionInfoField ("CompanyName",bufVersionInfo,pLanguage);
      m_FileDescription = GetVersionInfoField ("FileDescription",bufVersionInfo,pLanguage);
      m_InternalName = GetVersionInfoField ("InternalName",bufVersionInfo,pLanguage);
      m_LegalCopyright = GetVersionInfoField ("LegalCopyright",bufVersionInfo,pLanguage);
      m_LegalTrademarks = GetVersionInfoField ("LegalTrademarks",bufVersionInfo,pLanguage);
      m_OriginalFilename = GetVersionInfoField ("OriginalFilename",bufVersionInfo,pLanguage);
      m_PrivateBuild = GetVersionInfoField ("PrivateBuild",bufVersionInfo,pLanguage);
      m_ProductName = GetVersionInfoField ("ProductName",bufVersionInfo,pLanguage);
      m_SpecialBuild = GetVersionInfoField ("SpecialBuild",bufVersionInfo,pLanguage);
    }      
  }
  free(bufVersionInfo);
}

const int* CMyWinApp::FileVersion () {
  if (m_fv[0] < 0) GetVersionInfo();
  return m_fv;
}

const int* CMyWinApp::ProductVersion () {
  if (m_pv[0] < 0) GetVersionInfo();
  return m_pv;
}

const CString& CMyWinApp::Comments () {
  if (m_Comments.IsEmpty()) GetVersionInfo();
  return m_Comments;
}

const CString& CMyWinApp::CompanyName () {
  if (m_CompanyName.IsEmpty()) GetVersionInfo();
  return m_CompanyName;
}

const CString& CMyWinApp::FileDescription () {
  if (m_FileDescription.IsEmpty()) GetVersionInfo();
  return m_FileDescription;
}

const CString& CMyWinApp::InternalName () {
  if (m_InternalName.IsEmpty()) GetVersionInfo();
  return m_InternalName;
}

const CString& CMyWinApp::LegalCopyright () {
  if (m_LegalCopyright.IsEmpty()) GetVersionInfo();
  return m_LegalCopyright;
}

const CString& CMyWinApp::LegalTrademarks () {
  if (m_LegalTrademarks.IsEmpty()) GetVersionInfo();
  return m_LegalTrademarks;
}

const CString& CMyWinApp::OriginalFilename () {
  if (m_OriginalFilename.IsEmpty()) GetVersionInfo();
  return m_OriginalFilename;
}

const CString& CMyWinApp::PrivateBuild () {
  if (m_PrivateBuild.IsEmpty()) GetVersionInfo();
  return m_PrivateBuild;
}

const CString& CMyWinApp::ProductName () {
  if (m_ProductName.IsEmpty()) GetVersionInfo();
  return m_ProductName;
}

const CString& CMyWinApp::SpecialBuild () {
  if (m_SpecialBuild.IsEmpty()) GetVersionInfo();
  return m_SpecialBuild;
}

0
 

Author Comment

by:RJV
ID: 1312421
Hi ROnslow,

I had a feeling there wasn't any straight forward solution, though that doesn't make much sense. After all, to keep things organized means more code size than simply keeping the same information in two different places. That's why I refused to believe there wouldn't be a simpler solution and came here for help.

I'll check it out and get back here. It looks like both of you deserve the credits (though I haven't received the email).

RJV

0
 

Author Comment

by:RJV
ID: 1312422
Hi ROnslow,

Arghhh! This one is indeed a first! I've never had a link error with a Win32 function. Unbelievably, this one struck 'gold', with these unresolved externals:

   _VerQueryValueA@16
   _GetFileVersionInfoA@16
   _GetFileVersionInfoSizeA@8

What did you do on the #include 'front' to overcome this?

Thanks again!

RJV

0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 10

Expert Comment

by:RONSLOW
ID: 1312423
It's not a #include that is missing .. otherwise it would be a compile time error instead.

You need to add "version.lib" to your link Object Modules/Libraries line (don't forget to do it for both debug and release).



0
 

Author Comment

by:RJV
ID: 1312424
I'll check it out and let you know.

0
 
LVL 2

Expert Comment

by:SamratAshok
ID: 1312425
RJV

RJV, I believe, my CVersion class is lot better than implementing it in CWinApp class.

However, Since Iam accessing the web right now from a client site, I will get someone to
send me an attachment tommorow and I will send it over.

Send me your email address, (one that can accept attachments) if you can.



0
 
LVL 2

Expert Comment

by:SamratAshok
ID: 1312426
Hold on a minute,

I talked to a colleague and he mentioned that there is some code in site
called www.codeguru.com

sure enough there is (it was made by Robert Rocco)
His design is preety much same as mine, (function name and class name are different)
But hey it should work.

This is the  URL.

http://www.codeguru.com/misc/version_info_from_resource.shtml

If you get lost  in that site, go to homepage, jump to link called "misc" and scroll down
till you see phrase like "VersionInfo from ... Resource file"

I will send my version of CVersion (pun intended) as soon as I can.

Ciao





0
 
LVL 2

Expert Comment

by:SamratAshok
ID: 1312427
Sorry for Information overload.

There is one more version of the same class at that site by Manual Laflamme (spelling not
sure)



0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1312428
You'll have plenty of alternatives to choose from.

I agree that a separate class is probably better than adding a class to CWinApp.  However, that is just what MFC do for registry access (put GetProfileString etc to CWinApp).  So either solution will work.

Perhaps the compromise is to add access to CVersion (or whatever) into your CWinApp class.  That way the CWinApp class can wrap the calls to CVersion so that CVersion will know to look in the current application's resources. (That is assuming CVersion is a class that can read from any exe/dll).

0
 
LVL 2

Expert Comment

by:SamratAshok
ID: 1312429
RONSLOW

Actually, I see the problem you are hinting at.

This is what I have done.

I have two constructors in CVersion object.

In first constructor, you can specify the filename you want to look into with full path

I did this with intention that I could see versions of my other dependat files (Application that i developed is spread over
4 executables and 3 dlls) on the same about box.

Somehow my boss rejected the idea, so I never actually did it.

In second constructor, I look for the resource in current executable.
This I accomplish by use of global MFC function
AfxGetApp and then get the module handle and ultimately
the executable name.
(preety much the same functions that you posted in code earlier)

{ God I wish MFC had simple thing like App.Path like Visual basic :---(   }

Motive behind this is :
Since I don't really need the precise App class. I do not need to cast it to current application derived CWinApp.

I hope I have made myself clear.

0
 
LVL 2

Expert Comment

by:SamratAshok
ID: 1312430
Here is my source code. I have not delved too deep into different language issues,
but you can go ahead and add it.

CVersion.h
>>>>>>>
#include "winver.h"

/*
This class works as follows

Whenever you need version information, create a cversion object either on stack or
by new

After creation, call Init member function and check the return value.
If value is true, use the version object, else dont use it

To obtain fileversion and productversion, use respective functions

To obtain any other information, use getvariableinfo function,

supply the key value and place holder for return value.

All functions return true on success, false on failure

*/


class CVersion
{
public:
      CVersion();
      CVersion(LPCSTR strFileName);
      ~CVersion();

      BOOL Init();

      BOOL GetFileVersion(CString &strVer);
      BOOL GetProductVersion(CString &strVer);
      BOOL GetVariableInfo(LPCSTR strKey, CString &strValue);

private:

      VS_FIXEDFILEINFO m_FixedInfo;
      char *m_lpData; // contains the entire Structure
      BOOL  m_bValid;
      BOOL  m_bLangFound;
      DWORD  m_structSize;
      CString m_strLanguage;
      CString m_strFileName;

      void GetLanguageID(CString &strLangID) {strLangID = m_strLanguage;};
};
<<<<<<

CVersion.cpp
>>>>>>
#include "stdafx.h"
#include "cversion.h"

// Link Library add Version.lib

CVersion::CVersion()
{
      m_lpData = NULL;
      m_bValid = FALSE;
      m_bLangFound = FALSE;
}

CVersion::CVersion(LPCSTR strFileName)
      : m_strFileName(strFileName)
{
      m_lpData = NULL;
      m_bValid = FALSE;
      m_bLangFound = FALSE;
}

#define SUFFICIENTLY_LARGE_BUFFER 500
BOOL CVersion::Init()
{
      CString strName;
      char *szName;
      DWORD temp;


      if (m_strFileName.IsEmpty())
      {
            szName = strName.GetBuffer(SUFFICIENTLY_LARGE_BUFFER);
             /////////////////////////
            // Get the executable name
            if (GetModuleFileName(AfxGetApp()->m_hInstance, szName, SUFFICIENTLY_LARGE_BUFFER) == 0)
            {
                  strName.ReleaseBuffer();
                  return FALSE;
            }
            strName.ReleaseBuffer();
      } else
      {
            strName = m_strFileName;
      }

      // We still need a char *
      szName = strName.GetBuffer();

      /////////////////////////
      // Get the Version Information of the executable
      m_structSize = ::GetFileVersionInfoSize(szName, &temp);
      if (m_structSize == 0)
      {
            strName.ReleaseBuffer();
            return FALSE;
      }

      m_lpData = new char [m_structSize];
      if (!GetFileVersionInfo(szName, 0, m_structSize, m_lpData))
      {
            delete  [] m_lpData;
            m_lpData = NULL;
            strName.ReleaseBuffer();
            return FALSE;
      }
      /////////////////////////
      // Now retrieve the fixedinfo structure from the version info

      LPVOID lplpBuff;
      UINT   nLen;

      VerQueryValue(m_lpData, "\\", &lplpBuff, &nLen);
      memcpy(&m_FixedInfo, lplpBuff, sizeof(VS_FIXEDFILEINFO));

      /////////////////////////
      // Now Determine the language id
      char *szLangugeID;
      if (VerQueryValue(m_lpData,"\\VarFileInfo\\Translation",
            &lplpBuff, &nLen))
      {
            UINT   nLangMajor = 0;
            UINT   nLangMinor = 0;

            szLangugeID = (char *)lplpBuff;
            // pick up the first language
            // for the more ambitious move, create an array and capture
            // all the language values

            memcpy(&nLangMajor, szLangugeID, 2);
            memcpy(&nLangMinor, szLangugeID + 2, 2);

            m_strLanguage.Format("%04X%04X",nLangMajor, nLangMinor);
            m_bLangFound = TRUE;
      } else
      {
            // Default to English
            m_strLanguage = "04090000";
      }

      // Init done successful
      m_bValid = TRUE;
      strName.ReleaseBuffer();
      return TRUE;
}

CVersion::~CVersion()
{
      if (m_lpData != NULL)
      {
            delete [] m_lpData;
      }
}

BOOL CVersion::GetFileVersion(CString &strVer)
{
      if (!m_bValid)
            return FALSE;

      UINT hMS = HIWORD(m_FixedInfo.dwFileVersionMS);
      UINT lMS = LOWORD(m_FixedInfo.dwFileVersionMS);

      UINT hLS = HIWORD(m_FixedInfo.dwFileVersionLS);
      UINT lLS = LOWORD(m_FixedInfo.dwFileVersionLS);

      strVer.Format("%d.%d.%d.%d",hMS, lMS, hLS, lLS);
      return TRUE;
}

BOOL CVersion::GetProductVersion(CString &strVer)
{
      if (!m_bValid)
            return FALSE;

      UINT hMS = HIWORD(m_FixedInfo.dwProductVersionMS);
      UINT lMS = LOWORD(m_FixedInfo.dwProductVersionMS);

      UINT hLS = HIWORD(m_FixedInfo.dwProductVersionLS);
      UINT lLS = LOWORD(m_FixedInfo.dwProductVersionLS);

      strVer.Format("%d.%d.%d.%d",hMS, lMS, hLS, lLS);
      return TRUE;
}

BOOL CVersion::GetVariableInfo(LPCSTR strKey, CString &strValue)
{
      LPVOID lplpBuff;
      UINT   nLen;
      CString strActualKey;
      char *szKey;


      // If one of them is false, return false
      if (!(m_bValid && m_bLangFound))
            return FALSE;

      strActualKey.Format("\\StringFileInfo\\%s\\%s",m_strLanguage, strKey);
      szKey = strActualKey.GetBuffer(strActualKey.GetLength());

      if (VerQueryValue(m_lpData, szKey, &lplpBuff, &nLen))
      {
            strActualKey.ReleaseBuffer();
            strValue = (char *)lplpBuff;
      } else
      {
            strActualKey.ReleaseBuffer();
            return FALSE;
      }

      return TRUE;
}
<<<<<<<

0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Named range not carried over 10 57
How to convert MFC::CString to UTF8 wchar_t* 10 102
wordcount challenge 11 78
Problem to open Excel file 15 45
In this article, I'll describe -- and show pictures of -- some of the significant additions that have been made available to programmers in the MFC Feature Pack for Visual C++ 2008.  These same feature are in the MFC libraries that come with Visual …
Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now