STA、MTA 和 OLE 噩梦

发布于 2024-07-25 23:50:05 字数 427 浏览 10 评论 0原文

我必须将一个 .NET 应用程序作为插件包含到另一个 .NET 应用程序中。 插件接口要求我从模板表单继承。 加载插件后,该表单将附加到 MDI 中。

到目前为止,一切正常,但每当我注册拖放事件、设置组合框的自动完成模式或在各种其他情况下,我都会收到以下异常:

...当前线程必须设置为 单线程单元(STA)模式 在可以进行 OLE 调用之前。 确保 你的 Main 函数有 STAThreadAttribute 标记在上面...

主应用程序在 MTA 中运行并由另一家公司开发,因此我对此无能为力。

我尝试执行在 STA 线程中导致这些异常的操作,但这也没有解决问题。

有人遇到过同样的情况吗? 我能做些什么来解决这个问题吗?

I have to include a .NET application into another .NET application as a plugin. The plugin interface requires me to inherit from a template form. The form is then attached in a MDI when the plugin is loaded.

Everything is working so far, but whenever I register for drag and drop events, set the autocomplete mode for a combobox or at various other situations I get the following exception:

...the current thread must be set to
single thread apartment (STA) mode
before OLE calls can be made. Ensure
that your Main function has
STAThreadAttribute marked on it...

The main application is running in MTA and developed by another company, so there is nothing I can do about it.

I tried to do the things that cause these exceptions in STA threads, but that didn't solve the problem either.

Has anyone been in the same situation? Is there anything I can do to solve the problem?

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

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

发布评论

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

评论(3

咿呀咿呀哟 2024-08-01 23:50:06

您可以尝试生成新线程并使用 0 调用 CoInitialize(aparment 线程)并在此线程中运行您的应用程序。
但是,您不会直接在此线程中更新控件,您应该对每个 UI 修改使用 Control.Invoke。

我不知道这是否一定有效,但你可以尝试一下。

You could try to spawn new thread and call CoInitialize with 0 on it (aparment threaded) and run your application in this thread.
However you won't be to update controls directly within this thread you should use Control.Invoke for every UI modification.

I don't know if this is going to work for sure, but you could try it.

三生一梦 2024-08-01 23:50:06

我最近在尝试从网络摄像头读取图像时遇到了这个问题。 我最终做的是创建一个方法,该方法产生一个新的 STA 线程,在该线程上运行单线程方法。

问题

private void TimerTick(object sender, EventArgs e)
{
   // pause timer
   this.timer.Stop();

        try
        {
            // get next frame
            UnsafeNativeMethods.SendMessage(this.captureHandle, WindowsMessageCameraGetFrame, 0, 0);

            // copy frame to clipboard
            UnsafeNativeMethods.SendMessage(this.captureHandle, WindowsMessageCameraCopy, 0, 0);

            // notify event subscribers
            if (this.ImageChanged != null)
            {
                IDataObject imageData = Clipboard.GetDataObject();

                Image image = (Bitmap)imageData.GetData(System.Windows.Forms.DataFormats.Bitmap);

                this.ImageChanged(this, new WebCamEventArgs(image.GetThumbnailImage(this.width, this.height, null, System.IntPtr.Zero)));
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error capturing the video\r\n\n" + ex.Message);
            this.Stop();
        }
    }
   // restart timer
   Application.DoEvents();

   if (!this.isStopped)
   {
      this.timer.Start();
   }
}

解决方案:将单线程逻辑移至其自己的方法中,并从新的 STA 线程中调用该方法。

private void TimerTick(object sender, EventArgs e)
{
    // pause timer
    this.timer.Stop();

    // start a new thread because GetVideoCapture needs to be run in single thread mode
    Thread newThread = new Thread(new ThreadStart(this.GetVideoCapture));
    newThread.SetApartmentState(ApartmentState.STA);
    newThread.Start();

    // restart timer
    Application.DoEvents();

    if (!this.isStopped)
    {
        this.timer.Start();
    }
}

/// <summary>
/// Captures the next frame from the video feed.
/// This method needs to be run in single thread mode, because the use of the Clipboard (OLE) requires the STAThread attribute.
/// </summary>
private void GetVideoCapture()
{
    try
    {
        // get next frame
        UnsafeNativeMethods.SendMessage(this.captureHandle, WindowsMessageCameraGetFrame, 0, 0);

        // copy frame to clipboard
        UnsafeNativeMethods.SendMessage(this.captureHandle, WindowsMessageCameraCopy, 0, 0);

        // notify subscribers
        if (this.ImageChanged!= null)
        {
            IDataObject imageData = Clipboard.GetDataObject();

            Image image = (Bitmap)imageData.GetData(System.Windows.Forms.DataFormats.Bitmap);

            // raise the event
            this.ImageChanged(this, new WebCamEventArgs(image.GetThumbnailImage(this.width, this.height, null, System.IntPtr.Zero)));
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("Error capturing video.\r\n\n" + ex.Message);
        this.Stop();
    }
}

I recently ran into this problem myself while trying to read images from a web camera. What I ended up doing was creating a method that spawned a new STA thread, on which the single-thread method was run.

The problem

private void TimerTick(object sender, EventArgs e)
{
   // pause timer
   this.timer.Stop();

        try
        {
            // get next frame
            UnsafeNativeMethods.SendMessage(this.captureHandle, WindowsMessageCameraGetFrame, 0, 0);

            // copy frame to clipboard
            UnsafeNativeMethods.SendMessage(this.captureHandle, WindowsMessageCameraCopy, 0, 0);

            // notify event subscribers
            if (this.ImageChanged != null)
            {
                IDataObject imageData = Clipboard.GetDataObject();

                Image image = (Bitmap)imageData.GetData(System.Windows.Forms.DataFormats.Bitmap);

                this.ImageChanged(this, new WebCamEventArgs(image.GetThumbnailImage(this.width, this.height, null, System.IntPtr.Zero)));
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error capturing the video\r\n\n" + ex.Message);
            this.Stop();
        }
    }
   // restart timer
   Application.DoEvents();

   if (!this.isStopped)
   {
      this.timer.Start();
   }
}

The solution: Move the single-thread logic to its own method, and call this method from a new STA thread.

private void TimerTick(object sender, EventArgs e)
{
    // pause timer
    this.timer.Stop();

    // start a new thread because GetVideoCapture needs to be run in single thread mode
    Thread newThread = new Thread(new ThreadStart(this.GetVideoCapture));
    newThread.SetApartmentState(ApartmentState.STA);
    newThread.Start();

    // restart timer
    Application.DoEvents();

    if (!this.isStopped)
    {
        this.timer.Start();
    }
}

/// <summary>
/// Captures the next frame from the video feed.
/// This method needs to be run in single thread mode, because the use of the Clipboard (OLE) requires the STAThread attribute.
/// </summary>
private void GetVideoCapture()
{
    try
    {
        // get next frame
        UnsafeNativeMethods.SendMessage(this.captureHandle, WindowsMessageCameraGetFrame, 0, 0);

        // copy frame to clipboard
        UnsafeNativeMethods.SendMessage(this.captureHandle, WindowsMessageCameraCopy, 0, 0);

        // notify subscribers
        if (this.ImageChanged!= null)
        {
            IDataObject imageData = Clipboard.GetDataObject();

            Image image = (Bitmap)imageData.GetData(System.Windows.Forms.DataFormats.Bitmap);

            // raise the event
            this.ImageChanged(this, new WebCamEventArgs(image.GetThumbnailImage(this.width, this.height, null, System.IntPtr.Zero)));
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("Error capturing video.\r\n\n" + ex.Message);
        this.Stop();
    }
}
有木有妳兜一样 2024-08-01 23:50:06

更新:公司发布了新的STA版本。 这个问题不再相关了。

Update: The company released a new STA version. The question is no longer relevant.

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