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