草庐IT

c# - 使我的 COM 程序集调用异步

coder 2024-06-03 原文

我刚刚“获得”在当前工作中维护用 C# 编码的遗留库的特权。

这个动态链接库:

  • 为使用 Uniface 制作的大型遗留系统公开方法,该系统别无选择,只能调用 COM 对象。
  • 充当此遗留系统与另一个系统的 API 之间的链接。
  • 在某些情况下使用 WinForm 作为其 UI。

根据我对组件的理解,更直观:

*[Uniface 中的大型遗留系统]* ==[COM]==> [C# 库] == [托管 API]==> *[大型 EDM 管理系统]*

问题是:此 C# 库中的方法之一运行时间太长,我“应该”使其异步!

我习惯了 C#,但根本不习惯 COM。我已经完成并发编程,但 COM 似乎给它增加了很多复杂性,到目前为止我所有的试验都以以下任一方式结束:

  • 完全没有错误消息的崩溃
  • 我的 Dll 只部分工作(只显示其 UI 的一部分,然后关闭),仍然没有给我任何错误

我没有关于如何在 COM dll 中处理线程的想法和资源,我将不胜感激任何提示或帮助。

到目前为止,我已更改代码的最大部分以使我的方法异步:

// my public method called by the external system
public int ComparedSearch(string application, out string errMsg) {
  errMsg = "";
  try {
    Action<string> asyncOp = AsyncComparedSearch;
    asyncOp.BeginInvoke(application, null, null);
  } catch (ex) {
    // ...
  }
  return 0;
}

private int AsyncComparedSearch(string application) {
  // my actual method doing the work, that was the called method before
}

任何提示或有用的资源将不胜感激。 谢谢。

更新 1:

按照下面的答案和线索(特别是关于 SynchronizationContext,并在 this example 的帮助下)我能够重构我的代码并使其工作,但只有在从另一个窗口调用时C# 中的应用程序,而不是通过 COM。 当我调用该函数时,遗留系统遇到了一个相当模糊的错误,并且没有提供有关崩溃的任何详细信息。

更新 2:

我试验中的最新更新:当调用来自测试项目时,我设法使多线程工作,不是来自 Uniface 系统。 经过多次试验,我们倾向于认为我们的遗留系统在其当前配置中不能很好地支持多线程。但这不再是问题的重点:)

下面是一段似乎有效的代码:

string application;
SynchronizationContext context;

// my public method called by the external system
public int ComparedSearch(string application, out string errMsg) {
    this.application = application;
    context = WindowsFormsSynchronizationContext.Current;
    Thread t = new Thread(new ThreadStart(AsyncComparedSearchAndShowDocs));
    t.Start();
    errMsg = "";
    return 0;
}

private void AsyncComparedSearch() {
    // ANY WORK THAT AS NOTHING TO DO WITH UI
    context.Send(new SendOrPostCallback(
        delegate(object state)
        {
            // METHODS THAT MANAGE UI SOMEHOW
        }
    ), null);
}

我们现在正在考虑修改此 COM 程序集以外的其他解决方案,例如将此库封装在 Windows 服务中并在系统和服务之间创建接口(interface)。它应该更具可持续性..

最佳答案

不了解更多细节很难判断,但这里几乎没有问题。

您通过 BeginInvoke 在另一个线程上执行委托(delegate),但您不等待它。您的 try\catch block 不会捕获任何内容,因为它已经通过,而远程调用仍在执行。相反,您应该将 try\catch block 放在 AsyncComparedSearch 中。

由于您不等待远程方法执行结束(EndInvoke 或通过回调),我不确定您如何处理 COM 调用的结果。我猜想您是从 AsyncComparedSearch 中更新 GUI。如果是这样,那是错误的,因为它在另一个线程上运行,你不应该从除 GUI 线程之外的任何地方更新 GUI - 这很可能导致崩溃或其他意外行为。因此,您需要将 GUI 更新工作同步到 GUI 线程。在 WinForms 中你需要使用 Control.BeginInvoke (不要将它与 Delegate.BeginInvoke 混淆)或其他方式(例如 SynchronizationContext )将代码同步到 GUI 线程。我使用类似这样的东西:

private delegate void ExecuteActionHandler(Action action);

public static void ExecuteOnUiThread(this Form form, Action action)
{
  if (form.InvokeRequired) { // we are not on UI thread
    // Invoke or BeginInvoke, depending on what you need
    form.Invoke(new ExecuteActionHandler(ExecuteOnUiThread), action);
  }
  else { // we are on UI thread so just execute the action
    action();
  }
}

然后我在任何线程中都这样调用它:

theForm.ExecuteOnUiThread( () => theForm.SomeMethodWhichUpdatesControls() );

此外,阅读this answer一些注意事项。

关于c# - 使我的 COM 程序集调用异步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15340620/

有关c# - 使我的 COM 程序集调用异步的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  3. ruby - 在 Ruby 中编写命令行实用程序 - 2

    我想用ruby​​编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序

  4. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  5. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  6. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  7. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  8. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  9. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  10. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

随机推荐