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

#始めに
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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466942/98934da7-31ef-8f1d-7189-8a449d8473a5.png)

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

//		Application->MainFormOnTaskBar = true;

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

#感想

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

以上