      1 ﻿
      2 /**
      3  * @name	CeL function for Windows registry
      4  * @fileoverview
      5  * 本檔案包含了 Windows registry 的 functions。
      6  * @since
      7  */
      8
      9 if (typeof CeL === 'function'){
     10
     11 /**
     12  * 本 module 之 name(id)，<span style="text-decoration:line-through;">不設定時會從呼叫時之 path 取得</span>。
     13  * @type	String
     14  * @constant
     15  * @inner
     16  * @ignore
     17  */
     18 var module_name = 'OS.Windows.registry';
     19
     20 //===================================================
     21 /**
     22  * 若欲 include 整個 module 時，需囊括之 code。
     23  * @type	Function
     24  * @param	{Function} library_namespace	namespace of library
     25  * @param	load_arguments	呼叫時之 argument(s)
     26  * @return
     27  * @name	CeL.OS.Windows.registry
     28  * @constant
     29  * @inner
     30  * @ignore
     31  */
     32 var code_for_including = function(library_namespace, load_arguments) {
     33
     34 //	requires
     35 if (eval(library_namespace.use_function(
     36 		'code.compatibility.is_DOM')))
     37 	return;
     38
     39
     40 /**
     41  * null module constructor
     42  * @class	Windows registry 的 functions
     43  */
     44 CeL.OS.Windows.registry
     45 = function() {
     46 	//	null module constructor
     47 };
     48
     49 /**
     50  * for JSDT: 有 prototype 才會將之當作 Class
     51  */
     52 CeL.OS.Windows.registry
     53 .prototype = {
     54 };
     55
     56
     57
     58
     59
     60
     61
     62
     63 /*	http://msdn2.microsoft.com/en-us/library/x05fawxd.aspx
     64 	作Registry的操作
     65 	WSH_registry.Base	設定工作的基準，這應該是個目錄，將會附加在每個key前面
     66
     67 	WSH_registry(key)	WshShell.RegRead()
     68 *undo*				key假如輸入object，會將之一一分開處理，此時WSH_registry.Err會包含所有發生的錯誤，WSH_registry.Err[0]=發生錯誤的數量
     69 *undo*	WSH_registry(key,0,'info')	完整資訊（包括type）
     70 *undo*	WSH_registry(keyDir,keyPattern,'dir')	傳回整個dir的資料。dir的預設值/標準の値：['']
     71 	WSH_registry(key,value[,type])	WshShell.RegWrite()
     72 	WSH_registry(key,value),WSH_registry(key,value,'auto')	auto detect type
     73 	WSH_registry(key,value,1)	WshShell.RegWrite(key,value)
     74 	WSH_registry(key,0,'del')	WshShell.RegDelete()
     75
     76 TODO:
     77 backup all
     78 search
     79
     80 test:
     81 if(0){
     82  var k="HKCU\\Software\\Colorless echo\\Comparer\\test\\test",r=WSH_registry(k,1),p=function(){if(WSH_registry.Err)alert(WSH_registry.Err.message);else alert('('+typeof r+')'+k+'\n'+r);};
     83  p();
     84  WSH_registry(k,0,'del');
     85  r=WSH_registry(k);
     86  p();
     87  r=WSH_registry(k="HKCU\\Software\\Colorless echo\\Comparer\\");
     88  p();
     89 }
     90
     91 */
     92 WSH_registry.Err=WSH_registry.Base=0;
     93 function WSH_registry(key,value,type){
     94  WSH_registry.Err=null;
     95  if(WSH_registry.Base){if(WSH_registry.Base.slice(-1)!='\\')WSH_registry.Base+='\\';key=WSH_registry.Base+key;}
     96  if(!key)return;
     97  //if(typeof WshShell!='object')WshShell=new ActiveXObject("WScript.Shell");
     98  if(typeof key=='object'){var i,c=0;for(i in key)c+=WSH_registry(i,key[i],type) instanceof Error?0:1;return c;}
     99  try{
    100   var _f=WSH_registry.F;
    101   //if(typeof type=='string')type=_f[type];
    102   if(type=='del')WshShell.RegDelete(key);
    103   else if(typeof value!='undefined'){
    104    if(typeof type=='undefined'||type=='auto')	//	自動判別
    105     type=typeof value=='number'&&!value%1?'REG_DWORD'	//	DWORD:4bytes,REG_BINARY
    106     :typeof value=='string'&&value.indexOf('\n')==-1?value.indexOf('%')==-1?'REG_SZ':'REG_EXPAND_SZ'	//	REG_EXPAND_SZ:"%windir%\\calc.exe"等
    107     :0;	//	unknown:multi_sz/none/dword_big_endian/link/resource_list	http://www.cotse.com/dlf/man/TclCmd/registry.htm,http://cmpp.linuxforum.net/cman/mann/registry.htm
    108    //if(isNaN(type))WshShell.RegWrite(key,value);else WshShell.RegWrite(key,value,WSH_registry.T[type]);
    109    if(typeof type=='string')WshShell.RegWrite(key,value,type);else WshShell.RegWrite(key,value);
    110   }
    111   value=WshShell.RegRead(key);	//	寫入後再讀取，傳回真正寫入的值
    112   //alert('('+typeof value+')'+key+'\n'+value);
    113  }catch(e){
    114   //	http://klcintw4.blogspot.com/2007/09/javascriptie.html
    115   if(e.description.indexOf("伺服程式無法產生物件")!=-1)
    116    alert("請調整IE瀏覽器的安全性\n網際網路選項→安全性→自訂層級\n「起始不標示為安全的ActiveX控制項」設定為啟用或提示。");
    117   WSH_registry.Err=e;return;
    118  }
    119  return value;
    120 }
    121
    122
    123 /*
    124 	registry 登錄值/登錄項目操作
    125
    126 bug:
    127 registry_function.checkAccess('HKLM') always return false. this is OK: registry_function.checkAccess('HKLM\\SOFTWARE\\')
    128
    129 TODO:
    130 Win32_SecurityDescriptor
    131 .moveKey(from,to)
    132 .moveValue(from,to)
    133 用.apply()實作prototype之function，不另外寫。
    134 */
    135 //registry_function[generateCode.dLK]='VBA,JSArrayToSafeArray';
    136 function registry_function(path,sComputer,flag){	//	key path, ComputerName, create?
    137 /*
    138  if(!registry_function.prototype.oReg){	//	不能用 this.prototype.~
    139   var oReg=getWMIData('default:SWbemLocator');//try{oReg=new Enumerator(GetObject("winmgmts:{impersonationLevel=impersonate}//"+(sComputer||'.')+"/root/default:StdRegProv"));}catch(e){}
    140   if(!oReg)try{
    141    //	http://msdn2.microsoft.com/en-us/library/aa393774.aspx
    142    var oLoc=new ActiveXObject("WbemScripting.SWbemLocator")
    143 	,oSvc=oLoc.ConnectServer(sComputer||null,"root/default");
    144    oReg=oSvc.Get("StdRegProv");
    145   }catch(e){return;}
    146   registry_function.prototype.oReg=oReg;
    147  }
    148 */
    149 /*
    150  try{
    151   this.oReg=new ActiveXObject("WbemScripting.SWbemLocator").ConnectServer(sComputer||null,"root/default").Get("StdRegProv");
    152  }catch(e){return;}	//	User-defined function to format error codes.
    153 */
    154  // with(this)base:'',subkey:{},value:{},type:{},flag:0
    155  this.setPath(path,sComputer);
    156  return this;
    157 }
    158
    159
    160 //	下面是公私共用 function
    161 /*
    162 http://www.supinfo-projects.com/en/2004/api_basederegistre__vb_en/2/
    163 http://www.microsoft.com/taiwan/msclub/4P/topic_0402-3.aspx
    164 REG_BINARY 二進位制資料。登錄檔編輯器會以十六進位的記數法來顯示二進位制的資料，而你必須用十六進位制的記數法 來輸入二進位的資料。舉個例子來說，如REG_BINARY值為0x02 0xFE 0xA9 0x38 0x92 0x38 0xAB 0xD9。
    165 REG_DWORD 雙字組值(32-bits)。很多REG_DWORD內容值都使用像是布林值(0 或1、true或false、yes或者是no)。你也可以看到時間值以百萬秒(millisecond)的方式被放在REG_DWORD當中(1000 即1秒)。32-bit未指定的範圍可以從0到4,294,967,295，並且32-bit指定數值範圍可以從-2,147,483,648到 2,147,483,647。你可以使用十進位制或者是十六進位制的方法來編輯這些數值。如REG_DWORD值可表示為0xFE020001及 0x10010001。
    166 REG_DWORD_BIG_ENDIAN 雙字組(Double-word)值以最顯著的方式被存放在記憶體當中。這些位元的順多與REG_DWORD的順序相反。舉個例子來說，數值 0x01020304被以0x01 0x02 0x03 0x04的型態放置在記憶體當中，你並不會在Intel-based 的架構中看到諸如此類的架構。
    167 REG_DWORD_LITTLE_ENDIAN 雙字組值至少有顯者的位元組被儲存在記憶體當中，這個型態跟REG_DWORD是相同的，並且因為Intel-based的架構是以這種格式來儲存數值 的，在Windows XP當中，它是最普遍的數值。舉例來說，0x01020304以0x04 0x03 0x02 0x01的內容被存放在記憶體當中，登錄檔編輯器並不提供用來建立REG_DWORD_LITTLE_ENDIAN 值的能力，因為這個數值資料型態對於REG_DWORD在登錄檔當中的角色而言是相同的。
    168 REG_EXPAND_SZ 變數長度的文字資料。以這種資料型態放置的資料可以是變數、及在使用它們之前，用來延伸這些變數的數值的程式。舉個例子來說，REG_EXPAND_SZ 值包含了%USERPROFILE%\Favorites在程式使用它之前，可能被延伸為C:\Documents and Settings\Jerry\Favorites 。這些登錄器API (Application Programming Interface)會依照所呼叫的程式來延伸環境變數REG_EXPAND_SZ字串，所以它在程式沒有擴充他們的時候，是沒有作用的。您可以看看第十章「引用使用者資訊檔」，以學習更多此類內容值的型態，以修正一些有趣的問題。
    169 REG_FULL_RESOURCE_DESCRIPTOR 資源列表會將裝置及裝置的驅動程式列示出來。這也就資料型態對於PNP裝置來講很重要的原因。登錄檔編輯器並不提供任何方去來製作這種型態的內容值，但是 它允許你顯示它們。你可以查看HKLM\HARDWARE\DESCRIPTION\Description做為這類資料型態的範例。
    170 REG_LINK 它是一個連接，而您無法建立REG_LINK值。
    171 REG_MULTI_SZ 包含一個字串列表的二進位值。登錄檔編輯器會在每一行中顯示一個字串，並且允許你編輯這些列表。在 這些登錄檔當中，一個空的字元(0x00)被每個字串分隔開來，並且兩個空的字串被放置在此列表的結尾。
    172 REG_NONE 擁有並未定義的數值。 Consists of hex data.
    173 REG_QWORD Quadruple-word值(64-bits)。此一型態的資料與REG_DWORD型態相似，但是它包含了 64 bits而不是32 bit。而支援此一型態的作業系統只有Windows XP 64-Bit Edition。你可以使用十進位或者是十六進位的記數方法來查看及編輯此類的登錄值。 0xFE02000110010001為REG_QWORD的一個例子。
    174 REG_QWORD_BIG_ENDIAN Quadruple-word值會將最顯著的位元組第一個儲存在記憶體當中。而此位元組的順序則與REG_QWORD儲存這些值的順序相反。你可以查看 REG_DWORD_BIG_ENDIAN得到更多資訊。
    175 REG_QWORD_LITTLE_ENDIAN 至少有Quadruple-word值儲存在記憶體當中。這種型態與REG_QWORD相同。您可以查看REG_DWORD_LITTLE_ENDIAN 取得更多的資訊。登錄檔編輯器並不提供製作REG_QWORD_LITTLE_ENDIAN 內容的能力，因為這個值的型態對於登錄檔中的REG_QWORD而言是唯一的。
    176 REG_RESOURCE_LIST 是REG_FULL_RESOURCE_DESCRIPTION 內容值的列表。登錄檔編輯器允許你查看，但不允許你編輯這種型態的資料。
    177 REG_RESOURCE_REQUIREMENTS_LIST 列示了裝置所需資源的列表。登錄檔編輯器允許你查看，但並不允許你編輯此種型態的值。
    178 REG_SZ 固定長度的文字 REG_DWORD、REG_SZ值為在登錄檔當中最普遍的資料型態。而REG_SZ值的範例為 Microsoft Windows XP或Jerry Honeycutt。每個字串都是以一個鑋值字元為結尾。程式並在REG_SZ值當中並沒有擴充環境變數。
    179 */
    180 /* private */registry_function.typeName='REG_NONE,REG_SZ,REG_EXPAND_SZ,REG_BINARY,REG_DWORD,REG_DWORD_BIG_ENDIAN,REG_LINK,REG_MULTI_SZ,REG_RESOURCE_LIST,REG_FULL_RESOURCE_DESCRIPTOR,REG_RESOURCE_REQUIREMENTS_LIST,REG_QWORD,REG_QWORD_LITTLE_ENDIAN=11'.split(',');
    181 //	將 TypeValue 轉成 TypeName
    182 registry_function.getTypeName = registry_function.prototype.getTypeName = function(
    183 		/* int */type) {
    184 	return registry_function.typeName[type];
    185 };
    186 //	將 TypeName 轉成 TypeValue
    187 registry_function.getTypeValue = registry_function.prototype.getTypeValue = function(
    188 		/* string */type) {
    189 	if (!registry_function.typeValue) {
    190 		var i, t = registry_function.typeValue = {}, n = registry_function.typeName;
    191 		for (i in n)
    192 			t[n[i]] = i;
    193 	}
    194 	return registry_function.typeValue[type];
    195 };
    196
    197
    198
    199 /*	將 HKEY_CURRENT_USER 等表示法與數字代號互轉
    200 	http://msdn2.microsoft.com/en-us/library/aa393664.aspx
    201 	http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/tags/v1_8_5_19/ext/Win32API/lib/win32/registry.rb?view=markup&pathrev=11732
    202 	http://www.51log.net/dev/304/4539587.htm
    203 */
    204 registry_function.getRegCode=registry_function.prototype.getRegCode=function(/*string */name){
    205  if(!registry_function.RegCode){
    206   var i,r=registry_function.RegCode={
    207 	HKCR:0,HKEY_CLASSES_ROOT:0
    208 	,HKCU:1,HKEY_CURRENT_USER:1
    209 	,HKLM:2,HKEY_LOCAL_MACHINE:2
    210 	,HKUS:3,HKU:3,HKEY_USERS:3
    211 	//,HKEY_PERFORMANCE_DATA:4
    212 	,HKCC:5,HKEY_CURRENT_CONFIG:5
    213 	,HKEY_DYN_DATA:6
    214 	//,HKEY_PERFORMANCE_TEXT:0x50
    215 	//,HKEY_PERFORMANCE_NLSTEXT:0x60
    216   };
    217   for(var i in r)if(!isNaN(r[i])){
    218    r[i]+=0x80000000;//&
    219    if(i.indexOf('_')!=-1)r[r[i]]=i;	//	reverse
    220   }
    221  }
    222  //alert(name+'\n'+registry_function.RegCode[name]);
    223  return registry_function.RegCode[name];
    224 };
    225
    226
    227 //	分開base與path，並作檢查。
    228 registry_function.separatePath=function(path,sComputer,isValue){
    229  if(typeof path=='object')return path;	//	處理過的
    230 /*
    231  if(isNaN(base)&&isNaN(base=this.getRegCode(base))&&typeof path=='string'&&(path=path.match(/^([A-Z_]+)\\(.+)$/)))
    232   base=this.getRegCode(path[1]),path=path[2];
    233 */
    234  var base,v;	//	base, ValueName (or tmp)
    235  if(typeof path=='string' && (v=path.match(/^([A-Z_]+)(\\(.*))?$/)))
    236   base=this.getRegCode(v[1]),path=v[3]/*||'\\'*/;
    237
    238  if(!base/*||isNaN(base)*/)return;
    239  //alert('registry_function.separatePath:\n'+base+'	'+path);
    240  if(typeof path!='string' || !path&&path!=='')return;
    241
    242  v=0;
    243  //	判別輸入
    244  if(!/[\\]$/.test(path))
    245   if(!isValue&&this.checkAccess([base,path],1/* KEY_QUERY_VALUE */,sComputer))
    246    //	輸入 SubkeyName
    247    path+='\\',v='';
    248   //	輸入 ValueName
    249   else if(v=path.match(/^(.+\\)([^\\]+)$/))path=v[1],v=v[2];
    250   //	輸入 root 之 ValueName，如 HKEY_CURRENT_USER\value
    251   else v=path,path='';
    252
    253  if(path[1]=='\\')path[1]='';
    254  //alert('registry_function.separatePath:\n'+base+'\n'+path+'\n'+v);
    255  return typeof v=='string'?[base,path,v]:[base,path];	//	考慮用{base:,key:,value:}
    256 };
    257 // private
    258 registry_function.prototype.separatePath=function(name,base){
    259  //return this instanceof registry_function?[this.base,this.path+path]:registry_function.separatePath(path);
    260  return typeof name=='string'?name.indexOf('\\')==-1?[this.base,this.path,name]:registry_function.separatePath(this.getPath()+name,this.computer):[this.base,this.path];
    261 };
    262
    263
    264 /*	主要的 WMI 執行 interface
    265 	http://msdn2.microsoft.com/En-US/library/aa394616.aspx
    266 In scripting or Visual Basic, the method returns an integer value that is 0 (zero) if successful. If the function fails, the return value is a nonzero error code that you can look up in WbemErrorEnum.
    267 */
    268 registry_function.oRegA = {};
    269 registry_function.runMethod=registry_function.prototype.runMethod=function(name,inPO,sComputer/*,flag*/){	//	inPO: input parameters object
    270  var oReg=this.oReg||registry_function.oRegA[sComputer||'.'];
    271  if(!oReg)try{
    272   oReg=this.oReg=registry_function.oRegA[sComputer||'.']
    273 	=new ActiveXObject('WbemScripting.SWbemLocator')
    274 	.ConnectServer(sComputer||null,'root/default')
    275 	.Get('StdRegProv');
    276  }catch(e){
    277   //popErr(e);
    278   return;
    279  }
    280
    281  try{
    282   var i,oMethod=oReg.Methods_.Item(name)	//	若無此方法會 throw error!
    283 	,oInParam=oMethod.InParameters.SpawnInstance_();
    284   //if(name=='SetMultiStringValue')for(i in inPO){try{oInParam[i]=inPO[i];}catch(e){popErr(e,0,'registry_function.runMethod: '+name+' error:\nset ['+i+'] to ['+inPO[i]+']');}if(name=='CheckAccess')alert(name+': oInParam['+i+']='+inPO[i]);}
    285   for(i in inPO)oInParam[i]=inPO[i];	//	若無此property會 throw error!
    286   return oReg.ExecMethod_(oMethod.Name,oInParam);//oOutParam
    287  }catch(e){
    288   popErr(e);
    289   return e;
    290  }
    291 };
    292
    293
    294 /*	The CheckAccess method verifies that the user has the specified permissions.
    295 	http://msdn2.microsoft.com/en-us/library/aa384911.aspx
    296 	http://msdn2.microsoft.com/en-us/library/ms724878.aspx
    297
    298 制定一個訪問標記以描述訪問新鍵的安全性
    299     此參數可以是下列值的一個聯合
    300     KEY_ALL_ACCESS
    301     KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_SUB_KEY, KEY_CREATE_LINK, 和 KEY_SET_VALUE 訪問的聯合.
    302     KEY_CREATE_LINK
    303     允許創建嚴格符號的鏈接.
    304     KEY_CREATE_SUB_KEY
    305     允許創建子鍵.
    306     KEY_ENUMERATE_SUB_KEYS
    307     允許枚舉子鍵.
    308     KEY_EXECUTE
    309     允許讀訪問.
    310     KEY_NOTIFY
    311     允許改變通知.
    312     KEY_QUERY_VALUE
    313     允許查詢子鍵的數據.
    314     KEY_READ
    315     KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, 和 KEY_NOTIFY 訪問的聯合.
    316     KEY_SET_VALUE
    317     允許設置子鍵的數據.
    318     KEY_WRITE
    319     KEY_SET_VALUE 和 KEY_CREATE_SUB_KEY 訪問的聯合
    320
    321 KEY_ALL_ACCESS (0xF003F)	Combines the STANDARD_RIGHTS_REQUIRED, KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, and KEY_CREATE_LINK access rights. (&& READ_CONTROL?)
    322 KEY_CREATE_LINK (0x0020)	Reserved for system use.
    323 KEY_CREATE_SUB_KEY (0x0004)	Required to create a subkey of a registry key.
    324 KEY_ENUMERATE_SUB_KEYS (0x0008)	Required to enumerate the subkeys of a registry key.
    325 KEY_EXECUTE (0x20019)	Equivalent to KEY_READ.
    326 KEY_NOTIFY (0x0010)	Required to request change notifications for a registry key or for subkeys of a registry key.
    327 KEY_QUERY_VALUE (0x0001)	Required to query the values of a registry key.
    328 KEY_READ (0x20019)	Combines the STANDARD_RIGHTS_READ, KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY values.
    329 KEY_SET_VALUE (0x0002)	Required to create, delete, or set a registry value.
    330 KEY_WOW64_32KEY (0x0200)	Indicates that an application on 64-bit Windows should operate on the 32-bit registry view. For more information, see Accessing an Alternate Registry View.
    331 	This flag must be combined using the OR operator with the other flags in this table that either query or access registry values.
    332 	Windows 2000:  This flag is not supported.
    333 KEY_WOW64_64KEY (0x0100)	Indicates that an application on 64-bit Windows should operate on the 64-bit registry view. For more information, see Accessing an Alternate Registry View.
    334 	This flag must be combined using the OR operator with the other flags in this table that either query or access registry values.
    335 	Windows 2000:  This flag is not supported.
    336 KEY_WRITE (0x20006)	Combines the STANDARD_RIGHTS_WRITE, KEY_SET_VALUE, and KEY_CREATE_SUB_KEY access rights.
    337
    338 http://www.supinfo-projects.com/en/2004/api_basederegistre__vb_en/2/
    339 */
    340 registry_function.accessFlag = {
    341 		KEY_QUERY_VALUE : 1,
    342 		KEY_SET_VALUE : 2,
    343 		KEY_CREATE_SUB_KEY : 4,
    344 		KEY_ENUMERATE_SUB_KEYS : 8,
    345 		KEY_NOTIFY : 0x10,
    346 		KEY_CREATE_LINK : 0x20,
    347 		// KEY_WOW64_32KEY:0x0200,
    348 		// KEY_WOW64_64KEY:0x0100,
    349 		DELETE : 0x10000,
    350 		READ_CONTROL : 0x20000,
    351 		STANDARD_RIGHTS_EXECUTE : 0x20000,
    352 		STANDARD_RIGHTS_READ : 0x20000,
    353 		STANDARD_RIGHTS_WRITE : 0x20000,
    354 		KEY_WRITE : 0x20006,
    355 		KEY_READ : 0x20019,
    356 		KEY_EXECUTE : 0x20019,
    357 		// WRITE_DAC:0x40000,
    358 		// WRITE_OWNER:0x80000,
    359 		// STANDARD_RIGHTS_REQUIRED:0xF0000,
    360 		KEY_ALL_ACCESS : 0xF003F
    361 		// ,SYNCHRONIZE:0x100000,
    362 		// STANDARD_RIGHTS_ALL:0x1F0000
    363 };
    364 //	check access of key base+path
    365 registry_function.checkAccess=registry_function.prototype.checkAccess=function(path,uRequired,sComputer){
    366  if(path=this.separatePath(path,sComputer)){
    367   if(typeof uRequired=='string')uRequired=registry_function.accessFlag[uRequired];
    368   //alert('registry_function check:\n'+this.getRegCode(path[0])+'\\'+path[1]+'\n'+this.runMethod('CheckAccess',{hDefKey:path[0],sSubKeyName:path[1],uRequired:uRequired||3/*KEY_QUERY_VALUE+KEY_SET_VALUE*/},sComputer).bGranted);
    369   try{return this.runMethod('CheckAccess',{hDefKey:path[0],sSubKeyName:path[1],uRequired:uRequired||3/*KEY_QUERY_VALUE+KEY_SET_VALUE*/},sComputer).bGranted;}	//	有可能不存在 .bGranted !
    370   catch(e){return;}
    371  }
    372 };
    373
    374
    375 //	一次性功能，不通過創建object
    376 /*	ӥ۞某 path: Subkey(機碼) 之 {ValueName:(int)ValueType} 資訊。無 Value 會 return undefined
    377 registry_function.getValue('HKEY_CLASSES_ROOT\\.odp')	傳ީ設值
    378 registry_function.getValue('HKEY_CLASSES_ROOT\\.odp\\')	傳回整個目錄值
    379 */
    380 registry_function.getValueType=function(path,sComputer,flag){
    381  if(!(path=this.separatePath(path,sComputer)))return;
    382
    383  //	http://msdn2.microsoft.com/en-us/library/aa390388.aspx
    384  var oOutParam=this.runMethod('EnumValues',{hDefKey:path[0],sSubKeyName:path[1]},sComputer),aNames,aTypes,i=0,r={'':1/* 取得預設值: REG_SZ */};
    385  if(!oOutParam || oOutParam.sNames==null)return;	//	error 大概都是 ==null，可能因為輸入value而非key值
    386  aNames=oOutParam.sNames.toArray(),aTypes=oOutParam.Types.toArray();
    387  //aNames.push(''),aTypes.push(1);	//	預設值
    388  if(flag==1)return [aNames,aTypes];
    389  for(;i<aNames.length;i++)
    390   //WScript.Echo('('+sRegTypes[aTypes[i]]+') '+aNames[i]);
    391   r[aNames[i]]=aTypes[i];//,this.value[aNames[i]]=getValue(aNames[i],aTypes[i]);
    392
    393  return flag==2?[aNames,r]:typeof path[2]=='string'?r[path[2]]:r;
    394 };
    395 //	傳回某 Value(數值) 之 (int)type 或 {ValueName:(int)ValueType}
    396 registry_function.prototype.getValueType=function(name,force){
    397  if(force||!this.type||!this.type[name]){	//	可能有更新
    398   var t=registry_function.getValueType(this.separatePath(),this.computer,2)||[];
    399   this.type=(this.valueA=t[0]||[]).length?t[1]:{};
    400  }
    401  //alert('registry_function.prototype.getValueType:\n'+name+'	'+this.type[name]);
    402  if(this.type)return typeof name=='string'?this.type[name]:this.type;	//	應先copy
    403 };
    404 registry_function.prototype.getValueA = function(force) {
    405 	if (force || !this.valueA)
    406 		this.getValueType(0, 1);
    407 	return this.valueA;
    408 };
    409
    410
    411 /*	一次性功能，不通過創建object
    412 	讀取 Subkey(機碼) 之名稱資訊。無 Subkey 會 return undefined
    413
    414 TODO:
    415 return registry_function object
    416 */
    417 registry_function.getSubkeyName=function(path,sComputer,flag){
    418  if(!(path=this.separatePath(path,sComputer)))return;
    419  //alert('registry_function.getSubkeyName:\npath: '+path);
    420
    421  //	http://msdn2.microsoft.com/en-us/library/aa390387.aspx
    422  var i=0,r={},aNames=this.runMethod('EnumKey',{hDefKey:path[0],sSubKeyName:path[1]=='\\'?'':path[1]},sComputer).sNames;
    423  if(aNames!=null){	//	error 大概都是 ==null，可能因為: 1.無Subkey 2.輸入value而非key值
    424   if(flag==1)return aNames;
    425   for(aNames=aNames.toArray();i<aNames.length;i++)
    426    r[aNames[i]]={};//registry_function(r.base+aNames[i]+'\\')
    427   //alert('registry_function.getSubkeyName: '+aNames.length);
    428   return flag==2?[aNames,r]:path[2]?path[2] in r:r;
    429  }
    430 };
    431 registry_function.prototype.getSubkeyName = function(force, flag) {
    432 	if (force || !this.subkey) {
    433 		var t = registry_function.getSubkeyName(this.separatePath(),
    434 				this.computer, 2)
    435 				|| [];
    436 		this.subkey = (this.subkeyA = t[0] || []).length ? t[1] : {};
    437 	}
    438 	return flag ? this.subkeyA : this.subkey;
    439 };
    440
    441
    442 /*	設定 object 之初始 path。
    443 oRegistryF.subkey
    444 oRegistryF.type
    445 oRegistryF.value
    446 */
    447 registry_function.prototype.setPath=function(path,sComputer){	//	base key path
    448  if(!(path=registry_function.separatePath(path,sComputer)))return;	//	因為是初次設定，所以這裡不能用 this.separatePath()
    449
    450  this.base=path[0],this.path=path[1],this.computer=sComputer;
    451  if(!/[\\]$/.test(this.path))this.path+='\\';	//	確保this.path是key值
    452
    453  //this.subkey={},this.type={},this.value={};	//	預防 no access permission 之後卻還被呼叫
    454  if(this.checkAccess(0,0,sComputer))
    455 	this.value={}
    456 	,this.type=this.getValueType()
    457 	,this.subkey=this.getSubkeyName(1)
    458 	;
    459  //	else: no access permission or doesn't exist.
    460  return path;
    461 };
    462
    463 //	傳回 object 之初始 path。
    464 registry_function.prototype.getPath = function() {
    465 	return this.getRegCode(this.base) + '\\' + this.path;
    466 };
    467
    468
    469 registry_function.prototype.reset = function() {
    470 	//	預防 no access permission 之後卻還被呼叫
    471 	this.subkey = {}, this.type = {}, this.value = {};
    472 	this.setPath(this.separatePath(), this.computer);
    473 };
    474
    475 //	尚未完善!
    476 registry_function.isExist=function(path,sComputer,flag){
    477  path=this.separatePath(path,sComputer);
    478  if(!path)return;
    479
    480  var _t=this.getSubkeyName([path[0],path[1].replace(/[^\\]+\\?$/,'')],0,2);
    481  _t= _t && (!path[1]||path[1]=='\\'||_t.length&&_t[1][path[1].replace(/^(.*?)([^\\]+)\\?$/,'$2')]);
    482  return !_t||!path[2]?_t:typeof this.getValueType(path)!='undefined';
    483
    484  //if(this.checkAccess(path,1/* KEY_QUERY_VALUE */,sComputer))return true;
    485  //if(flag)return;	//	不以create的方法test。
    486
    487  //	若可create(並access)，表示不存在（需刪掉建出來的），return false。否則unknown，return undefined。
    488
    489 };
    490 registry_function.prototype.isExist = function(name, flag) {
    491 	return registry_function.isExist(this.separatePath(name),
    492 			this.computer, flag);
    493 };
    494
    495 //	RegMethod	http://www.cqpub.co.jp/hanbai/pdf/18451/18451_wmi.pdf
    496 registry_function.useMethod = ',String,ExpandedString,Binary,DWORD,DWORD,String,MultiString,String,MultiString,String,QWORD'
    497 	.split(',');
    498 registry_function.useValueName = ',s,s,u,u,u,s,s,s,s,s,u'.split(',');
    499 registry_function.useArray = ',,,1,,,,1,,1,,'.split(',');
    500 //	以 type 取得 path 之 Value。預設自動判別 type
    501 registry_function.getValue=function(path,sComputer,/*int || undefined */type){
    502  if(!(path=this.separatePath(path,sComputer)))return;
    503  if(typeof path[2]!='string'){
    504   //	get all
    505   var r={},i;
    506   type=this.getValueType(path,sComputer);
    507   for(i in type)r[path[2]=i]=this.getValue(path,sComputer,type[i]);
    508   return r;
    509  }
    510
    511  var m;	//	method
    512  if(!type&&!(type=this.getValueType(path,sComputer))||!(m=this.useMethod[type]))return;
    513
    514  var oOutParam=this.runMethod('Get'+m+'Value',{hDefKey:path[0],sSubKeyName:path[1],sValueName:path[2]},sComputer);
    515  if(!oOutParam)return;
    516  //if(oOutParam.returnValue)return oOutParam.returnValue;
    517
    518  //	different method return different value name
    519  oOutParam=oOutParam[this.useValueName[type]+'Value'];
    520  //	some methods return VB Array
    521  if(this.useArray[type])oOutParam=VBA(oOutParam);
    522
    523  //if(!oOutParam)return;
    524  if(type==7/*REG_MULTI_SZ*/)oOutParam=oOutParam.toArray();
    525  else if(type==3/*REG_BINARY*/)oOutParam=fromCharCode(oOutParam.toArray());
    526  //alert(oMethod.Name+'\n'+'('+type+')'+name+'\n'+oOutParam);
    527  //if(type==3)alert(typeof oOutParam);
    528  return oOutParam;
    529 };
    530 registry_function.prototype.getValue=function(name,/*int || undefined */type){
    531  var i,v;
    532  if(typeof name=='string'){
    533   if(this.getSubkeyName()[name])
    534    v=registry_function.getValue([this.base,this.path+'\\'+name,''],this.computer,1/* 取得預設值: REG_SZ */);
    535   else{
    536    if(name in this.value)return this.value[name];//if(m=this.value[name])return m;
    537    if(!type)type=this.getValueType(name);	//	bug: 假如在之前已經更新過，可能得到錯誤的 type ！
    538    v=registry_function.getValue(this.separatePath(name),this.computer,type);
    539   }
    540   if(typeof v!='undefined')this.value[name]=v;
    541   return v;
    542  }
    543
    544  if(!this.gotAllValue){
    545   //	get all
    546   for(i in this.type)
    547    //{v=registry_function.getValue(this.separatePath(i),this.computer,this.type[i]);if(typeof v!='undefined')this.value[i]=v;}
    548    this.value[i]=registry_function.getValue(this.separatePath(i),this.computer,this.getValueType(i));
    549   this.gotAllValue=true;
    550  }
    551  return this.value;	//	應先copy
    552 };
    553
    554
    555 /*	僅設定 Value	硬將小數設成REG_DWORD會四捨五入
    556 TODO:
    557 set default value:
    558 setValue('@',object)
    559 */
    560 registry_function.setValue=function(path, value, /*int || undefined */type, sComputer, isValue){
    561  if(!(path=this.separatePath(path,sComputer,isValue)))return 5;
    562
    563  if(typeof value=='undefined')return;	//	want to delete?
    564  if(!type||isNaN(type)&&isNaN(type=this.getTypeValue(type)))	//	自動判別
    565   type=!isNaN(value)?value%1?1/*REG_SZ*/:4/*REG_DWORD*/	//	DWORD:4bytes, or QWORD
    566    :typeof value=='string'?
    567     /^[\x0-\xff]$/.test(value)&&/[\x0\x80-\xff]/.test(value)?3/*REG_BINARY*/
    568 	:value.indexOf('\n')!=-1?7/*REG_MULTI_SZ*/
    569 	:value.indexOf('%')==-1?1/*REG_SZ*/:2/*REG_EXPAND_SZ:"%windir%\\calc.exe"等*/
    570    :typeof value=='object'?3/*REG_BINARY*/:0/*REG_NONE*/;	//	may buggy
    571  var m=this.useMethod[type],o;
    572  //alert('registry_function.setValue:\npath:'+path+'\nvalue:'+(''+value).replace(/\0/g,'\\0')+'\ntype:'+type+'\nm:'+m+'\n\ncreate id:'+this.setValue.cid+'\nexist:'+this.isExist([path[0],path[1]]));
    573  if(!m)return 6;
    574  if( this.setValue.cid && !this.isExist([path[0],path[1]]) )
    575   //alert('registry_function.setValue: add Key:\n'+path[0]+'\n'+path[1]),
    576   this.addKey(path);
    577
    578  o={hDefKey:path[0],sSubKeyName:path[1],sValueName:path[2]};
    579
    580  //	http://msdn.microsoft.com/en-us/library/aa393286(VS.85).aspx
    581  if(type==3/*REG_BINARY*/&&typeof value=='string'){
    582   var i=0,v=value;
    583   for(value=[];i<v.length;i++)value.push(v.charCodeAt(i));//value.push(''+v.charCodeAt(i));
    584  }
    585  //	some methods need VB Array
    586  if(this.useArray[type])value=JSArrayToSafeArray(value);
    587  //	different method has different value name
    588  o[this.useValueName[type]+'Value']=value;
    589
    590  m=this.runMethod('Set'+m+'Value',o,sComputer);
    591  return m instanceof Error?m:m.returnValue;
    592 };
    593 //	Create intermediate directories as required.
    594 //	設為true記得setValue後馬上改回來，否則可能出現自動加subkey的情形。
    595 //registry_function.setValue.cid=0;
    596 registry_function.prototype.setValue = function(name, value, /*int || undefined */type) {
    597 	return registry_function.setValue(this.separatePath(name), value,
    598 			type, this.computer);
    599 };
    600
    601
    602 /*
    603 只能刪除葉結點項，連同該子項下的所有值均被刪除(如果不存在子項，或該項下還有子項則不能刪除則無效果)
    604 */
    605 registry_function.deleteKey=function(path,sComputer,flag){
    606  if(!(path=this.separatePath(path,sComputer))
    607 	||path[2]	//	不接受值
    608 	)return;
    609
    610  flag=flag||0;
    611  if(flag&1){
    612   //	recursive
    613   var i,k=this.getSubkeyName(path,sComputer);
    614   for(i in k)this.deleteKey([path[0],path[1]+k[i]],sComputer,flag-(flag&2)/* 不連上層empty者一起刪除 */);
    615   flag-=1;
    616  }
    617
    618  //	do deleteKey
    619  var r=this.runMethod('DeleteKey',{hDefKey:path[0],sSubKeyName:path[1]},sComputer);
    620  if(!(flag&2))return r instanceof Error?r:r.returnValue;
    621
    622  //	連上層empty者一起刪除
    623  flag-=(flag&1)+(flag&2);
    624  while(!(r instanceof Error) && (r=path[1].match(/^(.+)[^\\]+\\$/,''))){
    625   path[1]=r[1];
    626   if(this.getSubkeyName(path,sComputer)||this.getValueType(path,sComputer))break;
    627   r=this.deleteKey(path,sComputer,flag);
    628  }
    629  return path;
    630 };
    631 registry_function.prototype.deleteKey = function(name, flag) {
    632 	var p = registry_function.deleteKey(this.separatePath(name),
    633 			this.sComputer, flag);
    634 	if (typeof p === 'object' && this.path !== p[1]
    635 			&& this.path.indexOf(p[1]) === 0)
    636 		// 若 p[1] 比較短，表示連本 object 都被刪了。reset
    637 		this.reset();
    638 	return p;
    639 };
    640
    641
    642 //	return 0: success, others: failed
    643 registry_function.deleteValue = function(path, sComputer) {
    644 	if (!(path = this.separatePath(path, sComputer)) || !path[2] // 不接受key
    645 	)
    646 		return;
    647
    648 	var r = this.runMethod('DeleteValue', {
    649 		hDefKey : path[0],
    650 		sSubKeyName : path[1],
    651 		sValueName : path[2]
    652 	}, sComputer);
    653
    654 	return r instanceof Error ? r : r.returnValue;
    655 };
    656 registry_function.prototype.deleteValue = function(name) {
    657 	return registry_function.deleteValue(this.separatePath(name),
    658 			this.computer);
    659 };
    660
    661 //	input key or value, 自動判別
    662 registry_function.deletePath = function(path, sComputer) {
    663 	if (path = this.separatePath(path, sComputer))
    664 		return path[2] ? this.deleteValue(path, sComputer) : this
    665 				.deleteKey(path, sComputer);
    666 };
    667
    668
    669 //	僅設定 Key	add Subkey 創建註冊表項，可以一次創建完整的項子樹(各級不存在也會被創建)
    670 registry_function.addKey = function(path, oValue, flag, sComputer) { // flag:add/overwrite/reset(TODO)
    671 	if (!(path = this.separatePath(path, sComputer)))
    672 		return;
    673
    674 	var i, r = this.runMethod('CreateKey', {
    675 			hDefKey : path[0],
    676 			sSubKeyName : path[1] = path[1]/* +(path[2]||'') */
    677 		}, sComputer).returnValue;
    678
    679 	if (typeof oValue == 'object') {
    680 		r = 0;
    681 		for (i in oValue)
    682 			path[2] = i, r += this.setValue(path, oValue[i], 0,
    683 					sComputer);
    684 	}
    685 	return r;
    686 };
    687 registry_function.prototype.addKey = function(name, oValue, flag) { // flag:add/overwrite/reset(TODO)
    688 	return registry_function.addKey(this.separatePath(name), oValue,
    689 			flag, this.computer);
    690 };
    691
    692
    693 if(0){
    694 	CeL.no_initialization = 1;
    695
    696 	var r = new registry_function('HKCU\\Software\\Colorless echo\\regTest\\test3\\');
    697 	//	alert((r.getValue())['test1']);
    698 	r.setValue('test3', 34452);
    699 	r.setValue('test4', 34452.53);
    700 	r.setValue('test5', {
    701 		ghjk : 'hghj'
    702 	});
    703 	alert(r.getPath() + '\nAccess: ' + r.checkAccess() + '\n\n' + r.getValue('test4'));
    704 	r.deleteValue('test3');
    705 	r.deleteValue('test4');
    706 	r.addKey('test\\test1');
    707 	alert(r.addKey('test1\\test1'));
    708 	r.deleteKey('test\\test1');
    709 	r.deleteKey('test1\\test1');
    710
    711 	/*
    712 	oRegistryF.setValue(name,value,type);
    713 	oRegistryF.getValue();
    714 	oRegistryF.getValue(name);
    715 	oRegistryF.getValueType(name);
    716 	oRegistryF.deleteValue(name);
    717 	oRegistryF.deleteKey(name);
    718 	oRegistryF.addKey(name);
    719 	oRegistryF.addKey(name,oValue,flag:add/overwrite/reset);
    720 	*/
    721 }
    722
    723 //	include library
    724 function _iL() {
    725 	// if(typeof WshShell!='object')WshShell=new ActiveXObject("WScript.Shell");
    726 }
    727 //or: isHTA
    728 _iL.p = library_namespace.env.registry_path_key_name;
    729 _iL.for_include = 'try{var o;try{o=new ActiveXObject("Microsoft.XMLHTTP")}catch(e){o=new XMLHttpRequest()}o.open("GET",(new ActiveXObject("WScript.Shell")).RegRead("'
    730 	//	TODO: 以更精確的方法處理。
    731 	+ _iL.p.replace(/\\/, '\\\\')
    732 	+ '"),false);o.send(null);eval(o.responseText)}catch(e){}';// WScript.Echo(e.message);
    733
    734 //CeL.extend({registry_function:registry_function,_iL:_iL});
    735 CeL.extend({reg:registry_function});
    736
    737
    738 return (
    739 	CeL.OS.Windows.registry
    740 );
    741 };
    742
    743 //===================================================
    744
    745 CeL.setup_module(module_name, code_for_including);
    746
    747 };
    748