COM无法启动作为AnyCPU编译的进程外.Net服务器

Oli*_*ock 9 .net c# windows com

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

  • 我在64位计算机上运行:带有Visual Studio 2008 SP1的Windows 7.
  • 我可以在任务管理器中看到它确实启动了我的服务器.所以我猜问题是COM和服务器之间的通信(类注册).
  • 我的测试客户端应用程序是用C#编写的,但无论是为x86还是x64编译都无关紧要.使用32位C++编写的东西也会出现问题.
  • 如果我使用x64重建服务器并运行它,然后重建为AnyCPU,那么COM可以启动它.重启会让我回到原来的状态.也许COM事先不知道将要使用什么位,并且之前的执行有所帮助.
  • 我找到了Andy McMullen的博客文章,并尝试将CLSCTX_ACTIVATE_64_BIT_SERVER传递给CoCreateInstance(),但之前触发了失败:0x80040154(REGDB_E_CLASSNOTREG).我在COM注册中做错了吗?你可以在下面看到它非常简单.当以64位运行时发生注册,并且当客户端是64位时发生问题,因此不应涉及Wow6432Node.

另一个人有类似的问题,但MSFT的答案令人困惑.他似乎建议它只能通过DCOM(见链接)或COM +工作.我怀疑要么是要做很多工作,要么比分发我的.exe构建为x64和x86要糟糕得多.

你可能想知道我为什么要实现IPersistFile.这是因为我的真正问题是让BindMoniker()从32位C++程序运行到我的AnyCPU .Net程序.我把问题简化为这里提出的更简单的例子.

这是客户端代码:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是服务器:

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
}
Run Code Online (Sandbox Code Playgroud)

Ayk*_*vik 1

尝试使用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);
Run Code Online (Sandbox Code Playgroud)

我还认为,根据 .NET com 服务器,.NET 客户端程序集存在一些问题,但我找不到任何资源......

希望,这会有所帮助...