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

7

6

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.

Dockage answered 2/9, 2011 at 22:1 Comment(10)
Are you running in medium trust or full trust environment?Premier
Or perhaps running on Windows Vista or 7 and running VS as Administrator?Endocardial
Yeah, I know Adobe "says" their IFilter "doesn't work" on Windows 7, but the IFilter test program in the Windows SDK has no problem pulling text from a PDF with the IFilter, and I can do it fine within VS, just not outside of it :\Dockage
No repro btw, works fine when I try it. The error code is miserable, E_FAIL which doesn't mean anything more than "couldn't make it work, don't know why". Not untypical for shoddy COM servers.Thaliathalidomide
Hrm. Perhaps I'll send this around to my coworkers and see how many of them get successful text reads. Perhaps it's just something broken in my environment. Thanks :)Dockage
So far, every machine in my office that I've tried does the same thing: works in VS2010, doesn't work outside :\Dockage
Works fine for me too. I have Adobe 10.0 (my AcroRdIF.dll - COM entry point - file version is 10.1.0.534), tested with VS 2008 & VS 2010, with UAC on, with Windows 7 64-bit. Have you tried to uncheck the "enable the visual studio hosting process" in the "Debug" tab of project properties, see if it changes anything?Lambency
Running inside Visual Studio isn't the problem. Running without Visual Studio is the problem.Dockage
which powershell are you trying? v1, v2? console or ISE?Stipe
Hans Passant and @Simon Mourier I couldn't reproduce the problem either, inside and out of the IDE it worked fine. FYI: The regkey on my XP system points to v9.0.0.0 of AcroRdIF.dll. Also I tried Admin and also non-admin accounts and both worked. Running Process Monitor I saw this regkey (HKCU\Software\Classes\CLSID\{E8978DA6-047F-4E3D-9C78-CDBE46041603}\InprocServer32) failed to be accessed but then this one was used: (HKCR\CLSID\{E8978DA6-047F-4E3D-9C78-CDBE46041603}\InprocServer32).. hope that helps - can you try on a PC outside your work environment?Foregoing
M
3

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?

Miyamoto answered 12/9, 2011 at 15:31 Comment(1)
Actually, this is potentially good news. The code really needs to be running from a service, but I could get away with a "hidden" windowed application if that's what it takes. I'm gonna confirm this on my end then award the bounty. Thanks!Dockage
H
3

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.

Hayton answered 2/9, 2011 at 22:56 Comment(0)
M
3

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?

Miyamoto answered 12/9, 2011 at 15:31 Comment(1)
Actually, this is potentially good news. The code really needs to be running from a service, but I could get away with a "hidden" windowed application if that's what it takes. I'm gonna confirm this on my end then award the bounty. Thanks!Dockage
S
3

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.

Shuttlecock answered 12/1, 2012 at 20:0 Comment(2)
The "answer" didn't really solve the problem so much as explained why it was happening; we just gave up on using Adobe's IFilter and purchased a toolkit so someone else could lose sleep over it :) This is interesting, though, I'll check it out.Dockage
This technique does actually work, though I then determined that IPersistFile is no longer supported - you must use IPersistStream.Socialist
D
1

I can't reproduce the problem you describe... some general pointers to check:

Dezhnev answered 11/9, 2011 at 14:43 Comment(0)
D
1

"Technically speaking adobe supplied and correctly registered the PDF text extraction filter DLL (ACRORDIF.DLL) but it wouldn't be instantiated by any common means, that is either using LoadIFilter API or using direct COM object creation after looking up the filter object CLSID in the registry. Was it broken? No, because somehow windows search could use it!? Some people argued that the filter was dropped in STA threading mode (like it did in the old v6 days) but that isn't corroborated by the ThreadingModel of the filter DLL. Some talked about running it only through a Job object. Adobe support kept themselves tight lipped and were claiming that the restriction was there for our security — ahem." ... "Can you guess how the trick works? They hard coded the names of MS tools like FILTDUMP in the PDF filter ACRORDIF.DLL!!! So when the PDF IFilter object is being instantiated, it checks the calling process name, and if it is one in the "whitelist" it works, otherwise it fakes a problem and E_FAILs. Scandalous. For proof, rename your program to "filtdump.exe" and as if by magic everything works, even plain LoadIFilter without job objects."

Does Adobe reader support PDF text extraction or not?

Durmast answered 25/10, 2014 at 8:25 Comment(0)
M
0

Not sure what is happening there but as a workaround I wonder if you might try launching the process with something like...

System.Diagnostics.Process.Start("THE_PROCESS.exe");

Then once the process is running you could try to get the object from the running objects table using the ProgID...

object appObj = System.Runtime.InteropServices.Marshal.GetActiveObject("THE_PROGID");
Menhaden answered 10/9, 2011 at 16:23 Comment(3)
These are in-process COM servers; there's no process to launch. I have tried manually loading the COM server without the Activator object but I'm guessing I'm doing exactly what it's doing because I get the same result.Dockage
I also cannot reproduce... As long as I compile as x86 your sample works.Menhaden
Doing this is a security hole unless you verify the exe is signed first.... System.Diagnostics.Process.Start("THE_PROCESS.exe");Gamogenesis
E
0

Two suggestions.

Use [STAThread] attribute.

[STAThread]
static void Main(string[] args)
{...}

Try calling CoInitialize

[DllImport("ole32.dll")]
static extern int CoInitialize(IntPtr pvRes);
CoInitialize((System.IntPtr)null)
Endocrinology answered 13/9, 2011 at 12:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.