MFC MDI 函数调用与 SendMessage。 C 程序员试图理解一个基本概念
MFC MDI Function calling vs SendMessage. C programmer trying to understand a basic concept
作为高级硬件EE,我的大部分编程时间都使用C 进行固件和根据需要进行内联汇编。我一直在研究 MFC MDI,你们中的一些人已经很好地帮助了我。我正在创建一个设置对话框并离开菜单项以写入注册表以存储和检索应用程序 user settings
。我在星期天用谷歌搜索了六种方法来尝试理解基本的 "Calling a function from another .cpp file class"
和许多其他变体来得到我的答案......失败(主要是因为我可能不理解他们的答案)。
我有一个主程序重置,它会破坏我的应用程序创建的 HKEY_CURRENT_USER 密钥。效果很好,没有问题。现在,我不再将 "Settings"
菜单中的项目与 "Reset App"
项目一起移动到 property sheet/page dialogs
.
之一中的 button press
我可以使用它,但我不清楚为什么我最初关于如何执行它的想法失败了。
所以,在我的应用程序中,我触发了这个函数:
void CApplication::OnResetProgramSettings() //Truncated function for StackOF clarity
{
// ask the user
int DisableUserWarnings = FALSE;
if (DisableUserWarnings == FALSE) {
if (IDNO == AfxMessageBox(IDS_WARNING_RESET_APP, MB_ICONQUESTION | MB_YESNO))
return;
}
LSTATUS status = SHDeleteKey(HKEY_CURRENT_USER, _T("SOFTWARE\Trains"));
}
调用自:
BEGIN_MESSAGE_MAP(CApplication, CWinAppEx)
...other commands
ON_COMMAND(ID_SETTINGS_RESET_REGISTRY, OnResetProgramSettings)
...other commands
ON_UPDATE_COMMAND_UI(ID_SETTINGS_RESET_REGISTRY, OnUpdateOnResetProgramSettings)
END_MESSAGE_MAP()
为了在我的新 Dialog Settings
部分完成这项工作,我实施了这个:
void CSettingsReset::OnBnClickedButtonReset()
{
// Global reset
AfxGetMainWnd()->SendMessage(WM_COMMAND, ID_SETTINGS_RESET_REGISTRY);
//CApplication::OnResetProgramSettings();
//&CApplication::OnResetProgramSettings();
}
它的工作方式与我如上所述选择菜单项 "Reset App"
完全一样。
属性 页面称为 SettingsReset.cpp
,上面的内容位于 Application.cpp
。
在 C 语言环境中,我通常只调用包含在 SettingsReset.h
文件中的 application.h
的函数,如下所示:
OnResetProgramSettings();
我意识到这在 C++ 中的工作方式不同。您可以看到上面代码中注释掉的两个行项目,下面取消注释:
CApplication::OnResetProgramSettings(); //Doesn't get called, static error if memory serves
&CApplication::OnResetProgramSettings(); //Doesn't get called
CApplication OnResetProgramSettings; //Creates an object I don't want/need... or do I?
所以我发送AFX消息到"achieve"
相同的操作结果。我的最终问题是 "call"
Application.cpp 文件中的 OnResetProgramSettings()
FROM
SettingsReset.cpp
文件的正确方法是什么?我读过有关制作函数 "Static"
的信息,但我不清楚如何做到这一点 and/or 为什么......现在每个函数都有两个单独的处理程序......即。 OnResetProgramSettings()
和 OnResetProgramSettings1()
..对吗?
有没有一种方法可以做到这一点而不必使用 AFX 消息传递来触发该功能?
问题是 ON_UPDATE_COMMAND_UI
宏创建了一个私有(或受保护?)成员函数,在您的例子中是 CApplication::OnResetProgramSettings
。这意味着您不能直接从另一个 class 调用它(在您的情况下 CSettingsReset
)。
一种方法是像您一样通过 PostMessage
触发命令(除非您依赖 AfxGetMainWnd()
而不是在对话框构造函数中获取指向应用程序 class 的指针——如果您稍后更改主要 window 或使用系统通知图标等,这很容易出错。
另一种方法是移动 public class 中的功能,您 可以 直接调用,让 CApplication::OnResetProgramSettings
简单地调用新的功能。这样就避免了发送到消息队列的中间步骤。
当然,整个设计都被破坏了,所有这些实用的东西都应该从任何特定的 window class 中移出到一个专用服务 class 中,该服务封装了与任何相关的所有内容该注册表功能是,您的 windows 接收并使用指向该服务的指针 class。将其视为 MVVM 的过时的、错误的版本,因为您使用的是过时的技术 (MFC)。
您可以通过两种简单的方法从 'outside' 调用应用程序 class 的 non-static 成员函数 class.但它们本质上相同,因为您只需要通过实际应用程序object(实例)调用该成员函数。
首先,您可以使用 object 本身。在您的代码中的某处,您将有一个如下所示的应用程序变量:
CApplication MyApp;
如果您的项目是使用 Visual Studio 向导创建的,这 可能 会在“CApplication.cpp”文件中,并且会有一个 在“CApplication.h”中的声明 header。任何包含 header 的源文件都可以简单地调用 public 成员† 函数,如下所示:
MyApp.OnResetProgramSettings();
或者,您可以使用 AfxGetApp()
调用(在 MFC headers;但请注意,这必须转换为指向派生 class:
的指针
static_cast<CApplication*>(AfxGetApp())->OnResetProgramSettings();
但是,像这样调用成员有一个非常重要的警告:您不能对采用参数的函数执行此操作,在 'normal' 调用方法中,这些参数由框架提供。因此,例如,它根本不适用于 ON_UPDATE_COMMAND_UI
消息处理程序(需要 CCmdUI*
参数,由框架提供)。
† 请注意,消息处理程序在使用 class 向导创建时被声明为 protected,因此您将拥有稍微更改一下 CApplication
class,使您需要以上述方式访问 public。但那是微不足道的。
作为高级硬件EE,我的大部分编程时间都使用C 进行固件和根据需要进行内联汇编。我一直在研究 MFC MDI,你们中的一些人已经很好地帮助了我。我正在创建一个设置对话框并离开菜单项以写入注册表以存储和检索应用程序 user settings
。我在星期天用谷歌搜索了六种方法来尝试理解基本的 "Calling a function from another .cpp file class"
和许多其他变体来得到我的答案......失败(主要是因为我可能不理解他们的答案)。
我有一个主程序重置,它会破坏我的应用程序创建的 HKEY_CURRENT_USER 密钥。效果很好,没有问题。现在,我不再将 "Settings"
菜单中的项目与 "Reset App"
项目一起移动到 property sheet/page dialogs
.
button press
我可以使用它,但我不清楚为什么我最初关于如何执行它的想法失败了。
所以,在我的应用程序中,我触发了这个函数:
void CApplication::OnResetProgramSettings() //Truncated function for StackOF clarity
{
// ask the user
int DisableUserWarnings = FALSE;
if (DisableUserWarnings == FALSE) {
if (IDNO == AfxMessageBox(IDS_WARNING_RESET_APP, MB_ICONQUESTION | MB_YESNO))
return;
}
LSTATUS status = SHDeleteKey(HKEY_CURRENT_USER, _T("SOFTWARE\Trains"));
}
调用自:
BEGIN_MESSAGE_MAP(CApplication, CWinAppEx)
...other commands
ON_COMMAND(ID_SETTINGS_RESET_REGISTRY, OnResetProgramSettings)
...other commands
ON_UPDATE_COMMAND_UI(ID_SETTINGS_RESET_REGISTRY, OnUpdateOnResetProgramSettings)
END_MESSAGE_MAP()
为了在我的新 Dialog Settings
部分完成这项工作,我实施了这个:
void CSettingsReset::OnBnClickedButtonReset()
{
// Global reset
AfxGetMainWnd()->SendMessage(WM_COMMAND, ID_SETTINGS_RESET_REGISTRY);
//CApplication::OnResetProgramSettings();
//&CApplication::OnResetProgramSettings();
}
它的工作方式与我如上所述选择菜单项 "Reset App"
完全一样。
属性 页面称为 SettingsReset.cpp
,上面的内容位于 Application.cpp
。
在 C 语言环境中,我通常只调用包含在 SettingsReset.h
文件中的 application.h
的函数,如下所示:
OnResetProgramSettings();
我意识到这在 C++ 中的工作方式不同。您可以看到上面代码中注释掉的两个行项目,下面取消注释:
CApplication::OnResetProgramSettings(); //Doesn't get called, static error if memory serves
&CApplication::OnResetProgramSettings(); //Doesn't get called
CApplication OnResetProgramSettings; //Creates an object I don't want/need... or do I?
所以我发送AFX消息到"achieve"
相同的操作结果。我的最终问题是 "call"
Application.cpp 文件中的 OnResetProgramSettings()
FROM
SettingsReset.cpp
文件的正确方法是什么?我读过有关制作函数 "Static"
的信息,但我不清楚如何做到这一点 and/or 为什么......现在每个函数都有两个单独的处理程序......即。 OnResetProgramSettings()
和 OnResetProgramSettings1()
..对吗?
有没有一种方法可以做到这一点而不必使用 AFX 消息传递来触发该功能?
问题是 ON_UPDATE_COMMAND_UI
宏创建了一个私有(或受保护?)成员函数,在您的例子中是 CApplication::OnResetProgramSettings
。这意味着您不能直接从另一个 class 调用它(在您的情况下 CSettingsReset
)。
一种方法是像您一样通过 PostMessage
触发命令(除非您依赖 AfxGetMainWnd()
而不是在对话框构造函数中获取指向应用程序 class 的指针——如果您稍后更改主要 window 或使用系统通知图标等,这很容易出错。
另一种方法是移动 public class 中的功能,您 可以 直接调用,让 CApplication::OnResetProgramSettings
简单地调用新的功能。这样就避免了发送到消息队列的中间步骤。
当然,整个设计都被破坏了,所有这些实用的东西都应该从任何特定的 window class 中移出到一个专用服务 class 中,该服务封装了与任何相关的所有内容该注册表功能是,您的 windows 接收并使用指向该服务的指针 class。将其视为 MVVM 的过时的、错误的版本,因为您使用的是过时的技术 (MFC)。
您可以通过两种简单的方法从 'outside' 调用应用程序 class 的 non-static 成员函数 class.但它们本质上相同,因为您只需要通过实际应用程序object(实例)调用该成员函数。
首先,您可以使用 object 本身。在您的代码中的某处,您将有一个如下所示的应用程序变量:
CApplication MyApp;
如果您的项目是使用 Visual Studio 向导创建的,这 可能 会在“CApplication.cpp”文件中,并且会有一个 在“CApplication.h”中的声明 header。任何包含 header 的源文件都可以简单地调用 public 成员† 函数,如下所示:
MyApp.OnResetProgramSettings();
或者,您可以使用 AfxGetApp()
调用(在 MFC headers;但请注意,这必须转换为指向派生 class:
static_cast<CApplication*>(AfxGetApp())->OnResetProgramSettings();
但是,像这样调用成员有一个非常重要的警告:您不能对采用参数的函数执行此操作,在 'normal' 调用方法中,这些参数由框架提供。因此,例如,它根本不适用于 ON_UPDATE_COMMAND_UI
消息处理程序(需要 CCmdUI*
参数,由框架提供)。
† 请注意,消息处理程序在使用 class 向导创建时被声明为 protected,因此您将拥有稍微更改一下 CApplication
class,使您需要以上述方式访问 public。但那是微不足道的。