objProcess.Terminate not Found - vba

Trying to kill InternetExplorer:
Sub IE_kill()
Dim objWMI As Object, objProcess As Object, objProcesses As Object
Set objWMI = GetObject("winmgmts://.")
Set objProcesses = objWMI.ExecQuery( _
"SELECT * FROM Win32_Process WHERE Name = 'iexplore.exe'")
For Each objProcess In objProcesses
If Not objProcess Is Nothing Then
hh = objProcesses.Count ' 1
objProcess.Terminate ' Here is Error Not Found
If Err.Number <> 0 Then
Else
'DisplayErrorInfo
Exit For
End If
End If
Next
Set objProcesses = Nothing: Set objWMI = Nothing
End Sub
but get sometimes error on objProcess.Terminate Not Found
how to solve problem? Error catch do not help. On error resume next not work as error raise instead.

I have tried this modification of your code (for MS Edge) and it worked about 3 times so far:
Option Explicit
Sub KillIE()
Dim objWMI As Object, objProcess As Object, objProcesses As Object
Set objWMI = GetObject("winmgmts://.")
Set objProcesses = objWMI.ExecQuery("SELECT * FROM Win32_Process")
For Each objProcess In objProcesses
If Not objProcess Is Nothing Then
If InStr(1, UCase(objProcess.Name), "EDGE") > 0 Then
Debug.Print objProcess.Name
objProcess.Terminate
If Not Err.Number <> 0 Then
Exit For
End If
End If
End If
Next
End Sub
You can give it a try and check the objProcess.Name, before it gives an error. Consider replacing "EDGE" with INTERNETEXPLORER or IEXPLORER.

As mentioned in one of the comments, you can use the taskkill command as shown below:
Sub IE_kill
Dim objShell, strCommand
strCommand = "taskkill /f /im iexplore.exe"
Set objShell = CreateObject("wscript.shell")
objShell.Run strCommand
Set objShell = Nothing
End Sub
Check this answer out to know more about the taskkill
OR, if you want to stick to the wmi, you can try the following "workaround"(it will not throw the error you are currently getting-see further explanation in comments):
Dim objw, strComputer, arrPID(), intIndex
strComputer = "."
intIndex=-1
Set objw = GetObject("winmgmts://"&strComputer&"/root/cimv2")
Set objps = objw.ExecQuery("Select * from win32_process where name = 'iexplore.exe'")
for each instance in objps
intIndex = intIndex + 1
redim preserve arrPID(intIndex)
arrPID(intIndex) = instance.processID 'storing all the process IDs of the processes having name = iexplore.exe
next
for each pid in arrPID
Set objps = objw.ExecQuery("Select * from win32_process where processID = "&pid) 'getting the process with the process IDs
for each instance in objps
instance.terminate 'As soon as this line gets executed for the first process ID in the array, It will terminate ALL the iexplore processes. This means, for the remaining process IDs in the array, this line would not even get executed because when we try to find the process with that process ID, it wouldn't be found and hence we would not be able to enter the for-loop and tus no error is generated.
next
next

Related

How to fix '438 - Object Doesn't Support Property or Method Error'

I have included an audit trail code to be called to 2 different forms in my access database. The code works fine for one of the forms but in the other form it produces a 438 error.
-The same parameter is used to call the code in both forms
-The debugger highlights this line : 'If Nz(ctl.Value) <> Nz(ctl.OldValue) Then
-I have attempted to comment out the code which calls the procedure and the problem appears to be with the parameter "SingleName"
-I have checked both the Control Source and Name for the textbox and both appear correct.
Sub AuditChanges(IDField As String, UserAction As String)
On Error GoTo AuditChanges_Err
Dim cnn As ADODB.Connection
Dim rst As ADODB.Recordset
Dim ctl As Control
Dim datTimeCheck As Date
Dim strUserID As String
Set cnn = CurrentProject.Connection
Set rst = New ADODB.Recordset
rst.Open "SELECT * FROM TBL_AuditTrail", cnn, adOpenDynamic,
adLockOptimistic
datTimeCheck = Now()
strUserID = Environ("USERNAME")
Select Case UserAction
Case "EDIT"
For Each ctl In Screen.ActiveForm.Controls
If ctl.Tag = "Audit" Then
If Nz(ctl.Value) <> Nz(ctl.OldValue) Then
With rst
.AddNew
![DateTime] = datTimeCheck
![UserName] = strUserID
![FormName] = Screen.ActiveForm.Name
![Action] = UserAction
![RecordID] =
Screen.ActiveForm.Controls(IDField).Value
![FieldName] = ctl.ControlSource
![OldValue] = ctl.OldValue
![NewValue] = ctl.Value
.Update
End With
End If
End If
Next ctl
Case Else
With rst
.AddNew
![DateTime] = datTimeCheck
![UserName] = strUserID
![FormName] = Screen.ActiveForm.Name
![Action] = UserAction
![RecordID] = Screen.ActiveForm.Controls(IDField).Value
.Update
End With
End Select
AuditChanges_Exit:
On Error Resume Next
rst.Close
cnn.Close
Set rst = Nothing
Set cnn = Nothing
Exit Sub
AuditChanges_Err:
MsgBox Err.Number & Err.Description
Resume AuditChanges_Exit
End Sub
Private Sub Form_BeforeUpdate(Cancel As Integer)
If Me.NewRecord Then
Call AuditChanges("SingleName", "NEW")
Else
Call AuditChanges("SingleName", "EDIT")
End If
End Sub
The BeforeUpdate event of the form is supposed to call the procedure and send any changes, deletions or additions to TBL_AuditTrail.
After the data is inputted and I attempt to save, the 438 error occurs.
The information is still sent to the table (TBL_AuditTrail)
An unbound control doesn't have an OldValue property. You could check for that:
If ctl.ControlSource <> "" Then
![OldValue].Value = ctl.OldValue
Else
' Skip unbound control.
End If
Without seeing the three forms in question, I can only say that something is different on Screen.ActiveForm.Controls(IDField) field. I would compare the properties of all three fields to see how the one that is failing is different.

Killing Two different Processes With VB

I am trying to figure out how to kill two processes at the same time I have managed to get one to work when it is opened but the other wont close.
Sub block()
For Each item As Process In Process.GetProcesses
If item.ProcessName = "taskmgr" And item.ProcessName = "cmd" Then
item.Kill()
End If
Next
End Sub
As noted by #Noodles and #Zaggler your logic is wrong on this line;
If item.ProcessName = "taskmgr" And item.ProcessName = "cmd" Then
This line essentially asks if the process name is "taskmgr" and if the same process name is "cmd". Since these two strings aren't the same "taskmgr" /= "cmd" this if clause will never be true. I suggest you do something like this;
Sub block()
For Each item As Process In Process.GetProcesses
If item.ProcessName = "taskmgr" Then
item.Kill()
ElseIf item.ProcessName = "cmd" Then
item.Kill()
End If
Next
End Sub
Or optionally if you plan to close many processes;
'declare at form loading or elsewhere
Dim proclist as new list (of string)
proclist.add("taskmgr")
proclist.add("cmd")
proclist.add("...")
Sub block()
For Each item As Process In Process.GetProcesses
If proclist.contains(item.ProcessName) Then
item.Kill()
End If
Next
End Sub
Give a try with this solution in vbscript :
Option Explicit
Dim Ws,fso,MainArray,LogFile,i,OutPut,count
Set Ws = CreateObject("Wscript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
MainArray = Array("taskmgr.exe","cmd.exe")
LogFile = Left(Wscript.ScriptFullName,InstrRev(Wscript.ScriptFullName, ".")) & "log"
count = 0
If fso.FileExists(LogFile) Then fso.DeleteFile LogFile
Set OutPut = fso.OpenTextFile(LogFile,2,True)
For i = LBound(MainArray) To UBound(MainArray)
Call Kill(MainArray(i))
Next
OutPut.WriteLine String(50,"*")
OutPut.WriteLine count & " Process were killed !"
OutPut.WriteLine String(50,"*")
If fso.FileExists(LogFile) Then
ws.run DblQuote(LogFile) 'To show the LogFile
End if
'******************************************
Sub Kill(MyProcess)
Dim colItems,objItem
Set colItems = GetObject("winmgmts:").ExecQuery("Select * from Win32_Process " _
& "Where Name like '%"& MyProcess &"%' AND NOT commandline like '%" & wsh.scriptname & "%'",,48)
For Each objItem in colItems
count= count + 1
OutPut.WriteLine Mid(objItem.CommandLine,InStr(objItem.CommandLine,""" """) + 2)
objItem.Terminate(0)
Next
End Sub
'***********************************************
Function DblQuote(Str)
DblQuote = Chr(34) & Str & Chr(34)
End Function
'***********************************************

Parsing xml string in VBA

I am trying to parse xml document that i am getting from a website.
from some reason i cant figure out i cant parse the value inside the 'RATE' node.
the xml string seems O.K.
but in the end of the code (commented) i get Object variable or With block variable not set error.
i will be grateful for any help.
XML STRING:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<CURRENCIES>
<LAST_UPDATE>2016-01-25</LAST_UPDATE>
<CURRENCY>
<NAME>Dollar</NAME>
<UNIT>1</UNIT>
<CURRENCYCODE>USD</CURRENCYCODE>
<COUNTRY>USA</COUNTRY>
<RATE>3.982</RATE>
<CHANGE>0.277</CHANGE>
</CURRENCY>
</CURRENCIES>
VBA CODE:
Private Sub loadXMLString(xmlString)
Dim strXML As String
Dim xNode As IXMLDOMNode
Dim XDoc As MSXML2.DOMDocument
strXML = xmlString
Set XDoc = New MSXML2.DOMDocument
If Not XDoc.LoadXML(strXML) Then 'strXML is the string with XML'
Err.Raise XDoc.parseError.ErrorCode, , XDoc.parseError.reason
End If
Set xNode = XDoc.FirstChild
Debug.Print xNode.SelectSingleNode("RATE").Text ' here i get the Object variable or With block variable not set error
Debug.Print xNode.ChildNodes(2).SelectSingleNode("RATE").Text ' also with that try i get the Object variable or With block variable not set error
End Sub
UPDATE:
i found the problem (as i wrote down in the comments to #Nathan).
the problem is the <?xml version="1.0" encoding="utf-8" standalone="yes"?> node
Tested it an this code is working:
so how can i do that with out to remove this node as a substring, there must be a way i guess, but i dont have a lot of experience working with XML
Private Sub loadXMLString(xmlString)
Dim strXML As String
Dim xNode As IXMLDOMNode
Dim XDoc As MSXML2.DOMDocument
strXML = "<CURRENCIES>" & _
"<LAST_UPDATE>2016-01-25</LAST_UPDATE>" & _
"<CURRENCY>" & _
"<NAME>Dollar</NAME>" & _
"<UNIT>1</UNIT>" & _
"<CURRENCYCODE>USD</CURRENCYCODE>" & _
"<COUNTRY>USA</COUNTRY>" & _
"<RATE>3.982</RATE>" & _
"<CHANGE>0.277</CHANGE>" & _
"</CURRENCY>" & _
"</CURRENCIES>"
Set XDoc = New MSXML2.DOMDocument
If Not XDoc.LoadXML(strXML) Then 'strXML is the string with XML'
Err.Raise XDoc.parseError.ErrorCode, , XDoc.parseError.reason
End If
Set xNode = XDoc.FirstChild
Debug.Print strXML
Debug.Print xNode.ChildNodes(1).SelectSingleNode("RATE").Text ' also with that try i get the Object variable or With block variable not set error
End Sub
SelectSingleNode() expects an XPath expression. Try this one:
xNode.SelectSingleNode("//RATE").Text
But in general it's not very smart to access properties of an object reference that could be Nothing – like it is in the above case, if SelectSingleNode does not find any matching node, this line will trigger a run-time error ("Object variable or With block variable not set", which effectively is a null pointer exception.)
Always guard your property accesses by validating your object reference:
Set rate = xNode.SelectSingleNode("//RATE")
If rate Is Nothing Then
Debug.Print "Error: no RATE found in document"
Else
Debug.Print rate.Text
End If
FWIW, here is a complete version of the code I would use, featuring a few nice details like a custom type for currency information and the use the Sleep() function to wait for the server to return the XML document:
Option Explicit
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Public Type CurrencyInfo
Success As Boolean
LastUpdate As Date
Name As String
Unit As Double
CurrencyCode As String
Country As String
Rate As Double
Change As Double
End Type
Private Function GetXmlDoc(url As String) As MSXML2.DOMDocument60
With New MSXML2.XMLHTTP60
.Open "GET", url, False
.send
While .readyState <> 4: Sleep 50: Wend
If .Status = 200 Then
If .responseXML.parseError.ErrorCode = 0 Then
Set GetXmlDoc = .responseXML
Else
Err.Raise vbObjectError + 1, "GetXmlDoc", "XML parser error: " & .responseXML.parseError.reason
End If
Else
Err.Raise vbObjectError + 2, "GetXmlDoc", "Server responded with status code " & .Status
End If
End With
End Function
Public Function GetCurrencyInfo(currencyName As String) As CurrencyInfo
Dim curr As MSXML2.DOMDocument60
Set curr = GetXmlDoc("http://the/url/you/use?currency=" + currencyName)
GetCurrencyInfo.Success = True
GetCurrencyInfo.LastUpdate = CDate(GetText(curr, "//LAST_UPDATE"))
GetCurrencyInfo.Name = GetText(curr, "//NAME")
GetCurrencyInfo.Unit = Val(GetText(curr, "//UNIT"))
GetCurrencyInfo.CurrencyCode = GetText(curr, "//CURRENCYCODE")
GetCurrencyInfo.Country = GetText(curr, "//COUNTRY")
GetCurrencyInfo.Rate = Val(GetText(curr, "//RATE"))
GetCurrencyInfo.Change = Val(GetText(curr, "//CHANGE"))
End Function
Private Function GetText(context As IXMLDOMNode, path As String) As String
Dim result As IXMLDOMNode
If Not context Is Nothing Then
Set result = context.SelectSingleNode(path)
If Not result Is Nothing Then GetText = result.Text
End If
End Function
Usage is as follows:
Sub Test()
Dim USD As CurrencyInfo
USD = GetCurrencyInfo("USD")
Debug.Print "LastUpdate: " & USD.LastUpdate
Debug.Print "Name: " & USD.Name
Debug.Print "Unit: " & USD.Unit
Debug.Print "CurrencyCode: " & USD.CurrencyCode
Debug.Print "Country: " & USD.Country
Debug.Print "Rate: " & USD.Rate
Debug.Print "Change: " & USD.Change
End Sub
Tried this, and got somwhere.
Dim strXML As String
Dim xNode As IXMLDOMNode
Dim XDoc As MSXML2.DOMDocument
Dim xParent As IXMLDOMNode
Dim xChild As MSXML2.IXMLDOMNode
strXML = xmlString
Set XDoc = New MSXML2.DOMDocument
If Not XDoc.Load(strXML) Then 'strXML is the string with XML'
Err.Raise XDoc.parseError.ErrorCode, , XDoc.parseError.reason
End If
Set xNode = XDoc.DocumentElement
Set xParent = xNode.FirstChild
For Each xParent In xNode.ChildNodes
For Each xChild In xParent.ChildNodes
Debug.Print xChild.Text
Next xChild
Next xParent

Quickest way to determine if a remote PC is online

I tend to run a lot of commands against remote PCs, but I always check to make sure they are online first. I currently use this code:
If objFSO.FolderExists("\\" & strHost & "\c$") Then
'The PC is online so do your thing
However, when the remote PC is not online, it takes my laptop ~45 seconds before it times out and resolves to FALSE.
Is there a way to hasten the timeout? Or is there another easily implementable solution to determine if a PC is online?
You could use WMI to ping it.
Function IsOnline(strHost As String) As Boolean
Dim strQuery As String
strQuery = "select * from Win32_PingStatus where Address = '" & strHost & "'"
Dim colItems As Object
Set colItems = GetObject("winmgmts://./root/cimv2").ExecQuery(strQuery)
Dim objItem As Object
For Each objItem In colItems
If IsObject(objItem) Then
If objItem.StatusCode = 0 Then
IsOnline = True
Exit Function
End If
End If
Next
End Function
You can use the return code from a ping request:
Function HostIsOnline(hostname)
Set oShell = WScript.CreateObject("WScript.Shell")
Set oShellExec = oShell.Exec("ping -n 1 " & hostname)
While oShellExec.Status = 0
WScript.Sleep(100)
Wend
HostIsOnline = (oShellExec.ExitCode = 0)
End Function

Why is this causing a type mismatch?

I have a VB6 application that calls a Crystal Report XI Report. However when I try to change the connection info I get a type mismatch. Any help would be appreciated.
Dim Report As craxddrt.Report ' This is how Report is defined
ChangeReportTblLocation Report ' This is the function where the mismatch occurs
This is the definition of ChangeReportTblLocation:
Private Function ChangeReportTblLocation(ByRef pReport As craxddrt.Report) As Boolean
Dim ConnectionInfo As craxddrt.ConnectionProperties
Dim crxTables As craxddrt.DatabaseTables
Dim crxTable As craxddrt.DatabaseTable
Dim crxSections As craxddrt.Sections
Dim crxSection As craxddrt.section
Dim crxSubreportObj As craxddrt.SubreportObject
Dim crxReportObjects As craxddrt.ReportObjects
Dim crxSubreport As craxddrt.Report
Dim ReportObject As Object
Dim Y As Integer
Dim lsDatabase As String
On Error GoTo errHandle_CRTL
lsDatabase = GetCurrentUserRoot("SOFTWARE\COTTSYSTEMS\APP", "Database")
If lsDatabase = "" Then
lsDatabase = gConn.DefaultDatabase
End If
If lsDatabase = "" Then
lsDatabase = "frasys"
End If
With pReport
For Y = 1 To .Database.Tables.Count
Set ConnectionInfo = .Database.Tables(Y).ConnectionProperties
ConnectionInfo.DeleteAll
ConnectionInfo.Add "DSN", frasysdsn
ConnectionInfo.Add "Database", lsDatabase
'This is the Line that causes the type mismatch
.Database.Tables(Y).Location = lsDatabase & ".dbo." & Database.Tables(Y).Location
Next Y
Set crxSections = .Sections
For Each crxSection In crxSections
Set crxReportObjects = crxSection.ReportObjects
For Each ReportObject In crxReportObjects
If ReportObject.Kind = crSubreportObject Then
Set crxSubreportObj = ReportObject
Set crxSubreport = crxSubreportObj.OpenSubreport
Set crxTables = crxSubreport.Database.Tables
For Y = 1 To crxTables.Count
Set crxTable = crxTables.Item(Y)
crxTable.Location = lsDatabase & ".dbo." & crxTable.Location
Next Y
End If
Next ReportObject
Next crxSection
End With
Set ConnectionInfo = Nothing
Set crxTables = Nothing
Set crxTable = Nothing
Set crxSections = Nothing
Set crxSection = Nothing
Set crxSubreportObj = Nothing
Set crxReportObjects = Nothing
Set crxSubreport = Nothing
Set ReportObject = Nothing
ChangeReportTblLocation = True
Exit Function
errHandle_CRTL:
Screen.MousePointer = vbDefault
MsgBox err.Number, err.Description, "ChangeReportTblLocation", err.Source
End Function
I think its just a typo:
.Database.Tables(Y).Location = lsDatabase & ".dbo." & .Database.Tables(Y).Location
I've added a . before the second Database.Tables(Y).Location in this line.
This does suggest though that you aren't using Option Explicit in your code. I can't stress strongly enough how important it is to use this. It will save you lots of time looking for odd typos (like this) and save your code from doing all sorts of weird things.
try using
call ChangeReportTblLocation(Report)