Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

VS_VERSION_INFO static ctrl

164 views
Skip to first unread message

RB

unread,
Jun 11, 2010, 11:01:16 PM6/11/10
to

I'm trying to figure the best way to set and track my MFC app version.
The issue is I see that the AppWizard upon project creation puts
version 1.0 in a static text in the class CAboutDlg : public CDialog.
I can manually edit this but it would seem there would be either
a way to access the value from code in MyDoc Class, or at least set
this value from code so that I don't have to manually edit said static text
to match whatever version I am implementing in my code or
schema. Appreciate any input on the best way to do the above or
how you implement your version data.

Joseph M. Newcomer

unread,
Jun 11, 2010, 11:27:55 PM6/11/10
to
I consider the Microsoft About box one of the single worst pieces of code generated by the
framework, and it proves once again that software *evolves* (there is no trace of
Intelligent Design anywhere!)

What you have to do is use the version APIs to get the version number of the current
executable (GetModuleFileName), then format it yourself in the OnInitInstance handler of
the About dialog (had there been any trace of Intelligent Design (a) this would have
already been done for you and (b) the About box would be in a separate pair of files
About.cpp and About.h, and we could then write once and replug an intelligently-designed
Abput box in)

The About box is the result of some summer intern being allowed to do design. No one who
cared about software could possibly have come up with a design as bad as the one we have
now for the About box.

You can download the About box code that Brent Rector wrote if you go to
www.flounder.com/downloads and download the code for our book. I did some minor
enhancements, but the code is over ten years old and doesn't cover modern CPUs. I should
rewrite it to use the CPUID instruction instead of the sort-of-kludge it uses. But
Brent's code will nicely substitute values from the VERSIONINFO resource into the static
controls (you preload the static control with the VERSIONINFO keyword you want to use!)

But Brent is an Intelligent Designer. Too bad something this simple couldn't have been
produced by the framework.
joe

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

David Webber

unread,
Jun 12, 2010, 3:48:17 AM6/12/10
to

"RB" <NoMail@NoSpam> wrote in message
news:#dg$MudCLH...@TK2MSFTNGP05.phx.gbl...

Let me suggest an alternative to extracting the version number with the
Version APIs as Joe suggests.

I have a couple of EXE's and a few DLL's, and when I build them, I want them
all to get matching version numbers.

So I put the versioninfo in the .rc2 file (to stop appstudio from buggering
it about) and use #defined constants (VERMAJ, VERMIN, VERFIX, BUILDNUMBER)
from an included header file (see below).

This means that I can change the version number of all my modules very
easily, and I can also get the version number by including the header file
in .cpp files.

Dave
--
David Webber
Mozart Music Software
http://www.mozart.co.uk
For discussion and support see
http://www.mozart.co.uk/mozartists/mailinglist.htm

//==================================

VS_VERSION_INFO VERSIONINFO
FILEVERSION VERMAJ,VERMIN,VERFIX,BUILDNUMBER
PRODUCTVERSION VERMAJ,VERMIN,VERFIX,BUILDNUMBER
....
VALUE "FileVersion", VERSIONSTRING
VALUE "ProductVersion", PRODUCTSTRING
....


//==================================
The included header file contains:

// Stringisation.
// (Two steps needed).

#define _STR(x) #x
#define STR(x) _STR(x)

// The following are used as defined quantities
// in the versioninfo resource:

#define VERMAJ 1
#define VERMIN 0
#define VERFIX 0
#define BUILDNUMBER 0

#define VERMAJSTR STR( VERMAJ )
#define VERMINSTR STR( VERMIN )
#define VERFIXSTR STR( VERFIX )
#define BUILDSTR STR( BUILDNUMBER )#define VERSIONSTRING VERMAJSTR "." VERMINSTR "." VERFIXSTR "." BUILDSTR
#define PRODUCTSTRING VERMAJSTR "." VERMINSTR "." VERFIXSTR "." BUILDSTR


//==================================

David Wilkinson

unread,
Jun 12, 2010, 5:47:55 AM6/12/10
to
David Webber wrote:
> Let me suggest an alternative to extracting the version number with the
> Version APIs as Joe suggests.
>
> I have a couple of EXE's and a few DLL's, and when I build them, I want
> them all to get matching version numbers.
>
> So I put the versioninfo in the .rc2 file (to stop appstudio from
> buggering it about) and use #defined constants (VERMAJ, VERMIN, VERFIX,
> BUILDNUMBER) from an included header file (see below).

Clever. Why didn't I think of this?

--
David Wilkinson
Visual C++ MVP

RB

unread,
Jun 12, 2010, 7:47:56 AM6/12/10
to
Thanks Joe.


RB

unread,
Jun 12, 2010, 7:49:50 AM6/12/10
to

Thanks David I will try this.


RB

unread,
Jun 12, 2010, 9:17:03 AM6/12/10
to

> So I put the versioninfo in the .rc2 file (to stop appstudio from buggering it about)

Hi again David, I kinda dumb on rc files. I understand what you are
doing in the header file, but I need a little help on the rc context.
First off do I delete the data that is in my original (ResourceView) rc file?

And then I am confused as to what I actually put in the rc2 file ?

RB

unread,
Jun 12, 2010, 1:07:26 PM6/12/10
to
Ok been reading and experimenting and I am beginning to see some of
what you meant. I have the below done. First I cut this out of my old
rc file (by opening it up in Notepad) and then pasted it into the rc2 file

/////////in my rc2 file///////////////////////////////////
// Add manually edited resources here...
#include "AppVer.h"

#ifndef _MAC
VS_VERSION_INFO VERSIONINFO
//----- used to be FILEVERSION 1,0,0,1 -----//
FILEVERSION VERMAJ,VERMIN,VERFIX, BUILDNUMBER // edited
PRODUCTVERSION VERMAJ,VERMIN,VERFIX, BUILDNUMBER
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L

#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "FileHandling MFC Application\0"
VALUE "FileVersion", VERSIONSTRING"\0" // edited
VALUE "InternalName", "FileHandling\0"
VALUE "LegalCopyright", "Copyright (C) 2010\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "FileHandling.EXE\0"
VALUE "ProductName", "FileHandling Application\0"
VALUE "ProductVersion", VERSIONSTRING"\0" // edited
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // !_MAC
//////////==== then I put this in my AppVer.h file =============//

#define _STR(x) #x
#define STR(x) _STR(x)

#define VERMAJ 1


#define VERMIN 0
#define VERFIX 0

#define BUILDNUMBER 1

#define VERMAJSTR STR( VERMAJ )
#define VERMINSTR STR( VERMIN )
#define VERFIXSTR STR( VERFIX )
#define BUILDSTR STR( BUILDNUMBER )
#define VERSIONSTRING VERMAJSTR "." VERMINSTR "." VERFIXSTR "." BUILDSTR
#define PRODUCTSTRING VERMAJSTR "." VERMINSTR "." VERFIXSTR "." BUILDSTR

// =====However I guess now I have to set the window text in the Static
// control to get all of this to show up


David Webber

unread,
Jun 12, 2010, 6:22:36 PM6/12/10
to

From: "RB" <NoMail@NoSpam>

> Ok been reading and experimenting and I am beginning to see some of
> what you meant. I have the below done. First I cut this out of my old
> rc file (by opening it up in Notepad) and then pasted it into the rc2 file

That's the idea: but you can also do it in Visual Studio by right clicking
in the rc2 file in the "solution view" and choosing "Open with ..." to open
the file in a normal editing window.

(But be careful editing standard .rc files like that as it is possible to do
things APPSTUDIO doesn't like.)

> /////////in my rc2 file///////////////////////////////////
>....

That's the general idea.

// =====However I guess now I have to set the window text in the Static
> // control to get all of this to show up

Exactly. Something like:

CString s;
s.Format( _T("This is my program version %d.%d.%d.%d"), VERMAJ, VERMIN,
VERFIX, BUILDNUMBER );
m_wnd.SetWindowText( s );

Dave

RB

unread,
Jun 13, 2010, 9:47:05 AM6/13/10
to

Yea, I was using another format function but having problems with an
assertion, so I tried your CString method. But I am still getting the
assertion, I must not be calling it correctly. I first tried it in the
dialog constructor, and got the assertion.
So then I tried it in the handler that calls the dialog, but got
the same assertion. I am foo barring somewhere.
Code below.

//// CAboutDlg dialog used for App About
//
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
CStatic m_CtrlStaticCr;
CStatic m_CtrlStaticVer;
//}}AFX_DATA
//............
}

//// DDX Stuff
//
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
DDX_Control(pDX, IDC_STATICcr, m_CtrlStaticCr);
DDX_Control(pDX, IDC_STATICver, m_CtrlStaticVer);
//}}AFX_DATA_MAP
}

//// handler that runs the dialog
//
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();
}


Giovanni Dicanio

unread,
Jun 13, 2010, 1:48:26 PM6/13/10
to
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

David Webber

unread,
Jun 13, 2010, 2:22:36 PM6/13/10
to

"RB" <NoMail@NoSpam> wrote in message

news:u1Z9q7vC...@TK2MSFTNGP04.phx.gbl...

> Yea, I was using another format function but having problems with an
> assertion, so I tried your CString method. But I am still getting the
> assertion, I must not be calling it correctly. I first tried it in the
> dialog constructor, and got the assertion.
> So then I tried it in the handler that calls the dialog, but got
> the same assertion. I am foo barring somewhere.

In MFC there are two concepts: the Window with its HWND (looked after by
Windows), and the class (derived from CWnd, in this case CDialog) which
wraps the Window (looked after by MFC).

When you construct your class, it is not attached to a Window, so it doesn't
know about the controls, which are yet to become Windows. So you can't
touch them.

When you invoke DoModal() the window is attached to the class, and it gives
you a chance to initialise anything you need when it calls OnInitDialog().
That is where you can set the text in static controls.

Looked at from outside from an object oriented programming point of view,
this structure is a complete mess. But when MFC was invented I don't think
anyone at Microsoft had heard of object oriented programming. (Otherwise
why do you have to create the view of the document before you create the
document?) From the point of view of creating a thin wrapper round the
Windows API, it makes more sense. And in those days people who knew the
Windows API could learn MFC quite quickly, just because it was a thin
wrapper. But nowadays who writes programs in C using the Windows API?

[I suppose .NET was a bid to escape the historical quirks of MFC, but those
of us with lots of legacy MFC code we're still developing have grown to know
and, well not exactly love but coexist with, the vagaries of MFC's
structure.]

Dave

--

RB

unread,
Jun 13, 2010, 3:34:48 PM6/13/10
to
Thanks Giovanni, worked like a charm, though I changed the
SetVersionString function to no args. I have a couple of
questions if you would be so kind. See code and comments
below. Questions are at very bottom in the OnInitDialog.

#include .....others.....
#include "AppVer.h" // has version string data thanks
// to David Webber

/////////////////////////////////////////////////////////////////////////////


// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
private:
CString m_strVersion;
public:
void SetVersionString( );
CAboutDlg( );

// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
CStatic m_CtrlStaticCr;
CStatic m_CtrlStaticVer;
//}}AFX_DATA

// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX);
//}}AFX_VIRTUAL

// Implementation
protected: /// ** used the class wizard to add suggested
// OnInitDialog handler ** //
//{{AFX_MSG(CAboutDlg)
virtual BOOL OnInitDialog( );
//}}AFX_MSG
DECLARE_MESSAGE_MAP( )
};
/// ** suggested SetVersion function, but no args ** //
void CAboutDlg::SetVersionString( )
{
m_strVersion.Format( _T(" version %d.%d.%d.%d"),


VERMAJ, VERMIN, VERFIX, BUILDNUMBER );
}

----constructor, nothing happening here

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
DDX_Control(pDX, IDC_STATICcr, m_CtrlStaticCr);
DDX_Control(pDX, IDC_STATICver, m_CtrlStaticVer);
//}}AFX_DATA_MAP
}

..........message map stuff ..........
............

//// handler that runs the dialog
//
void CFileHandlingApp::OnAppAbout( )
{
CAboutDlg aboutDlg;

aboutDlg.DoModal( );
}

/////////////////////////////////////////////////////////////////////////////
// CFileHandlingApp message handlers

BOOL CAboutDlg::OnInitDialog( )
{ //** Class Wizard added base call ** //
CDialog::OnInitDialog( );

//** being added code //
SetVersionString( ); // format the CString
HWND hDlg = m_CtrlStaticVer.GetSafeHwnd( );

//** Question 1.
//** here I used the API SetWindowText to get a return, the
// MFC SetWindowText was a void return, Is this a big deal ?

BOOL bResult = ::SetWindowText(hDlg, m_strVersion);

//**Question 2
//** Class Wizard put below return in ? when I had planned to return the
//** the result of the SetWindow, Can you explain what this is all about ?

return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}


RB

unread,
Jun 13, 2010, 3:58:28 PM6/13/10
to
>When you invoke DoModal( ) the window is attached to the class, and it gives you a chance to initialise anything you need when it
>calls OnInitDialog(). That is where you can set the text in static controls.

You know I had a gut feeling that it was the window was not yet
created or something like that, but I am just too inexperienced to
know what to do about it. Giovanni also suggested to me the
OnInitDialog and a SetString function that worked out great.
It would seem to me that MFC would have generated an empty
OnInitDialog handler from the start to give a hint to clueless newbs
like me, but I guess that might be asking too much. However I do
see other functions created just as said with //TODO: comments//
in the Doc/View structure.
In any case THANKS to you for all of this, it has solved my
version dilemma in a functional way that I am very pleased with.
RB

Joseph M. Newcomer

unread,
Jun 13, 2010, 10:26:24 PM6/13/10
to
Serious error: see below...

****
This is incorrect code. You must put this in the OnInitDialog handler of the dialog.

The assertion failure, if you looked at it, said the window does not exist. Big surprise.
The window does not exist! In fact, the window does not exist until the OnInitDialog
handler is invoked in the context of the dialog.

As a general rule, you should NEVER touch a control variable of a dialog from outside the
dialog. In fact, it is a serious design error in the MFC framework that defaults control
variables to public and declares handlers as public methods. This design error was
induced by the incredibly bad ClassWizard of VS<=6, which couldn't parse the header files
because it had an /ad hoc/ parser. When VS.NET delivered an intelligent parsers, they
forgot to change the behavior to make sense. It *never* makes sense to declare a control
variable or handler as public, and the default should be 'protected'.

You violate that rule here by attempting to manipulate a control variable from outside the
dialog. The control variable is not bound to a control until INSIDE the OnInitDialog
handler (in fact, it is bound when the CDialog::OnInitDialog call invokes the
DoDataExchange method of the dialog class). Since the code you show here takes place long
before OnInitDialog, there is no possible way the variable could be bound to a control. In
fact, the control doesn't even exist at the point you are trying to manipulate it.
joe

> aboutDlg.DoModal();

Giovanni Dicanio

unread,
Jun 14, 2010, 6:03:33 AM6/14/10
to
On 13/06/2010 21:34, RB wrote:

> Thanks Giovanni, worked like a charm, though I changed the
> SetVersionString function to no args. I have a couple of
> questions if you would be so kind. See code and comments
> below. Questions are at very bottom in the OnInitDialog.

> class CAboutDlg : public CDialog


> {
> private:
> CString m_strVersion;
> public:
> void SetVersionString( );

If the SetVersionString method is not designed to be called from the
outside of the class, you could make it 'private' (so it can be
accessible only inside CAboutDlg class), or 'protected' (so it can be
accessible inside CAboutDlg class and classes derived from it).


> BOOL CAboutDlg::OnInitDialog( )
> { //** Class Wizard added base call ** //
> CDialog::OnInitDialog( );
>
> //** being added code //
> SetVersionString( ); // format the CString
> HWND hDlg = m_CtrlStaticVer.GetSafeHwnd( );
>
> //** Question 1.
> //** here I used the API SetWindowText to get a return, the
> // MFC SetWindowText was a void return, Is this a big deal ?
>
> BOOL bResult = ::SetWindowText(hDlg, m_strVersion);

Frankly speaking, in MFC code I've always used CWnd::SetWindowText
method (not the global raw Win32 API ::SetWindowText).

e.g. considering the m_CtrlStaticVer control class, I would just write:

m_CtrlStaticVer.SetWindowText( someString );

However, you are right that the return value of ::SetWindowText is lost
in this case.

In VC10 (VS2010), the implementation of CWnd::SetWindowText is like this:

<code>

void CWnd::SetWindowText(LPCTSTR lpszString)
{
ENSURE(this);
ENSURE(::IsWindow(m_hWnd) || (m_pCtrlSite != NULL));

if (m_pCtrlSite == NULL)
::SetWindowText(m_hWnd, lpszString);
else
m_pCtrlSite->SetWindowText(lpszString);
}

</code>

So, the return value of ::SetWindowText is just discarded.
I would have preferred a method returning BOOL, to better wrap the raw
Win32 ::SetWindowText.

Note that ATL's CWindow::SetWindowText() correctly returns a BOOL, so it
is a better wrapper to ::SetWindowText:

http://msdn.microsoft.com/en-us/library/wfaxc8w5(VS.80).aspx

>
> //**Question 2
> //** Class Wizard put below return in ? when I had planned to return the
> //** the result of the SetWindow, Can you explain what this is all about ?
>
> return TRUE; // return TRUE unless you set the focus to a control
> // EXCEPTION: OCX Property Pages should return FALSE
> }

When you use a framework like MFC, it is better to follow the rules of
this framework, as indicated by the comments introduced by the MFC Wizard.

Note also that OnInitDialog method wraps the WM_INITDIALOG Win32
message, and in the "Return Value" paragraph you can read:

http://msdn.microsoft.com/en-us/library/ms645428(VS.85).aspx

<quote>

The dialog box procedure should return TRUE to direct the system to set
the keyboard focus to the control specified by wParam. Otherwise, it
should return FALSE to prevent the system from setting the default
keyboard focus.

</quote>


Giovanni

RB

unread,
Jun 14, 2010, 9:38:50 AM6/14/10
to
> void CWnd::SetWindowText(LPCTSTR lpszString)
> {
> ENSURE(this);
>............

Oh I see, I was also later stepping thru it and began to have
a hunch this was the case. So the importance of the return
is dimished quite a bit being that a failure is handled within.

> Note that ATL's CWindow::SetWindowText() correctly returns a BOOL, so it is a better wrapper to ::SetWindowText:

I will check out the link, I had wondered about CWindow class,
was curious why MFC would seemingly have two classes to do
much of the same stuff, but never really investigated it enough to
even know what was the story. Thanks for the info.

> When you use a framework like MFC, it is better to follow the rules of this framework, as indicated by the comments introduced by
> the MFC Wizard.
> Note also that OnInitDialog method wraps the WM_INITDIALOG Win32 message, and in the "Return Value" paragraph you can read:

> The dialog box procedure should return TRUE to direct the system to set the keyboard focus to the control specified by wParam.
> Otherwise, it should return FALSE to prevent the system from setting the default keyboard focus.

Well yes I should have thought of that being that it is a class handler it
has it's own adjenda rather than me implementing mine on it's return.
I should have thought to wrap the call to SetWindowText and then
deal with my return accordingly before letting OnInitDialog deal with
it's own adjenda. That was stupid on my part but none the less always
glad to hear words of wisdom from experience.
This could be the last correspondence I will experience on this group
(only time will tell ) but I appreciate all you guys have helped me on,
and hopefully I can get my NNTP set up so the forums won't be so
cryptic. RB


RB

unread,
Jun 14, 2010, 9:59:33 AM6/14/10
to
Thanks Joe, another novice stupid move on my part. One
thing about me, I am not afraid to screw up in order to move
forward.
But in reference to the dangerous code that you so informatively
detailed, I have rectified it (with the help of Giovanni ) and it is
now working great and I have learned another facet of programming
that hopefully will stick with me enough not to do it again. In
retrospect I had a hunch previously that much of what you said was
the case from remembering long ago when I tried writing small simple
API apps that had child windows.
This has taught me that I am leaning too much on what is visually
available in the Class Wizard rather than having the foresight to
have looked in the docs for CDialog class I would have found
in the OnInitDialog class member text, clearly showing that it
was the function I was needing. Even though I have my VS2005
now, I still do my experimentations in VC6 since I am so used to
it. But this is yet another reason to move on even in that facet.
If I don't see you on this group again, thanks ever so much for all
your help. RB


Giovanni Dicanio

unread,
Jun 14, 2010, 10:35:12 AM6/14/10
to
On 14/06/2010 15:38, RB wrote:

>> Note that ATL's CWindow::SetWindowText() correctly returns a BOOL, so it is a better wrapper to ::SetWindowText:
>
> I will check out the link, I had wondered about CWindow class,
> was curious why MFC would seemingly have two classes to do
> much of the same stuff, but never really investigated it enough to
> even know what was the story. Thanks for the info.

Actually, CWindow is an ATL class, completely different from CWnd.
CWindow is an inexpensive class to create: it's just a wrapper around an
HWND data member (instead, MFC maintains maps between HWND's and CWnd's...).
Moreover, when an instance of CWindow goes out of scope, the associated
window is *not* destroyed.

The spirit of ATL is different from the spirit of MFC: ATL is a more
thin wrapper around Win32 APIs, heavily uses templates, is leaner than
MFC, supports COM programming very well, etc.

There is a project called WTL which started internally in Microsoft and
then went open-source, that is built upon ATL, and offers several C++
wrapper classes to several Windows controls.


> That was stupid on my part

When you try to learn something there is nothing stupid about it :)


> This could be the last correspondence I will experience on this group
> (only time will tell ) but I appreciate all you guys have helped me on,
> and hopefully I can get my NNTP set up so the forums won't be so
> cryptic. RB

This newsgroup seems still active :)


Giovanni

Joseph M. Newcomer

unread,
Jun 14, 2010, 11:43:16 AM6/14/10
to
See below...

On Mon, 14 Jun 2010 09:38:50 -0400, "RB" <NoMail@NoSpam> wrote:

>> void CWnd::SetWindowText(LPCTSTR lpszString)
>> {
>> ENSURE(this);
>>............
>
>Oh I see, I was also later stepping thru it and began to have
>a hunch this was the case. So the importance of the return
>is dimished quite a bit being that a failure is handled within.
>
>> Note that ATL's CWindow::SetWindowText() correctly returns a BOOL, so it is a better wrapper to ::SetWindowText:
>
>I will check out the link, I had wondered about CWindow class,
>was curious why MFC would seemingly have two classes to do
>much of the same stuff, but never really investigated it enough to
>even know what was the story. Thanks for the info.

****
CWnd is the MFC class

CWindow is the ATL class

CWindow is a stripped-down lightweight class for use in ActiveX controls (primarily in
ActiveVIrus controls, those controls whose purpose in life is to be blocked by
intelligently-configured browsers)

You would not use CWindow in an MFC app.
****


>
>> When you use a framework like MFC, it is better to follow the rules of this framework, as indicated by the comments introduced by
>> the MFC Wizard.
>> Note also that OnInitDialog method wraps the WM_INITDIALOG Win32 message, and in the "Return Value" paragraph you can read:
>> The dialog box procedure should return TRUE to direct the system to set the keyboard focus to the control specified by wParam.
>> Otherwise, it should return FALSE to prevent the system from setting the default keyboard focus.
>
>Well yes I should have thought of that being that it is a class handler it
>has it's own adjenda rather than me implementing mine on it's return.

****
All methods designed by the framework are designed with the frameworks's "agenda" in mind.
Note that this also means that in a raw Win32 app (using windows but no MFC), that the
return value from the WM_INITDIALOG message is what the Windows framework defines it to
be, and has nothing to do with your wishes. In fact, the resturn value (or lack thereof)
for EVERY WM_, EM_, CB_, etc. message is predefined by the Windows framework!

The CDialog::OnInitDialog virtual method you override is just a reflection of the deep
functionality of the WM_INITDIALOG message, and corresponds to its requirements. It
doesn't care at all about yours, since you will never see the return value from
OnInitDialog (only the dialog box framework, an integral part of Windows, sees it)
****


>I should have thought to wrap the call to SetWindowText and then
>deal with my return accordingly before letting OnInitDialog deal with
>it's own adjenda.

****
You are clearly confused about "agendas" here. The "agenda" on WM_INITDIALOG is to allow
YOU to do what YOU want with the controls in the dialog. As such, it is not issued until
all the controls are created. The CDialog::OnInitDialog virtual method reflects this
functionality. Note that the root CDiallog::OnInitDialog calls the virtual method
DoDataExchange, and your virtual DoDataExchange method calls the parent class's
DoDataExchange, and so on up the line (this allows one dialog to derive from another!).
DoDataExchange, knowing that the controls now exist (a guarantee), will bind the controls
to the variables.

So I'm not sure what "agenda" is going on here. It *specifically* exists to allow you to
implment "your agenda".
joe
****


> That was stupid on my part but none the less always
>glad to hear words of wisdom from experience.
>This could be the last correspondence I will experience on this group
>(only time will tell ) but I appreciate all you guys have helped me on,
>and hopefully I can get my NNTP set up so the forums won't be so
>cryptic. RB
>

Joseph M. Newcomer

unread,
Jun 14, 2010, 11:46:20 AM6/14/10
to
As I pointed out, VS2005 erroneously maintains the "public" nature of control variables
(although you *can* change it, most people don't know they *should*) and of handlers (you
are not given a option to change their visibility, a fudnamental design error, given they
are erroneously marked 'public'). I always hand-edit my .h files to lump the handlers
together (in a 'protected' area), lump the variables together (in a 'protected' area,
often in alphabetical order), and so on, instead of taking the horrible misorganization
the new tools seem to think would be acceptable.
joe

RB

unread,
Jun 14, 2010, 5:39:33 PM6/14/10
to

> ****
> CWnd is the MFC class
> CWindow is the ATL class
> CWindow is a stripped-down lightweight class for use in ActiveX controls
> (primarily in ActiveVIrus controls, those controls whose purpose in life is to
> be blocked by intelligently-configured browsers)
> You would not use CWindow in an MFC app.
> ****

Thank you, I will note that.

> You are clearly confused about "agendas" here. The "agenda" on
> WM_INITDIALOG is to allow YOU to do what YOU want with the controls
> in the dialog. As such, it is not issued until all the controls are created. The
> CDialog::OnInitDialog virtual method reflects this functionality. Note that the
> root CDiallog::OnInitDialog calls the virtual method DoDataExchange, and your

> ..................................


> So I'm not sure what "agenda" is going on here. It *specifically* exists to allow
> you to implment "your agenda".
> joe
> ****

Thanks again for the elaboration. I was attempting to describe my confused state
on using the return of OnInitDialog for my return value. Apologize for ambiguity
on my part in doing so. I do understand that I had the whole return idea wrong.
RB

JCO

unread,
Jun 14, 2010, 7:54:46 PM6/14/10
to
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" <giovanniD...@REMOVEMEgmail.com> wrote in message
news:eg3hiCyC...@TK2MSFTNGP02.phx.gbl...

RB

unread,
Jun 14, 2010, 10:09:09 PM6/14/10
to

"JCO" 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.

Well I think I can show you that part since it does work on my
App. See code at bottom.

> 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?

I will let Giovanni respond to that since I am used to using an old version
of VS that does not (that I am aware of ) do this.

----pasted pertinant code to version going to Exe (and any DLLs) on build
I put the below into my AppVer.h file. This is the one source for version data.
Include this file in each file that needs access to version data



// Stringisation.
// (Two steps needed).

#define _STR(x) #x
#define STR(x) _STR(x)

// The following are used as defined quantities


// in the versioninfo resource:

#define VERMAJ 1


#define VERMIN 0
#define VERFIX 0

#define BUILDNUMBER 0

#define VERMAJSTR STR( VERMAJ )
#define VERMINSTR STR( VERMIN )
#define VERFIXSTR STR( VERFIX )
#define BUILDSTR STR( BUILDNUMBER )
#define VERSIONSTRING VERMAJSTR "." VERMINSTR "." VERFIXSTR "." BUILDSTR
#define PRODUCTSTRING VERMAJSTR "." VERMINSTR "." VERFIXSTR "." BUILDSTR

#define CORP_NAME "RBC" // used in file serialize data
#define CPY_RIGHT_YR "Copyright (C) 2010" // used in CAbout dialog
// along with VERSIONSTRING

----Now as to the Exe properties part, what I did was look in my AppWizard
generated rc file, and cut out the CAbout dialog defined section, and then paste
it into rc2 file, i.e.

/////////in my rc2 file///////////////////////////////////
// Add manually edited resources here...

#include "AppVer.h" // this is the one version source

// From here down was cut out of Project rc file and then pasted here
// and then edited to receive the defines from the AppVer.h file
// See edits below

#ifndef _MAC

VS_VERSION_INFO VERSIONINFO
//--in the original rc file section this used to be
// FILEVERSION 1,0,0,1 --//
FILEVERSION VERMAJ,VERMIN,VERFIX, BUILDNUMBER


PRODUCTVERSION VERMAJ,VERMIN,VERFIX, BUILDNUMBER
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L

#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN

VALUE "CompanyName", CORP_NAME "\0" //*EDITED


VALUE "FileDescription", "FileHandling MFC Application\0"

VALUE "FileVersion", VERSIONSTRING "\0" //*EDITED


VALUE "InternalName", "FileHandling\0"

VALUE "LegalCopyright", CPY_RIGHT_YR "\0" //*EDITED


VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "FileHandling.EXE\0"
VALUE "ProductName", "FileHandling Application\0"

VALUE "ProductVersion", PRODUCTSTRING "\0" //*EDITED


END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // !_MAC

---The above will show in the properties when you right click on exe.
Note I had to leave a space between the DEFINE and the NULL
i.e. VERSIONSTRING "\0" and not VERSIONSTRING"\0"
or I got a " in the output. I choose to keep the "\0" separate from the
#defines since I used some of them later for sting literal initalizers.
Otherwise I guess you could include it in the define.

Giovanni Dicanio

unread,
Jun 15, 2010, 5:15:00 AM6/15/10
to

On 15/06/2010 01:54, JCO wrote:

> 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?

Are you thinking of something like this?

http://www.codeproject.com/KB/dotnet/build_versioning.aspx

Giovanni

Giovanni Dicanio

unread,
Jun 15, 2010, 5:20:29 AM6/15/10
to
On 14/06/2010 17:43, Joseph M. Newcomer wrote:

> CWindow is the ATL class
>
> CWindow is a stripped-down lightweight class for use in ActiveX controls (primarily in
> ActiveVIrus controls, those controls whose purpose in life is to be blocked by
> intelligently-configured browsers)

You can use CWindow to wrap any HWND's.
ATL was originally designed to build lightweight (quickly downloadable
from the web, and not requiring MFC DLL's) ActiveX controls, but then it
evolved in a small and fast template-based library for Win32 and COM
programming.

Giovanni

RB

unread,
Jun 15, 2010, 8:42:54 AM6/15/10
to

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

unread,
Jun 15, 2010, 9:52:44 AM6/15/10
to
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

Joseph M. Newcomer

unread,
Jun 15, 2010, 9:56:28 AM6/15/10
to
See below...

On Mon, 14 Jun 2010 22:09:09 -0400, "RB" <NoMail@NoSpam> wrote:

>
>"JCO" 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.
>
>Well I think I can show you that part since it does work on my
>App. See code at bottom.
>
>> 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?

****
This has been a gross oversight which I first complained about in the early 1990s, and
Microsoft has done NOTHING to provide a build-number incrementer (although it would be
easy enough to do as an integrated component of VS). I wrote my own build number
incrementer some years ago and you can find it on my MVP Tips site. We still don't have
it in VS2010, which means it has been something they have been aware of for over 15 years
and have still done NOTHING to fix, in spite of the demand of users.
joe
****

JCO

unread,
Jun 15, 2010, 1:24:05 PM6/15/10
to
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@NoSpam> wrote in message

news:umG$MhIDLH...@TK2MSFTNGP05.phx.gbl...

RB

unread,
Jun 15, 2010, 2:36:55 PM6/15/10
to

> "JCO" wrote in message
> 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

Well again, I am only a novice speculating, but when you say you added
this information,
Did you cut out the About Dialog segment of your rc file (so that it is
gone from that file) and then paste that exact cut into your rc2 file ?
Then try to compile, if all goes well then include your AppVer.h
file into the rc2 file, and hand edit the items in rc2 file you desire
to reflect from the header file. If you do them one at a time you should
be able to see what is causing the problem.
Also I did this using VC6 your version may have a different format
or order of items in the rc file, but none the less if you paste the
exact cut into the rc2 file and work from there you should be able
to decipher what you need. I remember David Webber said in his
version there was another way to get at the rc file text, in mine I had
to open it in notepad, which he said sometimes can cause problems
but my VC later just says it has been changed do I want to reload it,
I choose yes. I don't know of any other way to edit my version.
Good luck with it. It works great for me, I really like the setup
RB

JCO

unread,
Jun 15, 2010, 2:44:23 PM6/15/10
to

I understand the items that are added to the .rc2 file, however, are you
suppose to also edit the .rc file by commenting out everything listed under
"Version"?


"RB" <NoMail@NoSpam> wrote in message
news:umG$MhIDLH...@TK2MSFTNGP05.phx.gbl...

RB

unread,
Jun 15, 2010, 3:05:22 PM6/15/10
to
> I understand the items that are added to the .rc2 file, however,
> are you suppose to also edit the .rc file by commenting out
> everything listed under "Version"?

Yes, and sorry I said CAbout Dialog segment earlier. Actually
at first I cut and pasted the Dialog segement also and it worked
but I lost my ability to see and edit it's other aspects in the
resource editor so I pasted it back and it held next time
VS rewrote it.
But anyhow yes the version segment, but in my VS I cannot
comment out rc file segments since the VS writes (and rewrites )
the entire file. So I cut the version segment out totally and pasted it
into the rc2 file. See other reply (but ignore dialog segment and
use version)
If your VS allows you to comment in the rc file then yea you could
do that, but unless things changed with the newer VS that file belongs
to the VS so I would think that anything you were allowed to comment
would be gone next time VS rewrote it
RB


JCO

unread,
Jun 15, 2010, 5:15:28 PM6/15/10
to

When I delete the VERSION in the .rc, I get the following link errors:

Error 1 error LNK2019: unresolved external symbol _GetFileVersionInfoW@16
referenced in function "public: void __thiscall
CAppVersionDynamicDlg::OnBnClickedButton1(void)"
(?OnBnClickedButton1@CAppVersionDynamicDlg@@QAEXXZ) AppVersionDynamicDlg.objAppVersionDynamicError 2 fatal error LNK1120: 1 unresolved externals E:\My
C++\AppVersionDynamic\AppVersionDynamic\Debug\AppVersionDynamic.exeAppVersionDynamicIf I don't remove anything from the .rc file, I get the other two errors I
posted earlier.
Sorry this isn't working for me. I'm not that experienced in this stuff
either.
Thanks

"RB" <NoMail@NoSpam> wrote in message

news:eI1w22LD...@TK2MSFTNGP05.phx.gbl...

JCO

unread,
Jun 15, 2010, 5:32:42 PM6/15/10
to
Yes I got it to work. I had some code in the cpp file that was causing the
link error.
I will review what I have done now.. but everything seems okay and works.

"RB" <NoMail@NoSpam> wrote in message

news:eI1w22LD...@TK2MSFTNGP05.phx.gbl...

David Webber

unread,
Jun 15, 2010, 5:26:33 PM6/15/10
to


"JCO" <som...@somewhere.com> wrote in message
news:Oigi3zBD...@TK2MSFTNGP02.phx.gbl...

> 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.

#define VERMAX 3

causes VERMAX to be replaced by 3 before compilation of the exe, so of
course it is the same in the "property" dialoge.

> 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?

Haven't tried it. I only update my build number when making it available to
3rd parties, and I do that manually. It's good enough for my purposes.

David Webber

unread,
Jun 15, 2010, 5:29:15 PM6/15/10
to


"JCO" <som...@somewhere.com> wrote in message

news:#cDkO#KDLHA...@TK2MSFTNGP02.phx.gbl...

> 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

If you left the VERSIONINFO in the rc file AND pasted in the rc2 file, then
you have it twice. That might be what error 1 is telling you.

JCO

unread,
Jun 15, 2010, 7:03:34 PM6/15/10
to
Agreed!

"David Webber" <da...@musical-dot-demon-dot-co.uk> wrote in message
news:O#VF20NDL...@TK2MSFTNGP05.phx.gbl...

JCO

unread,
Jun 15, 2010, 7:14:48 PM6/15/10
to

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
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

//Use GetFileVersionInfo() to get file information
TCHAR szExePath[MAX_PATH];
::GetModuleFileName( NULL, szExePath, MAX_PATH );

DWORD dwDummy;
DWORD dwFVISize = GetFileVersionInfoSize( szExePath, &dwDummy );

LPBYTE lpVersionInfo = new BYTE[dwFVISize];
GetFileVersionInfo( szExePath , 0 , dwFVISize , lpVersionInfo );

if( lpVersionInfo )
delete lpVersionInfo;

VS_FIXEDFILEINFO *lpFfi;
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@16
referenced in function "public: void __thiscall

CAppVersionDynamicDlg::OnBnClickedButtonVersion(void)"
(?OnBnClickedButtonVersion@CAppVersionDynamicDlg@@QAEXXZ)AppVersionDynamicDlg.obj AppVersionDynamicError 2 error LNK2019: unresolved external symbol _GetFileVersionInfoSizeW@8

referenced in function "public: void __thiscall

CAppVersionDynamicDlg::OnBnClickedButtonVersion(void)"
(?OnBnClickedButtonVersion@CAppVersionDynamicDlg@@QAEXXZ)AppVersionDynamicDlg.obj AppVersionDynamic"Joseph M. Newcomer" <newc...@flounder.com> wrote in message
news:cc1f16hsn3lejfmtp...@4ax.com...

RB

unread,
Jun 15, 2010, 7:21:05 PM6/15/10
to
> "JCO" wrote
> Yes I got it to work. I had some code in the cpp file that was causing the
> link error. I will review what I have done now.. but everything seems
> okay and works.

Good I think you will find it convenient. If you work it right you
only have to edit the header file when anything changes and then
the rest updates itself on compile.
Remember to always keep spaces between items and the quotation
marks or you will end up seeing quotations in the output.
See comment below,
===========================================
//--in your version header file


#define _STR(x) #x
#define STR(x) _STR(x)

#define VERMAJ 1
#define VERMIN 0
#define VERFIX 0

#define BUILDNUM 0
#define YR 2010

#define V_MA_STR_LIT STR( VERMAJ )
#define V_MI_STR_LIT STR( VERMIN )
#define V_FX_STR_LIT STR( VERFIX )
#define B_N_STR_LIT STR( BUILDNUM )
#define YR_STR_LIT STR( YR )

// must leave space between items and the quotation marks or you will end up seeing quotations in the output.
#define VERSTR V_MA_STR_LIT "." V_MI_STR_LIT "." V_FX_STR_LIT "." B_N_STR_LIT "\0"
#define CPY_RT_YR_STR_LITERAL "Copyright (C) " YR_STR_LIT

===============================================
//----and reflected in your rc2 file------//
#include "YourVersion.h"

VS_VERSION_INFO VERSIONINFO
FILEVERSION VERMAJ, VERMIN, VERFIX, BUILDNUM
PRODUCTVERSION VERMAJ, VERMIN, VERFIX, BUILDNUM
...........
..................
VALUE "FileVersion", VERSTR
................

===============================================
//----and in your About Dialog------//
#include "YourVersion.h"

class CAboutDlg : public CDialog
{
........
private:
void SetVerStr( );
CString m_strVersion, m_strCpyRightYr ;
........
}

void CAboutDlg::SetVerStr( )
{
m_strVersion.Format( _T(" Version %d.%d.%d.%d"), VERMAJ, VERMIN, VERFIX, BUILDNUM );
m_strCpyRightYr = _T(CPY_RT_YR_STR_LITERAL);
}

BOOL CAboutDlg::OnInitDialog( )
{
CDialog::OnInitDialog( );
SetVerStr();
m_CtrlStaticVer.SetWindowText( m_strVersion );
m_CtrlStaticCr.SetWindowText( m_strCpyRightYr );
return TRUE;
}

=====================================
//-----and in your DocClass constructor--//
#include "YourVersion.h"

CFileHandlingDoc::CFileHandlingDoc( )
{ // These are CStrings in a Version Struct
VerData.Ver.Format( _T("Version %d.%d.%d.%d"), VERMAJ, VERMIN, VERFIX, BUILDNUM );
VerData.CpyRt = _T(CPY_RT_YR_STR_LITERAL);
}

//----and in your DocClass serialize function----//

void CFileHandlingDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring( ))
{
............
ar << VerData.Ver << VerData.CpyRt;
............
}
else
{
............
ar >> VerData.Ver >> VerData.CpyRt;
............
}
}

Joseph M. Newcomer

unread,
Jun 15, 2010, 11:57:28 PM6/15/10
to
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" <som...@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@16
>referenced in function "public: void __thiscall
>CAppVersionDynamicDlg::OnBnClickedButtonVersion(void)"
>(?OnBnClickedButtonVersion@CAppVersionDynamicDlg@@QAEXXZ)AppVersionDynamicDlg.obj AppVersionDynamicError 2 error LNK2019: unresolved external symbol _GetFileVersionInfoSizeW@8
>referenced in function "public: void __thiscall
>CAppVersionDynamicDlg::OnBnClickedButtonVersion(void)"
>(?OnBnClickedButtonVersion@CAppVersionDynamicDlg@@QAEXXZ)AppVersionDynamicDlg.obj AppVersionDynamic"Joseph M. Newcomer" <newc...@flounder.com> wrote in message
>news:cc1f16hsn3lejfmtp...@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
****

Joseph M. Newcomer

unread,
Jun 16, 2010, 12:04:05 AM6/16/10
to
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

Joseph M. Newcomer

unread,
Jun 16, 2010, 12:05:43 AM6/16/10
to
See below...

On Tue, 15 Jun 2010 13:44:23 -0500, "JCO" <som...@somewhere.com> wrote:

>
>I understand the items that are added to the .rc2 file, however, are you
>suppose to also edit the .rc file by commenting out everything listed under
>"Version"?

****
I have no idea what you mean by "commenting out everything listed under "Version". What
you need to do is DELETE the version resource from the .rc file. Highlight it in the tree
describing the resources and use the "delete" key, just like you would do in deleting any
other kind of resource.

Commenting something out is not a relevant concept here. Deleting it is what you want to
do!
joe

>
>
>"RB" <NoMail@NoSpam> wrote in message
>news:umG$MhIDLH...@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

unread,
Jun 16, 2010, 12:07:34 AM6/16/10
to
See below...

On Tue, 15 Jun 2010 16:15:28 -0500, "JCO" <som...@somewhere.com> wrote:

>
>When I delete the VERSION in the .rc, I get the following link errors:
>
>Error 1 error LNK2019: unresolved external symbol _GetFileVersionInfoW@16
>referenced in function "public: void __thiscall

****
RTFM. You did not include version.lib in the link! This is trivial to fix. You really,
really need to understand what "undefined symbol" means. It means it can't figure out
what the symbol means, because no library has that symbol defined in it. So figure out
what library DOES have that symbol defined, and add it to the link.

Fortunately, this is trivial, because every API call tells you *exactly* what library it
is found in!
joe
****

Giovanni Dicanio

unread,
Jun 16, 2010, 5:38:26 AM6/16/10
to
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

RB

unread,
Jun 16, 2010, 8:24:59 AM6/16/10
to
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"

Joseph M. Newcomer

unread,
Jun 16, 2010, 10:03:29 AM6/16/10
to
See below...

On Wed, 16 Jun 2010 11:38:26 +0200, Giovanni Dicanio
<giovanniD...@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

JCO

unread,
Jun 16, 2010, 10:21:25 AM6/16/10
to
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" <newc...@flounder.com> wrote in message

news:i7jg165ugb9uba3ne...@4ax.com...

JCO

unread,
Jun 16, 2010, 10:57:02 AM6/16/10
to

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" <newc...@flounder.com> wrote in message

news:crhg1652u574iem3g...@4ax.com...

JCO

unread,
Jun 16, 2010, 11:27:44 AM6/16/10
to
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" <giovanniD...@REMOVEMEgmail.com> wrote in message

news:#TsHxeTD...@TK2MSFTNGP06.phx.gbl...

Giovanni Dicanio

unread,
Jun 16, 2010, 11:34:03 AM6/16/10
to

On 16/06/2010 17:27, JCO wrote:

> 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);

What kind of exceptions?

Giovanni

Joseph M. Newcomer

unread,
Jun 16, 2010, 3:59:23 PM6/16/10
to
See below...

On Wed, 16 Jun 2010 10:27:44 -0500, "JCO" <som...@somewhere.com> wrote:

>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);

****
It had better throw exceptions! That's what it is SUPPOSED to do! You have an
UNINITIALIZED pointer variable lpFfi. I already pointed out, you did not initialize it,
but you are using it, and therefore it is the value 0xCCCCCCCC and this SHOULD cause
exceptions!

Initialize your variable! I gave you the code to do it!
joe
****


>
>
>"Giovanni Dicanio" <giovanniD...@REMOVEMEgmail.com> wrote in message
>news:#TsHxeTD...@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

Joseph M. Newcomer

unread,
Jun 16, 2010, 4:04:16 PM6/16/10
to
Read The F---ing Manual. This abbreviation was old in the 1970s.

Every page that describes an API tells you what library needs to be linked in. Some are
linked in by default; others you have to expressly include it.

If you get an undefined symbol, it means that some component that defines that symbol is
not linked in. If it is a library, of any kind, you will have to add the library to the
linker specification. Many APIs require you explicitly link a library in. In addition to
adding the explicit linker option, you can add, to your source

#pragma comment(lib, "XXXXX.lib")

except for the filename, this is all case-sensitive.
joe

Joseph M. Newcomer

unread,
Jun 16, 2010, 4:06:43 PM6/16/10
to
There is no such thing as "an" assertion error. Every assertion error tells you precisely
which file it occurred in, and precisely what line of that file it occurred on. Coupled
with the knowledge of which version of VS you are using, these three pieces of information
tell us what went wrong. In the *absence* of these three pieces of information, there is
no solution to the problem.

Did you enter the debugger? What did the ASSERT line say?
joe

JCO

unread,
Jun 19, 2010, 1:32:06 AM6/19/10
to
Error 1:
Debug Assertion Failed!
Program: ........ name of program
File: f:\dd\vcctools\vc7libs\ship\atlmfc\src\mfc\winocc.cpp
Line: 246

This is line 246:
ENSURE(::IsWindow(m_hWnd) || (m_pCtrlSite != NULL));


"Joseph M. Newcomer" <newc...@flounder.com> wrote in message

news:sibi16puh8g12a8sc...@4ax.com...

Joseph M. Newcomer

unread,
Jun 19, 2010, 10:28:41 AM6/19/10
to
See below....

On Sat, 19 Jun 2010 00:32:06 -0500, "JCO" <som...@somewhere.com> wrote:

>Error 1:
>Debug Assertion Failed!
>Program: ........ name of program
>File: f:\dd\vcctools\vc7libs\ship\atlmfc\src\mfc\winocc.cpp
>Line: 246
>
>This is line 246:
> ENSURE(::IsWindow(m_hWnd) || (m_pCtrlSite != NULL));
>

****
So what are the values of m_hWnd and m_pCtrlSite? This is in SetWindowText, so you need
to show us where you are calling it, not just the line, but the context!

Are you calling SetWindowText of a dialog before the DoModal()? This cannot POSSIBLY work
bcause until the DoModal is executed, there IS NO WINDOW to set the text to.

For example

CWhatever dlg;
dlg.m_Name.SetWindowText(s);
dlg.DoModal();

cannot work. In fact, BEFORE the DoModal, there is no dialog (hence no window) and AFTER
the DoModal there is no dialog (hence no window). The ONLY valid place you can do this
SetWindowText is in, or after the execution of, OnInitDialog. Until
CWhatever::OnInitDialog is executed, there is no control (if you don't have an
OnInitDialog, then CDialog::OnInitDialog is going to get called, and the same applies)
joe
*****

JCO

unread,
Jun 21, 2010, 5:33:30 PM6/21/10
to
m_hWnd and mPCtrlSite are both NULL

Yes that is my mistake which I assumed was the case from the start. I was
calling to make the static control change before I have a window. Yes I
called SetWindowText() in the CAboutDlg::OnInitDialog().

I'm not sure where to call it? It has to be called right after the dialog
is displayed.


"Joseph M. Newcomer" <newc...@flounder.com> wrote in message

news:1jkp16d871giu2sml...@4ax.com...

Joseph M. Newcomer

unread,
Jun 23, 2010, 1:29:50 PM6/23/10
to
Note that if you added an OnInitDialog handler, you code must follow the
CDialog::OnInitDialog();
call at the front, because until that is executed, there is no control binding. And if
this call is missing, you will have to add it!
joe
0 new messages