Ce n'est pas exactement une question simple parce que je viens de le résoudre, mais plus comme "suis-je le droit" type de question et un rappel pour ceux qui pourraient se coincer dans cela.désalignement de pile Delphi + com marshalling = mauvaise affectation
Il s'avère que Delphi n'aligne pas les variables sur la pile et qu'il n'y a pas de directives/options pour contrôler ce comportement. Le marshaller de COM par défaut sur mon XP SP3 semble exiger l'alignement de 4 bytes en marshaling cependant des enregistrements. Pire, quand il rencontre un pointeur non aligné, il ne renvoie pas d'erreur, oh non: il arrondit le pointeur à la limite de 4 octets la plus proche et continue ainsi. Par conséquent, si vous transmettez un enregistrement que vous avez attribué sur une pile dans la fonction COM-marshaled par référence, vous êtes vissé et vous ne le saurez même pas. Le problème peut être résolu en utilisant New/Dispose pour allouer des enregistrements, car les gestionnaires de mémoire ont tendance à aligner tout à 8 octets ou mieux, mais dieu, c'est ennuyeux, à la fois la partie de désalignement et les "trim-down-pointers" " partie.
Est-ce vraiment la raison, ou ai-je tort quelque part?
Mise à jour: Comment reproduire (Delphi 2007 pour Win32).
uses SysUtils;
type
TRec = packed record
a, b, c, d, e: int64;
end;
TDummy = class
protected
procedure Proc(param1: integer);
end;
procedure TDummy.Proc(param1: integer);
var a, b, c: byte;
rec: TRec;
begin
a := 5;
b := 9;
c := 100;
rec.a := param1;
rec.b := a;
rec.c := b;
rec.d := c;
writeln(IntToHex(integer(@rec), 8));
readln;
end;
var Obj: TDummy;
begin
obj := TDummy.Create;
try
obj.Proc(0);
finally
FreeAndNil(obj);
end;
end.
Ceci donne une adresse de résultat impaire, clairement non alignée sur quoi que ce soit. Si ce n'est pas le cas, essayez d'ajouter plus de variables octets à "a, b, c: byte" (et n'oubliez pas de simuler un peu de travail avec eux à la fin de la fonction).
La partie avec COM est plus facile à reproduire mais plus longue à expliquer. Créez une nouvelle application VCL appelée Sample Server, ajoutez un objet COM SampleObject implémentant ISampleObject, avec une bibliothèque de types, une instance unique à thread libre (assurez-vous de vérifier que ISampleObject est marqué comme Ole Automation dans la bibliothèque de types). Ouvrez la bibliothèque de types, déclarez un nouvel SampleRecord avec cinq champs __int64. Ajoutez une SampleFunction avec un seul paramètre SampleRecord * out à ISampleObject. Mettre en œuvre sampleFunction en TSampleObject par des valeurs fixes de retour:
function TSampleObject.SampleFunction(out rec: SampleRecord): HResult;
begin
rec.a := 1291;
rec.b := 742310;
//...
Result := S_OK;
end;
Notez comment Delphi déclare SampleRecord comme « enregistrement emballé » dans le code d'en-tête bibliothèque de type généré automatiquement:
SampleRecord = packed record
a: Int64;
b: Int64;
//...
end;
J'ai vérifié, et cela, au moins , a été corrigé dans Delphi 2010. Les enregistrements générés automatiquement ne sont pas compressés.
Enregistrez le serveur COM. Exécuter.
modifier maintenant la source ci-dessus (exemple 1) pour appeler ce serveur au lieu de simplement faire writeln:
uses SysUtils, Windows, ActiveX, SampleServer_TLB;
procedure TDummy.Proc(param1: integer);
var a, b, c: byte;
rec: SampleRecord;
Server: ISampleObject;
begin
a := 5;
b := 9;
c := 100;
rec.a := param1;
rec.b := a;
rec.c := b;
rec.d := c;
Server := CoSampleObject.Create;
hr := Server.SampleFunction(rec);
writeln('@: 'IntToHex(integer(@rec), 8)+', rec.a='+IntToStr(rec.a));
readln;
end;
var Obj: TDummy;
begin
CoInitializeEx(nil, COINIT_MULTITHREADED);
obj := TDummy.Create;
try
obj.Proc(0);
finally
FreeAndNil(obj);
CoUninitialize();
end;
end.
Observons que, si l'adresse de rec est pas aligné, les valeurs des champs rec sont erronés (en particulier, bitshifted à 8, 16 ou 24 bits, parfois enveloppé à la prochaine valeur).
Quelle version de Delphi, quel gestionnaire de mémoire? Pouvez-vous donner un exemple que nous pouvons essayer? –
Delphi 2007, prêt à l'emploi FastMM4. Exemples ajoutés – himself
Veuillez entrer un rapport dans Quality Central avec ce scénario de test. http://qc.embarcadero.com –