【问题标题】:Calling .NET Assembly from PowerBuilder (Exposing .NET Framework Components to COM)从 PowerBuilder 调用 .NET 程序集(向 COM 公开 .NET Framework 组件)
【发布时间】:2014-12-20 06:15:33
【问题描述】:

这里是编程环境。

  • 框架:ASP.NET Framework 4
  • 语言:Visual C# 2010,PowerBuilder 12.5.2 Build 5609 于 2014 年 1 月 2 日 01:29:51 构建

这是场景。

我正在创建一个 PowerBuilder 应用程序,它会启动一个带有多行编辑文本框的简单窗口,您可以在其中键入内容并单击按钮以加载 C# COM 类,该类检查拼写错误并返回值到 PowerBuilder 应用程序的文本框。

C# ClassLibrary.cs

using System;
using System.Runtime.InteropServices;

namespace InteropServices
{
    [Guid("Let's just assume that I have a correct Guid string here.")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface ISpellChecker
    {
        [(DispId(1)]
        string CheckText(string inputMsg);

        [(DispId(2)]
        void Dispose();
    }

    [ClassInterface(ClassInterfaceType.None)]
    [Guid("Let's just assume that I have a correct Guid string here.")]
    [ProgId("InteropServices.SpellChecker")]
    public class SpellChecker: ISpellChecker
    {
        private string newInputMsg

        public string inputMsg
        {
            get
            {
                return newInputMsg;
            }
            set
            {
                newInputMsg = value;
            }
        }

        private App spellCheckerApp;
        private MainWindow spellCheckerMainWindow;

        public SpellChecker() { }

        public string CheckText(string inputMsgBase)
        {
            inputMsg = inputMsgBase;
            spellCheckerApp = new App();
            spellCheckerMainWindow = new MainWindow(inputMsg);
            spellCheckerApp.Run(spellCheckerMainWindow);
            txtCorrected = MainWindow.TextReturned;

            return txtCorrected;
        }

        public string txtCorrected { get; set; }

        // This function was my futile attempt to resolve this issue, but it seemingly has no effect whatsoever.
        public void Dispose()
        {
            spellCheckerMainWindow.Close();
            spellCheckerApp.Shutdown();
            spellCheckerMainWindow = null;
            spellCheckerApp = null;
        }
    }
}

C# MainWindow.xaml

<Window x:Class="InteropServices.MainWindow"
        xmlns="http://schemas.microsft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsft.com/winfx/2006/xaml"
        Title="Spell Checker .NET" Height="350" Width="525" Loaded="Window_Loaded">
    <Grid>
        <TextBox Name="TextBoxSpellCheck" SpellCheck.IsEnabled="True" AcceptsReturn="True" TextWrapping="Wrap" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.CanContentScroll="True" Margin="50" />
        <Button Name="ButtonAccept" Margin="229,267,146,12" Width="128" Height="32" Content="Accept" IsDefault="True" Click="ButtonAccept_Click" />
        <Button Name="ButtonCancel" Margin="364,267,12,12" Width="128" Height="32" Content="Cancel" IsDefault="True" Click="ButtonAccept_Click" />
    </Grid>
</Window>

C# MainWindow.xaml.cs

using System;
// Omitting the rest of the default Usings

namespace InteropServices
{
    public partial class MainWindow : Window
    {
        private string txtChecked;
        private int caretIdx;
        private SpellingError spellingErr;
        private string p;

        public MainWindow(string p)
        {
            this.p = p;
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            txtChecked = p;
            TextBoxSpellCheck.Text = txtChecked;
            caretIdx = TextBoxSpellCheck.CaretIndex;
            spellingErr = TextBoxSpellCheck.GetSpellingError(caretIdx);

            if (spellingErr == null)
            {
                MessageBox.Show("No spelling error was found. Click OK to continue.", "Congratulations!");
                txtReturned = p;
                Application.Current.Shutdown();
            }
        }

        private void ButtonAccept_Click(object sender, RoutedEventArg e)
        {
            txtReturned = TextBoxSpellCheck.Text;
            Application.Current.Shutdown();
        }

        private void ButtonCancel_Click(object sender, RoutedEventArg e)
        {
            txtReturned = p;
            Application.Current.Shutdown();
        }

        public static string txtReturned
    }
}

从 main 中的 commandbutton 中单击类型 cb_1 的 PowerBuilder 事件

mle_1.Text = "Teh quik brownn fox junps ober teh lazy dgo!" // Too lazy to copy and paste this into the app's textbox, so here it is...
txtChecked = mle_1.Text
myOLEObject = CREATE OLEObject
result = myOLEObject.ConnectToNewObject("InteropServices.SpellChecker")

IF result < 0 THEN
    DESTROY myOLEObject
    MessageBox("Connecting to COM Object Failed", "Error: " + String(result))
    RETURN
ELSE
    txtCorrected = myOLEObject.CheckText(txtChecked) // This is the line that causes an error.
    mle_1.Text = txtCorrected
END IF

myOLEObject.Dispose() // This function was my futile attempt to resolve this issue, but it seemingly has no effect whatsoever.
myOLEObject.DisconnectObject()
DESTROY myOLEObject

ma​​in 的 PowerBuilder 实例变量

String txtChecked
String txtCorrected
Int result
OLEObject myOLEObject

到目前为止,我想出的解决方案一直很奇怪。在启动 PowerBuilder 或部署的可执行文件后,从 PowerBuilder 应用程序中单击按钮只能工作一次,并且在再次尝试再次单击该按钮时会给出以下消息:

PowerBuilder 应用程序执行错误 (R0035)

应用程序终止。

错误:在第 11 行调用外部对象函数 checktext 时出错 主对象 cb_1 的点击事件。

我应该对这些代码进行哪些更改才能使其每次都能正常工作?

【问题讨论】:

  • 第一个 C# 窗口在您再次单击 PB 按钮之前是否已关闭?
  • 是的。实际上,当您单击任一按钮时,都会执行 shutdown()。

标签: c# .net com powerbuilder interopservices


【解决方案1】:

您从 PowerBuilder 获得的诊断完全不充分,无法调试问题。最好的办法是使用 Visual Studio 调试器:

  • 项目 + 属性,调试选项卡。选择“启动外部程序”单选按钮并选择您的 PowerBuilder 测试程序。
  • Debug + Exceptions,勾选 CLR Exceptions 的 Throw 复选框。这会使调试器在您的程序引发异常时停止。
  • 在 CheckText() 开始处和 Run() 调用之后的语句中设置断点。 Loaded 事件处理程序中的一个应该很有用。
  • 按 F5 开始调试。

当您单击 PowerBuilder 按钮时,您的第一个断点应该命中。检查您是否喜欢 inputMsgBase 值,按 F5 继续。再次按下按钮,调试器现在很可能停止并告诉您出了什么问题。我有一些猜测,如果不知道你看到了什么,我现在不会冒险。

【讨论】:

  • Microsoft Visual Studio 报告第一次出现“System.InvalidOperationException”类型异常的机会发生在 PrsentationFramework.dll 中。附加信息:不能在同一个 AppDomain 中创建多个 System.Windows.Application 实例。
  • 这就是我的猜测。当然可以,尤其是当第二个断点没有在第一次单击按钮时命中时。摆脱一切,只需创建一个 TextBox 类的实例。
  • 我已经完成了关于不能在同一个 AppDomain 中创建多个 System.Windows.Application 实例的搜索,但到目前为止没有任何效果。对按钮操作使用 close() 而不是 shutdown() 并没有帮助,因为它会导致应用程序挂起并等待应用程序退出或关闭。我不明白的是,当单击 .NET 窗口的任一按钮时,应用程序并未终止,正如错误消息所证明的那样。
  • 当你说在 Run() 调用之后放置第二个断点时,你的意思是 txtCorrected = MainWindow.TextReturned;正确的?我这样做了,它毫无问题地达到了这一点,并且 .NET 窗口似乎关闭了,并在第一次单击任一按钮后将更正的(或原始的,如果取消的话)值返回到 PowerBuilder 应用程序。
猜你喜欢
  • 1970-01-01
  • 2017-01-23
  • 2011-01-31
  • 2010-09-09
  • 2010-09-26
  • 2010-12-31
  • 2017-07-31
  • 1970-01-01
  • 2023-03-19
相关资源
最近更新 更多