首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在C#中调用Delphi COM对象会引发AccessViolationException

在C#中调用Delphi COM对象会引发AccessViolationException
EN

Stack Overflow用户
提问于 2018-12-10 17:02:44
回答 2查看 290关注 0票数 2

我试图向Delphi COM对象发送一个字符串,并期望从该对象得到答案,但由于某种原因,它抛出了一个AccessViolationException。这是它抛出的异常,异常的描述翻译成英语是:尝试读取或写入受保护的内存。这通常表示其他内存已损坏。程序输出(带有堆栈顶部跟踪):

QManservice已启动。

按任意键即可停止。

接收订单的请求。

收到的字符串: S$GET ORDERS,Onnverwerkte uitzondering: System.AccessViolationException: Poging tot het lezen of schrijven van beveiligd geheugen。这句话的意思是:“我很高兴。”bij Microsoft.Win32.Win32Native.SysStringByteLen(IntPtr bstr)

bij System.StubHelpers.BSTRMarshaler.ConvertToManaged(IntPtr bstr)

bij QMan_SafanDarley.IWLM_.Send(字符串消息,字符串&答案)

D:\Michael\C# Projects\QManServiceConsoleApp\OrderEditor_WCF\QManService.cs:regel 210中的bij WorkLoadManagerServiceDefinitions.QManService.SendStringtoCON(String codToSend)

D:\Michael\CR Projects\QManServiceConsoleApp\OrderEditor_WCF\QManService.cs:regel 67中的bij WorkLoadManagerServiceDefinitions.QManService.RequestGetOrders() ...

这是调用COM的代码

代码语言:javascript
复制
private string SendStringToCOM(string cmdToSend)
    {
        try
        {
            Console.WriteLine($"String received: {cmdToSend}");
            if (WLM == null)
            {
                WLM = new WLM_();
            }
            string answer = string.Empty;
            WLM.Send(cmdToSend, out answer);
            Console.WriteLine("Answer received");
            return answer;
        } catch(Exception e)
        {
            Console.WriteLine(e.Message);
            Console.ReadKey();
            return string.Empty;
        }
    }

这是Delphi中接收调用的代码,它将调用发送到另一个单元,该单元根据接收到的命令执行数据库操作。

代码语言:javascript
复制
function TWLM_.Send(const Msg: WideString; out Answer: WideString) : Integer;
begin
    Result := fmProduction.AnalyzeData(Msg, 0);
end;

我要补充的是,这可以在我的pc和同事的pc上工作,但不能在第三台pc上工作。对于如何解决这个问题,有什么建议吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-12-10 20:41:15

代码语言:javascript
复制
function TWLM_.Send(const Msg: WideString; out Answer: WideString) : Integer;
begin
    Result := fmProduction.AnalyzeData(Msg, 0);
end;

在这里,您没有为Answer参数分配任何内容。这是作为out参数传递的,这意味着该方法需要将某些内容分配给它。这与函数返回值的行为方式完全相同。

如果你没有给这个变量赋值,那么当方法为它分配堆栈空间时,它将有一个恰好存在于堆栈上的(未赋值的)值。这将不是指向WideString的有效指针,但消费代码将尝试对其进行编组,就好像它是。有时这会立即崩溃,有时不会,有时可能只是破坏其他数据。无论哪种情况,这都是一个错误。

在原生Delphi代码中,您可以使用outvar参数behaving quite similarly -在这两种情况下,对于引用类型,接受参数的方法都可以读取和写入调用代码的指针。如果方法选择不修改该值,则不需要修改该值。然而,对于托管互操作,期望总是由该方法分配一个out参数。C#强制执行此操作,但Delphi不执行此操作。

在这种情况下,在Delphi端传递的空字符串根本不会传递给方法-您可能会认为它应该保持为空字符串,不被C#代码修改,但是通过将参数设置为out参数,调用代码期望接收该参数中的返回值,并立即用返回的任何内容覆盖传递的变量(在本例中,是一个指向无用信息的指针)。通过扩展,C#端的变量在传递给此方法之前可能具有的任何值在Delphi/COM端都是不可访问的。

票数 1
EN

Stack Overflow用户

发布于 2018-12-10 20:22:54

@J...关于answer参数没有被赋值的评论,在我的例子中,就是问题所在。我让一个同事修改了dll来给参数赋值,这似乎修复了这个错误,现在它可以正常工作了。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53702343

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档