If you look at the name of addObject you could already see that you can pass an object for every string in the listbox. So every string can have a unique object associated with it. But the procedure only accepts an
TObject. An object is a pointer to a TForm, TButton or anything else that is a pointer to something (as long as it is an TObject descendant).
But you just want a simple Integer connected to the strings in the listbox. Because Integer and Pointer are basically the same idea (they are both just a number, only one points to a memory location and the other is just a number) we can "abuse" the pointer in listbox-items to hold a number. In that case you could have a Pointer with value 100. It won't point to a valid memory location but the pointer still has that value.
To fool the procedure to accept an Integer as a pointer we need to "cast" the integer to a pointer, which in turn we can pass as an TObject with another cast. You see that in the following line:
listbox1.items.addObject(info.Name, TObject(IntPtr(Cnt)));
We "convert/cast" Cnt to a Pointer with IntPtr. After that we do that again with TObject(pointer) and we can pass that to addObject. Casting is just a way to say to the compiler "Just assign the value of one item to the other discarding the fact that the are not the same type".
Now to use that TObject in the listbox again we need to do the reverse.
seek(goalsfile, PtrInt(ListBox1.Items.Objects[ListBox1.ItemIndex]));
So we take the Object connected to the string at ItemIndex (ListBox1.Items.Objects[ListBox1.ItemIndex]) and use PtrInt to cast that pointer back to an Integer. Basically the PtrInt does nothing. But because we cant do Integer = Pointer we need this cast to be able to assign the value of the pointer to the integer (Integer = PtrInt(pointer) ).
This is quite an extensive explanation. I could have just said the last line but I wanted you to have the background information on the addObject too. Hope it was clear enough. (I'm not officially a teacher

)