リソースを使わないでモーダルダイアログを作成する方法

[戻る]
matyam 2010/01/28(木) 10:46:06
初心者です
複数のアプリで共用したいダイアログがあるのでリソースを使わないでプログラムを作成
したいのです。
コントロール類はすべてコードで配置しています。
(OK,CANCELボタンのほかいくつかのコントロールが配置され指定された時間で自動的に閉
じるダイアログです。リソースIDを使った場合には正常に表示されます)
環境は
Windows XP SP3, Visual Studio 2008 MFC
です

http://www.cycleof5th.com/tips/index.php?date=2007-05-16/1
を参考にして記述したのですが
digcore.cppの311行の
hWnd = ::CreateDialogIndirect(hInst, lpDialogTemplate,
    pParentWnd->GetSafeHwnd(), AfxDlgProc);
      (BOOL CWnd::CreateDlgIndirect内)
でhWndがNULLになり生成に失敗しているようです。

関連する部分のコード

messageBox.h
typedef struct _ty_dtp{
    DLGTEMPLATE dtp;
    WORD parm[4];
    _ty_dtp(){
        dtp.x = 0;
        dtp.y = 0;
        dtp.cx = 200;
        dtp.cy = 100;
        dtp.cdit = 2;
        dtp.style = 2160591040;  //リソースで作成したときの値
        dtp.dwExtendedStyle = 0;
    }
} ty_DLGTEMPLATE;

messageBox.cpp
Cmessagebox::Cmessagebox(CWnd* pParent /*=NULL*/)
//: CDialog(Cmessagebox::IDD, pParent) //リソース使用の場合はコメントアウトしな
い
{
swo = SW_SHOW;
swc = SW_SHOW;
killtime = 10000;

}

呼び出し部分
ty_DLGTEMPLATE dtp;
memset( dtp.parm, 0, sizeof( WORD ) * 4 );
msg = new Cmessagebox;
msg->setMessage( tmp0, 300, 40, 500000 );
msg->InitModalIndirect( &dtp.dtp, NULL );
stsd = msg->DoModal();
delete msg;
msg = NULL;

初心者かつ質問も初めてですので情報が足りないかもしれませんがよろしくお願いしま
す。

bun 2010/01/28(木) 11:23:28
コントロール類をコードで配置しただけなら、
コントロールが1つも載っていない枠だけのダイアログリソースを作成し、
普通にモーダルダイアログとしてDoModal()すれば良いのでは?

その後、InitDialogで、各コントロールをCreateしていけば良いだけです。

matyam 2010/01/28(木) 11:56:11
bunさん
早速の回答ありがとうございます。

確かにそのとおりなのですが,
複数のアプリでダイアログを共用しようとするとIDが重複しないように注意して設定しな
ければならないと思います。
リソース使わなければIDの重複を気にすることなくプログラミングができると思い質問さ
せていただきました。

背景の説明が不足して申し訳ありません。

仲澤@失業者 2010/01/28(木) 13:04:38
>複数のアプリでダイアログを共用しようとするとIDが重複しないように注意して
>設定しな>ければならないと思います。
>リソース使わなければIDの重複を気にすることなくプログラミングができると思い
>質問さ>せていただきました。

ん??? 全く意味がわかりませんねぇ。

複数の別々のアプリケーションで共有するDLGなら、
DLLにリソースとコードを分離すれば十分ですよね。
コモンダイアログ(ファイルオープンなど)と同じ仕組みじゃ
だめな理由が聞きたいところです。

そもそも、IDが違うということは、そのコントロールの
意味自体が異なるということです。意味の異なるコントロールを
配置したDLGは意味の異なるDLGであるのであって、
そもそも別に実装しなければいけません。

ITO 2010/01/28(木) 13:37:17
ん?
> 複数のアプリで共用したいダイアログがあるのでリソースを使わないでプログラムを
> 作成したいのです。
それは無理かな?と思います。
何か方法があるなら僕も知りたいですね。

> コントロール類はすべてコードで配置しています。
> リソース使わなければIDの重複を気にすることなくプログラミングができると思い
> 質問させていただきました。
IDってダイアログ上で使うコントロールIDですよね?
IDの重複を避けるのもリソースを使う目的のひとつだと思います。
コンパイルした時にエラーで知らせてくれます。

subaru 2010/01/28(木) 13:54:55
とりあえず
>dtp.cdit = 2;
コントロールが1つもないのに2を指定しているのはおかしいでしょう。

#ダイアログテンプレートを組み立てるのは面倒なので
#一旦リソースから読み込んでそのバイナリの内容を確認し、
#コード側に静的な配列として保持するというのもありかも。

matyam 2010/01/28(木) 13:58:14
中澤@失業者さま

厳しいご指摘ありがとうございます
当方初心者につきDLLについてはよくわからないのでCDialogの派生クラス(Cmessagebox)
を作りそのクラスを共用できないかと考えました。

Cmessagebox.hで
#define IDD_MESSAGEBOX    199
のように設定した場合
それを呼び出す方(メイン側)で同じ番号の空のリソースを作成すればダイアログを作成で
きるのですが,すでに同じ番号のダイアログが作成されていた場合に問題があるように思
われました。(認識が間違っているかも知れません)
そこで,ネットで検索してリソースを使わずにダイアログを作成する方法を見つけたので
試してみたところダイアログが表示できなかったので質問することにしました。

matyam 2010/01/28(木) 14:07:40
ITOさま

>> コントロール類はすべてコードで配置しています。
>> リソース使わなければIDの重複を気にすることなくプログラミングができると思い
>> 質問させていただきました。
>IDってダイアログ上で使うコントロールIDですよね?
>IDの重複を避けるのもリソースを使う目的のひとつだと思います。
>コンパイルした時にエラーで知らせてくれます。

ダイアログのID(Resource.hに記述されるもの)です

ロマ 2010/01/28(木) 14:38:27
コードを見て思いつくのは、
* cdit=2なのにDLGITEMTEMPLATEがない
* style(0x80c800c0)にDS_SETFONT(0x40)が指定されているのにフォント情報がない
です。

ty_DLGTEMPLATEのメモリーダンプと
正常なリソースをLoadResourceしたdlgtemplateのダンプを比較してみてください。
(VS2008でどうやれば簡単にダンプが出るのかは私には分かりませんが)

matyam 2010/01/28(木) 14:39:39
subaruさま

dtp.cdit = 0;

にするとCmessageBoxのOnInitDialog()まで行き着くことができました。
ありがとうございます。

CmessageBoxはDialogの挿入で作ったクラスでリソースはOKとCancelボタンがある状態で
す。そのDLGTEMPLATEをみていたためdtp.cdit = 2 になったものと思います。
OnInitDialog()ではOKボタンCancelボタンを移動しているのでそのところでエラーが出ま
すが一歩進んだと思います。
Dialogの挿入で作成したリソースにはOKとCancelボタンがあるのでそのDLGTEMPLATEを使
えばOKボタンCancelボタンの情報もあると思ったのですが足りないようですね。

matyam 2010/01/28(木) 16:02:39
[[解決]]
みなさま

質問の仕方が悪くて申し訳ありませんでした。

dtp.cdit = 0;

として

CmessageBoxのOnInitDialog()内にボタンコントロール(OKボタンCancelボタン相当)をコ
ードで書く

ことにより目的(リソースを使うことなくダイアログ作成する)が達成できました。

どうもありがとうございました。

仲澤@失業者 2010/01/28(木) 16:20:47
>Cmessagebox.hで
>#define IDD_MESSAGEBOX    199
>のように設定した場合
>それを呼び出す方(メイン側)で同じ番号の空のリソースを作成すればダイアログを
>作成できるのですが,すでに同じ番号のダイアログが作成されていた場合に問題が
>あるように思われました。(認識が間違っているかも知れません)

 残念ならがら間違っていると思います。
この問題が起きるのは、DLGのリソース dlg.rcを複数のexeの*.rcで
#includeして「*.rc」単位で共用しようとしているの場合などです。
この方法は、もはや誰もやらなくなった危険な賭けであると言っておきましょう。

 いまは、共用のDLGは共用のDLLに収めるのがごく普通の方法です。
きれいにカプセル化されたDLL上のDLGは、そのIDがいくつであるかなど、
知る必要さえありません。

 多くのプログラマが、おそらく一生使うことのないであろう、
CreateDialogIndirect()を勉強するより、DLLの活用方法を学ぶのを優先
させたほうが自分のためだと考えます。
 まぁ、外野席の人はおもしろいかもしれませんが(vv;)。

matyam 2010/01/28(木) 16:38:16
中澤@失業者さま

今後DLLについて勉強していきたいと思います。
どうもありがとうございました

subaru 2010/01/28(木) 17:38:53
自作MessageBox程度のものみたいなのでリソースなしで作るのもありかとは思うけど
多言語対応が必要になったらDLLに分離せざるを得ないでしょうね。

maru 2010/01/28(木) 17:56:49
>  多くのプログラマが、おそらく一生使うことのないであろう、
> CreateDialogIndirect()を勉強するより、DLLの活用方法を学ぶのを優先
> させたほうが自分のためだと考えます。
これには同意いたしますが、

> この問題が起きるのは、DLGのリソース dlg.rcを複数のexeの*.rcで
> #includeして「*.rc」単位で共用しようとしているの場合などです。
> この方法は、もはや誰もやらなくなった危険な賭けであると言っておきましょう。
残念ながら正しい記述とは言えないでしょう。マイクロソフトがやっています。
Visual Studioが作成したリソースの一部を抜粋。
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_JPN)
LANGUAGE 17, 1
#pragma code_page(932)
#include "res\\MFC_MDI.rc2"  // Microsoft Visual C++ 以外で編集されたリソース
#include "l.JPN\\afxres.rc"      // 標準コンポーネント
#include "l.JPN\\afxprint.rc"  // 印刷/印刷プレビュー リソース
#if !defined(_AFXDLL)
#include "l.JPN\\afxribbon.rc"        // MFC のリボン リソースとコントロ
ール バー リソース
#endif
#endif

既存のアプリケーションにリソースを追加するならいざ知らず、新規にアプリケーショ
ンを作成するのであれば、そのIDを避けて使用すればいいだけの話。要は使い方次第。
複数のそういうリソースがあってそのIDが衝突している場合は問題ですが。

仲澤@失業者 2010/01/28(木) 18:28:21
maruさんコメントありがとうございます。
やや意味が違ってるので、少し補足すると、

・M$さんがやっているのは「同じ」プロジェクト内での話し
・自分の主張は「異なる」プロジェクト間でのリソースの共有

であることをご確認ください(笑)。

そ〜いえば rcinclude っていうのもあったな(とほい目)。

仲澤@失業者 2010/01/28(木) 18:36:12
補足の訂正
・自分の主張は「異なる」プロジェクト間での「自(社)作」リソースの共有

もちろん、自分で編集して「よい」*.rcの話です。
これって、ほんとにまだやってる人いるんですか(質問)。
とほほっ(vv;)。

ロマ 2010/01/28(木) 20:42:23
解決したので、以下、お気楽に

>>  多くのプログラマが、おそらく一生使うことのないであろう、
>> CreateDialogIndirect()を勉強するより、DLLの活用方法を学ぶのを優先
>> させたほうが自分のためだと考えます。
> これには同意いたしますが、
 
プロパティーシートとプロパティーページのフォントを合わせるには
DLGTEMPLATEを使うしかないと思うんですが、他の手はありますか。

仲澤@失業者 2010/01/29(金) 09:20:05
>プロパティーシートとプロパティーページのフォントを合わせるには
>DLGTEMPLATEを使うしかないと思うんですが、他の手はありますか。

リソース上のフォントが一致しているというのは、ただの気休めにすぎません。
常に親と一致させたいのなら、

SetWindowFont( GetParent()->GetWindowFont());

する以外に確実な方法はありません。

ロマ 2010/02/01(月) 06:13:31
MFCということを忘れていました。
MFCだと中の人がDLGTEMPLATEを使ってシートとページのフォントを一致させてますね。

lfMessageFont付きのMessageBoxもどきを作る場合は、
コントロールのレイアウトを計算するより
DialogBoxIndirectの方が便利なように思います(MFCがほとんどやってくれそうです)。

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