Activator.CreateInstance()在VSIDE内部工作,但在外部不起作用
本文关键字:工作 内部 不起作用 外部 VSIDE Activator guid CreateInstance | 更新日期: 2023-09-27 18:07:30
我有一堆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);
}
}
}
我可以使这个工作为每一个COM CLSID,我已经尝试过到目前为止,只要我通过VS2010运行。无论是否附加调试器,无论是否附加托管进程,我都可以从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}"(内置的文本过滤器)可以工作,但"{E8978DA6-047F-4E3D-9C78-CDBE46041603}"(Acrobat Reader X的过滤器)不能。我不能弄清楚的是,通过IDE运行对COM互操作调用是否成功有什么不同。什么好主意吗?
编辑:我没有以管理员身份运行VS2010,但我已经尝试通过提升的Powershell控制台运行输出二进制文件,它仍然不起作用。
编辑2:到目前为止,我使用的唯一COM服务器再现了这个"错误"是Acrobat Reader X的AroRdIf.dll(以前的版本工作良好)。我不担心得到Acrobat的特定过滤器工作了,但我非常担心,我有代码在我的IDE中运行,但不是在它之外。而且,顺便说一句,Windows SDK FILTDUMP工具加载这个COM服务器没有问题,所以我知道这是可能的,我只是不知道如何。
所以我花了一些时间进行测试,并且我能够完全再现您所描述的问题。我重新创建了你的主机应用程序,我看到了相同的行为,但我想我至少可以添加一些新的信息。
一开始我和你想的一样,是visual studio让它工作的,但事实并非如此。如果您将其构建到控制台可执行文件中,然后从资源管理器启动它,则无需visual studio参与即可正常工作。此外,我还在开头添加了Debugger.Launch(),这样我就可以在从命令提示符运行时附加到它,即使VS完全附加和调试,我也会得到错误。我的结果都表明,不是VS使它工作,实际上是在命令提示符下运行它破坏了它。
我尝试了各种各样的东西使环境在命令提示符启动和windows资源管理器启动之间相同,但我每次都得到相同的东西;从资源管理器工作完美,从命令行死亡。
深入反射器,设置通过了所有的测试和一切。它是对
的实际调用RuntimeTypeHandle.CreateInstance(this, publicOnly, noCheck, ref canBeCached, ref ctor, ref bNeedSecurityCheck);
在RuntimeType类中,它正在爆炸,并且那时没有更多的托管代码要挖掘。在这一点上,我的猜测是,它必须是完全包含在Adobe COM服务器中的东西,当从命令提示符运行时,它会杀死它。
也许更了解windows内核的人可以谈谈从命令行执行与资源管理器执行之间的区别?
这可能是因为你的应用程序没有被提升到Visual Studio之外,并且在与COM组件交互的权限上失败了。
右键单击run as administrator
,看看它是否有区别。
这个问题很老了(已经回答了),但是我想我应该添加一些信息。
Adobe X (10.1.x)在某些条件下将无法提供过滤器接口。调用QueryInterface,或ClassFactory->CreateInstance或::LoadIFilter或任何将失败与E_FAIL。我所指的情况是,正在运行的进程不是"作业"的一部分。
。,他们的10。x filter检查当前进程是否在任何作业中。如果没有,它就失败了(至少对我来说)。我的工作是类似下面的伪代码:
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过滤器,那么当你在64位机器上运行64位或AnyCPU时,你会看到奇怪的行为…从VS运行可以在这里产生细微的差异
- 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 - 17 - f6 - 4 - ea9 - 8753 - 085 - cfbe5f17a/
- http://social.technet.microsoft.com/forums/en/sharepointsearch/thread/0f062b26 b6ad - 4 - c18 - 8 c33 - 192 e2a741dec
"从技术上讲adobe提供并正确注册了PDF文本提取过滤器DLL (ACRORDIF.DLL),但它不会通过任何常见手段实例化,即使用LoadIFilter API或在注册表中查找过滤器对象CLSID后使用直接COM对象创建。它坏了吗?不,因为windows搜索可以用它!?有些人认为过滤器在STA线程模式下被删除了(就像它在旧的v6时代所做的那样),但这并没有得到过滤器DLL的ThreadingModel的证实。有些人谈到只通过Job对象运行它。Adobe的支持人员守口如瓶,声称限制是为了我们的安全——嗯哼。"…"你能猜到这个把戏是怎么变的吗?"他们硬编码的名称 MS工具,如FILTDUMP在PDF过滤器acrordi . dll !!因此,当PDF filter对象被实例化时,它会检查调用进程名,如果它是"白名单"中的一个,它就会工作,否则它会出现问题并E_FAILs。可耻的。为了证明这一点,将程序重命名为"filtdump.exe",就好像魔法般地一切都工作了,即使是没有作业对象的普通LoadIFilter。"
adobereader是否支持PDF文本提取?
不知道那里发生了什么,但作为一个解决方案,我想知道你是否可以尝试启动进程,如…
System.Diagnostics.Process.Start("THE_PROCESS.exe");
然后一旦进程运行,你可以尝试使用ProgID从运行对象表中获取对象…
object appObj = System.Runtime.InteropServices.Marshal.GetActiveObject("THE_PROGID");
两个建议
使用[statthread]属性
[STAThread]
static void Main(string[] args)
{...}
尝试调用CoInitialize
[DllImport("ole32.dll")]
static extern int CoInitialize(IntPtr pvRes);
CoInitialize((System.IntPtr)null)