【问题标题】:COM Interop AccessViolationException intermittently WCF CallbackCOM Interop AccessViolationException 间歇性 WCF 回调
【发布时间】:2014-11-10 21:04:13
【问题描述】:

我们有一个基于 .NET 4 的服务,它自己托管一个带有回调的 WCF 服务。我们将此服务封装在公开 COM 对象的 .NET 4 dll 中。该服务被多种客户端使用,其中大多数是基于 .NET 的。

不幸的是,我们有一些无法更改的 VB6 客户端,并且在调用某些回调方法时会收到 AccessViolationExceptions。

服务的结构方式如下图所示。

MethodA由 VB6 客户端调用,通过 .NET dll 代理到 WCF 服务(尚未返回)

WCF CallbackA 调用提供枚举状态值

可能会调用 WCF CallbackB,需要 VB6 客户端进一步输入(此信息在 MethodA 开始时无法获取,会影响 MethodA 的结果)

方法A返回

CallbackA(效果很好,没有异常!)它是一个提供枚举的 OneWayOperation,VB 应用程序当前正在将此值写入 RichTextbox。

CallbackB(导致 AccessViolationException)是一种提供对象并期望返回具有两个基于值的属性的不同对象的方法。

我觉得这是尝试在与主线程不同的线程上创建 COM 对象时出现的某种问题(因为它当前挂在 MethodA 上)。不幸的是,我不确定如何纠正这个问题。我们可以控制服务中的代码、封装的 dll,我们可以就 VB6 客户端中的代码提供建议。

我们有自己的 VB6 测试应用程序,我们可以绕过 AccessViolation 错误....但它涉及注释掉回调方法中的任何代码(请参见下面的代码)我已经突出显示了如果留在其中导致异常的行“

Private Function ITerminalCallbackComClient_VerifySignature() As Long
Dim result As Long

'Not-Authorized = 0 and Authorized = 1'
result = 0

Dim msgResponse As Long

msgResponse = MsgBox("Signature Accepted?", vbYesNo + vbQuestion, "Signature Verification")

If msgResponse = vbYes Then
    result = 1
End
End If

ITerminalCallbackComClient_VerifySignature = result
End Function

2014 年 11 月 13 日更新

回调在 Visual Studio 6 中调试时起作用。但只要我们“制作”示例项目,它就会在执行回调时崩溃。如果我们删除对 MsgBox 的引用并只映射回一个静态值,它会按预期工作。

我们已更新 COM 互操作的签名以删除所有对象引用,而不仅仅是返回 0 或 1 以避免对象命名问题。

我已经更新了上面的VB6回调代码。

回调合约

[CallbackBehaviorAttribute(ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
public abstract class PS_Terminal_Link_Callback : ITerminalCallback
{

public abstract long VerifySignature();

}

服务合同

[ServiceContract(CallbackContract=typeof(ITerminalCallback))]
public interface ITerminal
{
   *MethodA*
}

【问题讨论】:

  • 如果在End If 之后移动Dim request As New... 行并从赋值中拆分声明(即,将Dim request As New... 更改为Dim request As PS_Terminal... 后跟Set request = New PS_Terminal...)会发生什么?
  • 我会尝试,但如果我删除所有对“请求”对象的引用,即使只使用 MsgBox 代码,它仍然会失败。如果我将所有涉及“请求”对象和 MsgBox 的行注释掉,该方法将执行并返回没有错误......不幸的是,这不是一个有效的修复。
  • 谢谢。我认为只是将代码从intResponse = MsgBox... 注释到End If 仍然失败?另外,定义ITerminalCallbackComClient.VerifySignature的代码(大概是.NET或COM)是什么?
  • 还是遇到这个问题,感谢建议,我已经添加了我在VB6端运行的更新代码以及Service合约和回调的定义。

标签: c# wcf vb6 com-interop sta


【解决方案1】:

如果是 VB6 代码,LONG 是 VB6 中的 win32 整数。为了与 16 位基本整数兼容,在 VB6 中是 16 位。长是 32 位。您将 VB6 long(32 位)放入消息框行中的 VB6 整数(16 位)中。

您的其他对象对您来说是私有的,因此我们无法查看它的规格和文档。

【讨论】:

  • 我不确定您在哪里看到了很长的内容,请查看对 VB6 代码的更新,该代码仍然失败并出现相同的异常。感谢您抽出宝贵时间回复。
  • Dim intResponse As Integer intResponse = MsgBox("Signature Accepted?", _ vbYesNo + vbQuestion, _ "Signature Verification") 将 Dim intResponse 设为 long(32 位)。
  • 啊,好吧,我明白你在说什么。出于调试目的,我已经完全删除了 MsgBox 的代码,包括 int vs Long 代码,问题仍然存在。
  • 我知道 COM 和 VB6/VBA/VBScript(以及其他基础知识)。如果将 dim 更改为 long,则 msgbox 将不再出错,永远。 COM的一些一般负责人。 .NET 的规则说,如果 com 对象不调用 .NET,它只能调用 com 对象。在 VB6 中,我们有所谓的 Publicaly Created Objects(就像您正在做的那样)和 Non-Creatable(您必须对可创建对象调用方法调用才能获得不可创建对象)。
  • 我已经进行了您提到的长期更改以及其他一些更新。该代码现在在 Visual Studio 6 中调试 VB6 代码时执行。一旦我们“制作”VB6 应用程序,它就会崩溃并出现与以前相同的异常。这是进步,但调试与非调试有什么不同。
【解决方案2】:

您也可以在调试器中启动。

windbg 或 ntsd(ntsd 是一个控制台程序,可能已安装)。两者都来自 Debugging Tools For Windows。

下载并安装 Windows 调试工具

http://msdn.microsoft.com/en-us/windows/hardware/hh852363

安装 Windows SDK,但只需选择调试工具。

在**C:**中创建一个名为Symbols的文件夹

启动 Windbg。 文件菜单-符号文件路径并输入

srv*C:\symbols*http://msdl.microsoft.com/download/symbols

然后

windbg -o -g -G c:\windows\system32\cmd.exe /k batfile.bat

您可以按F12 停止它,kb 将显示调用堆栈(g 继续程序)。如果有错误,它也会停止并显示它们。

键入lm 列出加载的模块,键入x *!* 列出符号,键入bp symbolname 设置断点

如果在 VB6 中编程,则此环境变量 link=/pdb:none 将符号存储在 dll 中,而不是单独的文件中。确保在没有优化的情况下编译程序并勾选 Create Symbolic Debug Info 框。两者都在项目属性的编译选项卡上。

CoClassSyms (microsoft.com/msj/0399/hood/hood0399.aspx) 也可以从类型库中生成符号。

在 COM 调用上放置一个断点(使用x *!* 找到它)。

现在您可以检查参数和/或查看详细的异常信息。

.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-25
    • 2011-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多