获取可停靠窗格C++的句柄时遇到问题

Having trouble getting a handle to a Dockable Pane C++

本文关键字:句柄 遇到 问题 C++ 停靠 获取      更新时间:2023-10-16

我通过 MFC 向导创建了一个基于多文档功能区的 MFC 应用程序。我试图获得m_wndFileView的句柄以更新其视图。我知道有几种方法可以做到这一点,但我不明白为什么我使用的方法不起作用。所以开始

class CMainFrame : public CMDIFrameWndEx
{
    ...
    CFileView         m_wndFileView;
    CPropertiesWnd    m_wndProperties;
    ...
}
class CFileView : public CDockablePane
{
    ...
    protected:
        CViewTree m_wndFileView;
    ...
};
class CPropertiesWnd : public CDockablePane
{
    ...
    protected:
        CMFCPropertyGridCtrl m_wndPropList;
    ...
};

框架是从主应用程序创建的

.cpp
// create main MDI Frame window
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame || !pMainFrame->LoadFrame(IDR_MAINFRAME))
{
    delete pMainFrame;
    return FALSE;
}
m_pMainWnd = pMainFrame;
// call DragAcceptFiles only if there's a suffix
//  In an MDI app, this should occur immediately after setting m_pMainWnd
// Enable drag/drop open
m_pMainWnd->DragAcceptFiles();
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Enable DDE Execute open
EnableShellOpen();
RegisterShellFileTypes(TRUE);

// Dispatch commands specified on the command line.  Will return FALSE if
// app was launched with /RegServer, /Register, /Unregserver or /Unregister.
if (!ProcessShellCommand(cmdInfo))
    return FALSE;
// The main window has been initialized, so show and update it
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();

MainFrm.cpp 创建以下两个窗格:

// Create file view
CString strFileView;
bNameValid = strFileView.LoadString(IDS_FILE_VIEW);
ASSERT(bNameValid);
if (!m_wndFileView.Create(strFileView, this, CRect(0, 0, 200, 200), TRUE, ID_VIEW_FILEVIEW, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_LEFT| CBRS_FLOAT_MULTI))
{
    TRACE0("Failed to create File View windown");
    return FALSE; // failed to create
}

// Create properties window
CString strPropertiesWnd;
bNameValid = strPropertiesWnd.LoadString(IDS_PROPERTIES_WND);
ASSERT(bNameValid);
if (!m_wndProperties.Create(strPropertiesWnd, this, CRect(0, 0, 200, 200), TRUE, ID_VIEW_PROPERTIESWND, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_RIGHT | CBRS_FLOAT_MULTI))
{
    TRACE0("Failed to create Properties windown");
    return FALSE; // failed to create
}

从主应用程序.cpp,我可以通过

CWnd * pwnd = ((CWnd*)(AfxGetApp()->m_pMainWnd));
CPropertiesWnd * pPropertiesWnd = (CPropertiesWnd*)pwnd->GetDlgItem(ID_VIEW_PROPERTIESWND);
CMFCPropertyGridCtrl * m_wndPropList = (CMFCPropertyGridCtrl *)pPropertiesWnd->GetDlgItem(2);

但由于某种原因,我无法访问文件视图窗格

CWnd * pwnd = ((CWnd*)(AfxGetApp()->m_pMainWnd));
CFileView * pFileViewWnd = (CFileView*)pwnd->GetDlgItem(ID_VIEW_FILEVIEW);
CViewTree * m_wndFileView= (CViewTree*)pFileViewWnd ->GetDlgItem(4);

(CFileView*)pwnd->GetDlgItem(ID_VIEW_FILEVIEW); 返回 NULL

请帮忙。这让我发疯。最后,我可以修改m_wndPropList但不能修改m_wndFileView,因为我无法获得 pFileViewWnd 的句柄。以相同方式创建的两个窗格不能以相同的方式访问。为什么?如果需要更多代码,请告诉我。谢谢。

你应该像这样在类中创建CMainFrame内联 getters:

CFileView& GetFileViewPane()
{
  return m_wndFileView;
}
CPropertiesWnd& GetPropsPane()
{
  return m_wndProperties;
} 

之后,您可以像这样访问这些窗口:

CMainFrame* pMainFrame = DYNAMIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
if (pMainFrame && pMainFrame->GetSafeHwnd()) // sanity check
{
  pMainFrame->GetFileViewPane().DoStuff();
}

所以@MarkRansom真的帮助了spy++的想法。为了获得句柄,我必须执行以下操作:

// get CWnd to main window
CWnd * pwnd = ((CWnd*)(AfxGetApp()->m_pMainWnd));
// from spy++ i found that the tabbed panes were in a window called
// "File View" so i found a child window with that title
HWND h = FindWindowExW(pwnd->GetSafeHwnd(), NULL, NULL, L"File View");
// casted it to a tabbedpane pointer
CTabbedPane * pFileViewWn = (CTabbedPane *)CWnd::FromHandle(h);
// mfc wizard did what seems to me as weird naming. to find the docking 
// panes i did the same as above but there was no title to this window
HWND hh = FindWindowExW(pFileViewWn->GetSafeHwnd(), NULL, NULL, L"");
// casted that
CDockablePane* pTabbedBar = (CDockablePane*)CWnd::FromHandle(hh);
// was able to find my specific docking pane using a resource id
CFileView * pFileViewWnd = (CFileView*)pTabbedBar->GetDlgItem(ID_VIEW_FILEVIEW);
// was able to find the control i wanted to use using a resource id
CViewTree * m_wndFileView = (CViewTree *)pFileViewWnd->GetDlgItem(4);
HTREEITEM hRoot = m_wndFileView->GetRootItem();
m_wndFileView->InsertItem(name, 2, 2, hRoot);

通过代码,我认为逻辑将是

tabbed pane
    File View Dockable Pane
        File View controls
    Class View Dockable Pane
        Class View controls

但不知何故,另一个窗口滑入

tabbed pane
    MYSTERY DOCKABLE WINDOW
        File View Dockable Pane
            File View controls
        Class View Dockable Pane
            Class View controls