COM无法启动外的过程.NET服务器编译成值为anycpu值为、无法启动、过程、服务器

2023-09-04 01:40:54 作者:有些爱不得不各自天涯

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

我是一个64位的机器上运行:Windows 7中使用Visual Studio 2008 SP1 。 我可以在任务管理器中看到,它并启动我的服务器。所以我想这个问题是在COM和服务器(类注册)之间的通信 在我的测试客户端应用程序是用C#,但它并不不论是编译为x86或x64。此问题也发生在东西写在32位C ++。 如果我使用的x64重建该服务器,并运行它,然后重新回来的值为anycpu,那么COM可以启动它。重新引导会带我回到原来的情况。也许COM不预先知道什么位数将被使用,并且一个previous执行帮助 在我发现安迪·麦克马伦的博客文章并试图通过CLSCTX_ACTIVATE_64_BIT_SERVER到的CoCreateInstance(),但是这将触发失败更早版本: 0x80040154的(REGDB_E_CLASSNOTREG)。难道我做错了什么在我的COM注册?你可以看到下面,这是很简单的。在64位运行时登记发生时,并且当客户端为64位,所以Wow6432Node不应参与出现问题。

另一个青年已经有了similar问题,但MSFT答案是令人困惑的。他似乎在暗示它只能通过DCOM(见链接)或COM +工作。我怀疑要么将是一个可怕的很多工作,大大高于分配我的.exe建成x64和x86恶化。

您可能会奇怪,为什么我实现IPersistFile。这是因为我真正的问题是让BindMoniker()从32位C ++程序,我值为anycpu的.Net程序的工作。我减少了我的问题在这里psented简单的例子$ P $。

下面是客户端code:

 公共部分类Form1中:形态
{
    公共Form1中()
    {
        的InitializeComponent();
    }

    [的DllImport(OLE32.DLL,ExactSpelling = TRUE,preserveSig = FALSE)]
    [返回:的MarshalAs(UnmanagedType.Interface)
    静态外部对象的CoCreateInstance(
       [在,的MarshalAs(UnmanagedType.LPStruct)的Guid rclsid,
       [的MarshalAs(UnmanagedType.IUnknown)对象pUnkOuter,
       CLSCTX dwClsContext,
       [在,的MarshalAs(UnmanagedType.LPStruct)的Guid RIID);

    [国旗]
    枚举CLSCTX:UINT
    {
        CLSCTX_LOCAL_SERVER =为0x4,
        CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000,
    }

    私人无效Form1_Load的(对象发件人,EventArgs的)
    {
        IPersistFile PF =(IPersistFile)的CoCreateInstance(
            新的GUID(1984D314-FC8D-44bc-9146-8A13500666A6),
            空值,
            CLSCTX.CLSCTX_LOCAL_SERVER,
            新的GUID(0000010b-0000-0000-C000-000000000046)); // IPersistFile
        pf.Load(C:\\笨蛋,0);
    }
}
 
详解服务器 磁盘和网卡知识

和这里是服务器:

 静态类节目
{
    [STAThread]
    静态无效的主要()
    {
        如果(Environment.CommandLine.Contains(/寄存器)){
            的RegistryKey CLS = Registry.LocalMachine.CreateSubKey(的String.Format(
                SOFTWARE \\ \\类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(假);

        RegistrationServices的章=新RegistrationServices的();
        reg.RegisterTypeForComClients(
            typeof运算(PersistFile)
            RegistrationClassContext.LocalServer,
            RegistrationConnectionType.MultipleUse);

        Application.Run(新Form1中());
    }
}

[标记有ComVisible特性(真),
 GUID(1984D314-FC8D-44bc-9146-8A13500666A6),
 ClassInterface(ClassInterfaceType.None)
公共类PersistFile:IPersistFile
{
    公共静态的Guid的ClassID
    {
        得到
        {
            GuidAttribute A =(GuidAttribute)typeof运算(PersistFile).GetCustomAttributes(typeof运算(GuidAttribute),假)[0];
            返回新的GUID(a.value中);
        }
    }

    #地区IPersistFile
    公共无效的GetClassID(出的Guid pClassID)
    {
        的MessageBox.show(的GetClassID);
        pClassID =的ClassID;
    }

    公众诠释IsDirty()
    {
        的MessageBox.show(IsDirty);
        返回1;
    }

    公共无效负载(串pszFileName,INT dwMode)
    {
        的MessageBox.show(的String.Format(加载{0},pszFileName));
    }

    公共无效保存(字符串pszFileName,布尔fRemember)
    {
        的MessageBox.show(保存);
        抛出新的NotImplementedException();
    }

    公共无效SaveCompleted(字符串pszFileName)
    {
        的MessageBox.show(SaveCompleted);
        抛出新的NotImplementedException();
    }

    公共无效GetCurFile(出字符串ppszFileName)
    {
        的MessageBox.show(GetCurFile);
        抛出新的NotImplementedException();
    }
    #endregion
}
 

解决方案

我想这个问题是在运行时。我创建了一个COM服务器,该服务器注册使用C ++库(注册的表现堪称完美)。从.NET(CS)切换到值为anycpu时,我遇到了问题。

该架构:

在C ++库接口的COM(基于两个x64和x86平台) 在.NET库包装(CS)(正确实例化所需的x64 / x86的C ++库) 在.NET应用程序(CS) - COM客户或COM服务器

丑陋的事情发生登记建成值为anycpu的.NET应用程序时。一旦COM客户端调用通过DCOM COM服务器,服务器应用程序启动,但客户端收到错误的COM服务器无法启动。

我去了一些措施进一步分析了注册数据讨论procmon和其他工具,我得出了相同的结论:

86注册类在课堂\ Wow6432Node x64和值为anycpu登记在班类(X64的Windows机器上,完全一样的按键,我敢打赌,x86和值为anycpu将在x86机器上注册的相同)

现在,我做了一些更多的实验:将在x86 / x64 /值为anycpu COM客户端可以使用没有问题,以任何基于x86 / x64的COM服务器连接,但它不能无论如何连接到值为anycpu COM服务器...

我然后进行以下的试验例:

有86 COM服务器注册,请用值为anycpu COM服务器可执行文件:COM客户已开始在x86 COM服务器,但没有沟通......这是一遍又一遍启动服务器。 有64位COM服务器注册,请用值为anycpu COM服务器可执行文件:COM客户是开始的64 COM服务器,但没有沟通......这是一遍又一遍启动服务器。 有值为anycpu COM服务器注册,更换与x86 COM服务器可执行文件:COM客户端能够成功启动并连接到x86的COM服务器 有值为anycpu COM服务器注册,更换了64位COM服务器可执行文件:COM客户端能够成功启动并连接到64 COM服务器 有86 COM服务器注册,与64位COM服务器替换可执行文件:COM客户端能够成功启动并连接到64 COM服务器 有64位COM服务器注册,与x86 COM服务器替换可执行文件:COM客户端能够成功启动并连接到x86的COM服务器

如果地狱是沟通的问题?这是很奇怪......没有了presented解决方案(CLSCTX_ACTIVATE_64_BIT_SERVER,preferredServerBitness或corflags)的帮助。

任何人都没有在这个问题上取得了一些进展?我们应该联系Microsoft?

I am trying to get COM to start my out-of-process .NET COM server. It works if the server process is compiled with x64, but if I use AnyCPU (which is what I want) then it hangs for a while and eventually fails with 0x80080005 (CO_E_SERVER_EXEC_FAILURE). How can I get this to work?

I am running on a 64-bit machine: Windows 7 with Visual Studio 2008 SP1. I can see in Task Manager that it does start my server. So I guess the problem is in the communications between COM and the server (class registration). My test client application is written in C#, but it doesn't matter whether it is compiled for x86 or x64. The problem also occurs with something written in 32-bit C++. If I rebuild the server using x64 and run it, and then rebuild back as AnyCPU, then COM can start it. A reboot will take me back to the original situation. Perhaps COM doesn't know in advance what bitness is going to be used, and a previous execution helps. I found Andy McMullen's blog post and tried passing CLSCTX_ACTIVATE_64_BIT_SERVER to CoCreateInstance(), but that triggers a failure earlier: 0x80040154 (REGDB_E_CLASSNOTREG). Am I doing something wrong in my COM registration? You can see below that it is very simple. Registration occurs when running in 64 bits, and the problem occurs when the client is 64 bits, so Wow6432Node should not be involved.

Another chap has had a similar problem, but the MSFT answer is confusing. He seems to be suggesting it can only work via DCOM (see link) or COM+. I suspect either will be an awful lot of work, and substantially worse than distributing my .exe built as x64 and x86.

You may be wondering why I am implementing IPersistFile. It is because my real problem is to get BindMoniker() working from a 32-bit C++ program to my AnyCPU .Net program. I have reduced my problem to the simpler example presented here.

Here is the client code:

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

and here is the server:

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
}

解决方案

I guess the problem is at run-time. I have created a COM Server which registers using a C++ library (registration is performed flawlessly). I have run into problems when switching to AnyCPU from .NET (CS).

The architecture:

C++ library interfacing COM (built on both x64 and x86 platforms) .NET library wrapper (CS) (correctly instantiates the required x64/x86 C++ library) .NET application (CS) - COM client or COM server

Ugly things happen when registering the .NET application built as "AnyCPU". Once the COM Client invokes the COM Server through DCOM, the server application starts but the client receives error that the COM Server could not be started.

I went some steps further, analyzed registration data with procmon and other tools and I reached the same conclusion:

x86 registers the classes in CLASSES\Wow6432Node x64 and AnyCPU register the classes in CLASSES (on a x64 windows machine, exactly the same keys; I bet that x86 and AnyCPU would register the same on an x86 machine)

Now, I did some more experiments: the x86/x64/AnyCPU COM Client can connect with no problems to any x86/x64 COM Server but it cannot connect anyhow to an AnyCPU COM Server...

I then performed the following test cases:

Have the x86 COM Server register, replace the executable with the AnyCPU COM Server: COM Client was starting the x86 COM Server, but no communication... it was starting the server over and over again.. Have the x64 COM Server register, replace the executable with the AnyCPU COM Server: COM Client was starting the x64 COM Server, but no communication... it was starting the server over and over again.. Have the AnyCPU COM Server register, replace the executable with the x86 COM Server: COM Client was able to successfully start the and connect to the x86 COM Server. Have the AnyCPU COM Server register, replace the executable with the x64 COM Server: COM Client was able to successfully start the and connect to the x64 COM Server. Have the x86 COM Server register, replace the executable with the x64 COM Server: COM Client was able to successfully start the and connect to the x64 COM Server. Have the x64 COM Server register, replace the executable with the x86 COM Server: COM Client was able to successfully start the and connect to the x86 COM Server.

Where the hell is the communication problem? This is very odd... None of the presented solutions (CLSCTX_ACTIVATE_64_BIT_SERVER, PreferredServerBitness or corflags) helped.

Anyone else did some progress on this matter? Should we contact Microsoft?