Question: how to type-cast a general pointer to a PtrUInt variable ? lazarus / 34-Windows ---------------------------------------------------------------------- KlausGunther · 2012-12-29 19:54 I'm replacing all my integer variables holding 32 bit pointers to PtrUInt data type. But the compiler warnes me at each and every occurence. What would be the correct type-casting ? I found a working trick for PString types (adresses of strings). I do the following: Code: [Select]var a64: PtrUint; s: string; begin s := 'this is my text'; a64 := WParam(s); end No compiler warnings, and works fine in 32 bit environment. 64 bit environment will soon be checked out. But it seems a bit arkward, isn't it ? Is there a more straight-forward method, working with all types of pointers ? ---------------------------------------------------------------------- marcov · 2012-12-29 23:52 This code is probably horribly wrong.  "s" is a managed type whose contents will be killed after the "end" and then a64 will point into nowhere. ---------------------------------------------------------------------- KlausGunther · 2012-12-30 00:07 Oh yes, shure ! I just tried to produce a complete code. The important thing is just: Code: [Select]a64 := WParam(s);making shure that a64 receives a valid PtrUInt value without compiler hints or warnings about non-portable conversions. The value seems correct, and the compiler doesn't say anything. This line would be used throughout the whole package, if there isn't a more elegant way to cast a string pointer to a PtrUInt. And what about general pointer types ? How to cast them to PtrUInt correctly ? ---------------------------------------------------------------------- User137 · 2012-12-30 08:46 Commonly string with pointers is referred to as PChar. When you assign string to PChar, it copies the memory, if i recall. ---------------------------------------------------------------------- KlausGunther · 2012-12-30 09:58 So, do you think that Code: [Select]a64 := WParam(s);creates a copy of the string s and places the address of that copy into a64 ? What would be the correct way to implement the Lazarus version of the Delphi code Code: [Select]a64 := @s;in Lazarus/FPC without having the compiler mock me ? EDIT And similar problem: I have to cast a procedure address as LongInt, as in Delphi code Code: [Select]  Result := CallWindowProc(Pointer(HotKey_oldmsgproc), wnd, Msg, wParam, lParam); or in Delphi code Code: [Select]  SetWindowLong(wnd, GWL_WNDPROC, Integer(@HotKey_MsgProc));I just can't find a way to avoid the hint: Conversion between ordinals and pointers is not portable. How can I cast those adresses to a PtrUInt ? ---------------------------------------------------------------------- marcov · 2012-12-30 16:12 There is no correct and 100% safe way to do that, since at any point the compiler might change the location of the string's allocation. That's why they are called dynamic. If you need to store character data for a long time in a pointer, allocate memory to a pchar and use that. ---------------------------------------------------------------------- KlausGunther · 2012-12-30 16:18 Yes, I know that. It's not for a long storage, but just for building the right parameter type for a function call. So I need to cast adresses to PtrUInt. Be it adresses of variables, string, procedures - it's all for the same usage. ---------------------------------------------------------------------- KlausGunther · 2012-12-30 17:33 I found a trick to cast pointers to a PtrUInt: Code: [Select] var   p: pointer;   adr: PtrUInt; begin       adr := 0;                                    // initialize variable to avoid compiler hint       p := @HotKey_MsgProc;            // get a procedure pointer (or any other pointer or address)       move(p,adr,sizeof(adr));            // cast to PtrUint by brutal copy    // and now, use the pointer value where a LongInt is expected       SetWindowLong(wnd, GWL_WNDPROC, adr);  Again, it's not a complete program, just a sample code with the variable declarations. It's working. But I find it really nasty. Isn't there a type-cast to load a pointer into a PtrUInt ? The latter isn't it designed for holding pointers ? But how do I get them into it ? EDIT I found the symetric method to cast an integer variable holding a pointer to a pointer variable: Code: [Select]        var           p: pointer         begin           p := nil;           move(HotKey_oldmsgproc,p,sizeof(p));           Result := CallWindowProc(p, wnd, Msg, wParam, lParam);  All this avoids compiler hints ans warning, and it's working. But ugly. There should be an in-built way to accomplish these casts ! ---------------------------------------------------------------------- Laksen · 2012-12-30 17:39 Code: [Select]var p: pointer;     pt: PtrUInt; begin    p := @something;    pt := PtrUInt(p); end; This will always work ---------------------------------------------------------------------- KlausGunther · 2012-12-30 18:05 It works, certainly. But the compiler doesn't like it: it warns about non-portable conversion between ordinals and pointers, at the line Code: [Select]   pt := PtrUInt(p);That's exactly what I want to avoide. Otherwise, I'll have hundreds of hints or warnings, and il will be really hard to find those which are really important. Because during conversion, this hint is usefull to show the points which need special attention. So, I don't want to block these hints. I just want to find a regular solution fully accepted by the compiler. ---------------------------------------------------------------------- KlausGunther · 2013-01-07 10:11 Isn't there really no "regular" way to cast a pointer or an address to a PtrUInt variable ? I'm using MOVE and it's working, but I don't feel happy with this work-arround. I have to do: Code: [Select]var adr1,adr2: PtrUInt; p: pointer; s: string; ... adr 1:= p; adr2 := @s; There are compiler warnings (conversion is not portable). Actually, I'm doing this: Code: [Select]move(p,adr1,sizeof(adr1)); p := @s; move(p,adr2,sizeof(adr2)); No more warnings, but no more control, too. There is certainly a way to do such casts without the compiler mocking about that. ---------------------------------------------------------------------- Martin_fr · 2013-01-07 11:17 In the Lazarus IDE you can write {%H-}   i:={%H-}PtrUInt(p); The IDE will filter the message (if it is a hint). As for your question. Yes PtrUInt has exactly the purpose of holding a pointer. But look up its declaration. It is simply a DWord or QWord or similar. There is an IFDEF and it is aliased to the correct size type. So for the compiler it is still casting a pointer (of which the compiler knows, that it has different sizes on different platforms) to an integer type (that the compiler believes to be of the same size always (might be ($mode) dependent)). There is no entirely "magic" integer type, for which the compiler knows it is save for pointers. You can write the typecast as an inline function. Then it is in a single place only. ---------------------------------------------------------------------- KlausGunther · 2013-01-07 16:32 YES ! That's it ! I dit this: Code: [Select]function PtrToI64(p:pointer):PtrUInt; inline; begin   result := {%H-}PtrUInt(p); end; and I call it like this: Code: [Select] var   p: pointer;   adr: PtrUInt; ... p := @MyString; adr := PtrToI64(p); Works fine and no more warnigs. Exactely what I wanted. Thank you very much !