From: RB on
Actually I have been experimenting with the
#define _STR(x) #x
#define STR(x) _STR(x)

And I found that instead stringizing every individual numerical
define as in
#define VERMAJ 1
#define V_MA_STR_LIT STR( VERMAJ )
........ etc

which ended up doing all of this
#define VERSTR_LITERAL V_MA_STR_LIT "." V_MI_STR_LIT "." V_FX_STR_LIT "." B_N_STR_LIT

I could use the numericals right of and just do this
#define VERSTR_LITERAL STR( VERMAJ.VERMIN.VERFIX.BUILDNUM)
// which can be used anywhere you would manually type in a string literal of "x.x.x.x"
// or in the first version case "1.0.0.0"
From: Joseph M. Newcomer on
See below...
On Wed, 16 Jun 2010 11:38:26 +0200, Giovanni Dicanio
<giovanniDOTdicanio(a)REMOVEMEgmail.com> wrote:

>On 16/06/2010 05:57, Joseph M. Newcomer wrote:
>
>>> LPBYTE lpVersionInfo = new BYTE[dwFVISize];
>> ****
>> You would be better served by
>> CBytArray VersionInfo;
>> VersionInfo.SetSize(dwFVISize];
>
>or STL's vector:
>
> vector<BYTE> VersionInfo(dwFVISize);
>
****
Absolutely. I use CByteArray because I'm more familiar with it, and GetData() is so much
cleanter than &VersionInfo[0], which is what std::vector requires
****
>>>
>>> if( lpVersionInfo )
>>> delete lpVersionInfo;
>> ****
>> Note there is no need to do the delete if you have used the CByteArray.
>>
>> Note also that you must not delete this data until *after* you have used it!
>
>Note also that if the memory was allocated using new BYTE[...], it
>should be deleted using delete[] (note the square brackets).
****
I thought of pointing this out, but given that (a) new should never have been used and (b)
the delete should not have existed at this point, it seemed silly to point out how to
"fix" defective code so it was "correct" with respect to a delete that should not exist!
joe
****
>
>I agree that with RAII classes like std::vector you just don't need to
>spend brain cycles :) to track these kind of memory leaks.
>
>Giovanni
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: JCO on
Yes this is all working now except for the implementation in the actual
About Box. I'm getting the Assertion Error.
For the AboutBox implementation I have the following:
prototypes
void SetVersionString (LPTCSTR sVer);
LPTCSTR GetVersionString (void);

//m_CtrlStaticVer is the control variable for the CStatic that is to be set
with the proper value in the dialog
BOOL CAboutDlg::OnInitDialog(void)
{
CString s;
s.Format( _T("AppVersionDynamic, Version %d.%d.%d.%d"), VERMAJ,
VERMIN, VERFIX,
BUILDNUMBER );
SetVersionString( s );

m_CtrlStaticVer.SetWindowText( GetVersionString() );
return TRUE;
}

I get 2 Assertion Errors. One deals with the control variable setting the
value. If commented out, I get still get an assertion on the dialog when
you close it out.

Thanks

"Joseph M. Newcomer" <newcomer(a)flounder.com> wrote in message
news:i7jg165ugb9uba3nei7p3tqleka51cvm7v(a)4ax.com...
> If you add a VERSIONINFO to the RC2 file, you must DELETE the EXISTING ONE
> from the .rc
> file! Otherwise, guess what, you have a duplicate resource of type
> VERSION, whose name is
> 1, and whose language is 0x0409.
>
> Error 1 leads directly to error 2.
> joe
>
> On Tue, 15 Jun 2010 12:24:05 -0500, "JCO" <someone(a)somewhere.com> wrote:
>
>>When I add this information to the RC2 file, I get these two errors:
>>1 CVT1100: duplicate resource, Type:VERSION, name:1, language:0x0409
>>2 LNK1123: failure during conversion to COFF: file invalid or corrupt
>>
>>"RB" <NoMail(a)NoSpam> wrote in message
>>news:umG$MhIDLHA.4400(a)TK2MSFTNGP05.phx.gbl...
>>> Corrective update, although the paste I gave you does in fact work
>>> in my App currently. You may want to reexamine my use of the
>>> results of #define _STR(x) #x
>>> #define STR(x) _STR(x)
>>> since I am still learning this area, and some reading I did last night
>>> proves to me that I did not fully understand what this macro was
>>> expanding to when I implemented some of the pasted code.
>>>
>>> I really should not be replying to questions since I am not at that
>>> level of competence yet. I only supplied it since I "appeared at the
>>> time" to have a working example of what you asked for, which
>>> the whole idea was given to me ( if you followed the thread )
>>> by David Webber, but the implementation (and any foo bars )
>>> are my doing, not Davids.
>>> So use what you will but be aware.
>>> RB
> Joseph M. Newcomer [MVP]
> email: newcomer(a)flounder.com
> Web: http://www.flounder.com
> MVP Tips: http://www.flounder.com/mvp_tips.htm

From: JCO on
Sorry, I'm not familiar with RTFM.
I'm not sure how to figure out what library is missing and how to include
it?

I made the change using CByteArray. That's a big help and your rigth... the
code looks cleaner. Plus I was able to delete the "delete[]"

Thanks so far.

"Joseph M. Newcomer" <newcomer(a)flounder.com> wrote in message
news:crhg1652u574iem3g5iu09amqun7o9n7on(a)4ax.com...
> The version library is not included by default in the link. If you get
> any kind of linker
> error, it is ESSENTIAL that you RTFM, which tells you which library needs
> to be linked in.
> Link in that library.
> joe
> ****
> On Tue, 15 Jun 2010 18:14:48 -0500, "JCO" <someone(a)somewhere.com> wrote:
>
>>
>>This is another issue that fits in this thread.
>>I've been messing with the GetFileVersionInfo() but when it's in my cpp, I
>>get link errors. I can't seem to find a header file that might be missing
>>so I don't understand it. The code snip is shown below. I have some
>>extra
>>code because I'm experimenting a bit but the issue is the
>>GetFileVersionInfo() linker Issue.
>>*********************************************************
>> //get filename, add .exe, then get handle to this filename
> ****
> Start throwing code away here
> ****
>> CString strFileName( _T("") );
>> strFileName = AfxGetApp()->m_pszExeName;
>> strFileName.Append( _T(".exe") );
>> HMODULE hmod = GetModuleHandle( strFileName );
>>
>> //use GetModuleFileName() to obtain full path of file
>> CString strFullPath( _T("") );
>> LPTSTR pstr = strFullPath.GetBufferSetLength(MAX_PATH+1);
>> DWORD pathLen = ::GetModuleFileName( hmod, pstr, MAX_PATH);
>>
>> strFullPath.ReleaseBuffer( pathLen ); //Note: ReleaseBuffer doesn't
>> need
>>a +1 for the null byte
> ****
> Throw away all the above code. As far as I can tell, it does nothing that
> can't be done
> in the four simple lines below.
>
> CString filename;
> LPTSTR p = fliename.GetBuffer(MAX_PATH);
> GetModuleFileName(NULL, p, MAX_PATH);
> filename.ReleaseBuffer();
>
> It is not at all clear why you have to use GetModuleHandle here at all.
> The module handle
> is not needed for anything. RTFM; using NULL as the module handle gives
> you the filename
> of the running executable!
> ****
>>
>> //Use GetFileVersionInfo() to get file information
>> TCHAR szExePath[MAX_PATH];
> ****
> This variable is not needed; eliminate it entirely!
> *****
>> ::GetModuleFileName( NULL, szExePath, MAX_PATH );
> ****
> Why are you repeating the GetModuleFileName, which was already done? Get
> rid of this
> line; it serves no useful purpose because you already have the module
> filename!
> ****
>>
>> DWORD dwDummy;
>> DWORD dwFVISize = GetFileVersionInfoSize( szExePath, &dwDummy );
> ****
> Given I used the variable "filename" above, this would simply be
> DWORD dwFVISize = ::GetFileVersionInfoSize(filename, &dwDummy);
> ****
>>
>> LPBYTE lpVersionInfo = new BYTE[dwFVISize];
> ****
> You would be better served by
> CBytArray VersionInfo;
> VersionInfo.SetSize(dwFVISize];
> *****
>> GetFileVersionInfo( szExePath , 0 , dwFVISize , lpVersionInfo );
> ****
> And then coding the above as
> ::GetFileVersionInfo(filename, 0, dwFVISize, VersionInfo.GetData());
> ****
>>
>> if( lpVersionInfo )
>> delete lpVersionInfo;
> ****
> Note there is no need to do the delete if you have used the CByteArray.
>
> Note also that you must not delete this data until *after* you have used
> it!
>
> And why is it that if the value is NULL, you try to call
> ::GetFileVersionInfo anyway? If
> you were testing for an allocation error, you would test BEFORE you tried
> to use the
> pointer. And there is no need to condition delete if it is NULL. And
> if the call
> failed, why are you blindly going on and tryhing to *use* the illegal
> values?
>>
>> VS_FIXEDFILEINFO *lpFfi;
> ****
> And where do I see this pointer being initialized? You have an
> uninitialized pointer and
> you blindly use it to access values below!
>
> It should be initialized as
> VS_FIXEDFILEINFO * Ffi =(VS_FIXEDFILEINFO *)VersionInfo.GetData();
> ****
>> DWORD dwFileVersionMS = lpFfi->dwFileVersionMS;
>> DWORD dwFileVersionLS = lpFfi->dwFileVersionLS;
>> DWORD dwLeftMost = HIWORD(dwFileVersionMS);
>> DWORD dwSecondLeft = LOWORD(dwFileVersionMS);
>> DWORD dwSecondRight = HIWORD(dwFileVersionLS);
>> DWORD dwRightMost = LOWORD(dwFileVersionLS);
>>
>> CString sMsg;
>> sMsg.Format( _T("Version: %d.%d.%d.%d") , dwLeftMost,
>>dwSecondLeft,dwSecondRight, dwRightMost );
>> MessageBox( sMsg );
>>
>>********************************************************
>>
>>These are the liker Errors:
>>Error 1 error LNK2019: unresolved external symbol _GetFileVersionInfoW(a)16
>>referenced in function "public: void __thiscall
>>CAppVersionDynamicDlg::OnBnClickedButtonVersion(void)"
>>(?OnBnClickedButtonVersion(a)CAppVersionDynamicDlg@@QAEXXZ)AppVersionDynamicDlg.obj
>>AppVersionDynamicError 2 error LNK2019: unresolved external symbol
>>_GetFileVersionInfoSizeW@8
>>referenced in function "public: void __thiscall
>>CAppVersionDynamicDlg::OnBnClickedButtonVersion(void)"
>>(?OnBnClickedButtonVersion(a)CAppVersionDynamicDlg@@QAEXXZ)AppVersionDynamicDlg.obj
>>AppVersionDynamic"Joseph M. Newcomer" <newcomer(a)flounder.com> wrote in
>>message
>>news:cc1f16hsn3lejfmtp2b5n0a20093vii1bf(a)4ax.com...
> ****
> RTFM. The documentation CLEARLY states that the API call is found in
> version.lib, so it
> is screamingly obvious that this library is not included in the link. So
> add it to the
> linker list of libraries to search!
> joe
> ****
>>> The idea is that the header file is used to create both the string in
>>> the
>>> About box and
>>> the values in the .rc file that describes the VERSIONINFO.
>>> joe
>>>
>>> On Mon, 14 Jun 2010 18:54:46 -0500, "JCO" <someone(a)somewhere.com> wrote:
>>>
>>>>I think I'm missing something but I'm interested in this topic.
>>>>If you have your version defined in a header file, then you can display
>>>>it
>>>>in the dialog, however, if you did a "property" on the exe file, has it
>>>>really changed? If so, then I got lost somewhere in this thread.
>>>>
>>>>Also;
>>>>I was under the impression that you can set something in VS that allowed
>>>>the
>>>>version to change each time you do a build. I don't remember how to do
>>>>this
>>>>but I always thought this was possible. Now it may only change the
>>>>Build
>>>>number and not anything else, however, this is a good feature. Is this
>>>>still possible, if so .... how do you do it?
>>>>
>>>>Thanks
>>>>
>>>>
>>>>"Giovanni Dicanio" <giovanniDOTdicanio(a)REMOVEMEgmail.com> wrote in
>>>>message
>>>>news:eg3hiCyCLHA.2012(a)TK2MSFTNGP02.phx.gbl...
>>>>> On 13/06/2010 15:47, RB wrote:
>>>>>
>>>>>> void CFileHandlingApp::OnAppAbout()
>>>>>> {
>>>>>> CAboutDlg aboutDlg;
>>>>>> CString s;
>>>>>> s.Format( _T(" version %d.%d.%d.%d"), VERMAJ, VERMIN, VERFIX,
>>>>>> BUILDNUMBER );
>>>>>> aboutDlg.m_CtrlStaticVer.SetWindowText(s); //gets a Debug
>>>>>> Assertion
>>>>>> Failed
>>>>>> aboutDlg.DoModal();
>>>>>
>>>>> You may want to add a method to your CAboutDlg class like
>>>>> SetVersionString(LPCTSTR pszVersion) and a data member of type CString
>>>>> (e.g. CString m_strVersion).
>>>>> This new method should set the version string, storing it into the
>>>>> proper
>>>>> data member.
>>>>>
>>>>> Then, CAboutDlg::OnInitDialog would get this string and
>>>>> .SetWindowText()
>>>>> it in the proper static control.
>>>>>
>>>>> e.g.:
>>>>>
>>>>> class CAboutDlg
>>>>> {
>>>>> ...
>>>>> public:
>>>>> void SetVersionString(LPCTSTR pszVersion)
>>>>> {
>>>>> m_strVersion = pszVersion;
>>>>> }
>>>>>
>>>>> ...
>>>>>
>>>>> private:
>>>>> CString m_strVersion;
>>>>> };
>>>>>
>>>>> In CAboudDlg::OnInitDialog() do:
>>>>>
>>>>> m_CtrlStaticVer.SetWindowText(m_strVersion);
>>>>>
>>>>>
>>>>> Giovanni
>>> Joseph M. Newcomer [MVP]
>>> email: newcomer(a)flounder.com
>>> Web: http://www.flounder.com
>>> MVP Tips: http://www.flounder.com/mvp_tips.htm
> Joseph M. Newcomer [MVP]
> email: newcomer(a)flounder.com
> Web: http://www.flounder.com
> MVP Tips: http://www.flounder.com/mvp_tips.htm

From: JCO on
Never mind! I went to the project property and added version.lib in the
area Linker->Dependency.
I never understood how to figure out that version.lib is what I needed
(other than Joseph's post)?

Of course this brings up all sorts of other errors further down in the code.
None of the code below works. It throws exceptions:

DWORD dwFileVersionMS = lpFfi->dwFileVersionMS;
DWORD dwFileVersionLS = lpFfi->dwFileVersionLS;
DWORD dwLeftMost = HIWORD(dwFileVersionMS);
DWORD dwSecondLeft = LOWORD(dwFileVersionMS);
DWORD dwSecondRight = HIWORD(dwFileVersionLS);
DWORD dwRightMost = LOWORD(dwFileVersionLS);


"Giovanni Dicanio" <giovanniDOTdicanio(a)REMOVEMEgmail.com> wrote in message
news:#TsHxeTDLHA.1368(a)TK2MSFTNGP06.phx.gbl...
> On 16/06/2010 05:57, Joseph M. Newcomer wrote:
>
>>> LPBYTE lpVersionInfo = new BYTE[dwFVISize];
>> ****
>> You would be better served by
>> CBytArray VersionInfo;
>> VersionInfo.SetSize(dwFVISize];
>
> or STL's vector:
>
> vector<BYTE> VersionInfo(dwFVISize);
>
>>>
>>> if( lpVersionInfo )
>>> delete lpVersionInfo;
>> ****
>> Note there is no need to do the delete if you have used the CByteArray.
>>
>> Note also that you must not delete this data until *after* you have used
>> it!
>
> Note also that if the memory was allocated using new BYTE[...], it should
> be deleted using delete[] (note the square brackets).
>
> I agree that with RAII classes like std::vector you just don't need to
> spend brain cycles :) to track these kind of memory leaks.
>
> Giovanni