2017年3月5日日曜日

ファイルロック.htaで後始末用functionに対応

先日までのファイルロック.htaではファイルのロックに成功するまでwsfが待機して、成功したらwsfが終了するだけでhta画面へのフィードバックがありませんでした。

本日のサンプルではコマンドラインのリダイレクトを使ってwsfファイルの終了を検出するようにして、wsfファイルが終了したら後始末用の関数を実行するようにしました。

以下ソース
<html>
<title>lock</title>
<body style="text-align:center;overflow:hidden;padding:0px;margin:0px;">
<input id=inp style="width:100%;text-align:center">
<button id=btnL>load</button>
<button id=btnI>init</button>
<table border=1 style="width:100%;">
<tr><td width=1>A</td><td><input id=inpA style="width:100%"></td></tr>
<tr><td width=1>B</td><td><input id=inpB style="width:100%"></td></tr>
<tr><td width=1>C</td><td><input id=inpC style="width:100%"></td></tr>
</table>
<table id=tbl style="position:absolute;top:0px;left:0px;width:100%;height:100%;background-color:#ccc"><td style="text-align:center">初期化中。。少々お待ちください</td></table>
</body>
<script id=scriptCode共有用>
AXO=function(name){return new ActiveXObject(name)}
shell = AXO('WScript.Shell')
fso=function(){
var fs=AXO('Scripting.FileSystemObject')
return {
AXO:fs,
gsf2:fs.GetSpecialFolder(2), // Z:\TEMP
Read:function(path, swCreate, swUnicode){
if(!fs.FileExists(path)){return}
with(fs.OpenTextFile(path, 1, swCreate, swUnicode)){ var str=AtEndOfStream ? '' : ReadAll(); Close() }
return str
},
Write:function(path,str,swUnicode,sw上書きしない){ with(fs.CreateTextFile(path, !sw上書きしない, swUnicode)){ Write(str); Close() } },
Lock:function(path){
var pathL=path+'.lock', ws, wsn=AXO('WScript.Network')
try{
ws=fs.CreateTextFile(pathL)
ws.Write(wsn.computerName+'\r\n'+wsn.userName)
return {Close:function(){ ws.Close(); fs.DeleteFile(pathL) }}
}
catch(e){
return this.Read(pathL)
}
}
}
}()
</script>
<script>
resizeTo(200,200)
inp.value = fso.gsf2+'\\lockTest.txt'
onbeforeunload=function(){ fso.AXO.FileExists(inp.value) && fso.AXO.DeleteFile(inp.value) }
obj = null
btnL.onclick=function(){
var path=inp.value, o
if(!fso.AXO.FileExists(path)){return alert('ファイルがありません')}
try{ eval('o = '+fso.Read(path)) }
catch(e){ return alert('ファイルが破損しています') }
obj = o
inpA.value = o.A
inpB.value = o.B
inpC.value = o.C
}
btnI.onclick=function(){
tbl.style.display = 'block'
wsf.negoWrite(inp.value, function(path){ fso.Write(path, "{A:'', B:'', C:''}") }, function(){
tbl.style.display = 'none'
btnL.onclick()
})
}
onload=function(){
btnI.onclick()
}
inpA.onchange=inpB.onchange=inpC.onchange=function(){
var m=arguments.callee, 処理待ち=m.処理待ち, chr=this.id.charAt(3), path=inp.value
m.処理待ち = (処理待ち || 0) + 1
wsf.negoWrite(inp.value, (''+function(path){
eval('o = '+fso.Read(path))
o.prop = 'VVV'
fso.Write(path, "{A:'"+o.A.replace(/'/g,"\'")+"', B:'"+o.B.replace(/'/g,"\'")+"', C:'"+o.C.replace(/'/g,"\'")+"'}")
}).replace(/prop/,chr).replace(/VVV/,this.value.replace(/'/g,"\'")),function(){
// この関数の代わりにbtnL.onclickを渡すとA,B,Cの複数項目を立て続けに編集した場合
// 1項目ずつ編集をファイルに適用して、その時点のファイル内容が画面に反映されて、
// 処理待ちの編集内容が見かけ上キャンセルされたようになってしまう。
// 処理待ちの有無によって動作を切り替える。
if(m.処理待ち==1){ return btnL.onclick() }
var o
eval('o = '+fso.Read(path))
document.getElementById('inp'+chr).value = o[chr]
})
}
wsf=function(){
var pathWSF=fso.gsf2+'\\lock.wsf'
fso.Write(pathWSF, ['<-job>',scriptCode共有用.outerHTML,'<-script>','!'+function(){
arg = WScript.Arguments
path = arg(0)
pathF = arg(1)
pathL = path+'.lock'
wsn = AXO('WScript.Network')
eval('f = '+fso.Read(pathF))
while(true){
try{
lock = fso.AXO.CreateTextFile(pathL)
lock.Write(wsn.computerName+'\r\n'+wsn.userName)
break
}
catch(e){ WScript.Sleep(1000 * 10 * Math.random()) } // 待ち時間が一定だと永遠にお見合い状態になってしまうので、ばらけさせる。
}
f(path)
// このスクリプトの動作を分かり易くするための待機時間。実際は不要。
WScript.Sleep(5000)
lock.Close()
try{
fso.AXO.DeleteFile(pathL)
fso.AXO.DeleteFile(pathF)
}catch(e){}
WScript.Echo('OK')
}+'()','<-/script>','<-/job>'].join('\r\n').replace(/<-/g,'<'))
var pathDQ=function(path){return 0<path.indexOf(' ') ? ('"'+path+'"') : path }
return {
negoWrite:function(path, fun, fun終了後){
var pathF=fso.gsf2+'\\fun'+(new Date()).getTime()+'.js', pathO=pathF+'.txt'
fso.Write(pathF, fun)
shell.run('cmd /C cscript '+pathDQ(pathWSF)+' '+pathDQ(path)+' '+pathDQ(pathF)+' > '+pathDQ(pathO), 0)
var objIV=setInterval(function(){
if(!fso.AXO.FileExists(pathO)){return}
try{fso.AXO.DeleteFile(pathO)}catch(e){return}
fun終了後 && fun終了後()
clearInterval(objIV)
},1000)
}
}
}()
</script>
</html>



このサンプルを2つ起動して、片方は「A」に「1」と入力してonchangeイベントを発生させ、もう片方は「B」に「2」と入力してonchangeイベントを発生させると対象ファイルに対して二つのwsfがロック試行&書き込みを行います。

書き込み完了後、wsfはコマンドラインに対して標準出力で「OK」という文字列を返すと、それがリダイレクトによってテキストファイルに出力されて、それによってhtaがwsfの終了を検出し、後始末用の関数を実行します。

このサンプルが行う「後始末」は書き込み成功後のファイルを読み込んで、書き込み待ち項目数に応じて個別の項目値か全ての項目値をinputエリアに代入します。

0 件のコメント:

コメントを投稿