Friday, May 2, 2008

Fixing "PRJ0050 Failed: Failed to register output"

I'm in the process of converting a COM DLL over to .Net using C++/CLR and I've been plagued with this error:

RegAsm : error RA0000 : An error occurred while writing the registration information to the registry. You must have administrative credentials to perform this task. Contact your system administrator for assistance
Project : error PRJ0050: Failed to register output. Please try enabling Per-user Redirection or register the component from a command prompt with elevated permissions.


I used Google to try and find a solution and found more confusion than solutions. The correct solution (for me) didn't appear anywhere. So here's my guide to solving this error.

There are three possible causes. Diagnosis is usually straightforward. Run Regsvr32 and try to manually register the DLL. If you see "entry-point DllRegisterServer was not found" then jump down to Disable Registration. If you see "access denied" then jump down to User Account Control. Finally, if you get "missing dependency," jump down to Missing Dependency.

User Account Control

This error is most likely to happen on Vista when you try to register a COM DLL. The reason is that, even if you are running as Administrator, you aren't really an Administrator because of User Account Control (UAC). This problem is easy to test. Enable per-user redirection in the project properties under Linker / General. Force the project to relink (make a minor change to a source file) and see what happens. If the error goes away, then you've found the problem. Amazingly enough, PROJ0050 is specifically mentioned in the documentation for the Linker Property Pages.

Other more intrusive solutions:
  • Close Visual Studio and restart it as an Administrator by right-clicking the Visual Studio icon and selecting Run as Administrator. The screen should blink and you should see the UAC prompt.
  • Always run Visual Studio as Administrator as follows. Right-click the Visual Studio icon, select Properties, go to the Compatibility tab, and enable "Run this program as an administrator."
  • Disable UAC (not recommended.)
  • Ignore the problem. It's not hurting anything.
No matter which solution you choose, make sure you test the registration of the dialog on a clean machine when you build your installer.

Disable Registration

This was the solution that applied to my problem. My project used to be a COM object written using MFC. The COM object required registration and so the project was set to register the DLL after linking. My fancy new .Net object did not require registration, so there was no "DllRegisterServer" entry point in the DLL. I fixed the problem in the project properties under Linker / General by setting Register Output to No. Make sure you do this for both Release and Debug builds.

Missing Dependency

This problem happens because your DLL is dependent on another DLL that can't be located. It's easy for this problem to happen if your DLL compiles to one directory and a dependent DLL compiles to another directory.

To diagnose this problem, use the Depends utility. Don't use the version that ships with Visual Studio, it's out of date. Download the latest version of Depends from http://www.dependencywalker.com/. When you run Depends, make sure you open the DLL that's in the target directory where the linker put it. Now look down the list in the middle pane and see what's marked with a yellow question mark. Ignore any modules with an hour glass, they are delay loaded and don't cause a problem if they are missing.

If the missing DLL is one of your DLLs, then update your path to include that DLL. Problem solved.

If the missing DLL is one of the MFC or C Runtime DLLs (which start with MSVC or MFC, respectively), then life is much more complicated. You might be having a problem with WinSxs, which means there's an error in your manifest. These problems can be nasty to fix, as I described in this post.

Finally, there was a red herring for my project when I ran Depends. The file MSVCR90D.DLL was marked as missing. I'm not sure what was causing this, but the DLL ran and loaded properly, so I'm suspicious that the problem was with Depends.

17 comments:

  1. Great post. Really helpful

    ReplyDelete
  2. The "Disable Registration" is not a real solution.
    If I have a client app required the COM registration to work, the COM registration failure would prevent the whole thing to work. Frankly, the genius at MS just love to screw people around. Can they just leave thing that worked alone?

    ReplyDelete
  3. Hello "Anonymous!" There are (at least!) two reasons why Disable Registration is very useful. First, pure .Net objects don't use COM. In my case, I had converted a C++ COM object to be a .Net object using C++/CLR. so Disable Registration was exactly the right solution.

    Even if you ignore .Net, one great reason to use Disable Registration is called Isolated COM, which allows you to use a COM object without registering it. I would strongly encourage you to use Isolated COM instead of registering your COM object in the registry. My prior post describes the advantages.

    The only place I've found where Isolated COM doesn't work is if you have to register a type library. In this case, Isolated COM doesn't solve the entire problem. (Isolated COM does not work on Win 9x either, but those versions of Windows are pretty much dead.)

    ReplyDelete
  4. I fixed the MSVCR90D.DLL missing problem with installing VS2008 SP1 and the VS2008 redistributable.
    They can be downloaded from MS. Apparently, MS forgot to test this stuff and the world does not run everything on .NET.

    ReplyDelete
  5. "Anonymous",

    While I strongly recommend installing VS2008 SP1, it's unrelated to the problem here. The only issue for me was how MSVCR90D.DLL appeared in Depends, since the component could be run without difficulty. I think there was just an issue with how Depends was handling the manifest.

    VS2008 actually can make things worse because of the painful way that Microsoft implemented the manifest for the Feature Pack and for SP1. See my earlier post.

    ReplyDelete
  6. man... you are right, all other post just confusing me. thank you for your post! :)

    ReplyDelete
  7. very helpful post...
    thanks a lot...

    ReplyDelete
  8. Many thanks...

    Best regards
    Danijel

    ReplyDelete
  9. Thank you for
    your great surpport!

    Xiongbiao luo

    ReplyDelete
  10. Thanks! Got me on the right track. Under Window 7, no matter which of your tips I appled, frustration continued. I had to launch PowerShell as administrator to get the dll registered.

    ReplyDelete
  11. PRJ0050: Failed to register output
    This error may also be caused by bad or missing resource strings in a project's resource (.rc) file. Make sure all of the .rgs files in the project have one, and only one resource string in the resource file pointing to them, and that all of the .rgs files referenced by the resource strings in the resource file exist.

    In my case: I had two resource string having the same Resource ID. Just made them different it worked.

    ReplyDelete
  12. "If the missing DLL is one of your DLLs, then update your path to include that DLL. Problem solved."
    Is there any other way apart from adding them to the PATH?

    ReplyDelete
    Replies
    1. Possible alternatives:
      1. Copy all dependent DLLs to the directory where you are registering your object.
      2. Delay Load the dependent library so it won't be loaded if you just need to register your DLL. For example, http://msdn.microsoft.com/en-us/library/hf3f62bz.aspx

      Delete