Hyperjase
Hyperjase

Reputation: 127

sub function not working in HTA

I'm not sure why but my sub function isn't working. I thought I'd followed how it should work but it just causes an error claiming my function is undefined.

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="x-ua-compatible" content="IE=edge">
<title>Remote Registry</title>
<HTA:APPLICATION
  APPLICATIONNAME="Remote Registry"
  ID="RemReg"
  VERSION="1.0.0.0"
  SCROLL="no"
  SINGLEINSTANCE="yes"
  CONTEXTMENU="no"
  NAVIGABLE="yes"
 SELECTION="no"
/>
<style type="text/css">
body
{
    margin: 0;
    width: 130px;
    height: 180px;
    overflow: hidden;
        font-family: arial;
    font-weight: bold;
    font-size: 12px;
}
</style>
</head>
<SCRIPT LANGUAGE="VBScript">
Sub CheckService
    strComputer = txtBox.value
    Set objWMIService = GetObject("winmgmts:" _
        & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
    Set colRunningServices = objWMIService.ExecQuery _
        ("Select * from Win32_Service Where Name=""RemoteRegistry""")
    For Each objService in colRunningServices 
    Output = objService.DisplayName  & " is " & objService.State
    Next
End Sub
</script>
<body>
    <input type="text" name="TxTbox" size="30" value=DTP-> Computer to check<br />
    <input id=checkservice type="button" value="Add Button" onClick="CheckService">
    <div id="strComputer"></div>
</body>
</html>

What am I missing? Something really simple? I've tried alternate names for the function, moving where the VBScript is. Nothing works :sRem

Upvotes: 2

Views: 5211

Answers (4)

Dinesh Jeedimetla
Dinesh Jeedimetla

Reputation: 87

Use parenthesis '()' function definition as below, it solves your issue.

Sub CheckService ()

//Your code

End Sub

Upvotes: 1

LesFerch
LesFerch

Reputation: 1995

The "[Subroutine name] is undefined" error occurs when the HTA document mode is 9 or higher and a subroutine is called from the HTML code without parentheses.

In this particular case, the code onClick="CheckService" should have been: onClick="CheckService()"

Note that the document mode of this HTA is ambiguous because it is declared as:

<meta http-equiv="x-ua-compatible" content="IE=edge">

This causes the HTML code within the HTA to be rendered using the highest document mode provided by MSHTML.dll. It has nothing to do with the edge browser.

Someone testing this HTA on a machine that has MSHTML 8 or lower will not see an error. On any machine with MSHTML 9 or higher, the error will occur. Please note that MSHTML 9 corresponds to Internet Explorer 9, which was released in 2011. So, by 2013, when this question was posted, most machines would get an error with the posted script.

The unofficially accepted answer eliminated the error by removing the meta line, causing the HTA to run in IE 7 mode, which does not require parentheses when calling a subroutine within the HTML code. Downgrading the HTA document mode probably had no negative effects in this case, but can result in HTML/CSS code that produces different results than expected.

Further background information on HTA document modes:

HTAs should target a specific document mode to ensure that the HTML/CSS code always works as expected. The ie=edge option should only ever have been used by expert coders who include multiple HTML code sections for different MSHTML versions. This is now obsolete as any machine in production should have MSHTML 11, which came out in 2013 and will never have any further upgrades. (Note: Windows 11 includes MSHTML 11, so HTAs still work.) Typically, an HTA should target IE=9, IE=10, or IE=11. There are some specific reasons to choose one of those three document modes, but that's a whole other discussion.

HTAs should generally start with code like this:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" http-equiv="X-UA-Compatible" content="IE=9">
<hta:application id=oHTA>
</head>

If your HTA has no DOCTYPE or X-UA-Compatible declaration, it will run in IE 5 mode by default. If it has only the DOCTYPE declaration, it will run in IE 7 mode by default. However, if there is a FEATURE_BROWSER_EMULATION registry setting for mshta.exe, then the default mode will be whatever has been set in that registry value.

If your HTA has an X-UA-Compatible declaration, it will run in that mode regardless of any registry setting (assuming the machine doesn't have an ancient version of MSHTML), so be sure to include the meta line as shown above (Note: the UTF-8 part is optional, but helpful for using special characters).

Upvotes: 3

dvj042210
dvj042210

Reputation: 1

A little basic HTML formatting of the Services list results makes it easier to read.

<!DOCTYPE html>
<html>
    <head>
        <title>Remote Registry</title>
        <hta:application
            applicationname="Remote Registry"
            id="RemReg"
            version="1.0.0.0"
            scroll="YES"
            singleinstance="yes"
            contextmenu="no"
            navigable="yes"
            selection="no"
            />
        <style type="text/css">
            body
            {
                margin: 0;
                width: 100%;
                height: 100%;
                overflow: hidden;
                font-family: arial;
                font-weight: bold;
                font-size: 12px;
            }
        </style>
        <script type="text/vbscript" id="EnumMyServices">

            ' <!--
            Sub EnumMyServices()
            dim WMI, objs, obj
            '
            set WMI = GetObject("WinMgmts:")
            on error resume next
            set objs = WMI.InstancesOf("Win32_Service")
            if err = 0 Then
            if objs.count > 0 then
            strHTML="<table border=1 align=left cellpadding=4 cellspacing=0>"
            strHTML=strHTML &  "<tr>"
            strHTML=strHTML &  "<th>DisplayName</th>"
            strHTML=strHTML &  "<th>State</th>"
            strHTML=strHTML &  "<th>StartMode</th>"
            strHTML=strHTML &  "</tr>"
            for each obj in objs
            ObName = obj.DisplayName 
            ObState = obj.State 
            ObStartMode = obj.StartMode 
            strHTML=strHTML &  "<tr>"
            strHTML=strHTML &  "<td>" & ObName & "</td>"
            strHTML=strHTML &  "<td>" & ObState & "</td>"
            strHTML=strHTML &  "<td>" & ObStartMode & "</td>"
            strHTML=strHTML &  "</tr>"
            next
            else
            strHTML="<table border=1 align=left cellpadding=4 cellspacing=0>"
            strHTML=strHTML &  "<tr>"
            strHTML=strHTML &  "<th>Attention</th>"
            strHTML=strHTML &  "</tr>"
            strHTML=strHTML &  "<tr>"
            strHTML=strHTML &  "<td>no services found!</td>"
            strHTML=strHTML &  "</tr>"
            end if
            else
            strHTML="<table border=1 align=left cellpadding=4 cellspacing=0>"
            strHTML=strHTML &  "<tr>"
            strHTML=strHTML &  "<th>Error!</th>"
            strHTML=strHTML &  "</tr>"
            strHTML=strHTML &  "<tr>"
            strHTML=strHTML &  "<td>An error occurred whilst trying to enum services!</td>"
            strHTML=strHTML &  "</tr>"
            end if
            set WMI=nothing
            set objs = nothing
            set obj = nothing
            on error goto 0

            strHTML=strHTML &  "</table>"
            strHTML=strHTML &  "<p>"   
            Results.InnerHTML=strHTML

            end sub
            ' -->
        </script>

        <script type="text/vbscript" id="EnumMyPrinters">
            ' <!--
            Sub EnumMyPrinters()
            dim WMI, objs, obj
            '
            set WMI = GetObject("WinMgmts:")
            on error resume next
            set objs = WMI.InstancesOf("Win32_Printer")
            if err = 0 Then
            if objs.count > 0 then
            window.document.getElementById("Results").innerText = "PRINTERS" & chr(13)
            for each obj in objs
            window.document.getElementById("Results").innerText = window.document.getElementById("Results").innerText & obj.Description & chr(13)
            next
            else
            window.document.getElementById("Results").innerText = "PRINTERS" & chr(13)
            window.document.getElementById("Results").innerText = "no printers found!" & chr(13)
            end if
            else
            window.document.getElementById("Results").innerText = "PRINTERS" & chr(13)
            window.document.getElementById("Results").innerText = "An error occurred whilst trying to enum printers!" & chr(13)
            end if
            set WMI=nothing
            set objs = nothing
            set obj = nothing
            on error goto 0
            end sub
            ' -->
        </script>

        <script type="text/vbscript" id="EnumMyProcesses">
            ' <!--
            Sub EnumMyProcesses()
            dim WMI, objs, obj
            '
            set WMI = GetObject("WinMgmts:")
            on error resume next
            set objs = WMI.InstancesOf("Win32_Process")
            if err = 0 Then
            if objs.count > 0 then
            window.document.getElementById("Results").innerText = "PROCESSES" & chr(13)
            for each obj in objs
            window.document.getElementById("Results").innerText = window.document.getElementById("Results").innerText & obj.Description & chr(13)
            next
            else
            window.document.getElementById("Results").innerText = "PROCESSES" & chr(13)
            window.document.getElementById("Results").innerText = "no processes found!" & chr(13)
            end if
            else
            window.document.getElementById("Results").innerText = "PROCESSES" & chr(13)
            window.document.getElementById("Results").innerText = "An error occurred whilst trying to enum processes!" & chr(13)
            end if
            set WMI=nothing
            set objs = nothing
            set obj = nothing
            on error goto 0
            end sub
            ' -->
        </script>

        <script type="text/vbscript" id="EnumMyProcessors">
            ' <!--
            Sub EnumMyProcessors()
            dim WMI, objs, obj
            '
            set WMI = GetObject("WinMgmts:")
            on error resume next
            set objs = WMI.InstancesOf("Win32_Processor")
            if err = 0 Then
            if objs.count > 0 then
            window.document.getElementById("Results").innerText = "PROCESSORS" & chr(13)
            for each obj in objs
            window.document.getElementById("Results").innerText = window.document.getElementById("Results").innerText & obj.Description & chr(13)
            next
            else
            window.document.getElementById("Results").innerText = "PROCESSORS" & chr(13)
            window.document.getElementById("Results").innerText = "no processors found!" & chr(13)
            end if
            else
            window.document.getElementById("Results").innerText = "PROCESSORS" & chr(13)
            window.document.getElementById("Results").innerText = "An error occurred whilst trying to enum processors!" & chr(13)
            end if
            set WMI=nothing
            set objs = nothing
            set obj = nothing
            on error goto 0
            end sub
            ' -->
        </script>
    </head>

    <body>
        <input id="btnServices" name="btnServices" type="button" value="Services" onclick="EnumMyServices" />
        <input id="btnPrinters" name="btnPrinters" type="button" value="Printers" onclick="EnumMyPrinters" />
        <input id="btnProcesses" name="btnProcesses" type="button" value="Processes" onclick="EnumMyProcesses" />
        <input id="btnProcessors" name="btnProcessors" type="button" value="Processors" onclick="EnumMyProcessors" />
        <p>
        <Font size="3" face="Tahoma"><h3>Results:</Font><hr></h3>
        <div id="Results">&nbsp</div>

    </body>
</html>

Upvotes: 0

Zeddy
Zeddy

Reputation: 2089

Change your code to the below and use the reference link above for your WMI call and you should be fine.

<!DOCTYPE html>

<html>

<head>
  <meta http-equiv="x-ua-compatible" content="IE=edge" />
  <title>Remote Registry</title>
  <hta:application
    applicationname="Remote Registry"
    id="RemReg"
    version="1.0.0.0"
    scroll="no"
    singleinstance="yes"
    contextmenu="no"
    navigable="yes"
    selection="no"
  />
  <style type="text/css">
    body
    {
      margin: 0;
      width: 130px;
      height: 180px;
      overflow: hidden;
      font-family: arial;
      font-weight: bold;
      font-size: 12px;
    }
  </style>
</head>

<script type="text/vbscript" id="CheckService">
Sub CheckService()
'
dim strComputer
  '
  strComputer = window.document.getElementById("txtComputer").value
  ' PLACE YOUR CALL TO WMI HERE - (I'm not sure mine is correct!)
  'Set objServices = GetObject( _
    "winmgmts:{impersonationLevel=impersonate," _
    & "authenticationLevel=pktPrivacy}!\\" _
    & strcomputer & "/root/cimv2")
  '
  Set colRunningServices = objWMIService.ExecQuery ("Select * from Win32_Service Where Name=" & chr(34) & "RemoteRegistry" & chr(34))
    if colRunningServices.items.count - 1 > 0 Then
      For Each objService in colRunningServices
        window.document.getElementById("Results").innerText = window.document.getElementById("Results").innerText & objService.DisplayName  & " is " & objService.State & chr(13)
      Next
    else
      window.document.getElementById("Results").innerText = "No running services found at this time!"
    end if
  '
End Sub
</script>

<body>
  <input type="text" id="txtComputer" name="txtComputer" size="30" value="Dtp-"/> Computer to check<br />
  <input id="btnCheckService" name="btnCheckService" type="button" value="Add Button" onclick="CheckService" />
  <div id="Results"></div>
</body>
</html>

UPDATE

I've modified the code to remove the META tag and add some sample subroutines for you.

What I did was saved the HTA to my desktop and executed from there, by double clicking on it.

<!DOCTYPE html>
<html>
<head>
  <title>Remote Registry</title>
  <hta:application
    applicationname="Remote Registry"
    id="RemReg"
    version="1.0.0.0"
    scroll="no"
    singleinstance="yes"
    contextmenu="no"
    navigable="yes"
    selection="no"
  />
  <style type="text/css">
    body
    {
      margin: 0;
      width: 130px;
      height: 180px;
      overflow: hidden;
      font-family: arial;
      font-weight: bold;
      font-size: 12px;
    }
  </style>
</head>
<script type="text/vbscript" id="EnumMyServices">
' <!--
Sub EnumMyServices()
  dim WMI, objs, obj
  '
  set WMI = GetObject("WinMgmts:")
  on error resume next
    set objs = WMI.InstancesOf("Win32_Service")
    if err = 0 Then
      if objs.count > 0 then
        window.document.getElementById("Results").innerText = "SERVICES" & chr(13)
        for each obj in objs
          window.document.getElementById("Results").innerText = window.document.getElementById("Results").innerText & obj.Description & chr(13)
        next
      else
        window.document.getElementById("Results").innerText = "SERVICES" & chr(13)
        window.document.getElementById("Results").innerText = "no services found!" & chr(13)
      end if
    else
      window.document.getElementById("Results").innerText = "SERVICES" & chr(13)
      window.document.getElementById("Results").innerText = "An error occurred whilst trying to enum services!" & chr(13)
    end if
    set WMI=nothing
    set objs = nothing
    set obj = nothing
  on error goto 0
end sub
' -->
</script>

<script type="text/vbscript" id="EnumMyPrinters">
' <!--
Sub EnumMyPrinters()
dim WMI, objs, obj
  '
  set WMI = GetObject("WinMgmts:")
  on error resume next
    set objs = WMI.InstancesOf("Win32_Printer")
    if err = 0 Then
      if objs.count > 0 then
        window.document.getElementById("Results").innerText = "PRINTERS" & chr(13)
        for each obj in objs
          window.document.getElementById("Results").innerText = window.document.getElementById("Results").innerText & obj.Description & chr(13)
        next
      else
        window.document.getElementById("Results").innerText = "PRINTERS" & chr(13)
        window.document.getElementById("Results").innerText = "no printers found!" & chr(13)
      end if
    else
      window.document.getElementById("Results").innerText = "PRINTERS" & chr(13)
      window.document.getElementById("Results").innerText = "An error occurred whilst trying to enum printers!" & chr(13)
    end if
    set WMI=nothing
    set objs = nothing
    set obj = nothing
  on error goto 0
end sub
' -->
</script>

<script type="text/vbscript" id="EnumMyProcesses">
' <!--
Sub EnumMyProcesses()
dim WMI, objs, obj
  '
  set WMI = GetObject("WinMgmts:")
  on error resume next
    set objs = WMI.InstancesOf("Win32_Process")
    if err = 0 Then
      if objs.count > 0 then
        window.document.getElementById("Results").innerText = "PROCESSES" & chr(13)
        for each obj in objs
          window.document.getElementById("Results").innerText = window.document.getElementById("Results").innerText & obj.Description & chr(13)
        next
      else
        window.document.getElementById("Results").innerText = "PROCESSES" & chr(13)
        window.document.getElementById("Results").innerText = "no processes found!" & chr(13)
      end if
    else
      window.document.getElementById("Results").innerText = "PROCESSES" & chr(13)
      window.document.getElementById("Results").innerText = "An error occurred whilst trying to enum processes!" & chr(13)
    end if
    set WMI=nothing
    set objs = nothing
    set obj = nothing
  on error goto 0
end sub
' -->
</script>

<script type="text/vbscript" id="EnumMyProcessors">
' <!--
Sub EnumMyProcessors()
dim WMI, objs, obj
  '
  set WMI = GetObject("WinMgmts:")
  on error resume next
    set objs = WMI.InstancesOf("Win32_Processor")
    if err = 0 Then
      if objs.count > 0 then
        window.document.getElementById("Results").innerText = "PROCESSORS" & chr(13)
        for each obj in objs
          window.document.getElementById("Results").innerText = window.document.getElementById("Results").innerText & obj.Description & chr(13)
        next
      else
        window.document.getElementById("Results").innerText = "PROCESSORS" & chr(13)
        window.document.getElementById("Results").innerText = "no processors found!" & chr(13)
      end if
    else
      window.document.getElementById("Results").innerText = "PROCESSORS" & chr(13)
      window.document.getElementById("Results").innerText = "An error occurred whilst trying to enum processors!" & chr(13)
    end if
    set WMI=nothing
    set objs = nothing
    set obj = nothing
  on error goto 0
end sub
' -->
</script>

<body>
  <div id="mycontainer">
    Results:<br />
    <div id="Results"></div>
  </div><br /><br />
  <input id="btnServices" name="btnServices" type="button" value="Services" onclick="EnumMyServices" />
  <input id="btnPrinters" name="btnPrinters" type="button" value="Printers" onclick="EnumMyPrinters" />
  <input id="btnProcesses" name="btnProcesses" type="button" value="Processes" onclick="EnumMyProcesses" />
  <input id="btnProcessors" name="btnProcessors" type="button" value="Processors" onclick="EnumMyProcessors" />
</body>
</html>

Upvotes: 1

Related Questions