从多线程 C# Windows 服务应用程序调用 VB6 DLL?

发布于 2024-07-26 12:43:44 字数 446 浏览 5 评论 0原文

我正在运行需要调用 VB6 dll 的多线程 Windows 服务。 没有关于此 VB6 dll 的文档,并且此遗留系统支持非常关键的业务流程。

第一次(第一个线程),这个 dll 表现良好。 当其他线程需要访问时,它开始提供错误的结果。

我读到一个人说:

“如果您使用 VB6,请注意一件事。您的线程 如果您是,则必须更改模型以支持公寓 运行多线程服务。 VB只支持多个 单线程单元,但 .NET 运行完全免费的线程 通常情况下。 调用 VB6 DLL 的线程需要是 与 DLL 兼容。”

团队的另一个人给了我这个想法,将这个 ddl 放在一个单独的应用程序域中。但我不确定。

我们如何使用从多线程 c# windows 服务应用程序调用的 VB6 dll?

I'm running a multithreaded windows service that need to call a VB6 dll. There's no documentation about this VB6 dll and this legacy system supports a very critical business process.

At first time (1st thread), this dll performs well. As other threads need access, it start provide wrong results.

I read one guys saying:

"Just be careful of one thing if you are using VB6. Your threading
model is going to have to change to support apartments if you are
running a multithreaded service. VB only supports multiple
single-threaded apartments, but .NET runs fully free threaded
normally. The thread that calls into the VB6 DLL needs to be
compatible with the DLL."

Another guy from team gave me the idea to put this ddl in a separated application domain. But I'm not sure.

How can we work with VB6 dll called from a multithreaded c# windows service application?

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

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

发布评论

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

评论(4

落花随流水 2024-08-02 12:43:45

这篇关于多线程 Visual Basic 6 DLL 的文章提供了一些见解。 它说:

制作 ActiveX DLL 项目
多线程,选择需要的
常规选项卡上的线程选项
项目属性对话框的。

这篇文章说有三种可能的模型选择:

One thread of execution 
Thread pool with round-robin thread assignment 
Every externally created object is on its own thread 

我假设默认为一个执行线程,并且需要选择其他两个选项之一。

This article on multithreading Visual Basic 6 DLL's provides some insight. It says:

To make an ActiveX DLL project
multithreaded, select the desired
threading options on the General tab
of the Project Properties dialog box.

This article says there are three possible models to choose from:

One thread of execution 
Thread pool with round-robin thread assignment 
Every externally created object is on its own thread 

I assume that the default is one thread of execution, and that one of the other two options needs to be selected.

慕巷 2024-08-02 12:43:45

您可能想看看这个: linky

这里是引起我注意的一个片段:

VB6 COM 对象是 STA 对象,这意味着它们必须在 STA 线程上运行。
您确实从两个 MTA 线程创建了该对象的两个实例,但该对象本身将在单个(COM (OLE) 创建的)STA 上运行
线程,并且来自两个 MTA 线程的访问将被封送和同步。
所以你应该做的是将线程初始化为 STA,以便每个对象在自己的 STA 线程上运行而无需封送
会没事的。

无论如何,VB 风格的 COM 对象始终是 STA。 现在为了防止单元编组和线程切换,您需要创建
STA 初始化公寓中的实例。
另请注意,当您在 Main 上设置 [MTAThread] 属性时,您实际上将主线程初始化为 MTA,当您创建
来自 MTA 线程的 STA 对象实例 COM 将创建一个单独的(非托管)线程并将其初始化为 STA(这称为
默认 STA),MTA 线程对 STA 对象的所有调用都将被封送(并导致线程切换),在某些情况下 Idispatch 调用
将由于 IP 封送失败而失败。
因此建议仅使用兼容公寓中的 STA(以及 VB6)对象。

You might want to take a look at this: linky

And here is a snippet that caught my attention:

VB6 COM objects are STA objects, that means they must run on an STA thread.
You did create two instances of the object from two MTA threads, but the object itself will run on a single (COM (OLE) created) STA
thread, and access from the two MTA threads will be marshaled and synchronized.
So what you should do is, initialize the threads as STA so that each objects runs on his own STA thread without marshaling and you
will be fine.

Anyway, VB style COM objects are always STA. Now in order to prevent apartment marshaling and thread switching you need to create
instances in STA initialized apartments.
Note also that when you set the [MTAThread] attribute on Main, you effectively initialize the main thread as MTA, when you create
instances of STA objects from MTA threads COM will create a separate (unmanaged) thread and initialize it as STA (this is called the
default STA), all calls to STA objects from MTA threads will be marshaled (and incur thread switches), in some cases Idispatch calls
will fail due to IP marshaling failures.
So the advise is use STA (and therefore VB6) objects from compatible apartments only.

弱骨蛰伏 2024-08-02 12:43:44

当线程进入时,您是否保存对象并稍后在新线程上重用它们? 如果可以的话,为每个线程创建新鲜的对象。 我们使用的数据层 dll 就遇到过这样的情况。 如果您在一个线程上创建连接,则无法从另一个线程使用该连接。 如果您在每个线程上创建一个新连接,它就可以正常工作。

如果创建对象的速度很慢,请查看 ThreadPool 类和 ThreadStatic 属性。 线程池一遍又一遍地回收同一组线程来完成工作,而 ThreadStatic 允许您创建仅针对一个线程存在的对象。 例如,

[ThreadStatic]
public static LegacyComObject myObject;

当收到请求时,将其转换为作业并将其放入线程池中。 作业启动时,检查静态对象是否初始化;

void DoWork()
{ 
    if (myObject == null)
    { 
        // slow intialisation process
        myObject = New ...
    }

    // now do the work against myObject
    myObject.DoGreatStuff();
}

When the threads come in, are you saving objects and reusing them later on new threads? If you can, create the objects fresh for every thread. We have a situation like this with a data layer dll we use. If you create a connection on one thread, it can't be used from another. If you create a new connection on each thread, it works fine.

If it's slow to create your objects, look at the ThreadPool class and the ThreadStatic attribute. Threadpools recycle the same set of threads over and over to do work, and ThreadStatic lets you create an object that exists for one thread only. eg

[ThreadStatic]
public static LegacyComObject myObject;

As a request comes in, turn it into a job and queue it in your thread pool. When the job starts, check if the static object is initialised;

void DoWork()
{ 
    if (myObject == null)
    { 
        // slow intialisation process
        myObject = New ...
    }

    // now do the work against myObject
    myObject.DoGreatStuff();
}
孤君无依 2024-08-02 12:43:44

你说

我正在运行多线程窗口
需要调用 VB6 dll 的服务。
没有关于这个的文档
VB6 dll 和这个遗留系统
支持非常关键的业务
流程。

同时你说

第一次(1°线程),这个dll
表现良好。 由于其他线程需要
访问,它开始提供错误
结果。

我非常确定管理层意识到您所看到的失败,因为支持关键业务流程的代码是旧的且没有记录,并且正在以从未打算使用的方式使用,并且从未经过测试使用。 我敢打赌,以前从未测试过它可以在 .NET 中使用,不是吗?

这是我的建议,这与我实际实现的类似:

VB6 DLL 期望在单个线程上调用。 不要失望!当你的服务启动时,让它启动一个适当类型的线程(我不能说,因为我故意忘记了所有 STA /MTA 的东西)。 将对该线程的访问 VB6 DLL 的请求排队。 让所有此类访问都通过单线程进行。

这样,就 VB6 DLL 而言,它的运行方式与测试时的运行方式完全一样。


顺便说一句,这与我实现的略有不同。 我有一个 Web 服务,而不是 Windows 服务。 我有一个 C DLL,而不是 VB6,也不是 COM。 我只是将对事物的所有访问重构为一个类,然后在每个公共方法周围放置锁定语句。

You say

I'm running a multithreaded windows
service that need to call a VB6 dll.
There's no documentation about this
VB6 dll and this legacy system
supports a very critical business
process.

and at the same time you say

At first time (1º thread), this dll
performs well. As other threads need
access, it start provide wrong
results.

I'd make very certain that Management is aware of the failure you're seeing because the code supporting the critical business process is old and undocumented, and is being used in a way it was never intended to be used, and was never tested to be used. I bet it's also never been tested to be used from .NET before, has it?

Here's my suggestion, and this is similar to something I've actually implemented:

The VB6 DLL expects to be called on a single thread. Do not disappoint it! When your service starts, have it start up a thread of the appropriate type (I can't say, since I've deliberately forgotten all that STA/MTA stuff). Queue up requests to that thread for access to the VB6 DLL. Have all such access go through the single thread.

That way, as far as the VB6 DLL is concerned, it's running exactly as it was tested to run.


BTW, this is slightly different from what I've implemented. I had a web service, not a Windows Service. I had a C DLL, not VB6, and it wasn't COM. I just refactored all access to the thing into a single class, then put lock statements around each of the public methods.

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