2010-07-01 9 views
3

Je suis assez nouveau à Delphi & devez coder un client SOAP. Importation du WSDL génère ce code (que je ne peux évidemment pas changer comme je l'ai évidemment de respecter le côté serveur)Delphi 7: Violation d'accès - TByteDynArray problème

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; 

Quelqu'un peut-il me coder un exemple des valeurs factices qui appellera sendMessage() et non la cause une violation d'accès? Je ne sais vraiment pas comment gérer TByteDynArray


[Modifier] tel que demandé, voici mon code, mais - disclaimer - je devais le pirater au sujet d'un lot (réduire) avant de poster, donc il ne peut pas compiler. Les deux parms à sendMessage() ne sont pas nuls

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

Ceci est juste une interface. Que faites-vous qui provoque une violation d'accès? –

+0

+1 pour une bonne question. Il y a deux manières de résoudre ceci - montrez-vous mon code et figurez pourquoi cela ne fonctionne pas, ou quelqu'un publie du code qui fonctionne et je peux le comparer au mien.Ok, je vais poster mon code, mais la chose importante (je pense) est que les deux params sont non-nul à l'appel – Mawg

+0

Vous êtes vraiment en train d'arracher les mâchoires de la victoire parce que vous avez utilisé TByteDynArray au lieu de seulement TBytes (qui est vraiment juste une chaîne). –

Répondre

3

New Idea: Avez-vous vérifie la plage dans cette unité? Ajouter {$ R +}

Si vous voulez utiliser un type de tableau dynamique, vous devez explicitement définir sa longueur dans le constructeur avant d'y accéder, et lors de la copie/affectation, vous devez également faire très attention.

Non seulement vous devez appeler SetLength sur chaque TByteDynArray avant d'accéder à ses éléments:

SetLength(Fdata, MyDesiredLengthWhichIsGreaterThanZero): 

Vous devez aussi faire attention ici, je pense que cela pourrait vous causer des ennuis:

property data: TByteDynArray read Fdata write Fdata; 

Votre auto -generator a créé ce code pour vous, et si vous savez vraiment que vous voulez un tableau dynamique, vous pouvez le publier. (Mise à jour: j'avais tort à ce sujet initialement). TRemotable, comme le souligne Rob, ne fonctionne pas avec les propriétés indexées, mais fonctionne bien avec les propriétés "array of byte" (TByteDynArray), donc si vous faites tout correctement, vous n'avez pas besoin d'arrêter d'utiliser TByteDynArray (j'étais faux à ce sujet initialement).

Si c'était moi qui écrive ceci à partir de rien, j'utiliserais plutôt un type "string" comme TBytes. Je me demande pourquoi il n'a pas utilisé TBytes, mais je comprends que vous implémentez un client SOAP en utilisant du code générateur WSDL généré automatiquement. Donc, étant donné cela, il devrait être éminemment possible de faire en sorte que votre code ne plante pas.

see also this Related question

Je ne sais pas comment écrire un client SOAP, mais il semble que votre code fait des choses louches. Il semblerait que vous ayez besoin de corriger votre gestion dynamique de la matrice, y compris le problème "oh-oh, pourquoi fais-tu un Cast ici" que Rob vous a signalé. Cependant, il ne semble pas non plus que vous soyez libre de changer de type, car il semble que vous deviez utiliser des types connus et gérés par vos mécanismes TRemotable.

Quant à votre demande, cela devrait fonctionner:

procedure TestMe(whatever:TWhatever); 
    var 
    FData:TByteDynArray; 
    begin 
    SetLength(FData,2); 
    FData[0] := 10; 
    FData[1] := 20; 
    sendMessage(FData, whatever); 
    end; 
+0

Merci, Warren (+1). Je viens de poster mon code (avec beaucoup de choses non pertinentes supprimées). Oui, je règle la longueur. Je peux écrire le Get/Set() mais je ne peux pas le faire en accédant directement à la propriété? (Je vous ai dit que je suis nouveau à Delphi) – Mawg

+0

Vous n'avez pas défini la longueur de fdata. Et vous pensiez que SetLength (SomethingElse, 10), puis assignant fdata = somthingelse fonctionnerait, ce qui ne sera pas le cas. –

+0

Vous devez lire le guide de langage Delphi et savoir quand utiliser un tableau dynamique, et dans le cas contraire, n'utiliser aucun type de tableau dynamique. –