VC++6.0 MFC WindowsXP sp2
分割した二つのウィンドウがありまして
右側はツリー構造、左側はリストビューを利用しております。
右側のツリーフォルダを選択した時に、左側のリストビューにその中身を表示するような
システム構造になっております。
また、リストビューは仮想リストコントロールを利用します。
そこで、仮想リストコントロールのSetItemCountExでシステムエラーになって落ちてし
まいます。
エラーメッセージは
// ウィンドウ生成
BOOL CMainFrame::OnCreateClient( LPCREATESTRUCT /*lpcs*/,
CCreateContext* pContext)
{
// 分割ウィンドウを作成します
CRect cr;
BOOL rc;
if (!m_wndSplitter.CreateStatic(this,1,2)){// 1行2列のビューを作成
TRACE0(Failed to create split bar );
return FALSE; // failed to create
}
GetClientRect(&cr); // ウィンドウの幅を取得
CSize paneSize(230, cr.Height()); // 左
側ペインの幅を設定
CSize paneSize1(cr.Width()-230 , cr.Height()); // 右側ペインの
幅を設定
((CCADExplorerApp*)AfxGetApp())->m_pDoc=(CXXXXXDoc*)(pContext-
>m_pCurrentDoc);
pContext->m_pCurrentFrame=this;
rc=m_wndSplitter.CreateView(0, 0,pContext->m_pNewViewClass,paneSize,
pContext );
if(!rc)return FALSE;
pContext->m_pNewViewClass=RUNTIME_CLASS(CCADExplorerView);
pContext->m_pCurrentDoc=((CXXXXApp*)AfxGetApp())->m_pDoc;
pContext->m_pCurrentFrame=this;
rc=m_wndSplitter.CreateView(0,1,pContext-
>m_pNewViewClass,paneSize1,pContext);
m_wndSplitter.RecalcLayout();
m_wndSplitter.SetActivePane(0,1);
}
extern pXXXXXView;
void CLeftView::OnInitialUpdate()
{
CTreeView::OnInitialUpdate();
// Treeを構築
SetTree();
CListCtrl& ListCtrl = pXXXXXView->GetMyListCtrl();
// ここでリストの数を設定しているが、SetItemCountExで落ちる。
ListCtrl.SetItemCountEx( m_List.size(), LVSICF_NOINVALIDATEALL |
LVSICF_NOSCROLL );
ListCtrl.Invalidate();
}
// ###################################
// 落ちたときのエラー箇所 winctrl2.cpp 378行目
// ###################################
BOOL CListCtrl::SetItemCountEx(int iCount, DWORD dwFlags /* =
LVSICF_NOINVALIDATEALL */)
{
ASSERT(::IsWindow(m_hWnd));
// can't have dwFlags on a control that isn't virutal
ASSERT(dwFlags == 0 || (GetStyle() & LVS_OWNERDATA));<<======ここで落
ちる
return (BOOL) ::SendMessage(m_hWnd, LVM_SETITEMCOUNT, (WPARAM) iCount,
(LPARAM) dwFlags);
}
そこのコメントにあるとおり、
仮想リストビューでは、dwFlagsを指定してはいけないということでしょう。
> そこのコメントにあるとおり、
> 仮想リストビューでは、dwFlagsを指定してはいけないということでしょう。
逆ですね。コメントは、仮想リストビューでない場合はdwFlagsを指定しない、
となっています。
仮想リストビューと言っておきながら、リストビューのスタイルに LVS_OWNERDATA
スタイルが立っていないのではないですか?
PreCreateWindowで、LVS_OWNERDATAスタイルを付加するようにしましょう。
この設定をしていますが、先ほどのエラーになります。
間違っている箇所はございますか?
BOOL CXXXXView::PreCreateWindow(CREATESTRUCT& cs)
{
int DisplayMode = atoi(GetRegistry( DisplayMode ));
// 0:アイコン 1:一覧 2:詳細
if( DisplayMode == 0 )
cs.style |= ( LVS_ICON | LVS_SHOWSELALWAYS | LVS_OWNERDATA );//アイコン
if( DisplayMode == 1 )
cs.style |= ( LVS_LIST | LVS_SHOWSELALWAYS | LVS_OWNERDATA );//一覧
if( DisplayMode == 2 )
cs.style |= ( LVS_REPORT | LVS_SHOWSELALWAYS | LVS_OWNERDATA );//詳細
cs.dwExStyle |= ( LVS_EX_TWOCLICKACTIVATE |
LVS_EX_INFOTIP |
LVSICF_NOINVALIDATEALL |
LVSICF_NOSCROLL);
return CListView::PreCreateWindow(cs);
}
補足として
GetRegistry( DisplayMode )はレジストりから、
前回、画面を終了した時、ビューの表示形式を取得している箇所なので今回のエラーと
は関係ありません。
無視してください。
すみません、逆でしたね。失礼しました。
> cs.dwExStyle |= ( LVS_EX_TWOCLICKACTIVATE |
> LVS_EX_INFOTIP |
> LVSICF_NOINVALIDATEALL | <==?
> LVSICF_NOSCROLL); <==?
ここが少し変ですが、今回の件とはあまり関係なさそうです。
本当に LVS_OWNERDATA スタイルが立っているのであれば、
原因はちょっとわかりません。
念のため、SetItemCountExを呼び出す前に、
ASSERT(ListCtrl.GetStyle() & LVS_OWNERDATA);
↑を入れてみてはいかがでしょうか?
ASSERT(ListCtrl.GetStyle() & LVS_OWNERDATA);を入れました。
結果ですが、
ASSERT(ListCtrl.GetStyle() & LVS_OWNERDATA);の箇所でエラーになりました。
どういう事なのでしょうか?
別のビューにLVS_OWNERDATAスタイルを立てている、
とかいうことはないですよね?
ぢつは GetRegistry で 0, 1, 2 以外の値が取得されちゃって、LVS_OWNERDATA が立って
ないとか。
LVS_SHOWSELALWAYS | LVS_OWNERDATA は、どの表示モードであるかにかかわらず設定する
のであれば、if 文の外に追い出しちゃうとか。
あと、考えられる可能性としては、
> CListCtrl& ListCtrl = pXXXXXView->GetMyListCtrl();
このpXXXXXViewやListCtrlが正しいリストビューを指しているかどうか。
強引なキャストを行っている箇所はないかどうか。
ASSERT_KINDOF(CListView, pXXXXXView);
ASSERT_KINDOF(CListCtrl, &ListCtrl);
などでチェックしてみる、とか。
ASSERT_KINDOF(CListView, pXXXXXView);の箇所で落ちる事がわかりました。
ということは、OnInitialUpdateの実行しているタイミングでは、
pXXXXXViewは実体化されていないという事のでしょうか?
CMainFrame::OnCreateClientの箇所で、
先にLeftViewをクリエイトしているので、その段階ではまだpXXXXXViewを生成していま
せん。
それが原因なのでしょうか?
wndSplitter.CreateView(0,0 -----);// ツリー側
wndSplitter.CreateView(0,1 -----);// リストビュー側
すみません、微妙に間違っていました。
先ほど、ASSERT_KINDOF(CListView, pXXXXXView);の箇所で落ちるといいましたが、
ASSERT_KINDOF(CListCtrl, &ListCtrl);で落ちてました。
> ASSERT_KINDOF(CListCtrl, &ListCtrl);で落ちてました。
だとすると、返されたListCtrlがCListCtrlクラスではない、
ということになると思います。
> CListCtrl& ListCtrl = pXXXXXView->GetMyListCtrl();
ここのGetMyListCtrl()はどのような実装になっているのですか?
CXXXXViewがCListView派生であるならば、
CListView::GetListCtrl()を使用していないのはなぜでしょうか?
CListView::GetListCtrl() は単に *(CListCtrl*)this を返すだけの嘘つきなので、
CListCtrl& List = GetListCtrl();
ASSERT_KINDOF(CListCtrl, &List);
としてもエラーになります。
実体は、あくまでも CListView なのです。