Re: Err Object Anomaly Bug in VB6+SP5 and How to Reproduce



Here is a shorter sample that does not use CreateWindow, but uses Form1 &
Form2. Form2 is subclassed. I call this sample, Sample #2.

For those who don't know what is this about, I repeat in short: If Form2 is
subclassed and has code that references any Form1 property or method, it
will crash the application if there was any runtime error anywhere in the
project in either EXE or IDE modes. It doesn't matter what, where, and when
the runtime error occurs, it will crash the application after displaying a
weird behavior. And by weird behavior I mean these things happen in the
following sequence:

- No message box displaying the runtime error that has just occurred.
- Public variables are reset to 0. I did not test string variables.
- Form1 is destroyed and reloaded. The new window has a different hWnd.
- If there was a Set statement to create objects in Form1's Form_Load event,
an error 429: "ActiveX component can't create object" shows up.
- Application crashes.

In the sample, I am using 'Form1.Caption = "ABC"' in the subclass procedure
to reproduce this problem, but the same thing happens if you reference any
of Form1 properties and methods. For example, 'x = Form1.hWnd' will cause
this problem too, despite its simplicity.

In the real world, the subclassed window receives Winsock messages, in which
it calls RaiseEvent which has code that accesses Form1 methods and
properties. I am not accessing any Form1 methods or properties in the
subclass procedure, but I am accessing them in event procedures called by
RaiseEvent.

My objective is to find a work around without removing 'Form1.Caption =
"ABC"', nor by deferring the code to a Timer, or for MS to fix this problem.

My environment: VB6 with SP5, Windows XP Pro with SP2. The problem is
reproducible in other OS's, such as Windows 2000.

Steps to reproduce the problem(Sample #2):

- Start a new Standard EXE Project, Form1 is created by default.
- Add a new Form, Form2 is added to the project.
- Add a new Module.
- Set the Startup Object in the project's properties to "Sub Main".
- Paste the following in the general section of Form1.

' Form1 Code ================================

Option Explicit

Private Sub Form_Load()
Form1LoadCounter = Form1LoadCounter + 1
MsgBox "Form_Load called, Form1 Load Counter = " & Form1LoadCounter
End Sub

Private Sub Form_Click()
Dim a As Integer

MsgBox "Form_Click called, RecursionCounter = " & RecursionCounter

a = 1000 / 0 ' Generate a division by zero runtime error and hangs the
app

MsgBox "Form1:Form_Click: After a = 1000 / 0" ' Never show up
End Sub

- Paste the following in the general section of Form2.

' Form2 Code ================================

Option Explicit

Private Sub Form_Load()
SubClassForm Me.hwnd
End Sub

Private Sub Form_Unload(Cancel As Integer)
UnSubClassForm
End Sub

- Paste the following in the general section of Module1.

' Module1 Code ================================

Option Explicit

Private Const GWL_WNDPROC = -4
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As
Long
Private Declare Function DefWindowProc Lib "user32" Alias "DefWindowProcA" _
(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long
Private Declare Function CallWindowProc Lib "user32" Alias _
"CallWindowProcA" (ByVal lpPrevWndFunc&, ByVal hwnd&, ByVal msg&, _
ByVal wParam&, ByVal lParam&) As Long

Private m_hWnd As Long
Private m_OldProc As Long

Public Form1LoadCounter As Long
Public RecursionCounter As Long ' For FormWindowProc

Public Sub SubClassForm(ByVal h As Long)
m_hWnd = h
m_OldProc = SetWindowLong(h, GWL_WNDPROC, AddressOf FormWindowProc)
End Sub

Public Sub UnSubClassForm()
If m_OldProc <> 0 Then
m_OldProc = SetWindowLong(m_hWnd, GWL_WNDPROC, m_OldProc)
End If
End Sub

Public Function FormWindowProc(ByVal hwnd As Long, ByVal uMsg As Long, _
ByVal wParam As Long, ByVal lParam As Long)
As Long

RecursionCounter = RecursionCounter + 1 ' Entered the procedure

Form1.Caption = "ABC" ' This line is where the exception occurs

' FormWindowProc = DefWindowProc(hwnd, uMsg, wParam, lParam)
FormWindowProc = CallWindowProc(m_OldProc, hwnd, uMsg, wParam, lParam)

RecursionCounter = RecursionCounter - 1 ' Left the procedure
End Function

Public Sub Main()

MsgBox "Main called"
Form1.Show
Form2.Show

End Sub

' End of code sample ================================


- Save and compile the project.
- Run the executable from Windows Explorer.
- The application will show the following messages:

Main called
Form_Load called, Form1 Load Counter = 1

- Click on Form1, a message box shows the following:

Form_Click called, RecursionCounter = 0

This line is before the line that causes the run time error.
RecursionCounter proofs that there is no recursion in the subclassing
procedure.

- Click OK
- Instead of showing "Error 11: Division by zero" and terminating the
application, the following unexpected message appears:

Form_Load called, Form1 Load Counter = 1

Public variables now are reset to 0. The counter variable used above is of
Public type Long and it's not forced to zero anywhere. Form_Load appears to
have been reexecuted. Main() function itself is not reexecuted.

- Click OK, and the application crashes.

Again, my objective is to find a work around without removing 'Form1.Caption
= "ABC"', nor by deferring the code to a Timer, or for MS to fix this
problem.



.



Relevant Pages

  • Re: singleton class help needed (repost from vsnet.general posted the
    ... Is Form1 the object you want to share? ... > Private Sub Button1_Click(ByVal sender As System.Object, ... The following procedure is required by the Windows Form Designer ...
    (microsoft.public.dotnet.general)
  • close Form1 & open Form2
    ... I am calling finalize when form2 loads and deactivates form1 which closes ... Public Sub CloseForm ... Private Sub btnShow_Click(ByVal sender As System.Object, ...
    (microsoft.public.dotnet.languages.vb)
  • Re: Newbie help: How to detect when a worker thread ihas completed normaly
    ... Create a windows application project and add one button to Form1, ... Private Sub Button1_Click(ByVal sender As System.Object, ... On the main UI several controls are disabled and sevral variables are ...
    (microsoft.public.dotnet.languages.vb)
  • Re: Pass Data between 2 forms
    ... Here's how I open form2 from form1. ... Private Sub Button1_Click(ByVal sender As System.Object, ... > Private Sub Button1_Click(ByVal sender As System.Object, ...
    (microsoft.public.dotnet.general)
  • RE: jpgs not showing on forms
    ... Rather than embed the pictures in the database store the paths to the JPEG ... Private Sub cmdAddImage_Click ... Dim strAdditionalTypes As String, strFileList As String ... Private Sub cmdDeleteImage_Click ...
    (microsoft.public.access.gettingstarted)