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 a开发者_JAVA百科n 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.
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?
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.
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.
I can't reproduce the problem you describe... some general pointers to check:
- IF you use the default Adobe IFilter then you will see strange behaviour when running as 64 Bit or AnyCPU on a 64 Bit machine... running from VS can make a subtle difference here
- http://support.microsoft.com/kb/2018558
- http://support.microsoft.com/kb/927675/en-us
- http://social.technet.microsoft.com/Forums/en-US/sharepointsearch/thread/aa966100-17f6-4ea9-8753-085cfbe5f17a/
- http://social.technet.microsoft.com/Forums/en/sharepointsearch/thread/0f062b26-b6ad-4c18-8c33-192e2a741dec
"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?
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");
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)
精彩评论