Ok to use VirtualProtect to change resource in Delphi? - delphi

I'm working on a simple localization effort in D2010. I'm handling all strings on forms because ETM seems like overkill for my needs, as did other 3rd party tools... (although I'm not so sure at this point!)
Is the code below for changing the Const.pas strings considered safe to change the button labels on standard message boxes?
procedure HookResourceString(rs: PResStringRec; newStr: PChar);
var
oldprotect: DWORD;
begin
VirtualProtect(rs, SizeOf(rs^), PAGE_EXECUTE_READWRITE, #oldProtect);
rs^.Identifier := Integer(newStr);
VirtualProtect(rs, SizeOf(rs^), oldProtect, #oldProtect);
end;
const
NewOK: PChar = 'New Ok';
NewCancel: PChar = 'New Cancel';
Procedure TForm.FormCreate;
begin
HookResourceString(#SMsgDlgOK, NewOK);
HookResourceString(#SMsgDlgCancel, NewCancel);
end;

Yes, it should be fine, but I have some comments:
Make sure to call your HookResourceString function from only one thread at a time. If two threads call it simultaneously, you could end up restoring the wrong permissions.
Also for multithreading, make sure you don't use this code at a time when some other thread might be attempting to load a resourcestring. LoadResString reads the Identifier field twice, and it needs to have the same value both times.
There's no need to declare the new values as typed constants. Ordinary true constants are fine. (The compiler knows they need to be PChars because they're passed as actual arguments for a PChar parameter.)

Why not use dxgettext? It's open source, so you could at least take a look at how they do it...
http://dxgettext.po.dk/

Related

How can I modify and return a variable of type PChar in a function call

I need store a variant value (which always return a string) in a PChar variable now i'm using this code
procedure VariantToPChar(v:variant; p : PChar);
Var
s : String;
begin
s:=v;
GetMem(p,Length(s)*Sizeof(Char));
StrCopy(p, PChar(s));
end;
But i'm wondering if exist a better way
Do you really, really have to create a PChar? As long as possible i would use Strings, and only if an external library (like the Windows API) requires a PChar, i would cast it.
uses
Variants;
var
vText: Variant;
sText: String;
begin
vText := 'Hello world';
// VarToStr() can handle also null values
sText := VarToStr(vText);
// If absolutely necessary, cast it to PChar()
CallToExternalFunction(PChar(sText));
Doing it like this you can avoid problems with memory (de)allocation, null values, and Ansi/Unicode chars. If the external function wants to write into the string, you can use SetLength() before casting. Maybe the article Working with PChar could give you some ideas.
Update: You really shouldn't do this or use this code as you're likely to encourage people to write code that leaks. People will call this and fail to free the memory since they don't know that this function allocates memory.
If you want to store something in a PChar size buffer, and have that value still be associated with p (the pointer p is modified and is different when you return from the procedure), then you need to make the parameter a var (by-reference instead of by-value) parameter like this:
procedure AllocPCharBufFromVariant(v:variant; var p : PChar);
Var
s : String;
begin
try
s:=v;
GetMem(p,(Length(s)+1)*Sizeof(Char)); // fixed to add 1 for the nul
StrCopy(p, PChar(s));
except
on E:EVariantError do
begin
p := nil;
end;
end;
end;
I have also shown above handling EVariantError, which I have chosen to handle by returning nil in the p parameter, but you should think about how you want it to work, and then deal with it somehow.
The above code also leaks memory which is awful, so I renamed it AllocPChar. It seems like your original code has so many problems that I can't recommend a good way to do what looks like a giant pile of bad things and the name you chose is among the most awful choices.
At least the name Alloc gives me a hint so I'm thinking "I better free this when I'm done with it".
I suspect just a
PChar(string(v))
expression will do the trick.
And the memory used to store the converted string content will be available in the scope of this code (i.e. as long as the string(v) will be referenced - so you may want to use an explicit string variable to ensure that your PChar memory is still allocated).

Elegant way for handling this string issue. (Unicode-PAnsiString issue)

Consider the following scenario:
type
PStructureForSomeCDLL = ^TStructureForSomeCDLL;
TStructureForSomeCDLL = record
pName: PAnsiChar;
end
function FillStructureForDLL: PStructureForSomeDLL;
begin
New(Result);
// Result.pName := PAnsiChar(SomeObject.SomeString); // Old D7 code working all right
Result.pName := Utf8ToAnsi(UTF8Encode(SomeObject.SomeString)); // New problematic unicode version
end;
...code to pass FillStructureForDLL to DLL...
The problem in unicode version is that the string conversion involved now returns a new string on stack and that's reclaimed at the end of the FillStructureForDLL call, leaving the DLL with corrupted data. In old D7 code, there were no intermediate conversion funcs and thus no problem.
My current solution is a converter function like below, which is IMO too much of an hack. Is there a more elegant way of achieving the same result?
var gKeepStrings: array of AnsiString;
{ Convert the given Unicode value S to ANSI and increase the ref. count
of it so that returned pointer stays valid }
function ConvertToPAnsiChar(const S: string): PAnsiChar;
var temp: AnsiString;
begin
SetLength(gKeepStrings, Length(gKeepStrings) + 1);
temp := Utf8ToAnsi(UTF8Encode(S));
gKeepStrings[High(gKeepStrings)] := temp; // keeps the resulting pointer valid
// by incresing the ref. count of temp.
Result := PAnsiChar(temp);
end;
One way might be to tackle the problem before it becomes a problem, by which I mean adapt the class of SomeObject to maintain an ANSI Encoded version of SomeString (ANSISomeString?) for you alongside the original SomeString, keeping the two in step in a "setter" for the SomeString property (using the same UTF8 > ANSI conversion you are already doing).
In non-Unicode versions of the compiler make ANSISomeString be simply a "copy" of SomeString string, which will of course not be a copy, merely an additional ref count on SomeString. In the Unicode version it references a separate ANSI encoding with the same "lifetime" as the original SomeString.
procedure TSomeObjectClass.SetSomeString(const aValue: String);
begin
fSomeString := aValue;
{$ifdef UNICODE}
fANSISomeString := Utf8ToAnsi(UTF8Encode(aValue));
{$else}
fANSISomeString := fSomeString;
{$endif}
end;
In your FillStructure... function, simply change your code to refer to the ANSISomeString property - this then is entirely independent of whether compiling for Unicode or not.
function FillStructureForDLL: PStructureForSomeDLL;
begin
New(Result);
result.pName := PANSIChar(SomeObject.ANSISomeString);
end;
There are at least three ways to do this.
You could change SomeObject's class
definition to use an AnsiString
instead of a string.
You could
use a conversion system to hold
references, like in your example.
You could initialize result.pname
with GetMem and copy the result of the
conversion to result.pname^ with
Move. Just remember to FreeMem it
when you're done.
Unfortunately, none of them is a perfect solution. So take a look at the options and decide which one works best for you.
Hopefully you already have code in your application to properly dispose off of all the dynamically allocated records that you New() in FillStructureForDLL(). I consider this code highly dubious, but let's assume this is reduced code to demonstrate the problem only. Anyway, the DLL you pass the record instance to does not care how big the chunk of memory is, it will only get a pointer to it anyway. So you are free to increase the size of the record to make place for the Pascal string that is now a temporary instance on the stack in the Unicode version:
type
PStructureForSomeCDLL = ^TStructureForSomeCDLL;
TStructureForSomeCDLL = record
pName: PAnsiChar;
// ... other parts of the record
pNameBuffer: string;
end;
And the function:
function FillStructureForDLL: PStructureForSomeDLL;
begin
New(Result);
// there may be a bug here, can't test on the Mac... idea should be clear
Result.pNameBuffer := Utf8ToAnsi(UTF8Encode(SomeObject.SomeString));
Result.pName := Result.pNameBuffer;
end;
BTW: You wouldn't even have that problem if the record passed to the DLL was a stack variable in the procedure or function that calls the DLL function. In that case the temporary string buffers will only be necessary in the Unicode version if more than one PAnsiChar has to be passed (the conversion calls would otherwise reuse the temporary string). Consider changing the code accordingly.
Edit:
You write in a comment:
This would be best solution if modifying the DLL structures were an option.
Are you sure you can't use this solution? The point is that from the POV of the DLL the structure isn't modified at all. Maybe I didn't make myself clear, but the DLL will not care whether a structure passed to it is exactly what it is declared to be. It will be passed a pointer to the structure, and this pointer needs to point to a block of memory that is at least as large as the structure, and needs to have the same memory layout. However, it can be a block of memory that is larger than the original structure, and contain additional data.
This is actually used in quite a lot of places in the Windows API. Did you ever wonder why there are structures in the Windows API that contain as the first thing an ordinal value giving the size of the structure? It's the key to API evolution while preserving backwards compatibility. Whenever new information is needed for the API function to work it is simply appended to the existing structure, and a new version of the structure is declared. Note that the memory layout of older versions of the structure is preserved. Old clients of the DLL can still call the new function, which will use the size member of the structure to determine which API version is called.
In your case no different versions of the structure exist as far as the DLL is concerned. However, you are free to declare it larger for your application than it really is, provided the memory layout of the real structure is preserved, and additional data is only appended. The only case where this wouldn't work is when the last part of the structure were a record with varying size, kind of like the Windows BITMAP structure - a fixed header and dynamic data. However, your record looks like it has a fixed length.
Wouldn't PChar(AnsiString(SomeObject.SomeString)) work?

Why is Self assignable in Delphi?

This code in a GUI application compiles and runs:
procedure TForm1.Button1Click(Sender: TObject);
begin
Self := TForm1.Create(Owner);
end;
(tested with Delphi 6 and 2009)
why is Self writable and not read-only?
in which situations could this be useful?
Edit:
is this also possible in Delphi Prism? (I think yes it is, see here)
Update:
Delphi applications/libraries which make use of Self assignment:
python4delphi
That's not as bad as it could be. I just tested it in Delphi 2009, and it would seem that, while the Self parameter doesn't use const semantics, which you seem to be implying it should, it also doesn't use var semantics, so you can change it all you want within your method without actually losing the reference the caller holds to your object. That would be a very bad thing.
As for the reason why, one of two answers. Either a simple oversight, or what Marco suggested: to allow you to pass Self to a var parameter.
Maybe to allow passing to const or var parameters?
It could be an artefact, since system doesn't have self anywhere on the left of := sign.
Assigning to Self is so illogical and useless that this 'feature' is probably an oversight. And as with assignable constants, it's not always easy to correct such problems.
The simple advice here is: don't do it.
In reality, "Self" is just a name reference to a place on the stack that store address pointing to object in the heap. Forcing read-only on this variable is possible, apparently the designer decided not to. I believe the decision is arbitrary.
Can't see any case where this is useful, that'd merely change a value in stack. Also, changing this value can be dangerous as there is no guarantee that the behavior of the code that reference instance's member will be consistence across compiler versions.
Updated: In response to PatrickvL comment
The 'variable' "Self" is not on the
stack (to my knowledge, it never is);
Instead it's value is put in a
register (EAX to be exact) just before
a call to any object method is made. –
Nope, Self has actual address on the memory. Try this code to see for yourself.
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(IntToStr(Integer(#Self)));
end;
procedure TForm1.Button2Click(Sender: TObject);
var
newform: TForm;
p: ^Integer;
begin
Self.Caption := 'TheOriginal';
newform := TForm.Create(nil);
try
newform.Caption := 'TheNewOne';
// The following two lines is, technically, the same as
// Self := newform;
p := Pointer(#Self);
p^ := Integer(newform);
ShowMessage(Self.Caption); // This will show 'TheNewOne' instead of 'TheOriginal'
finally
Self.Free; // Relax, this will free TheNewOne rather than TheOriginal
end;
end;
Sometimes, when you want to optimize a method for as far as you can take it (without resorting to assembly), 'Self' can be (ab)used as a 'free' variable - it could just mean the difference between using stack and using registers.
Sure, the contents of the stack are most probably already present in the CPU cache, so it should be fast to access, but registers are even faster still.
As a sidenote : I'm still missing the days when I was programming on the Amiga's Motorola 68000 and had the luxury of 16 data and 16 address registers.... I can't believe the world chose to go with the limited 4 registers of the 80x86 line of processors!
And as a final note, I choose to use Self sometimes, as the Delphi's optimizer is, well, not optimizing that well, actually. (At least, it pales compared to what trickery one can find in the various LLVM optimizers for example.) IMHO, and YMMV of course.

Is there a function like PHP's vardump in Delphi?

I've given up on the Delphi 7 debugger and am pretty much relying on outputdebugstrings. Is there a standard function I can call to get the contents of an object as a string like the debugger would if I set a breakpoint?
Not exactly what your looking for, but you can use RTTI to get access to the values of various published properties. The magical routines are in the TypInfo unit. The ones you are probably most interested in are GetPropList which will return a list of the objects properties, and GetPropValue which will allow you to get the values of the properties.
procedure TForm1.DumpObject( YourObjectInstance : tObject );
var
PropList: PPropList;
PropCnt: integer;
iX: integer;
vValue: Variant;
sValue: String;
begin
PropCnt := GetPropList(YourObjectInstance,PropList);
for iX := 0 to PropCnt-1 do
begin
vValue := GetPropValue(YourObjectInstance,PropList[ix].Name,True);
sValue := VarToStr( vValue );
Memo1.Lines.Add(PropList[ix].Name+' = '+sValue );
end;
end;
for example, run this with DumpObject(Self) on the button click of the main form and it will dump all of the properties of the current form into the memo. This is only published properties, and requires that the main class either descends from TPersistent, OR was compiled with {$M+} turned on before the object.
Rumor has it that a "reflector" like ability will be available in a future version of Delphi (possibly 2010).
Consider something like Codesite which is a much more complete tracing solution. It allows you to output much more complex info, and then search, print, and analyse the data. But for your purposes, you can simply send an object to it with Codesite.Send('Before', self); and you get all the RTTI available properties in the log. Do an "After" one too, and then you can compare the two in the Codesite output just by selecting both. It's saved me many times.
if delphi 7 is the .NET version, then you could do (some of) that with reflection. (not easy, but not terribly hard). if it's the normal, compiled thing, then it's a hard problem and the debugger is you best bet, apart from specialized printing functions/methods.

What is the correct way to check if a value is a date/number in Delphi

What is the correct way to check if a value is a date/number in Delphi?
I know other languages have functions like isDate and isNaN, but what is the Delphi equivalent? at the minute I have this
function isNumeric(s1:string):boolean;
begin
// will throw exception if its not a number
// there must be a better way to do this!!
try
StrTofloat(s1);
result := TRUE ;
except
result := FALSE;
end;
end;
But throwing exceptions cant be good, and it makes debugging hard as I keep seeing the exception dialogue every time the code is called.
For integers, you could use TryStrToInt to check and convert without throwing exceptions:
function TryStrToInt(const s: string; out i : integer): boolean;
I'm not absolutely sure there is a full equivalent for floats, though, so you might need to use StrToFloat() and accept the possibility of a TFormatException.
There's a family of functions like TryStrToFloat, TryStrToDateTime etc. which do that. By the way, StrToFloat and others use the "Try" versions internally before raising exceptions.
Firstly StrToFloatDef function is a useful alternative here if you want to stay in the language as delivered out the box.
However your best option is to deploy the JEDI code libraries (http://www.delphi-jedi.org/) and use the StrIsNumber function from there.
JEDI is open source, highly useful in lots of ways, and pretty much a must anyway.
Catching exceptions is very slow. If you plan on using such a function repeatedly in rapid succession, such as when validating fields during a file import, it might be worth it to roll your own function that does some simple character level checking before falling into a try/except block. I've used something similar before with a huge performance increase when parsing large amounts of data that was not in the correct format.
function IsNumeric(aValue : string): boolean;
var
i : integer;
begin
result := false;
for i := 1 to Length(aValue) do
if (NOT (aValue[i] in ['0'..'9', '.', '-', '+', 'E', 'e'])) then
exit;
try
StrToFloat(aValue);
result := true;
except
end;
end;
Obviously this may not be perfect, and has the limitation of hard-coded values in it. Depends entirely on your needs, this was just something simple that worked well for an internal process.
I use strtointdef(singlecharacter,-1)
procedure TForm1.Button1Click(Sender: TObject);
var
x,i:integer;
teststring:string;
begin
teststring:='1235';
for i:=1 to length(teststring) do begin
x:= strtointdef(teststring[i],-1);
if x=-1 then break;
end;
if x<0 then showmessage('not numeric')
else showmessage('numeric');
end;
You CAN turn off the annoying exceptions you don't want by checking the "ignore this exception" box that pops up. Future exceptions will be then ignored for that exception class. To start asking again, just go to the Options|Debugger Options and uncheck the ones you are ignoring.

Resources