How to change THash.Hash at runtime - delphi

How can I change the default THash.Hash algorythm from trhe default SHA-1 to MD5?
The following does not works:
var
StringHash: THash;
begin
StringHash.Create(nil);
StringHash.Hash := 'MD5';
end;
Edit:
Yes you are all right: I apologize for not having mentioned the fact that THash is a class of the new TurboPower LockBox 3.
My apologies again for this omission!
Anyway Sean has already given the answer I was looking for.
Thank you all

Assuming that you are referring to the THash component of TurboPower Lockbox, you can select the hashing algorithm at run-time like so:
function FindHashOfBananaBananaBanana: TBytes;
var
StringHash: THash;
Lib: TCrypographicLibrary;
begin
StringHash := THash.Create( nil);
Lib := TCrypographicLibrary( nil);
try
StringHash.CryptoLibrary := Lib;
StringHash.HashId := SHA512_ProgId; // Find constants for other algorithms
// in unit uTPLb_Constants.
StringHash.HashAnsiString('Banana banana banana');
SetLength( result, StringHash.HashOutputValue.Size);
StringHash.HashOutputValue.Read( result[0], StringHash.HashOutputValue.Size);
StringHash.Burn
finally
StringHash.Free;
Lib.Free
end
end;

Your example code is invalid. The variable type is THASH, the variable name is STRINGHASH. When you construct an instance of a class the format is typically:
var
StringHash:THash;
begin
StringHash := THash.Create();
try
DoSomethingWithStringHash;
finally
StringHash.Free()
end
end;
Fix your example and come back with more details.

Related

How to get unit path in runtime with Delphi?

I assume that it is possible to get the complete path of the unit (not just the name) at runtime, since when I generate an error, Delphi already has this stored information:
try
Assert (False, '#');
except
on E: EAssertionFailed from
begin
   ShowMessage (E.Message); // this show me the path
end;
end;
Would anyone know if there is any function that returns me the path of a specific unit, or something similar?
The complete path of the unit as it was on the machine that compiled the project is only possible using Assert. However personally I don't find that information incredibly useful unless you have many units with the same name in different folders or lost control over your source repository and and library paths in effect when compiling.
To get the unit name you can turn on map file or debug information (aka TD32) and do the following:
Use the FileByLevel function from JclDebug - in your case with the default value (0).
The level parameter tells the function how many calls it look up the callstack. If you put that method into a FormCreate of a VCL form for example and pass 1 it will give you Vcl.Forms.pas as the event handler was called from there.
I hesitate to write this answer as it shows a really dirty hack to get the unit name making use of the Assert compiler magic shown above.
Use the following unit:
unit UnitNameHack;
interface
const
cUnitNameSentinel = '$$$sentinel$$$';
var
HackUnitname: string = '';
implementation
var
OrgAssertErrorProc: TAssertErrorProc = nil;
procedure MyAssertErrorProc(const Message, Filename: string; LineNumber: Integer; ErrorAddr: Pointer);
begin
if Message = cUnitNameSentinel then begin
HackUnitname:= Filename;
end
else begin
OrgAssertErrorProc(Message, Filename, LineNumber, ErrorAddr);
end;
end;
initialization
OrgAssertErrorProc := AssertErrorProc;
AssertErrorProc := MyAssertErrorProc;
finalization
AssertErrorProc := OrgAssertErrorProc;
end.
Now whenever you need the unit name call
Assert(False, cUnitNameSentinel);
and retrieve the unit name from HackUnitname.
Note that you cannot wrap the Assert call and reading HackUnitName into a function, not even if inlined.
You've said, something similar. I see that it might have been in a different context, but anyway, for objects you can inspect UnitName or UnitScope to get the name of the module where the object instance was declared, without the module path (which is not valuable information anyway).
Based on Uwe Raabe's answer:
// directly after the implementation uses:
var
ThisUnit: string = '<unknown>';
procedure MyAssertErrorProc(const Message, Filename: string; LineNumber: Integer; ErrorAddr: Pointer);
begin
ThisUnit := Filename;
end;
procedure InitThisUnit;
var
OrgAssertErrorProc: TAssertErrorProc;
begin
OrgAssertErrorProc := AssertErrorProc;
try
AssertErrorProc := MyAssertErrorProc;
Assert(False);
finally
AssertErrorProc := OrgAssertErrorProc;
end;
end;
// [...]
// call InitThisUnit in the initialization section
initialization
InitThisUnit;
end.
It's still a hack, but a bit more elegant. ;-)

How to convert string to TPenStyle?

I saw some very similar threads here, but I couldn't find solution to my problem.
I take the value from TStringList and use it as pen style (psDot, psSolid and so on), but the compilation fails with Incompatible types: 'TPenStyle' and 'String' error message.
Here is the code:
Image1.Canvas.Pen.Style := myList.ValueFromIndex[j];
How can I convert myList.ValueFromIndex[j] to TPenStyle ?
if stored as psDot, psSolid else you have to adapt
uses TypInfo;
Image1.Canvas.Pen.Style := TPenStyle(GetEnumValue(TypeInfo(TPenStyle),myList.ValueFromIndex[j]));
as suggested by David Heffernan
Function PenStyleFromName(const Name: string):TPenStyle;
begin
Result := TPenStyle(GetEnumValue(TypeInfo(TPenStyle),Name));
end;
//....
Image1.Canvas.Pen.Style := PenStyleFromName(myList.ValueFromIndex[j]);

how to write a value into a created Registry in Delphi

myReg:=TRegistry.Create;
myReg.CreateKey('\sunandan123\');
//myReg.WriteString('Tile','1');
myReg.WriteString ('TileWallpaper','1') ;
This code gives an exception that i 'failed to set the value for 'TileWallpaper'. how to correct it?
Thanks
I always do it like this.
procedure TForm1.Button1Click(Sender: TObject);
var R: TRegistry;
begin
R := TRegistry.Create;
try
if not R.OpenKey('Software\CompanyName\ProductName\SubKey', True) then
RaiseLastOSError;
R.WriteString('ValueName', '1');
R.WriteString('Other Value Name', 'Some other value');
finally R.Free;
end;
end;
Calling CreateKey doesn't open the key which is why the write fails.
The easiest solution is to replace the call to CreateKey with one to OpenKey passing True for the CanCreate parameter. This will create the key if it does not already exist, and then open it for you to use in subsequent method calls.
myReg.OpenKey('\sunandan123\', True);
myReg.WriteString ('TileWallpaper', '1');
And for the sake of completeness you should include error handling, try/finally around the lifetime of myReg etc. I would also recommend that you explicitly set RootKey since at the moment you are relying on its default value of HKCU.

PascalScript including other script per uses or include command

I have included the PascalScript engine into my software. My user now wants to write a whole set of scripts for this engine, and would like to know if it is possible to include other Scripts by an include or uses commmand.
What he wants to do is write one script that holds all kinds of constants/variables and another that does the logic. In the end he wants to include the constants into his logic script.
I hope this was clear enough to understand.
I found out, heres how how do to it:
The UsePreprocessor Property of the PascalScript compiler needs to be set to true. If so you can now use the following preprocessor command:
{$I filename.txt}
Also you need to implement the OnNeedFile Event of the compiler with something like the following example that I found on the net:
function TForm1.ceNeedFile(Sender: TObject; const OrginFileName: String;
var FileName, Output: String): Boolean;
var
path: string;
f: TFileStream;
begin
Path := ExtractFilePath(ParamStr(0)) + FileName;
try
F := TFileStream.Create(Path, fmOpenRead or fmShareDenyWrite);
except
Result := false;
exit;
end;
try
SetLength(Output, f.Size);
f.Read(Output[1], Length(Output));
finally
f.Free;
end;
Result := True;
end;
(Please fix your question title)
I'm not entirely sure but afaik Pascalscript has no "file" concept. You could simply concat both parts before passing them to the interpreter, or have a small preprocessor look for the {$I } include statements and look the code to insert up.
If you set the conditional define to PS_USESSUPPORT
and in the OnFindUnknownFile event you have to load the pas-file content
into the output string.
Then you can use "Uses XYZ;".

How to fast copy from hash to listview?

There is a hash pas file http://gpdelphiunits.googlecode.com/svn-history/r4/trunk/src/GpStringHash.pas
We can create hash and add key - value
Question 1:
We want to know how to iterate key - value and copy data to listview.
Question 2: is there a way to fast copy like assign method to it?
Thank you very much in advance.
Dear gabr, Thank you so much for your immediate reply and your hash file. Is there doc or help files or examples or demo for your code ? Thank you so much again.
Just test, I do not know where i did wrong
Thank you so much. I just used your code but there is the following error prompt. Or I made some mistakes:
procedure TForm8.ab;
var
a: TGpStringHash;
i,j, fr:integer;
k: string;
enlist: TGpStringHashenumerator;
kv: TGpStringHashKV;
begin
a:=TGpStringHash.Create;
kv:=TGpStringHashKV.Create;
enlist:= TGpStringHashenumerator.Create(a);
for j:=1 to 10 do begin
if a.HasKey(inttostr(j)) then begin
fr:=a.ValueOf(inttostr(j));
a.Update(inttostr(j),fr+1);
end
else begin
a.Add(inttostr(j),1);
end;
end;
for i:=0 to a.Count -1 do begin
kv:=enlist.GetCurrent;
memo1.Lines.Add(kv.Key + inttostr(kv.value) );
end;
end; /// Division by Zero ERROr ///FindBucket(const key: string): cardinal;
ANSWER:
You're using enumerator improperly. Don't instantiate it in front and always use MoveNext to move to the next element.
// fill 'a' as above
enlist := TGpStringHashenumerator.Create(a);
while enList.MoveNext do begin
kv:=enlist.GetCurrent;
memo1.Lines.Add(kv.Key + inttostr(kv.value) );
end;
1) Use the latest version. It implements enumerators for all containers.
2) No.
EDIT:
I have committed my internal GpStringHash test app to the repository. It can server as a demo on how to use GpStringHash classes.
To enumerate TGpStringHash you would use
var
hash: TGpStringHash;
kv: TGpStringHashKV;
for kv in hash do
// do something with kv.Key and kv.Value
If you're using an older Delphi without support for enumerators, you can use ForEach method with an external callback method.
procedure TGpStringHash.ForEach(enumerator: TGpStringHashEnumMethod);
var
enum: TGpStringHashEnumerator;
begin
enum := GetEnumerator;
try
while enum.MoveNext do
enumerator(enum.Current);
finally FreeAndNil(enum); end;
end; { TGpStringHash.ForEach }

Resources