Delphi Dynamic Array assign to temporary local dynamic array variable - delphi

I have problem with new released delphi 10.2 the new compiler show error when
var
FGlobalVar: array of integer;
procedure SomeProc()
var
ALocalVar: array of integer;
begin
ALocalVar := Pointer(FGlobalVar); {assign dynamic array}
{Do Something}
end;
In previous version compiler delphi not show any errors.

That code should never have compiled, and Tokyo closes the loop hole. The problem with that cast is that reference counting can by bypassed. The code as you have it does not suffer that problem, but if the cast is written on the left hand side of the assignment, then no reference is taken.
Pointer(LocalVar) := GlobalVar;
Written this way round, LocalVar is assigned a reference to the dynamic array but the reference count is not incremented. I appreciate that your code is not written this way round, but I believe that this is the reason why the developers chose to make the change.
In any case, yhere is no need for the cast if you use types that are compatible. Switch to TArray<Integer> and the cast is not necessary. Further, your code will be able to interact with generic methods.

Related

Delphi TDictionary : values are replace automatically when have the same key

I am using delphi XE5.
This a resume of my code, Next code works, but there have to be something in my code that destroy normal behaviour:
unit Class1;
type
TClass1 = class
private
FDic:TDictionary<String,String>.Create;
public
constructor create;
procedure insertValue(key,value:String);
end;
implementation
constructor TClass1.create;
begin
FDic:=TDictionary<String,String>.Create;
end;
procedure insertValue(key,value:String);
begin
if(FDic.ContainsKey(key))then
FDic[key] := value
else
begin
FDic.Add(key,value);
end;
end.
And now another unit:
unit Class2;
type
uses Class2;
TClass1 = class
public
class2 :TClass2;
TS: TStringList;
procedure DoSomething;
end;
implementation
procedure TClass1.DoSomething;
var
i: Integer;
c,test: TClass1;
begin
c := TClass1.create;
c.insertValue('height','.34cm');
c.insertValue('width','22cm');
c.insertValue('radio','2cm');
TS.AddObject('square',c);
c := TClass1.create;
c.insertValue('height','.88cm');
c.insertValue('width','11cm');
c.insertValue('top','12cm');
TS.AddObject('circle',c);
test := TS.Objects[0] as TClass1;//test.FDic height should be .34cm but gets the value of the last object create, the same for width an common keys.
//here when I look for the values of FDic test.FDic.Items['height'] the value is .88cm instead of .34cm, each time the values of any element of the Dictionary is replace with the previous of the last object created. And the memory address is the same. Why don't create a new memory address for any new element if it is a different object.
That is a resume of my code, I can put all my code because is too big, but I would like to know where I can search to resolve this problem. I am not is not easy, maybe I am not the only one with that problema, maybe some class in the uses, class variables, there is something that causes a memory problema in that dictionary, but no way to find it.
It's a little hard to be sure of the problem because you posted code that does not compile. For future reference, please don't do that. It's good to cut down the code to a small size, but you should then make it into a small console application that compiles and runs and demonstrates the fault. In spite of this, I think that I can see where the problem is.
You are creating objects and then adding them to a string list with
TS.AddObject(...);
But then you never free those objects. That, I guess, is the source of the leak. You can deal with this by setting the OwnsObjects property of the string list to True.
Specifies whether the string list owns the objects it contains.
The OwnsObjects property specifies whether the string list owns the
stored objects or not. If the OwnsObjects property is set to True,
then the Destroy destructor will free up the memory allocated for
those objects.
That I think will explain the leaks. The other part of your question is why index 0 contains the item that you added second. The only explanation for that, given the code in the question, is that your string list has the Sorted property set to True.
Again, I'm inferring this with a little intuition, but if you have only posted a complete program that compiled and run then your question could have been answered with complete certainty.
I do wonder whether or not a string list is the correct class to be using here. Perhaps you would be better with TObjectDictionary<string, TClass1>. You would create it like this:
dict := TObjectDictionary<string, TClass1>.Create([doOwnsValues]);
The use of doOwnsValues tells the dictionary that it is take assume ownership of the objects that you add as values and destroy them when they are removed from the dictionary, or when the dictionary is destroyed.
Note also that your insertValue method can be implemented in a far simpler way using the AddOrSetValue method.

Access Violation when handling forms

I have procedure to show/hide one element on TForm like that:
procedure ShowHideControl(const ParentForm: TForm; const ControlName: String; ShowControl: Boolean);
var
i: Integer;
begin
for i := 0 to pred(ParentForm.ComponentCount) do
begin
if (ParentForm.Components[i].Name = ControlName) then
begin
if ShowControl then
TControl(ParentForm.Components[i]).Show
else
TControl(ParentForm.Components[i]).Hide;
Break;
end;
end;
end;
then I try to use it like:
procedure TForm1.Button6Click(Sender: TObject);
begin
ShowHideEveryControl(TForm(TForm1), 'Button4', True);
end;
Why do I get Access Violation on Button6 click?
For me everything is OK... Button4 exists as a child :)
This cast is wrong:
TForm(TForm1)
You are telling the compiler to ignore the fact that TForm1 is not a TForm instance, and asking it to pretend that it is. That is fine until you actually try to use it as an instance, and then the error occurs.
You need to pass a real instance to a TForm descendent. You can write it like this:
ShowHideEveryThing(Self, 'Button4', True);
Just in case you are not clear on this, the parameter of your procedure is of type TForm. That means you need to supply an instance of a class that either is, or derives from TForm. I repeat, you must supply an instance. But you supply TForm1 which is a class.
And then the next problem comes here:
if (ParentForm.Components[i].Name = FormName) then
begin
if ShowForm then
TForm(ParentForm.Components[i]).Show
else
TForm(ParentForm.Components[i]).Hide;
Break;
end;
Again you have used an erroneous cast. When the compiler tells you that it a particular object does not have a method, you must listen to it. It's no good telling the compiler to shut up and pretend that an object of one type is really an object of a different type. Your button is categorically not a form, so don't try to cast it to TForm.
It is very hard to know what you are actually trying to do here. When you write:
ShowHideEveryThing(Self, 'Button4', True);
It would seem to me to me more sensible to write:
Button4.Show;
It is not a good idea to refer to controls using their names represented as text. It is much safer and cleaner to refer to them using reference variables. That way you let the compiler do its job and check the type safety of your program.
The names used in your function are suspect:
procedure ShowHideEveryThing(const ParentForm: TForm; const FormName: String;
ShowForm: Boolean);
Let's look at them:
ShowHideEveryThing: but you claim that the function should show/hide one element. That does not tally with the use of everything.
FormName: you actually pass a component name, and then look for components owned by ParentForm that have that name. It seems that FormName is wrong.
ShowForm: again, do you want to control visibility of the form, or a single element?
Clearly you need to step back and be clear on the intent of this function.
As an aside, you should generally never need to write:
if b then
Control.Show
else
Control.Hide;
Instead you can write:
Control.Visible := b;
My number one piece of advice to you though is to stop casting until you understand it properly. Once you understand it properly, design your code if at all possible so that you don't need to cast. If you ever really do need to cast, make sure that your cast is valid, ideally by using a checked cast with the as operator. Or at least testing first with the is operator.
Your code shows all the hallmarks of a classic mistake. The compiler objects to the code that you write. You have learnt from somewhere that casting can be used to suppress these compiler errors and now you apply this technique widely as a means to make your program compile. The problem is that the compiler invariably knows what it is talking about. When it objects, listen to it. If ever you find yourself suppressing a compiler error with a cast, take a step back and think carefully about what you are doing. The compiler is your friend.

Porting mozilla's NSModule to Delphi

In extension to this question, I guess I'll best show what I've got so far.
What I'm trying to do is create a Firefox extension with Delphi, that'll work with the Firefox versions of the future that will use an exported NSModule structure, and no longer an NSGetModule function.
Main questions I'm struggling with for the moment is:
Is the code below correct? I may be wrong with how the pointers and arrays of records work.
How to debug this? If I build it and it runs then I'm kind of sure it'll work, but in debugging my library I can only check if my init code does its job. (and for now, Firefox 3.6 doesn't seem to pick up my #mozilla.org/network/protocol;1?name=xxm contract)
The code I'm trying to port is here:
http://mxr.mozilla.org/mozilla-central/source/xpcom/components/Module.h
type
TConstructorProcPtr=function(aOuter:nsISupports;const aIID:TGUID;var aResult:pointer):nsresult;
TLoadFuncPrt=function:nsresult;
TUnloadFuncPrt=procedure;
TCIDEntry=record
cid:TGUID;
service:boolean;
getFactoryProc:pointer;//TGetFactoryProcPtr;
constructorProc:TConstructorProcPtr;
end;
TContractIDEntry=record
contractid:PChar;
cid:TGUID;//PGUID?
end;
TCategoryEntry=record
category,entry,value:PChar;
end;
TXPCOMModule=packed record
kVersion:integer;//=1;
mVersion:cardinal;//kModuleVersion
mCIDs:^TCIDEntry;//pointer to first in array, last should be nil
mContractIDs:^TContractIDEntry;//pointer to first in array, last should be nil
mCategoryEntries:^TCategoryEntry;//pointer to first in array, last should be nil
getFactoryProcPtr:pointer;//TGetFactoryProcPtr;
loadProc:TLoadFuncPrt;
unloadProd:TUnloadFuncPrt;
end;
You almost certainly need the cdecl calling convention on all your procedure- and function-pointer declarations:
TConstructorProcPtr = function(aOuter: nsISupports; const aIID: TGUID; var aResult: Pointer): nsresult; cdecl;
TLoadFuncPrt = function: nsresult; cdecl;
TUnloadFuncPrt = procedure; cdecl;
I assume you've declared nsISupports as a Delphi interface. Otherwise, you need to make sure the aOuter parameter above is a pointer as it is in the C++ code.
For TContractIDEntry, and all the other places where you use PChar, I advise you to use PAnsiChar instead. The size of Delphi's Char type changed a couple of years ago, but the C++ char is and always will be one byte, so use Delphi's one-byte character type explicitly. Also, your comment wondering whether to declare the cid field as a PGUID was correct; asterisk means pointer.
TContractIDEntry = record
contractid: PAnsiChar;
cid: PGUID;
end;
The kVersion field should not be a member of the record you declare. In C++, it's a static member, which means it occupies no space in the structure itself; it's shared by all instances of that type. It's equivalent to a class field in a Delphi class, but I don't think records offer that feature. Make it a unit-level variable instead of a field.

Elegant way for handling this string issue. (Unicode-PAnsiString issue)

Consider the following scenario:
type
PStructureForSomeCDLL = ^TStructureForSomeCDLL;
TStructureForSomeCDLL = record
pName: PAnsiChar;
end
function FillStructureForDLL: PStructureForSomeDLL;
begin
New(Result);
// Result.pName := PAnsiChar(SomeObject.SomeString); // Old D7 code working all right
Result.pName := Utf8ToAnsi(UTF8Encode(SomeObject.SomeString)); // New problematic unicode version
end;
...code to pass FillStructureForDLL to DLL...
The problem in unicode version is that the string conversion involved now returns a new string on stack and that's reclaimed at the end of the FillStructureForDLL call, leaving the DLL with corrupted data. In old D7 code, there were no intermediate conversion funcs and thus no problem.
My current solution is a converter function like below, which is IMO too much of an hack. Is there a more elegant way of achieving the same result?
var gKeepStrings: array of AnsiString;
{ Convert the given Unicode value S to ANSI and increase the ref. count
of it so that returned pointer stays valid }
function ConvertToPAnsiChar(const S: string): PAnsiChar;
var temp: AnsiString;
begin
SetLength(gKeepStrings, Length(gKeepStrings) + 1);
temp := Utf8ToAnsi(UTF8Encode(S));
gKeepStrings[High(gKeepStrings)] := temp; // keeps the resulting pointer valid
// by incresing the ref. count of temp.
Result := PAnsiChar(temp);
end;
One way might be to tackle the problem before it becomes a problem, by which I mean adapt the class of SomeObject to maintain an ANSI Encoded version of SomeString (ANSISomeString?) for you alongside the original SomeString, keeping the two in step in a "setter" for the SomeString property (using the same UTF8 > ANSI conversion you are already doing).
In non-Unicode versions of the compiler make ANSISomeString be simply a "copy" of SomeString string, which will of course not be a copy, merely an additional ref count on SomeString. In the Unicode version it references a separate ANSI encoding with the same "lifetime" as the original SomeString.
procedure TSomeObjectClass.SetSomeString(const aValue: String);
begin
fSomeString := aValue;
{$ifdef UNICODE}
fANSISomeString := Utf8ToAnsi(UTF8Encode(aValue));
{$else}
fANSISomeString := fSomeString;
{$endif}
end;
In your FillStructure... function, simply change your code to refer to the ANSISomeString property - this then is entirely independent of whether compiling for Unicode or not.
function FillStructureForDLL: PStructureForSomeDLL;
begin
New(Result);
result.pName := PANSIChar(SomeObject.ANSISomeString);
end;
There are at least three ways to do this.
You could change SomeObject's class
definition to use an AnsiString
instead of a string.
You could
use a conversion system to hold
references, like in your example.
You could initialize result.pname
with GetMem and copy the result of the
conversion to result.pname^ with
Move. Just remember to FreeMem it
when you're done.
Unfortunately, none of them is a perfect solution. So take a look at the options and decide which one works best for you.
Hopefully you already have code in your application to properly dispose off of all the dynamically allocated records that you New() in FillStructureForDLL(). I consider this code highly dubious, but let's assume this is reduced code to demonstrate the problem only. Anyway, the DLL you pass the record instance to does not care how big the chunk of memory is, it will only get a pointer to it anyway. So you are free to increase the size of the record to make place for the Pascal string that is now a temporary instance on the stack in the Unicode version:
type
PStructureForSomeCDLL = ^TStructureForSomeCDLL;
TStructureForSomeCDLL = record
pName: PAnsiChar;
// ... other parts of the record
pNameBuffer: string;
end;
And the function:
function FillStructureForDLL: PStructureForSomeDLL;
begin
New(Result);
// there may be a bug here, can't test on the Mac... idea should be clear
Result.pNameBuffer := Utf8ToAnsi(UTF8Encode(SomeObject.SomeString));
Result.pName := Result.pNameBuffer;
end;
BTW: You wouldn't even have that problem if the record passed to the DLL was a stack variable in the procedure or function that calls the DLL function. In that case the temporary string buffers will only be necessary in the Unicode version if more than one PAnsiChar has to be passed (the conversion calls would otherwise reuse the temporary string). Consider changing the code accordingly.
Edit:
You write in a comment:
This would be best solution if modifying the DLL structures were an option.
Are you sure you can't use this solution? The point is that from the POV of the DLL the structure isn't modified at all. Maybe I didn't make myself clear, but the DLL will not care whether a structure passed to it is exactly what it is declared to be. It will be passed a pointer to the structure, and this pointer needs to point to a block of memory that is at least as large as the structure, and needs to have the same memory layout. However, it can be a block of memory that is larger than the original structure, and contain additional data.
This is actually used in quite a lot of places in the Windows API. Did you ever wonder why there are structures in the Windows API that contain as the first thing an ordinal value giving the size of the structure? It's the key to API evolution while preserving backwards compatibility. Whenever new information is needed for the API function to work it is simply appended to the existing structure, and a new version of the structure is declared. Note that the memory layout of older versions of the structure is preserved. Old clients of the DLL can still call the new function, which will use the size member of the structure to determine which API version is called.
In your case no different versions of the structure exist as far as the DLL is concerned. However, you are free to declare it larger for your application than it really is, provided the memory layout of the real structure is preserved, and additional data is only appended. The only case where this wouldn't work is when the last part of the structure were a record with varying size, kind of like the Windows BITMAP structure - a fixed header and dynamic data. However, your record looks like it has a fixed length.
Wouldn't PChar(AnsiString(SomeObject.SomeString)) work?

Why is Self assignable in Delphi?

This code in a GUI application compiles and runs:
procedure TForm1.Button1Click(Sender: TObject);
begin
Self := TForm1.Create(Owner);
end;
(tested with Delphi 6 and 2009)
why is Self writable and not read-only?
in which situations could this be useful?
Edit:
is this also possible in Delphi Prism? (I think yes it is, see here)
Update:
Delphi applications/libraries which make use of Self assignment:
python4delphi
That's not as bad as it could be. I just tested it in Delphi 2009, and it would seem that, while the Self parameter doesn't use const semantics, which you seem to be implying it should, it also doesn't use var semantics, so you can change it all you want within your method without actually losing the reference the caller holds to your object. That would be a very bad thing.
As for the reason why, one of two answers. Either a simple oversight, or what Marco suggested: to allow you to pass Self to a var parameter.
Maybe to allow passing to const or var parameters?
It could be an artefact, since system doesn't have self anywhere on the left of := sign.
Assigning to Self is so illogical and useless that this 'feature' is probably an oversight. And as with assignable constants, it's not always easy to correct such problems.
The simple advice here is: don't do it.
In reality, "Self" is just a name reference to a place on the stack that store address pointing to object in the heap. Forcing read-only on this variable is possible, apparently the designer decided not to. I believe the decision is arbitrary.
Can't see any case where this is useful, that'd merely change a value in stack. Also, changing this value can be dangerous as there is no guarantee that the behavior of the code that reference instance's member will be consistence across compiler versions.
Updated: In response to PatrickvL comment
The 'variable' "Self" is not on the
stack (to my knowledge, it never is);
Instead it's value is put in a
register (EAX to be exact) just before
a call to any object method is made. –
Nope, Self has actual address on the memory. Try this code to see for yourself.
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(IntToStr(Integer(#Self)));
end;
procedure TForm1.Button2Click(Sender: TObject);
var
newform: TForm;
p: ^Integer;
begin
Self.Caption := 'TheOriginal';
newform := TForm.Create(nil);
try
newform.Caption := 'TheNewOne';
// The following two lines is, technically, the same as
// Self := newform;
p := Pointer(#Self);
p^ := Integer(newform);
ShowMessage(Self.Caption); // This will show 'TheNewOne' instead of 'TheOriginal'
finally
Self.Free; // Relax, this will free TheNewOne rather than TheOriginal
end;
end;
Sometimes, when you want to optimize a method for as far as you can take it (without resorting to assembly), 'Self' can be (ab)used as a 'free' variable - it could just mean the difference between using stack and using registers.
Sure, the contents of the stack are most probably already present in the CPU cache, so it should be fast to access, but registers are even faster still.
As a sidenote : I'm still missing the days when I was programming on the Amiga's Motorola 68000 and had the luxury of 16 data and 16 address registers.... I can't believe the world chose to go with the limited 4 registers of the 80x86 line of processors!
And as a final note, I choose to use Self sometimes, as the Delphi's optimizer is, well, not optimizing that well, actually. (At least, it pales compared to what trickery one can find in the various LLVM optimizers for example.) IMHO, and YMMV of course.

Resources