SAP status message error captured to automatically close - vba

I am new SAP GUI scripting. I have a question regarding to how to stop SAP GUI script running if there's any status messages captured.
I recently create SAP GUI script recording and Excel macro for automation, so far, everything works very well if there's any data collected. However if there's no data collected and will have status bar then the script will become error.
So I tried to find a way to create some code if the status error show up, the script will automatically close, but seems like I only can make it work if the error is only for "No items selected (see long text)". However there are also other few status error will shown up as well, so I'm thinking to make the status bar captured the whole error if possible.
Hopefully you guys can help me regarding this in SAP GUI scripting,
thanks.
If session.findById("wnd[0]/sbar").Text = "No items selected (see long text)" Then
Exit Sub
End If

You can check for the messagetype of the status bar. If it is E then you've got an error.
Instead checking for the text like in your code you check for the messagetype
If session.findById("wnd[0]/sbar").MessageType= "E" Then
' Whatever code is needed here
Exit Sub
End If

Related

Problem handling errors with FileSystemWatcher

To start with it has been many years since I have done much programming, probably about 15 years, in fact VB 6 was still being taught then so I'm not up to date on anything and can get lost in what I'm reading but I am trying. I'm using Visual Studio 2019 and trying to create a VB Windows Forms App that uses the FileSystemWatcher. Unfortunately the only solutions to my problem that I could find are in C#. I tried to transfer them to my app but couldn't get them to work. Actually Visual Studio wasn't happy with what I put in and wouldn't run at all, probably due to incorrect syntax.
This part of my little app is supposed to copy a file that another program creates, while the other program is running, and place the copy in another folder. It seemed simple, detect that the file had been changed and then copy the changed file. Well I came across a few problems.
The first problem is that if I create an empty file the code works most times with no problems but occassionally 2 copies of the file are created. I could live with that but.
If I replace the empty file with a larger file, the file that it is meant to copy, then it can make 3 or 4 copies and most times produces a messagebox telling me that it can't access the file because it is in use. The main program is also minimised to display the error message, which I don't want.
Even if my app is the only program running and I replace the watched file manually with the larger file I still get the file in use error, so I am assuming that the event has been triggered twice and one of them is the process that is using the file and causing the error.
If I tell the error message to cancel then my program continues and produces only 1 copy of the file. Which is what I do want.
The second problem is that the file being copied is also accessed by another program for a short period imediately after it has been changed and this also causes an extra few copies of it to be made and sometimes a file in use error message box appears, and again the main program is minimised to display the error message. I originally had other IO.NotifyFilters in place that weren't really necassary and thought that they may have been triggering the errors so I removed them, but it made no difference.
The most common error is that the file is in use but there has also been the odd "Unhandled exception has occured in your application. could not find file.". The only reason that I can think of for this error is that the file may have been renamed to a backup file and a new version created by the main program at the exact time my program tried to access it.
From what I have read the FileSystemWatcher can trigger multiple times and I presume that this is what is causing the duplicate copies from both problems.
I need my app to make only 1 copy without the error messagebox appearing as this program needs to run in the background with no user input. Essentially this part of my app is an external program to backup a file when the file changes because the main program changes this file often but only seems to back up the file every few hours.
The following code is what I have used but nothing that I have tried has caught the error so I removed the error event handler. This code was copied from something else that was similar and in C# then modified for my purpose. I thought that the {} were used for C# not VB but it seems to work and if I take them out it won't.
My code for the FileSystemwatcher is:-
WatchFile = New System.IO.FileSystemWatcher With {
.Path = Path.GetDirectoryName(strArkMapFileNamePath),
.Filter = Path.GetFileName(strArkMapFileNamePath),
.NotifyFilter = IO.NotifyFilters.LastWrite
}
' add the handler to each event
AddHandler WatchFile.Changed, New FileSystemEventHandler(AddressOf OnLastWrite)
'Set this property to true to start watching
WatchFile.EnableRaisingEvents = True
The event handler is:-
Private Sub OnLastWrite(sender As Object, e As FileSystemEventArgs)
'Copy the Save file to a new folder and rename it.
My.Computer.FileSystem.CopyFile(
strArkMapFileNamePath,
strBackupPath & "\" & strArkMapFileName & "_" &
DateTime.Now.ToString("dd.MM.yyyy_hh.mm.ss") & ".ark",
Microsoft.VisualBasic.FileIO.UIOption.OnlyErrorDialogs,
Microsoft.VisualBasic.FileIO.UICancelOption.DoNothing)
End Sub
I added an error event handler after AddHandler WatchFile.Changed, New FileSystemEventHandler(AddressOf OnLastWrite) but that did nothing.
I tried to add an on error statement before the end sub and that did nothing either, I presume because the Microsoft.VisualBasic.FileIO.UIOption.OnlyErrorDialogs, caught the error first.
I got frustrated and tried to add a statement before the Microsoft.VisualBasic.FileIO.UIOption.OnlyErrorDialogs, but it didn't like that and I didn't expect it to work.
So how do I catch the errors before the FileSystemWatcher acts on the error?
I don't know what I am doing wrong so any help would be appreciated.
Also if anybody could offer code for what I need to do can it please be code for a Windows Forms App because I don't seem to have much luck in converting C# or anything else.
Edit
I have replaced the My.Computer.FileSystem.CopyFile with the File.Copy method as suggested and added a few extra bits..
Private Sub OnLastWrite(sender As Object, e As FileSystemEventArgs)
'Verify that source file exists
If File.Exists(strArkMapFileNamePath) Then
'Copy the Save file to a new folder and rename it.
Dim i As Integer
For i = 0 To 3
Try
' Overwrite the destination file if it already exists.
File.Copy(strArkMapFileNamePath, strBackupPath & "\" & strArkMapFileName & "_" & DateTime.Now.ToString("dd.MM.yyyy_hh.mm.ss") & ".ark", True)
i = 3
' Catch exception if the file was already copied.
Catch copyError As IOException
'If copy failed reset counter
i += 1
End Try
Next
End If
End Sub
Although this shouldn't be required because this is done before the FileSystemWatcher is enabled I have added an If statement to check that the files exists before attempting to copy the file.
I'm not entirely happy with the loop but I know under normal conditions that it's not going to be an endless loop.
Is there a way to just catch the specific errors that I would need to deal with or will it be fine the way it is?
I will probably still need to work out how to stop the FileSystemWatcher from sending more than 1 event or somehow make multiple events appear as 1.
The If statement was the last thing that I added and for some reason the program now seems to only make 1 copy and appears to be faster.
The other external program that accesses the file being copied must be slower to react than my program because now it displays a message that it's waiting until my program has finished copying the file.
My program is now performing as it was intended but I believe that it is just a matter of timing rather than the correct code.

Publish an excel worksheet as an HTML file using a command button

So I have tons of data in my workbook that I need to pass on to my users in a way that allows them to interact with the workbook..., but also limits what they can actually do. So I have made it so they can access certain pages to Add needed data, then I've given access to a menu page so they can run a report.
This report I have found is best if it's an html page.
To that end, I have tried several different ways, save as...and publish. I like the publish version, but I can not for the life of me get this working. All the samples I see, appear to be the same. Here is the line of code in question:
ActiveWorkbook.PublishObjects.Add(xlSourceSheet, ActiveWorkbook.Path & ".htm, "Sheet1", "", xlHtmlStatic, "", "Report Title").Publish True
Every time I get a run time error '1004':
Method 'Publish' of object 'PublishObject' failed
I have the above line of code in a sub, am I missing something? Do I need to set up the publish differently? Thanks for any ideas.
I have had a similar mysterious problem that sometimes it (.Publish) works and sometimes it doesn't, when I try publish.
However, I think the problem might be, in cases when it doesn't work right off the bat, to first save the relevant region as a webpage so that it exists already on the server. After that region has been saved at least once (manually or else maybe with .SaveAs .. see below), then the publish might work.
Here is an example of how I get this to work more consistently, something to convey the structure that works for me:
wkb=ActiveWorkbook.Name 'save wb for later access
url="http://a.com/b.htm" 'save to Internet
sheetname="c"
Sheets(sheetname).Range("d1:e2").Select 'activating sheet may be necessary
On Error Resume Next 'anticipate error to handle it
'Now comes the publish line the first time... which may work.. or not
ActiveWorkbook.PublishObjects.Add(xlSourceRange,url,sheetname,"d1:e2",xlHtmlStatic,"blah","moreblah").Publish (True) 'may fail to create page on website if page didn't already exist
theerr=Err.Number
On Error GoTo 0 'back to default error handling (none)
If theerr <> 0 Then 'if here perhaps because page nonexistent
'msgbox "maybe add warning here [FYI]"
Sheets("dummysheetwithlittleornodata").Copy 'will create workbook
On Error Resume Next
ActiveWorkbook.SaveAs url 'may fail to create webpage first time
ActiveWorkbook.saveAs url 'twice needed for some reason sometimes. [works for me]
On Error GoTo 0
'with fresh dummy html page created, now publish should hopefully work.. let's try again
ActiveWorkbook.Close savechanges:=False 'clean up and avoid popup
Workbooks(wkb).Activate 'get back to correct wkb
Sheets(sheetname).Range("d1:e2").Select
ActiveWorkbook.PublishObjects.Add(xlSourceRange,url,sheetname,"d1:e2",xlHtmlStatic,"blah","moreblah").Publish (True) 'hopefully if failed first time, now it succeeded ! good luck.
End If
The above code structure has allowed me to solve several publish problems I was having. All the techniques together have been enough so far to allow me to save a range from a sheet as a webpage (to server I have write access to) without having to do anything manually (like a manual save or even click on popup). Good Luck.
[The different non-obvious techniques include activating a range before trying a range publish, using the error handling approach and anticipating failure at certain points, the 2x saveas to compensate for mysterious inconsistent failures when using one saveas only, closing and getting back to original workbook cleanly, and using saveas to "guarantee" page exists in form that will make publish to succeed more consistently.]

Console application - first Message Box is not focused

I am in the process of developing a VB.Net console app to get ID & password from users and should pop a message when invalid ID or password is entered, but I am stuck with a peculiar behavior observed while using Message box in console app. When the first message box is shown, its Out-Of-Focus & we explicitly need to bring the message box to focus. But the next subsequent message boxes are In-Focus.
Below is just the sample code.
Sub Main()
Start:
Console.WriteLine("Press Enter")
Console.ReadLine()
MsgBox("Good Day")
GoTo Start
End Sub
Just want to know why such thing is happening & what should be done so the first message box also will be In-Focus.?
You can use the MessageBoxOptions.ServiceNotification to show the dialog on top.
This is converted from a C# application, so not exactly sure if this is correct VB.NET (it should be though):
MsgBox( "Good Day"
, ""
, MessageBoxButtons.OK
, MessageBoxIcon.Asterisk
, MessageBoxDefaultButton.Button1
, MessageBoxOptions.ServiceNotification
)
But note this:
You shouldn't use a MessageBox inside a Console application. These are just two different worlds.
To explain why:
What do you expect when you run this application remotely using the console? There is no way to show that messagebox then. Use Console.WriteLine, but with different coloring if you want to show something is in error, or a warning, or something good.

Can I call a dialog, while other dialog is opened?

I have a macro, which is called on event SelectionChange. This macro have to check, what template is attached to the document. It is possible, that attached template doesn't exist on computer that is opening the document. I need to know, when this occurs, so I can't use ActiveDocument.AttachedTemplate (it would show simply Normal.dot, when template doesn't exist). So, I use:
Application.Dialogs(wdDialogToolsTemplates).Template
And that works fine.
But, when I try to find something in document by ctrl+F, selection is changed while searching and event fires. Macro is called, but on the line above I get an error:
This method or property is not available because the find and replace dialog box is active
So, the question is - is there a way to use this property, while the find and replace dialog box is active...? Or mabe - is there a way to check, if find and replace dialog box is active?
As I suggested in comment you could try to use On Error Resume Next to get rid of the error you have. However, I made some tests and that could be interesting for you what I have found out. You could add error handling in two ways which will have different outcomes.
'1st attempt will keep Find-Replace window and it will omit error
On Error Resume Next
Debug.Print Application.Dialogs(wdDialogToolsTemplates).Template
On Error Goto 0
'2nd attempt will close Find-Replace window and will return template name
On Error Resume Next 'this seems to be unnecessary anyway
Dim tmpDialog As Dialog
Set tmpDialog = Application.Dialogs(wdDialogEditFind)
'Find-Replace window will be closed at this stage
Debug.Print Application.Dialogs(wdDialogToolsTemplates).Template
Tried and tested for Office-Word-2010.

Intermittent error when attempting to control another database

I have the following code:
Dim obj As New Access.Application
obj.OpenCurrentDatabase (CurrentProject.Path & "\Working.mdb")
obj.Run "Routine"
obj.CloseCurrentDatabase
Set obj = Nothing
The problem I'm experimenting is a pop-up that tells me Access can't set the focus on the other database. As you can see from the code, I want to run a Subroutine in another mdb. Any other way to achieve this will be appreciated.
I'm working with MS Access 2003.
This is an intermittent error. As this is production code that will be run only once a month, it's extremely difficult to reproduce, and I can't give you the exact text and number at this time. It is the second month this happened.
I suspect this may occur when someone is working with this or the other database.
The dataflow is to update all 'projects' once a month in one database and then make this information available in the other database.
Maybe, it's because of the first line in the 'Routines' code:
If vbNo = MsgBox("Do you want to update?", vbYesNo, "Update") Then
Exit Function
End If
I'll make another subroutine without the MsgBox.
I've been able to reproduce this behaviour. It happens when the focus has to shift to the called database, but the user sets the focus ([ALT]+[TAB]) on the first database. The 'solution' was to educate the user.
This is an intermittent error. As this is production code that will be run only once a month, it's extremely difficult to reproduce, and I can't give you the exact text and number at this time. It is the second month this happened.
I suspect this may occur when someone is working with this or the other database.
The dataflow is to update all 'projects' once a month in one database and then make this information available in the other database.
Maybe, it's because of the first line in the 'Routines' code:
If vbNo = MsgBox("Do you want to update?", vbYesNo, "Update") Then
Exit Function
End If
I'll make another subroutine without the MsgBox.
I've tried this in our development database and it works. This doesn't mean anything as the other code also workes fine in development.
I guess this error message is linked to the state of one of your databases. You are using here Jet connections and Access objects, and you might not be able, for multiple reasons (multi-user environment, unability to delete LDB Lock file, etc), to properly close your active database and open another one. So, according to me, the solution is to forget the Jet engine and to use another connexion to update the data in the "other" database.
When you say "The dataflow is to update all 'projects' once a month in one database and then make this information available in the other database", I assume that the role of your "Routine" is to update some data, either via SQL instructions or equivalent recordset updates.
Why don't you try to make the corresponding updates by opening a connexion to your other database and (1) send the corresponding SQL instructions or (2) opening recordset and making requested updates?
One idea would be for example:
Dim cn as ADODB.connexion,
qr as string,
rs as ADODB.recordset
'qr can be "Update Table_Blablabla Set ... Where ...
'rs can be "SELECT * From Table_Blablabla INNER JOIN Table_Blobloblo
set cn = New ADODB.connexion
cn.open
You can here send any SQL instruction (with command object and execute method)
or open and update any recordset linked to your other database, then
cn.close
This can also be done via an ODBC connexion (and DAO.recordsets), so you can choose your favorite objects.
If you would like another means of running the function, try the following:
Dim obj As New Access.Application
obj.OpenCurrentDatabase (CurrentProject.Path & "\Working.mdb")
obj.DoCmd.RunMacro "MyMacro"
obj.CloseCurrentDatabase
Set obj = Nothing
Where 'MyMacro' has an action of 'RunCode' with the Function name you would prefer to execute in Working.mdb
I've been able to reproduce the error in 'development'.
"This action cannot be completed because the other application is busy. Choose 'Switch To' to activate ...."
I really can't see the rest of the message, as it is blinking very fast. I guess this error is due to 'switching' between the two databases. I hope that, by educating the user, this will stop.
Philippe, your answer is, of course, correct. I'd have chosen that path if I hadn't developed the 'routine' beforehand.
"I've been able to reproduce this behaviour. It happens when the focus has to shift to the called database, but the user sets the focus ([ALT]+[TAB]) on the first database. The 'solution' was to educate the user." As it is impossible to prevent the user to switch application in Windows, I'd like to close the subject.