我想从命令行运行EA编写的VBScript代码(作为夜间工作)。除了将其复制到.vbs文件并像这样运行它之外,是否有其他方法可以做到?我的脚本中有一堆!INC-ludes,这意味着要进行双重维护才能使两个版本都保持最新。有解决办法吗?
答案 0 :(得分:2)
此处没有开箱即用的解决方案。但是您可以编写VBScript代码来模仿EA在脚本运行时的功能,即
此外,您至少需要在运行脚本时替换EA中易于使用的所有功能。
由于EA是32位应用程序,因此您需要调用32位版本的脚本引擎(cscript.exe)来运行与EA API通信的脚本,通常在C:\ Windows \ SysWOW64 \ cscript.exe
以上所有任务均被编译为以下脚本代码:
option explicit
'(c) Martin Jecny 2020
'WScript.Echo "Scripting Engine: " & ScriptEngine & " ver. " & ScriptEngineMajorVersion & "." & ScriptEngineMinorVersion & "." & ScriptEngineBuildVersion
'WScript.Echo "Creating Repository object"
dim Repository 'as EA.Repository 'defined as global, as it is default in EA environment
set Repository=CreateObject("EA.Repository")
dim ses 'as EA.Session
WScript.Echo "Start: " & Now
runIt(WScript.Arguments) 'complete script name, -v|--verbose
WScript.Echo "End: " & Now
'cleanup
on error resume next
Repository.exit
set Repository=Nothing
on error goto 0
sub runIt(argList)
dim result 'as Variant
if argList.Count <1 then
WScript.Echo "Usage: runEaScript <scriptGroup>.<scriptName> [-v|--verbose] [-c|--copysource]"
result=cleanup(Nothing)
WScript.Quit(0)
end if
'parse arguments
dim scriptFullName 'as String
scriptFullName=argList(0)
dim arg
dim verbose 'as Boolean
verbose=false
dim copysource 'as Bollean
copysource=false
for each arg in argList
select case arg
case "-v", "--verbose"
WScript.Echo "Verbose mode on"
verbose=true
case "-c", "--copysource"
copysource=true
if verbose then
WScript.Echo "Copy of the produced code will be stored to current directory"
end if
end select
next
if verbose then WScript.Echo "Requested script to run: '" & scriptFullName & "'"
if verbose then WScript.Echo "Opening cloud Repository ..."
Repository.OpenFile ("mycloudrepository --- ;Connect=Cloud=protocol:http,address:cloudhost,port:80;Data Source=modelname;DSN=modelname;LazyLoad=1;")
if verbose then WScript.Echo "Retrieving main script code ..."
dim sql 'as String
dim mainScriptCode 'as String
mainScriptCode=getScriptCode(scriptFullName)
if Len(mainScriptCode)<1 then
WScript.Echo "500002" & ": " & "Main script code retrieval failed."
result=cleanup(Nothing)
WScript.Quit(3)
end if
if verbose then WScript.Echo "Resolving !INCludes ..."
dim startPos 'as Integer 'position of !INC in the code
dim endOfPreviousLinePos 'as Integer 'position before start of the !INC line
dim startToInc 'as String ' string between start of line and !INC directive
dim endLinePos 'as Integer 'end position of !INC line
dim endIncPos 'as Integer 'end of included script name within the line
startPos=1 'start position of !INC in script code
endLinePos=0
endIncPos=0
dim includeList 'as Scripting.Dictionary 'list of already included scripts
set includeList=CreateObject("Scripting.Dictionary")
includeList.RemoveAll
dim includeString 'as String '!INC <script> string
dim toBeReplaced 'as String 'usualy full line with !INC string
do while startPos<>0
'detect !INC
startPos = InStr(1,mainScriptCode,"!INC ")
'detection and removal of !INC within commented line
if startPos > 0 then
endLinePos=InStr(startPos,mainScriptCode,chr(10))
endOfPreviousLinePos=InStrRev(mainScriptCode, chr(10),startPos)
if endOfPreviousLinePos <> (startPos-1) then
startToInc=mid(mainScriptCode,endOfPreviousLinePos,startPos-endOfPreviousLinePos)
if InStr(startToInc,"'")>0 then
if verbose then WScript.Echo "Skipping commented reference " & startToInc & toBeReplaced
toBeReplaced=mid(mainScriptCode,startPos,endLinePos-startPos)
mainScriptCode=Replace(mainScriptCode,toBeReplaced,"",1,1)
startPos=InStr(1,mainScriptCode,"!INC ")
end if
end if
end if
'including the code if not already included
if startPos > 0 then
endLinePos=InStr(startPos,mainScriptCode,chr(10))
includeString=trim(mid(mainScriptCode,startPos+5,endLinePos-(startPos+5))) 'ommit !INC string
toBeReplaced=mid(mainScriptCode,startPos,endLinePos-startPos)
'remove comment from reference line
endIncPos=InStr(1,includeString,"'") 'comment?
if endIncPos>0 then 'strip comment after reference
includeString=left(includeString,endIncPos-1)
end if
includeString=trim(includeString)
Err.Clear 'probably not necessary, just for sure
on error resume next
includeList.Add includeString,includeString 'Dictionary object has natively unique index
if Err.Number >0 then 'already exists
if verbose then WScript.Echo includeString & " already included, removing the reference."
mainScriptCode=Replace(mainScriptCode,toBeReplaced,"",1,1)
else 'new one found
if verbose then WScript.Echo "Including '" & includeString & "'"
mainScriptCode=Replace(mainScriptCode,toBeReplaced,getScriptCode(includeString),1,1)
end if
on error goto 0
end if
loop
'adapt code for running in pure VBS environment
if verbose then WScript.Echo "Adapting the code ..."
mainScriptCode=adaptToPureVbsCode(mainScriptCode)
'make file with the code to run
dim tempFileName 'as String
dim fso 'as Scripting.FileSystemObject
dim tempFolder 'as Folder
set fso=CreateObject("Scripting.FileSystemObject")
set tempFolder=fso.GetSpecialFolder(2) 'get temp diectory
tempFileName=fso.GetSpecialFolder(2).Path & "\" & fso.getTempName
dim mainScriptFile 'as File
set mainScriptFile=fso.createTextFile(tempFileName)
result=mainScriptFile.Write(mainScriptCode) '@TODO error handling
result=mainScriptFile.Close
if verbose then WScript.Echo "Written to file: " & tempFileName
if copysource then
dim scriptdir 'as Folder
scriptdir = fso.GetParentFolderName(WScript.ScriptFullName)
result=fso.CopyFile (tempFileName, scriptdir & scripFullName& ".vbs",true) 'overwrite allowed
end if
executeGlobal fso.openTextFile( tempFileName).readAll() 'run the complete script from temporary file
if verbose then Wscript.Echo "000000" & ": " & "Successful exit"
WScript.Quit(0)
end sub
function getScriptCode(scriptFullName)
if Len(scriptFullName)<1 then
WScript.Echo "500001" & ": " & "No script name provided"
getScriptCode=""
exit function
end if
if InStr(scriptFullName,".")<2 then
WScript.Echo "500004" & ": " & "No group - provide full script name in the form <Group>.<Script>"
getScriptCode=""
exit function
end if
dim dotPos 'as Integer
dotPos=InStr(scriptFullName,".")
dim scriptGroupName 'as String
dim ScriptName 'as String
scriptGroupName=Left(scriptFullName,dotPos-1)
scriptName=Mid(scriptFullName,dotPos+1)
if Len(scriptName)<1 then
WScript.Echo "500005" & ": " & "No script name - provide full script name in the form <Group>.<Script>"
getScriptCode=""
end if
dim sql
sql="select s.script from t_script s, t_script g where s.scriptauthor=g.scriptname"
sql = sql & " and g.script like '" & scriptGroupName & "'"
sql = sql & " and s.notes like '%Script Name=""" & scriptName & """%'"
dim scriptCode 'as String
getScriptCode=getSqlSingleValue(sql)
end function
'* adapts the code to run in pure VBS outside of EA
'* @param String 'original EA VBS code
'* @return String 'code with replacements
function adaptToPureVbsCode(code) '@TODO: replacement for Session.Input and Session.Prompt
dim regEx 'as RegExp
set regEx=New RegExp
regEx.IgnoreCase=true
regEx.Global=true
regEx.Pattern=chr(10)
'beautification of the code, mainly for debug purposes
code=regEx.Replace(code,chr(13) & chr(10))
'redirect outuput commands
regEx.Pattern="session.output" 'replace output command
code=regEx.Replace(code,"WScript.Echo")
'comment out manipulation with script output window
regEx.Pattern="Repository.EnsureOutputVisible \""Script\"""
code=regEx.Replace(code,"'"& "Repository.EnsureOutputVisible ""Script""")
regEx.Pattern="Repository.ClearOutput \""Script\"""
code=regEx.Replace(code,"'Repository.ClearOutput ""Script""")
adaptToPureVbsCode=code
end function
'* returns single (or first) value from single column; SQL query must comply to this; returns empty string if not found
'* @param sql as String SQL query
'* @return String
public function getSqlSingleValue(sql) 'as String
dim xmlDoc 'as MSXML2.DomDocument60 '1.2.0
set xmlDoc=CreateObject("Msxml2.DOMDocument.6.0") '1.2.0
dim node 'as MSXML2.IXMLDomNode
xmlDoc.loadXML(Repository.SQLQuery(sql)) '@TODO fails with field names like COUNT(*) on "("; needs escaping
set node= xmlDoc.selectSingleNode("//Row[1]/child::node()")
if node is nothing then
getSqlSingleValue=""
exit function
end if
if len(node.text)>0 then
getSqlSingleValue=node.text
else
getSqlSingleValue=""
end if
end function
'*@ Cleanup of the environment
'*@param FileSystemObject fso
'*@return void
function cleanup(fso)
on error resume next
Repository.CloseFile
Repository.Exit
set Repository=nothing
result=fso.DeleteFile(tempFileName)
set fso=nothing
on error goto 0
end function
“ C:\ Windows \ SysWOW64 \ cscript.exe”“ C:\ Users \ user \ Documents \ jobs \ runEaScript.vbs”“我的脚本组。我的脚本名称” --verbose / nologo
必须注意的是,VBScript的文本操作并不是很快,并且脚本准备可能需要一些时间。如果您需要经常运行脚本,请对生成的VBS文件进行一些缓存。