1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

C++Builderで、複数のウィンドウを前面に出して、他のアプリの背後に隠れないようにする

Last updated at Posted at 2022-02-09

始めに

C++Builderでは、フォームを前面に出して、他のアプリの背後に行かないようにするには、通常は FormStyle=fsStayOnTop にすれば良いが、複数のウィンドウを同時に表示した場合は、意図した通りに動作しない。
かなりの試行錯誤の上で、意図した通りに動作したと思われるので、
そのソースコードを記載する。
なお、FormStyleはfsNormal のままとする。
なお、Visual C++でもウィンドウメッセージに対する処理なので、
同様にウィンドウメッセージ処理を設定すれば、
同じような効果が得られると思われる。

メインフォーム

ウィンドウメッセージの「WM_NCACTIVATE」をフックするのと、
サブフォームをモードレスで開く。

Unit1.h
//---------------------------------------------------------------------------

# 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をフックしている。

Unit1.cpp
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------

# 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に対する物の場合は、処理しないようにしている。

Unit2.h
//---------------------------------------------------------------------------
# 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
Unit2.cpp

//---------------------------------------------------------------------------

# 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;
}
//---------------------------------------------------------------------------

動作画面

動作している時の様子を下記に示す。

window.png

追記

プロジェクトのcppファイルで

// Application->MainFormOnTaskBar = true;

の様にApplication->MainFormOnTaskBarをコメントアウトして下さい。
メインフォームとサブフォームの重なり関係に問題が生じます。

感想

これだけの事に相当ハマって、疲れました。

以上

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?