Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Activator.CreateInstance(<guid>) works inside VSIDE but not externally

I have a bunch of COM objects which all implement the same interface, and need to create one of them as chosen at runtime from a list of options. Since I know the CLSID for each of the implementing COM servers, this should be easy. However, for a certain subset of COM libraries, I can only make this work if I'm running inside of the VS2010 IDE.

Here is the entire program I'm using to test with:

using System;

namespace ComTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var clsid = "{E8978DA6-047F-4E3D-9C78-CDBE46041603}";
            var type = Type.GetTypeFromCLSID(new Guid(clsid));
            var obj = Activator.CreateInstance(type, true);
            Console.WriteLine("Obj is {0}", obj);
        }
    }
}

I can make this work for every COM CLSID I've tried so far, as long as I run through VS2010. With or without the debugger attached, and with or without the hosting process attached, I get a System.__ComObject back from CreateInstance.

When I compile and run this code from a console window, for certain CLSID values, I instead get:

Unhandled Exception: System.Runtime.InteropServices.COMException: Creating an instance of the COM component with CLSID {E8978DA6-047F-4E3D-9C78-CDBE46041603} from the IClassFactory failed due to the following error: 80004005.
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache)
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic)
   at ComTest.Program.Main(String[] args) in 

This only happens with particular CLSIDs -- for example, "{c1243ca0-bf96-11cd-b579-08002b30bfeb}" (the built-in text IFilter) works, but "{E8978DA6-047F-4E3D-9C78-CDBE46041603}" (Acrobat Reader X's IFilter) doesn't. What I can't figure out is how being run via the IDE makes any different on wether a COM Interop call will succeed. Any ideas?

EDIT:

I'm not running VS2010 as an Administrator, but I have tried running the output binary through an elevated Powershell console and it still doesn't work.

EDIT 2:

Thus far the only COM server I've used that reproduces this "bug" is Acrobat Reader X's AroRdIf.dll (prior versions work fine). I'm not worried about getting Acrobat's specific IFilter working anymore, but I am very concerned that I have code that runs in my IDE but not outside of it. And, as an aside, the Windows SDK FILTDUMP tool has no problem loading this COM server, so I know it's possible, I just don't know how.

like image 323
Michael Edenfield Avatar asked Sep 02 '11 22:09

Michael Edenfield


3 Answers

So I spent some time testing this out, and I was able to reproduce the issue exactly as you describe. I recreated your exact console app and I see the same behavior, but I think I can at least add some new information.

At first I thought the same as you, that it was something with visual studio making it work, but that's not actually the case. If you build this into a console executable, and then launch it from explorer, it works fine with no visual studio involvement. Also I added Debugger.Launch() to the beginning so I could attach to it when run from the command prompt, and I get the error even with VS fully attached and debugging. My results all indicate that it's not VS that's making it work, it's actually running it from the command prompt that is breaking it.

I tried all kinds of stuff to make the environment the same between command prompt launching and windows explorer launching, but I get the same thing every time; works perfect from explorer and dies from command line.

Digging in with reflector, the setup is passing all of its tests and everything. It's the actual call to:

RuntimeTypeHandle.CreateInstance(this, publicOnly, noCheck, ref canBeCached, ref ctor, ref bNeedSecurityCheck);

In the RuntimeType class which is bombing out, and there's no more managed code to dig into at that point. At this point my guess is that it has to be something entirely contained in the Adobe COM Server that is killing it off when run from the command prompt.

Maybe someone who knows more about the guts of windows can speak to the differences between executing from the command line vs. explorer?

like image 190
David Hay Avatar answered Nov 15 '22 10:11

David Hay


It's probably because your application is not elevated outside of Visual Studio and is failing on permissions to interact with the COM components.

Right-click and run as administrator to see if it makes a difference.

like image 41
TheCodeKing Avatar answered Nov 15 '22 10:11

TheCodeKing


This Question is old (and answered), but I thought I would add a little information.

Adobe X (10.1.x) will fail to provide an IFilter interface under some conditions. Calls to QueryInterface, or ClassFactory->CreateInstance or ::LoadIFilter or whatever will fail with E_FAIL. The condition I'm referring to is when the process that is running is not part of a "Job".

I.e., their 10.x IFilter checks to see if the current process is in any job. If not, it fails (for me at least). My work around is something like the following psuedo-code:

HANDLE curProc = GetCurrentProcess();
BOOL bResult = FALSE;
int iResult = IsProcessInJob(curProc, NULL, &bResult);
if(iResult != 0 && bResult == FALSE) {
    HANDLE hJob = CreateJobObject(NULL,"whatever");
    AssignProcessToJob(hJob,curProc);
}

There may be side effects to this, i.e., the new job gets default security of the current user. I have more testing to do. I welcome anyone's input.

like image 42
Les Avatar answered Nov 15 '22 11:11

Les