static変数なのに2つインスタンスができてるような… こんなの絶対おかしいよ

C++/CLI でふ

コード

/*---------------------------------------------*
 * ヘッダー
 * 重要なのは WindowActiveHooker::INSTANCE;
 * WindowActiveHooker::GetInstance() で参照してる。
 *---------------------------------------------*/
ref class OfficeWindow : System::Windows::Forms::IWin32Window
{
public:

	OfficeWindow(System::IntPtr hWnd) : m_hWnd(hWnd){}
	property IntPtr Handle {
		virtual IntPtr get () { return m_hWnd; }
	}

private:

	System::IntPtr	m_hWnd;

};

public ref class WindowActiveHooker
{
public:

	delegate void FNWindowActiveCallback(System::Windows::Forms::IWin32Window^ wnd);
	static WindowActiveHooker^ GetInstance();

public:

	bool	Start();
	bool	Shutdown();

	event	FNWindowActiveCallback^ activeEvent;

internal:

	void	InvokeActiveEvent(OfficeWindow^ mWnd);

private:

	WindowActiveHooker();
	static void DummyFunction(System::Windows::Forms::IWin32Window^ wnd){}

private:

	static WindowActiveHooker^	INSTANCE = nullptr;

};


/*------------------------------------------*
 *	cpp
 *------------------------------------------*/
#include "stdafx.h"
#include "header.h"

#pragma managed(push, off)
LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam);
HHOOK            n_hHook = NULL;
#pragma managed(pop)

/*------------------------------------------*
 *	static
 *------------------------------------------*/
WindowActiveHooker^ WindowActiveHooker::GetInstance()
{
	if(INSTANCE == nullptr)
		INSTANCE = gcnew WindowActiveHooker();
	return INSTANCE;
}

/*------------------------------------------*
 *	instance
 *------------------------------------------*/
WindowActiveHooker::WindowActiveHooker()
{
	::OutputDebugString(TEXT("*** kashira?\n"));
//	activeEvent += gcnew FNWindowActiveCallback(DummyFunction);
}

bool WindowActiveHooker::Start()
{
	if(n_hHook != NULL)
		return false;
	n_hHook = ::SetWindowsHookEx(WH_CBT, &CBTProc, n_hInstance, ::GetCurrentThreadId());
	return n_hHook != NULL;
}

bool WindowActiveHooker::Shutdown()
{
	if(n_hHook == NULL)
		return false;
	if(::UnhookWindowsHookEx(n_hHook))
		n_hHook = NULL;
	return n_hHook == NULL;
}

void WindowActiveHooker::InvokeActiveEvent(OfficeWindow^ mWnd)
{
	activeEvent(mWnd);
}

// global funtion
void ReciveActiveMessageProxy(HWND hWnd)
{
	System::IntPtr h(hWnd);
	OfficeWindow   mWnd(h);
	WindowActiveHooker::GetInstance()->InvokeActiveEvent(%mWnd);
}

#pragma managed(off)


/*---------------------------------------------------------------------*
 *
 *	dll main
 *
 *---------------------------------------------------------------------*/
LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	if(nCode == HCBT_ACTIVATE)
	{
		const CBTACTIVATESTRUCT* activeStruct = (CBTACTIVATESTRUCT*)lParam;
		HWND                     hWnd         = (HWND)wParam;
		ReciveActiveMessageProxy(hWnd);
	}

	return ::CallNextHookEx(n_hHook, nCode, wParam, lParam);
}


BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
	if(fdwReason == DLL_PROCESS_ATTACH)
	{
		n_hInstance = hinstDLL;
	}

	return true;
}

使いはじめ

// C#
void init()
{
	// 使い始め
	// ウィンドウが作成された後に実行される
	WindowActiveHooker.GetInstance().Start();
	WindowActiveHooker.GetInstance().activeEvent += new WindowActiveHooker.FNWindowActiveCallback(INSTANCE_activeEvent);
}

void INSTANCE_activeEvent(IWin32Window wnd)
{
	// ごにょごにょ実行
}


これで、C++/CLI 側で event が invoke されて、C# 側の INSTANCE_activeEvent() がコールバックされるよねー! …と思ったら全然されない。

色々確認すると

  • C# 側の init() の中」と「C++/CLI CBTProc() を経由した ReciveActiveMessageProxy() の中」で、コンストラクタが2回走ってる。

→ WindowActiveHooker::INSTANCE が2つある…?

なーぜーやー… Singleton の意味が無いじゃないですか…



ちなみに、このクラスが定義されているライブラリは2つのプロジェクトから利用されています。 C# lib プロジェクトから static 変数を見るケースと、Office AddInプロジェクトから見るケースと。 …コレがイケナイ…と思ったけど、全然関係無いや(たぶん)

C# AddInプロジェクト ――┐(2)
  |                     ↓
  |(1)               C++/CLI プロジェクト
  ↓                       ↑
C# libプロジェクト ――――┘(1)

追記

C# Window アプリケーションからこれらライブラリを利用してみたところ、期待度どおりに Callback してくれました。 INSTANCE は複数出来てない模様。

となると、Office の何かが何かしてる…のかなぁ…あああどないせいっちゅーねん… orz