0

I am using Implements Idisposable inside a Class object because of a callback exception being thrown during calls to a DLL inside a method in the Class. The thinking is that the Class was undergoing garbage collection too early when the DLL was still processing.

However, I found and used some code from MSDN (below) and replaced the auto-created code at the end of the class with this code and it seems to work:

#Region "IDisposable"
    '---Code entirely copied from MSDN

    Private managedResource As System.ComponentModel.Component
    Private unmanagedResource As IntPtr
    Protected disposed As Boolean = False

    Protected Overridable Overloads Sub Dispose(
        ByVal disposing As Boolean)
        If Not Me.disposed Then
            If disposing Then
                Try
                    managedResource.Dispose()
                Catch
                End Try
            End If
            ' Add code here to release the unmanaged resource.
            unmanagedResource = IntPtr.Zero
            ' Note that this is not thread safe. 
        End If
        Me.disposed = True
    End Sub

    'Private Sub AnyOtherMethods()
    'If Me.disposed Then
    'Throw New ObjectDisposedException(Me.GetType().ToString, "This object has been disposed.")
    'End If
    'End Sub

    'Do not change or add Overridable to these methods. 
    'Put cleanup code in Dispose(ByVal disposing As Boolean). 
    Public Overloads Sub Dispose() Implements IDisposable.Dispose
        '  Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

    Protected Overrides Sub Finalize()
        '  Dispose(False)
        MyBase.Finalize()
    End Sub
#End Region

There is one caveat: if after instantiating the class, I loop and wait for a global Boolean parameter to be set to true at the end of the method inside the class (which calls the DLL), then dispose the object, the callback error will appear.

Public ProcFinished As Boolean

Public Class ProcClass 
  Sub New(param1, param2, param3)
     MyMethodThatCallsDLL(param1, param2, param3)
  End Sub

  Sub MyMethodThatCallsDLL(param1, param2, param3)
    
    'Call DLL
    ReferenceName.DLLName(param1, param2, param3) 

    '...do some math...

    ProcFinished = True
  End Sub

End Class   


'...somewhere else in Project
ProcFinished = False

Dim myproc As New ProcClass(param1, param2, param3)

Do Until ProcFinished = True 'waits till Public ProcFinished is True
Loop

myproc.Dispose()  '(don't know if this is needed?)

The question is whether the myproc.Dispose() code above is required, given the IDiposable code? I cannot intepret the IDisposable code that well, but it does look like there is some trickery for assigning the class as managed code, so it doesn't get killed by GC(?)

  • 2
    Implementing IDisposable for you class means you could (maybe should) be using the Using pattern for your ProcClass instance, then calling the Dispose method is a non issue – Hursey Oct 13 '20 at 20:20
  • 1
    You have commented out `Dispose(True)` and `Dispose(False)`, so your class never performs any actions on a `Dispose`. The `unmanagedResource = IntPtr.Zero` does not look anything like cleaning up unmanaged resources either. If you uncomment them back and put a proper resource cleanup in `Dispose(ByVal disposing As Boolean)`, then your class will be ready to be Disposed. Which *should* be done with [`Using`](https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/using-statement). See https://stackoverflow.com/a/898867/11683 for a better explanation of `IDisposable`. – GSerg Oct 13 '20 at 20:39
  • 2
    The right way to fix this: "The thinking is that the Class was undergoing garbage collection too early when the DLL was still processing." Is not to implement `IDisposable`. The right way to fix it is to ensure that a reference to the class is still held while the DLL is still processing so that it won't be garbage collected. – Craig Oct 13 '20 at 21:16
  • 1
    ^ Which is performed [with `GC.KeepAlive`](https://stackoverflow.com/q/56405624/11683). Which needs to be placed [at the end of the area where the object must be alive](https://stackoverflow.com/q/20098498/11683). – GSerg Oct 13 '20 at 21:27
  • Simply using `Using myproc As New ProcClass() ...End Using` with the default generated Idisposable code at the end of the class seems to work. I understand `End Using` carries out the disposal and frees up resources for GC? –  Oct 13 '20 at 21:43
  • @GSerg, so could I add GC.KeepAlive after the call to the DLL inside the method, which is inside the Class? This makes me think IDisposable could be dropped if that works? –  Oct 13 '20 at 21:45
  • @Jimi, there is a method in the class which returns a Public Boolean when it is completed, as the OP states, it is called ProcFinished. FYI - I don't know why my class becomes eligible for GC, that's why I asked the question. Shouldn't you provide an answer, rather then a hit-and-run comment? Your statement is essentially: "you should not ask this question." Is that what I am hearing? –  Oct 14 '20 at 03:52
  • @wrktsj IDisposable is not used for keeping the object alive. You need to place the call to `GC.KeepAlive` after the last point where the dll callback can happen. – GSerg Oct 14 '20 at 06:52
  • *I loop and wait for a global Boolean parameter to be set to true*: where do you *loop and wait*? How is a dll method call setting a *global variable*? Why don't you have the obvious `dim ProcFinished = DLLMethodThatReturnsABoolean()`? The code you posted doesn't make sense. Are you initializing an instance of `ProcClass` which *automagically does something* (maybe throwing `DoEvents` in the middle)? If you simply declare an object in a scope that is left without any specific action on the local variables declared, there you have it. As mentioned, IDisposable is not meant at all to prevent GC. – Jimi Oct 14 '20 at 08:19
  • 1
    [...] It's meant to dispose of unmanaged resources that your class has created while *alive*. The standard `public Dispose()` method, calls the protected `Dispose(true)` method which is responsible (when the argument is `true`) for disposing of these disposable objects. `GC.SuppressFinalize(Me)` is meant to hint the GC that the class has already performed the necessary clean-up, it doesn't prevent the class from being disposed of (or even less finalized). -- You should post the real code that initializes this class object and the context of the operations described, which is what matters here. – Jimi Oct 14 '20 at 08:29
  • @Jimi - Thanks I'll look at your comments above in a more little detail later. For now, the `ProcFinished` is a Boolean parameter that is set to `True` at the end of the Method (inside the Class) which calls the DLL. The class is not threaded, so unfortunately, so .NET should wait until the end of the Method when `ProcFinished = True`. You can see `ProcFinished = False` before class instantiation. The loop `Do Until ProcFinished = True ... Loop` waits until the `Public` variable `ProcFinished` is `True` (at the end of the method that calls the DLL). –  Oct 14 '20 at 22:44
  • Modified the code at the end of the OP so you can see the textbook-like Class instantiation, and a Method inside the class which calls a referenced DLL. –  Oct 14 '20 at 23:03
  • Make `MyMethodThatCallsDLL` a function that returns a boolean. Call it after you have initialized your `ProcClass` class, not in the constructor of the class. Otherwise, make your `ProcClass` raise an event when the dll it calls returns its results. You can pass the dll values to a custom EventArgs object, or you could also set public properties of the `ProcClass` corresponding to the values returned. What you cannot have is a loop that pretends to be *waiting* something in an undefined context. You can also Run a Task. Many other options, except what you're using now, that's not an option. – Jimi Oct 14 '20 at 23:38
  • So I can still use the loop, but just make the loop syntax: `Do Until MyFuncThatCallsDll = True ... Loop`?, and don't use a method inside the class to call the DLL and don't go through the constructor (`Sub New ... End Sub`)? What does avoiding the Method and constructor do vs. using a simple Function that evaluates to Boolean? Skipping the constructor seems like a trick? –  Oct 16 '20 at 15:42

0 Answers0