始めに
C++Builderでは、フォームを前面に出して、他のアプリの背後に行かないようにするには、通常は FormStyle=fsStayOnTop にすれば良いが、複数のウィンドウを同時に表示した場合は、意図した通りに動作しない。
かなりの試行錯誤の上で、意図した通りに動作したと思われるので、
そのソースコードを記載する。
なお、FormStyleはfsNormal のままとする。
なお、Visual C++でもウィンドウメッセージに対する処理なので、
同様にウィンドウメッセージ処理を設定すれば、
同じような効果が得られると思われる。
メインフォーム
ウィンドウメッセージの「WM_NCACTIVATE」をフックするのと、
サブフォームをモードレスで開く。
//---------------------------------------------------------------------------
# ifndef Unit1H
# define Unit1H
//---------------------------------------------------------------------------
# include <System.Classes.hpp>
# include <Vcl.Controls.hpp>
# include <Vcl.StdCtrls.hpp>
# include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE で管理されるコンポーネント
void __fastcall FormShow(TObject *Sender);
private: // ユーザー宣言
void __fastcall WindowNActive(TMessage &message);
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(WM_NCACTIVATE, TMessage, WindowNActive);
END_MESSAGE_MAP(TForm);public: // ユーザー宣言
public: // ユーザー宣言
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
# endif
BEGIN_MESSAGE_MAP~でWM_NCACTIVATEをフックしている。
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
# include <vcl.h>
# pragma hdrstop
# include "Unit2.h"
# include "Unit1.h"
//---------------------------------------------------------------------------
# pragma package(smart_init)
# pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WindowNActive(TMessage &message)
{
HWND hWnd = this->Handle;
if(message.WParam)
{
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0,SWP_NOSIZE | SWP_NOMOVE );
}
else
{
}
message.Result = 1;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
Form2->Show();
}
//---------------------------------------------------------------------------
WM_NCACTIVATEをフックしたときの処理と、
Form2の表示を行っている。
サブフォーム
ウィンドウメッセージの「WM_NCACTIVATE」をフック。
ただし、Form1をクリックしたときにも処理が来てしまうので、
LParam(=ウィンドウハンドル)をチェックして、
Form1に対する物の場合は、処理しないようにしている。
//---------------------------------------------------------------------------
# ifndef Unit2H
# define Unit2H
//---------------------------------------------------------------------------
# include <System.Classes.hpp>
# include <Vcl.Controls.hpp>
# include <Vcl.StdCtrls.hpp>
# include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
class TForm2 : public TForm
{
__published: // IDE で管理されるコンポーネント
TMemo *Memo1;
private: // ユーザー宣言
void __fastcall WindowNActive(TMessage &message);
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(WM_NCACTIVATE, TMessage, WindowNActive);
END_MESSAGE_MAP(TForm);public: // ユーザー宣言
__fastcall TForm2(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm2 *Form2;
//---------------------------------------------------------------------------
# endif
//---------------------------------------------------------------------------
# include <vcl.h>
# pragma hdrstop
# include "Unit1.h"
# include "Unit2.h"
//---------------------------------------------------------------------------
# pragma package(smart_init)
# pragma resource "*.dfm"
TForm2 *Form2;
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm2::WindowNActive(TMessage &message)
{
HWND hWnd = this->Handle;
//このウィンドウが表示されていない場合は処理しない
if(this->Visible == false)
{
message.Result = 1;
return;
}
//デバッグライト(必要が無ければ消す)
String str;
str.sprintf(L"w=[%x] l=[%x] r=[%x]",message.WParam,message.LParam,message.Result);
Memo1->Lines->Add(str);
if(message.WParam)
{
if(message.LParam == (int)Form1->Handle)
{
message.Result = 1;
return;
}
else
{
//前面に出す
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0,SWP_NOSIZE | SWP_NOMOVE);
}
}
else
{
if(message.LParam == (int)Form1->Handle)
{
message.Result = 1;
return;
}
}
message.Result = 0;
}
//---------------------------------------------------------------------------
動作画面
動作している時の様子を下記に示す。
追記
プロジェクトのcppファイルで
// Application->MainFormOnTaskBar = true;
の様にApplication->MainFormOnTaskBarをコメントアウトして下さい。
メインフォームとサブフォームの重なり関係に問題が生じます。
感想
これだけの事に相当ハマって、疲れました。
以上