gpt4 book ai didi

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

转载 作者:可可西里 更新时间:2023-11-01 12:44:12 25 4
gpt4 key购买 nike

我试图让 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 事先不知道将使用什么位数,而之前的执行会有所帮助。
  • 我找到了 Andy McMullen's blog post并尝试将 CLSCTX_ACTIVATE_64_BIT_SERVER 传递给 CoCreateInstance(),但这会更早地触发故障:0x80040154 (REGDB_E_CLASSNOTREG)。我在 COM 注册中做错了什么吗?你可以在下面看到它非常简单。 64位运行时出现注册,客户端是64位时出现问题,所以应该不涉及Wow6432Node。

另一个人有一个 similar problem ,但 MSFT 的回答令人困惑。他似乎在暗示它只能通过 DCOM(参见链接)或 COM+ 工作。我怀疑两者都需要大量工作,而且比分发构建为 x64 和 x86 的 .exe 差得多。

您可能想知道我为什么要实现 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);
}
}

这是服务器:

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
}

最佳答案

我想问题出在运行时。我已经创建了一个 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)都没有帮助。

其他人在这件事上取得了一些进展吗?我们应该联系 Microsoft 吗?

关于c# - COM 无法启动编译为 AnyCPU 的进程外 .Net 服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9303814/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com