Delphi - Write string to Reg_Binary registry key - delphi

I need to convert a string to write it into a registry.reg_binary key.
I have the basic code for writing into the key as follows:
try
rootkey := HKEY_CURRENT_USER;
if OpenKey(Key, False) then
begin
reg.WriteBinaryData('SomeKey', SomeValue, Length(SomeVale));
CloseKey;
end;
finally
reg.Free;
end;
In the above, SomeValue needs to be the hex value of a TEdit text field;
My current tack is convert the TEdit.text using IntToHex on the Ord value of each character. This gives me a string that looks like what I want to write...
At this point I'm stumped...

If you want to write a string, then you should call WriteString.
reg.WriteString('SomeKey', SomeValue);
If you have an integer, then call WriteInteger.
IntValue := StrToInt(SomeValue);
reg.WriteInteger('SomeKey', IntValue);
If you have true binary data, then it shouldn't matter what it looks like — hexadecimal or whatever. Call WriteBinaryData and be done with it. The actual appearance of the data is immaterial because you don't have to read it in that format. You'll read it later with ReadBinaryData and it will fill your buffer with the bytes in whatever format they had when you wrote them.
IntValue := StrToInt(SomeValue);
reg.WriteBinaryValue('SomeKey', IntValue, SizeOf(IntValue));
That will write all four bytes of your integer into the registry as a binary value.
When the Windows Registry Editor displays the key's value to you, it will probably display each byte in hexadecimal, but that's just a display format. It doesn't mean you have to format your data like that before you add it to the registry.

Granted this assumes that your string only contains ansi data,
but if your trying to write a string to a registry value as a binary value then the following changes to your logic would work:
var
EdStr : AnsiString;
:
EdStr := AnsiString(Edit1.Text); // de-unicode
reg.WriteBinaryData('SomeKey', EdStr[1], Length(EdStr));

Related

Constant single using the hex memory value in Delphi

How can I make a single constant based on a hex value where that hex value is an unsigned integer and the raw memory for the single. I would like to do something like this but it doesn't compile and this will try and cast the hex value to a single and then store the result of that cast instead of storing hex value itself:
LARGEST_SINGLE_LESS_THAN_ZERO = Single($80800000);
I get a "Invalid Typecast" error.
For example:
The single value for 1 is stored as $3F800000 in memory. I would like to be able to create a const that lets me set the value using $3F800000 instead of 1.
I have also tried other variations such as this without luck:
LARGEST_SINGLE_LESS_THAN_ZERO = PSingle(#$80800000)^;
Background
I have a method that I use to get the next smallest single when provided with a single value:
type
PInt32 = ^Int32;
function NextBefore(const aValue: Single): Single;
var
int32Value: Int32;
begin
// this function ignores special values nan/inf
int32Value := PInt32(#aValue)^;
if (UInt32(int32Value) = $80000000) or (int32Value = 0) then
begin
// special handling needed for -0 and 0. We need to go to the smallest
// negative number.
int32Value := $80800000;
end
else
begin
if int32Value >= 0 then
Dec(int32Value)
else
Inc(int32Value);
end;
Result := PSingle(#int32Value)^;
end;
This is really useful because we use vector operations that can only do a > or < so we use it to do the equivalent of a >= and a <=. We often check against 0. So where we need get all of the data >= 0 we do something like this:
MyVector.ThresholdGT(NextBefore(0));
It would be nicer to provide the other developers with a constant for these types of operations. Trying to use the PSingle format below won't work because the number is not a variable.
In order to declare a single constant with a hex value in such a way that it cannot be altered by code, it can be done in two steps:
const
iLARGEST_SINGLE_LESS_THAN_ZERO : Int32 = $80800000;
var
LARGEST_SINGLE_LESS_THAN_ZERO : Single absolute iLARGEST_SINGLE_LESS_THAN_ZERO;
Trying to change the value of LARGEST_SINGLE_LESS_THAN_ZERO will give a compiler error: Left side cannot be assigned to.
It's hard to do this cleanly with the constraints of the language. Perhaps the best that you can do is to make a variant record type that has both integer and single fields overlapped.
type
TSingleIntegerVariantRec = record
case Integer of
0: (I: Integer);
1: (S: Single);
end;
Once you have that type available you can declare typed constants using the integer field, but then read the single field.
const
LARGEST_SINGLE_LESS_THAN_ZERO: TSingleIntegerVariantRec = (I: $80800000);
....
MyVector.ThresholdGT(LARGEST_SINGLE_LESS_THAN_ZERO.S);
If you want to add an extra nuance you could implement an implicit cast operator to Single which would allow you to omit the .S. If you made that operator inline then I suspect the emitted code would be very efficient.
This does what you ask, but I wouldn't claim that it was very elegant. We're I you I would move the code to use the next value down into the library function so that you can pass 0 and shield the consumer of the library from these implementation details.
In other words you would add a ThresholdGTequal method that was implemented like this:
procedure TMyVector.ThresholdGTequal(const Value: Single);
begin
ThresholdGT(NextBefore(Value));
end;
Then the consumers of this code simply write:
MyVector.ThresholdGTequal(0);
and remain oblivious to all of the gnarly implementation details.

Delphi Lockbox Hashing

I need to hash a string, preferably as SHA512, although it could be SHA256, SHA1, MD5 or CRC32.
I have downloaded Lockbox 3, put a TCryptographicLibrary and a THash component on a form, set the Hash property to SHA-512 and used the following code to produce a test result:
procedure TForm1.Button1Click(Sender: TObject);
begin
Hash1.HashString('myhashtest');
Edit1.Text := Stream_To_AnsiString(Hash1.HashOutputValue);
end;
To best illustrate the problem, I have gone on to an online hash calculator and the MD5 hash of 'myhashtest' is ff91e22313f0a41b46719e7ee6f99451 but setting the hash property in my test program to MD5 results in ÿ‘â#ð¤Fqž~æù”Q which is clearly wrong. I have tried the same test using other Hash properties, including the SHA512 which i want, and they all return rubbish.
Where am I going wrong?
THash.HashOutputValue is a stream of the raw hashed bytes. It appears that Stream_To_AnsiString() merely copies those raw bytes as-is into an AnsiString, it does not encode the bytes in any way. What you are looking for is the hex encoded version of the raw bytes instead. I do know that LockBox has a Stream_To_Base64() function (as shown in this example), but I do not know if it has a Stream_To_Hex() type of function. If it does not, you can easily create your own, eg:
function Stream_To_Hex(Stream: TStream): AnsiString;
var
NumBytes, I: Integer;
B: Byte;
begin
NumBytes := Stream.Size - Stream.Position;
SetLength(Result, NumBytes * 2);
for I := 0 to NumBytes-1 do
begin
Stream.ReadBuffer(B, 1);
BinToHex(#B, #Result[(I*2)+1], 1);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Hash1.HashString('myhashtest');
Edit1.Text := Stream_To_Hex(Hash1.HashOutputValue);
end;
Many cryptographic functions 'silently' (i.e. without stating so in the docs) output and require Base64- or hex-encoded strings (and also often AnsiStrings). This is because encrypted text can contain any data, and as soon as you start treating that as 'strings', string handling functions can easily choke on that (e.g. null-terminated strings containing a null). By Base-64/hex encoding the cryptotext you make sure it will be plain old ASCII characters that evene old code can read/write.
If you dig around a little in the cryptocode or its method parameters you usually can determine that, and convert your strings accordingly.
I figured out where stream_to_hex, it is inside uTPLB_StreamUtils (pas or hpp) depending if you are using c builder or delphi.

Convert hex str to decimal value in delphi

I've got a problem to convert a string representation of an hex value in integer value with Delphi.
for example:
$FC75B6A9D025CB16 give me 802829546 when i use the function:
Abs(StrToInt64('$FC75B6A9D025CB16'))
but if i use the calc program from Windows, the result is: 18191647110290852630
So my question is: who's right? me, or the calc?
Does anybody already have this kind of problem?
In fact 802829546 is clearly wrong here.
Calc returns a 64bit unsigned value (18191647110290852630d).
Delphi Int64 type uses highest bit as sign:
Int := StrToInt64('$FC75B6A9D025CB16');
Showmessage(IntToStr(Int));
returns value -255096963418698986 which is correct
If you need to work with values larger than 64bit signed, then check out Arnaud's answer here.
The number is too big to be represented as a signed 64-bit number.
FC75B6A9D025CB16h = 18191647110290852630d
The largest possible signed 64-bit value is
2^63 - 1 = 9223372036854775807
to work with big numbers you need external library for delphi
Large numbers in Pascal (Delphi)
I had to use a Delphi library named "DFF Library" because I work on Delphi6 and the type Uint64 does not exist in this version.
Main page
Here's my code to transform a string of hexadecimal value to a string of decimal value:
You need to add UBigIntsV3 to your uses in your unit.
function StrHexaToUInt64Str(const stringHexadecimal: String): string;
var
unBigInteger:TInteger;
begin
unBigInteger:=TInteger.Create;
try
// stringHexadecimal parameter is passed without the '$' symbol
// ex: stringHexadecimal:='FFAA0256' and not '$FFAA0256'
unBigInteger.AssignHex(stringHexadecimal);
//the boolean value determine if we want to add the thousand separator or not.
Result:=unBigInteger.converttoDecimalString(false);
finally
unBigInteger.free;
end;
end;

Crash in Delphi function - StrToDateTime

Who can to advice in my problem.
I set date format as 'JUL/12 - 12 15:35', but when using StrToDateTime then give EConvertError.
What can I do with this format which contains 2 - date separator ?
Use next code
function LocaleFormatStrToDateTime(const S: string): TDateTime;
var
LFormatSettings: TFormatSettings;
begin
LFormatSettings := GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT);
LFormatSettings.ShortTimeFormat := FormatSettings.ShortTimeFormat;
LFormatSettings.TimeSeparator := FormatSettings.TimeSeparator;
Result := StrToDateTime(S, LFormatSettings);
end;
----------
**
the best solution is use jvDateUtil.StrToDate*
**
Your format is completely non-standard (and almost incomprehensible), so can't be handled by the built-in Date/Time formatters.
You've designed your own format, so you need to write your own code to convert to and from it.
This is nature's way of telling you not to use wacky date and time formats!
Probably the string you're trying to convert is not compatible with the default system format. Taking a look at the method signature and description reveals that you can override it to suit your needs, see an example here.
It would be helpful if you posted a piece of the code you have so far, maybe you overlooked something.
EDIT
I've missed the fact that your're using a complex format, including multiple separators for the date, which I'm not sure that are supported in delphi.
I guess that in this case you could split your string into pieces and then encode them into a TDateTime. To convert your month name to a month number you can iterate through the LFormatSettings.ShortMonthNames array, something like:
String longMonth:= copy(S, 0, 3);
for i := Low(LFormatSettings.ShortMonthNames) to High(LFormatSettings.ShortMonthNames) do
if SameText(longMonth, LFormatSettings.ShortMonthNames[i]) then begin
shortMonth:=FormatFloat('00', i);
Break;
end;

Avoiding Locale Conflicts when storing TDateTime's in Floats?

I got the TDateTime thing fixed by using Floating vars to store them in a file. However, now I face a new problem: Invalid Floating Point - Most likely because of the Comma Separator.
How can I set the default separator in my program? Or is there any other way around?
You can use a TFormatSettings record to specify the decimal separator when you call StrToFloat and FloatToStr. You have to decide what to use and stick to that. Here is sample code with a .
var
d: TDateTime;
s: string;
fs: TFormatSettings;
begin
d := Now();
fs.DecimalSeparator := '.';
s := FloatToStr(d, fs);
end;
Another option would be to use the XML standard date time format. Delphi has some functions in XSBuiltIns to do the conversion from TDateTime to string and back. You will have a time zone offset in the value so if you move your persisted TDateTime from one time zone to another you may have some unwanted behavior. It depends on the usage of the value.
var
d: TDateTime;
s: string;
begin
d := Now();
s := DateTimeToXMLTime(d);
d := XMLTimeToDateTime(s);
end;
As Mikael suggested, there are a many ways to do this. To re-cap you wish to store a TDateTime to a file in textual format and be able to restore this value successfully irrespective of the locale on which the restoration happens.
Option 1
When storing, call FloatToStr, say, but force a '.' for the decimal separator through the TFormatSettings parameter. On restore, use StrToFloat with the same TFormatSettings.
Option 2
Encode the 8 byte TDateTime value using base 64. This has the downside that it renders the value unreadable.
Option 3
Similar to option 1, but encode the TDateTime by calling DateTimeToStr and explicitly passing a TFormatSettings that does not rely on anything in the locale – so do not rely on the locale's date or time separators, instead force your own. To reverse call StrToDateTime with an identical TFormatSettings record.

Resources