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.
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:
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.
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.