A common error occurring when compiling a 64-bit application: error C2440, OnTimer

10.10.2012

One of the most common errors a programmer encounters when porting applications from a Win32 system to a Win64 one is the error related to the function OnTimer. The function OnTimer is used nearly in every application and you are likely to get some compilation errors. Earlier (in Visual Studio 6) this function had the prototype "OnTimer(UINT nIDEvent)" and is most likely to be present in user classes in the same form. Now this function has the prototype "OnTimer(UINT_PTR nIDEvent)" and it causes a compilation error for the 64-bit system.

Here is a standard example:

class CPortScanDlg : public CDialog
{
  ...
  afx_msg void OnTimer(UINT nIDEvent);
  ...
};
BEGIN_MESSAGE_MAP(CPortScanDlg, CDialog)
...
  ON_WM_TIMER()
END_MESSAGE_MAP()

For this code, at the stage of compilation the following error will be announced:

1>.\Src\Portscandlg.cpp(136) : error C2440: 'static_cast' :
cannot convert from 'void (__cdecl CPortScanDlg::* )(UINT)' to
'void (__cdecl CWnd::* )(UINT_PTR)'
1> Cast from base to derived requires dynamic_cast or static_cast

The point is that the function type is explicitly converted in the macro ON_WM_TIMER:

#define ON_WM_TIMER() \
{ WM_TIMER, 0, 0, 0, AfxSig_vw, \
  (AFX_PMSG)(AFX_PMSGW) \
  (static_cast< void (AFX_MSG_CALL CWnd::*)(UINT_PTR) > \
    ( &ThisClass :: OnTimer)) },

The conversion goes successfully when building the 32-bit version because the types UINT and UINT_PTR coincide. But in the 64-bit mode these are different types and the function type conversion is impossible and that leads to the compilation error which is not quite clear at first.

This error is rather easy to fix. You should change the definition of the function OnTimer in the user classes. Here is an example of the corrected code:

class CPortScanDlg : public CDialog
{
  ...
  afx_msg void OnTimer(UINT_PTR nIDEvent); //Fixed
  ...
};

Sometimes the function OnTimer is used in programs more than once.

We recommend you to search for the line "OnTimer(UINT " before compilation and replace it with "OnTimer(UINT_PTR ". You may also use "find and replace" function as shown in Figure 1.

Figure 1 - Using the function "Find and Replace" to correct the definitions of OnTimer functions

Figure 1 - Using the function "Find and Replace" to correct the definitions of OnTimer functions

But do not forget that in the both cases there must be a space at the end of the lines. Unfortunately, you cannot see this space in the figure. If there are no spaces, you will get "OnTimer(UINT_UINT_PTR nIDEvent)".