トップ回答者
変数の共有

質問
回答
-
今回の問題の解決に寄与するかどうかにかかわらず、
なんだかおかしいなと思うところを指摘してみます。
CSplashDlg cDlg;
これ、コメントアウトするとスプラッシュウィンドウ自体が作成されないので、
//cDlg.Create(CSplashDlg::IDD); ←この行とその下をコメントでなくすると、ダイアログは表示されますが、
その下のSetWindowLong()やら、SetWindowPos()を呼び出してしまうのはまずいのでは?//cDlg.ShowWindow(SW_SHOW); Staticコントロールに記述した文字列は表示されません。その場合すぐ下の行はコメントとし ています。
まあ、ここでいうすぐ下の行というのが、SetWindowLong()とSetWindowPos()であれば問題ないですが。
で、ここでShowWindow()を呼んでしまうと、WM_EX_TOOLWINDOWがセットされる前に
表示されてしまうのでスプラッシュウィンドウもタスクバーに表示されてしまうのではないですかね?
::SetWindowLong(cDlg.GetSafeHwnd(), GWL_EXSTYLE, WS_POPUP | WS_VISIBLE );
ここでは WS_POPUP | WS_VISIBLE となっていますが、
cDlg.SetWindowPos(&CWnd::wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
やりたいのは、WS_EX_TOOLWINDOWをつけてやりたいのですよね?
次の行で行っている、TOPMOSTにする処理も合わせて、
cDlg.ModifyStyleEx(0, WS_EX_TOOLWINDOW | WS_EX_TOPMOST);
が適当だと思います。
また、普通こういう場合は、SetWindowLong()よりも、ModifyStyleEx()を使うと思います。- 回答としてマーク B_Wolf 2009年9月17日 7:14
-
スプラッシュウィンドウをいつまで表示しているのか、によって変わってきますね・・・。
現状は CTest04Dlg が DoModal によりモーダルループに入っていますから、モーダルループの終わる、EndDialog 呼び出し以降、というよりはモーダルダイアログが閉じた後で処理が行われます。
CTest04Dlg にスプラッシュダイアログのポインタでも持たせておき、
CTest04Dlg dlg;
CSplashDlg splash;
dlg.m_pSplash = &splash;
とでもしてメインのダイアログにスプラッシュダイアログのポインタを渡してから、スプラッシュダイアログを表示するようにしておいて、
メインダイアログの初期化処理が終わった段階でいいのなら、CTest04Dlg::OnInitDialog の最後で、
m_pSplash->DestoryWindow();
とするか、メインダイアログが表示されてから、なら CTest04Dlg::OnPaint でスプラッシュダイアログを閉じるか、という感じでしょうか。
CTest04Dlg のコンストラクタでスプラッシュダイアログのポインタを NULL にしておく事と、OnPaint の時点でスプラッシュを閉じるのなら、ポインタが NULL ではないのかの確認処理と、スプラッシュを閉じた後にポインタを NULL にする事を忘れないようにして下さい。
# メインダイアログで CWnd::OnEnterIdle をオーバーライド、というのを最初に考えたのに、ちらっと確認した限りは呼ばれなかった・・・。親ウィンドウが受けるメッセージだったかな・・・。- 回答としてマーク B_Wolf 2009年9月17日 7:14
-
返信が遅くなり、すいませんでした。ウィルス対策でシステムのフルスキャン等をしておりましたので・・・。
それでスプラッシュウィンドウ替わりのダイアログ内の Static、こちらでは表示できていますが・・・。
CSplashDlg の Static コントロールの Visible が false になっている、何て事はないですよね?
追記
しっかり読み込んでいなかったようで、勘違いしていました。
スプラッシュウィンドウ替わりのダイアログにリソースエディタで Static を貼り付け、文章はない、という状況でしょうか?
スプラッシュウィンドウ替わりのダイアログはモードレスで作成されているようですので、DDX 部分で空の文字列を渡しているとか、DDX 部分で指定する為、予め空になっている等という事はないでしょうか?
この予想があっているとして、ですが、スプラッシュウィンドウ内で色々処理をするべきではないと思いますので、リソースエディタで表示文字列を設定し、単に表示するだけ、にした方がいいと思います。
なお、紹介させて頂いた MSJ サンプルですが、これは別スレッドを起動して、再描画処理もしっかり行い、メインウィンドウの初期化が終わったら消える、という少し重た目のサンプルです。
ですが、Visual Studio のスプラッシュウィンドウ等のようにプライマリスレッドが初期化処理で余裕がなく、スプラッシュウィンドウの再描画処理が行われない等の場合には非常に効果があります。
余裕があれば、一度目を通してみる事をお勧めします。
さらに追記、というよりバグ修正
以前の書き込みで提示したコードですが、
::SetWindowLong(dlg.GetSafeHwnd(), GWL_EXSTYLE, WS_EX_TOOLWINDOW);
ではなく、
::SetWindowLong(dlg.GetSafeHwnd(), GWL_EXSTYLE, dlg.GetExStyle() | WS_EX_TOOLWINDOW);
でした。全スタイルを無視して WS_EX_TOOLWINDOW のみを設定していたわけで、そのせいでダイアログフレームも表示されなくなっていました。
今、B_Wolf さんが抱えておられるバグとは無関係ですが、念の為、ご報告しておきます。
すべての返信
-
アプリケーションクラス・・・ということはCWinApp派生クラスでしょうか?
そこであればAfxGetAppでとれるので
static_cast<CHogeHogeApp>(AfxGetApp())->m_hogehoge
の様な形でアクセスできます。
ほかにもtheApp.m_hogehogeとか、いっそ共有にしたいメンバ変数をstatic宣言してCHogeHogeApp::m_hogehogeとかでもいいと思いますよ。
#まぁせめてsetter/getterを使うのがましかなぁとか思いますが。
どんなデータを共有するのかが書かれていませんので、アプリケーションクラスに置くのが正しいかどうかはご自分で判断してください。
もちろん、同じプロセスのダイアログ間ですよね?
異なるプロセスなら何らかのプロセス間通信が必要ですし、同一プロセスでもスレッドが違うなどであれば排他処理などが必要かもしれません。- 編集済み らーめん食べたいなぁ 2009年9月3日 4:15 もうちょっと追記
-
根本は・・・モードレスダイアログが出せないところですね。
アプリケーションの設定であれば、アプリケーションクラスがデータを持つことはおかしくないので位置的にはそこでいいと思います。
ちなみにアプリケーションが起動時に表示する、B_Wolfさんが見出し画面と呼んでいるものは「スプラッシュウィンドウ」とか「スプラッシュスクリーン」と呼ばれるものです。
モードレスダイアログで、スプラッシュみたいな処理をしたい場合
CHogeDlg dlg;
dlg.Create(CHogeDlg::IDD);
dlg.ShowWindow(SW_SHOW);// 読み込み処理
dlg.DestroyWindow();
ぐらいでもよいと思います。
ただまぁ読み込みがすぐ終わってすぐ消えそうな気もしますが。
スプラッシュではなくずっと表示させる場合、ダイアログのインスタンスを上記のような作り方をすると関数を抜けるとインスタンスが破棄されてしまうので、別のところにおいてください。
#「次の質問は表示したダイアログに読み込み経過を表示するようにプログレスバーを置いたのですが、プログレスバーが動きません」かなぁ? -
どーも、PATIOです。
私もらーめん食べたいなぁさんと同意見でこの場合はモードレスでうまくいっていない原因を突き詰めて解決すべきかなと
思います。本来は出来ないはずは無いので。
モードレスとモーダルの違いは、ウインドウを表示するコードが書かれた関数の中で止まるかどうかです。
モーダルであれば、その関数内で止まるのでダイアログのインスタンスを関数内のローカル変数にしていても
大丈夫なんですが、モードレスの場合はそのまま処理が流れてしまうので状況によってはインスタンスを
ローカルにおくのは拙いケースもあります。
ウインドウが閉じられるまで確実にインスタンスが保持されている事を保証できれば良いのですけれど、
タイミング的に怪しい場合は、インスタンスをメンバー変数に置いたりする必要があるかもしれません。
この辺はどう実装するのかで話が変わってきそうです。
解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。 -
こんばんわ。ミッヒーといいます。
スプラッシュウィンドウが表示されないと言う事ですが、メインのダイアログは DoModal で呼び出していませんか?
メインのダイアログの OnInitDialog はダイアログの作成途中、初期化部分ですので、そこでスプラッシュウィンドウを出そうとしても、メインの DoModal の戻りを待っている状態ですから、何も表示されないのではないかと思います。
スプラッシュウィンドウを表示するのであれば、メインのダイアログを表示する ( DoModel ) 前に表示処理を行う必要があると思います。
なお、スプラッシュウィンドウに関してですが、http://www.microsoft.com/msj/code.aspx にある、MSJ October 1999 Vol.14 No.10 の C++ サンプルが非常に参考になると思います。
# MSJ 日本語版ではApril 2000 No.66 ですが、古書と言っていいものですよね。
# Best of MSJ Vol.9 に載っているかもしれません。( これも古い書籍ですが・・・。 )
追記
全体像がよく判らないので、想像下での話になりますが。
ダイアログを表示するが、その前にデータを読み込む必要があり、起動しているのが判るようにスプラッシュウィンドウを表示させ、その間にデータを読み込む、という場合であるなら、CWinApp 派生クラスにデータを読み込むのではなく、メインのダイアログを宣言しておいて、そのメンバ変数に読み込むようにすればいいように思いますが・・・。- 編集済み ミッヒー 2009年9月7日 14:33 追記
-
CSplashDlgの実装が全く分かりませんから、表示されませんと書かれても状況がわかりません。
そもそもCSplashDlg上のStaticコントロールがどういう状態で配置されているのかも分かりませんし。
単純に表示するべき文字列がうまく引き渡せていないとかと言う話なら文字列を引き渡せば、
解決するかもしれません。
提示されている情報からではなんとも判断が付きません。
あと、デバッガで追いかけたりしていますか?
CSplashDlgのOnInitDialogとかにブレイクポイントを張って
Staticコントロールに設定する内容が引き渡されているかとか調べられると思うのですが。
解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。 -
Static コントロールのみが表示されない、という現象でしょうか?
というより、スプラッシュウィンドウの為、Static だけですよね・・・。
ご提示して下さったのとほぼ等価なコードを作ってみましたが、タスクバーにタイトルが表示され、メインのダイアログの下に表示されてました。
ひょっとして、メインダイアログと勘違いされている、等という事はないでしょうか?
( 勘違いだったらすいません。 )
それで、そちらの状態が判らないので、スプラッシュウィンドウを表示してみる事にしました。
スプラッシュウィンドウですから、キャプション、その他をダイアログリソースで削除し、タスクバーにタイトルが表示されないように、
CSplashDlg dlg;
::SetWindowLong(dlg.GetSafeHwnd(), GWL_EXSTYLE, WS_EX_TOOLWINDOW);
dlg.SetWindowPos(&CWnd::wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
で表示されるようになりましたが、ダイアログとして作成したものを、ツールウィンドウ扱いしている為、スプラッシュダイアログのエッジが描画されませんでした。
そこで改めて、ご紹介した MSJ サンプルを見た所、ダイアログではなく、ウィンドウがスプラッシュウィンドウとして使われていました。
キャプションも、システムメニューもない、WS_POPUP | WS_VISIBLE のみが設定されたウィンドウです。
確かにポップアップウィンドウなら、WS_EX_TOOLWINDOW フラグを指定してタスクバーに表示させない、という手間も必要ないわけですが・・・。
CSplashDlg::OnNcPaint ハンドラを実装し、ダイアログのエッジを描画するか、ポップアップウィンドウとして作成するか、という感じのようです。 -
PATIOさん、ミッヒーさんお世話になっております。
CSplashDlgの実装ですが、リソースの追加でダイアログを追加し、そのときに作成されたSTATICコントロールのキャプションに「初期化実行中」と書き換えてそのまま表示させようとしているだけなのですが、メインのダイアログが表示されるとSTATICコントロールの文字も表示されます。
メインダイアログの表示前はSTATICコントロールの文字は表示されないという現象です。
CSplashDlgは、ポップアップで作成しています。
なお、OnInitDailogにブレークポイントを張るとそこで一時停止します。 -
返信が遅くなり、すいませんでした。ウィルス対策でシステムのフルスキャン等をしておりましたので・・・。
それでスプラッシュウィンドウ替わりのダイアログ内の Static、こちらでは表示できていますが・・・。
CSplashDlg の Static コントロールの Visible が false になっている、何て事はないですよね?
追記
しっかり読み込んでいなかったようで、勘違いしていました。
スプラッシュウィンドウ替わりのダイアログにリソースエディタで Static を貼り付け、文章はない、という状況でしょうか?
スプラッシュウィンドウ替わりのダイアログはモードレスで作成されているようですので、DDX 部分で空の文字列を渡しているとか、DDX 部分で指定する為、予め空になっている等という事はないでしょうか?
この予想があっているとして、ですが、スプラッシュウィンドウ内で色々処理をするべきではないと思いますので、リソースエディタで表示文字列を設定し、単に表示するだけ、にした方がいいと思います。
なお、紹介させて頂いた MSJ サンプルですが、これは別スレッドを起動して、再描画処理もしっかり行い、メインウィンドウの初期化が終わったら消える、という少し重た目のサンプルです。
ですが、Visual Studio のスプラッシュウィンドウ等のようにプライマリスレッドが初期化処理で余裕がなく、スプラッシュウィンドウの再描画処理が行われない等の場合には非常に効果があります。
余裕があれば、一度目を通してみる事をお勧めします。
さらに追記、というよりバグ修正
以前の書き込みで提示したコードですが、
::SetWindowLong(dlg.GetSafeHwnd(), GWL_EXSTYLE, WS_EX_TOOLWINDOW);
ではなく、
::SetWindowLong(dlg.GetSafeHwnd(), GWL_EXSTYLE, dlg.GetExStyle() | WS_EX_TOOLWINDOW);
でした。全スタイルを無視して WS_EX_TOOLWINDOW のみを設定していたわけで、そのせいでダイアログフレームも表示されなくなっていました。
今、B_Wolf さんが抱えておられるバグとは無関係ですが、念の為、ご報告しておきます。 -
ミッヒーさん、度々申し訳ありません。
いわれるように、作ってみたのですが、うまく表示されません。
サンプルコードがうまく添付できないので、下記に夫々のコードを記します。どこか間違いがあるのでしょうか。また、
::SetWindowLong(dlg.GetSafeHwnd(), GWL_EXSTYLE, dlg.GetExStyle() | WS_EX_TOOLWINDOW);
を実行すると
cDlg.SetWindowPos(&CWnd::wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
の実行でエラーが発生します。
// Test04.h : PROJECT_NAME アプリケーションのメイン ヘッダー ファイルです。
//#pragma once
#ifndef __AFXWIN_H__
#error "PCH に対してこのファイルをインクルードする前に 'stdafx.h' をインクルードしてください"
#endif#include "resource.h" // メイン シンボル
// CTest04App:
// このクラスの実装については、Test04.cpp を参照してください。
//class CTest04App : public CWinApp
{
public:
CTest04App();// オーバーライド
public:
virtual BOOL InitInstance();// 実装
DECLARE_MESSAGE_MAP()
};extern CTest04App theApp;
// Test04.cpp : アプリケーションのクラス動作を定義します。
//#include "stdafx.h"
#include "Test04.h"
#include "Test04Dlg.h"
#include "SplashDlg.h"#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CTest04AppBEGIN_MESSAGE_MAP(CTest04App, CWinApp)
ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()
// CTest04App コンストラクションCTest04App::CTest04App()
{
// TODO: この位置に構築用コードを追加してください。
// ここに InitInstance 中の重要な初期化処理をすべて記述してください。
}
// 唯一の CTest04App オブジェクトです。CTest04App theApp;
// CTest04App 初期化BOOL CTest04App::InitInstance()
{
// アプリケーション マニフェストが visual スタイルを有効にするために、
// ComCtl32.dll Version 6 以降の使用を指定する場合は、
// Windows XP に InitCommonControlsEx() が必要です。さもなければ、ウィンドウ作成はすべて失敗します。
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
// アプリケーションで使用するすべてのコモン コントロール クラスを含めるには、
// これを設定します。
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);CWinApp::InitInstance();
if (!AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
return FALSE;
}// 標準初期化
// これらの機能を使わずに最終的な実行可能ファイルの
// サイズを縮小したい場合は、以下から不要な初期化
// ルーチンを削除してください。
// 設定が格納されているレジストリ キーを変更します。
// TODO: 会社名または組織名などの適切な文字列に
// この文字列を変更してください。
SetRegistryKey(_T("アプリケーション ウィザードで生成されたローカル アプリケーション"));CSplashDlg cDlg;
//cDlg.Create(CSplashDlg::IDD); ←この行とその下をコメントでなくすると、ダイアログは表示されますが、
//cDlg.ShowWindow(SW_SHOW); Staticコントロールに記述した文字列は表示されません。その場合すぐ下の行はコメントとし ています。
::SetWindowLong(cDlg.GetSafeHwnd(), GWL_EXSTYLE, WS_POPUP | WS_VISIBLE );
cDlg.SetWindowPos(&CWnd::wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);CTest04Dlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: ダイアログが <OK> で消された時のコードを
// 記述してください。
}
else if (nResponse == IDCANCEL)
{
// TODO: ダイアログが <キャンセル> で消された時のコードを
// 記述してください。
}// ダイアログは閉じられました。アプリケーションのメッセージ ポンプを開始しないで
// アプリケーションを終了するために FALSE を返してください。
return FALSE;
}
"SplashDlg.h"のコードです。
#pragma once
#include "afxwin.h"
// CSplashDlg ダイアログclass CSplashDlg : public CDialog
{
DECLARE_DYNAMIC(CSplashDlg)public:
CSplashDlg(CWnd* pParent = NULL); // 標準コンストラクタ
virtual ~CSplashDlg();using CDialog::Create;
// ダイアログ データ
enum { IDD = IDD_SPLASH_DIALOG };protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV サポートCWnd* m_pParent;
int m_nID;DECLARE_MESSAGE_MAP()
public:
BOOL Create(void);
virtual BOOL OnInitDialog();
};
// SplashDlg.cpp : 実装ファイル
//#include "stdafx.h"
#include "Test04.h"
#include "SplashDlg.h"
// CSplashDlg ダイアログIMPLEMENT_DYNAMIC(CSplashDlg, CDialog)
CSplashDlg::CSplashDlg(CWnd* pParent /*=NULL*/)
: CDialog(CSplashDlg::IDD, pParent)
{
m_pParent = pParent;
m_nID = CSplashDlg::IDD;
}CSplashDlg::~CSplashDlg()
{
}void CSplashDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CSplashDlg, CDialog)
END_MESSAGE_MAP()
// CSplashDlg メッセージ ハンドラBOOL CSplashDlg::Create(void)
{
return CDialog::Create(m_nID, m_pParent);
}BOOL CSplashDlg::OnInitDialog()
{
CDialog::OnInitDialog();UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
// 例外 : OCX プロパティ ページは必ず FALSE を返します。
}
以上です。
よろしくお願いいたします。 -
今回の問題の解決に寄与するかどうかにかかわらず、
なんだかおかしいなと思うところを指摘してみます。
CSplashDlg cDlg;
これ、コメントアウトするとスプラッシュウィンドウ自体が作成されないので、
//cDlg.Create(CSplashDlg::IDD); ←この行とその下をコメントでなくすると、ダイアログは表示されますが、
その下のSetWindowLong()やら、SetWindowPos()を呼び出してしまうのはまずいのでは?//cDlg.ShowWindow(SW_SHOW); Staticコントロールに記述した文字列は表示されません。その場合すぐ下の行はコメントとし ています。
まあ、ここでいうすぐ下の行というのが、SetWindowLong()とSetWindowPos()であれば問題ないですが。
で、ここでShowWindow()を呼んでしまうと、WM_EX_TOOLWINDOWがセットされる前に
表示されてしまうのでスプラッシュウィンドウもタスクバーに表示されてしまうのではないですかね?
::SetWindowLong(cDlg.GetSafeHwnd(), GWL_EXSTYLE, WS_POPUP | WS_VISIBLE );
ここでは WS_POPUP | WS_VISIBLE となっていますが、
cDlg.SetWindowPos(&CWnd::wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
やりたいのは、WS_EX_TOOLWINDOWをつけてやりたいのですよね?
次の行で行っている、TOPMOSTにする処理も合わせて、
cDlg.ModifyStyleEx(0, WS_EX_TOOLWINDOW | WS_EX_TOPMOST);
が適当だと思います。
また、普通こういう場合は、SetWindowLong()よりも、ModifyStyleEx()を使うと思います。- 回答としてマーク B_Wolf 2009年9月17日 7:14
-
-
ミッヒーさん、お世話になっております。
先ほど、表示はうまくできるようになったと、いいましたが、今度は読込処理終了後にスプラッシュウィンドウを閉じることが、できなくて困っております。
というのは、スプラッシュウインドウをAppクラスでメインダイアログが表示される前に表示するようにしているのですが、
CTest04Dlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
の後にcDlg.DestroyWindow()を記述して閉じれると思っていたのですが、実際に動作させると、メインダイアログを閉じないと、この行へ来ないので、スプラッシュウィンドウを閉じることができなくなっています。どのようにすれば閉じることができるでしょうか。
以上、よろしくご教授下さい。 -
スプラッシュウィンドウをいつまで表示しているのか、によって変わってきますね・・・。
現状は CTest04Dlg が DoModal によりモーダルループに入っていますから、モーダルループの終わる、EndDialog 呼び出し以降、というよりはモーダルダイアログが閉じた後で処理が行われます。
CTest04Dlg にスプラッシュダイアログのポインタでも持たせておき、
CTest04Dlg dlg;
CSplashDlg splash;
dlg.m_pSplash = &splash;
とでもしてメインのダイアログにスプラッシュダイアログのポインタを渡してから、スプラッシュダイアログを表示するようにしておいて、
メインダイアログの初期化処理が終わった段階でいいのなら、CTest04Dlg::OnInitDialog の最後で、
m_pSplash->DestoryWindow();
とするか、メインダイアログが表示されてから、なら CTest04Dlg::OnPaint でスプラッシュダイアログを閉じるか、という感じでしょうか。
CTest04Dlg のコンストラクタでスプラッシュダイアログのポインタを NULL にしておく事と、OnPaint の時点でスプラッシュを閉じるのなら、ポインタが NULL ではないのかの確認処理と、スプラッシュを閉じた後にポインタを NULL にする事を忘れないようにして下さい。
# メインダイアログで CWnd::OnEnterIdle をオーバーライド、というのを最初に考えたのに、ちらっと確認した限りは呼ばれなかった・・・。親ウィンドウが受けるメッセージだったかな・・・。- 回答としてマーク B_Wolf 2009年9月17日 7:14