Link to home
Start Free TrialLog in
Avatar of Tom Knowlton
Tom KnowltonFlag for United States of America

asked on

URGENT: Cause of Invalid ProgID in .NET DLL registered for COM Interop

ASP code (tomtest.asp):

<%
Set DBObj = Server.CreateObject("BFUser.BFTom")
Response.Write("From CSharp COM Object:  " & DBObj.GetNetworkLoginName())
Set DBObj = Nothing
%>

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

C# DLL code (user.dll):

using System;

      public class BFTom
      {
            public BFTom()
            {
                  //
                  // TODO: Add constructor logic here
                  //
            }

            public string GetNetworkLoginName()
            {
                  
                  //System.Security.Principal.WindowsIdentity ident = System.Security.Principal.WindowsIdentity.GetCurrent();
                  //return ident.Name;
                  return "Some cool thing";

            }

      }



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


ERROR:

The page cannot be displayed
There is a problem with the page you are trying to reach and it cannot be displayed.

--------------------------------------------------------------------------------

Please try the following:

Click the Refresh button, or try again later.

Open the localhost home page, and then look for links to the information you want.
HTTP 500.100 - Internal Server Error - ASP error
Internet Information Services

--------------------------------------------------------------------------------

Technical Information (for support personnel)

Error Type:
Server object, ASP 0177 (0x800401F3)
Invalid ProgID. For additional information specific to this message please visit the Microsoft Online Support site located at: http://www.microsoft.com/contentredirect.asp.
/tomtest.asp, line 2


Browser Type:
Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; .NET CLR 1.0.3705)

Page:
GET /tomtest.asp

Time:
Wednesday, November 19, 2003, 1:02:01 PM


More information:
Microsoft Support
 
Avatar of Tom Knowlton
Tom Knowlton
Flag of United States of America image

ASKER

Here is the process I am using to register the DLL for use by ASP 3.0:

stop web service
unregister DLL
copy in new DLL
register DLL
start web service
run test web page


BATCH FILE:

net stop w3svc
cd\
cd WINNT
cd MICROS~1.NET
cd FRAMEW~1
cd V10~1.370
gacutil -u BFUser.dll
regasm c:\winnt\system32\BFUser.dll /unregister
pause
cd\
cd WINNT
cd MICROS~1.NET
cd FRAMEW~1
cd V10~1.370
gacutil -u BFUser.dll
regasm c:\winnt\system32\BFUser.dll /unregister
pause
net start w3svc

then I go to the test ASP page and get the error above...
Avatar of Göran Andersson
You have not registered the dll. You can either register it with regsvr32 in a dos prompt:

regsvr32 c:\path\to\the\dll\user.dll

Or you can create an application for it in Component Services, and add it as a component.
GreenGhost:

Okay...but I thought under .NET you did not use regsvr32.

I thought instread you used gacutil   and    regasm   to do what regsvr32 does?
You unregister the component twice, shouldn't you register it the second time?

net stop w3svc
cd\
cd WINNT
cd MICROS~1.NET
cd FRAMEW~1
cd V10~1.370
gacutil -u BFUser.dll
regasm c:\winnt\system32\BFUser.dll /unregister
pause
cd\
cd WINNT
cd MICROS~1.NET
cd FRAMEW~1
cd V10~1.370
gacutil BFUser.dll
regasm c:\winnt\system32\BFUser.dll
pause
net start w3svc
UNREGISTER:

gacutil -u BFUser.dll
regasm c:\winnt\system32\BFUser.dll /unregister


REGISTER:
gacutil -i BFUser.dll
regasm c:\winnt\system32\BFUser.dll

I was missing the -i in the register call....

hmmm....better double-check my batch file....I think that was a typo here in EE when I posted.

But you are not using the component from APS.NET but from ASP. I don't know if gacutil and regasm works then.

I see now that the second call to gacutil should be like this:
gacutil /i BFUser.dll
Avatar of purpleblob
purpleblob

Wow, I went off for a few minutes to try this out and all of a sudden there's several answers :-)

Anyway I hadn't tried this before, so thought I'd give it a try. I had no problems whatsoever, so if I tell you what I did, then you can see if it works as per your

I created a Class library and added the following code

using System;

namespace MyNamespace
{
      public class MyObject
      {
            public string MyName()
            {
                  return "I am called MyObject";
            }
      }
}

I then open project properties and selected the Configuration Properties, build option and set Register for COM interop to True (you can also use regasm or tlbexp and then register the object yourself if you prefer but this option will do all the work for you when you build the DLL).

Okay now I created the ASP

<%
Set obj = Server.CreateObject("MyNamespace.MyObject")
Response.Write(obj.MyName)
Set obj = Nothing
%>

And that's it everything worked first time - cool.

Not sure if this helps you but it appears your TLB is/was not registered, I noticed when I used regasm one time it didn't create the TLBand hence didn't register anything - don't know if you've been using this to create the typelib.

Hope this helps
I notice you're alsoi registering your object with the GAC - this isn't required for COM interop so I've not used it - obviously you may be aware of this and registering for other purposes, but just thought I'd highlight this point :-)
GreenGhost / purpleblob:

Some very good input from both of you!!!

Give me a few minutes to digest your ideas and try a few more things (per your recommendations).

I'll be back in 10 or 15 minutes.

Tom
I did not know that gacutil was needed to be run for COM Interop!!!!

Okay...I'll try commenting this line out....
gacutil is not required for COM interop.

Basically you create the typelib using regasm (which also registers it or tlbexp (there you have to register the typelib yourself).

MS supply's a surrogate (mscoree.dll) which interacts with the .NET DLL - so you only require the typelib for your .NET DLL and this will (I assume) be late bound using mscoree.dll.

Anyway, I'm thankful to knowlton for asking the question - it forced me to look into this which is something I'd wondered about for some time :-)
Okay:

Here is my REVISED BATCH FILE:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


REM
REM  STOP WEB SERVICE
REM
net stop w3svc
pause

REM
REM  COPY IN NEW DLL...
REM
copy n:\%1.dll c:\winnt\system32
pause


REM
REM  REGISTER COM DLL
REM
cd\
cd WINNT
cd MICROS~1.NET
cd FRAMEW~1
cd V10~1.370
regasm c:\winnt\system32\%1.dll
pause

REM
REM  START WEB SERVICE
REM
net start w3svc
pause




I tried this with a BRAND NEW COM DLL called SimpleTest:



using System;

namespace SimpleTest
{
      /// <summary>
      /// Summary description for Class1.
      /// </summary>
      public class ClassTest
      {
            public ClassTest()
            {
                  //
                  // TODO: Add constructor logic here
                  //
            }

            public string Speak()
            {
                  return "Bark Bark";
            }
      }
}


NOTES:  

1)  I created a strong name for the DLL:   sn -k key.snk
2)  I set "Register for COM Interop" to TRUE before compiling.


Worked JUST GREAT the first time......


Going to test a second time here in a little bit....see if I can get BFUser.dll to work also.....



Tom
Yippeee :-) Well done
ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I made some changes to SimpleTest and ran through the process again....IT WORKS!!!!


Now....I still need to see if BFUser can be made to work...that was the original problematic DLL that prompted this question in the first place.  :)

Back in a few....

Tom
Still no luck with BFUser.DLL

here is the ASP page trying to use BFUser.DLL:

<%
Set DBObj = Server.CreateObject("BFUser.BFTom")
Response.Write("From CSharp COM Object:  " & DBObj.GetNetworkLoginName())
Set DBObj = Nothing
%>

Here is the current code for BFUser.DLL:

using System;

      public class BFTom
      {
            public BFTom()
            {
                  //
                  // TODO: Add constructor logic here
                  //
            }

            public string GetNetworkLoginName()
            {
                  
                  //System.Security.Principal.WindowsIdentity ident = System.Security.Principal.WindowsIdentity.GetCurrent();
                  //return ident.Name;
                  return "Some cool thing";

            }

      }

Does the namspace and the DLL name have to match?
Okay I've looked into the regasm util a little further as I found this didn't create my typelib and register it (well it wouldn't if it never created it :-) ). Basically the info. I found previously on using this feature of COM interop (i.e. creating COM wrappers to a .NET DLL) all states you simply type

regasm MyAssembly.dll

This appears to be incorrect as no .tlb is created, instead you need to type

regasm MyAssembly.dll /tlb

this will both create the .tlb and register it. This may have been where you were having problems previously with your batch file.
TheLearnedOne:

The link you provided was EXCELLENT:

http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=113

Why can't all tutorials be this CLEAR?
No the namespace and DLL should not have to match as this is simply a ProgID - which could be anything as long as it references the correct surrogate and typelib.

Sorry, but more on regasm, it appears that regasm with the /tlb still doesn't correctly register a tyelib - curious it appears this util is buggy. Anyway, enough about that. Using the standard tylib registation techniques will register the tylib correctly.
purpleblob:

What you say may be true....but my batch file is working just fine without the /tlb switch added to the regasm call!!!!

Go figure.

I think the problem with BFUSER.DLL is the namespace (or lack thereof).
I added the namespace back into BFUSER.DLL's C# source code like this:

using System;

namespace BFUser
{
      public class BFTom
      {
            public BFTom()
            {
                  //
                  // TODO: Add constructor logic here
                  //
            }

            public string GetNetworkLoginName()
            {
                  
                  //System.Security.Principal.WindowsIdentity ident = System.Security.Principal.WindowsIdentity.GetCurrent();
                  //return ident.Name;
                  return "Some cool thing";

            }

      }
}



And now IT WORKS!!!!!


I think the syntax in ASP 3.0 is

Set DBObj = Server.CreateObject("[namespace].[class name]")

OR

Set DBObj = Server.CreateObject("[user specified progid].[class name]")


NOT

Set DBObj = Server.CreateObject("[DLL name].[class name]")

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you use the default code when constructing a C# Class Library....the namespace DOES MATCH the DLL Name....hence my confusion when I:

1)  Deleted the namespace code
2)  Referenced the DLL name (not the namespace)


SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Correct.