Solved

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

Posted on 2003-11-19
24
1,087 Views
Last Modified: 2007-12-19
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
 
0
Comment
Question by:knowlton
  • 13
  • 7
  • 3
  • +1
24 Comments
 
LVL 5

Author Comment

by:knowlton
ID: 9782386
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...
0
 
LVL 29

Expert Comment

by:Göran Andersson
ID: 9782432
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.
0
 
LVL 5

Author Comment

by:knowlton
ID: 9782481
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?
0
 
LVL 29

Expert Comment

by:Göran Andersson
ID: 9782482
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
0
 
LVL 5

Author Comment

by:knowlton
ID: 9782499
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.

0
 
LVL 29

Expert Comment

by:Göran Andersson
ID: 9782516
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
0
 
LVL 6

Expert Comment

by:purpleblob
ID: 9782589
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
0
 
LVL 6

Expert Comment

by:purpleblob
ID: 9782605
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 :-)
0
 
LVL 5

Author Comment

by:knowlton
ID: 9782608
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
0
 
LVL 5

Author Comment

by:knowlton
ID: 9782620
I did not know that gacutil was needed to be run for COM Interop!!!!

Okay...I'll try commenting this line out....
0
 
LVL 6

Expert Comment

by:purpleblob
ID: 9782700
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 :-)
0
 
LVL 5

Author Comment

by:knowlton
ID: 9782730
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
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 6

Expert Comment

by:purpleblob
ID: 9782745
Yippeee :-) Well done
0
 
LVL 96

Accepted Solution

by:
Bob Learned earned 400 total points
ID: 9782770
I think that you are skirting around the issue.  This is what I have taken from this discussion:

1.  .NET assembly in .COM   Look at this article:  
     Calling .NET From COM
     http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=113

2.  This is not COM Interoperability, that applies to running a COM object in a .NET assembly.

3.  The ProgID for a .NET assembly is Namespace.Object.  I don't see any reference to Namespace, so I imagine that it is being taken from the Default Namespace property of the project.

4.  RegAsm give the .NET assembly a COM-like reference in the registry.  GACUtil places a link in the Global Assembly Cache for the .NET assembly.
0
 
LVL 5

Author Comment

by:knowlton
ID: 9782809
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
0
 
LVL 5

Author Comment

by:knowlton
ID: 9782844
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";

            }

      }

0
 
LVL 5

Author Comment

by:knowlton
ID: 9782851
Does the namspace and the DLL name have to match?
0
 
LVL 6

Expert Comment

by:purpleblob
ID: 9782873
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.
0
 
LVL 5

Author Comment

by:knowlton
ID: 9782896
TheLearnedOne:

The link you provided was EXCELLENT:

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

Why can't all tutorials be this CLEAR?
0
 
LVL 6

Expert Comment

by:purpleblob
ID: 9782906
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.
0
 
LVL 5

Author Comment

by:knowlton
ID: 9782910
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).
0
 
LVL 5

Author Comment

by:knowlton
ID: 9782975
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)


0
 
LVL 6

Assisted Solution

by:purpleblob
purpleblob earned 100 total points
ID: 9782979
How odd my version doesn't seem to be creating the tlb - ah well less said the better :-)

As per the article references by TheLearnedOne you can simply prefix your class with a namespace yourself if you desire, i.e.

using System;
using System.Runtime.InteropServices;

namespace MyNamespace
{
      [ProgId("Whatsup.Doc")]
      public class MyObject
      {
            public string MyName()
            {
                  return "I am called MyObject";
            }
      }
}

Or obviously you can let the tools create the ProgId for you and as you've found out this consists of your Namespacename.Classname. I've used the ProgId attribute and it works fine.
0
 
LVL 5

Author Comment

by:knowlton
ID: 9782990
Correct.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Entity Framework is a powerful tool to help you interact with the DataBase but still doesn't help much when we have a Stored Procedure that returns more than one resultset. The solution takes some of out-of-the-box thinking; read on!
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now