我试图向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的代码
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中接收调用的代码,它将调用发送到另一个单元,该单元根据接收到的命令执行数据库操作。
function TWLM_.Send(const Msg: WideString; out Answer: WideString) : Integer;
begin
Result := fmProduction.AnalyzeData(Msg, 0);
end;
我要补充的是,这可以在我的pc和同事的pc上工作,但不能在第三台pc上工作。对于如何解决这个问题,有什么建议吗?
发布于 2018-12-10 20:41:15
function TWLM_.Send(const Msg: WideString; out Answer: WideString) : Integer;
begin
Result := fmProduction.AnalyzeData(Msg, 0);
end;
在这里,您没有为Answer
参数分配任何内容。这是作为out
参数传递的,这意味着该方法需要将某些内容分配给它。这与函数返回值的行为方式完全相同。
如果你没有给这个变量赋值,那么当方法为它分配堆栈空间时,它将有一个恰好存在于堆栈上的(未赋值的)值。这将不是指向WideString
的有效指针,但消费代码将尝试对其进行编组,就好像它是。有时这会立即崩溃,有时不会,有时可能只是破坏其他数据。无论哪种情况,这都是一个错误。
在原生Delphi代码中,您可以使用out
和var
参数behaving quite similarly -在这两种情况下,对于引用类型,接受参数的方法都可以读取和写入调用代码的指针。如果方法选择不修改该值,则不需要修改该值。然而,对于托管互操作,期望总是由该方法分配一个out
参数。C#强制执行此操作,但Delphi不执行此操作。
在这种情况下,在Delphi端传递的空字符串根本不会传递给方法-您可能会认为它应该保持为空字符串,不被C#代码修改,但是通过将参数设置为out
参数,调用代码期望接收该参数中的返回值,并立即用返回的任何内容覆盖传递的变量(在本例中,是一个指向无用信息的指针)。通过扩展,C#端的变量在传递给此方法之前可能具有的任何值在Delphi/COM端都是不可访问的。
发布于 2018-12-10 20:22:54
@J...关于answer参数没有被赋值的评论,在我的例子中,就是问题所在。我让一个同事修改了dll来给参数赋值,这似乎修复了这个错误,现在它可以正常工作了。
https://stackoverflow.com/questions/53702343
复制相似问题