Release ビルドしたファイルを実行するとEditView の描画がおかしくなる?

[戻る]
MesaBoogie 2010/01/30(土) 12:14:32
Windows XP SP3 Visual Studio 2005 MFC SDI CEditView use boost/regex.hpp
MFCの使用の設定は、「スタティック ライブラリで MFC を使用する」を選択しています。
1. メニューバーに配置した、ボタンを押下。
2. 現在表示されている、EditView の文字を取得。
3. boost ライブラリィを用いて文字列処理を行う。
4. 文字処理を行った文字列を再びEditView に表示。
このようなプログラムなのですが、不可解な現象といいますか、バグの原因が掴めない状
況です、
プログラムをVS2005 を起動し、Debug モード、およびRelease モードで実行すると

期待通り、EditView のテキストデータを取得し、文字列処理をおこない、
その文字列が再描画できます。
ところがRelease ビルドした、実行ファイルを適当に(仮にディスクトップ)置いて、実
行しますと下記のような状態です。
1. EditView に文字列入力。(コピーペーストで貼り付ける)
2. ボタン押下。
3. 文字列処理を行った内容が表示されなければならないのに、EditView の文字が消えて
しまう。

1 から3 を4回繰り返すと、5回目のボタン押下でようやく、文字処理を行った内容が
EditViewに表示されます、このような状況なのですが、原因が全く掴めません?
尚、Debug モードでビルドしたものを、同じようにディスクトップなどに置いて、実行す
る場合には、この現象はおこりません。
どのような、原因が考えられますでしょうか?
またRelease モードでビルドした実行ファイルをデバッグする手段等を、ご存知の方がお
られましたら、よろしくお願いします。

ryo 2010/01/30(土) 12:39:07
現象・動きの説明だけでは想像するしかないので

>1. メニューバーに配置した、ボタンを押下。
>2. 現在表示されている、EditView の文字を取得。
>3. boost ライブラリィを用いて文字列処理を行う。
>4. 文字処理を行った文字列を再びEditView に表示。

このあたりのソースを提示できますでしょうか?

ITO 2010/01/30(土) 13:06:51
> またRelease モードでビルドした実行ファイルをデバッグする手段等を、
> ご存知の方がおられましたら、よろしくお願いします。
僕だったらこれかな?
 ・メッセージボックスを表示して、どこまで処理が進んだか確認する。
 ・コンソールウインドウを作成して、必要なデータをある程度リアルタイムで
  表示する。

MesaBoogie 2010/01/30(土) 15:07:47
お世話になります、少し長くなりますが、ソースを貼らさせていただきます、よろしくお
願いします。

>1. メニューバーに配置した、ボタンを押下。
/**
  * 正規表現適用ボタンのメッセージ ハンドラ
  */
void CxxxView::OnRegularApplied()
{
    // TODO: ここにコマンド ハンドラ コードを追加します。
    CSQLEditorDoc *pDoc = (CSQLEditorDoc*)((CFrameWnd
*)AfxGetMainWnd())->GetActiveDocument();
    pDoc->onViewToView();
}

>2. 現在表示されている、EditView の文字を取得。
/**
 * 現在エディットビューに表示されている文字列を取得し配列に格納する
 */
void CxxxDoc::getDocmentString(void)
{
    m_vec.clear();
    // Document を取得する。
    CSQLEditorDoc *pDoc = (CSQLEditorDoc*)((CFrameWnd
*)AfxGetMainWnd())->GetActiveDocument();
    // 取得したデータの先頭ポインタを取得。
    void* P = m_viewList.GetHead();
    CEdit* pEdit; // エディットクラス型のポインタ変数。
    pEdit = (CEdit*) P;
    m_Lines = pEdit->GetLineCount();
    int nBegin, nEnd, nLen, nCou;
    for(UINT i = 0; i < m_Lines; ++i)
    {
        // 文字数
        nBegin = pEdit->LineIndex(i);
        nEnd = nBegin + pEdit->LineLength(nBegin);
        nCou = nEnd-nBegin+1;
        // 一行取得
        boost::scoped_array<char> buffer(new char[nCou]);
        try {
            nLen = pEdit->GetLine(i, buffer.get());
            buffer[nLen]='\0';
            m_vec.push_back(buffer.get());
        }
        catch(std::bad_alloc)
        {
            AfxMessageBox(_T("メモリエラー"));
            abort();
        }
        catch(...)
        {
            AfxMessageBox(_T("その他のメモリエラー"));
            abort();
        }
    }
}

>3. boost ライブラリィを用いて文字列処理を行う。
/*
 * 正規表現を適用し置換する
 */
std::string RegularExpression::regularReplace(std::string str, std::string
reg_ex, const std::string replace)
{
    std::string result;
    boost::regex reg_exp(reg_ex);
    result = boost::regex_replace(str, reg_exp, replace);

    return result;
}

>4. 文字処理を行った文字列を再びEditView に表示。
/**
 * 正規表現適用後の文字列を表示
 */
void CSQLEditorDoc::showDocument()
{
    std::vector<CString>::iterator ite = m_vec.begin();
    std::string str;
    // Document を取得する。
    CSQLEditorDoc *pDoc = (CSQLEditorDoc*)((CFrameWnd
*)AfxGetMainWnd())->GetActiveDocument();
    void* P = m_viewList.GetHead();
    CEdit* pEdit;
    pEdit = (CEdit*) P;

    int nBegin, nEnd;

    for(UINT i = 0; i < m_Lines; ++i)
    {
        nBegin=pEdit->LineIndex(i);
        str = *ite;
        nEnd = nBegin + pEdit->LineLength(nBegin);
        pEdit->SetSel(nBegin, nEnd);
        pEdit->ReplaceSel(str.c_str());
        ++ite;
    }
    UpdateAllViews(FALSE);
}

MesaBoogie 2010/01/30(土) 15:51:51
ITO さんの助言を頼りに、何処でデータが欠落しているのか、メッセージボックス頼りに
探したところ、
エディットビューのデータが取得出来ていないことが判明しました、ドキュメントの取得
方法が不味いのでしょうか?
ポイントは絞り込めれましたが対処の方法が分かりません、引き続きよろしくお願いいた
します。
/**
 * 現在エディットビューに表示されている文字列を取得し配列に格納する
 */
void CxxxDoc::getDocmentString(void)
{
    m_vec.clear();
    // Document を取得する。
    CSQLEditorDoc *pDoc = (CSQLEditorDoc*)((CFrameWnd
*)AfxGetMainWnd())->GetActiveDocument();
    // 取得したデータの先頭ポインタを取得。
    void* P = m_viewList.GetHead();
    CEdit* pEdit; // エディットクラス型のポインタ変数。
    pEdit = (CEdit*) P;
    m_Lines = pEdit->GetLineCount();
    int nBegin, nEnd, nLen, nCou;
    for(UINT i = 0; i < m_Lines; ++i)
    {
        // 文字数
        nBegin = pEdit->LineIndex(i);
        nEnd = nBegin + pEdit->LineLength(nBegin);
        nCou = nEnd-nBegin+1;
        // 一行取得
        boost::scoped_array<char> buffer(new char[nCou]);
        try {
            nLen = pEdit->GetLine(i, buffer.get());
            buffer[nLen]='\0';
            m_vec.push_back(buffer.get());
        }
        catch(std::bad_alloc)
        {
            AfxMessageBox(_T("メモリエラー"));
            abort();
        }
        catch(...)
        {
            AfxMessageBox(_T("その他のメモリエラー"));
            abort();
        }
    }
    // m_vec のデータを表示(View のデータは取得出来ていない)
    std::string str;
    std::vector<CString>::iterator it = m_vec.begin();
    while(it != m_vec.end())
    {
        str = *it;
        AfxMessageBox(str.c_str());
        ++it;
    }    
}

ITO 2010/01/30(土) 17:59:40
boostはよく分かりませんが、
>nLen = pEdit->GetLine(i, buffer.get());
直接代入出来るのですか?
一度代入できる変数に移してから代入した方がいいってことないですか?

ryo 2010/01/30(土) 19:47:49
ちょっとソースをみてる時間がないので
手法の追加だけ

OutputDebugStringってのを使えば、
リリースビルドしたものを、VS上で実行したときに
TRACEマクロのような使い方できます。

ITO 2010/02/01(月) 11:29:49
うーん、
>        try {
>            nLen = pEdit->GetLine(i, buffer.get());
まず、nLenの値をチェックですかね。
コンソールウインドウを使えば、Release モードでも表示できます。

あと、忘れがちなのがデータ領域の確保ですね。
「array」となっているので可変できるのだと思いますが、設定の方はいいでしょうか?
書き込むデータの位置が設定したデータの範囲外にあるとか?

Debug モードは、動いてしまうことがあります。

gak 2010/02/01(月) 17:19:13
掲示ソースを見て気になった点。

> boost::scoped_array<char> buffer(new char[nCou]);
GetLine() はTCHAR配列を要求する。
プロジェクトの使用文字セットが UNICODE 指定時、(TCHAR != char なので) char 固
定の上記コードは破綻する。

> nLen = pEdit->GetLine(i, buffer.get());
GetLine() は、渡す配列の先頭wordに配列長を格納して呼び出す仕様になっているようだ。
が、掲示コードにはソレをしている形跡が無く先頭wordが未初期化状態。
http://msdn.microsoft.com/ja-jp/library/7775836w%28VS.80%29.aspx
# (MSDNの)MFCの文字列関係の解説で「バイト数で」とか書かれている部分の多くは
# 「TCHAR単位で」の間違いである事が多いので注意。

古いスレッドには追加発言できません。