Activator.CreateInstance()在VSIDE内部工作,但不在外部工作

我有一堆COM对象,它们都实现了相同的接口,并且需要在运行时从选项列表中创建其中一个。 由于我知道每个实现COM服务器的CLSID,因此这应该很容易。 但是,对于某个COM库的子集,如果我在VS2010 IDE中运行,我只能使这个工作。

这是我用来测试的整个程序:

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); } } } 

只要我通过VS2010运行,我就可以为迄今为止尝试过的每个COM CLSID做这项工作。 无论是否附加调试器,无论是否附加了托管进程,我都会从CreateInstance获取System.__ComObject

当我从控制台窗口编译并运行此代码时,对于某些CLSID值,我得到:

 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 

这只发生在特定的CLSID上 – 例如,“{c1243ca0-bf96-11cd-b579-08002b30bfeb}”(内置文本IFilter)有效,但“{E8978DA6-047F-4E3D-9C78-CDBE46041603}”(Acrobat) Reader X的IFilter)没有。 我无法弄清楚的是,通过IDE运行是如何使COM Interop调用成功的任何不同之处。 有任何想法吗?

编辑:

我没有以管理员身份运行VS2010,但我尝试通过提升的Powershell控制台运行输出二进制文件,但它仍然无效。

编辑2:

到目前为止,我用过的唯一一个重现这个“bug”的COM服务器是Acrobat Reader X的AroRdIf.dll(之前的版本工作正常)。 我不担心让Acrobat的特定IFilter工作了,但我非常担心我的代码在我的IDE中运行但不在其中。 而且,顺便说一句,Windows SDK FILTDUMP工具加载这个COM服务器没有问题,所以我知道它是可能的,我只是不知道如何

所以我花了一些时间来测试它,我能够完全按照你描述的方式重现这个问题。 我重新创建了你的确切控制台应用程序,我看到了相同的行为,但我想我至少可以添加一些新信息。

起初我和你一样认为,视觉工作室使它成功,但事实并非如此。 如果您将其构建为控制台可执行文件,然后从资源管理器中启动它,它可以正常工作,没有视觉工作室参与。 我还在开头添加了Debugger.Launch(),所以当从命令提示符运行时我可以附加到它,即使VS完全连接和调试我也会收到错误。 我的结果都表明它不是VS正在使它工作,它实际上是从命令提示符运行它打破它。

我尝试了各种各样的东西,使命令提示符启动和Windows资源管理器启动之间的环境相同,但我每次都得到同样的东西; 从资源管理器中完美运行并从命令行中消亡。

使用reflection器挖掘,设置正在通过所有测试和一切。 这是实际的电话:

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

在轰炸的RuntimeType类中,此时没有更多的托管代码可供挖掘。 在这一点上,我的猜测是它必须是完全包含在Adobe COM Server中的东西,它在从命令提示符运行时将其终止。

也许有人了解更多关于Windows的内容可以说明从命令行执行命令与探险家之间的区别?

这可能是因为您的应用程序未在Visual Studio外部升级,并且未能获得与COM组件交互的权限。

右键单击并run as administrator身份run as administrator ,看它是否有所作为。

这个问题很老(并且已经回答),但我想我会添加一些信息。

在某些情况下,Adobe X(10.1.x)将无法提供IFilter接口。 调用QueryInterface,或ClassFactory-> CreateInstance或:: LoadIFilter或其他任何将失败的E_FAIL。 我所指的条件是当正在运行的进程不是“作业”的一部分时。

即,他们的10.x IFilter检查当前进程是否在任何工作中。 如果没有,它失败了(至少对我而言)。 我的解决方法类似于以下伪代码:

 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); } 

可能存在副作用,即新作业获得当前用户的默认安全性。 我有更多的测试要做。 我欢迎任何人的意见。

我无法重现你描述的问题…一些检查的一般指示:

“从技术上讲,adobe提供并正确注册了PDF文本提取filterDLL(ACRORDIF.DLL),但它不会通过任何常见方式实例化,即使用LoadIFilter API或在查找filter对象CLSID后使用直接COM对象创建在注册表中。它被破坏了吗?不,因为某种程度上Windows搜索可以使用它!?有些人认为filter在STA线程模式中被删除(就像在旧的v6天中那样)但是ThreadingModel没有证实这一点。一些人谈到了只通过一个Job对象来运行它.Adobe支持让自己紧张不已,声称限制是为了我们的安全 – 咳咳 。“ …“你能猜出这个技巧是如何工作的吗?他们在PDFfilterACRORDIF.DLL中硬编码了 MS工具的名称 ,比如FILTDUMP !!!所以当实例化PDF IFilter对象时,它会检查调用进程名称,并且如果它是“白名单”中的一个,它就可以工作,否则就会出现问题和E_FAILs。诽谤。为了certificate,将你的程序重命名为“filtdump.exe”,好像通过魔法一切正常,甚至是没有作业对象的普通LoadIFilter。“

Adobe Reader是否支持PDF文本提取?

不知道那里发生了什么,但作为一种解决方法,我想知道你是否可以尝试启动这个过程…

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

然后,一旦进程运行,您可以尝试使用ProgID从运行对象表中获取对象…

 object appObj = System.Runtime.InteropServices.Marshal.GetActiveObject("THE_PROGID"); 

两个建议。

使用[STAThread]属性。

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

尝试调用CoInitialize

 [DllImport("ole32.dll")] static extern int CoInitialize(IntPtr pvRes); CoInitialize((System.IntPtr)null)