既存のオブジェクトをタブのページに分ける際の現象について

[戻る]
みらくる 2007/02/02(金) 21:30:05
先週からVCをはじめた初心者です。
開発環境は WinXP SP1  VC++6.0になります。

まずメインのダイアログがあり、そこにエディットボックスなどで数値を入力し加工す
るプログラムを作っています。
入力の種類により個別の項目を設けていたのですが、スペースの関係上タブに分けるこ
とにしました。
メインのダイアログ上の処理をタブの各ページのダイアログに丸々写し、動作させよう
と修正を施します。
結果数値の入力などは上手くいくのですが、数値を加工する処理の部分の実行時に下記
エラーが発生するようになりました。
<エラー部分>
File:winocc.cpp
Line:345

処理としては同じもののはずなのに、何が原因なのか検討もつきません。
理由として考えられるものがありましたら、ご教授頂きたく存じます。
また、メインダイアログ上での処理は上手くいくので、各タブページから数値の加工す
る処理部分のみメインを呼び出す良い方法などありましたら教えてください。

質問の仕方やアプローチに問題があるかもしれませんが、助けていただけると幸いです

ねこ 2007/02/02(金) 23:35:57
せっかく
><エラー部分>
>File:winocc.cpp
>Line:345
という手がかりがあるのに、なんで調べないのでしょうか?

超初心者 2007/02/02(金) 23:37:28
> File:winocc.cpp
> Line:345
その情報では判らないんじゃないの。
ここを読んでいる人が、あなたと同じアプローチをしたり、
あなたと同じバージョンのVCを使っているわけじゃないんだし。

> アプローチに問題があるかもしれませんが、
あなたのアプローチを知らないので問題があるかどうかわからない。

どういうことがしたくて、どういうことをしたら、
どういうエラーになったのかわからないけれど、
俺だったらこうするって方法を示しますね。

各タブのオブジェクト(クラス)に共通オブジェクト(メインダイアログ)への
ポインタを持たせる。
各タブのオブジェクトを作成時にそのポインタを設定するのを忘れずに。

みらくる 2007/02/03(土) 01:51:25
>という手がかりがあるのに、なんで調べないのでしょうか?
すみません。
該当するソース部分から具体的な問題点が判断できず、頓挫してしまいました。
ただ、出ている現象の唯一のエラーメッセージだったため、載せることにした次第で
す。

>あなたのアプローチを知らないので問題があるかどうかわからない。
そうですね。
現在行っているアプローチとしては、メインのダイアログにあったソースをそのままタ
ブのページダイアログにコピーするという方法でした。
移したいオブジェクトに関するソースは、検索などかけて抜けがないようタブページに
移植しているのですが。
一方で元のメインダイアログとのデータのやりとりができるか、また見落としなどがあ
ったりするのではないかという危惧がありました。
出ている現象も関数との引数のやりとり部分で引っかかってる節があるため、そのアプ
ローチ自体遠回りで非効率だったのではないかと。

本当なら中身の処理をメインダイアログに残して、タブページにはオブジェクトのイン
タフェース部分のみというのをやりたかったりしました。
例えばリソースビュー上でボタンをタブにカットアンドペーストで移動させ、実行時タ
ブに移動したボタンを押すことによりメインダイアログに残っている処理を実行するみ
たいに。
ただ、実際どう関連付けるかわからず、仕方なくボタンを押した際の処理ごとタブペー
ジに移動させています。
現状の方法での問題点を解決したいのもありますが、一方でもっと良い手法があれば教
えて頂きたいという希望がありました。
結果として趣旨のよくわからない質問になってしまったのだと反省しきりです。

>各タブのオブジェクト(クラス)に共通オブジェクト(メインダイアログ)へのポイン
タを持たせる。
申し訳ないのですが、その場合どうポインタを持たせるかまで教えて頂けないでしょう
か?
タブオブジェクトのヘッダに何らかの宣言をするという趣旨でしょうか?

とおりすがり 2007/02/03(土) 03:37:04
>その情報では判らないんじゃないの。
ってのはあなたの書き込みを読んで他人が再現できるように書いてねって話

http://www.hyuki.com/writing/techask.html
ここを読むといいかもしれない

ぬふや 2007/02/03(土) 12:38:27
関連するソースの分量が多そうだし、ソースから原因探すよりデバッガで見つけた
ほうが早いと思う。

やり方は主に2パターン。
・VCからデバッグを開始(F5)して、エラーが出た時点でブレークさせる。
・エラーダイアログからデバッガにアタッチさせる。

で、問題の発生したスレッドのコールスタック等を足がかりに調べれば何処で何を
したのが原因かわかるはず。

アタッチは、エラーのダイアログの中のどれかを選択すれば出来たと思いますが。

ライブラリの中でエラーが出ているようですので、大方NULLじゃ駄目な変数が
NULLだったりとかだと思います。

みらくる 2007/02/03(土) 15:41:53
色々レスありがとうございます。

>ってのはあなたの書き込みを読んで他人が再現できるように書いてねって話
ご指摘の通り、再現させるための情報を入れてませんでした。
現在スレを立てた状態から色々検討して“親ダイアログ中の実行したい関数を、タブの
子ダイアログから
public宣言した関数を介して実行する方向”で模索しています。
以下関連する部分のソースをピックアップしてみます。

<メインダイアログ.h>
public:
    void    Open_Function( short Size, BYTE* Data );
protected:
    void    Test_Function( short Size, BYTE* Data );


<メインダイアログ.cpp>

// 実行したい処理
void CDlg_Main::Test_Function( short Size, BYTE* Data )
{
    ***************
}

// 外部からの参照用処理
void CDlg_Main::Open_Function( short Size, BYTE* Data )
{
    Test_Function( Size, Data );
}


<タブページ子ダイアログ.cpp>

    CDlg_Main    cTest;
    void(CDlg_Main::*fp)(short Size, BYTE* Data);

    fp = cTest.Open_Function;
    (cTest.*fp)(size_data, data);


上記のような状態でコンパイルは通ったのですが、子ダイアログの処理を実行しようと
すると
Debug Assertion Failed!のメッセージと共にwinocc.oppの345行目を指摘されてしまい
ます。
またメインダイアログ中で値をとり、Test_Functionを実行すると問題なく動くような状
況です。
十分な情報かどうかわかりませんが、こんな感じです。


やり方は主に2パターン。
・VCからデバッグを開始(F5)して、エラーが出た時点でブレークさせる。
・エラーダイアログからデバッガにアタッチさせる。

で、問題の発生したスレッドのコールスタック等を足がかりに調べれば何処で何を
したのが原因かわかるはず。

アタッチは、エラーのダイアログの中のどれかを選択すれば出来たと思いますが。

ライブラリの中でエラーが出ているようですので、大方NULLじゃ駄目な変数が
NULLだったりとかだと思います。



デバッグライブラリウインドウでエラーを指摘されている状態で処理をブレークしまし
た。
ソースコードが表示されている部分にアセンブラコードが出るようになったのですが、
次のアタッチが
よくわかりませんでした。
デバッグライブラリウインドウの操作をしようとしても、その状態だとデバッグモード
で実行中の
ダイアログがハングアップしているのでやりかたが不味かったのかもしれません。
もうすこし方法を検討してみます。

rikizo 2007/02/03(土) 17:24:20
初めて書き込ませて頂きます。

>開発環境は WinXP SP1  VC++6.0になります。
SDKですか?それともMFC使ってますか?


>public宣言した関数を介して実行する方向”で模索しています。

最初からTest_Functionをpublicにすればいいのでは?


>CDlg_Main    cTest;
>void(CDlg_Main::*fp)(short Size, BYTE* Data);
>fp = cTest.Open_Function;
>(cTest.*fp)(size_data, data);

子ダイアログ上で
cTestという親ダイアログと同じクラスのインスタンスを作っているだけであって、
親ダイアログそのものじゃないですよね?
ならば、そのメンバ関数のポインタを取得したところで意味ないのでは?
staticなメンバ関数なら大丈夫かも知れないけど。


#ちなみに私も初心者なので間違っていたらごめんなさい。

みらくる 2007/02/03(土) 18:08:16
rikizoさん、指摘ありがとうございます。
>SDKですか?それともMFC使ってますか?
MFCです。

>cTestという親ダイアログと同じクラスのインスタンスを作っているだけであって、親
ダイアログそのものじゃないですよね?
そうだったのですか。
この書き方でメインダイアログを呼んでいるとばかり思ってました。
逆に、メインダイアログのメンバのポインタを取得するにはどういった書き方をすれば
よいのでしょうか?

rikizo 2007/02/03(土) 20:20:03
>逆に、メインダイアログのメンバのポインタを取得するにはどういった書き方をすれば
よいのでしょうか?

GetParent()を使うとか。

rikizo 2007/02/03(土) 20:28:36
そもそも

>CDlg_Main    cTest;
>void(CDlg_Main::*fp)(short Size, BYTE* Data);
>fp = cTest.Open_Function;
>(cTest.*fp)(size_data, data);

これが何をやっているのかご自分で理解されているでしょうか。
ものすごーく意味のない事をしています。

VCを初めて一週間とのことですが、C++の知識はどの程度ありますか?
C++やクラスの概念を理解していない状態で
MFCを使うのは難しいんじゃないかと思います。

自分がそうなので(^^;

ITO 2007/02/03(土) 20:44:54
VC 6.0
> File:winocc.cpp
> Line:345

>void AFX_CDECL CWnd::InvokeHelper(DISPID dwDispID, WORD wFlags, VARTYPE vtRet,
>    void* pvRet, const BYTE* pbParamInfo, ...)
>{
>    ASSERT(m_pCtrlSite != NULL); ← ココ 345行   // not an OLE control 
(not yet, at least) 
>    if (m_pCtrlSite == NULL)
>        return;

>    va_list argList;
>    va_start(argList, pbParamInfo);
>    m_pCtrlSite->InvokeHelperV(dwDispID, wFlags, vtRet, pvRet, 
>pbParamInfo,
>        argList);
>    va_end(argList);
>}



>// not an OLE control (not yet, at least) 

 Active X Controlを使っていないですか?
うまく動作していないんじゃない?

ITO 2007/02/03(土) 20:46:27
修正
> Active X Controlを使っていないですか?
> うまく動作していないんじゃない?


正解
 Active X Controlを使っていますか?
  うまく動作していないんじゃない?

ITO 2007/02/03(土) 20:50:00
MFCのソースはこの場所にあります。
VC6.0の場合。
  C:\Program Files\Microsoft Visual Studio\VC98\MFC\SRC

winocc.cppもあったよ。

みらくる 2007/02/03(土) 21:01:08
[[解決]]
> Active X Controlを使っていますか?
Active X Controlが使われているかの確認方法がわからないのですが、改造する前は同
じ処理で動いていたため、私の方法が間違っているのだと思います。

>これが何をやっているのかご自分で理解されているでしょうか。
>ものすごーく意味のない事をしています。
実はあまり理解できていません。
ネットにあるコードを見て、いろいろと試して確認するという作り方をしているためな
のですが。

>VCを初めて一週間とのことですが、C++の知識はどの程度ありますか?
どう程度を表せばいいかわからないのですが、何年か前に基本は勉強しました。
ただ、長らくCの環境ばかりを扱っていたため、かなり忘れています。
ですので、今は作りながら思い出すという状況にあります。

>MFCを使うのは難しいんじゃないかと思います。
私も同感です。
ただ、改造母体とするプログラムがMFCの環境で作られている関係上、別の選択肢が
取り辛かったりします。
本来なら基本から勉強して臨んだり、また別の方法を模索した方が建設的だとは思いま
すが。
時間と環境の制約があるなか、必要な部分の変更により求める成果物を作成する事を最
優先と考えていました。

しかしそれはこちらの我侭でしかなく、そういった手前勝手な事情につき合わせてしま
って申し訳なく思います。
こちらが質問をするレベルに達していないにも関わらず、結果場を荒らしてしまって本
当に申し訳ありません。

色々ご指導いただきありがとうございました。
そして、本当にすみませんでした。

超初心者 2007/02/03(土) 22:34:25
Windowsプログラミングを始めたばかりの人がよく起こす現象だな。

C言語風にたとえていえば

int a = 10;

void functionB()
{
  int c;
  c = 5; // これを実行しても a の値は5にならない。
}

上記は判りますよね。
intをCDlg_Mainに置き換えてみてください。

--------------------------------------------------------------------

Active X Controlが原因となると俺にはそこまで手伝えないな。

解決ってことになっているけど、解決?

rikizo 2007/02/04(日) 06:05:13
解決してないのに無理に解決にしなくてもいいと思いますよ〜。
私もCすらまともに知らない状態で、MFCで作られた粗悪なWindowsソフトの
バージョンアップを命ぜられた事がありますので、みらくるさんの状況もよくわかりま
す。

おそらく、起きている問題の本質はActiveXとはあまり関係なくて
親ダイアログの関数を無事に呼べれば解決しそうな気がします。

↓こんなんでダメですかね?

CDlg_Main* pDlg = (CDlg_Main*)GetParent(); // 親ダイアログのポインタを取得
pDlg->Open_Function(size_data, data); // メンバ関数を呼び出す


#protectedなメンバ関数をpublicなメンバ関数を通して呼び出すのは
#設計的にどうなの?、っていう事についてはここで言及しません。

ITO 2007/02/04(日) 14:23:07
>>MFCを使うのは難しいんじゃないかと思います。
>私も同感です。
SDKを使ってすべてC言語でWindowのアプリケーションを作るよりは楽だと思います。
確かにC++を使うので、その分難しいところもあります。



>親ダイアログの関数を無事に呼べれば解決しそうな気がします。
ダイアログではないですが僕が良く使う方法は、
グロ-バル変数でCXXXDlg *Dlgを作成する。
(CXXXDlgは親ダイアログのクラス名)
親ダイアログのOnInitDialogでなく以下のところで
Dlg = this;を作成する。

 
XXXXDlg::CBALOOKDlg(CWnd* pParent /*=NULL*/)
    : CDialog(XXXXDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(CBALOOKDlg)
    //}}AFX_DATA_INIT
     Dlg = this ←ココ
    // メモ: LoadIcon は Win32 の DestroyIcon のサブシーケンスを要求しませ
ん。
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
あとは、関数を呼びたい所から「Dlg->XXXX」XXXは関数名
とすればいいと思います。

 注意として、ウィンドウの操作、親ダイアログ固有のイベントに関する動作の関数
は、SetEvent,フラグを利用して親ダイアログで動かさないとまずいと思います。
例外が発生して、(ウィンドウの操作で多いのがHWND == NULL) 途中でソフトが
中断される可能性があります。

ITO 2007/02/04(日) 14:27:44
追加です。
 まだ、解決してないのなら、続けたほうがみらくるさん、後にみらくるさんと
 同じように分らなくて過去ログをみにきた人のためにもなります。

遠慮は必要ですが、解からないのに解決にすることはないと思います。

ITO 2007/02/04(日) 14:33:08
連投すみません
>遠慮は必要ですが
自分で解決しようとしないで何でも質問すればいいと言うのはまずいです。
少しでも努力することが大切です。

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