#include <windows.h>
#include <tchar.h>
#include <gdiplus.h>
#include <D2D1.h>

//  汎用プラグイン仕様ドラフト 2008/11/04 バージョン
//  現在のところ、ミニマムな仕様です。
//  現在の仕様で取得できないデータを取得するコールバックが欲しかったり、
//  通知して欲しいイベントなどがあれば、ご要望ください。

#pragma once

#pragma pack(push, 1)

namespace GenericPlugin
{
	enum DrawMode
	{
		DrawModeGdiplus = 0,
		DrawModeDirect2D,
	};
	class DrawItem		//  フェイスへの描画のためのオブジェクト
	{
	public:
		Gdiplus::Bitmap *FrameBuffer;	//  フェイスへ描画されるオブジェクトへのポインタ。中身のビットマップの書き換えだけ許可されている。決してdelete したり、サイズを変更したりしてはいけない
		RECT rcView;					//  フェイス上に描画される位置。このサイズが必ずしもビットマップのサイズと一致するわけではないので注意。この範囲内でアライメントされる場合がある。
		BOOL fIsVisible;				//  現在表示状態にあるか、非表示状態にあるかのフラグ。アニメーションなどは、表示状態のときのみ処理することを推奨
	};
	class DrawItemD2D
	{
	public:
		ID2D1RenderTarget *pRenderTarget;
		RECT rcView;
		BOOL fIsVisible;
	};

	class SoundData		//  サウンドデータを取得するためのオブジェクト
	{
	public:
		double * PCMData;	//  サンプルデータが格納されるバッファ。
		int nChannels;		//  PCMData に収められたチャネル数。Windows PCM 形式 (チャネルごとにインタリーブ) です。
		int nCount;			//  取得したサンプル数。PCMData の実際の数は、nChannels * nCount 個である。
	};

	class SoundInfo
	{
	public:
		int nUniqueId;				//  対象ファイルの一意 ID
		LPCTSTR pszFilePath;		//  ファイルのパス (ファイル名は含まない)
		LPCTSTR pszFileName;		//  ファイル名
		LPCTSTR pszTitle;			//  タグのタイトル
		LPCTSTR pszArtist;			//  タグのアーティスト
		LPCTSTR pszAlbum;			//  タグのアルバム
		LPCTSTR pszDate;			//  タグの日付
		LPCTSTR pszTrackNumber;		//  タグのトラック番号
		LPCTSTR pszGenre;			//  タグのジャンル
		LPCTSTR pszComment;			//  タグのコメント
		LPCTSTR pszTotalTime;		//  ファイルの総演奏時間
		LPCTSTR pszListCurrent;		//  ファイルのリスト上での演奏順番
		LPCTSTR pszListNumber;		//  ファイル番号 (プレイリストの No. カラムの値)
		LPCTSTR pszListCount;		//  リスト上のファイルの数
		LPCTSTR pszListPlayed;		//  リスト上の再生済みファイル数 (現在未実装)
		LPCTSTR pszListTotalTime;	//  リスト上の全ファイルの合計演奏時間
		LPCTSTR pszFileType;		//  ファイルの種類
		LPCTSTR pszBitrate;			//  平均ビットレート
		LPCTSTR pszBitsPerSample;	//  ビット深度
		LPCTSTR pszSamplerate;		//  サンプリングレート
		LPCTSTR pszChannels;		//  チャネル数
		LPCTSTR pszChannelMode;		//  チャネルモード文字列 (JointStereo とか、5.1ch Surround とか)
		LPCTSTR pszBitrateMode;		//  ビットレートモード (CBR or VBR)

		__int64 qlTotalTime;		//  ファイルの総演奏時間 (ms 単位)
		int nListCurrent;			//  ファイルのリスト上での演奏順番
		int nListNumber;			//  ファイル番号 (プレイリストの No. カラムの値)
		int nListCount;				//  リスト上のファイルの数
		int nListPlayed;			//  リスト上の再生済みファイル数 (現在未実装)
		__int64 qlListTotalTime;	//  リスト上の全ファイルの合計演奏時間
		int nBitrate;				//  平均ビットレート
		int nBitsPerSample;			//  ビット深度
		int nSamplerate;			//  サンプリングレート
		int nChannles;				//  チャネル数
	};

	//  データ取得のコールバック関数とか

	//DWORD WINAPI WaitLockFace(HANDLE hFace, DWORD nCount, CONST HANDLE *lpHandles, DWORD dwMilliseconds);
	//void WINAPI UnlockFace(HANDLE hFace);
	//HANDLE WINAPI FindFirstFaceItem(HANDLE hFace, LPCTSTR pszSubCategory, LPTSTR pszFieldName, int nBufferLength);
	//BOOL WINAPI FindNextFaceItem(HANDLE hffi, LPTSTR pszFieldName, int nBufferLength);
	//void WINAPI FindFaceItemClose(HANDLE hffi);
	//DrawItem WINAPI GetFaceItem(HANDLE hFace, LPCTSTR pszFieldName);
	//void WINAPI InvalidateFaceRect(HANDLE hFace, const RECT& rcUpdate);
	//void WINAPI UpdateFace(HANDLE hFace);
	//SoundData* WINAPI GetCurrentSoundData(int nCount);
	//void WINAPI FreeSoundData(SoundData *data);
	//__int64 WINAPI GetCurrentSoundTime(void);
	//int WINAPI GetConfigFileDirectory(LPTSTR pszBuffer, int nLength);
	//DrawMode WINAPI GetDrawMode(void);
	//DrawItemD2D WINAPI GetFaceItemD2D(HANDLE hFace, LPCTSTR pszFieldName);
	//HANDLE WINAPI GetFaceFromIndex(int index);
	//LPCTSTR WINAPI GetWindowNameFromHandle(HANDLE hFace);
	//void WINAPI ReleaseFace(HANDLE hFace);

	enum
	{
		GenericPlugin_Version = 0x0200,		//  汎用プラグインのバージョン。PluginCallbacks に渡されるので、どのコールバックが使えるかの目安にどうぞ
	};

	typedef void (WINAPI * pfnRegisterDialog) (HWND hwndDialog);
	//  モードレスダイアログを登録する
	//  この関数でダイアログを登録すると、メッセージループ内で
	//  このダイアログに対して IsDialogMessage() API を実行するため、
	//  Tab キーでのフォーカスの移動などが正常に行えるようになる。
	//  ダイアログを破棄する前に、必ず UnregisterDialog を呼び出すこと。

	typedef void (WINAPI * pfnUnregisterDialog) (HWND hwndDialog);
	//  登録したモードレスダイアログを、登録解除する
	//  RegisterDialog で登録したダイアログは、
	//  破棄する前に必ずこのコールバックを呼び、登録を解除すること

	typedef DWORD (WINAPI * pfnWaitLockFace) (HANDLE hFace, DWORD nCount, CONST HANDLE *lpHandles, DWORD dwMilliseconds);
	//  指定したタイムアウト時間の間、フェイスをロックとシグナルオブジェクトの待機を試みる。
	//  GetFaceItem を行う前にロックしないと、正しい描画オブジェクトが得られない可能性がある。
	//  ロックしたら、必ずアンロックすること。
	//  ワーキングスレッドの終了検知との間でデッドロックしないように、WaitForMultipleObjects と互換になっている。
	//  フェイスのロックだけを行いたい場合、nCount は 0 でも正しく動作する。
	//  ロックに成功すると、WAIT_OBJECT_0 + nCount が返る。
	//  その他の戻り値は、WaitForMultipleObjects と完全互換がある。
	//  なお、WaitForMultipleObjetcts と異なり、すべてのオブジェクトがシグナル状態になるまで待機することはできない。
	//  ロック期間はなるべく短くなるように、時間のかかる内容はあらかじめレンダリングしておいて、ロック後コピーだけするなど工夫をすること。
	//  また、ロック中は、フェイス関連のコールバック以外は呼ばないこと。デッドロックする可能性あり
	//  具体的に呼んでいいのは、現在のところ、次の４つ。UnlockFace / GetFaceItem / InvalidateFaceRect / UpdateFace

	typedef void (WINAPI * pfnUnlockFace) (HANDLE hFace);
	//  フェイスのロックの解除を行う。ロックとアンロックの回数は整合性を取らないと、他のスレッドが止まります。

	typedef HANDLE (WINAPI * pfnFindFirstFaceItem) (HANDLE hFace, LPCTSTR pszSubCategory, LPTSTR pszFieldName, int nBufferLength);
	//  サブカテゴリ名で、フェイス上の最初のアイテムを検索する
	//  サブカテゴリ名が一致するアイテムがない場合、NULL が返る。
	//  一致するアイテムがあった場合、最初のアイテムのフィールド名が格納され、
	//  検索ハンドルが返る。FindNextFaceItem へ検索ハンドルを渡すことで、
	//  次のアイテムのフィールド名を取得できる。
	//  検索が終わったら、必ず FindFaceItemClose を呼ぶこと。

	typedef BOOL (WINAPI * pfnFindNextFaceItem) (HANDLE hffi, LPTSTR pszFieldName, int nBufferLength);
	//  検索ハンドルを用いて、フェイス上の次のアイテムを検索する
	//  一致する次のアイテムが見つかった場合は、アイテムのフィールド名が格納され、TRUE が返る。
	//  一致するアイテムがもうなかった場合には、FALSE が返る。

	typedef void (WINAPI * pfnFindFaceItemClose) (HANDLE hffi);
	//  フェイス居アイテムの検索ハンドルを閉じる
	//  検索ハンドルは必ずこのコールバックで閉じること
	//  閉じ忘れると、メモリリークします。

	typedef DrawItem (WINAPI * pfnGetFaceItem) (HANDLE hFace, LPCTSTR pszFieldName);
	//  指定した名前のフィールドで定義された、フェイスアイテムをに対する描画オブジェクトを取得する
	//  視覚効果や、歌詞表示など、目的に応じてフェイス作者側と協議して、
	//  フィールド名または、特定のキーの内容などで識別できるように、ルールを決定しておく必要がある
	//  指定されたフィールドが存在しない場合は、DrawItem::FrameBuffer が NULL で返ってくる。
	//
	//  uLilith 2009-11-25 以降では、Direct2D モードである場合、必ず NULL が返る
	//  GetDrawMode で、Gdiplus モードか Direct2D モードか判別できるので、
	//  Direct2D モードでは、GetFaceItemD2D を使用して、Direct2D で描画すること

	typedef void (WINAPI * pfnInvalidateFaceRect) (HANDLE hFace, const RECT& rcUpdate);
	//  フェイス上の指定した領域を無効化し、UpdateFace で更新されるように予約する。
	//  なるべく最小の領域を指定すること。無効領域は、内部的には、リージョンで保持されます。
	//  なので、複数の矩形領域を変更した場合は、複数の変更領域全体を含む矩形で１回呼ぶのではなく、
	//  それぞれの矩形で毎回呼び出した方が、描画の負荷が軽くなります。

	typedef void (WINAPI * pfnUpdateFace) (HANDLE hFace);
	//  フェイス上の無効化された領域を描画し、ウィンドウの表示を更新する。
	//  あらかじめ InvalidateFaceRect を使っておかないと、更新されません。
	//  また、この呼び出しでは、αチャネル変換をした上で、UpdateLayeredWindow を呼び出すので、
	//  処理がかなり重いです。無駄な呼び出しは避けてください。
	//  複数領域を更新するには、領域ごとに呼び出すのではなく、InvalidateRect で全部登録してから、１度だけこれを呼んでください。
	//  なお、処理の整合性を保つため、フェイスをアンロックする前に呼び出すこと。

	typedef SoundData* (WINAPI * pfnGetCurrentSoundData) (int nCount);
	//  現在の再生位置から、指定した数のサンプルデータを読み出す。
	//  SoundData クラスへのポインタが返るので、中身を参照すること。
	//  本体側の再生バッファのサイズによっては、指定したサンプル数取得できない場合がある。
	//  取得できる最大数は、再生バッファサイズ / 2 秒分。
	//  ただし、デコード遅延などにより、このサンプル数分取れないこともある。
	//  再生バッファサイズ / 4 秒分くらいまでに収めておくべき。
	//  なお、再生バッファサイズの最低値は、200ms なので、50ms 分を上限の目安とするとよい。
	//  取得したサンプルデータは、必ず FreeSoundData で解放すること。delete 使ってはダメ。

	typedef void (WINAPI * pfnFreeSoundData) (SoundData *data);
	//  取得したサンプルデータを解放する。
	//  delete などを使わずに、必ずこのコールバックを使用して解放すること。
	//  解放し忘れるとメモリリークするので注意

	typedef __int64 (WINAPI * pfnGetCurrentSoundTime) (void);
	//  現在の再生位置をミリ秒単位で取得する。

	typedef int (WINAPI * pfnGetConfigFileDirectory) (LPTSTR pszBuffer, int nLength);
	//  uLilith の設定フォルダのパスを取得する

	typedef DrawMode (WINAPI * pfnGetDrawMode)(void);
	//  現在の描画モードを返す。このモードは、uLilith 起動中に変更されることはない

	typedef DrawItemD2D (WINAPI * pfnGetFaceItemD2D) (HANDLE hFace, LPCTSTR pszFieldName);
	//  Direct2D モードで、アイテムの描画オブジェクトを取得する
	//  GetFaceItem と使い方は同じ。返されるのは、Gdiplus::Bitmap ではなく、
	//  ID2D1RenderTarget である。
	//  AddRef してから渡されるので、必要なくなったら必ず Release すること。
	//  2009-11-25 時点での実装では、ID2D1BitmapRenderTarget のインスタンスであるので、
	//  QueryInterface と ID2D1BitmapRenderTarget::GetBitmap を使用して、
	//  ID2D1Bitmap を取得することができるが、今後変更される可能性がある。

	typedef ID2D1RenderTarget *(WINAPI *pfnGetRootRenderTarget) (HANDLE hFace);
	//  Direct2D で内部バッファを作成するための、基準 RenderTaget を取得する。
	//  これで作成した RenderTarget から、CreateCompatibleRenderTarget で、内部で使用する RenderTarget を作成すること
	//  また、AddRef してから返されるので、必要なくなったら Release すること

	typedef HANDLE (WINAPI * pfnGetFaceFromIndex) (int index);
	//  フェイスのハンドルをインデックスから取得する
	//  index == 0 は常にメインウィンドウで、アプリケーションの終了処理中でなければ必ず存在する。
	//  これ以上フェイスが存在しない場合、NULL が返る。

	typedef LPCTSTR (WINAPI * pfnGetWindowNameFromHandle) (HANDLE hFace);
	//  フェイスのハンドルから、ウィンドウ名を取得する

	struct PluginCallbacks
	{
		DWORD dwVersion;
		pfnRegisterDialog RegisterDialog;
		pfnUnregisterDialog UnregisterDialog;
		pfnWaitLockFace WaitLockFace;
		pfnUnlockFace UnlockFace;
		pfnFindFirstFaceItem FindFirstFaceItem;
		pfnFindNextFaceItem FindNextFaceItem;
		pfnFindFaceItemClose FindFaceItemClose;
		pfnGetFaceItem GetFaceItem;
		pfnInvalidateFaceRect InvalidateFaceRect;
		pfnUpdateFace UpdateFace;
		pfnGetCurrentSoundData GetCurrentSoundData;
		pfnFreeSoundData FreeSoundData;
		pfnGetCurrentSoundTime GetCurrentSoundTime;
		pfnGetConfigFileDirectory GetConfigFileDirectory;
		pfnGetDrawMode GetDrawMode;
		pfnGetFaceItemD2D GetFaceItemD2D;
		pfnGetRootRenderTarget GetRootRenderTarget;
		pfnGetFaceFromIndex GetFaceFromIndex;
		pfnGetWindowNameFromHandle GetWindowNameFromHandle;
	};

	enum SoundStatus
	{
		SoundStatusPlay = 0,	//  再生が開始された
		SoundStatusSuspend,		//  再生が一時停止された
		SoundStatusResume,		//  再生が再開された
		SoundStatusStop,		//  再生が停止された
		SoundStatusSeeked,		//  シークが行われた
		SoundStatusMax,
	};

	enum FaceItemNotify
	{
		FaceItemNotifySizeChanged = 0,	//  領域サイズが変わり、フレームバッファがクリアされた
		FaceItemNotifyMax,
	};
	struct FaceItemNotifySizeChangedStruct
	{
		DrawMode mode;
		DrawItem Item;
		DrawItemD2D ItemD2D;
	};
	typedef	LPVOID (WINAPI * pfnInitializePlugin) (HWND hwndMain, const PluginCallbacks* callbacks);
	typedef void (WINAPI * pfnUninitializePlugin) (LPVOID lpvUserData);
	typedef HWND (WINAPI * pfnShowProperty) (LPVOID lpvUserData, HWND hwndOwner);
	typedef int (WINAPI * pfnOnFaceLoad) (LPVOID lpvUserData, HANDLE hFace, LPCTSTR pszFileName);
	typedef int (WINAPI * pfnOnFaceUnload) (LPVOID lpvUserData, HANDLE hFace, LPCTSTR pszFileName);
	typedef int (WINAPI * pfnOnSoundOpen) (LPVOID lpvUserData, LPVOID lpvInstance, const SoundInfo& Info);
	typedef int (WINAPI * pfnOnSoundChange) (LPVOID lpvUserData, LPVOID lpvInstance, const SoundInfo& Info);
	typedef int (WINAPI * pfnOnSoundClose) (LPVOID lpvUserData, LPVOID lpvInstance);
	typedef int (WINAPI * pfnOnUpdateVisual) (LPVOID lpvUserData, HANDLE hFace);
	typedef int (WINAPI * pfnOnSoundStatus) (LPVOID lpvUserData, SoundStatus Status);
	typedef void (WINAPI * pfnFaceEffectCallback) (LPVOID lpvUserData, HANDLE hFace, const DrawItem& Canvas, LPCTSTR pszFieldName);
	typedef BOOL (WINAPI * pfnFaceItemNotifyCallback) (LPVOID lpvUserData, HANDLE hFace, LPCTSTR pszFieldName, FaceItemNotify NotifyCode, LPCVOID pNotifyStruct);

	enum SupportedDrawMode
	{
		SupportedDrawModeGdiplus = 0,
		SupportedDrawModeDirect2D,
	};
	struct GenericPluginInfo
	{
		DWORD dwVersion;
		LPCTSTR pszPluginName;
		LPCTSTR pszAuthorName;
		LPCTSTR pszComment;
		pfnInitializePlugin InitializePlugin;
		pfnUninitializePlugin UninitializePlugin;
		pfnShowProperty ShowProperty;
		pfnOnFaceLoad OnFaceLoad;
		pfnOnFaceUnload OnFaceUnload;
		pfnOnSoundOpen OnSoundOpen;
		pfnOnSoundChange OnSoundChange;
		pfnOnSoundClose OnSoundClose;
		pfnOnUpdateVisual OnUpdateVisual;
		pfnOnSoundStatus OnSoundStatus;
		pfnFaceEffectCallback FaceEffectCallback;
		pfnFaceItemNotifyCallback FaceItemNotifyCallback;
		SupportedDrawMode dwSupportedMode;
	};

	typedef void (WINAPI * pfnGetPluginInfo) (GenericPluginInfo& info);


	//  以下はプラグイン側で実装する API
	//  すべての API を実装する必要はない。
	//  モジュール定義ファイルを使用するのが望ましい。
	//  本体側は、GetProcAddress でこれらの API を取得する。
	//  存在しない場合は、呼び出しを行わない。
	//  なお、これらの API は、どのスレッドから呼ばれるか一定ではないので、
	//  特定のスレッドからの呼び出しを前提としたコードは書かないこと
	//  一応、プラグインの呼び出しはクリティカルセクションで保護されるので、
	//  どれかの API が呼ばれている間に別の API が呼ばれることは考えなくていい
	//  例外的に、InitializePlugin と UninitializePlugin は、
	//  必ずメインスレッドから呼ばれる。
	//  ウィンドウを作成する必要がある場合には、InitializePlugin で作成すること。
	//  それ以外の API は、メッセージループを持たないスレッドから呼ばれる可能性がある。
	//  あるいは、独自にスレッドを作成し、そちらでメッセージループを用意し、
	//  そのスレッドに所属させてウィンドウを作成すること。

	void WINAPI GetPluginInfo(GenericPluginInfo& info);
	//  プラグインの情報を取得する関数
	//  プラグインをロードして一番最初に呼ばれる。
	//  プラグインの各種 API と、インターフェースバージョンを格納した構造体を返す
	//  この API は、C リンケージ名でエクスポートすること
	
	LPVOID WINAPI InitializePlugin(HWND hwndMain, const PluginCallbacks* callbacks);
	//  プラグインをロードしたあとに、呼ばれる初期化関数
	//  プラグインを多重登録した場合は、複数回呼ばれることがあるので注意。
	//  その場合でも、UninitializePlugin との呼び出し回数の整合性は取られる。
	//  引数には、メインウィンドウのハンドルと、プラグインから使えるコールバック関数が渡される。
	//  コールバック関数を使う場合は、値を保存しておくこと。
	//  また、戻り値には、インスタンスを識別する ID を返すこと。
	//  アロケートしたユーザデータへのポインタでかまわない。
	//  プラグインが多重登録されている場合は、ID でどれの処理か識別する。
	//  この API を省略した場合は、ID は 0 で以降の API が呼び出される。

	void WINAPI UninitializePlugin(LPVOID lpvUserData);
	//  プラグインのアンロード前に呼ばれる解放関数
	//  プラグインが多重登録されている場合は、InitializePlugin で返した
	//  それぞれの ID を引数に、複数回呼ばれる。

	HWND WINAPI ShowProperty(LPVOID lpvUserData, HWND hwndOwner);
	//  プラグインの設定ウィンドウを開く関数
	//  引数には、ID と、親ウィンドウとすべきウィンドウのハンドルが渡される。
	//  特に設定が必要ない場合には、実装しなくてかまわない。
	//  モードレスダイアログでの実装を推奨する。
	//  その場合、RegisterDialog / UnregisterDialog コールバックを使用すると、
	//  Tab キーでのフォーカスの移動などが本体側で処理される。

	int WINAPI OnFaceLoad(LPVOID lpvUserData, HANDLE hFace, LPCTSTR pszFileName);
	//  フェイスがロードされたときに呼ばれる関数
	//  引数には、ID と、読み込んだフェイス定義ファイルのフルパス名が渡される。
	//  フェイス上への描画を行うプラグインでは、フェイス定義ファイルを読み込み、
	//  描画すべきフェイスアイテムと、その独自パラメータを参照すること。
	//  この関数は、フェイスがロックされている状態で呼び出されるので、
	//  内部でスレッドを生成し、コールバックの WaitLockFace を使用する場合、
	//  デッドロックに注意すること

	int WINAPI OnFaceUnload(LPVOID lpvUserData, HANDLE hFace, LPCTSTR pszFileName);
	//  フェイスがアンロードされたときに呼ばれる関数
	//  ID とアンロードされたフェイスの定義ファイルのフルパス名が渡される。
	//  この関数は、フェイスがロックされている状態で呼び出されるので、
	//  内部でスレッドを生成し、コールバックの WaitLockFace を使用する場合、
	//  デッドロックに注意すること

	int WINAPI OnSoundOpen(LPVOID lpvUserData, LPVOID lpvInstance, const SoundInfo& Info);
	//  サウンドファイルがオープンされたときに呼ばれる関数
	//  クロスフェード時など、必ずしも対応する OnSoundClose が呼ばれたあとに
	//  呼び出されるわけではないのに注意。
	//  次のファイルの OnSoundOpen が呼ばれてから、前のファイルの OnSoundClose が呼ばれることがある。
	//  lpvInstance が一意の値なので、Open と Close の対応は、それで識別すること。
	//  本体対応のタグ情報などは、すべて SoundInfo に収められているので活用すべし。

	int WINAPI OnSoundChange(LPVOID lpvUserData, LPVOID lpvInstance, const SoundInfo& Info);
	//  ノンストップ再生などで、インスタンスは変化せずに、曲情報だけ変化したときに呼ばれる関数
	//  この API が用意されておらず、OnSoundOpen が実装されている場合には、
	//  OnSoundClose と OnSoundOpen を代わりに呼び出す。
	//  この API の呼び出しでは、サウンドのフォーマット (ビット深度/チャネル数/サンプリングレート)が
	//  変化していないことが保証されるので、Close & Open より、少し効率的に処理できるはず。

	int WINAPI OnSoundClose(LPVOID lpvUserData, LPVOID lpvInstance);
	//  サウンドファイルがクローズされたときに呼ばれる関数
	//  必ずしも１回前の OnSoundOpen と対応しているわけではないので注意。
	//  lpvInstance で、OnSoundOpen との対応を識別すること。

	int WINAPI OnUpdateVisual(LPVOID lpvUserDatam, HANDLE hFace);
	//  更新スレッドから呼ばれる関数
	//  本体のフレームレートの設定に応じて、定期的に呼び出される。
	//  Visualization プラグインなどでの再生状況に応じた処理で使われる。
	//  ただし、本体側の描画更新をブロックするので、
	//  プラグイン側の処理が重い場合は、この API 経由での処理は行うべきではない。
	//  独自にスレッドを作成し、そちらで処理を行うこと。
	//  フェイス上でのアニメーションの実現など、本体側のフレームレートに依存したくない場合も同様。

	int WINAPI OnSoundStatus(LPVOID lpvUserData, SoundStatus Status);
	//  サウンドの再生開始/停止などのアクションを通知を受け取る関数
	//  受け取れる通知は、上のほうの SoundStatus 列挙体の定義を参照すること

	void WINAPI FaceEffectCallback(LPVOID lpvUserData, HANDLE hFace, const DrawItem& Canvas, LPCTSTR pszFieldName);
	//  フェイスのエフェクトを行うコールバック関数
	//  Canvas.FrameBuffer には、フェイスウィンドウ自体のフレームバッファが渡される。
	//  すでに描画されている内容を書き換えて or 書き加えて独自のエフェクトを行うことができる。
	//  エフェクトを行うべき領域は、rcView で指示される。
	//  指示された領域外は、絶対に変更しないこと。フェイスの表示がおかしくなる。
	//  fIsVisible が FALSE のときには、コールバック自体が呼ばれないので、ここは考慮しなくてよい。
	//  このコールバックは、フェイスの描画処理中から呼ばれるため、
	//  呼び出し側でフェイスがロックされているので、デッドロックに注意すること。

	BOOL WINAPI FaceItemNotifyCallback(LPVOID lpvUserData, HANDLE hFace, LPCTSTR pszFieldName, FaceItemNotify NotifyCode, LPCVOID pNotifyStruct);
	//  フェイスアイテムの状態が変わったときに呼び出されるコールバック関数
	//  Category == PluginFrameBuffer のアイテムの状態が変わったとき、必要に応じて呼び出される
	//  各プラグインがハンドルしているフィールド名は、uLilith 側からは把握できないので、
	//  pszFieldName をチェックし、プラグイン内でハンドリングしているフィールドのみ処理すること。
	//  また、処理を行った場合には、TRUE を、それ以外の場合は、FALSE を返すこと。
	//  プラグインから TRUE が返った場合、uLilith 本体は、後続のプラグインのコールバックは呼び出さない。
	//  
	//  現状、NotifyCode は FaceItemNotifySizeChanged １つのみ。
	//  NotifyCode == FaceItemNotifySizeChanged のときには、pNotifyStruct には、
	//  FaceItemNotifySizeChangedStruct へのポインタが渡される。
	//  FaceItemNotifySizeChangedStruct::Item.rcView に、新しい表示矩形が渡されるので、
	//  新しいサイズに基づいて、FrameBuffer の内容を更新すること。
	//  この FaceItemNotifySizeChanged が送られる前に、FrameBuffer の内容はクリアされる。
	//  FaceItemNotifySizeChanged は、フェイス処理の中から呼ばれるため、
	//  呼び出し側でフェイスがロックされているので、デッドロックに注意すること。
};

#pragma pack(pop)