dotnet interop:
Greetings all,
I'm having a very challenging problem. We have a VB.NET middle-tier
assembly (.DLL) made up of several classes. The code needs to run
both periodically and on-demand, so we decided to use some very
simple SQL Server jobs which run VBScript code to call the assembly.
Other classes in the DLL are called by an ASP.NET application.
The assembly includes two relatively simple classes derived from the
same base class, which I will call Alpha and Bravo. There are two
SQL Server jobs, one for each class; each job calls its class'
constructor and then invokes the class' Run() method, like so:
Dim oAgent
Set oAgent = CreateObject("BrokenDLL.Alpha")
oAgent.TraceLevel = 4
oAgent.Run
Set oAgent = Nothing
The problem is that one job succeeds and one job fails, but ONLY ON
THE PRODUCTION SERVER; it works fine on my machine. The production
server is running Windows 2000 Advanced Server; I have Windows 2000
Professional.
I know that the code never reaches the Run() method in the failing
job from examining trace data.
In order to better figure out what was going on, I translated each
job's VBScript code into a JScript file to be launched by the Windows
Script Host. (JScript has better error handling than VBScript as I
recall.) One script ran successfully and one failed, as before.
This time I got an error message: "Class doesn't support Automation",
which apparently is VB/VBScript error 430.
I am surprised by the "Class doesn't support Automation" error
because the two classes are so similar; it makes no sense to me that
one class works and the other doesn't. As I mentioned, the two
classes are derived from the same base class, and in fact they both
share the same Run() method inherited from the base class. The
constructors are very similar:
Sub New()
Dim eDataType As utilities.DataType = DataType.Alpha
Dim oJob As New Job(eDataType, client.Job.JobType.FileQueuer)
MyBase.m_oJob = oJob
MyBase.m_User = _
New Authentication().GetSystemAccount(eDataType)
MyBase.m_Queue = New AlphaQueue(MyBase.m_User)
End Sub
Sub New()
Dim eDataType As utilities.DataType = DataType.Bravo
Dim oJob As New Job(eDataType, client.Job.JobType.FileQueuer)
MyBase.m_oJob = oJob
MyBase.m_User = _
New Authentication().GetSystemAccount(eDataType)
MyBase.m_Queue = New BravoQueue(MyBase.m_User)
End Sub
Originally there were no ClassInterface attributes declared for any
of the classes. After doing some reading on how the interop layer
works, I tried explicitly setting a ClassInterface attribute to
ClassInterfaceType.AutoDispatch, which is the default; that did not
fix the problem. I did "regasm /tlb" to generate a type library, and
then used the OLE View tool to look at the IDL, and the interface for
the interface class "Bravo" did have the "oleautomation" attribute.
Strange...
I have tried all the other remedies I could think of to resolve the
problem. I have of course unregistered and re-registered the DLL
with REGASM. I have rebooted the server. I have checked file and
SQL Server permissions, although the fact that one job succeeds
should indicate that that effort was a waste of time. I made sure
that the SQLSERVERAGENT service and the World Wide Web Publishing
Service were stopped when the DLL was installed.
It occurred to me early on that the registry entries for the COM
wrapper might be corrupt. The relevant registry keys follow. By the
way, there are other InprocServer32 keys pointing to older versions
of the same DLL which had been previously installed at the same
location; I understand that these registry keys aren't removed by
"regasm /unregister" by design, so that side-by-side deployment can
work. As I see it this shouldn't be a problem because the key with
the ProgID points to the key corresponding to the correct version,
and the COM object is instantiated by ProgID.
I have been wrestling with this problem for a day and a half, and I
don't know what else to check. Any help would be MUCH appreciated!
- Rob
--------------------------------
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\BrokenDLL.Bravo]
@="BrokenDLL.Bravo"
[HKEY_CLASSES_ROOT\BrokenDLL.Bravo\CLSID]
@="{E270E1DF-AC77-326D-9A92-5A3F33C773EE}"
--------------------------------
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\CLSID\{E270E1DF-AC77-326D-9A92-5A3F33C773EE}]
@="BrokenDLL.Bravo"
[HKEY_CLASSES_ROOT\CLSID\{E270E1DF-AC77-326D-9A92-5A3F33C773EE}\Implemented
Categories]
[HKEY_CLASSES_ROOT\CLSID\{E270E1DF-AC77-326D-9A92-5A3F33C773EE}\Implemented
Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}]
[HKEY_CLASSES_ROOT\CLSID\{E270E1DF-AC77-326D-9A92-5A3F33C773EE}\InprocServer32]
@="C:\\WINNT\\system32\\mscoree.dll"
"ThreadingModel"="Both"
"Class"="BrokenDLL.Bravo"
"Assembly"="BrokenDLL, Version=1.4.7.0, Culture=neutral,
PublicKeyToken=0a02e62e1ce3d396"
"RuntimeVersion"="v1.0.3705"
"CodeBase"="file:///C:/Inetpub/wwwroot/WebApp/bin/BrokenDLL.DLL"
[HKEY_CLASSES_ROOT\CLSID\{E270E1DF-AC77-326D-9A92-5A3F33C773EE}\ProgId]
@="BrokenDLL.Bravo"