2

Thanks to Timiz0r, I've solved this issue, but it's multi-step so I'm detailing the full solution here; the original question is below. First, I changed my ILS function to be simply:

Public Overrides Function InitializeLifetimeService() As Object
    Return Nothing
End Function

Then I included this in my Program as well as A. As Timiz0r pointed out, Form inherits MarshalByRefObject, so I didn't have to include a Inherits statement on my main class (which already inherited Form). This was the big thing, because I didn't include it originally. Next, I changed my AppDomain setup to be:

Dim _ADomain As AppDomain = AppDomain.CreateDomain(Name)
Dim item As New A
item = CType(_ADomain.CreateInstanceAndUnwrap(GetType(A).Assembly.FullName, GetType(A).FullName), A)

With these changes I can now use separate instances of the DLL COM object as desired.

Original Question


I am writing an application that creates a list of objects, each referring to a DLL, and each object placed in its own AppDomain to keep the instances of the DLL from interfering with each other. Taken another way:

  1. Program maintains a List(Of A)
  2. A is created as an instance of AppDomain using CreateInstanceAndUnwrap
  3. Each A refers to mirror.dll, which is including in the application's references

All of this is fine and dandy except that when setting up the Domain, the call to InitializeLifetimeService is not respected... kind of. After waiting the default 5 minutes and making a call to one of my A's, I get the RemoteException error. However, putting in some Try/Catch statements I discovered that I can reach the A in question, but it fails when it tries to RaiseEvent. In addition, it seems that the DLL object itself is dropped (or it also fails when trying to RaiseEvent, which it does often).

According to this article, the override in AppDomain should automatically create a lease that doesn't expire. So I try this:

_ADomain = AppDomain.CreateDomain(Name)
_ADomain.InitializeLifetimeService()
Dim item As A
item = CType(_ADomain.CreateInstanceAndUnwrap(GetType(A).Assembly.FullName, GetType(A).FullName), A)

No dice. According to another MSDN article, overriding InitializeLifetimeService and returning Nothing will do the same thing. So, within the A Class, I do:

<SecurityPermissionAttribute(SecurityAction.Demand, _
                                 Flags:=SecurityPermissionFlag.Infrastructure)> _
Public Overrides Function InitializeLifetimeService() As Object
    Return Nothing
End Function

Yet again, nothing happens. So, going by yet another article, I try to just set a long lease:

<SecurityPermissionAttribute(SecurityAction.Demand, _
                                 Flags:=SecurityPermissionFlag.Infrastructure)> _
Public Overrides Function InitializeLifetimeService() As Object
    Dim lease As ILease = CType(MyBase.InitializeLifetimeService(), ILease)
    If lease.CurrentState = LeaseState.Initial Then
        lease.InitialLeaseTime = TimeSpan.FromDays(5)
        lease.SponsorshipTimeout = TimeSpan.FromDays(5)
        lease.RenewOnCallTime = TimeSpan.FromDays(5)
    End If
    Return lease
End Function

Part of the problem for this seems to be that I never get A in the Initial state. But that shouldn't be an issue if I use the previous setup and always return Nothing, right? Unfortunately, there's very little out there in the way of examples for doing this kind of thing, so I may well be doing something wrong. I'm all ears for how I should approach this, the entire project is for naught if I can't get over this problem.

I should probably mention that the (third party, closed source) DLL is not serializable and is highly unlikely to inherit MarshalByRefObject. This is why I put the class into the AppDomain and not the DLL, but may be part of the problem.

This question might be related, but the setup is different from what I'm doing and it's for C#, which I'm having a tad trouble converting to VB in my head.

Community
  • 1
  • 1
Kodithic
  • 160
  • 12

1 Answers1

4

It's been a while since I've implemented something similar, but I think you need to have A, as well as the class with the event handler, inherit from MarshalByRefObject and provide an ILease that doesn't expire.

Also, just in case returning null in the InitializeLifetimeService method doesn't work after making the change stated above, here's the code I use to provide a non-expiring ILease:

Public Overrides Function InitializeLifetimeService() As Object
    Dim lease As ILease = DirectCast(MyBase.InitializeLifetimeService(), ILease)
    If lease.CurrentState = LeaseState.Initial Then
        lease.InitialLeaseTime = TimeSpan.Zero
    End If
    Return lease
End Function

I can't remember the reason I use the above code rather than returning null. I figured I would provide it just in case, though.

Timiz0r
  • 1,304
  • 7
  • 7
  • The class calling A is the main form, and I've tried to Inherit MarshalByRefObject, only to get an error that the base class "cannot be different from the base class "System.Windows.Forms.Form' of one of its other partial types" – Kodithic Feb 23 '12 at 20:00
  • Luckily, `Form` inherits from `MarshalByRefObject`. – Timiz0r Feb 23 '12 at 21:02
  • Didn't know that. But if it inherits, shouldn't the main class already have the requisite setup, then? Or would I have to do something extra to apply it? – Kodithic Feb 23 '12 at 21:11
  • Just go ahead and override `InitializeLifetimeService` and hope I don't have to delete this answer for being incorrect : – Timiz0r Feb 23 '12 at 21:21
  • Actually, turns out that's what I had to do. I made a few other changes, I'll update my main post to communicate what I did to solve. Thank you for the help! – Kodithic Feb 23 '12 at 22:15
  • Hrm, except now I'm getting highly inconsistent errors. Buffer overflows, memory issues, etc. Sometimes it happens, sometimes it doesn't, and always before the form loads so I get non-descript reports. Thoughts? – Kodithic Feb 23 '12 at 23:14
  • You can try looking at http://stackoverflow.com/a/7828214/998208 and see if you find anything. Also, are you sure you need to run `_ADomain.InitializeLifetimeService()`? – Timiz0r Feb 23 '12 at 23:19