.NET 进程外 COM 对象在 API 调用中共享静态实例

发布于 2024-11-09 23:01:49 字数 909 浏览 5 评论 0原文

很难解释我们的处境。

我们有一个 3 层应用程序。引擎是一个用 C++ 编码的 DLL,然后我们有一个 VB6 ActiveX EXE,它通过 API 调用访问引擎,在顶层,我们有一个 Excel 插件(在 C# 中使用 VSTO 框架)使用互操作 DLL 调用中间层。此时,从 Addin 到引擎的每个“连接”都会创建一个新的 EXE(VB6 使用 API 调用来访问引擎)并且一切正常。 现在我们将中间层移至.NET,它“大概”工作得很好(它通过了我们所有的单元测试),但是,当我们同时打开 2 个“连接”时,我们发现了一个错误(ups,没有单元测试检查这种情况)因为这是一种新行为)。 DLL 具有静态对象,它在同一进程中的所有实例之间共享,并且我们在“连接”之间进行交互。在我们的旧版本中,每个“连接”都会创建一个新的 EXE,进程之间没有内存共享,现在它是同一个进程,并且它们共享内存和静态对象。

按照这个问题。我们尝试用 C# 构建一个 COM EXE 来在中间层执行进程外对象,但我们得到了相同的结果。它们共享静态对象,最终每个连接不会创建一个独立的进程。

很明显,但目前无法承受,将 API 调用移至 ATL 或将静态对象更改为带有句柄的可实例化引用,并更改所有 API 调用以获取/设置此处理程序。我查看了 MS All-in-one 中的所有示例,但没有找到任何解决方案。不可能一次只保留一个连接,每个工作簿可以有一个连接,并且将来我们希望探索同时具有多个连接的 Web 应用程序。

有什么建议吗?

提前致谢,

It's hard to explain our situaction.

We have a 3-tier application. The engine is a DLL coded in C++, then we have a VB6 ActiveX EXE that access to the engine via API calls, and at the top level we have a Excel Addin (in C# using VSTO framework) calling the middle layer with an interop DLL. At this time, each "connection" from the Addin to the engine creates a new EXE (VB6 uses API calls to access to the engine) and all works fine.
Now we are moving the middle layer to .NET, it works 'presumably' fine (it pass all our Unit test) but, we found an error when we open 2 "connections" at same time (ups, no unit test check this situation because it's a new behavour). The DLL have static objects that it's shared over all instances in the same process and we have interactions between "connections". In our old version each "connection" creates a new EXE with no memory sharing between processes, now it's the same process and they share memory and the static objects.

Following the tips from this question. We tried to build a COM EXE in C# to do an out-of-process objects in the middle layer but we have the same result. They share the static objects, at the end, each connection not creates a independent process.

It's clear, but not affordable at this time, moving API calls to ATL or changing the static objects to instanciable references with a handle and change all the API calls to get/set this handlers. I reviewed all examples in MS All-in-one but I didn't find any solution. Neither it's possible to keep only one connection at time, each workbook can have one connection and in the future we want to explore a Web application with multiple connections at same time.

Any suggestion?

Thanks in advance,

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

绻影浮沉 2024-11-16 23:01:50

COM 是为每个 COM 对象启动新的 EXE,还是使用单个 EXE 实例化所有对象,由传递给 CoRegisterClassObject 的标志参数控制。请参阅

http://msdn.microsoft.com/en -us/library/ms693407(v=vs.85).aspx

http://msdn.microsoft.com/en-us/library/ms679697(v=vs.85).aspx

您需要传递 REGCLS_SINGLEUSE 或 REGCLS_MULTI_SEPARATE 标志。

现在,技巧是传递此标志,因为您可能不会直接调用此方法 - 详细信息取决于您如何实现 COM EXE。

Whether COM starts new EXE per each COM object, or uses single EXE to instantiate all the object is controlled by flags parameters passed to CoRegisterClassObject. See

http://msdn.microsoft.com/en-us/library/ms693407(v=vs.85).aspx, and

http://msdn.microsoft.com/en-us/library/ms679697(v=vs.85).aspx

You need to pass REGCLS_SINGLEUSE or REGCLS_MULTI_SEPARATE flags.

Now, the trick is to pass this flag, as you might not call this method directly - the details depend on how you implemented the COM EXE.

沒落の蓅哖 2024-11-16 23:01:50

从问题中尚不清楚,但听起来您的“中间层”是作为 VB6 EXE 构建的,并且您试图用 .net DLL 替换它。如果是这样的话,您肯定会得到您所描述的行为。

对于 VB6 EXE com 项目,实例化一个新对象会启动一个新进程。使用 .net dll(或者实际上是 Vb6 dll),您不会获得新进程。

您要么需要创建一个公开 COM 对象的 .net EXE,就像您的 VB6 exe 所做的那样,或者(听起来您已经研究过这一点)您需要重构您的 EXE 对象以正确处理单个实例中的多个实例过程。

老实说,后者可能会更好,因为像这样依赖单例通常是一种糟糕的代码味道。但紧要关头,您应该能够使用 .net 项目复制 VB6 exe 的行为。你不能在 dll 中做到这一点。

it's not clear from the question, but it sounds like the "middle layer" you have was built as a VB6 EXE, and you're trying to replace it with a .net DLL. If that's the case, you'll definitely get the behavior you describe.

With a VB6 EXE com project, instantiating a new object starts a new process. With a .net dll (or a Vb6 dll really) you +won't+ get a new process.

You'd either need to create a .net EXE that exposes COM objects just like your VB6 exe does, or (sounds like you've already investigated this) you'll need to refactor your EXE objects to properly handle multiple instances within a single process.

Honestly, it'd probably be better to do that latter, since relying on singletons like this is generally a bad code smell. But it a pinch, you should be able to replicate the behavior of the VB6 exe with a .net project. You just can't do it in a dll.

甜味超标? 2024-11-16 23:01:50

你的中间层是用.Net 创建的吗?如果是,您可能会遇到这样的问题:您的 COM 类是作为本机 .net 对象而不是 COM 对象创建的。该解决方案通常涉及使用主互操作程序集。看看

Was your middle layer created in .Net? If it was, you might be facing the issue that your COM class is been created as a native .net object instead of a COM object. The solution usually involve using Primary Interop Assemblies. Take a look on this SO question to see if it matches your problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文