Delphi 7:访问冲突 - TByteDynArray问题

3

我是一名新手Delphi程序员,需要编写一个SOAP客户端。导入WSDL会生成以下代码(显然我不能更改,因为必须遵守服务器端的规定)

  DataPart            = class;             
  Message             = class;             
  eMessage            = class;             

  eventType = ( send, delete, etc );

  DataPart = class(TRemotable)
  private
    FhasData: Boolean;
    Fdata: TByteDynArray;
  published
    property hasData: Boolean read FhasData write FhasData;
    property data: TByteDynArray read Fdata write Fdata;
  end;
  Message = class(TRemotable)
  private
    FMessageID: Int64;
    Ftimestamp: TXSDateTime;
    Fevent: eventType;
    FmagicNumber: WideString;
    FDataPart: DataPart;
  published
    property MessageID: Int64 read FMessageID write FMessageID;
    property timestamp: TXSDateTime read Ftimestamp write Ftimestamp;
    property event: eventType read Fevent write Fevent;
    property magicNumber: WideString read FmagicNumber write FmagicNumber;
    property DataPart: DataPart read FDataPart write FDataPart;
  end;

  eMessage = class(TRemotable)
  private
    FencryptedMessage: TByteDynArray;
    Fdata: DataPart;
  published
    property encryptedMessage: TByteDynArray read FencryptedMessage write FencryptedMessage;
    property data: DataPart read Fdata write Fdata;
  end;

  MyApplicationPortType = interface(IInvokable)
  ['{99767D33-6B4A-7547-4DAC-0608095CAC70}']

    function  sendMessage(const encryptedMessage: TByteDynArray; const data: DataPart): WideString; stdcall;
  end;

有没有人能给我编写一个带有虚拟值的示例,调用sendMessage()而不会导致访问冲突?我真的不知道如何处理TByteDynArray


[编辑]按照要求,这是我的代码,但是 - 免责声明 - 在发布之前,我必须对其进行大量修改(缩小)。 sendMessage()的两个参数都非空

  var theMessageArray: TByteDynArray;
      theResult : WideString;
      messageData : TByteDynArray;
      i : Integer;
begin
  theMessage.messageID := theMessage.messageID + 1;
  theMessage.timestamp := TXSDateTime.Create();
  theMessage.timestamp.AsDateTime := Now();
  theMessage.event := delete;
  theMessage.magicNumber  := 'magic # ' + IntToStr(theMessage.messageID);

  SetLength(messageData, 1);
  messageData[0] := 0;

  theMessage.dataPart.hasData := True;
  messageData := theMessage.dataPart.messageData;

  SetLength(messageData, $1000 * dataSize);

  for i := 0 to $1000 * dataSize - 1 do
        messageData[i] := i and $FF;

  theMessage.DataPart.messageData := messageData;

  theMessageArray := TByteDynArray(theMessage);
  theResult := (HTTPRIO1 as MyApplicationPortType).sendMessage(theMessageArray, theMessage.dataPart);

3
这只是一个界面。你做了什么导致了访问冲突? - Mason Wheeler
一个好问题加1。有两种解决方法 - 显示我的代码并找出为什么它不起作用,或者有人发布一些有效的代码,我可以将其与自己的代码进行比较。好的,我会发布我的代码,但重要的事情(我认为)是在调用时两个参数都不为空。 - Mawg says reinstate Monica
你真的是从胜利的口中抢走了失败,因为你使用了TByteDynArray而不是只用TBytes(它实际上只是一个字符串)。 - Warren P
我非常好奇在你的Delphi版本中TByteDynArray是在哪里定义的。在Delphi 2010中,这种类型不再被定义了。至少我找不到。根据帮助文档,它在System单元中。 - Warren P
4
可能的AV源代码是这样的:theMessageArray := TByteDynArray(theMessage); 这个变量不是一个动态数组;类型转换不会使它成为一个动态数组。赋值语句将尝试增加所谓数组的引用计数,甚至可能在不崩溃的情况下运行。之后,sendMessage 尝试将该内存用作数组。它读取“长度”,并尝试访问那么多字节。那个长度并不准确反映有多少字节存在,或者也许引用计数修改已经破坏了内存。经验法则:如果你对一个动态数组进行类型转换,那么就出现了问题。 - Rob Kennedy
显示剩余8条评论
1个回答

3

新思路:您在此单元中启用了范围检查吗?请添加{$R+}

如果您想使用动态数组类型,必须在构造函数中显式设置其长度,然后才能访问它,在复制/赋值时也必须非常小心。

不仅必须在访问其元素之前对每个TByteDynArray调用SetLength:

SetLength(Fdata, MyDesiredLengthWhichIsGreaterThanZero):

在这里你也必须小心,我认为这可能会给你带来麻烦:

  property data: TByteDynArray read Fdata write Fdata;

你的自动生成器为您生成了该代码,如果您确实知道您想要一个动态数组,那么显然可以将其发布。(更新:我最初关于此事的看法是错误的)。
正如Rob所指出的那样,TRemotable不能与索引属性一起使用,但可以很好地与“byte数组”(TByteDynArray)属性一起使用,因此,如果您做得正确,您不需要停止使用TByteDynArray(我最初关于此事的看法是错误的)。
如果我从头开始编写这个程序,我会使用“string”类型,比如TBytes。我想知道为什么它没有使用TBytes,但我理解您正在使用某些自动生成的WSDL生成器代码来实现SOAP客户端。因此,在这种情况下,应该可以轻松地使您的代码不崩溃。 请参见相关问题 我不知道如何编写SOAP客户端,但是你的代码似乎有些可疑。看起来你需要修复动态数组处理,包括Rob指出的“哎呀,为什么你在这里进行了强制转换”的问题。然而,看起来你也不能随意更改类型,因为你必须使用TRemotable机制已知并处理的类型。
至于你的请求,这应该可以工作:
  procedure TestMe( whatever:TWhatever );
  var 
    FData:TByteDynArray;
  begin
     SetLength(FData,2); 
     FData[0] := 10; 
     FData[1] := 20;
     sendMessage(FData, whatever);
  end;

1
我认为你提出的修复方案与TRemotable不兼容。数组需要在类中定义,以便TRemotables的使用者知道如何获取数组的全部内容。使用数组属性无法实现这一点(因为使用者不知道有效的索引值是什么)。 - Rob Kennedy
2
如果您正在使用为您生成的自动生成代码,则必须在其错误时进行更改。请参阅我为您喜欢的相关问题:http://stackoverflow.com/questions/3154879/delphi-problem-setting-length-of-a-tbytedynarray - Warren P
1
设置本地messageData变量的长度,然后将其分配给动态数组属性似乎是正确的做法。将一个动态数组分配给另一个动态数组是完全安全的。引用计数会更新,因此数组会一直保持活动状态,直到所有人都完成为止。我认为这可能归结于确定sendMessage函数期望接收哪个字节数组。那么,Mawg,什么是MyApplicationPortType,你应该给它什么样的加密消息呢? - Rob Kennedy
嗨,Rob,MyApplicationPortType只是对真实功能的重命名 - 它发布SendMessage()函数。确实,我应该在发送之前加密MessageArray,但让我们在这里省略这一步,以简化操作。 - Mawg says reinstate Monica
如果我在那个转换处设置断点,那么在调试器中查看theMessage结构时,似乎包含宽字符串成员的指针值。那么,我应该如何将整个对象转换为TByteDynArray? - Mawg says reinstate Monica
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接