Deniz da King
Deniz da King

Reputation: 401

Adding a GUI to VBScript

I'm currently working on a VBS script but I need user interaction with script. Basically I need two buttons and 4 checkboxes (checkboxes isn't important).

Upvotes: 7

Views: 44489

Answers (3)

Namhyeon Go
Namhyeon Go

Reputation: 673

Today, I would like to introduce two projects that will interest you.

  • wsh-js-gtk - Make your own GUI from JScript/VBScript with GTK-server
  • welsonjs - Build a windows desktop apps based on WSH/HTA with ES6/HTML5 compatibility polyfills, module.exports(NodeJS) styled module implementation.

Upvotes: 1

Igor Krupitsky
Igor Krupitsky

Reputation: 885

The best approach I found is to open HTA file from VBS using "WScript.Shell Run" and communicate back to the VBS using an XML file.

Example (dialog.vbs)

Set fso = CreateObject("Scripting.FileSystemObject") 
Set oFile = fso.GetFile(Wscript.ScriptFullName) 
sFolder = oFile.ParentFolder 
sHtaFilePath = sFolder & "\dialog.hta"
Dim oShell: Set oShell = CreateObject("WScript.Shell")
oShell.Run sHtaFilePath, 1, True

'Load return data from XML File
If fso.FileExists(sHtaFilePath & ".xml") Then
    Set oXml = CreateObject("Microsoft.XMLDOM")
    oXML.async = False
    oXML.load sHtaFilePath & ".xml"

    MsgBox "Value 1: " & oXML.SelectSingleNode("/root/txt1").text
    MsgBox "Value 2: " & oXML.SelectSingleNode("/root/txt2").text

    fso.DeleteFile sHtaFilePath & ".xml"
End If

Example HTA (dialog.hta)

<html>
  <title>Test</title>
  <head>
  <HTA:APPLICATION 
  ID=oHTA 
  SINGLEINSTANCE="yes"
  SCROLL="no"
  />
</head>

<script language="vbscript">
  Window.ResizeTo 300, 200
  Set fso = CreateObject("Scripting.FileSystemObject") 

  Sub Send()
    Dim sFilePath: sFilePath = Replace(location.href,"file:///","")
    sFilePath = Replace(sFilePath,"/","\")
    sFilePath = Replace(sFilePath," %20"," ")

    'Save return date to XML File
    Set oXml = CreateObject("Microsoft.XMLDOM")
    Set oRoot = oXml.createElement("root")
    oXml.appendChild oRoot
    AddXmlVal oXml, oRoot, "txt1", txt1.value
    AddXmlVal oXml, oRoot, "txt2", txt2.value
    oXml.Save sFilePath & ".xml"

    self.Close()
  End Sub

  Sub AddXmlVal(oXml, oRoot, sName, sVal)
    Set oNode = oXml.createElement(sName)
    oNode.Text = sVal
    oRoot.appendChild oNode
  End Sub

</script>

<body>
  <div>
    Value 1 
    <input id="txt1" style="width: 100px;">
  </div>

  <div>
    Value 2 
    <select id=txt2 style="width: 100px;">
      <option value="A">A</option>
      <option value="B">B</option>
      <option value="C">D</option>
    </select>
  </div>

<p align=center>
  <input type="button" value="Send" onclick="Send()">
  <input type="button" value="close" onclick="self.Close()">
</p>

</body>
</html>

Even better approach is for the HTA file to be created by the VBS file and then deleted. This way HTA does not have to be distributed along with the VBS.

Set fso = CreateObject("Scripting.FileSystemObject") 

sHtml = "<div>Value 1 " & _
    "<input id='txt1' style='width: 100px'>" & _
  "</div>" & _
  "<div>Value 2 " & _
    "<select id='txt2' style='width: 100px'>" & _
      "<option value='A'>A</option>" & _
      "<option value='B'>B</option>" & _
      "<option value='C'>D</option>" & _
    "</select>" & _
  "</div>" & _
  "<p align=center>" & _
    "<input type='button' value='Send' onclick='Send()'> " & _
    "<input type='button' value='Close' onclick='self.Close()'>" & _
  "</p>"

  Set oRet = OpenDialog(sHtml, "txt1,txt2", 300, 200, "Dialog 1")
  MsgBox "Value 1: " & oRet("txt1") & ", Value 2: " & oRet("txt2")

'==================================
Function OpenDialog(sHtml, sFields,iWidth,iHeight, sTitle)
  sHtaFilePath = Wscript.ScriptFullName & ".hta"

  CreateHtaFile sHtaFilePath, sHtml, sFields,iWidth,iHeight,sTitle

  Set f = fso.GetFile(sHtaFilePath)
  f.attributes = f.attributes + 2 'Hidden

  Dim oShell: Set oShell = CreateObject("WScript.Shell")

  oShell.Run """" & sHtaFilePath & """", 1, True

  If fso.FileExists(sHtaFilePath) Then
    fso.DeleteFile sHtaFilePath
  End If

  Set oRet = CreateObject("Scripting.Dictionary")

  'Load return data from XML File
  If fso.FileExists(sHtaFilePath & ".xml") Then
      Set oXml = CreateObject("Microsoft.XMLDOM")
      oXML.async = False
      oXML.load sHtaFilePath & ".xml"

      For each sField In Split(sFields,",")
        oRet.Add trim(sField), oXML.SelectSingleNode("/root/" & trim(sField)).text
      Next

      fso.DeleteFile sHtaFilePath & ".xml"
  End If

  Set OpenDialog = oRet
End Function

Sub CreateHtaFile(sHtaFilePath, sHtml, sFields, iWidth, iHeight, sTitle)
  Set f = fso.CreateTextFile(sHtaFilePath, True)
  f.WriteLine "<html><title>FL Reporting</title><head><HTA:APPLICATION ID=oHTA SINGLEINSTANCE=""yes"" SCROLL=""no""/></head>"
  f.WriteLine "<script language=""vbscript"">"
  f.WriteLine "Window.ResizeTo " & iWidth & ", " & iHeight
  f.WriteLine "Set fso = CreateObject(""Scripting.FileSystemObject"")"
  f.WriteLine ""
  f.WriteLine "Sub Send()"
  f.WriteLine " Dim sFilePath: sFilePath = Replace(location.href,""file:///"","""")"
  f.WriteLine " sFilePath = Replace(sFilePath,""/"",""\"")"
  f.WriteLine " sFilePath = Replace(sFilePath,""%20"","" "")"
  f.WriteLine " Set oXml = CreateObject(""Microsoft.XMLDOM"")"
  f.WriteLine " Set oRoot = oXml.createElement(""root"")"
  f.WriteLine " oXml.appendChild oRoot"

  For each sField In Split(sFields,",")
    f.WriteLine " AddXmlVal oXml, oRoot, """ & sField & """, GetVal(" & sField & ")"
  Next

  f.WriteLine " oXml.Save sFilePath & "".xml"""
  f.WriteLine " self.Close()"
  f.WriteLine "End Sub"
  f.WriteLine ""
  f.WriteLine "Sub AddXmlVal(oXml, oRoot, sName, sVal)"
  f.WriteLine " Set oNode = oXml.createElement(sName)"
  f.WriteLine " oNode.Text = sVal"
  f.WriteLine " oRoot.appendChild oNode"
  f.WriteLine "End Sub"
  f.WriteLine ""
  f.WriteLine "Function GetVal(o)"
  f.WriteLine " GetVal = o.value"
  f.WriteLine " If o.Type = ""checkbox"" Then"
  f.WriteLine "   If o.checked = False Then"
  f.WriteLine "     GetVal = """""
  f.WriteLine "   End If"
  f.WriteLine " End If"
  f.WriteLine "End Function"  
  f.WriteLine "</script>"
  f.WriteLine "<body>"
  f.WriteLine sHtml
  f.WriteLine "</body></html>"
  f.Close
End Sub

Upvotes: 1

peter
peter

Reputation: 42207

VBScript has dialogs, only not many and no checkboxes, you would need a COM object to do so (and there are). I'm sure you know Messagebox and here an example of the less known Popup

Dim WshShell, BtnCode
Set WshShell = WScript.CreateObject("WScript.Shell")

BtnCode = WshShell.Popup("Do you feel alright?", 7, "Answer This Question:", 4 + 32)

Select Case BtnCode
   case 6      WScript.Echo "Glad to hear you feel alright."
   case 7      WScript.Echo "Hope you're feeling better soon."
   case -1     WScript.Echo "Is there anybody out there?"
End Select

However, the best way to have more dialogs in vbscript is using HTA. Here an example

<HTML><HEAD>
   <HTA:APPLICATION
   ID = "oApp"
   APPLICATIONNAME = "Example"
   BORDER = "thick"
   CAPTION = "yes"
   ICON = "app.ico"
   SHOWINTASKBAR = "yes"
   SINGLEINSTANCE = "yes"
   SYSMENU = "yes"
   WINDOWSTATE = "normal"
   SCROLL = "yes"
   SCROLLFLAT = "yes"
   VERSION = "1.0"
   INNERBORDER = "yes"
   SELECTION = "no"
   MAXIMIZEBUTTON = "yes"
   MINIMIZEBUTTON = "yes"
   NAVIGABLE = "yes"
   CONTEXTMENU = "yes"
   BORDERSTYLE = "normal"
   >

   <SCRIPT language="vbscript">
   sub SimpleExeample()
     document.body.innerHTML = "<form name=myform><input type=checkbox name=chk1>Check me<br><br><button onclick='alert(myform.chk1.checked)'>Show if checked</button></form>"
   end sub
   </SCRIPT>

</HEAD>
<BODY onLoad="SimpleExeample()">
</BODY>
</HTML>

In one thing i agree with Cody, vbscript is nearly dead, if you start programming choose another language. Take a look at Ruby, the start is easy to learn an it is FUN. Here an example of u ruby script using shoes as GUI

require 'green_shoes'
Shoes.app{
  button("Click me!"){alert("You clicked me.")}
}

EDIT: since my Ruby alternative rises some questions, here a more traditionel way closer to Vbscript uses of the same sample. The sample above is used more for a functional chained way of programming.

require 'green_shoes'
Shoes.app do
  button("Click me!") do
    alert("You clicked me.")
  end
end

Upvotes: 8

Related Questions