【问题标题】:MFC ON_WM_TIMER() issue with static cast静态转换的 MFC ON_WM_TIMER() 问题
【发布时间】:2012-09-14 09:01:18
【问题描述】:

在我的扩展 CWinApp 的类 CDatabaseApplicationApp 中遇到 ON_WM_TIMER 问题

> 1>c:\programs\databaseapplication\databaseapplication\databaseapplication.cpp(20):
> error C2440: 'static_cast' : cannot convert from 'void (__thiscall
> CDatabaseApplicationApp::* )(UINT_PTR)' to 'void (__thiscall CWnd::*
> )(UINT_PTR)' 1>          Types pointed to are unrelated; conversion
> requires reinterpret_cast, C-style cast or function-style cast

我已经包含了函数OnTimer

class CLifescanDatabaseApplicationApp : public CWinApp
{
public:
    CLifescanDatabaseApplicationApp();
protected:
    CLifescanDatabaseApplicationDlg * m_ptheWindow;
// Overrides
public:
    virtual BOOL InitInstance();

// Implementation
    afx_msg void OnTimer(UINT_PTR nTimerID);
    DECLARE_MESSAGE_MAP()
};

OnTimer 只是:

void CDatabaseApplicationApp::OnTimer(UINT_PTR nTimerID)
{
    AfxMessageBox(_T("Help"));
}

使用源文件顶部的定义设置计时器:

#define ID_TIMER_DATABASEQUERY 1

SetTimer

中定义
BOOL CDatabaseApplicationApp::InitInstance()
{
    // InitCommonControlsEx() is required on Windows XP if an application
    // manifest specifies use of ComCtl32.dll version 6 or later to enable
    // visual styles.  Otherwise, any window creation will fail.
    INITCOMMONCONTROLSEX InitCtrls;
    InitCtrls.dwSize = sizeof(InitCtrls);
    // Set this to include all the common control classes you want to use
    // in your application.
    InitCtrls.dwICC = ICC_WIN95_CLASSES;
    InitCommonControlsEx(&InitCtrls);

    CWinApp::InitInstance();


    AfxEnableControlContainer();
AfxInitRichEdit2();
    // Create the shell manager, in case the dialog contains
    // any shell tree view or shell list view controls.
    CShellManager *pShellManager = new CShellManager;

    // Standard initialization
    // If you are not using these features and wish to reduce the size
    // of your final executable, you should remove from the following
    // the specific initialization routines you do not need
    // Change the registry key under which our settings are stored
    // TODO: You should modify this string to be something appropriate
    // such as the name of your company or organization
    SetRegistryKey(_T("Local AppWizard-Generated Applications"));



    m_ptheWindow = new CDatabaseApplicationDlg();
    m_pMainWnd = m_ptheWindow;
    if(m_ptheWindow!=nullptr)
    {
        m_ptheWindow->Create(CDatabaseApplicationDlg::IDD,CWnd::GetDesktopWindow());
        m_ptheWindow->ShowWindow(SW_SHOW);
    }
    // Delete the shell manager created above.
    if (pShellManager != NULL)
    {
        delete pShellManager;
    }

    if(!m_ptheWindow->SetTimer(ID_TIMER_DATABASEQUERY,10000,nullptr))
    {
        return false;
    }
    // Since the dialog has been closed, return FALSE so that we exit the
    //  application, rather than start the application's message pump.
    return TRUE;
}

有什么办法可以解决这个问题吗?

【问题讨论】:

  • 这是真正的代码吗?您不会在 SetTimer 中使用OnTimer,任何地方都没有static_cast
  • 是的,它是真正的代码。不确定 SetTimer 中的 OnTimer 是什么意思,Prosise 书中的示例和互联网上的示例都有。
  • 编译器在 databaseapplication.cpp 的第 20 行抱怨 static_cast。这未显示在您提交的代码中。由于您没有在SetTimer 中指定回调,它将在您调用SetTimer 的类中调用OnTimer 方法,即CDatabaseApplicationDlg,因此您需要在那里覆盖OnTimer
  • 那么我如何在没有窗口的类上调用 SetTimer。你必须解释一个回调,因为我以前没有使用过,抱歉。
  • 我已经添加了答案。但是,我仍然不清楚static_cast 来自哪里。

标签: c++ mfc


【解决方案1】:

如果主窗口调用SetTimer

if(!m_ptheWindow->SetTimer(ID_TIMER_DATABASEQUERY,10000,nullptr))
 {
     return false;
 } 

OnTimer 覆盖可能应该在窗口类中(派生自 CWnd),而不是在应用程序类中。

【讨论】:

  • 应用程序只是一个无模式对话框,提供查询数据库的选项,但我不想在那里进行处理。我需要放入 m_PtheWindow-> 部分,或者它想要一个带有四个参数的 SetTimer,这没有意义。
  • “四参数版本”是 MFC 之外的 Win32 API。错误消息说它需要一个CWnd 成员函数,您可以从窗口类中获得它。可能,您可以让窗口的onTimer 函数将消息传递给应用程序类。 MFC 本身不想这样做。
【解决方案2】:

CWnd::SetTimer 将一个指向函数的指针作为最后一个参数,该函数将被调用以处理 WM_TIMER 消息(一个回调函数)。

如果此参数设置为 NULL,则将调用该窗口的 OnTimer 方法,这意味着您必须覆盖 CDatabaseApplicationDlg 类的 OnTimer 方法。

如果您不想这样做,则需要显式指定回调函数,即将调用其他一些函数来处理消息。这可以是全局函数或静态类成员。但是,非静态类成员不会开箱即用,因为成员函数指针并不是真正的指针,因此您需要将它们包装到其他东西中。

如果您的 CDatabaseApplication 类有一个 static 成员,例如:

void CDatabaseApplicationApp::OnTimer(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
{
   // in your case:
   // hWnd => HWND of your ID_TIMER_DATABASEQUERY instance
   // nMsg => WM_TIMER
   // nIDEvent => ID_TIMER_DATABASEQUERY, unless you also set other timers
   // dwTime => elapsed time, same as value of GetTickCount()
   AfxMessageBox(_T("Help"));
}

那么你可以像这样设置计时器:

m_ptheWindow->SetTimer(ID_TIMER_DATABASEQUERY, 10000, CDatabaseApplicationApp::OnTimer)

【讨论】:

  • 这不起作用;错误 C2664: 'CWnd::SetTimer' : 无法将参数 3 从 'void (__cdecl *)(UINT_PTR)' 转换为 'void (__stdcall *)(HWND,UINT,UINT_PTR,DWORD)' 1> 没有这个功能范围内的名称与目标类型匹配
  • 对不起,我太快了 :) SetTimer 采用与 Win API 签名兼容的回调,而不是 MFC 的。我已经更新了示例
  • 好的,通过移除所有ON_WM_TIMER()解决,将静态函数改为static void CALLBACK OnTimer(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);和 SetTimer 到 if(!::SetTimer(NULL,ID_TIMER_DATABASEQUERY,10000, CLifescanDatabaseApplicationApp::OnTimer)) 对你必须走一条非常复杂的路线才能让一些简单的工作变得不那么印象深刻。
  • 其实很简单——你只需要覆盖CWnd's OnTimer。您希望应用程序如何知道要调用所有不相关类中的哪个 OnTimer 方法?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-14
  • 2020-10-14
  • 1970-01-01
相关资源
最近更新 更多