2018年8月20日月曜日

ADO警告画面を出さずにMySQLを使用する実用的なサンプル

スクリプトを実行する度に警告メッセージが表示されてしまうのを回避する方法については先日書いた通りですが、今回は外部スクリプトとして実用的なサンプルを作成しました。


汎用スクリプト = function(){
// 一時的なスクリプトファイルを作成して処理を外部化する場合、
// 汎用スクリプトファイルのPathではなく関数を埋め込む方が良さそう。
外部スクリプトファイル={
作成:function(メイン関数){
var path一時的 = AXO.fs.pathTMP+'/'+getTime()+'_外部スクリプト.js'
var str出力 = [
'main = '+メイン関数,
'汎用スクリプト = '+汎用スクリプト,
'汎用スクリプト()',
'!'+function(){
var arg = WScript.Arguments
var path = arg[LEN] ? arg(0) : ''
var 引数
eval('引数 = ' + AXO.fs.Read(path)+'.引数')
var returnValue = main(引数)
if(path){ AXO.fs.Write(path, toJSON({returnValue:returnValue, 正常終了:true})) }
}+'()'
].join('\r\n')
AXO.fs.Write(path一時的, str出力)
return path一時的
},
実行:function(path, 引数, sw表示, sw同期, func完了後, intインターバル長さms, int待機打ち切りms, func打ち切り後){
// 非同期モード かつ 外部スクリプト完了後に"func完了後"を実行させる機能は
// setIntervalを使用しているためWSHでは使用不可。
// 引数の有無に関わらず受け渡し用の一時的なファイルは作成する。(外部スクリプトが正常終了したか確認するため)
var path一時的 = AXO.fs.pathTMP+'/'+getTime()+'_外部スクリプト用引数受け渡しファイル.txt'
AXO.fs.Write(path一時的, toJSON({引数:引数}))
// ファイルの更新日時は秒までしか単位がなく、ミリ秒単位で処理完了した場合は
// 作成と更新が同じ日時になるので更新状態の識別には使えない。
var func後始末=function(sw打ち切り){
var objRV
eval('objRV = '+AXO.fs.Read(path一時的))
var flagエラー
if(!objRV.正常終了){
// 外部スクリプトで何らかのエラーが発生し、一時的なファイルが更新されていない
flagエラー = true
}
AXO.fs().DeleteFile(path一時的)
if(flagエラー){return}
if(sw打ち切り){ return func打ち切り後 ? func打ち切り後() : 0 }
if(func完了後){ func完了後(objRV.returnValue) }
}
AXO.shell().run('cmd /C cscript "'+path+'"'+(path一時的 ? ' "'+path一時的+'"' : ''), sw表示 ? 1 : 0, sw同期 ? true : false)
if(!func完了後){return func後始末()}
if(sw同期){ return func後始末() }
var dat待機開始=getTime()
int待機打ち切りms = int待機打ち切りms || (1000 * 60)
var objInterval = setInterval(function(){
if(int待機打ち切りms < (getTime()-dat待機開始)){
clearInterval(objInterval)
return func後始末(true)
}
if(dat作成 < get更新time()){
clearInterval(objInterval)
func後始末()
}
}, intインターバル長さms || 1000)
},
削除:function(path){ AXO.fs().DeleteFile(path) }
}
var ActiveXObject関係=function(){
AXO = function(短縮名, 正式名){
var AXO = new ActiveXObject(正式名)
return arguments.callee[短縮名] = function(){ return AXO }
}
var fso = AXO('fs', 'Scripting.FileSystemObject')
var fs = fso()
fso.Read = function(p){var r=fs.OpenTextFile(p),v=r.AtEndOfStream?'':r.ReadAll();r.Close();return v}
fso.RAS = function(p){return fso.Read(p).split('\r\n')}
fso.Write = function(path,v){with(fs.CreateTextFile(path)){Write(v);Close()}}
fso.pathTMP = fs.GetSpecialFolder(2)
var obj = AXO('shell', 'WScript.Shell')
var shell = obj()
obj.getDir = function(path,swDir){
var arr=shell.exec('cmd /C dir /A'+(swDir?'':'-')+'D /B "'+path.replace(/[/]/g,'\\')+'"').StdOut.ReadAll().split('\r\n').reverse()
!arr[0] && arr.shift()
return arr.reverse()
}
}
ActiveXObject関係()
LEN='length'
for0L = function(arr,fun){for(var i=0,L=arr[LEN],res;i<L;i++){if(res=fun(i,arr[i])){return res}}}
forIn = function(obj,fun){var name,res; for(name in obj){if(res=fun(name, obj[name])){return res}}}
getTime=function(d){return (d || new Date()).getTime()}
toJSON=function(){
var main=function(o){ var t=gt(o); return o===null ? 'null' : objT[t] ? objT[t](o) : objC[gc(o)](o) }
var gt=function(o){return typeof(o)}, gc=function(o){return o.constructor}, objT={}, objC={}, fStr, nt='\n\t'
var n2nt = function(v){return (v+'').replace(/\n/g,nt)}
objT[gt('')] = fStr = function(s){return '"'+(s+'').replace(/\\/g,'\\\\').replace(/\r/g,'\\r').replace(/\n/g,'\\n').replace(/"/g,'\\"')+'"'}
objT[gt(0)] = objT[gt(true)] = objT[gt(gt.und)] = objC[gc(/1/)] = function(v){return (''+v).toLowerCase()}
objC[gc(new Date())] = function(o){return 'new Date("'+o+'")'}
objC[gc(gc)] = function(o){return インデント調整(o)}
objC[gc({})] = function(o){
if(循環.名前push(o)){return '"参照の重複"'}
var a=[], i=0
forIn(o,function(n,v){ a[i++] = fStr(循環.名前=n)+':'+n2nt(main(v)) })
循環.pop()
return '{'+nt+a.join(','+nt)+'\n}'
}
objC[gc([])] = function(o){
if(循環.名前push(o)){return '"参照の重複"'}
var a0=[], s, a1=[], i=0
for0L(o,function(i,v){a0[循環.名前=i]=n2nt(main(v))}), s='['+nt+a0.join(','+nt)+'\n]'
forIn(o,function(n,v){ !a0[n] && (a1[i++] = 'a['+fStr(循環.名前=n)+']='+n2nt(main(v))) })
循環.pop()
return a1[LEN] ? (インデント調整(function(){
var a=sss
aaa111
return a
})+'()').replace(/sss/,n2nt(s)).replace(/aaa111/,a1.join(nt)) : s
}
objC[gc(function(){})] = function(o){
if(循環.名前push(o)){return '"参照の重複"'}
var a1=[], i=0
forIn(o,function(n,v){ a1[i++] = 'f['+fStr(循環.名前=n)+']='+n2nt(main(v)) })
循環.pop()
return a1[LEN] ? (インデント調整(function(){
var f=sss
aaa111
return f
})+'()').replace(/sss/,n2nt(o)).replace(/aaa111/,a1.join(nt)) : o
}
var 循環=function(){
var arr候補, arr確定, key, arr重複候補
var getKey=function(){return key[LEN] ? '['+key.join('][')+']' : ''}
return {
init:function(){arr候補=[]; arr確定=[]; key=[]; arr重複候補=[], this.名前=''},
名前:'',
名前push:function(o){
this.名前 && key.push(fStr(this.名前))
// 追加した名前に対応するoと一致するものがarr候補にあるならtrueを返す
var fun=function(i,候補){return o==候補.o && arr確定.push({s:候補.key, d:getKey()}) && key.pop()}
if(key[LEN] && (forIn(arr候補,fun) || forIn(arr重複候補,fun))){return true}
// 一致するものがなければ候補に追加する
arr候補.push({o:o, key:getKey()})
},
pop:function(){key.pop(), arr重複候補.push(arr候補.pop())},
getRes:function(objName){var a=[]; for0L(arr確定,function(i,o){ a.push(objName+o.d+' = '+objName+o.s) }); return a}
}
}()
return function(o){
循環.init()
var s=main(o), a=循環.getRes('o')
return !a[LEN] ? s : 'function(){\n\tvar o='+s.replace(rNg,nt)+'\n\t'+a.join('\n\t')+'\n\treturn o\n}()'
}
}()
}
汎用スクリプト()
!function(){
MySQL = {
Execute:function(SQL, func完了後){
var path=AXO.fs.pathTMP+'/'+getTime()+'_MySQL.js'
var path外部js=外部スクリプトファイル.作成(function(SQL){
try{
var objMS = AXO('MySQL','ADODB.Connection')
objMS().Open('MySQL')
var rec = objMS().Execute(SQL)
}
catch(e){ return 'MySQL利用不可' }
var フィールド数 = rec.Fields.Count
var arrフィールド名 = []
for(var i=0; i<フィールド数 ;i++){ arrフィールド名[i] = rec.Fields(i).Name }
var arrレコード = []
for(i=0; !rec.EOF ;rec.MoveNext(),i++){
arrレコード[i] = {}
for0L(arrフィールド名, function(j,フィールド名){
arrレコード[i][フィールド名] = rec.Fields(フィールド名).Value
})
}
return { arrフィールド:arrフィールド名, arrレコード:arrレコード }
})
外部スクリプトファイル.実行(path外部js, SQL, 0, 1, func完了後)
外部スクリプトファイル.削除(path外部js)
},
keyValue化:function(obj, フィールド名){
// Executeが返すobjの中のarrレコードは配列型。
// その配列内から、任意のフィールド名の値が「〇〇」なレコードを探し出すには一手間必要。
// その一手間をkeyValue化によって省略するのが、このメソッド。
var objKV = {}
for0L(obj.arrレコード, function(i,obj1レコード){
objKV[obj1レコード[フィールド名]] = obj1レコード
})
return objKV
}
}
var SQL動作確認 = "select count(object) from tbl where name='ABC'"
MySQL.Execute(SQL動作確認, function(戻り値){
if(戻り値=='MySQL利用不可' || 戻り値==SQL動作確認){ MySQL = false }
WScript.Echo(toJSON(戻り値))
})
WScript.Quit()
}()

2 件のコメント:

  1. この問題に直面し、この記事を見つけましたが
    全く理解できませんでした。。。。
    初心者にわかるような解説加えて頂けないでしょうか。。。

    返信削除
    返信
    1. コメントありがとうございます。
      解説不足で、すみません。

      HTAファイルの中にscriptタグを記入して、その中でADODB.connectionでMySQLなどを使用すると警告画面が表示されてしまいます。
      しかし、拡張子がjsやwsfのファイルの場合(cscript.exeやwscript.exeで実行した場合)は警告画面が表示されません。

      ですから、HTAから「WScript.Shell」のRunやExecメソッドを使って「jsファイル(あるいはwsfファイル)」を実行すれば警告画面が表示されないように出来ます。

      上記に関するシンプルなプログラムを、下記URLに作成しました。
      https://gist.github.com/imasara2script/a97654479f470d50b2b37a705197bd94

      ※「1_この方法は警告画面が出ない.hta」と「1_外部.js」は同じフォルダに保存されている必要があります。

      削除