I am working on code in VBA trying to determine when the next several scheduled tasks will run. I am using the Task Scheduler COM object (Schedule.Service). I can enumerate all the tasks, all their triggers, and even show the next run time by using the NextRunTime property. What I am after is the next several runtimes. Microsoft has the GetRunTimes method documented, which sounds like what I am after. But anytime I try to use the method I get the error that the object doesn't support the property method.
I have tried in VBA, VBS, and PowerShell all with the same results. I have tried on two Windows 7 PCs, Windows 2008 R2, and Windows 2012 and all have the same results. On one Windows 7 PC the Get-Member shows that method, but gives the error "Cannot find an overload for GetRunTimes". COM object browsers don't show the method either.
I have never encountered this before but I don't code all the time. It is as if Microsoft documented it but left it out. Has anyone successfully used the GetRunTimes method of the Task Scheduler object?
The error I get in VBA is
Run-time error '438': Object doesn't support this property or method
This happens as soon as it gets to the GetRunTimes line
Here is a portion of the code:
Set objTS = CreateObject("Schedule.Service")
objTS.Connect (strComputer)
Set rootFolder = objTS.GetFolder("\")
Set ColTasks = rootFolder.GetTasks(0)
If ColTasks.Count = 0 Then
tmpArray(0) = ""
Else
For Each task In ColTasks
With task
If .Name = "RebootSchedule" Then
Set triggers = task.Definition.triggers
'This next line generates the error, everything else works)
Set runtimes = .GetRunTimes("8/1/2017", "9/1/2017")
...
Related
Working in VB/VBA, I have a window handle and I need to convert it to a window object/instance which I can use to access the window object's properties.
AccessibleObjectFromWindow has not proven useful.
How do I do this?
Update
Below is additional detail.
I am working with a window created using mshta.exe and configured with some scripts:
CreateObject("WScript.Shell").Run "%systemroot%\syswow64\mshta.exe about:""<head><script>moveTo(-32000,-32000);document.title='" & x86WindowSignature & "'</script><hta:application showintaskbar=no /><object id='shell' classid='clsid:8856F961-340A-11D0-A96B-00C04FD705A2'><param name=RegisterAsBrowser value=1></object><script>shell.putproperty('" & x86WindowSignature & "',document.parentWindow);</script></head>""", 0, False
For Each Window In CreateObject("Shell.Application").Windows
On Error Resume Next
Set Getx86Window = Window.GetProperty(x86WindowSignature)
Error = Err.Number
On Error GoTo 0
If Error = 0 Then Exit For
Pause 0.01, True
Next Window
' Configure the window environment - global object variables are defined, one for each scripting object - they are instantiated by calling the Initialize routine
Getx86Window.execScript "var VBScript, JScript;"
Getx86Window.execScript "Sub Initialize() : Set VBScript = CreateObject(""MSScriptControl.ScriptControl"") : VBScript.Language = ""VBScript"" : Set JScript = CreateObject(""MSScriptControl.ScriptControl"") : JScript.Language = ""JScript"" End Sub", "VBScript"
' Initialize the window environment
Getx86Window.Initialize
x86WindowSignature is a function that returns a unique string or key.
I'm going through this process because Microsoft doesn't provide 64-bit versions of the VBScript and JScript engines and this process allows me to create 32-bit versions and use them from a 64-bit world.
To reuse this scripting container I need to look at the existing windows and query one of the properties I created:
Set Getx86Window = Window.GetProperty(x86WindowSignature)
Normally I use this logic to find the window of interest:
' Look for an existing window
For Each Window In CreateObject("Shell.Application").Windows
On Error Resume Next
Set Getx86Window = Window.GetProperty(x86WindowSignature)
Error = Err.Number
On Error GoTo 0
If Error = 0 Then Exit Function
Next Window
But, if the application crashes or otherwise fails to close the scripting window, it remains open but is not listed with CreateObject("Shell.Application").Windows.
But I can find it using FindWindow:
WindowHandle = API_FindWindow("HTML Application Host Window Class", x86WindowSignature)
I'm stuck trying to convert the window handle to a VB/VBA "Window" object variable.
I tried a simple copy memory from the handle variable to the object variable but that failed.
It turns out I made an incorrect observation in my initial work. I thought that I was not getting all the windows returned to me that I had created. That is not true. This line:
CreateObject("Shell.Application").Windows
always returns all the windows that were created by Shell.Application. So I had at my disposal all the windows my application had created in the past.
When I posed my question, I thought that I could only get those "lost" window objects by using lower level Windows SDK calls and then somehow convert those hWnds into Shell.Application window object references. I never did figure out how to do that or if it is even possible but that need is no longer required.
I've got an issue with a piece of VBA code that runs fine on a windows 7 machine, but doesn't work on windows 10. My VBA skills aren't good enough to figure this one out.
This part of the code in run in a Excel class and is used to load a xml file and return the xml as a class.
Public Function GetDomNodeList(ByRef log As Logger) As MSXML2.IXMLDOMNodeList
Dim domdocument As New MSXML2.DOMDocument60
'Open file for handling
domdocument.async = False
domdocument.Load (strThisFilePath)
'Call the helper sub to do the actual work:
Set GetDomNodeList = domdocument.childNodes
End Function
When debugging it tells me there is a type mismatch. I've tried to debug the issue, but I'm running short on knowledge here. My main question is why this works on windows 7 and why not on windows 10 running the same office version (2016) VBA7.1
After a lot of trials I found a solution. Export the class, remove it and import the class again and all magically works again. I'm baffled by this.
I have a VB.net program that I wrote and have used hundreds of times. Whilst using Windows 7 I "upgraded" to Office 2010 and IIRC had to make a few small changes to get it to work. I have now (and again I put it in quotes as I fail to see the benefits of calling it an upgrade !) "upgraded" to Windows 10 but went back to Office 2007 as I much prefer it. I am also using Visual Studio Community 2015. All of that may or may not be of help !!!
So, I run the program and it fails with the following error :
An unhandled exception of type
'System.Runtime.InteropServices.COMException' occurred in
KA_Newsletter.exe
Additional information: Word cannot open this document template.
(L:...\Customize Ribbon Example 2.dotm)
I have looked up the error and there is a Microsoft page ...
MS Support Bug
... that suggests this may be a Bug, it explains why it may be happening and gives a resolution but I program for fun, I'm not an expert in VB at all and it may as well be written in Russian for all it helps me !!!
I also have no idea why Word should be trying to open that Example Template either, I copy a Template of my own to create a new Word document, this is pretty basic stuff !!! This is the relevant code, any help would be very much appreciated ...
Dim myNewsLetter As String
.
.
.
If File.Exists(myNewsLetter) Then
'do nothing
Else
myTemplate = myTempFolder & "KA_Newsletter.doc"
File.Copy(myTemplate, myNewsLetter)
Create_Blank_Newsletter()
End If
.
.
.
Private Sub Create_Blank_Newsletter()
myMSWord = New Word.Application
myMSDoc = myMSWord.Documents.Open(myNewsLetter) << <Error occurs on this line
myMSWord.WindowState= Word.WdWindowState.wdWindowStateNormal
myMSWord.Visible= False
UPDATE :
Olaf, I updated the code as follows ...
myMSWord = New Word.Application
Dim inval As Object
'Marshal the object before passing it to the method.
inval = New System.Runtime.InteropServices.DispatchWrapper(myNewsLetter)
myMSDoc = myMSWord.Documents.Open(inval)
'myMSDoc = myMSWord.Documents.Open(myNewsLetter)
... but I am getting a similar error on the Open statement ...
An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in KA_Newsletter.exe
Additional information: Type mismatch. (Exception from HRESULT: 0x80020005 (DISP_E_TYPEMISMATCH))
Any ideas ?
The MS page says you should try something like
Dim inval As Object
'Marshal the object before passing it to the method.
inVal = New System.Runtime.InteropServices.DispatchWrapper(myNewsLetter)
myMSDoc = myMSWord.Documents.Open(inval)
I have a Word .dot file which works in older versions of Word but fails with error 432 when run in Word 2013.
When I debug the code I have the line:
Load customerForm
And VBA shows the error:
Run-time error '432': File name or class name not found during Automation operation
The project "pennyscode" includes "Module1" which contains the function being debugged, "ThisDocument" and a form called "customerForm".
I have tried changing the name to "pennyscode.customerForm" but this doesn't make any difference.
This code is being called from a Sub function which is called from Document_New().
Updates
I can place a breakpoint on the Load customerForm line and demonstrate that it is the line that is causing the problem. If at this point I mouse over the word "customerForm" VBA comes up with
customerForm = <Object variable or With block variable not set>
If I delete/skip the Load line then the next line is customerForm.Show and that produces the same error.
If I just open the .dotm file and then use Alt-F11 to open VBA, I can look at the code for selectCustomer, list properties/methods and customerForm appears in the list.
Additional Note
I believe that within the Load function it must be calling GetObject and it is this that is failing. It is as if VBA can't find the customerForm object even though it appears in the project.
I've posted the full code of the function being called from Document_New below.
Sub selectCustomer()
Dim Doc As Document
Set Doc = Application.ActiveDocument
If Doc.CustomDocumentProperties.Item("Customer") = "Nothing" Then
Load customerForm
customerForm.Show
Unload customerForm
Doc.Fields.Update
a$ = Doc.CustomDocumentProperties.Item("InvoiceNumber")
a$ = customerForm.pathBox.Value + "\" + a$
Doc.SaveAs (a$)
End If
End Sub
I've also posted the full .dotm (Excel 2013) and .dot (previous excel) and some sample data (.xls) here:
Dropbox/Public/Invoice 2015-16.dotm
Dropbox/Public/Invoice 2015-16.dot
Dropbox/Public/data.xls
Update
I've not had much luck making progress on this question. Can anyone suggest an approach to investigating this? Or how I might improve the information on the question?
I finally managed to fix this, and I have a few learnings.
Firstly the debugger shows the error as occurring on the Load customerForm line, but this is actually not the case.
The customerForm has an _Initialize function which loads data into it before it is displayed. This function was failing with but the debugger stops on the wrong place.
I was able to debug this more effectively by putting a breakpoint on the start of the _Initialize sub and then stepping through the code.
Once I had discovered this I realized that the code was failing to find the XLSX file due to a wrong path, thus causing the run-time error.
Once I'd fixed up all the paths, I then hit a second error: runtime error '9' which is a subscript problem. This also reported on the Load customerForm line and was also due to a problem with the _Initialize function.
This was the true source of the problem, and demonstrated a functional change between Office 2013 and previous versions of Office.
My code was opening an XLSX file and attempting to read data from it:
Dim myXL As Object
Dim myWS As Object
Set myXL = GetObject("C:\Test\data.xlsx")
myXL.Application.Visible = True
myXL.Parent.Windows(1).Visible = True
Set myWS = myXL.Application.Worksheets("Customers")
The run-time error 9 was due to the index of the Windows property, as their were no windows. In previous versions of Office, there was a single window, with 2013 the array is empty.
After much messing about I tried adding this line:
myXL.Activate
before accessing the Windows() array. Once that was executed Windows(1) existed and the code worked as before.
Hope this can help someone else struggling with similar problems.
Recently, my Access .mdb database started intermittently not allowing Access (both Access 2003 and 2007) to quit. If I quit (whether by pressing the X button or from the menu, then it closes the database and appears to exit Access, as well, but then it suddenly reappears (without any database open). The only way for me to exit at that point is from the task manager.
There are two significant changes that I did recently that might be related. 1) I started using the WinSCP .Net assembly to access an ftp server, which I had to install and register for COM from the instructions here. 2) I started using ODBC, first as a linked table, and then from VBA ADO code (see this). I doubt that this second change is causing this problem because I've had the problem both when I was using the linked tables and when with ADO.
This doesn't happen every time I open the database, and I haven't noticed a pattern. What could be causing this strange problem?
Edit - I found the root of the problem. By breaking my ftp download code at various points and seeing whether it will exit, I narrowed it down to the following:
Dim PDFFolders As Recordset
Set PDFFolders = CurrentDb.OpenRecordset("PDFFolders")
Dim syncOptions As TransferOptions
Set syncOptions = New TransferOptions
syncOptions.filemask = "*/*.pdf"
On Error Resume Next 'In case it doesn't exist
Do While Not PDFFolders.EOF
sess.SynchronizeDirectories SynchronizationMode_Local, info!RTFFolder, _
info!BasePDFFolder & "/" & PDFFolders!Name, False, , , _
syncOptions
PDFFolders.MoveNext
Loop
PDFFolders.Close
Set syncOptions = Nothing
Set PDFFolders = Nothing
On Error GoTo 0
If it runs the sess.SynchronizeDirectories statement, then access won't exit, otherwise it does. Looks to me like a bug win WinSCP.
I can do other things like downloading files, creating directories, etc. with no problem, but when it gets to this statement, it doesn't exit access afterwards.
Sticky instances of Access usually result from hanging object references.
If Access hangs the way you described, I would suspect a nasty circular reference.
To investigate on circular references, you basically have two options:
Inspect your code on circular dependencies - That might become tedious and not so easy. But if you know your code base deeply, you might have suspects where to look first.
Add logging to your code - In case you cannot spot the problem via inspection alone, you can consider adding consequent logging of object creation/deletion (through Class_Initialize/Class_Terminate). For larger code bases using classes heavily, this is a good investment to start with.
If your problem is with classes where you cannot control the code (as is your case), you might consider using that external classes only through wrapper classes where you can log creation/deletion. Of course in tricky cases, termination of the wrapper class does not mean termination of the wrapped class.
BTW, I strongly recommend to make sure to set every object reference explicitly to Nothing ASAP:
Set MyObj = GetMyObject()
' Proceed with coding here later
' First write the following line
Set MyObj = Nothing
Special thoughts have to be given in the case of local error handling to make sure to set the reference to Nothing in either case.
A good way to ensure this is using a With-block instead of an explicit variable (if the usage pattern allows to):
With GetMyObject()
' Use the object's members here
End With
With this pattern you save declaring the local variable and can be sure that the object reference does not survive the current method.
I still think it's a bug in WinSCP, but I found a workaround. I noticed that it only happened if I took the information from a table in the database, and not if I put in a hard-coded string. So I just added & vbNullString, which concatenates a blank string, which changes the data type from a Field to a String, and now it doesn't happen anymore.