This unit fails to compile in XE2 Update 3 with error "Internal Error: SY6315". In XE there is no such problem.
unit Test;
interface
uses
SysUtils;
var
Proc: TProc;
implementation
initialization
Proc := procedure
var ByteArr: array of Byte;
begin
SetLength(ByteArr, 10);
end;
end.
Does anyone have any experience of this problem?
Update: I have submitted a QC report: QC#102888.
Looks like a compiler bug, this is a workaround using TBytes
Proc := procedure
var
ByteArr: TBytes;
begin
SetLength(ByteArr, 10);
end;
Related
In a common Delphi pattern, i am passing a value as an untyped const to a function:
procedure DoSomething(const Something; SomethingLength: Integer);
begin
//...
end;
In this example, i happen to be passing Windows FORMATETC structure:
procedure Test;
var
omgp: TFormatEtc;
begin
omgp := Default(TFormatEtc);
omgp.cfFormat := RegisterClipboardFormat('CF_PNG');
omgp.ptd := nil;
omgp.dwAspect := DVASPECT_CONTENT or DVASPECT_THUMBNAIL;
omgp.lindex := -1; //all pages
omgp.tymed := TYMED_HGLOBAL;
DoSomething(omgp, SizeOf(omgp));
end;
I need to get the address of this data, so i can pass it to an underlying Windows function something that requires the pointer to the data.
In order to do this, i have always used Pointer(#data):
procedure DoSomething(const Something; SomethingLength: Integer);
begin
SomethingThatNeedsAPointer(Pointer(#Something));
end;
Until this one API call, in one particular case, is failing (it's returning the wrong values). For no particular reason, I happened to look closely at the pointer value being passed. When i was checking everythe parameter value in the debugger i noticed something horrifying. I noticed that:
#Something
Pointer(#Something)
return different values.
#Something should already be a pointer
Pointer(#Something) should be a redundant cast
Which way is the right way to get the address of untyped data?
Edit: People went to lunch on something unrelated to the question. I've edited the question so that hopefully people will focus on the question, and not the example.
This is a debugger bug, whereby the debugger is mis-reporting the value of Pointer(#Salt). I can reproduce the fault in XE5, XE6 and XE7, but not in XE4 and XE8. So it seems that this is a defect introduced in XE5 and removed in XE8.
Whenever you see an issue like this, a debugger fault is always a possibility. In this case we can demonstrate that the fault lies in the debugger with this program:
{$APPTYPE CONSOLE}
uses
System.SysUtils;
procedure DoSomething(const Salt; SaltLength: Integer);
begin
Writeln(IntToHex(NativeUInt(Pointer(#Salt)), 8));
Writeln(IntToHex(NativeUInt(#Salt), 8));
end;
procedure Test;
var
salt: AnsiString;
begin
salt := 'salt';
DoSomething(salt[1], Length(salt));
end;
begin
Test;
end.
This program outputs:
007C9BD4
007C9BD4
even though #Salt and Pointer(#Salt) are accorded different values by the debugger.
Note that this program
{$APPTYPE CONSOLE}
procedure DoSomething(const Salt; SaltLength: Integer);
var
i: Integer;
P: PAnsiChar;
begin
P := #Salt;
for i := 0 to SaltLength-1 do
begin
Writeln(P^);
inc(P);
end;
end;
procedure Test;
var
salt: AnsiString;
begin
salt := 'salt';
DoSomething(salt[1], Length(salt));
end;
begin
Test;
end.
outputs:
s
a
l
t
I cannot reproduce your case in XE8.
The debugger shows same address for both #Salt and Pointer(#Salt).
Likewise the output of this test snippet is identical.
I can only assume that what the debugger is telling you is untrue somehow.
(Update: A test in XE7 reproduces the error in the debugger. The outcome of the snippet is the same though.)
program Test;
{$APPTYPE CONSOLE}
procedure Test1(p: Pointer);
begin
WriteLn(Cardinal(p));
end;
procedure Test(const Salt);
begin
Test1(#Salt);
Test1(Pointer(#Salt));
Test1(Addr(Salt));
end;
var
s:AnsiString;
begin
s := 'Test';
Test( s[1]);
ReadLn;
end.
I'm porting program from Delphi 2009 to XE4 and got problem with LockBox encryption. Encrypt/decrypt unit is using just one component:
interface
function Encrypt(aStr: String): String;
function Decrypt(aStr: String): String;
function NeedEncrypt(): Boolean;
implementation
uses
windows,
strUtils,
LbClass;
var
LbRijndael: TLbRijndael;
localNeedEncrypt: Boolean;
function NeedEncrypt(): Boolean;
begin
Result := localNeedEncrypt;
localNeedEncrypt := False;
end;
function Encrypt(aStr: AnsiString): AnsiString;
begin
Result := aStr;
if RightStr(aStr, 2) = '==' then
Exit;
Result := LbRijndael.EncryptString(aStr);
end;
function Decrypt(aStr: AnsiString): AnsiString;
begin
Result := aStr;
if RightStr(aStr, 2) = '==' then
Result := LbRijndael.DecryptString(aStr)
else
localNeedEncrypt := True;
end;
initialization
LbRijndael := TLbRijndael.Create(nil);
LbRijndael.GenerateKey('KEYABC');
LbRijndael.CipherMode := cmECB;
LbRijndael.KeySize := ks128;
end.
As I understood there is no LockBox2 for Delphi XE4.
Can I use LockBox3 for this purpose? If yes, can I use just needed units without installation into Delphi (this was done with LockBox2)?
Whilst the LB2 and LB3 APIs are very different, you should be able to port this code across without too much difficulty. As you are creating the components dynamically at runtime, you shouldn't need to install the packages into your IDE, providing your library path is set to include the LB3 source.
i'm trying to call a procedure within a class using super object, but it won't work, what am i doing wrong here ?
Code sample:
program test_rpc;
{$IFDEF FPC}
{$MODE OBJFPC}{$H+}
{$ELSE}
{$APPTYPE CONSOLE}
{$ENDIF}
uses
SysUtils, superobject;
type
TCC = class(TObject)
published
procedure controler_method1(const This, Params: ISuperObject; var Result: ISuperObject);
end;
procedure TCC.controler_method1(const This, Params: ISuperObject; var Result: ISuperObject);
var
i: Integer;
begin
write('action called with params ');
writeln(Params.AsString);
end;
var
s: ISuperObject;
CC: TCC;
begin
CC := TCC.Create;
s := TSuperObject.Create;
s.M['controler.action1'] := CC.MethodAddress('controler_method1');
try
s['controler.action1("HHAHAH")'];
finally
s := nil;
writeln('Press enter ...');
readln;
end;
end.
that will crash, what am i doing wrong here ?
it actually gets to "action called with Params" but fails to show the param...
The super method has signature as follows:
TSuperMethod = procedure(const This, Params: ISuperObject;
var Result: ISuperObject);
This means that you cannot use an instance method since an instance method has an incompatible signature. Your method must look like this:
procedure sm(const This, Params: ISuperObject; var Result: ISuperObject);
begin
....
end;
The reason you get a runtime error rather than a compile time error is that you abandoned the type system by using the # operator. Remove the # and your program will fail at compile time with an error message that is a terser version of what I said above.
It's one of the great fallacies of Delphi programming that one must use the # operator to obtain a function pointer. It's a bad habit that you would do well to unlearn.
I recently migrated from D2010 to DXE2 and found a showstopper bug (Or feature?) in XE2 and XE3 (Tested in my friend XE3) related to RTTI generation for TBytes fields inside classes.
I found that the RTTI information for a TBytes variable inside a class is never generated.
The following code works well in D2010, but shows the message "Error" in XE2/XE3
Does anyone have any clue? This will totally break all our software data serialization implementation
To test the code please add Rtti unit to the uses declaration
type
TMyClass = class
public
Field1: Integer;
Field2: TBytes;
end;
procedure TForm2.Button1Click(Sender: TObject);
var
i: Integer;
Data: TMyClass;
Rtti: TRttiContext;
RttiClassType: TRttiInstanceType;
begin
Data := TMyClass.Create;
try
// Get the context
Rtti := TRttiContext.Create;
try
// Get the type for the class
RttiClassType := TRttiInstanceType(Rtti.GetType(Data.ClassInfo));
// Check the fields
for i := 0 to High(RttiClassType.GetFields) do
begin
// Check the field type
if not Assigned(RttiClassType.GetFields[i].FieldType) then
ShowMessage('Error');
end;
finally
Rtti.Free;
end;
finally
Data.Free;
end;
end;
The error message will be displayed when checking for Field2 that is a TBytes becayse the FieldType is always nil!!!
Does anyone has any clue of what have changed in the RTTI from D2010 do XE2? Maybe because the TBytes type was changed from array of Byte to the generic array?
You can fix this error (it is actually not the same bug as the one Mason mentioned).
type
FixTypeInfoAttribute = class(TCustomAttribute)
public
FTypeInfo: PPTypeInfo;
constructor Create(TypeInfo: PTypeInfo);
end;
procedure FixFieldType(TypeInfo: PTypeInfo);
var
ctx: TRttiContext;
t: TRttiType;
f: TRttiField;
a: TCustomAttribute;
n: Cardinal;
begin
t := ctx.GetType(TypeInfo);
for f in t.GetFields do
begin
for a in f.GetAttributes do
begin
if (a is FixTypeInfoAttribute) and f.ClassNameIs('TRttiInstanceFieldEx') then
begin
WriteProcessMemory(GetCurrentProcess, #PFieldExEntry(f.Handle).TypeRef,
#FixTypeInfoAttribute(a).FTypeInfo, SizeOf(Pointer), n);
end;
end;
end;
end;
constructor FixTypeInfoAttribute.Create(TypeInfo: PTypeInfo);
begin
FTypeInfo := PPTypeInfo(PByte(TypeInfo) - SizeOf(Pointer));
end;
Then you add the attribute to your class definition:
type
TMyClass = class
private
Field1: Integer;
[FixTypeInfo(TypeInfo(TBytes))]
Field2: TBytes;
end;
and make sure the FixFieldType routine is called:
initialization
FixFieldType(TypeInfo(TMyClass));
Tested on XE
This is a known issue that was fixed in XE3. Unfortunately, upgrading is the only way to get a fix for it; bug fixes don't usually get ported back.
EDIT: Or not. Apparently this is not actually fixed, as it still occurs in XE3. Reporting it as a new case and mentioning 103729 would probably be the best course of action.
can anyone tell me why I get "Return value ... might be undefined" here:
function TXMLAcceptorBCOLSubmission.createRecordsInBCFEEPAR(AXML: TRipXMLElement): String;
var
...
begin
Result := '';
I am using Delphi 5 and it looks like the problem is caused by declaring more than 30 variables (I know, I know). It doesn't seem to matter what they are called or what types they are.
Following code doesn't generate a warning using Delphi 5 so
either it is a bug in an other Delphi version (you should mention the version you use)
or either it is something you didn't show us yet.
Code
program ProveAPoint;
{$APPTYPE CONSOLE}
uses SysUtils;
type
TRipXMLElement = record
end;
TXMLAcceptorBCOLSubmission = class
public
function createRecordsInBCFEEPAR(AXML: TRipXMLElement): string;
end;
function TXMLAcceptorBCOLSubmission.createRecordsInBCFEEPAR(AXML: TRipXMLElement): String;
begin
Result := '';
end;
var
AXML: TRipXMLElement;
begin
with TXMLAcceptorBCOLSubmission.Create do
begin
createRecordsInBCFEEPAR(AXML);
Free;
end;
end.