COM不能启动Out-of-process .Net服务器编译为AnyCPU

我试图让COM启动我的进程外的.NET COM服务器。 如果服务器进程是用x64编译的,但是如果我使用AnyCPU(这是我想要的),那么它会挂起一段时间,并最终以0x80080005(CO_E_SERVER_EXEC_FAILURE)失败。 我怎样才能使这个工作?

  • 我在64位计算机上运行:使用Visual Studio 2008 SP1的Windows 7。
  • 我可以看到在任务pipe理器,它确实启动我的服务器。 所以我想问题是在COM和服务器之间的通信(类注册)。
  • 我的testing客户端应用程序是用C#编写的,但不pipe它是为x86还是x64编译的。 用32位C ++编写的东西也会出现问题。
  • 如果我使用x64重build服务器并运行它,然后重build为AnyCPU,则COM可以启动它。 重启将使我回到原来的情况。 也许COM预先不知道要使用的位数,而以前的执行是有帮助的。
  • 我find了Andy McMullen的博客文章,并尝试将CLSCTX_ACTIVATE_64_BIT_SERVER传递给CoCreateInstance(),但是之前触发了一个失败:0x80040154(REGDB_E_CLASSNOTREG)。 我在COM注册中做错了什么? 你可以在下面看到,这很简单。 当以64位运行时会发生注册,并且当客户端是64位时会发生问题,所以不应该涉及Wow6432Node。

另一个人也有类似的问题 ,但MSFT的答案是混乱的。 他似乎暗示它只能通过DCOM(请参阅链接)或COM +工作。 我怀疑要么会是一个非常多的工作,而且比分配我的.exe作为x64和x86构build更差。

您可能想知道为什么我正在实施IPersistFile。 这是因为我真正的问题是从一个32位的C ++程序工作到我的AnyCPU .Net程序的BindMoniker()。 我已经减less了我的问题到这里提出的更简单的例子。

这里是客户端代码:

public partial class Form1 : Form { public Form1() { InitializeComponent(); } [DllImport("ole32.dll", ExactSpelling = true, PreserveSig = false)] [return: MarshalAs(UnmanagedType.Interface)] static extern object CoCreateInstance( [In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid, [MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, CLSCTX dwClsContext, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid); [Flags] enum CLSCTX : uint { CLSCTX_LOCAL_SERVER = 0x4, CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000, } private void Form1_Load(object sender, EventArgs e) { IPersistFile pf = (IPersistFile)CoCreateInstance( new Guid("1984D314-FC8D-44bc-9146-8A13500666A6"), null, CLSCTX.CLSCTX_LOCAL_SERVER, new Guid("0000010b-0000-0000-C000-000000000046")); // IPersistFile pf.Load("c:\\bozo", 0); } } 

这里是服务器:

 static class Program { [STAThread] static void Main() { if (Environment.CommandLine.Contains("/reg")) { RegistryKey cls = Registry.LocalMachine.CreateSubKey(String.Format( "SOFTWARE\\Classes\\CLSID\\{0}", PersistFile.ClassID.ToString("B"))); cls.SetValue("InprocHandler32", "Ole32.dll"); RegistryKey ls32 = cls.CreateSubKey("LocalServer32"); ls32.SetValue(null, '"' + Application.ExecutablePath + '"'); ls32.SetValue("ServerExecutable", Application.ExecutablePath); } Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); RegistrationServices reg = new RegistrationServices(); reg.RegisterTypeForComClients( typeof(PersistFile), RegistrationClassContext.LocalServer, RegistrationConnectionType.MultipleUse); Application.Run(new Form1()); } } [ComVisible(true), Guid("1984D314-FC8D-44bc-9146-8A13500666A6"), ClassInterface(ClassInterfaceType.None)] public class PersistFile : IPersistFile { public static Guid ClassID { get { GuidAttribute a = (GuidAttribute)typeof(PersistFile).GetCustomAttributes(typeof(GuidAttribute), false)[0]; return new Guid(a.Value); } } #region IPersistFile public void GetClassID(out Guid pClassID) { MessageBox.Show("GetClassID"); pClassID = ClassID; } public int IsDirty() { MessageBox.Show("IsDirty"); return 1; } public void Load(string pszFileName, int dwMode) { MessageBox.Show(String.Format("Load {0}", pszFileName)); } public void Save(string pszFileName, bool fRemember) { MessageBox.Show("Save"); throw new NotImplementedException(); } public void SaveCompleted(string pszFileName) { MessageBox.Show("SaveCompleted"); throw new NotImplementedException(); } public void GetCurFile(out string ppszFileName) { MessageBox.Show("GetCurFile"); throw new NotImplementedException(); } #endregion } 

尝试使用RegistrationServices类来注册您的com程序集。 它也将选择正确的注册表修改,并做一些其他的事情。

例:

 Assembly currentAssembly = Assembly.GetExecutingAssembly(); System.Runtime.InteropServices.RegistrationServices regAsm = new System.Runtime.InteropServices.RegistrationServices(); bool isRegistered = regAsm.RegisterAssembly(currentAssembly, System.Runtime.InteropServices.AssemblyRegistrationFlags.SetCodeBase); 

此外,我认为,.NET客户端程序集根据.NET COM服务器有一些麻烦,但我找不到任何资源…

希望,这将有助于…

我想这个问题是在运行时。 我已经创建了一个COM服务器,使用C ++库进行注册(注册完美无瑕)。 从.NET(CS)切换到AnyCPU时遇到问题。

架构:

  • 连接COM的C ++库(在x64和x86平台上构建)
  • .NET库封装(CS)(正确实例化所需的x64 / x86 C ++库)
  • .NET应用程序(CS) – COM客户端或COM服务器

注册构建为“AnyCPU”的.NET应用程序时会发生丑陋的事情。 一旦COM客户端通过DCOM调用COM服务器,服务器应用程序启动,但客户端收到COM服务器无法启动的错误。

我又进了一步,用procmon和其他工具分析了注册数据,得出了同样的结论:

  • x86在CLASSES \ Wow6432Node中注册这些类
  • x64和AnyCPU注册CLASSES中的类(在x64 windows机器上,完全相同的密钥;我敢打赌,x86和AnyCPU将在x86机器上注册相同)

现在,我做了更多的实验:x86 / x64 / AnyCPU COM客户端可以连接到任何x86 / x64 COM服务器没有问题,但它不能连接任何AnyCPU COM服务器…

然后我执行了以下测试用例:

  1. 有x86 COM服务器注册,用AnyCPU COM服务器替换可执行文件:COM客户端启动x86 COM服务器,但没有通信…它一遍又一遍地启动服务器。
  2. 有x64 COM服务器注册,用AnyCPU COM服务器替换可执行文件:COM客户端启动x64 COM服务器,但没有通信…它一遍又一遍地启动服务器。
  3. 具有AnyCPU COM服务器注册,用x86 COM服务器替换可执行文件:COM客户端能够成功地启动并连接到x86 COM服务器。
  4. 有AnyCPU COM服务器注册,用x64 COM服务器替换可执行文件:COM客户端能够成功启动并连接到x64 COM服务器。
  5. 有x86 COM服务器注册,用x64 COM服务器替换可执行文件:COM客户端能够成功启动并连接到x64 COM服务器。
  6. 有x64 COM服务器注册,用x86 COM服务器替换可执行文件:COM客户端能够成功地启动并连接到x86 COM服务器。

地狱是沟通的问题? 这是非常奇怪的…没有提出的解决方案(CLSCTX_ACTIVATE_64_BIT_SERVER,PreferredserverBitness或corflags)帮助。

还有人在这个问题上取得了一些进展? 我们应该联系微软吗?