I was using the MOTO BIT Mdict as my dictionary component, putting all my translations in the Application object as per the below code, and it worked fine, until the component expired 2 days ago for unknown reasons, 12 years later on.
The MOTO Bit website is not replying - so now I seek help if anyone knows how I can reprogram the code below to use with the build in asp scripting.dictionary instead. Is it possible at all?
Function Write(strID, Comment)
If ValidNumber(strID) Then
If (IsObject(Application("Translation_" & StoryCountry)) = False) OR Debugf = True Then
SET objDic = Server.CreateObject("Multi.Dictionary")
'Load the translations into the dic object
set toRs = conn.execute("EXEC dbo.GetTranslationsByCountryID " & StoryCountry)
If Not toRs.Eof Then
tRow = toRs.GetRows()
For tx = 0 To UBound(tRow, 2)
IF objDic.Exists(tRow(0, tx)) THEN
ELSE
strTranslationKey = tRow(0, tx)
strTranslationText = tRow(1, tx)
objDic.Add strTranslationKey, strTranslationText
END IF
Next
SET Application("Translation_" & StoryCountry) = objDic
End If
Set toRs = Nothing
End If
Write = Application("Translation_" & StoryCountry)(strID)
Else
Write = "Invalid"
End If
End Function
Unfortunately, Lord Svendson, using Scripting.Dictionary objects at the Application level is not allowed. When you attempt to SET Application("Translation_" & StoryCountry) = objDic, it errors for this reason. You will need to find a workaround to using Scripting.Dictionary
I'm writing a Windows Form App on VS2019 that will open an excel file and perform nested loop.
Basically, there are two lists of integer. The code is going to loop through every row to check if the value of cell A exist in any of the lists, then assign a string to cell B.
The list in the original code has around 400 elements, but I cut it down to post here. Then something interesting happens. When I run the original code with 400+ elements, it loops the row and stopped halfway, then it gives me the "Exception from HRESULT: 0x800AC472". However, when I run the codes below it has no error.
So I thought if the huge list is the problem. I wonder if any of you had met this scenario before and how you solve it.
[Update] I've added more elements to the list and tried to run it. It did throw the same exception. I also tried reducing the amount of the elements and run again and it worked without error. So I guess it's because of the amount of element.
Private Sub generateZone(ByVal worksheet As Object)
'Initialise Excel Object
xlsApp = New Excel.Application
'Open file
xlsWorkBook = xlsApp.Workbooks.Open("File location")
'Open worksheet(according to the spreadsheet)
xlsWorkSheet = xlsWorkBook.Worksheets("sheet1")
'Excel interaction setting
With xlsApp
.Visible = True
.Application.Visible = True
.DisplayAlerts = False
.EnableEvents = False
End With
Dim emZone1 As New List(Of Integer)(New Integer() {87371, 87390, 94614, 92000, 82898, 96500, 99124, 93260, 82496, 97858, 90323, 88083, 80770, 84186, 86318, 91922, 85987, 80635, 84079, 96691, 85578, 83108, 96081, 87642, 96703, 96692, 99193, 93039, 97003, 89374, 99252, 82305, 87907, 90966, 80517, 88471, 92395, 86109, 87112, 92849, 93853, 91136, 90512, 97143, 96105, 93966, 81136, 97218, 97816, 82525, 97714, 98175, 94940, 97262, 81750, 92075, 98905, 96199, 94072, 83841, 88243, 98375, 84142, 92818, 83527, 97446, 88632, 86542, 84768, 86283, 84910, 88986, 92802, 99145, 81487, 84729, 80010, 90896, 99418, 87545, 95937, 89904, 88073, 85255, 87285, 88442, 86325, 90223, 92048, 85160, 98768, 80283, 91273, 92077, 91043, 81409, 96042, 82536, 92726, 91980})
Dim emZone2 As New List(Of Integer)(New Integer() {86634, 92330, 95970, 95577, 87510, 89481, 94248, 93860, 81857, 82810, 93228, 80095, 94437, 84887, 88766, 92706, 92264, 88109, 91992, 82751, 94767, 95397, 96066, 91667, 94059, 89419, 82796, 82310, 86961, 85681, 93969, 81736, 81009, 97445, 80741, 92154, 84923, 86182, 91660, 90665, 81388, 87722, 94031, 94678, 84074, 80550, 82953, 81317, 95132, 92163})
'get last row
Dim lastRow As Integer
lastRow = worksheet.UsedRange.Rows.Count
'loop through every row
For i As Integer = 1 To lastRow
'get pronvice from column J
Dim province As String = worksheet.Range("J" & i).Value
If province = "Sabah" Or province = "Sarawak" Then
'check zone1
For Each zone1 As Integer In emZone1
If emZone1.Contains(worksheet.Range("L" & i).Value) Then
worksheet.Range("M" & i).Value = "Zone 1"
Else
'check zone2
For Each zone2 As Integer In emZone2
If emZone2.Contains(worksheet.Range("L" & i).Value) Then
worksheet.Range("M" & i).Value = "Zone 2"
' Exception from HRESULT: 0x800AC472 shows here
Else
'if not in both zone
worksheet.Range("M" & i).Value = "EM"
End If
Next
End If
Next
Else
'if not sabah and sarawak
worksheet.Range("M" & i).Value = "WM"
End If
Next
'releaseObject(xlsWorkSheet)
'releaseObject(xlsWorkBook)
'releaseObject(xlsApp)
End Sub
Not sure if this is the same but another SO post with this same error was resolved with the following answer:
"In my case, the exception was been thrown because my excel Interop tools was displaying a modal dialog (associated with a expired licence key - shame on me). If I closed the dialog (which was been displayed in the background) and then hit 'continue' in Visual Studio, the program was able to connect to the xlsx file and retrive data succesfully."
-mbmihura
Have you verified that no popups or anything are appearing?
Is your excel licensed as well?
If not this,
I would add a limit to your loop and try to find if there is a fixed number of iterations before the error, if so, then there is some default limit being imposed.
One final thought,
I have seen these interop excel calls not get properly disposed in a lot of examples which causes many excels to be stuck running in the background.
Check your task manager and ensure that isn't happening. If so, close them out and try your tests again.
I think you just need to check for empty cells before reading the value. Excel will throw an exception when the cell is empty and you try to parse it as a string
Dim xlsRange As Excel.Range = Nothing
' In your loop
xlsRange = DirectCast(xlsWorkSheet.Cells("J" & i), Excel.Range)
If xlsRange.Value IsNot Nothing Then
Dim province = xlsRange.Value.ToString()
End If
' /Loop
' always release it at the end
If xlsRange IsNot Nothing Then Marshal.ReleaseComObject(xlRange)
I still prefer loading everything into objects and operating on them after releasing all the Excel objects
I have through an API fetched my data as an XML, and I wish to cycle through nodes (there are several of the same type) and add them to certain fields/a table.
Example from the XML-file:
<HistRating
xmlns="">
<EndrAr>2020</EndrAr>
<EndrMnd>7</EndrMnd>
<Rating>A</Rating>
</HistRating>
<HistRating
xmlns="">
<EndrAr>2019</EndrAr>
<EndrMnd>6</EndrMnd>
<Rating>A</Rating>
</HistRating>
I have tried the following format (at this point the XML I need is in a string in xmlDoc xmlDoc = CreateObject("MSXML2.DOMDocument.6.0"). Fully aware that this is not a really "sexy" way to write it, but I'm new at this game:
Set nodeXML = xmlDoc.getElementsByTagName("EndrAr")
Range("G1").Value = nodeXML(1).Text
Range("H1").Value = nodeXML(2).Text
Range("I1").Value = nodeXML(3).Text
Set nodeXML = xmlDoc.getElementsByTagName("EndrMnd")
Range("G2").Value = nodeXML(1).Text
Range("H2").Value = nodeXML(2).Text
Range("I2").Value = nodeXML(3).Text
Set nodeXML = xmlDoc.getElementsByTagName("Rating")
Range("G3").Value = nodeXML(1).Text
Range("H3").Value = nodeXML(2).Text
Range("I3").Value = nodeXML(3).Text
This works great as long as all three items are there. Unfortunately that is not given. If it is a new company i.e. (3) wont exist (there is one line per year above), and I would like to either set the cell to Blank or No value or something.
The result from when I run the above code:
But if I try to add a line 4 to test what happens if value does not exists I get the following (for obvious reasons)
What I would love some help with is:
Can I by some "magic" add a ifmissing (tried it, but could not get it to work)?
Other ways to add a if variable is not found, input following into cell
Or are there a complete different way I should have solved this?
This is to add accounting data from last X available years (where X is ie 4, or less if not 4 is available) from 30 nodes.
You could use an Error trapping Function. Note in the code below we choose not to use the returned boolean.
Dim myTest as String
.
.
TryReadingXmlNode nodeXML,1, myText
Range("G1").Value = myText
.
.
Public Function TryReadingXmlNode(ByVal ipNode as object, ByVal ipIndex as Long, ByRef opText as string) as boolean
On Error Resume Next
opText=ipNode.Item(ipIndex).Text
TryReadingXmlNode=Len(opText)>0
If err.number>0 then opText="NoValue"
on Error Goto 0
End Function
Start by querying all of the HistRating elements, then loop over that collection:
Const MAX_YEARS As Long = 4
Dim ratings, rating, c As Range, i as Long
Set c= Range("A1")
Set ratings = xmlDoc.getElementsByTagName("HistRating")
For Each rating in ratings
c.offset(0, i) = rating.getElementsByTagName("EndrAr")(0).Text
c.offset(1, i) = rating.getElementsByTagName("EndrMnd")(0).Text
c.offset(2, i) = rating.getElementsByTagName("Rating")(0).Text
i = i + 1
If i >= MAX_YEARS Then Exit For 'exit if processed enough nodes
Next rating
VBA code to monitor windows process displayed in task manager.
I am trying to get the RAM usage and CPU usage of an application and add those values in excel.
i tried using WMI class as below but howerver i am getting process ID.I am unable to retrieve RAM usage and CPU usage.
Can anyone help me in this?
Sub test2()
Set objWMIService = GetObject("winmgmts:\\.\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Process where caption='excel.exe'", , 48)
For Each objItem In colItems
Sheet1.Range("d2").Value = objItem.ProcessId
Next
Set colItems = objWMIService.ExecQuery( _"SELECT * FROM Win32_PerfFormattedData_PerfProc_Process where IDProcess=" & Sheet1.Range("d2").Value, , 48)
For Each objItem In colItems
Sheet1.Range("A1").Value = "PercentProcessorTime: " & objItem.PercentProcessorTime
Next
End Sub
If you choose to go the WMI route, then you might be after the WorkingSetSize property of the Win32_Process class:
WorkingSetSize Data type: uint64 Access type: Read-only Qualifiers:
DisplayName ("Working Set Size"), Units ("bytes") Amount of memory in
bytes that a process needs to execute efficiently—for an operating
system that uses page-based memory management. If the system does not
have enough memory (less than the working set size), thrashing occurs.
If the size of the working set is not known, use NULL or 0 (zero). If
working set data is provided, you can monitor the information to
understand the changing memory requirements of a process.
And the PercentProcessorTime of the Win32_PerfFormattedData_PerfProc_Process class:
PercentProcessorTime Data type: uint64 Access type: Read-only
Qualifiers: CookingType ("PERF_100NSEC_TIMER") , Counter
("PercentProcessorTime") , PerfTimeStamp ("TimeStamp_Sys100NS") ,
PerfTimeFreq ("Frequency_Sys100NS") Percentage of time that the
processor is executing a non-idle thread. This property was designed
as a primary indicator of processor activity. It is calculated by
measuring the time that the processor spends executing the thread of
the idle process in each sample interval, and subtracting that value
from 100%. (Each processor has an idle thread which consumes cycles
when no other threads are ready to run.) It can be viewed as the
percentage of the sample interval spent doing useful work. This
property displays the average percentage of busy time observed during
the sample interval. It is calculated by monitoring the time the
service was inactive, and then subtracting that value from 100%.
But you might also want to look at the SWbemRefresher object (https://msdn.microsoft.com/en-us/library/aa393838(v=vs.85).aspx).
Skeleton VBA code for you to work with:
Dim srvEx As SWbemServicesEx
Dim xlProcSet As SWbemObjectSet
Dim xlPerfSet As SWbemObjectSet
Dim objEx As SWbemObjectEx
Set srvEx = GetObject("winmgmts:\\.\root\CIMV2")
Set xlProcSet = srvEx.ExecQuery("SELECT * FROM Win32_Process WHERE name = 'EXCEL.EXE'")
Set xlPerfSet = srvEx.ExecQuery("SELECT * FROM Win32_PerfFormattedData_PerfProc_Process WHERE name = 'EXCEL'")
For Each objEx In xlProcSet
Debug.Print objEx.Name & " RAM: " & objEx.WorkingSetSize / 1024 & "kb"
Next
For Each objEx In xlPerfSet
Debug.Print objEx.Name & " CPU: " & objEx.PercentProcessorTime & "%"
Next
These functions allow to monitor RAM and CPU usage as requested. Notice that the application name in one is case sensitive and includes the extension, in the other is case insensitive and does not include the extension.
Debug.Print ProcessCpuUsage("Excel")
Debug.Print ProcessMemoryUsage("EXCEL.EXE") / 1024
Function ProcessCpuUsage(ProcessName As String) As Double
Dim Wmi As Object, Processes As Variant, Process As Object
Set Wmi = GetObject("winmgmts:")
Set Processes = Wmi.ExecQuery("SELECT PercentProcessorTime FROM win32_PerfFormattedData_PerfProc_Process WHERE Name='" & ProcessName & "'")
For Each Process In Processes
Exit For
Next Process
ProcessCpuUsage = Process.PercentProcessorTime
End Function
Function ProcessMemoryUsage(ProcessName As String) As Double
Dim Wmi As Object, Processes As Variant, Process As Object
Set Wmi = GetObject("winmgmts:")
Set Processes = Wmi.ExecQuery("SELECT WorkingSetSize FROM Win32_Process WHERE Name='" & ProcessName & "'")
For Each Process In Processes
Exit For
Next Process
ProcessMemoryUsage = Process.WorkingSetSize
End Function
I am trying to create a class (named ClassSection) that contains a collection (named DefectCollection). It needs a function to add items to that collection but I'm having trouble making it work. I get Error 91 "Object variable or with block variable not set."
I have looked at the other answers on here, which is what got me this far, but I don't understand what I'm missing.
Here is the class module code:
Public DefectCollection As Collection
Private Sub Class_Initialise()
Set DefectCollection = New Collection
End Sub
Public Function AddDefect(ByRef defect As CDefect)
DefectCollection.Add defect [<---- error 91]
End Function
And here is the code that calls the function: ('defect' is another class, which works fine - I want each 'ClassSection' to be able to hold an unlimited number of 'defects')
Dim SC As Collection
Dim section As ClassSection
Set SC = New Collection
Dim SurveyLength As Double
For Each defect In DC
SurveyLength = WorksheetFunction.Max(SurveyLength, defect.Pos, defect.EndPos)
Next defect
SurveyLength = Int(SurveyLength)
For i = 0 To numSurveys
For j = 0 To SurveyLength
Set section = New ClassSection
section.ID = CStr(j & "-" & dates(i))
SC.Add Item:=section, Key:=section.ID
Next j
Next i
Dim meterage As Double
For Each defect In DC
meterage = Int(defect.Pos)
Set section = SC.Item(meterage & "-" & defect.SurveyDate)
section.AddDefect defect
Next defect
Thanks!
You get the error because the DefectCollection is Nothing. This is due to the fact that you mispelled the initalization method:
Private Sub Class_Initialise() '<-- it's with "Z", not "S"
Hence, the initialization of the class is never called, the object remain Nothing by default and the method fails when trying to add an object to Nothing