In Delphi 7, int64s are signed, if I try to declare a hex constant larger than $8000000000000000 (eg, what is really an uint64) I get an error. Can you advise some workarounds, please?
You can make a variant record like so
type muint64 = record
case boolean of
true: (i64 : int64);
false:(lo32, hi32: cardinal);
end;
Now you can just use the cardinals to fill your uint64 with unsigned data.
The other option would be to use code like this:
const almostmaxint64 = $800000045000000;
var muint64: int64;
begin
muint64:= almostmaxint64;
muint64:= muint64 shl 1;
end
Without support from the compiler you don't have many options.
I'm presuming that you wish to pass a value to a function in some external DLL. You'll have to declare the parameter as a signed 64 bit integer, Int64. Then all you can do is pass in the signed value that has the same bit pattern as the desired unsigned value. Build yourself a little converter tool with a compiler that has support for unsigned 64 bit integers.
Traditionally, Broland implementations suffered interoperability issues because lack of largest unsigned supported by target platform. I remember using LongInt values instead of DWORD and waiting for troubles since very early days of Turbo Pascal for Windows. Then was Cardinal happiness, but no, D4 introduced largest integer Int64 in its signed form only. Again.
So your only option is to rely on signed fundamental type Int64 and pray... wait, no, just use Int64Rec typecast to perform arithmetics on least and most significant part separately.
Back to constant declaration:
const
foo = $8000004200000001; // this will work because hexadecimal notation is unsigned by its nature
// however, declared symbol foo becomes signed Int64 value
// attempting to use decimal numeral will result in "Integer constant too large" error
// see "True constants" topic in D7 Help for more details
procedure TForm1.FormCreate(Sender: TObject);
begin
// just to verify
Caption := IntToHex(foo, SizeOf(Int64) * 2);
end;
Unfortunately, the other workaround is to change your compiler. Free Pascal always keeps signed and unsigned types in sync.
This snippet compiles and yields correct result in Borland Delphi Version 15.0 (a.k.a Delphi 7).
Related
I'm comparing a SmallInt variable with the result of the Ord function.
Example:
var
MySmallInt : SmallInt;
begin
MySmallInt := 5;
if(MySmallInt > Ord('C'))
then ShowMessage('True')
else ShowMessage('False');
end
After doing this, the following warning message is shown (W1023):
W1023 Comparing signed and unsigned types - widened both operands
Delphi's hint on the Ord function says that it should return a SmallInt and that's why I can't understand what causes the warning message. (I've looked for Ord function in the System unit but I didn't find it).
Further Informations:
I'm testing under Delphi XE7.
Under Delphi 2007, the same code doesn't give me any warning.
As David said, Ord() is a so called "compiler magic" (or, as they call it now, "intrinsic" or "pseudo-") function, i.e. not a real function that is called, but just something that uses a function syntax, but is recognized by the compiler as a special construct and turned into code directly. The same is true for e.g. Chr(), Writeln(), etc. They can usually have different and/or multiple types of parameters or return values and sometimes even have additional syntax elements.
The documentation says, about Ord(X):
The result is the ordinal position of X; its type is the smallest standard integer type that can hold all values of X's type.
In Delphi XE7, 'C' is a WideChar, and the return value of Ord('C') will be a 16 bit unsigned type (Word). Smallint is signed type. That is why you get the warning, because you are comparing a signed and an unsigned type of the same size, so the values must be widened to the next larger type (Integer).
In Delphi 2007, 'C' is not a WideChar, it is an AnsiChar, so the result of Ord('C') is a Byte. There is no need for widening to the next larger type, since Smallint can contain all values of Byte, so both can be promoted to Smallint.
I agree that the info hint in the editor is deceptive. Ord() does not always return a Smallint, it returns the minimum type that is needed to hold all values of the argument.
Ord() is an intrinsic function that yields an unsigned type. Hence the warning. In your case, you are passing it a WideChar, and so the matching integral type is Word.
I am new in Delphi and I need in my project add some constant to TFileTime which is record of lower and upper part of 64bit value. How to do this in Delphi? I have found only code in C++, but i dont know how make in Delphi unsigned int64 (ULONGLONG) and also I dont know how to cast this to longword (DWORD):
ULONGLONG qwResult;
// Copy the time into a quadword.
qwResult = (((ULONGLONG) ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
// Add constant
qwResult += constant;
// Copy the result back into the FILETIME structure.
ft.dwLowDateTime = (DWORD) (qwResult & 0xFFFFFFFF );
ft.dwHighDateTime = (DWORD) (qwResult >> 32 );
Thanks
The FILETIME struct is defined as:
typedef struct _FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME, *PFILETIME;
So, because Windows runs on little Endian, the layout of this struct is compatible with a 64 bit integer value.
So, you can cast TFileTime to UInt64, do the arithmetic, and cast back. Like this:
function IncrementedFileTime(const Value: TFileTime; const Incr: UInt64): TFileTime;
begin
Result := TFileTime(UInt64(Value) + Incr);
end;
Now, the documentation for the FILETIME record says:
It is not recommended that you add and subtract values from the
FILETIME structure to obtain relative times. Instead, you should copy
the low- and high-order parts of the file time to a ULARGE_INTEGER
structure, perform 64-bit arithmetic on the QuadPart member, and copy
the LowPart and HighPart members into the FILETIME structure.
Do not cast a pointer to a FILETIME structure to either a
ULARGE_INTEGER* or __int64* value because it can cause alignment
faults on 64-bit Windows.
This is an issue on targets where alignment errors result in hard faults. For instance Itanium. However, on x86 and x64 the code in my answer is fine because those architectures do not issue hard faults for alignment errors. Which is just as well because the Delphi compiler isn't very good at alignment.
I'm trying to handle the WM_XBUTTONUP message which is from the extra mouse buttons on some mice. The SDK documentation states that the low word of wParam holds the virtual key information and that the high word holds which button was pressed. I understand how this works in 32bit code, however in 64bit code the wParam is a 64bit unsigned integer. I've seen code that uses Lo(msg.wparam) and Hi(msg.wparam). Does this code still work in 64bits or does something have to change? In other words, does the definition of "high word" change from 32bit to 64bit?
You should have shown the code. Lo and Hi return the low byte and the high byte of a 16-bit value, respectively, so they wouldn't work with 32-bit code, either. Perhaps you meant LoWord and HiWord.
In 64-bit code, you can typecast a 64-bit integer value to Int64Rec:
case Int64Rec(Msg.WParam).Lo of ...
Any code that uses Lo() and Hi() is wrong because those functions return the low and high order bytes of a Word.
The MSDN documentation says the following:
Use the following code to get the information in the wParam parameter:
fwKeys = GET_KEYSTATE_WPARAM (wParam);
fwButton = GET_XBUTTON_WPARAM (wParam);
These macros are defined in the header files as:
#define GET_KEYSTATE_WPARAM(wParam) (LOWORD(wParam))
#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam))
In turn, LOWORD and HIWORD are defined as follows:
#define LOWORD(_dw) ((WORD)(((DWORD_PTR)(_dw)) & 0xffff))
#define HIWORD(_dw) ((WORD)((((DWORD_PTR)(_dw)) >> 16) & 0xffff))
These macros are designed to perform the correct task when compiled into both 32 bit and 64 bit code.
In Delphi, the Windows unit contains translations of LoWord and HiWord that perform the same tasks, albeit implemented in a somewhat different manner. So I would implement the following functions:
function GET_KEYSTATE_WPARAM(wParam: WPARAM): Word; inline;
function GET_XBUTTON_WPARAM(wParam: WPARAM): Word; inline;
....
function GET_KEYSTATE_WPARAM(wParam: WPARAM): Word;
begin
Result := LoWord(wParam);
end;
function GET_XBUTTON_WPARAM(wParam: WPARAM): Word;
begin
Result := HiWord(wParam);
end;
I had problems with the following code:
var
FileSize : Int64;
...
FileSize := Info.nFileSizeLow or (Info.nFileSizeHigh shl 32);
I expected it to work because of the Int64 type of the left side of the assignment. But it does not. The partial calculation containing the shl seems to produce an overflow.
So I changed it to:
FileSize := Info.nFileSizeLow or (Int64 (Info.nFileSizeHigh) shl 32);
which works on my 32 bit operating system, but does not work on Vista 64 bit!
Finally,
FileSize := Info.nFileSizeHigh;
FileSize := FileSize shl 32;
FileSize := Info.nFileSizeLow or FileSize;
works on both systems.
Can someone explain the differences in these three versions?
Generally speaking, the type of the expression a * b, where a and b are of type Integer and * is an operator that applies to Integer, is an integer type with the same range as Integer. (I say generally, as an exception is /.) In order for an operator to use 64-bit operations, one or more of the operands must have a range that is only expressible with a 64-bit type. That should cause all the operands to be promoted to 64-bit, and a 64-bit operation performed.
The fact that the left hand side of an assignment is a 64-bit location generally has no effect on the interpretation and typing of the expression on the right hand side of the assignment operator. This is the way it is in almost all languages that I'm aware of that have statically dispatched 32-bit and 64-bit operator overloads (as opposed to polymorphically dispatched operators on arbitrary precision integers or numeric towers etc.); making things behave otherwise would be very surprising behaviour.
For example, arguments to procedure calls are effectively implicit assignments to the parameters. If the left hand side of an assignment could change the interpretation of the expression on the right, we would not know how to interpret the argument to a procedure call without already knowing the definition:
var a, b: Integer;
// ...
P((a shl 16) or b); // 32-bit operation or 64-bit operation?
I do not know why you are seeing different behaviour with your second and third versions of the code. As far as I can see, they should be interpreted the same, and in my tests, they are interpreted the same. If you could provide sample code that works on 32-bit Windows but fails on 64-bit Windows, I could investigate further.
Actually, this is pretty well documented in Delphi 7's help file, under "Integer types":
In general, arithmetic operations on integers return a value of type Integer--which, in its current implementation, is equivalent to the 32-bit Longint. Operations return a value of type Int64 only when performed on one or more Int64 operand. Hence the following code produces incorrect results.
The code example provided:
var
I: Integer;
J: Int64;
...
I := High(Integer);
J := I + 1;
To get an Int64 return value in this situation, cast I as Int64:
...
J := Int64(I) + 1;
First of all FileSize must be defined as UInt64 and not Int64...
UInt64 (not available in early Delphi versions) is an unsigned 64 bit integer, aka a QWORD. This is the expected type for the FileSize (you won't expect a negative file size, won't you?).
IMHO you could have coded - using UInt64 because we don't want to have some values reported as negative:
FileSize := UInt64(Info.nFileSizeLow) or (UInt64(Info.nFileSizeHigh) shl 32));
But under Delphi 7 it produces the same exact code as yours.
FileSize := Info.nFileSizeLow or (Int64(Info.nFileSizeHigh) shl 32));
So there is perhaps some compiler regression. Could you take a look at the asm generated code (step debugger then Alt+F2), and see if there is a difference. But it's unlikely...
In all cases, here is a better (and faster) code:
with Int64Rec(FileSize) do
begin
Lo := Info.nFileSizeLow;
Hi := Info.nFileSizeHigh;
end;
The official MSDN documentation states about the WIN32_FIND_DATA Structure:
nFileSizeHigh: The high-order DWORD value of the file size, in bytes.
This value is zero unless the file size is greater than MAXDWORD.
The size of the file is equal to
(nFileSizeHigh * (MAXDWORD+1)) +
nFileSizeLow.
nFileSizeLow: The low-order DWORD value of the file size, in bytes.
Here is the resulting code:
FileSize := UInt64(Info.nFileSizeLow)+(UInt64(Info.nFileSizeHigh)*UInt64(1 shl 32));
Quite a funny definition, indeed...
This is not really an answer, but it's too long for a comment.
I noticed Delphi gets confused when the result of an expression is to be written into a 64 bit variable, but the operands are 32 bit. I ran into this bug when I was implementing a hash function returning an 64 bit number. Your third variant works because you're first assigning the 64 bit variable, helping Delphi figure out it really needs to do 64 bit arithmetic.
I'm tempted to say both variants (1) and (2) are actually failing because Delphi generates 32 bit arithmetic and then assignes the result to the 64 bit variable. I'm tempted to say the variant that works well on your 32 bit machine benefits from some sort of "unlucky non-failure" (ie: the code is bad, but none the less it produces good results for the given test). The trouble is, COMPILED code doesn't change when moved from a 32bit machine to a 64 bit machine. If the code is the same, the input is the same, you'd have to pin the error on the CPU, but you know you didn't find an bug in your CPU, so you have to fall back and re-think your tests, or pin it on the "unluck non-failure".
test on Delphi 7 and version 2 is OK. Must be bug of later version
I'm needing to call a Windows API function introduced in Vista from my Delphi app, but I don't have any Delphi headers which describe the function.
Related functions are already documented in the JEDI Windows API library, but not this function.
My C++ is almost non-existent, and I'm struggling to work out the Delphi definitions that correspond to the function and it's parameter as documented on MSDN.
From http://msdn.microsoft.com/en-us/library/aa814417.aspx
NETIOAPI_API GetIpInterfaceEntry(__inout PMIB_IPINTERFACE_ROW Row);
typedef struct _MIB_IPINTERFACE_ROW {
ADDRESS_FAMILY Family;
NET_LUID InterfaceLuid;
NET_IFINDEX InterfaceIndex;
ULONG MaxReassemblySize;
ULONG64 InterfaceIdentifier;
ULONG MinRouterAdvertisementInterval;
ULONG MaxRouterAdvertisementInterval;
BOOLEAN AdvertisingEnabled;
BOOLEAN ForwardingEnabled;
BOOLEAN WeakHostSend;
BOOLEAN WeakHostReceive;
BOOLEAN UseAutomaticMetric;
BOOLEAN UseNeighborUnreachabilityDetection;
BOOLEAN ManagedAddressConfigurationSupported;
BOOLEAN OtherStatefulConfigurationSupported;
BOOLEAN AdvertiseDefaultRoute;
NL_ROUTER_DISCOVERY_BEHAVIOR RouterDiscoveryBehavior;
ULONG DadTransmits;
ULONG BaseReachableTime;
ULONG RetransmitTime;
ULONG PathMtuDiscoveryTimeout;
NL_LINK_LOCAL_ADDRESS_BEHAVIOR LinkLocalAddressBehavior;
ULONG LinkLocalAddressTimeout;
ULONG ZoneIndices[ScopeLevelCount];
ULONG SitePrefixLength;
ULONG Metric;
ULONG NlMtu;
BOOLEAN Connected;
BOOLEAN SupportsWakeUpPatterns;
BOOLEAN SupportsNeighborDiscovery;
BOOLEAN SupportsRouterDiscovery;
ULONG ReachableTime;
NL_INTERFACE_OFFLOAD_ROD TransmitOffload;
NL_INTERFACE_OFFLOAD_ROD ReceiveOffload;
BOOLEAN DisableDefaultRoutes;
}MIB_IPINTERFACE_ROW, *PMIB_IPINTERFACE_ROW;
Among other bits, the bit I'm struggling with at the minute is the ZoneIndices[ScopeLevelCount] field; I can't work out what size the array is supposed to be.
This is what I've defined so far, although I haven't worked out the enums in the original C++ definition yet. I'll be explicitly loading the Windows DLL on Vista and getting the address of the new function to call.
type
PMIB_IPINTERFACE_ROW = ^MIB_IPINTERFACE_ROW;
{$EXTERNALSYM PMIB_IPINTERFACE_ROW}
_MIB_IPINTERFACE_ROW = record
Family: ADDRESS_FAMILY;
InterfaceLuid: NET_LUID;
InterfaceIndex: NET_IFINDEX;
MaxReassemblySize,
InterfaceIdentifier,
MinRouterAdvertisementInterval,
MaxRouterAdvertisementInterval: Cardinal;
AdvertisingEnabled,
ForwardingEnabled,
WeakHostSend,
WeakHostReceive,
UseAutomaticMetric,
UseNeighborUnreachabilityDetection,
ManagedAddressConfigurationSupported,
OtherStatefulConfigurationSupported,
AdvertiseDefaultRoute: LongBool;
RouterDiscoveryBehavior: NL_ROUTER_DISCOVERY_BEHAVIOR;
DadTransmits,
BaseReachableTime,
RetransmitTime,
PathMtuDiscoveryTimeout: Cardinal;
LinkLocalAddressBehavior: NL_LINK_LOCAL_ADDRESS_BEHAVIOR;
LinkLocalAddressTimeout,
ZoneIndices[ScopeLevelCount],
SitePrefixLength,
Metric,
NlMtu: Cardinal;
Connected,
SupportsWakeUpPatterns,
SupportsNeighborDiscovery,
SupportsRouterDiscovery: LongBool;
ReachableTime: Cardinal;
TransmitOffload: NL_INTERFACE_OFFLOAD_ROD;
ReceiveOffload: NL_INTERFACE_OFFLOAD_ROD;
DisableDefaultRoutes: LongBool;
end;
{$EXTERNALSYM _MIB_IPINTERFACE_ROW}
MIB_IPINTERFACE_ROW = _MIB_IPINTERFACE_ROW;
{$EXTERNALSYM MIB_IPINTERFACE_ROW}
TMibIpInterfaceRow = MIB_IPINTERFACE_ROW;
PMibIpInterfaceRow = PMIB_IPINTERFACE_ROW;
const
iphlpapilib = 'iphlpapi.dll';
var
HIpHlpApi: THandle = 0;
GetIpInterfaceEntry: function(const pArpEntry: MIB_IPINTERFACE_ROW): LongInt; stdcall;
{$EXTERNALSYM GetIpInterfaceEntry}
Does anybody out there have suggestions or tips/tricks for translating a function definition like this?
Many thanks,
Conor
The Win32 BOOLEAN type is one byte, but Delphi's LongBool type is four. Use Delphi's ByteBool instead.
Maybe you can try "C 2 pas"
http://cc.embarcadero.com/Item/26951
Also found these tools:
http://www.drbob42.com/delphi/headconv.htm
http://rvelthuis.de/programs/convertpack.html
http://rvelthuis.de/articles/articles-convert.html#cconvs
Hmm. A strange structore. But if you look into w2def.h, you can see that ScopeLevelCount=16. So your array should have 16 elements,
Make sure you use the packed command when defining your record because Delphi aligns complex data types on 2, 4 or 8 byte boundaries by default.
TExample = record
f1: Integer; // start at offset 0x00
f2: Char; // start at offset 0x04
f3: Integer; // start at offset 0x06 or 0x08 depending on alignment
end;
TExample = packed record // this is what c++ would do
f1: Integer; // start at offset 0x00
f2: Char; // start at offset 0x04
f3: Integer; // start at offset 0x05
end;
The ZoneIndices array should be defined like this:
ZoneIndices : array [0..ScopeLevelCount - 1] of Cardinal;
ScopeLevelCount is a constant that is 16
I often used Dr. Bob's Header Converter for this task, but mostly I took the long and tedious way of manually performing the conversion, because it helped me to understand the API better. (Because I was going to use it and I have to familiarize myself with it anyway)
Also see this article: http://www.delphi-jedi.org/api-howto.html
In general it's best not to put to much hopes on a header conversion tool, because C++ is a very powerful and complex language. Most conversion tools I tested only supported a subset of C++ and its preprocessor, thus making it necessary to manually make fixes to the generated source.
you can investigate some already translated APIs/structures that related to this subject and convert it yourself. for example this one
I don't see any field of type ULONG64 in the translation, but I do in the original.
Further, FPC also has an header converter which works fine for structs. Typically windows api structures are packed.
In doubt, use some free msvc product to write the sizeof(structure) and do the same under pascal. If that matches, and you still have doubts, calculate field offsets with a bit of pointer magic and compare them.