VB6 IDE Runtime - Sub/Function Exits unexpectedly after an error - vb6

Previously I've noticed some instances when running an App in the IDE causes unexpected behaviour. But I've now (accidentally) found a reproducible set of circumstances that cause it to ignore error trapping (or lack of).
The code below shows the problem:
Private Sub Sub1()
On Error Resume Next
err.clear
Call Sub2
Debug.Print 10 / 0
If Err.Number <> 0 Then
Debug.Print "Found error in Sub1"
End If
Err.Clear
Call Sub2
End Sub
Sub Sub2()
' On Error Resume Net
err.clear
Debug.Print 10 / 0
If Err.Number <> 0 Then
Debug.Print "Found error in Sub2"
End If
End Sub
Sub1 calls Sub2.
I've REM'd the 'On Error Resume Next' line as if I'm debugging Sub2. But when the error is reached (Debug.print 10 / 0), instead of the IDE halting, it silently exits to the calling routine.
So if I had disabled the error trapping so that I could debug Sub2, the IDE would behave very oddly and just return the calling routine.
If I also disable the 'On Error Resume Next' in Sub1, the IDE behaves as expected and does raise an error in Sub2.
The work around is always to disable error trapping immediately before calling a Sub/Function and then to enable it again after return. But that seems a kludge. Does anyone know a 'fix' (hotfix that I've missed?).
I'm not suggesting that MS fix this (if it is a bug) - just wondering how others work round the problem.

I'm generally using Option->General->Break on All Errors: On in the IDE. When the IDE hits an error it stops and waits for my confirmation. This happens even if there is an On Error Resume Next.
If the error is accounted for I have two options:
Skip to next line manually with Ctrl+F9
Right click menu Toggle->Break on Unhandled Errors and continue with F5
The latter option's sub-menu is similar to the choices in Options dialog but is a temporary setting per debugging sessions (until IDE is restarted).
The hard part is developing with Break on All Errors. Sometimes I have to use specially crafted typelibs that alter methods signatures to return LONGs instead of HRESULTs so that VB6 does not Err.Raise but to silently fail with a (checked) retval.
Developing with Break on All Errors tends to be mandatory for any VB6 project in excess of 100k LOC. For smaller ones you can buy t-shirts with On Error Resume Next slogan and enjoy the paycheck at the end of the month :-))

Related

Inequality comparison to produces wrong result (sometimes)

Our VB6 app has a very strange control-flow problem. It appears that an inequality comparison of double values is incorrect sometimes. Furthermore, adding MsgBox calls seems to have some side effects. And lastly, there are differences between running in the IDE vs compiled, and which computer was used to run the compiler.
We cannot reproduce this outside of our app itself, but below are code snippets intended to convey the essential information.
In the first code sample, all values of d(i) are >>> 1 (around 25 million). So the second branch of the If..Then should always be taken. In the IDE, this is what happens. In the compiled EXE from one PC the second branch is only ever taken for i=1 - which is incorrect.
Code block 1:
Dim d(1 to 4) as Double
Dim result(1 to 4) as Double
' ... Some logic to set the value of d goes here
For i = 1 To 4
If d(i) < 1 Then
result(i) = 0
Else
result(i) = numerator(i) / d(i)
End if
Next
Now, if the code is modified to include MsgBox calls... everything works correctly. The second branch is taken all the time (!!)
It is as though the MsgBox calls have some side effect which negates the problem noted above.
Code block 2:
If d(i) < 1 Then
result(i) = 0
MsgBox "Took first branch, d(i) = " & CStr(d(i))
Else
result(i) = numerator(i) / d(i)
MsgBox "Took second branch, d(i) = " & CStr(d(i))
MsgBox "Some other info"
End if
The exact set of MsgBox calls is necessary. If any is eliminated, or if two are combined, the "side effect" does not occur and the inequality for i > 1 is evaluated incorrectly.
Further details:
Setting VB6 to use "no optimizations" when compiling (to native code) will fix the control flow problem.
Compiling on another PC produces an EXE which does not have the problem. The resulting EXEs are binary different (even accounting for version #s, etc.)
Running / step tracing in the IDE never reproduces the problem
This is all so strange we're starting to think "the compiler is broken".
Could there be an obscure issue in the VB6 runtime or compiler which leads to ... memory corruption? Stack corruption? Or some unknown old cached data polluting the EXE? Bad hardware on the PC that compiles wrong? These are all highly unlikely and yet I'm not sure what else to think.
Any tips to what might be going on would be welcome.
UPDATE: We're thinking the computer which compiles the incorrectly working EXE may not have VB6 SP6 on it. I'll update again if we confirm this is related.

Solving "unable to connect to the specified server" error in Diadem DataFileHeaderAccess

I am currently using Diadem to process a large amount of data.
There is a specific treatment that I must do on a large number of files. Therefore, I have a script loading each file one by one to do this every time.
The thing is, after several hours of computation, I get an error : Incorrect instruction or user command. In <DataFileHeaderAccess.VBC> (line:1328, column:5): Unable to conect to the specified server.
By this time, it will have successfully passed the portion of code where it happens several times, and if I launch it back on the file that has issues, it will not fail (not for this file at least).
Even more strange is that nothing is done remotely there, so I have no idea which server it might be talking about. And the file is ot opened elsewhere. Most of the time, it happens when I'm not even in the office.
And finally, I managed to find nothing anywhere regarding this issue, And I'm growing quite desperate to manage to solve it.
So ... Simple question ... "Help ?".
Well, let's develop it a little :
What might be the cause of this issue ?
How can I solve it ?
Here is the portion of code incriminated if it might help :
Function TryLoadGroup(sPath, sFileName, sGroupName, sNewGroupName)
Dim oDataFileHeader, oImportedGroup
Set oDataFileHeader = DataFileHeaderAccess(sPath & sFileName, "TDM", True)
Dim iLoop, bRet
For iLoop = 1 To oDataFileHeader.GroupCount
If oDataFileHeader.GroupNameGet(iLoop) = sGroupName Then
bret = True
End If
Next
oDataFileHeader.Close(False)
If bRet Then
Set oImportedGroup = DatafileLoadSel(sPath & sFileName,"TDM", sGroupName & "/*")
oImportedGroup.Item(1).Name = sNewGroupName
Set TryLoadGroup = oImportedGroup
Else
Set TryLoadGroup = Data.CreateElementList
End If
End Function
Set oDataFileHeader = DataFileHeaderAccess(sPath & sFileName, "TDM", True)
The error message just means that it is not capable to open the file.
There are some things I can think of
The file is corrupt (but this seems not to be true because you can open it)
The file is opened by DIAdem or a group of it is already loaded into DIAdem
DIAdem has run out of memory
Potentially you should put an error handler arround your inner loop
on error goto 0
' call a method
if 0 <> err.number then
LogFileWrite "Unable to insert file '" & filename & "': " & err.description
end if
on error goto 0
This will allow you to go on processing and see the error in the DIAdem Logfile later on.

Word 2010 "object error" during template load

We have recently upgraded to Office 2010 from 2003. VBScript type code that was working fine in 2003 now fails intermittently in 2010, with 'object error' or 'command failed'.
From what I've managed to work out, this appears to be the result of the Normal template still downloading/loading, despite the CreateObject call completing. When the code works, it seems that normal has loaded quickly.
Code:
Dim oWord As Object
Set oWord = CreateObject("Word.Application")
oWord.Visible = True
Set document = oWord.Documents.Open("\\networkshare\networkshare\mytemplate.dot")
The code fails on "Set document ="
I have looked for solutions to this however I haven't found any trace of people having this issue elsewhere. If I insert a delay between oWord.Visible and Set document, the issue is resolved. I'd prefer to fix this properly though, as we often deal with many hundreds of documents in one run.
I have tried to detect the completion of loading for Normal, however have been unsuccessful in this regard.
Has anyone else seen this issue and found a solution?
Many thanks
Philip
May be you should try "grab" a Word object before creating it.
Dim oWord As Object
On Error Resume Next
Set oWord = GetObject(,"Word.Application")
If oWord Is Nothing Then Set oWord = CreateObject("Word.Application")
Alternatively, disable alerts, and put the oWord.Documents.Open into a loop. For a few times with a second wait in between or until the .dot template is opened, then re-enable alerts.
Since it's on a network share, latency most likely be higher than on local storage devices. That may explain why if a wait works fine.
Depending on what the .dot template do, you might want it Visible after it is opened.
Code that was used to solve this issue:
Set oWord = CreateObject("Word.Application")
On Error Resume Next
Set oDoc = Nothing
Do While oDoc Is Nothing
Set oDoc = oWord.Documents.Open([template path])
<Wait 50ms>
Loop On Error Goto 0
Off topic, but would be useful for others with this issue:
As of Word 2010, the ActivePrinter property is now case sensitive, so you have to ensure capitalisation is the same as shown in the printers dialog.
The error Word 2010 generates when setting this property fails is "Microsoft Word: There is a printer error"

Excel Not Responding During Macro

I have a macro that runs on a continous loop 24/7. The computer will occasionally freeze but there is no error in the excel code. The code uses the following in order to run efficiently:
DoEvents
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
startagain:
'code
'calculations, alerts, and screen are updated
GoTo startagain
I also am using what I believe is an efficient method of copying and pasting (a bulk of the code is pasting values and formulas):
Length = Range("C1").Value
Set rng = Sheets("Linked Data").Range("A2:AA" & Length)
Range("A2").Value = rng.Value
I have chagned the processor priority on the computer to "high" for EXCEL.exe, I have the computer performance set to maximum performance, I have disable all un-necessary add-ins, and I have turned off autorecover saving.
Despite all of the above, the computer will sometimes freeze and become unresponsive. Does anyone know anything that can be done to improve the reliability?
Avoid Goto and use Application.OnTime Method to run a procedure repeatively.
You can also think of creating a Automation-addin which may lead to performance imporvement as its compiled code.
Kindly refer this link
You may also refer this link for performance imporvement link

Return to an already open application when a user tries to open a new instance in vb6

Suppose a user minimize my visual basic application to the taskbar notification icon. Now I want when user open a new instance, the old one should restore.
Generally, the strategy used to create a single-instance application is to add some code to the application initialization that determines whether an instance is already running. If one is, it gets a handle to its main window, passes the focus to it, and silently dies. If one is not, it continues to run and completes the rest of the initialization sequence as usual.
You'll find lots of old VB 6 articles that accomplished this by iterating through all of the top-level windows, looking for one whose caption matches the one you expect. But this is a pretty fragile solution, it doesn't take very much to throw it off.
Same deal with the App.PrevInstance property. This is very simple to use, but also very simple in its implementation. It works based on the name of the executable and looks for a running process whose name is a match. However, this is easily defeated if a user creates and renames a copy of the executable. If this is acceptable for you, you could implement this very easily by querying the App.PrevInstance property. Otherwise, you'll need to use a more robust solution.
One such possibility is to create and register a named mutex when the first instance of your application is starting up. Then, when subsequent instances try to register that same mutex, they will fail, indicating that an instance is already running. You can find instructions on using mutexes in VB 6 in the answers to this question.
A couple of important caveats to using mutexes:
You need to make sure that you call the ReleaseMutex and CloseHandle functions when your application is closed in order to release ownership of and destroy the mutex that you created.
When you are running your program in the VB 6 IDE (e.g., to debug it) and it registers a mutex, the mutex belongs to the IDE and won't be released until you close the IDE and restart it. To prevent this, you can suppress the creation of the mutex when running inside of the IDE/debugger using conditional compilation. If you take this approach, make sure to test your program outside of the debugger to be sure that the mutex-related functionality is working as expected! You should never ship something to customers that you haven't thoroughly tested.
You can find all of the VB 6 declarations for these Windows API functions by using the API Viewer program that comes bundled with your VB 6 installation.
More information about handling multiple instances of a VB 6 application is available here on Karl Peterson's site. There's also a complete example implementation in this article on VB Accelerator—focus specifically at step 2, you don't need the rest of the code.
You can often do this fairly simply using DDE in a degenerate way:
Form1.frm
Option Explicit
'This is Form1. To use as DDE source at design time we set:
' Form1.LinkMode = 1 (Source, i.e. vbLinkSource).
' Form1.LinkTopic = "Form1" (default).
'
'Note we use (hidden) Label1 on this Form as a DDE destination.
Private PrevState As Integer
Private Sub Form_LinkExecute(CmdStr As String, Cancel As Integer)
'Got a "command" so restore Form1 and accept the command.
WindowState = PrevState
Caption = "I am awake!"
Cancel = False
End Sub
Private Sub Form_Load()
PrevState = WindowState
End Sub
Private Sub Form_Resize()
If WindowState <> vbMinimized Then PrevState = WindowState
End Sub
Module1.bas
Option Explicit
Private Sub Main()
Load Form1
'After Form1 is loaded (hidden), try DDE link to possible prior copy.
With Form1.Label1
.LinkTopic = App.EXEName & "|Form1"
On Error Resume Next
.LinkMode = vbLinkManual
If Err.Number = 0 Then
On Error GoTo 0
'Link succeeded. Wake up prior copy via pushback to
'the DDE source, then unload Form1 and terminate.
.LinkExecute "Wake up!"
Unload Form1
Else
On Error GoTo 0
'Link failed, so we're 1st. Show Form1.
Form1.Show vbModal
End If
End With
End Sub

Resources