//
//	clipprp.cs
//
//	プロパティテーブル
//
//	CLiP - Common Library for P/ECE
//	Copyright (C) 2017 Naoyuki Sawa
//
//	* Sun Mar 12 22:26:18 JST 2017 Naoyuki Sawa
//	- 1st リリース。
//	- まず、基本的な関数だけを実装しました。
//	  まだ、ユーティリティ関数は実装していません。
//	* Mon Mar 13 21:21:21 JST 2017 Naoyuki Sawa
//	- ユーティリティ関数を実装しました。
//	- ユーティリティマクロは、C#言語仕様上難しいので、未対応です。
//	  プロパティエディタは、C#版のPDCursesが無いので、未対応です。
//	* Wed Mar 15 22:06:35 JST 2017 Naoyuki Sawa
//	- cliplibc.csモジュールを追加した事に伴い、PrpTbl_path_p_subr()関数がstrncmp(),strcspn(),strtoul()を利用するように変更しました。
//	  変更前のPrpTbl_path_p_subr()関数は暫定的にStringBuilderを使用した非効率な実装でしたが、今回の変更によってほぼC言語版のPrpTbl_path_p_subr()関数と同じ効率になりました。
//	  尚、PrpTbl_list_subr()関数はまだStringBuilderを使用していますが、PrpTbl_list_subr()関数は今回の変更とは関係無いのでそのままです。
//
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace org.piece_me {
	public static partial class libclip {
		//*****************************************************************************
		//	定数
		//*****************************************************************************
		public const int Prp_name	=  1;		//タイプ定義に属する値の名前,又は,テーブル定義に属する値の名前,又は,変数定義に属する値の名前。
		public const int Prp_desc	=  2;		//タイプ定義に属する値の名前,又は,テーブル定義に属する値の名前,又は,変数定義に属する値の名前。
		public const int Prp_fmt	=  3;		//タイプ定義に属する値の名前,又は,テーブル定義に属する値の名前,又は,変数定義に属する値の名前。タイプ定義に属する文字列の名前,又は,テーブル定義に属する文字列の名前,又は,変数定義に属する文字列の名前。
		public const int Prp_len	=  4;		//タイプ定義に属する値の名前,又は,テーブル定義に属する値の名前,又は,変数定義に属する値の名前。
		public const int Prp_pos	=  5;		//変数定義に属する値の名前。
		public const int Prp_type	=  6;		//変数定義に属する値の名前。
		public const int Prp_dim	=  7;		//変数定義に属するBLOBの名前。
		public const int Prp_attr	=  8;		//変数定義に属するBLOBの名前。
		public const int Prp_init	=  9;		//タイプ定義に属する値の名前。
		public const int Prp_range	= 10;		//タイプ定義に属するBLOBの名前。
		public const int Prp_enum	= 11;		//タイプ定義に属するBLOBの名前。
		//-----------------------------------------------------------------------------
		public const int PrpTbl_Double	= 0x7FFF;	//組み込み'Double'型のテーブル名。当モジュールの内部処理と、/tool/dPrpTblC/の実装で、一致している必要があるため、ここで定義しています。アプリケーションが、この定数を意識する必要は有りません。
		//*****************************************************************************
		//	ローカル関数
		//*****************************************************************************
		//iOp = ┬ 0/*inf*/		iVal=(ST_PrpInf),pPrpTbl=参照しない,iBitPos=0
		//      │ 1/*init*/		iVal=参照しない
		//      │ 2/*set*/		iVal=設定値
		//      └ 3/*get/acc*/		iVal=0/*get*/,又は,増減値/*acc*/	'get'と'acc 0'は区別出来ないが問題無い。
		private static int PrpTbl_op_v(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, object _iVal, IEnumerable<int> _aName, int iOp) {
			int iVal = (_iVal is int) ? (int)_iVal : 0/*dummy*/;	//引数_iValは(int),又は,ST_PrpInfです。(int)の方が多く、頻繁にキャストする事を防ぐため、ここでキャストしておく事にします。
			IEnumerator<int> aName = _aName.GetEnumerator();
			VoidPtr pTblKey;
			//テーブルキーを取得する。
			pTblKey = REG_open_key(pPrpKey, iTbl);
			if(!pTblKey) { throw new ApplicationException(); }
			//最初の変数名を取得しておく。
			// - C言語版ではfor(;;)ループの中で行っていますが、C#版では最初の取得はここで行う必要が有ります。
			//   C#のIEnumerator.MoveNext()は、次の要素へ進めずに終端かどうかを判断する事が出来ないからです。
			int iName = aName.MoveNext() ? aName.Current : -1;
			for(;;) {
				int iBitPos2, iArraySize, iOffset, nIndex, iType, iBitLen;
				VoidPtr pVarKey;
				UInt16Ptr pDim;
				//初回の変数名,又は,前回のループの最後に取得した変数名が無ければ、呼び出し側のバグです。
				if(iName == -1) { throw new ApplicationException(); }
				//変数キーを取得する。
				pVarKey = REG_open_key(pTblKey, iName);
				if(!pVarKey) { throw new ApplicationException(); }
				//変数のビット位置を取得する。
				iBitPos2 = REG_get_value(pVarKey, Prp_pos);
				if(iBitPos2 == -1) { throw new ApplicationException(); }
				//テーブルのビット位置に、変数のビット位置を加算して、変数のビット位置とする。
				iBitPos += iBitPos2;
				//配列全体の要素数を1としておく。スカラー変数だった場合は1のままになる。
				iArraySize = 1;
				//配列オフセットを0としておく。
				iOffset = 0;
				//インデクスが指定された数を0としておく。
				nIndex = 0;
				//配列データを取得する。
				pDim = REG_get_blob(pVarKey, Prp_dim);
				//配列データが有れば…
				if(pDim) {
					int nDim, iBound, iIndex;
					//次元数を取得する。
					nDim = REG_get_blob_size(pDim);
					if((nDim & 1) != 0) { throw new ApplicationException(); }	//(要素数-1)は1個2バイトなので配列データのバイト数が奇数にはなり得ない。もしそうなったらデータエラーです。
					nDim >>= 1;	//配列データのバイト数⇒次元数に変換する。
					//各次元について…
					do {
						//この次元の(要素数-1)を取得する。
						iBound = pDim.Read();	//このループ以降の処理でpDimを参照しないのでpDimを破壊して構わない。
						//(要素数-1)⇒(要素数)に補正する。
						iBound++;
						//配列全体の要素数に、この次元の要素数を乗算する。
						iArraySize *= iBound;
						//インデクスが指定されていたら…
						if((iName = aName.MoveNext() ? aName.Current : -1) != -1) {
							//この次元のインデクスを取得する。
							iIndex = aName.Current;
							if((uint)iIndex >= (uint)iBound) { throw new ApplicationException(); }
							//前の次元までの配列オフセットに、この次元の要素数を乗算する。
							iOffset *= iBound;
							//配列オフセットに、この次元のインデクスを加算する。
							iOffset += iIndex;
							//インデクスが指定された数を増やす。
							nIndex++;
						//インデクスが指定されていなければ…
						} else {
							if(nIndex != 0) { throw new ApplicationException(); }	//全て指定するか,又は,全て省略のみ可。そうでなければ呼び出し側のバグです。
							//iArraySizeを求めるために、処理を継続する。
							/** no job **/
						}
					} while(--nDim != 0);
					//ここでnIndexは配列データの次元数に一致しているか,又は,0(=呼び出し側がインデクスを全て省略した場合)になっています。
					if((nIndex == 0) && (iOp > 2/*set*/)) { throw new ApplicationException(); }	//'inf','init','set'以外(='get/acc')はインデクスの省略は不可。呼び出し側のバグです。
				}
				//タイプ名,又は,テーブル名を取得する。
				iType = REG_get_value(pVarKey, Prp_type);
				//タイプ名,又は,テーブル名が無ければ、'var'型と見なす。
				if(iType == -1) {
					//名前配列が終端でなければ、呼び出し側のバグです。
					if((iName = aName.MoveNext() ? aName.Current : -1) != -1) { throw new ApplicationException(); }
					//配列オフセットに、'var'型のビット数を乗算する。
					iOffset *= 32;
					//変数のビット位置に、配列オフセットを加算する。
					iBitPos += iOffset;
					switch(iOp) {
					default:throw new ApplicationException();
					case 0/*inf*/:
						{
							ST_PrpInf pInf = (ST_PrpInf)_iVal;
							pInf.iType	= iType;							//変数の型。(-1=var型,0x0000～0x7FFF=table型,0x8000～0xFFFF=type型)
							pInf.iBitPos	= iBitPos;							//変数のビット位置。(0ベースのオフセット)
							pInf.pDim	= (nIndex != 0) ? null : REG_get_blob(pVarKey, Prp_dim);	//配列の各次元のインデクスの最大値。		┬配列変数のパス名を指定し,かつ,インデクスを全て省略した場合のみ、nDim=1以上,pDim=配列データへのポインタを格納します。
							pInf.nDim	= REG_get_blob_size(pInf.pDim) >> 1;				//配列の次元数。				┘上記以外の場合は、nDim=0,pDim=nullを格納します。配列変数の一要素のパス名を指定した場合(インデクスを指定した場合)は、nDim=0,pDim=nullが格納される事に注意して下さい。		pDim[0～nDim-1]の値は、配列の各次元の要素数ではなく、インデクスの最大値(=要素数-1)である事に注意せよ。
							pInf.pName	= REG_get_string(pVarKey, Prp_name);				//名前文字列が無ければ、nullが格納される。
							pInf.pDesc	= REG_get_string(pVarKey, Prp_desc);				//説明文が無ければ、nullが格納される。
							pInf.pFmt	= REG_get_string(pVarKey, Prp_fmt);				//書式文字列が無ければ、nullが格納される。	┬変数に対してPrpTbl_inf_l()等を呼び出した場合、書式文字列と書式番号の両方が無ければ、
							pInf.iFmt	= REG_get_value( pVarKey, Prp_fmt);				//書式番号が無ければ、-1が格納される。		┘その変数のタイプ,又は,その変数のテーブルから、書式文字列と書式番号の取得を試みる。
						}
						break;
					case 1/*init*/:
						//'var'型の変数を初期化する。
						iVal = 0;
						/* FALLTHRU */
						goto case 2;
					case 2/*set*/:
						//'var'型の変数を書き込む。
						// - 配列データが有り,かつ,呼び出し側がインデクスを全て省略した場合、配列全体に書き込む。
						//  それ以外ならば、一つの変数,又は,配列の一要素に書き込む。
						do {
							bitarray_lsb1st_set(pPrpTbl, iBitPos, 32, iVal);
							iBitPos += 32;
							if(nIndex != 0) { break; }	//配列変数で,かつ,呼び出し側がインデクスを指定した場合は、ここで抜ける。
						} while(--iArraySize != 0);		//スカラー変数だった場合は、(iArraySize=1)なので、一回のループで抜ける。
						break;
					case 3/*get/acc*/:
						{
							int iAcc = iVal;
							//'var'型の変数を読み出す。
							iVal = bitarray_lsb1st_get(pPrpTbl, iBitPos, 32);	//'get'の場合、これが戻り値となる。
							//'acc'ならば…											//┐
							if(iAcc != 0) {											//│
								//数値を増減する。(ラップアラウンド演算)						//│
								iVal += iAcc;					//'acc'の場合、これが戻り値となる。	//├'get'の場合もこの処理を行っても構わないのだが、無駄であり性能低下するので避ける事にした。
								//'var'型の変数を書き込む。								//│
								bitarray_lsb1st_set(pPrpTbl, iBitPos, 32, iVal);					//│
							}												//┘
						}
						break;
					}
					break;	//ここまで
				//タイプ名,又は,テーブル名が、0x8000以上ならばタイプ名である。
				} else if(iType >= 0x8000) {
					VoidPtr pTypKey;
					Int16Ptr pRng, pEnm;
					//名前配列が終端でなければ、呼び出し側のバグです。
					if((iName = aName.MoveNext() ? aName.Current : -1) != -1) { throw new ApplicationException(); }
					//タイプキーを取得する。
					pTypKey = REG_open_key(pPrpKey, iType);
					if(!pTypKey) { throw new ApplicationException(); }
					//このタイプの(ビット数-1)を取得する。
					iBitLen = REG_get_value(pTypKey, Prp_len);
				//不要	if(iBitLen == -1) { throw new ApplicationException(); }	この下の判定に含まれるので不要。
					//(ビット数-1)⇒(ビット数)に補正する。
					iBitLen++;
					if((iBitLen < 1) || (iBitLen > 16)) { throw new ApplicationException(); }
					//配列オフセットに、このタイプのビット数を乗算する。
					iOffset *= iBitLen;
					//変数のビット位置に、配列オフセットを加算する。
					iBitPos += iOffset;
					//範囲データ,又は,列挙データを取得する。
					pRng = REG_get_blob(pTypKey, Prp_range);
					pEnm = REG_get_blob(pTypKey, Prp_enum);
					//範囲型の変数ならば…
					if(pRng && !pEnm) {
						//最小値,最大値を取得する。
						int iMin = pRng.Read();
						int iMax = iMin + (ushort)pRng.Read();
						switch(iOp) {
						default:throw new ApplicationException();
						case 0/*inf*/:
							{
								ST_PrpInf pInf = (ST_PrpInf)_iVal;
								pInf.iType	= iType;							//変数の型。(-1=var型,0x0000～0x7FFF=table型,0x8000～0xFFFF=type型)
								pInf.iBitPos	= iBitPos;							//変数のビット位置。(0ベースのオフセット)
								pInf.pDim	= (nIndex != 0) ? null : REG_get_blob(pVarKey, Prp_dim);	//配列の各次元のインデクスの最大値。		┬配列変数のパス名を指定し,かつ,インデクスを全て省略した場合のみ、nDim=1以上,pDim=配列データへのポインタを格納します。
								pInf.nDim	= REG_get_blob_size(pInf.pDim) >> 1;				//配列の次元数。				┘上記以外の場合は、nDim=0,pDim=nullを格納します。配列変数の一要素のパス名を指定した場合(インデクスを指定した場合)は、nDim=0,pDim=nullが格納される事に注意して下さい。		pDim[0～nDim-1]の値は、配列の各次元の要素数ではなく、インデクスの最大値(=要素数-1)である事に注意せよ。
								pInf.pName	= REG_get_string(pVarKey, Prp_name);				//名前文字列が無ければ、nullが格納される。
								pInf.pDesc	= REG_get_string(pVarKey, Prp_desc);				//説明文が無ければ、nullが格納される。
								pInf.pFmt	= REG_get_string(pVarKey, Prp_fmt);				//書式文字列が無ければ、nullが格納される。	┬変数に対してPrpTbl_inf_l()等を呼び出した場合、書式文字列と書式番号の両方が無ければ、
								pInf.iFmt	= REG_get_value( pVarKey, Prp_fmt);				//書式番号が無ければ、-1が格納される。		┘その変数のタイプ,又は,その変数のテーブルから、書式文字列と書式番号の取得を試みる。
								if((pInf.pFmt == null) && (pInf.iFmt == -1)) {					//値の書式が設定されていなければ、タイプに設定された書式を検索する。
									pInf.pFmt	= REG_get_string(pTypKey, Prp_fmt);			//書式文字列が無ければ、nullが格納される。	┬変数に対してPrpTbl_inf_l()等を呼び出した場合、書式文字列と書式番号の両方が無ければ、
									pInf.iFmt	= REG_get_value( pTypKey, Prp_fmt);			//書式番号が無ければ、-1が格納される。		┘その変数のタイプ,又は,その変数のテーブルから、書式文字列と書式番号の取得を試みる。
								}
							}
							break;
						case 1/*init*/:
							//範囲型の変数を初期化する。
							iVal = REG_get_value(pTypKey, Prp_init);
						//不要	if(iVal == -1) { throw new ApplicationException(); }	この下の判定に含まれるので不要。
							iVal += iMin;
							/* FALLTHRU */
							goto case 2;
						case 2/*set*/:
							//範囲型の変数を書き込む。
							// - 配列データが有り,かつ,呼び出し側がインデクスを全て省略した場合、配列全体に書き込む。
							//  それ以外ならば、一つの変数,又は,配列の一要素に書き込む。
							if((iVal < iMin) || (iVal > iMax)) { throw new ApplicationException(); }	//多分、呼び出し側のバグ。
							iVal -= iMin;
							do {
								bitarray_lsb1st_set(pPrpTbl, iBitPos, iBitLen, iVal);
								iBitPos += iBitLen;
								if(nIndex != 0) { break; }	//配列変数で,かつ,呼び出し側がインデクスを指定した場合は、ここで抜ける。
							} while(--iArraySize != 0);		//スカラー変数だった場合は、(iArraySize=1)なので、一回のループで抜ける。
							break;
						case 3/*get/acc*/:
							{
								int iAcc = iVal;
								//範囲型の変数を読み出す。
								iVal = bitarray_lsb1st_get(pPrpTbl, iBitPos, iBitLen);
								iVal += iMin;					//'get'の場合、これが戻り値となる。
								if((iVal < iMin) || (iVal > iMax)) { throw new ApplicationException(); }	//多分、当モジュールのバグ。
								//'acc'ならば…														//┐
								if(iAcc != 0) {														//│
									//数値を増減する。(飽和演算)											//│
									iVal += iAcc;				//┐									//│
									if(iVal < iMin) { iVal = iMin; }	//├'acc'の場合、これが戻り値となる。					//├'get'の場合もこの処理を行っても構わないのだが、無駄であり性能低下するので避ける事にした。
									if(iVal > iMax) { iVal = iMax; }	//┘									//│
									//範囲型の変数を書き込む。											//│
									bitarray_lsb1st_set(pPrpTbl, iBitPos, iBitLen, iVal - iMin);	//iValは戻り値なので変化させないよう注意せよ。	//│
								}															//┘
							}
							break;
						}
					//列挙型の変数ならば…
					} else if(pEnm && !pRng) {
						int nEnm, iIdx = -1/*'init'と'set'を区別するための初期値*/;
						//列挙値の数を取得する。
						nEnm = REG_get_blob_size(pEnm);
						if((nEnm & 1) != 0) { throw new ApplicationException(); }	//列挙値は1個2バイトなので列挙データのバイト数が奇数にはなり得ない。もしそうなったらデータエラーです。
						nEnm >>= 1;	//列挙データのバイト数⇒列挙値の数に変換する。
						switch(iOp) {
						default:throw new ApplicationException();
						case 0/*inf*/:
							{
								ST_PrpInf pInf = (ST_PrpInf)_iVal;
								pInf.iType	= iType;							//変数の型。(-1=var型,0x0000～0x7FFF=table型,0x8000～0xFFFF=type型)
								pInf.iBitPos	= iBitPos;							//変数のビット位置。(0ベースのオフセット)
								pInf.pDim	= (nIndex != 0) ? null : REG_get_blob(pVarKey, Prp_dim);	//配列の各次元のインデクスの最大値。		┬配列変数のパス名を指定し,かつ,インデクスを全て省略した場合のみ、nDim=1以上,pDim=配列データへのポインタを格納します。
								pInf.nDim	= REG_get_blob_size(pInf.pDim) >> 1;				//配列の次元数。				┘上記以外の場合は、nDim=0,pDim=nullを格納します。配列変数の一要素のパス名を指定した場合(インデクスを指定した場合)は、nDim=0,pDim=nullが格納される事に注意して下さい。		pDim[0～nDim-1]の値は、配列の各次元の要素数ではなく、インデクスの最大値(=要素数-1)である事に注意せよ。
								pInf.pName	= REG_get_string(pVarKey, Prp_name);				//名前文字列が無ければ、nullが格納される。
								pInf.pDesc	= REG_get_string(pVarKey, Prp_desc);				//説明文が無ければ、nullが格納される。
								pInf.pFmt	= REG_get_string(pVarKey, Prp_fmt);				//書式文字列が無ければ、nullが格納される。	┬変数に対してPrpTbl_inf_l()等を呼び出した場合、書式文字列と書式番号の両方が無ければ、
								pInf.iFmt	= REG_get_value( pVarKey, Prp_fmt);				//書式番号が無ければ、-1が格納される。		┘その変数のタイプ,又は,その変数のテーブルから、書式文字列と書式番号の取得を試みる。
								if((pInf.pFmt == null) && (pInf.iFmt == -1)) {					//値の書式が設定されていなければ、タイプに設定された書式を検索する。
									pInf.pFmt	= REG_get_string(pTypKey, Prp_fmt);			//書式文字列が無ければ、nullが格納される。	┬変数に対してPrpTbl_inf_l()等を呼び出した場合、書式文字列と書式番号の両方が無ければ、
									pInf.iFmt	= REG_get_value( pTypKey, Prp_fmt);			//書式番号が無ければ、-1が格納される。		┘その変数のタイプ,又は,その変数のテーブルから、書式文字列と書式番号の取得を試みる。
								}
							}
							break;
						case 1/*init*/:
							//列挙型の変数を初期化する。
							iIdx = REG_get_value(pTypKey, Prp_init);
						//不要	if(iIdx == -1) { throw new ApplicationException(); }	この下の判定に含まれるので不要。
							if((uint)iIdx >= (uint)nEnm) { throw new ApplicationException(); }	//データエラー
							/* FALLTHRU */
							goto case 2;
						case 2/*set*/:
							//列挙型の変数を書き込む。
							// - 配列データが有り,かつ,呼び出し側がインデクスを全て省略した場合、配列全体に書き込む。
							//  それ以外ならば、一つの変数,又は,配列の一要素に書き込む。
							if(iIdx == -1) {	//'init'からのFALLTHRUでなければ…
								for(;;) {
									if( ++iIdx >= nEnm) { throw new ApplicationException(); }
									if(pEnm.Read() == iVal) { break; }	//このループ以降の処理でpEnmを参照しないのでpEnmを破壊して構わない。
								}
							}
							do {
								bitarray_lsb1st_set(pPrpTbl, iBitPos, iBitLen, iIdx);
								iBitPos += iBitLen;
								if(nIndex != 0) { break; }	//配列変数で,かつ,呼び出し側がインデクスを指定した場合は、ここで抜ける。
							} while(--iArraySize != 0);		//スカラー変数だった場合は、(iArraySize=1)なので、一回のループで抜ける。
							break;
						case 3/*get/acc*/:
							{
								int iAcc = iVal;
								//列挙型の変数を読み出す。
								iIdx = bitarray_lsb1st_get(pPrpTbl, iBitPos, iBitLen);
								if((uint)iIdx >= (uint)nEnm) { throw new ApplicationException(); }	//多分、当モジュールのバグ。
								//'acc'ならば…							//┐
								if(iAcc != 0) {							//│
									//順序番号を増減する。(順序番号に対する飽和演算)	//│
									iIdx += iAcc;						//│
									if(iIdx <        0) { iIdx =        0; }		//├'get'の場合もこの処理を行っても構わないのだが、無駄であり性能低下するので避ける事にした。
									if(iIdx > nEnm - 1) { iIdx = nEnm - 1; }		//│
									//列挙型の変数を書き込む。				//│
									bitarray_lsb1st_set(pPrpTbl, iBitPos, iBitLen, iIdx);	//│
								}								//┘
								iVal = pEnm[iIdx];	//戻り値
							}
							break;
						}
					} else {
						throw new ApplicationException();
					}
					break;	//ここまで
				//タイプ名,又は,テーブル名が、0x7FFF以下ならばテーブル名である。
				} else {
					//テーブルキーを取得する。
					pTblKey = REG_open_key(pPrpKey, iType);
					if(!pTblKey) { throw new ApplicationException(); }
					//このテープルの(ビット数-1)を取得する。
					iBitLen = REG_get_value(pTblKey, Prp_len);
					if(iBitLen == -1) { throw new ApplicationException(); }
					//(ビット数-1)⇒(ビット数)に補正する。
					iBitLen++;
					//配列オフセットに、このテーブルのビット数を乗算する。
					iOffset *= iBitLen;
					//変数のビット位置に、配列オフセットを加算する。
					iBitPos += iOffset;
					//名前配列が終端ならば…
					if((iName = aName.MoveNext() ? aName.Current : -1) == -1) {
						// * Mon Oct 12 13:35:44 JST 2015 Naoyuki Sawa
						// - アプリケーションプログラムが組み込み'Double'型の変数に対してPrpHdr_get_*()とPrpHdr_set_*()を呼び出した時の処理を変更しました。
						//   変更前は、エラー停止していました。
						//   変更後は、PrpHdr_get_*()は整数部を返し、PrpHdr_set_*()は指定された整数値を浮動小数値に変換して設定するようになりました。
						//   <例>
						//    │table App
						//    │      Double x
						//    │end
						//    ①PrpHdr_fset_l(pPrpHdr, 12.34, PrpVar_x, -1);	//12.34を設定する。
						//    　PrpHdr_get_l(pPrpHdr, PrpVar_x, -1);		//12を返す。		←サービス
						//    ②PrpHdr_set_l(pPrpHdr, 1234, PrpVar_x, -1);	//1234.0を設定する。	←サービス
						//    　PrpHdr_fget_l(pPrpHdr, PrpVar_x, -1);		//1234.0を返す。
						// - 上記はあくまでもサービスであり、組み込み'Double'型の変数に対して整数用の関数(PrpHdr_get_*()とPrpHdr_set_*())を呼び出す事は、望ましくはありません。
						//   このサービスの濫用は避けて、組み込み'Double'型の変数に対しては明示的に浮動小数用の関数(PrpHdr_fget_*()とPrpHdr_fset_*())を呼び出すの望ましいです。
						//   このサービスは却ってアプリケーションプログラムが変数型を間違えた場合のバグ発見を遅らせる恐れも有り、有害と判断したらこのブロックを削除して下さい。
						// - アプリケーションプログラムが組み込み'Double'型の変数に対してPrpHdr_incr_*(),PrpHdr_decr_*()を呼び出した場合は、変更後も変更前と同じでエラーになります。
						//   アプリケーションプログラムが組み込み'Double'型の変数に対してPrpHdr_init_*()を呼び出す事は、変更前も合法でした。変更後も変わらず合法で正しく動作します。
						if(iType == PrpTbl_Double) {
							//C言語版ではここにaNameを渡していたが、C#では型が違う(aNameはIEnumerator型,引数はIEnumerable型)のでaNameを渡せない。──┬┬┬┬┬┬┬┬┬┬┬┐
							//しかし良く考えると、aNameは終端に到達しているので、C言語版でここにaNameを渡していた理由は単に{-1}を渡すためだった。    ││││││││││││
							//要するに、aNameの残りの部分は空のシーケンスと等価であるから、新たに空のシーケンスを作成して渡しても同じ結果となる。    ↓↓↓↓↓↓↓↓↓↓↓↓
							if( iOp == 2/*set*/                           ) {             PrpTbl_fset_v(pPrpKey, iType, pPrpTbl, iBitPos, (int)iVal, Enumerable.Empty<int>()); return 0/*dummy*/; }
							if((iOp == 3/*get/acc*/) && (iVal == 0)/*get*/) { return (int)PrpTbl_fget_v(pPrpKey, iType, pPrpTbl, iBitPos,            Enumerable.Empty<int>());                    }
							//0/*inf*/,1/*init*/ならばこの下で正しく処理される。((iOp==3/*get/acc*/)&&iVal/*acc*/)ならばこの下でエラー停止する。
						}
						//'inf','init'以外ならば、呼び出し側のバグです。
						// - テーブル変数を対象として実行出来るのは、'inf','init'のみです。
						//   'set','get/acc'は、テーブル変数のフィールドを対象とする必要が有ります。
						switch(iOp) {
						default:throw new ApplicationException();
						case 0/*inf*/:
							{
								ST_PrpInf pInf = (ST_PrpInf)_iVal;
								pInf.iType	= iType;							//変数の型。(-1=var型,0x0000～0x7FFF=table型,0x8000～0xFFFF=type型)
								pInf.iBitPos	= iBitPos;							//変数のビット位置。(0ベースのオフセット)
								pInf.pDim	= (nIndex != 0) ? null : REG_get_blob(pVarKey, Prp_dim);	//配列の各次元のインデクスの最大値。		┬配列変数のパス名を指定し,かつ,インデクスを全て省略した場合のみ、nDim=1以上,pDim=配列データへのポインタを格納します。
								pInf.nDim	= REG_get_blob_size(pInf.pDim) >> 1;				//配列の次元数。				┘上記以外の場合は、nDim=0,pDim=nullを格納します。配列変数の一要素のパス名を指定した場合(インデクスを指定した場合)は、nDim=0,pDim=nullが格納される事に注意して下さい。		pDim[0～nDim-1]の値は、配列の各次元の要素数ではなく、インデクスの最大値(=要素数-1)である事に注意せよ。
								pInf.pName	= REG_get_string(pVarKey, Prp_name);				//名前文字列が無ければ、nullが格納される。
								pInf.pDesc	= REG_get_string(pVarKey, Prp_desc);				//説明文が無ければ、nullが格納される。
								pInf.pFmt	= REG_get_string(pVarKey, Prp_fmt);				//書式文字列が無ければ、nullが格納される。	┬変数に対してPrpTbl_inf_l()等を呼び出した場合、書式文字列と書式番号の両方が無ければ、
								pInf.iFmt	= REG_get_value( pVarKey, Prp_fmt);				//書式番号が無ければ、-1が格納される。		┘その変数のタイプ,又は,その変数のテーブルから、書式文字列と書式番号の取得を試みる。
								if((pInf.pFmt == null) && (pInf.iFmt == -1)) {					//値の書式が設定されていなければ、テーブルに設定された書式を検索する。
									pInf.pFmt	= REG_get_string(pTblKey, Prp_fmt);			//書式文字列が無ければ、nullが格納される。	┬変数に対してPrpTbl_inf_l()等を呼び出した場合、書式文字列と書式番号の両方が無ければ、
									pInf.iFmt	= REG_get_value( pTblKey, Prp_fmt);			//書式番号が無ければ、-1が格納される。		┘その変数のタイプ,又は,その変数のテーブルから、書式文字列と書式番号の取得を試みる。
								}
							}
							break;
						case 1/*init*/:
							//テーブル変数を初期化する。
							// - 配列データが有り,かつ,呼び出し側がインデクスを全て省略した場合、配列全体にを初期化する。
							//  それ以外ならば、一つの変数,又は,配列の一要素を初期化する。
							do {
								PrpTbl_init(pPrpKey, iType, pPrpTbl, iBitPos);
								iBitPos += iBitLen;
								if(nIndex != 0) { break; }	//配列変数で,かつ,呼び出し側がインデクスを指定した場合は、ここで抜ける。
							} while(--iArraySize != 0);		//スカラー変数だった場合は、(iArraySize=1)なので、一回のループで抜ける。
							break;
						}
						break;	//ここまで
					}
					//次のループでこのテーブルに対して処理を繰り返す。
				}
			}
			return iVal;
		}
		//-----------------------------------------------------------------------------
		//リストaAttrの、一個目の終端までが必須属性リスト,二個目の終端までが拒否属性リストであると見なして、必須属性マスクと拒否属性マスクを作成する。
		private static void PrpTbl_make_attr_mask(out VoidPtr fIncl, out VoidPtr fExcl, IEnumerable<int> aIncl, IEnumerable<int> aExcl) {
			//必須属性マスクを作成する。
			fIncl = bitarray_alloc(256);
			foreach(int iAttr in aIncl) {
				if((uint)iAttr > 255) { throw new ApplicationException(); }				//呼び出し側のバグ。属性値が範囲外,又は,終端(-1)を忘れている。
				if(bitarray_lsb1st_get(fIncl, iAttr, 1) != 0) { throw new ApplicationException(); }	//呼び出し側のバグ。必須属性リスト内で属性値が重複指定された,又は,終端(-1)を忘れている。
				bitarray_lsb1st_set(fIncl, iAttr, 1, 1);
			}
			//拒否属性マスクを作成する。
			fExcl = bitarray_alloc(256);
			foreach(int iAttr in aExcl) {
				if((uint)iAttr > 255) { throw new ApplicationException(); }				//呼び出し側のバグ。属性値が範囲外,又は,終端(-1)を忘れている。
				if(bitarray_lsb1st_get(fExcl, iAttr, 1) != 0) { throw new ApplicationException(); }	//呼び出し側のバグ。拒否属性リスト内で属性値が重複指定された,又は,終端(-1)を忘れている。
				if(bitarray_lsb1st_get(fIncl, iAttr, 1) != 0) { throw new ApplicationException(); }	//呼び出し側のバグ。必須属性リストと拒否属性リストの両方に同じ属性値を含めてはいけない。	この検査を行わずに処理を継続する事は可能だが、必ず失敗する条件であり呼び出し側のバグの可能性が高いので、発見を早めるためにエラー停止する事にした。
				bitarray_lsb1st_set(fExcl, iAttr, 1, 1);
			}
		}
		//-----------------------------------------------------------------------------
		//変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和と、必須属性マスク,及び,拒否属性マスクとの比較を行う。
		//・戻り値 = 0: 変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、拒否属性マスクの属性を一つ以上含んでいる。(必須属性マスクとの比較結果は不問)
		//・戻り値 = 1: 変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、拒否属性マスクの属性を一つも含んでいないが、必須属性マスクの属性を全て満たしていない。
		//・戻り値 = 2: 変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、拒否属性マスクの属性を一つも含んでおらず,かつ,必須属性マスクの属性を全て満たしている。
		private static int PrpTbl_test_attr_mask(Int32Ptr fAttr, Int32Ptr fIncl, Int32Ptr fExcl) {
			int iAttr, iTest = 2;	//仮の戻り値を2(=両方の条件を満たしている)としておく。
			//全ての属性について、32ビットづつ…
			for(iAttr = 0; iAttr < (256/32); iAttr++) {
				//セットされている属性の一部でも、拒否属性マスクに含まれていたら、処理を打ち切って0(=拒否属性マスクの条件を満たしていない)を返す。
				if(( fAttr[iAttr] & fExcl[iAttr]) != 0) { return 0; }
				//クリアされている属性の一部でも、必須属性マスクに含まれていたら、仮の戻り値を1(=必須属性マスクの条件を満たしていない)に変更する。
				if((~fAttr[iAttr] & fIncl[iAttr]) != 0) { iTest = 1; }
			}
			//1(=必須属性マスクの条件を満たしていない),又は,2(=両方の条件を満たしている)を返す。
			return iTest;
		}
		//-----------------------------------------------------------------------------
		//変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和の、属性マスクを作成する。
		private static VoidPtr PrpTbl_merge_attr_mask(VoidPtr pVarKey, VoidPtr fInhe) {
			VoidPtr fAttr = bitarray_alloc(256);
			//継承属性マスクをコピーして、属性マスクの初期値とする。
			bitarray_lsb1st_copy(fAttr, 0, fInhe, 0, 256);
			//変数キーpVarKeyの属性リストを取得する。
			BytePtr pAttr = REG_get_blob(pVarKey, Prp_attr);
			//変数キーpVarKeyの属性リストが有れば…
			if(pAttr) {
				//属性の数を取得する。
				int nAttr = REG_get_blob_size(pAttr);
				//各属性について…
				while(--nAttr >= 0) {
					int iAttr = pAttr.Read();
					//属性マスクの該当ビットを確実にセットする。
					bitarray_lsb1st_set(fAttr, iAttr, 1, 1);
				}
			}
			return fAttr;
		}
		//-----------------------------------------------------------------------------
		//PrpTbl_init_attr_v()の再帰処理とPrpTbl_copy_attr_v()の再帰処理は、共通部分が多いので一つの関数にまとめました。
		private static void PrpTbl_init_copy_attr_subr(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTblDst, int iBitPosDst, VoidPtr pPrpTblSrc/*PrpTbl_init_attr_v()から呼び出された場合はnull*/, int iBitPosSrc/*PrpTbl_init_attr_v()から呼び出された場合はダミー*/, VoidPtr fInhe, VoidPtr fIncl, VoidPtr fExcl) {
			VoidPtr pTblKey, pVarKey;
			int i;
			int[] aName = new int[1];
			//テーブルキーを取得する。
			pTblKey = REG_open_key(pPrpKey, iTbl);
			if(!pTblKey) { throw new ApplicationException(); }
			//全ての変数キーについて…
			for(i = 0;
			   (pVarKey = REG_open_nth_key(pTblKey, i, out aName[0])) != null;
			    i++) {
				int iType, iBitLen, iBitPos, iArraySize, iTest;
				UInt16Ptr pDim;
				VoidPtr fAttr;
				//タイプ名,又は,テーブル名を取得する。
				iType = REG_get_value(pVarKey, Prp_type);
				//タイプ名,又は,テーブル名が有れば…
				if(iType != -1) {
					//タイプ,又は,テーブルのビット数を取得する。
					VoidPtr pTblOrTypKey = REG_open_key(pPrpKey, iType);
					if(!pTblOrTypKey) { throw new ApplicationException(); }
					iBitLen = REG_get_value(pTblOrTypKey, Prp_len);
					if(iBitLen == -1) { throw new ApplicationException(); }
					iBitLen++;	//(ビット数-1)⇒(ビット数)に補正する。
				//タイプ名,又は,テーブル名が無ければ、'var'型と見なす。
				} else {
					iBitLen = 32;
				}
				//変数のビット位置を取得する。
				iBitPos = REG_get_value(pVarKey, Prp_pos);
				if(iBitPos == -1) { throw new ApplicationException(); }
				//配列全体の要素数を1としておく。スカラー変数だった場合は1のままになる。
				iArraySize = 1;
				//配列データを取得する。
				pDim = REG_get_blob(pVarKey, Prp_dim);
				//配列データが有れば…
				if(pDim) {
					//次元数を取得する。
					int nDim = REG_get_blob_size(pDim);
					if((nDim & 1) != 0) { throw new ApplicationException(); }	//(要素数-1)は1個2バイトなので配列データのバイト数が奇数にはなり得ない。もしそうなったらデータエラーです。
					nDim >>= 1;	//配列データのバイト数⇒次元数に変換する。
					do {
						//この次元の(要素数-1)を取得する。
						int iBound = pDim.Read();	//このループ以降の処理でpDimを参照しないのでpDimを破壊して構わない。
						//(要素数-1)⇒(要素数)に補正する。
						iBound++;
						//配列全体の要素数に、この次元の要素数を乗算する。
						iArraySize *= iBound;
					} while(--nDim != 0);
				}
				//変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和の、属性マスクを作成する。
				fAttr = PrpTbl_merge_attr_mask(pVarKey, fInhe);
				//変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和と、必須属性マスク,及び,拒否属性マスクとの比較を行う。
				//・iTest = 0: 変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、拒否属性マスクの属性を一つ以上含んでいる。(必須属性マスクとの比較結果は不問)
				//・iTest = 1: 変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、拒否属性マスクの属性を一つも含んでいないが、必須属性マスクの属性を全て満たしていない。
				//・iTest = 2: 変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、拒否属性マスクの属性を一つも含んでおらず,かつ,必須属性マスクの属性を全て満たしている。
				iTest = PrpTbl_test_attr_mask(fAttr, fIncl, fExcl);
				//テーブル変数(iType<=0x7FFF)ならば…
				if((uint)iType <= 0x7FFF) {
					//変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、少なくとも、拒否属性マスクの属性を一つも含んでいなければ…
					// - この時点で必須属性マスクの属性を全て満たしていなくても、下位階層の変数の属性との論理和によって満たす可能性が有るので、この時点で条件を満たしていなくても再帰する。
					//   ただし、この時点で拒否属性マスクの属性を一つ以上含んでいたら、下位階層で条件を満たす可能性は無いので、再帰を打ち切る。(再帰しても結果は同じになるが、無駄である。)
					if(iTest >= 1) {
						//テーブル型のスカラ変数,又は,テーブル型の配列変数の各要素について、再帰する。
						do {
							PrpTbl_init_copy_attr_subr(pPrpKey, iType, pPrpTblDst, iBitPosDst + iBitPos,
												   pPrpTblSrc, iBitPosSrc + iBitPos, fAttr, fIncl, fExcl);
							iBitPos += iBitLen;
						} while(--iArraySize != 0);		//スカラー変数だった場合は、(iArraySize=1)なので、一回のループで抜ける。
					}
				//'var'変数(iType=-1),又は,タイプ変数(iType>=0x8000)ならば…
				} else {
					//変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、拒否属性マスクの属性を一つも含んでおらず,かつ,必須属性マスクの属性を全て満たしていれば…
					if(iTest == 2) {
						//PrpTbl_copy_attr_v()から呼び出された場合…
						if(pPrpTblSrc) {
							//変数のビット位置から、(変数のビット数*配列全体の要素数)ぶんの範囲を、コピーする。
							bitarray_lsb1st_copy(pPrpTblDst, iBitPosDst + iBitPos,
									     pPrpTblSrc, iBitPosSrc + iBitPos, iBitLen * iArraySize);
						//PrpTbl_init_attr_v()から呼び出された場合…
						} else {
							//このスカラ変数,又は,配列変数を初期化する。
							PrpTbl_op_v(pPrpKey, iTbl, pPrpTblDst, iBitPosDst, 0/*dummy*/, aName, 1/*init*/);
							//                                     ~~~~~~~~~~ 'iBitPosDst+iBitPos'としないように注意せよ。テーブルのビット位置に、変数のビット位置を加算する処理は、PrpTbl_op_v()がaNameを参照して行う。
						}
					}
				}
			}
		}
		//-----------------------------------------------------------------------------
		private static bool PrpTbl_list_subr(VoidPtr pPrpKey, int iTbl, Func<int/*iType*/,IEnumerable<int>/*aName*/,string/*sPath*/,object/*arg*/,bool> callback, List<int> aName, StringBuilder sPath, object arg) {
			int i, iNameLen, iPathLen1, iName;
			VoidPtr pTblKey, pVarKey;
			//変数名とインデクスの長さ(終端の-1を除く)を求める。
			iNameLen = aName.Count;
			//変数名を追加する前の、パス名の長さを記憶しておく。
			iPathLen1 = sPath.Length;
			//テーブルキーを取得する。
			pTblKey = REG_open_key(pPrpKey, iTbl);
			if(!pTblKey) { throw new ApplicationException(); }
			//全ての変数キーについて…
			for(i = 0;
			   (pVarKey = REG_open_nth_key(pTblKey, i, out iName)) != null;
			    i++) {
				int iType;
				string pName;
				UInt16Ptr pDim;
				//名前とインデクスの終端(-1)を格納する。
				aName.Add(iName);
				//パス名に、変数名を追加する。
				pName = REG_get_string(pVarKey, Prp_name);
				pName = pName ?? iName.ToString();	//変数名が格納されていなければ、数値を変数名とする。
				sPath.Append(pName);
				//タイプ名,又は,テーブル名を取得する。
				iType = REG_get_value(pVarKey, Prp_type);
				//配列データを取得する。
				pDim = REG_get_blob(pVarKey, Prp_dim);
				//配列データが有れば…
				if(pDim) {
					int nDim, iDim, iPathLen2;
					//'[インデクス,インデクス,...,インデクス]'を追加する前の、パス名の長さを記憶しておく。
					iPathLen2 = sPath.Length;
					//次元数を取得する。
					nDim = REG_get_blob_size(pDim);
					if((nDim & 1) != 0) { throw new ApplicationException(); }	//(要素数-1)は1個2バイトなので配列データのバイト数が奇数にはなり得ない。もしそうなったらデータエラーです。
					nDim >>= 1;	//配列データのバイト数⇒次元数に変換する。
					//aNameはaName[iNameLen+1]～aName[iNameLen+nDim]にインデクスを格納するので、pDimもpDim[1]～pDim[nDim]で(要素数-1)を参照出来るようにポインタを1つ前へずらしておく。
					pDim--;
					//インデクスを初期化する。
					for(iDim = 1; iDim <= nDim; iDim++) { aName.Add(0); }	//この次元のインデクスを0としておく。
					do {
						//パス名に、'[インデクス,インデクス,...,インデクス]'を追加する。
						sPath.Append('[');
						for(iDim = 1; iDim <= nDim; iDim++) {
							if(iDim != 1) { sPath.Append(','); }
							sPath.Append(aName[iNameLen + iDim]);
						}
						sPath.Append(']');
						//テーブル変数(iType<=0x7FFF)ならば…
						if((uint)iType <= 0x7FFF) {
							//組み込み'Double'型のテーブル変数ならば…
							if(iType == PrpTbl_Double) {
								//アプリケーション定義のコールバック関数を呼び出す。
								if(callback.Invoke(iType, aName, sPath.ToString(), arg)) { return true; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
							//アプリケーション定義のテーブル変数ならば…
							} else {
								//アプリケーション定義のコールバック関数を呼び出す。
								if(callback.Invoke(iType, aName, sPath.ToString(), arg)) { return true; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
								//このテーブル変数について再帰する。
								sPath.Append('.');
								if(PrpTbl_list_subr(pPrpKey, iType, callback, aName, sPath, arg)) { return true; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
							}
						//'var'変数(iType=-1),又は,タイプ変数(iType>=0x8000)ならば…
						} else {
							//アプリケーション定義のコールバック関数を呼び出す。
							if(callback.Invoke(iType, aName, sPath.ToString(), arg)) { return true; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
						}
						//パス名から、'[インデクス,インデクス,...,インデクス]'[.]を削除する。
						sPath.Length = iPathLen2;
						//インデクスを進める。後方の次元を早く変化させる。
						for(iDim = nDim; iDim >= 1; iDim--) {
							int iBound = pDim[iDim];	//この次元の(要素数-1)を取得する。	pDimもpDim[1]～pDim[nDim]で(要素数-1)を参照出来るようにポインタを1つ前へずらしてあります。
							    iBound++;			//(要素数-1)⇒(要素数)に補正する。
							if(++aName[iNameLen + iDim] < iBound) { break; }
							     aName[iNameLen + iDim] = 0;
						}//↓for()を抜けた時のiDimを参照している事に注意。
					} while(iDim != 0);	//インデクスを進められなくなったら抜ける。
				//配列データが無ければ…
				} else {
					//テーブル変数(iType<=0x7FFF)ならば…
					if((uint)iType <= 0x7FFF) {
						//組み込み'Double'型のテーブル変数ならば…
						if(iType == PrpTbl_Double) {
							//アプリケーション定義のコールバック関数を呼び出す。
							if(callback.Invoke(iType, aName, sPath.ToString(), arg)) { return true; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
						//アプリケーション定義のテーブル変数ならば…
						} else {
							//アプリケーション定義のコールバック関数を呼び出す。
							if(callback.Invoke(iType, aName, sPath.ToString(), arg)) { return true; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
							//このテーブル変数について再帰する。
							sPath.Append('.');
							if(PrpTbl_list_subr(pPrpKey, iType, callback, aName, sPath, arg)) { return true; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
						}
					//'var'変数(iType=-1),又は,タイプ変数(iType>=0x8000)ならば…
					} else {
						//アプリケーション定義のコールバック関数を呼び出す。
						if(callback.Invoke(iType, aName, sPath.ToString(), arg)) { return true; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
					}
				}
				//パス名から、変数名[.]を削除する。
				sPath.Length = iPathLen1;
				//変数名とインデクスの長さを元に戻す。
				aName.RemoveRange(iNameLen, aName.Count - iNameLen);
			}
			return false;
		}
		//-----------------------------------------------------------------------------
		private class ST_PrpDmp {
			public TextWriter	fp;
			public VoidPtr		pPrpKey;
			public int		iTbl;
			public VoidPtr		pPrpTbl;
			public int		iBitPos;
			public Func<int/*iFmt*/,int/*iVal*/,string> fnVarFmt/*null可*/;
			public int		fOpt;
			public int		maxDepth;
		}
		private static bool PrpTbl_dump_maxDepth(int iType, IEnumerable<int> aName, string sPath, object arg) {
			ST_PrpDmp pDmp = (ST_PrpDmp)arg;
			int depth = sPath.Where(c => (c == '.')).Count();	//'.'の数を数える。
			if(depth > pDmp.maxDepth) { pDmp.maxDepth = depth; }
			return false;
		}
		//階層形式のダンプは、リテラル値を持たない変数(=テーブル変数)も含めて、全ての変数について1行づつ出力する。
		private static bool PrpTbl_dump_callback(int iType, IEnumerable<int> aName, string sPath, object arg) {
			ST_PrpDmp pDmp = (ST_PrpDmp)arg;
			string pName;
			ST_PrpInf stPrpInf;
			int p1 = 0, p2;
			int depth = 0;
			stPrpInf = PrpTbl_inf_v(pDmp.pPrpKey, pDmp.iTbl, aName);
			if(stPrpInf.iType != iType) { throw new ApplicationException(); }	//バグ
			if((pDmp.fOpt & PrpDmp_Vbs) != 0) {	//verbose
				if(iType == -1) {
					pName = "var";
				} else if(iType == PrpTbl_Double) {
					pName = "Double";
				} else if((pName = REG_get_string_l(pDmp.pPrpKey, iType, Prp_name)) == null) {
					pName = iType.ToString();
				}
				pDmp.fp.Write("{0}\t{1}\t", stPrpInf.iBitPos, pName);
			}
			while((p2 = sPath.IndexOf('.', p1)) != -1) {
				pDmp.fp.Write('\t');
				depth++;
				p1 = p2 + 1/*'.'*/;
			}
			pDmp.fp.Write(sPath.Substring(p1));
			//テーブル変数(iType<=0x7FFF)ならば…
			if((uint)iType <= 0x7FFF) {
				if(iType == PrpTbl_Double) {
					while(depth < pDmp.maxDepth) {
						pDmp.fp.Write('\t');
						depth++;
					}
					pDmp.fp.Write("\t= ");
					pDmp.fp.Write(PrpTbl_ffmt_v(pDmp.pPrpKey, pDmp.iTbl, pDmp.pPrpTbl, pDmp.iBitPos, aName));
					depth++;
				}
			//'var'変数(iType=-1),又は,タイプ変数(iType>=0x8000)ならば…
			} else {
				while(depth < pDmp.maxDepth) {
					pDmp.fp.Write('\t');
					depth++;
				}
				pDmp.fp.Write("\t= ");
				pDmp.fp.Write(PrpTbl_fmt_v(pDmp.pPrpKey, pDmp.iTbl, pDmp.pPrpTbl, pDmp.iBitPos, pDmp.fnVarFmt, aName));
				depth++;
			}
			if(stPrpInf.pDesc != null) {
				while(depth < (pDmp.maxDepth + 1)) {
					pDmp.fp.Write('\t');
					depth++;
				}
				pDmp.fp.Write("\t#//{0}", stPrpInf.pDesc);
			}
			pDmp.fp.Write('\n');
			return false;
		}
		//絶対パス形式のダンプは、リテラル値を持つ変数(=var変数,タイプ変数,Doubleテーブル変数)の行だけを出力する。
		private static bool PrpTbl_dump_abs_callback(int iType, IEnumerable<int> aName, string sPath, object arg) {
			ST_PrpDmp pDmp = (ST_PrpDmp)arg;
			string pName;
			ST_PrpInf stPrpInf;
			stPrpInf = PrpTbl_inf_v(pDmp.pPrpKey, pDmp.iTbl, aName);
			if(stPrpInf.iType != iType) { throw new ApplicationException(); }	//バグ
			//テーブル変数(iType<=0x7FFF)ならば…
			if((uint)iType <= 0x7FFF) {
				if(iType == PrpTbl_Double) {
					if((pDmp.fOpt & PrpDmp_Vbs) != 0) {	//verbose
						pName = "Double";
						pDmp.fp.Write("{0}\t{1}\t", stPrpInf.iBitPos, pName);
					}
					pDmp.fp.Write(sPath);
					pDmp.fp.Write("\t= ");
					pDmp.fp.Write(PrpTbl_ffmt_v(pDmp.pPrpKey, pDmp.iTbl, pDmp.pPrpTbl, pDmp.iBitPos, aName));
					if(stPrpInf.pDesc != null) { pDmp.fp.Write("\t#//{0}", stPrpInf.pDesc); }
					pDmp.fp.Write('\n');
				}
			//'var'変数(iType=-1),又は,タイプ変数(iType>=0x8000)ならば…
			} else {
				if((pDmp.fOpt & PrpDmp_Vbs) != 0) {	//verbose
					if(iType == -1) {
						pName = "var";
					} else if((pName = REG_get_string_l(pDmp.pPrpKey, iType, Prp_name)) == null) {
						pName = iType.ToString();
					}
					pDmp.fp.Write("{0}\t{1}\t", stPrpInf.iBitPos, pName);
				}
				pDmp.fp.Write(sPath);
				pDmp.fp.Write("\t= ");
				pDmp.fp.Write(PrpTbl_fmt_v(pDmp.pPrpKey, pDmp.iTbl, pDmp.pPrpTbl, pDmp.iBitPos, pDmp.fnVarFmt, aName));
				if(stPrpInf.pDesc != null) { pDmp.fp.Write("\t#//{0}", stPrpInf.pDesc); }
				pDmp.fp.Write('\n');
			}
			return false;
		}
		//*****************************************************************************
		//	基本的な関数
		//*****************************************************************************
		public static VoidPtr PrpTbl_new(VoidPtr pPrpKey, int iTbl) {
			VoidPtr pPrpTbl, pTblKey;
			int iBitLen;
			//テーブルキーを取得する。
			pTblKey = REG_open_key(pPrpKey, iTbl);
			if(!pTblKey) { throw new ApplicationException(); }
			//このテープルの(ビット数-1)を取得する。
			iBitLen = REG_get_value(pTblKey, Prp_len);
			if(iBitLen == -1) { throw new ApplicationException(); }
			//(ビット数-1)⇒(ビット数)に補正する。
			iBitLen++;
			//テーブルのビット配列を確保する。
			pPrpTbl = bitarray_alloc(iBitLen);
			if(!pPrpTbl) { throw new ApplicationException(); }
			//テーブルを初期化する。
			PrpTbl_init(pPrpKey, iTbl, pPrpTbl, 0/*iBitPos*/);
			return pPrpTbl;
		}
		public static void PrpTbl_init(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos) {
			VoidPtr pTblKey;
			int i;
			int[] aName = new int[1];
			//テーブルキーを取得する。
			pTblKey = REG_open_key(pPrpKey, iTbl);
			if(!pTblKey) { throw new ApplicationException(); }
			//全ての変数を初期化する。
			for(i = 0;
			    REG_open_nth_key(pTblKey, i, out aName[0]);
			    i++) {
				PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, 0/*dummy*/, aName, 1/*init*/);
			}
		}
		public static void PrpTbl_init_attr(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, int iAttr) {
			PrpTbl_init_attr_v(pPrpKey, iTbl, pPrpTbl, iBitPos, new int[] { iAttr }, new int[] { });
		}
		public static void PrpTbl_init_attr_v(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, IEnumerable<int> aIncl, IEnumerable<int> aExcl) {
			VoidPtr fIncl, fExcl;
			//必須属性マスクと拒否属性マスクを作成する。
			PrpTbl_make_attr_mask(out fIncl, out fExcl, aIncl, aExcl);
			//再帰処理を開始する。
			PrpTbl_init_copy_attr_subr(pPrpKey, iTbl, pPrpTbl, iBitPos, null/*pPrpTblSrc*/, 0/*iBitPosSrc*/, bitarray_alloc(256)/*fInhe*/, fIncl, fExcl);	//PrpTbl_init_attr_v()とPrpTbl_copy_attr_v()の共通処理
		}
		public static void PrpTbl_copy_attr(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTblDst, int iBitPosDst, VoidPtr pPrpTblSrc,int iBitPosSrc, int iAttr) {
			PrpTbl_copy_attr_v(pPrpKey, iTbl, pPrpTblDst, iBitPosDst, pPrpTblSrc, iBitPosSrc, new int[] { iAttr }, new int[] { });
		}
		public static void PrpTbl_copy_attr_v(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTblDst, int iBitPosDst, VoidPtr pPrpTblSrc, int iBitPosSrc, IEnumerable<int> aIncl, IEnumerable<int> aExcl) {
			VoidPtr fIncl, fExcl;
			//必須属性マスクと拒否属性マスクを作成する。
			PrpTbl_make_attr_mask(out fIncl, out fExcl, aIncl, aExcl);
			//再帰処理を開始する。
			PrpTbl_init_copy_attr_subr(pPrpKey, iTbl, pPrpTblDst, iBitPosDst, pPrpTblSrc, iBitPosSrc, bitarray_alloc(256)/*fInhe*/, fIncl, fExcl);	//PrpTbl_init_attr_v()とPrpTbl_copy_attr_v()の共通処理
		}
		//-----------------------------------------------------------------------------
		public static void PrpTbl_init_l(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, params int[] aName) {
			PrpTbl_init_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName);
		}
		public static void PrpTbl_init_v(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, IEnumerable<int> aName) {
		    //{{特例処理
			//「PrpTbl_init_l(pPrpKey,iTbl,pPrpTbl,0,-1)」の形で呼び出された場合は、PrpTbl_op_v()を経由せずに、ここでPrpTbl_init()を呼び出す事にした。
			// - PrpTbl_op_v()を呼び出すと、PrpTbl_op_v()が誤ってエラーと判断してしまう。
			//   PrpTbl_op_v()に特例処理を追加するよりも、ここで判断する方が自然だと思うので、ここに特例処理を追加する事にしました。
			if(!aName.GetEnumerator().MoveNext()) { PrpTbl_init(pPrpKey, iTbl, pPrpTbl, iBitPos); return; }
		    //}}特例処理
			PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, 0/*dummy*/, aName, 1/*init*/);
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static void PrpTbl_init_f(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, string sFmt, params object[] args) {
			PrpTbl_init_p(pPrpKey, iTbl, pPrpTbl, iBitPos, string.Format(sFmt, args));
		}
		public static void PrpTbl_init_p(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, string sPath) {
			PrpTbl_init_v(pPrpKey, iTbl, pPrpTbl, iBitPos, PrpTbl_path_p(pPrpKey, iTbl, sPath));
		}
		//-----------------------------------------------------------------------------
		public static void PrpTbl_set_l(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, int iNewVal, params int[] aName) {
			PrpTbl_set_v(pPrpKey, iTbl, pPrpTbl, iBitPos, iNewVal, aName);
		}
		public static void PrpTbl_set_v(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, int iNewVal, IEnumerable<int> aName) {
			PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, iNewVal, aName, 2/*set*/);
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static void PrpTbl_set_f(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, int iNewVal, string sFmt, params object[] args) {
			PrpTbl_set_p(pPrpKey, iTbl, pPrpTbl, iBitPos, iNewVal, string.Format(sFmt, args));
		}
		public static void PrpTbl_set_p(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, int iNewVal, string sPath) {
			PrpTbl_set_v(pPrpKey, iTbl, pPrpTbl, iBitPos, iNewVal, PrpTbl_path_p(pPrpKey, iTbl, sPath));
		}
		//-----------------------------------------------------------------------------
		public static int PrpTbl_get_l(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, params int[] aName) {
			return PrpTbl_get_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName);
		}
		public static int PrpTbl_get_v(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, IEnumerable<int> aName) {
			return PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, 0/*増減値*/, aName, 3/*get/acc*/);
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static int PrpTbl_get_f(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, string sFmt, params object[] args) {
			return PrpTbl_get_p(pPrpKey, iTbl, pPrpTbl, iBitPos, string.Format(sFmt, args));
		}
		public static int PrpTbl_get_p(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, string sPath) {
			return PrpTbl_get_v(pPrpKey, iTbl, pPrpTbl, iBitPos, PrpTbl_path_p(pPrpKey, iTbl, sPath));
		}
		//-----------------------------------------------------------------------------
		public static int PrpTbl_acc_l(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, int iAcc, params int[] aName) {
			return PrpTbl_acc_v(pPrpKey, iTbl, pPrpTbl, iBitPos, iAcc, aName);
		}
		public static int PrpTbl_acc_v(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, int iAcc, IEnumerable<int> aName) {
			return PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, iAcc, aName, 3/*get/acc*/);
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static int PrpTbl_acc_f(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, int iAcc, string sFmt, params object[] args) {
			return PrpTbl_acc_p(pPrpKey, iTbl, pPrpTbl, iBitPos, iAcc, string.Format(sFmt, args));
		}
		public static int PrpTbl_acc_p(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, int iAcc, string sPath) {
			return PrpTbl_acc_v(pPrpKey, iTbl, pPrpTbl, iBitPos, iAcc, PrpTbl_path_p(pPrpKey, iTbl, sPath));
		}
		//-----------------------------------------------------------------------------
		public class ST_PrpInf {
			public int		iType;		//変数の型。(-1=var型,0x0000～0x7FFF=table型,0x8000～0xFFFF=type型)
			public int		iBitPos;	//変数のビット位置。(0ベースのオフセット)
			public int		nDim;		//配列の次元数。				┬配列変数のパス名を指定し,かつ,インデクスを全て省略した場合のみ、nDim=1以上,pDim=配列データへのポインタを格納します。
			public UInt16Ptr	pDim/*[nDim]*/;	//配列の各次元のインデクスの最大値。		┘上記以外の場合は、nDim=0,pDim=nullを格納します。配列変数の一要素のパス名を指定した場合(インデクスを指定した場合)は、nDim=0,pDim=nullが格納される事に注意して下さい。		pDim[0～nDim-1]の値は、配列の各次元の要素数ではなく、インデクスの最大値(=要素数-1)である事に注意せよ。
			public string		pName;		//名前文字列が無ければ、nullが格納される。
			public string		pDesc;		//説明文が無ければ、nullが格納される。
			public string		pFmt;		//書式文字列が無ければ、nullが格納される。	┬変数に対してPrpTbl_inf_l()等を呼び出した場合、書式文字列と書式番号の両方が無ければ、	┬(pFmt=null,iFmt=-1),又は,(pFmt=書式文字列,iFmt=-1),又は,(pFmt=null,iFmt=書式番号)のいずれかです。
			public int		iFmt;		//書式番号が無ければ、-1が格納される。		┘その変数のタイプ,又は,その変数のテーブルから、書式文字列と書式番号の取得を試みる。	┘同時指定は不可。万一、(pFmt=書式文字列,iFmt=書式番号)が格納されていたら、dPrpTblC.exeのバグです。
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static ST_PrpInf PrpTbl_inf_l(VoidPtr pPrpKey, int iTbl, params int[] aName) {
			return PrpTbl_inf_v(pPrpKey, iTbl, aName);
		}
		public static ST_PrpInf PrpTbl_inf_v(VoidPtr pPrpKey, int iTbl, IEnumerable<int> aName) {
			ST_PrpInf pInf = new ST_PrpInf();
			PrpTbl_op_v(pPrpKey, iTbl, null/*dummy*/, 0/*iBitPos*/, pInf, aName, 0/*inf*/);
			//                                        ~~~~~~~~~~~~PrpTbl_op_v()が(pInf.iBitPos)を計算するためにiBitPosの初期値として0を指定する。
			return pInf;
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static ST_PrpInf PrpTbl_inf_f(VoidPtr pPrpKey, int iTbl, string sFmt, params object[] args) {
			return PrpTbl_inf_p(pPrpKey, iTbl, string.Format(sFmt, args));
		}
		public static ST_PrpInf PrpTbl_inf_p(VoidPtr pPrpKey, int iTbl, string sPath) {
			return PrpTbl_inf_v(pPrpKey, iTbl, PrpTbl_path_p(pPrpKey, iTbl, sPath));
		}
		//-----------------------------------------------------------------------------
		public static string PrpTbl_fmt_l(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, Func<int/*iFmt*/,int/*iVal*/,string> fnVarFmt/*null可*/, params int[] aName) {
			return PrpTbl_fmt_v(pPrpKey, iTbl, pPrpTbl, iBitPos, fnVarFmt, aName);
		}
		public static string PrpTbl_fmt_v(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, Func<int/*iFmt*/,int/*iVal*/,string> fnVarFmt/*null可*/, IEnumerable<int> aName) {
			int iVal = PrpTbl_get_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName);
			ST_PrpInf stPrpInf = PrpTbl_inf_v(pPrpKey, iTbl, aName);
			//<"書式文字列">と<書式番号>の同時指定は不可としました。
			//│2016/1/1以前は同時指定も可能だったのですが、変数フォーマッタに書式文字列と書式番号を渡しても、実質、書式文字列の使い道が無く無駄でした。
			//│変数フォーマッタの仕様を単純にするために、<"書式文字列">と<書式番号>の同時指定は不可とする事にしました。
			if((stPrpInf.pFmt != null) && (stPrpInf.iFmt != -1)) { throw new ApplicationException(); }	//<"書式文字列">と<書式番号>の同時指定は不可。もしここで止まったらdPrpTblC.exeのバグです。
			//書式指定=<"書式文字列">ならば…
			if(stPrpInf.pFmt != null) {
				return iVal.ToString(stPrpInf.pFmt);
			//書式指定=<書式番号>,かつ,変数フォーマッタ指定有りならば…
			} else if((stPrpInf.iFmt != -1) && (fnVarFmt != null)) {
				return fnVarFmt.Invoke(stPrpInf.iFmt, iVal);
			//書式指定=<書式番号>,かつ,変数フォーマッタ指定無し、又は、書式指定無しならば…
			} else {
				return iVal.ToString();
			}
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static string PrpTbl_fmt_f(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, Func<int/*iFmt*/,int/*iVal*/,string> fnVarFmt/*null可*/, string sFmt, params object[] args) {
			return PrpTbl_fmt_p(pPrpKey, iTbl, pPrpTbl, iBitPos, fnVarFmt/*null可*/, string.Format(sFmt, args));
		}
		public static string PrpTbl_fmt_p(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, Func<int/*iFmt*/,int/*iVal*/,string> fnVarFmt/*null可*/, string sPath) {
			return PrpTbl_fmt_v(pPrpKey, iTbl, pPrpTbl, iBitPos, fnVarFmt/*null可*/, PrpTbl_path_p(pPrpKey, iTbl, sPath));
		}
		//-----------------------------------------------------------------------------
		public static void PrpTbl_fset_l(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, double dNewVal, params int[] aName) {
			PrpTbl_fset_v(pPrpKey, iTbl, pPrpTbl, iBitPos, dNewVal, aName);
		}
		public static void PrpTbl_fset_v(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, double dNewVal, IEnumerable<int> aName) {
			List<int> aName2 = new List<int>(aName);
			long lNewVal = BitConverter.DoubleToInt64Bits(dNewVal);
			aName2.Add(1);			//下位ワード
			PrpTbl_set_v(pPrpKey, iTbl, pPrpTbl, iBitPos, (int)lNewVal, aName2);
			aName2[aName2.Count - 1] = 2;	//上位ワード
			PrpTbl_set_v(pPrpKey, iTbl, pPrpTbl, iBitPos, (int)(lNewVal >> 32), aName2);
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static void PrpTbl_fset_f(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, double dNewVal, string sFmt, params object[] args) {
			PrpTbl_fset_p(pPrpKey, iTbl, pPrpTbl, iBitPos, dNewVal, string.Format(sFmt, args));
		}
		public static void PrpTbl_fset_p(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, double dNewVal, string sPath) {
			PrpTbl_fset_v(pPrpKey, iTbl, pPrpTbl, iBitPos, dNewVal, PrpTbl_path_p(pPrpKey, iTbl, sPath));
		}
		//-----------------------------------------------------------------------------
		public static double PrpTbl_fget_l(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, params int[] aName) {
			return PrpTbl_fget_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName);
		}
		public static double PrpTbl_fget_v(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, IEnumerable<int> aName) {
			List<int> aName2 = new List<int>(aName);
			aName2.Add(1);			//下位ワード
			long lo = (uint)PrpTbl_get_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName2);
			aName2[aName2.Count - 1] = 2;	//上位ワード
			long hi = (uint)PrpTbl_get_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName2);
			return BitConverter.Int64BitsToDouble(lo | (hi << 32));
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static double PrpTbl_fget_f(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, string sFmt, params object[] args) {
			return PrpTbl_fget_p(pPrpKey, iTbl, pPrpTbl, iBitPos, string.Format(sFmt, args));
		}
		public static double PrpTbl_fget_p(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, string sPath) {
			return PrpTbl_fget_v(pPrpKey, iTbl, pPrpTbl, iBitPos, PrpTbl_path_p(pPrpKey, iTbl, sPath));
		}
		//-----------------------------------------------------------------------------
		public static string PrpTbl_ffmt_l(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, params int[] aName) {
			return PrpTbl_ffmt_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName);
		}
		public static string PrpTbl_ffmt_v(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, IEnumerable<int> aName) {
			double dVal = PrpTbl_fget_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName);
			ST_PrpInf stPrpInf = PrpTbl_inf_v(pPrpKey, iTbl, aName);
			//組み込み'Double'型の変数に対して設定出来る書式指定は<"書式文字列">のみとした。
			//│そうしないと変数フォーマッタの第5引数をintに出来ず複雑になるからです。
			//│組み込み'Double'型の変数に対して<書式番号>を指定しないで下さい。
			if(stPrpInf.iFmt != -1) { throw new ApplicationException(); }	//組み込み'Double'型の変数に対して<書式番号>の指定は不可。
			//書式指定=<"書式文字列">ならば…
			if(stPrpInf.pFmt != null) {
				return dVal.ToString(stPrpInf.pFmt);
			//書式指定無しならば…
			} else {
				return dVal.ToString();
			}
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static string PrpTbl_ffmt_f(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, string sFmt, params object[] args) {
			return PrpTbl_ffmt_p(pPrpKey, iTbl, pPrpTbl, iBitPos, string.Format(sFmt, args));
		}
		public static string PrpTbl_ffmt_p(VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, string sPath) {
			return PrpTbl_ffmt_v(pPrpKey, iTbl, pPrpTbl, iBitPos, PrpTbl_path_p(pPrpKey, iTbl, sPath));
		}
		//-----------------------------------------------------------------------------
		public static IEnumerable<int> PrpTbl_path_f(VoidPtr pPrpKey, int iTbl, string sFmt, params object[] args) {
			return PrpTbl_path_p(pPrpKey, iTbl, string.Format(sFmt, args));
		}
		public static IEnumerable<int> PrpTbl_path_p(VoidPtr pPrpKey, int iTbl, string sPath) {
			return PrpTbl_path_p_subr(pPrpKey, iTbl, sPath);
		}
		private static List<int> PrpTbl_path_p_subr(VoidPtr pPrpKey, int iTbl, StringPtr sPath) {
			List<int> aName = new List<int>();
			int iType = iTbl;
			if(sPath[0] != '\0') {
				for(;;) {
					VoidPtr pTblKey, pVarKey;
					int len, i, c, iName;
#if     DEBUG
					UInt16Ptr pDim;	//┬当関数においてレジストリから配列データを取得するのはエラー検査のためだけである。
					int nDim;	//┘結果には影響無いので、リリースビルドでは配列データを取得しない事にした。
#endif//DEBUG
					pTblKey = REG_open_key(pPrpKey, iType);						//テーブルキーを取得する。
					if(!pTblKey) { throw new ApplicationException(); }				//テーブルキーが無ければエラー停止する。
					len = strcspn(sPath, ".[");							//パス名の文字列から、次の変数名の文字列の長さを取得する。
					if(len == 0) { throw new ApplicationException(); }				//変数名の文字列が無ければエラー停止する。
					for(i = 0;									//現在のテーブルの全ての変数キーについて…
					   (pVarKey = REG_open_nth_key(pTblKey, i, out iName)) != null;
					    i++) {
						string pName = REG_get_string(pVarKey, Prp_name);			//変数名の文字列を取得する。
						pName = pName ?? iName.ToString();					//変数名の文字列が格納されていなければ、数値を変数名とする。
						if((pName.Length == len) && (strncmp(sPath, pName, len) == 0)) { break; }	//変数名の文字列が一致したら抜ける。
					}
					if(!pVarKey) { throw new ApplicationException(); }				//変数名の文字列が一致する変数キーが無ければエラー停止する。
					iType = REG_get_value(pVarKey, Prp_type);					//タイプ名,又は,テーブル名を取得する。
					aName.Add(iName);								//変数名の数値を格納する。
#if     DEBUG
					pDim = REG_get_blob(pVarKey, Prp_dim);						//配列データを取得する。	配列変数でなければ(pDim=null)になる。
					nDim = REG_get_blob_size(pDim/*null可*/);					//┬次元数を取得する。		配列変数でなければ(nDim=0)になる。
					if((nDim & 1) != 0) { throw new ApplicationException(); }			//│(要素数-1)は1個2バイトなので配列データのバイト数が奇数にはなり得ない。もしそうなったらデータエラーです。
					nDim >>= 1;									//┘配列データのバイト数⇒次元数に変換する。
#endif//DEBUG
					sPath += len;									//パス名の文字列を、この変数名の文字列の分進める。
					c = sPath.Read();								//変数名の文字列の次の文字を取得して、次へ進める。
					if(c == '[') {									//配列指定ならば…
						for(;;) {
							StringPtr endptr;
							if(!isdigit(sPath[0])) { throw new ApplicationException(); }	//'[',又は,','の直後の文字が数字でなければエラー。
							i = (int)strtoul(sPath, out endptr, 0);				//インデクスを取得する。
#if     DEBUG
							if(--nDim < 0) { throw new ApplicationException(); }		//次元数がオーバーしたらエラー停止する。	スカラー変数に対して配列指定が行われた場合もここで停止する。
							if(i > pDim.Read()) { throw new ApplicationException(); }	//インデクスが範囲外ならばエラー停止する。	配列データの値は(要素数-1),即ちインデクスの最大値であるから、インデクスがエラーとなる条件は'>='ではなく'>'である事に注意せよ。
#endif//DEBUG
							aName.Add(i);							//インデクスを格納する。
							sPath = endptr;							//インデクスを読み飛ばす。
							c = sPath.Read();						//インデクスの終端文字を取得して、次へ進める。
							if(c == ']') { break; }						//インデクスの終端文字が']'だったならば、ループを抜ける。
							if(c != ',') { throw new ApplicationException(); }		//インデクスの終端文字が','だったならば、次のシーケンスに対してインデクスアクセスを継続する。']'でも','でもなかったらエラー。
						}
#if     DEBUG
						if(nDim != 0) { throw new ApplicationException(); }			//配列変数に対しては、次元を全て指定するか,又は,全て省略するかの、どちらかのみ可。このブロックは次元を指定した場合なので、全て指定されなかったら(=次元が残っていたら)エラー停止する。
#endif//DEBUG
						c = sPath.Read();							//']'の次の文字を取得して、次へ進める。
					}
					if(c == 0) { break; }								//変数名の文字列の次の文字,又は,']'の次の文字がヌル文字ならば、ループを抜ける。
					if(c != '.') { throw new ApplicationException(); }				//変数名の文字列の次の文字,又は,']'の次の文字が'.'ならば、継続する。ヌル文字でも'.'でもなければ、エラー停止する。
					if((uint)iType > 0x7FFF) { throw new ApplicationException(); }			//この変数がテーブル変数(iType<=0x7FFF)でなければ，即ち'var'変数(iType=-1),又は,タイプ変数(iType>=0x8000)ならば、次の階層は無いはずである。従って、継続しようとしたらエラー停止する。
#if     DEBUG
					if(nDim != 0) { throw new ApplicationException(); }				//配列変数に対して次元を全て省略する事は、パスの末尾でのみ可。配列変数に対して次元を全て省略した後に、継続しようとしたらエラー停止する。
#endif//DEBUG
				}
			}
			return aName;	//C言語版ではタイプ名,又は,テーブル名を返していたが、C#版では利便性のために名前配列を返す事にした。タイプ名,又は,テーブル名が必要な場合は別途PrpTbl_inf_v()等を呼び出して下さい。
		}
		//-----------------------------------------------------------------------------
		public static bool PrpTbl_list(VoidPtr pPrpKey, int iTbl, Func<int/*iType*/,IEnumerable<int>/*aName*/,string/*sPath*/,object/*arg*/,bool> callback, object arg) {
			IEnumerable<int> aName;
			string sPath;
			return PrpTbl_list(pPrpKey, iTbl, callback, out aName, out sPath, arg);
		}
		public static bool PrpTbl_list(VoidPtr pPrpKey, int iTbl, Func<int/*iType*/,IEnumerable<int>/*aName*/,string/*sPath*/,object/*arg*/,bool> callback, out IEnumerable<int> aName, object arg) {
			string sPath;
			return PrpTbl_list(pPrpKey, iTbl, callback, out aName, out sPath, arg);
		}
		public static bool PrpTbl_list(VoidPtr pPrpKey, int iTbl, Func<int/*iType*/,IEnumerable<int>/*aName*/,string/*sPath*/,object/*arg*/,bool> callback, out string sPath, object arg) {
			IEnumerable<int> aName;
			return PrpTbl_list(pPrpKey, iTbl, callback, out aName, out sPath, arg);
		}
		public static bool PrpTbl_list(VoidPtr pPrpKey, int iTbl, Func<int/*iType*/,IEnumerable<int>/*aName*/,string/*sPath*/,object/*arg*/,bool> callback, out IEnumerable<int> aName, out string sPath, object arg) {
			List<int> _aName = new List<int>();
			StringBuilder _sPath = new StringBuilder();
			bool retVal = PrpTbl_list_subr(pPrpKey, iTbl, callback, _aName, _sPath, arg);
			aName = _aName;
			sPath = _sPath.ToString();
			return retVal;
		}
		//-----------------------------------------------------------------------------
		public const int PrpDmp_Abs	= (1<<0);	//absolute
		public const int PrpDmp_Vbs	= (1<<1);	//verbose
		public static void PrpTbl_dump(TextWriter fp, VoidPtr pPrpKey, int iTbl, VoidPtr pPrpTbl, int iBitPos, Func<int/*iFmt*/,int/*iVal*/,string> fnVarFmt/*null可*/, int fOpt/*(PrpDmp_*の0個以上の組み合わせ)*/) {
			ST_PrpDmp stPrpDmp = new ST_PrpDmp();
			stPrpDmp.fp		= fp;
			stPrpDmp.pPrpKey	= pPrpKey;
			stPrpDmp.iTbl		= iTbl;
			stPrpDmp.pPrpTbl	= pPrpTbl;
			stPrpDmp.iBitPos	= iBitPos;
			stPrpDmp.fnVarFmt	= fnVarFmt;
			stPrpDmp.fOpt		= fOpt;
			if((fOpt & PrpDmp_Abs) != 0) {	//absolute
				PrpTbl_list(pPrpKey, iTbl, PrpTbl_dump_abs_callback, stPrpDmp);
			} else {
				PrpTbl_list(pPrpKey, iTbl, PrpTbl_dump_maxDepth, stPrpDmp);	//1パス目で最大深度を判断する。
				PrpTbl_list(pPrpKey, iTbl, PrpTbl_dump_callback, stPrpDmp);	//2パス目で表示する。値とコメントの列を最大深度に揃える。
			}
		}
		//*****************************************************************************
		//	ユーティリティ関数
		//*****************************************************************************
		public class ST_PrpHdr {
			public VoidPtr		pPrpKey;
			public int		iTbl;
			public VoidPtr		pPrpTbl;
		}
		//-----------------------------------------------------------------------------
		public static ST_PrpHdr PrpHdr_new(VoidPtr pPrpKey, int iTbl) {
			ST_PrpHdr pPrpHdr;
			VoidPtr pTblKey;
			int iBitLen;
			//テーブルキーを取得する。
			pTblKey = REG_open_key(pPrpKey, iTbl);
			if(!pTblKey) { throw new ApplicationException(); }
			//このテープルの(ビット数-1)を取得する。
			iBitLen = REG_get_value(pTblKey, Prp_len);
			if(iBitLen == -1) { throw new ApplicationException(); }
			//(ビット数-1)⇒(ビット数)に補正する。
			iBitLen++;
			//ST_PrpHdrとテーブルのビット配列を確保する。
			pPrpHdr = new ST_PrpHdr();
			pPrpHdr.pPrpTbl = bitarray_alloc(iBitLen);
			//ST_PrpHdrとテーブルを初期化する。
			PrpHdr_init(pPrpHdr, pPrpKey, iTbl);
			return pPrpHdr;
		}
		public static void PrpHdr_init(ST_PrpHdr pPrpHdr, VoidPtr pPrpKey, int iTbl) {
			//プロパティテーブルキーとテーブル名を格納する。
			pPrpHdr.pPrpKey	= pPrpKey;
			pPrpHdr.iTbl	= iTbl;
			//テーブルを初期化する。
			PrpTbl_init(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0);
		}
		public static void PrpHdr_init_attr(ST_PrpHdr pPrpHdr, int iAttr) {
			PrpHdr_init_attr_v(pPrpHdr, new int[] { iAttr }, new int[] { });
		}
		public static void PrpHdr_init_attr_v(ST_PrpHdr pPrpHdr, IEnumerable<int> aIncl, IEnumerable<int> aExcl) {
			PrpTbl_init_attr_v(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, aIncl, aExcl);
		}
		public static void PrpHdr_copy_attr(ST_PrpHdr pPrpHdrDst, ST_PrpHdr pPrpHdrSrc, int iAttr) {
			PrpHdr_copy_attr_v(pPrpHdrDst, pPrpHdrSrc, new int[] { iAttr }, new int[] { });
		}
		public static void PrpHdr_copy_attr_v(ST_PrpHdr pPrpHdrDst, ST_PrpHdr pPrpHdrSrc, IEnumerable<int> aIncl, IEnumerable<int> aExcl) {
			if((pPrpHdrDst.pPrpKey != pPrpHdrSrc.pPrpKey) ||
			   (pPrpHdrDst.iTbl    != pPrpHdrSrc.iTbl   )) { throw new ApplicationException(); }	//コピー先とコピー元は同じ型のプロパティテーブルでなければならない。
			PrpTbl_copy_attr_v(pPrpHdrDst.pPrpKey, pPrpHdrDst.iTbl, pPrpHdrDst.pPrpTbl, 0,
			                                                        pPrpHdrSrc.pPrpTbl, 0, aIncl, aExcl);
		}
		//-----------------------------------------------------------------------------
		public static void PrpHdr_init_l(ST_PrpHdr pPrpHdr, params int[] aName) {
			PrpHdr_init_v(pPrpHdr, aName);
		}
		public static void PrpHdr_init_v(ST_PrpHdr pPrpHdr, IEnumerable<int> aName) {
			PrpTbl_init_v(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, aName);
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static void PrpHdr_init_f(ST_PrpHdr pPrpHdr, string sFmt, params object[] args) {
			PrpHdr_init_p(pPrpHdr, string.Format(sFmt, args));
		}
		public static void PrpHdr_init_p(ST_PrpHdr pPrpHdr, string sPath) {
			PrpTbl_init_p(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, sPath);
		}
		//-----------------------------------------------------------------------------
		public static void PrpHdr_set_l(ST_PrpHdr pPrpHdr, int iNewVal, params int[] aName) {
			PrpHdr_set_v(pPrpHdr, iNewVal, aName);
		}
		public static void PrpHdr_set_v(ST_PrpHdr pPrpHdr, int iNewVal, IEnumerable<int> aName) {
			PrpTbl_set_v(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, iNewVal, aName);
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static void PrpHdr_set_f(ST_PrpHdr pPrpHdr, int iNewVal, string sFmt, params object[] args) {
			PrpHdr_set_p(pPrpHdr, iNewVal, string.Format(sFmt, args));
		}
		public static void PrpHdr_set_p(ST_PrpHdr pPrpHdr, int iNewVal, string sPath) {
			PrpTbl_set_p(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, iNewVal, sPath);
		}
		//-----------------------------------------------------------------------------
		public static int PrpHdr_get_l(ST_PrpHdr pPrpHdr, params int[] aName) {
			return PrpHdr_get_v(pPrpHdr, aName);
		}
		public static int PrpHdr_get_v(ST_PrpHdr pPrpHdr, IEnumerable<int> aName) {
			return PrpTbl_get_v(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, aName);
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static int PrpHdr_get_f(ST_PrpHdr pPrpHdr, string sFmt, params object[] args) {
			return PrpHdr_get_p(pPrpHdr, string.Format(sFmt, args));
		}
		public static int PrpHdr_get_p(ST_PrpHdr pPrpHdr, string sPath) {
			return PrpTbl_get_p(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, sPath);
		}
		//-----------------------------------------------------------------------------
		public static int PrpHdr_acc_l(ST_PrpHdr pPrpHdr, int iAcc, params int[] aName) {
			return PrpHdr_acc_v(pPrpHdr, iAcc, aName);
		}
		public static int PrpHdr_acc_v(ST_PrpHdr pPrpHdr, int iAcc, IEnumerable<int> aName) {
			return PrpTbl_acc_v(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, iAcc, aName);
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static int PrpHdr_acc_f(ST_PrpHdr pPrpHdr, int iAcc, string sFmt, params object[] args) {
			return PrpHdr_acc_p(pPrpHdr, iAcc, string.Format(sFmt, args));
		}
		public static int PrpHdr_acc_p(ST_PrpHdr pPrpHdr, int iAcc, string sPath) {
			return PrpTbl_acc_p(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, iAcc, sPath);
		}
		//-----------------------------------------------------------------------------
		public static ST_PrpInf PrpHdr_inf_l(ST_PrpHdr pPrpHdr, params int[] aName) {
			return PrpHdr_inf_v(pPrpHdr, aName);
		}
		public static ST_PrpInf PrpHdr_inf_v(ST_PrpHdr pPrpHdr, IEnumerable<int> aName) {
			return PrpTbl_inf_v(pPrpHdr.pPrpKey, pPrpHdr.iTbl, aName);
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static ST_PrpInf PrpHdr_inf_f(ST_PrpHdr pPrpHdr, string sFmt, params object[] args) {
			return PrpHdr_inf_p(pPrpHdr, string.Format(sFmt, args));
		}
		public static ST_PrpInf PrpHdr_inf_p(ST_PrpHdr pPrpHdr, string sPath) {
			return PrpTbl_inf_p(pPrpHdr.pPrpKey, pPrpHdr.iTbl, sPath);
		}
		//-----------------------------------------------------------------------------
		public static string PrpHdr_fmt_l(ST_PrpHdr pPrpHdr, Func<int/*iFmt*/,int/*iVal*/,string> fnVarFmt/*null可*/, params int[] aName) {
			return PrpHdr_fmt_v(pPrpHdr, fnVarFmt, aName);
		}
		public static string PrpHdr_fmt_v(ST_PrpHdr pPrpHdr, Func<int/*iFmt*/,int/*iVal*/,string> fnVarFmt/*null可*/, IEnumerable<int> aName) {
			return PrpTbl_fmt_v(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, fnVarFmt, aName);
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static string PrpHdr_fmt_f(ST_PrpHdr pPrpHdr, Func<int/*iFmt*/,int/*iVal*/,string> fnVarFmt/*null可*/, string sFmt, params object[] args) {
			return PrpHdr_fmt_p(pPrpHdr, fnVarFmt, string.Format(sFmt, args));
		}
		public static string PrpHdr_fmt_p(ST_PrpHdr pPrpHdr, Func<int/*iFmt*/,int/*iVal*/,string> fnVarFmt/*null可*/, string sPath) {
			return PrpTbl_fmt_p(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, fnVarFmt, sPath);
		}
		//-----------------------------------------------------------------------------
		public static void PrpHdr_fset_l(ST_PrpHdr pPrpHdr, double dNewVal, params int[] aName) {
			PrpHdr_fset_v(pPrpHdr, dNewVal, aName);
		}
		public static void PrpHdr_fset_v(ST_PrpHdr pPrpHdr, double dNewVal, IEnumerable<int> aName) {
			PrpTbl_fset_v(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, dNewVal, aName);
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static void PrpHdr_fset_f(ST_PrpHdr pPrpHdr, double dNewVal, string sFmt, params object[] args) {
			PrpHdr_fset_p(pPrpHdr, dNewVal, string.Format(sFmt, args));
		}
		public static void PrpHdr_fset_p(ST_PrpHdr pPrpHdr, double dNewVal, string sPath) {
			PrpTbl_fset_p(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, dNewVal, sPath);
		}
		//-----------------------------------------------------------------------------
		public static double PrpHdr_fget_l(ST_PrpHdr pPrpHdr, params int[] aName) {
			return PrpHdr_fget_v(pPrpHdr, aName);
		}
		public static double PrpHdr_fget_v(ST_PrpHdr pPrpHdr, IEnumerable<int> aName) {
			return PrpTbl_fget_v(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, aName);
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static double PrpHdr_fget_f(ST_PrpHdr pPrpHdr, string sFmt, params object[] args) {
			return PrpHdr_fget_p(pPrpHdr, string.Format(sFmt, args));
		}
		public static double PrpHdr_fget_p(ST_PrpHdr pPrpHdr, string sPath) {
			return PrpTbl_fget_p(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, sPath);
		}
		//-----------------------------------------------------------------------------
		public static string PrpHdr_ffmt_l(ST_PrpHdr pPrpHdr, params int[] aName) {
			return PrpHdr_ffmt_v(pPrpHdr, aName);
		}
		public static string PrpHdr_ffmt_v(ST_PrpHdr pPrpHdr, IEnumerable<int> aName) {
			return PrpTbl_ffmt_v(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, aName);
		}
		//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		public static string PrpHdr_ffmt_f(ST_PrpHdr pPrpHdr, string sFmt, params object[] args) {
			return PrpHdr_ffmt_p(pPrpHdr, string.Format(sFmt, args));
		}
		public static string PrpHdr_ffmt_p(ST_PrpHdr pPrpHdr, string sPath) {
			return PrpTbl_ffmt_p(pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, sPath);
		}
		//-----------------------------------------------------------------------------
		public static IEnumerable<int> PrpHdr_path_f(ST_PrpHdr pPrpHdr, string sFmt, params object[] args) {
			return PrpHdr_path_p(pPrpHdr, string.Format(sFmt, args));
		}
		public static IEnumerable<int> PrpHdr_path_p(ST_PrpHdr pPrpHdr, string sPath) {
			return PrpTbl_path_p(pPrpHdr.pPrpKey, pPrpHdr.iTbl, sPath);
		}
		//-----------------------------------------------------------------------------
		public static bool PrpHdr_list(ST_PrpHdr pPrpHdr, Func<int/*iType*/,IEnumerable<int>/*aName*/,string/*sPath*/,object/*arg*/,bool> callback, out IEnumerable<int> aName, out string sPath, object arg) {
			return PrpTbl_list(pPrpHdr.pPrpKey, pPrpHdr.iTbl, callback, out aName, out sPath, arg);
		}
		//-----------------------------------------------------------------------------
		public static void PrpHdr_dump(TextWriter fp, ST_PrpHdr pPrpHdr, Func<int/*iFmt*/,int/*iVal*/,string> fnVarFmt/*null可*/, int fOpt/*(PrpDmp_*の0個以上の組み合わせ)*/) {
			PrpTbl_dump(fp, pPrpHdr.pPrpKey, pPrpHdr.iTbl, pPrpHdr.pPrpTbl, 0, fnVarFmt, fOpt);
		}
	}
}
