Someone managed to install InstantObjects in Delphi XE4?
I'm compiling the latest sources who are on svn repository. After correcting some issues as the compiler version, I am stuck in the following code snippet:
procedure TInstantAccessor.SetOnCompare(Value: TInstantCompareObjectsEvent);
begin
if #Value <> #FOnCompare then
begin
FOnCompare := Value;
RefreshView;
end;
end;
Resulting in the error message "[dcc32 Error] InstantPresentation.pas (1580): E2008 Incompatible types" on the line:
if #Value <> #FOnCompare then
But they are the same type: TInstantCompareObjectsEvent
What's wrong?
Maybe casting the procedural pointer to the generic Pointer type can solve:
procedure TInstantAccessor.SetOnCompare(Value: TInstantCompareObjectsEvent);
var
PValue, PFOnCompare: Pointer;
begin
PValue := Pointer(#Value); // Casting the original pointer to an generic pointer
PFOnCompare := Pointer(#FOnCompare);
if #PValue <> #PFOnCompare then
begin
FOnCompare := Value;
RefreshView;
end;
end;
What Fabricio wrote in the comments make sense. I surrounded the code with the directives {$T-} and {$T+} and the code compiled!
Now I'm in trouble in other parts of the code, but that's another story.
procedure TInstantAccessor.SetOnCompare(Value: TInstantCompareObjectsEvent);
begin
{$T-}
if #Value <> #FOnCompare then
begin
FOnCompare := Value;
RefreshView;
end;
{$T+}
end;
Thank you all.
Related
Found that exception handling in Delphi Tokyo behaves a little different than in previous Delphi versions.
function FuncTest: integer;
begin
Result := 1;
try
raise Exception.Create('Error Message');
finally
Result := 2;
end;
end;
function Test:integer;
begin
Result:=0;
try
Result:=FuncTest;
finally
ShowMessage(Result.ToString);
end;
end;
In earlier Delphi versions the message box shows here "2", Tokyo - "0".
Is this a Tokyo bug or the exceptions should not be handled like this?
The Tokyo behaviour is correct. A function that raises an exception does not return a value. You have hitherto been relying on implementation detail.
Consider this code:
Result:=FuncTest;
This executes as follows:
FuncTest is called.
Result is assigned.
Now, because step 1 raises an exception, step 2 does not execute.
If anything, I would say that the behaviour you report from earlier versions is dubious. In this function:
function Test:integer;
begin
Result:=0;
try
Result:=FuncTest;
finally
ShowMessage(Result.ToString);
end;
end;
The statement Result:=FuncTest raises an exception and so Result should not be modified by that statement. Another way to think of it is that the function is called but the assignment is not executed.
One of the problems with the Delphi ABI is that function return values are sometimes implemented as implicit var parameters. Which means that the assignment may or may not happen. To demonstrate:
{$APPTYPE CONSOLE}
uses
System.SysUtils;
type
TRec1 = record
X1: NativeInt;
end;
TRec2 = record
X1: NativeInt;
X2: NativeInt;
end;
function GetRec1: TRec1;
begin
Result.X1 := 1;
raise Exception.Create('');
end;
function GetRec2: TRec2;
begin
Result.X1 := 1;
raise Exception.Create('');
end;
procedure Main;
var
Rec1: TRec1;
Rec2: TRec2;
begin
Rec1 := Default(TRec1);
Writeln(Rec1.X1);
try
Rec1 := GetRec1;
except
end;
Writeln(Rec1.X1);
Rec2 := Default(TRec2);
Writeln(Rec2.X1);
try
Rec2 := GetRec2;
except
end;
Writeln(Rec2.X1);
end;
begin
Main;
Readln;
end.
This outputs:
0
0
0
1
Which is rather disappointing. It should not be possible to modify the caller's variable, but the use of an implicit var parameter rather than a value return allows this leakage. In my view this is a serious flaw in the design of the Delphi ABI, a flaw that you will not find in most other languages.
In your code, there is no var parameter because the return type is transferred in a register. In which case any Delphi version that outputs 2 is broken.
Fundamentally though, your code is mistaken in its expectations. If a function raises an exception then you must assume that the return value is ill-defined.
Finally, your code outputs 0 in XE3 and XE7, so I wonder how far back you need to go to see a value of 2.
Consider this:
function FuncTest: integer;
begin
Result := 1;
try
try
raise Exception.Create('Error Message');
except
{ do nothing }
end
finally
Result := 2;
end;
end;
Don't think that "finally" handles an exception locally, rather than "returning an exception". To handle it locally requires a LOCAL try-except clause.
There is an old project that I need to recompile to XE5 trying to aavoid the weird Twebbrowser errors that the original D7 component brings. The code bellow works great on D7 but not on XE5.
function GetFrame(FrameNo: Integer; WB: TWEbbrowser): IWebbrowser2;
var
OleContainer: IOleContainer;
enum: IEnumUnknown;
unk: IUnknown;
Fetched: PLongint;
begin
while WB.ReadyState <> READYSTATE_COMPLETE do
Application.ProcessMessages;
if Assigned(WB.document) then
begin
Fetched := nil;
OleContainer := WB.Document as IOleContainer;
OleContainer.EnumObjects(OLECONTF_EMBEDDINGS, Enum);
Enum.Skip(FrameNo);
Enum.Next(1, Unk, Fetched);
Result := Unk as IWebbrowser2;
end
else
Result := nil;
end;
I've checked and the parameters for EnumObjects are the same on both versions but XE5 says "E2033. Types of actual and formal var parameters must be identical".
Any idea how I can recompile this puppy? Thanks. Peace!
For a variable parameter, the actual argument must be of the exact type of the formal parameter.
If you get the error I can assume that type of your enum variable is not of type : ActiveX.IEnumUnknown, so you can try to change this line in the variable declaration section :
enum: IEnumUnknown;
to :
enum: ActiveX.IEnumUnknown;
In my studying process I use "Coding in Delphi" book by Nick Hodges. I am using Delphi 2010.
In the chapter about anonymous methods, he provides a very interesting example about faking .NET using. When I try to compile the example, I get an error from the compiler. Please help me to get a result.
My class:
type
TgrsObj = class
class procedure Using<T: class>(O: T; Proc: TProc<T>); static;
end;
implementation
{ TgrsObj }
class procedure TgrsObj.Using<T>(O: T; Proc: TProc<T>);
begin
try
Proc(O);
finally
O.Free;
end;
end;
Here is how I try to use the code above:
procedure TForm4.Button1Click(Sender: TObject);
begin
TgrsObj.Using(TStringStream.Create,
procedure(ss: TStringStream)
begin
ss.WriteString('test string');
Memo1.Lines.Text := ss.DataString;
end);
end;
Compiler error:
[DCC Error] uMain.pas(36): E2010 Incompatible types: 'TProc<ugrsObj.Using<T>.T>' and 'Procedure'
That is because type inference in Delphi is poor. It could in fact infere T from the first parameter but unfortunately the compiler is not satisfied then for the second parameter which would perfectly match.
You have to explicitly state the type parameter like this:
TgrsObj.Using<TStringStream>(TStringStream.Create, procedure(ss: TStringStream)
begin
ss.WriteString('test string');
Memo1.Lines.Text := ss.DataString;
end);
I have written a code with Delphi 2009 and updated my CodeGear Delphi to XE2. It compiled perfectly with Delphi 2009, but now it doesn't ! It gives me this error instead :
[DCC Error] Incompatible types: 'TFormStyle' and 'TTeeFontStyle'!
I tried creating a new Vcl Forms Application and wrote the command that generates this error :
Form1.FormStyle := FsNormal;
and it compiled perfectly too,I don't know why is this happening, although I believe there's nothing wrong with my syntax, please help, thanks.
This is the code that is not compiling :
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
var Handled: Boolean);
begin
begin
KeyPreview := True;
case Msg.message of
WM_KEYDOWN:
if Msg.wParam = 27 then
begin
form1.Menu:=mainmenu1;
fullscreen1.Checked:=false;
form1.formstyle:=fsnormal;
form1.BorderStyle:=bssizeable;
end
else
if msg.wParam=VK_f5 then
begin
browser.Navigate(memo2.Text);
end;
end;
end;
end;
There is name conflict with some TeeChart module, which is in "use" clause. You can write full-qualified identificator name to resolve this problem:
formstyle := Vcl.Forms.fsnormal;
P.S. Note that I deleted "form1." qualifier also. Normally it is not very useful in the form method body, and sometimes even harmful (imagine that you have multiple instances of TForm1)
In addition to the answer of MBo, I think it is better to use:
Self.formstyle := Vcl.Forms.fsnormal;
When you have multiple instances of TForm1, this will always adjust the instance you are using at that moment.
Qualify the value with the particular enum type that it comes from:
Form1.FormStyle := TFormStyle.fsNormal;
Or even:
Form1.FormStyle := Vcl.Forms.TFormStyle.fsNormal;
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.