将 MFC 应用程序从 VC6 迁移到 VS2010,现在不为 CPropertyPage 子类调用 OnInitDialog()

发布于 2024-12-02 04:40:09 字数 2993 浏览 0 评论 0原文

我的任务是将我们产品的 UI 迁移到 VS2010。它是一个MFC应用程序,最初是用VC6编写的。我已执行以下步骤:

  • 使用 VS2010 转换 VC6 .dsp 修复了
  • 由于更严格的 VS2010 编译器导致的编译错误
  • 删除了对 VC6 mfc 库和目录的所有项目引用

我的问题是,对于对话框对象(实际上是 CPropertyPage 对象),OnInitDialog () 不会在其他方法之前被调用。这会导致异常,因为 OnInitDialog() 需要设置成员变量。

对话框类 (CPAGEViewDefRecordFields) 是我们自己的 CValidatedPropertyPage 的子类,而 CValidatedPropertyPage 又派生自 MFC CPropertyPage 类。虚拟方法 OnInitDialog() 存在于所有子类中。

在VS2010版本中,当在包含的属性表上调用DoModal()时,不会调用CPAGEViewDefRecordFields类的OnInitDialog()方法。在VC6版本中,它被调用并且一切正常。

在VC6中,我可以看到消息WM_INITDIALOG被发送,并在AfxDlgProc()中处理,然后调用对话框对象的OnInitDialog()。

在VS2010版本中,处理的第一个消息是WM_NOTIFY,而不是WM_INITDIALOG。

不幸的是我以前没有 MFC 经验。我假设 VC6 版本和 VS2010 版本之间 MFC 的行为发生了变化。但是我在网上找不到任何与此类似的内容。

我是否还错过了另一个迁移步骤?进行迁移时我是否需要对项目中的资源进行一些操作?

我已检查资源是否绑定到正确的 cpp 文件,因为我可以双击属性页,IDE 将我带到 CPAGEViewDefRecordFields 类的正确文件。

如果你们有任何想法,我将非常感激。

谢谢! 克里斯.

class CPAGEViewDefRecordFields : public CValidatedPropertyPage
{
public:

   // Construction

   CPAGEViewDefRecordFields(CWnd*         pParent,
                           CXpViewProp*  pViewProp,
                           CFont*        pFont      = NULL,
                           UINT          nIDCaption = 0,
                           BOOL          bSumOpRequired = TRUE,
                           BOOL          bMinMaxRequired = TRUE,
                           BOOL          bAllRecords = TRUE,
                           BOOL          bShowInitSel = TRUE,
                           XLong         lLimits = 0,
                           BOOL          bSortSelTree = TRUE,
                           CXpThreshBaseLogProp* pThreshLogProp = NULL);

  ~CPAGEViewDefRecordFields();

  // Dialog Data
  //{{AFX_DATA(CPAGEViewDefRecordFields)
  enum { IDD = IDD_VIEW_DEF_RECORD_FIELDS };
  //}}AFX_DATA

  // Overrides
  // ClassWizard generate virtual function overrides
  //{{AFX_VIRTUAL(CPAGEViewDefRecordFields)
  virtual BOOL OnInitDialog();
  //}}AFX_VIRTUAL

 virtual BOOL OnSetActive();
 virtual BOOL OnKillActive();
 virtual void OnOK();

protected:

  ... 

  // Generated message map functions
  //{{AFX_MSG(CPAGEViewDefRecordFields)
  afx_msg void OnPbRemove();
  afx_msg void OnPbAdd();
  afx_msg void OnDblclkAvailableFields(NMHDR* pNMHDR, LRESULT* pResult);
  afx_msg void OnDblclkSelectedFields(NMHDR* pNMHDR, LRESULT* pResult);
  //}}AFX_MSG
  DECLARE_MESSAGE_MAP()

private:
  ...

更新:

经过一些调试,我可以看到我认为的问题所在。不过,我不是MFC程序员,不太明白。

我可以看到正在为属性表调用 OnInitDialog(),然后将 WM_INITDIALOG 从属性表发送到属性页。然而,在 Windows 内部的某个时刻,正在发送 WM_NOTIFY 消息,因此这是收到的第一条消息,而不是预期的 WM_INITDIALOG

我已经突出显示了堆栈跟踪上的点,附上 - 谁能解释为什么这是发生?这是正常行为吗?我将来应该迎合这种情况吗?

我实际上找到了一个解决方法,那就是有一个初始化标志,这样在调用 OnInitDialog() 之前不会执行任何代码。这不是最好的解决方案,我担心这更像是一种黑客攻击,所以我仍然希望能够理解这些消息。 (你看,我不是 MFC 程序员!)

谢谢!

显示 WM 消息的堆栈跟踪

I have been tasked with migrating our product's UI to VS2010. It is an MFC app, originally written in VC6. I have performed the following steps:

  • Converted the VC6 .dsp using VS2010
  • fixed up compile errors due to stricter VS2010 compiler
  • Removed all project references to VC6 mfc libs and directories

My problem is that for a dialog object (actually it's a CPropertyPage object), OnInitDialog() is not being called before other methods are. This causes an exception as OnInitDialog() needs to setup member variables.

The dialog class (CPAGEViewDefRecordFields) is subclassed from our own CValidatedPropertyPage, which in turn is derived from the MFC CPropertyPage class. The virtual method OnInitDialog() is present in all subclasses.

In the VS2010 version, when DoModal() is called on the containing property sheet, the OnInitDialog() method of the CPAGEViewDefRecordFields class is not being called. In the VC6 version, it is being called and all works ok.

In VC6, I can see that the message WM_INITDIALOG is sent, and handled in AfxDlgProc(), which in turn then calls OnInitDialog() of the dialog object.

In the VS2010 version, the first message that is processed is WM_NOTIFY, not WM_INITDIALOG.

Unfortunately I have no prior experience in MFC. What I am assuming that something has changed in the behaviour of MFC between the VC6 version and the VS2010 version. However I've not been able to find anything on the net which is similar to this.

Is there another migration step I have missed? Should I have to do something to the resources in the project when doing the migration?

I have checked that the resource is tied to the correct cpp file, as I can double click on the property page, and the IDE takes me to the correct file for the CPAGEViewDefRecordFields class.

If any of you have any ideas, I'd be very grateful.

Thanks!
Chris.

class CPAGEViewDefRecordFields : public CValidatedPropertyPage
{
public:

   // Construction

   CPAGEViewDefRecordFields(CWnd*         pParent,
                           CXpViewProp*  pViewProp,
                           CFont*        pFont      = NULL,
                           UINT          nIDCaption = 0,
                           BOOL          bSumOpRequired = TRUE,
                           BOOL          bMinMaxRequired = TRUE,
                           BOOL          bAllRecords = TRUE,
                           BOOL          bShowInitSel = TRUE,
                           XLong         lLimits = 0,
                           BOOL          bSortSelTree = TRUE,
                           CXpThreshBaseLogProp* pThreshLogProp = NULL);

  ~CPAGEViewDefRecordFields();

  // Dialog Data
  //{{AFX_DATA(CPAGEViewDefRecordFields)
  enum { IDD = IDD_VIEW_DEF_RECORD_FIELDS };
  //}}AFX_DATA

  // Overrides
  // ClassWizard generate virtual function overrides
  //{{AFX_VIRTUAL(CPAGEViewDefRecordFields)
  virtual BOOL OnInitDialog();
  //}}AFX_VIRTUAL

 virtual BOOL OnSetActive();
 virtual BOOL OnKillActive();
 virtual void OnOK();

protected:

  ... 

  // Generated message map functions
  //{{AFX_MSG(CPAGEViewDefRecordFields)
  afx_msg void OnPbRemove();
  afx_msg void OnPbAdd();
  afx_msg void OnDblclkAvailableFields(NMHDR* pNMHDR, LRESULT* pResult);
  afx_msg void OnDblclkSelectedFields(NMHDR* pNMHDR, LRESULT* pResult);
  //}}AFX_MSG
  DECLARE_MESSAGE_MAP()

private:
  ...

UPDATE:

After some debugging, I can see what I think is the problem. However, not being an MFC programmer, I don't understand it.

I can see that OnInitDialog() is being called for the property sheet, and that a WM_INITDIALOG is then sent from the property sheet to the property pages. however, at some point in the windows internals, a WM_NOTIFY message is being sent, so this is the first message that is received, not the expected WM_INITDIALOG

I've highlighted the points on the stack trace, attached - can anyone explain why this is occuring? Is this normal behaviour - should I be catering for this in the future?

I've actually found a workaround, and that's to have an initialised flag, so that no code is executed until OnInitDialog() has been called. This is not the best solution, and I fear is more of a hack, so i would still appreciated any understanding of these messages. (I'm not an MFC programmer by trade you see!)

thanks!

stack trace showing WM messages

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

九命猫 2024-12-09 04:40:09

OnInitDialog 在所有对话框控件创建之后、对话框显示之前调用。

OnInitDialog is called after all the dialog controls are created and just before the dialog box is displayed.

剧终人散尽 2024-12-09 04:40:09

我想我最好回答这个问题。

答案来自一位SO用户的评论:

您使用初始化标志的解决方法与我所做的相同。看起来树视图在创建树视图但您的对话框尚未准备好时会发送通知。您可能不知道其他控件何时执行相同的操作,因此您需要一个初始化标志

“解决方法”是保证对话框准备就绪的唯一方法。

Thought I'd better answer this.

The answer came from a SO user's comment:

Your workaround with an initialized flag is the same as I would do. It looks like a tree view sends a notification when the tree view is created but your dialog isn't ready yet. You might not know when other controls do the same thing, so you need an initialized flag

The "workaround" is the only way to guarantee that the dialog is ready.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文