# Operator usage when mapping method entry points - delphi

When dynamically loading a DLL where DoSomething is a method type variable we can do
DoSomething:= GetProcAddress(MyDLLHandle ,'DoSomething');
or
#DoSomething:= GetProcAddress(MyDLLHandle ,'DoSomething');
Both of these seem to behave identically in modern versions of Delphi. My question is - has the # operator always been optional and, if not, in which version of Delphi did it become optional?
The documentation states that #, when used with routine (function/procedure) types returns the entry point of the function with type Pointer. When using the variable directly it naturally has whatever specific type it was declared with but also returns the entry point to the method. GetProcAddress returns a Pointer so I'm assuming that the habit of including # when loading a DLL comes from a time when these mismatched types were not assignment compatible. Is this the case?
Are there any reasonable arguments to prefer either of these styles?

I don't believe that anything has changed since the original versions of Delphi.
The official header translation for GetProcAddress has a return type of FARPROC which is an alias to the untyped Pointer type. Because of this, you can put pretty much anything pointer-esque on the left hand side of the assignment statement, because type checking is suspended when one of the operands is Pointer.
On the other hand, consider this program:
var
Proc: procedure;
Ptr: Pointer;
begin
Ptr := Proc;
end.
This fails to compile with:
E2010 Incompatible types: 'Pointer' and 'procedure, untyped pointer or untyped parameter'
The simple fix is to use the # operator:
var
Proc: procedure;
Ptr: Pointer;
begin
Ptr := #Proc;
end.
It is certainly the case that many Delphi examples use:
#Proc := GetProcAddress(...);
rather than
Proc := GetProcAddress(...);
I rather suspect that there is nothing deep here. Just a case of a choice made by the author of one of the first online articles on the subject propagating throughout history with no good reason. Which reminds me of the terrible Rosetta code example of dynamic loading that tests whether an HMODULE is greater than 32, an erroneous check that can be seen in Stack Overflow questions on a weekly basis!
Should you use # in these circumstances or not? In my view you should not. It doesn't make much difference, and given that why bother with a needless piece of punctuation?
There is one other scenario that I know where you need to use #, and in that case you actually need ##. Consider the following program:
{$APPTYPE CONSOLE}
uses
SysUtils;
var
Proc: procedure;
Ptr: Pointer;
begin
Ptr := #Proc;
Writeln(Format('%p', [Ptr]));
Ptr := ##Proc;
Writeln(Format('%p', [Ptr]));
Readln;
end.
Output
00000000
00423EBC
The first assignment gets the value held in the Proc variable, which because it is a default initialised global, is zero. The second assignment gets the address of the Proc variable. And for that you need ##. It's pretty unusual to need this much indirection, but it tends to crop up when writing code related to dynamic linking.

Related

How to track down double pointer usage mistakes

Recently I've ported a huge chunk of code form C++ to Delphi (over 1mb of C code). The code is full with pointers. Despite project compiling and working well for 99% of the time, I'm seeing some weird results from time to time, which leads me to think there might be bugs with pointer handling - indeed, I've already found a couple. The problem is that they are really hard to track down without any clues/hints from compiler.
Maybe you have some tips, for such cases:
var
a: PSingle;
GetMem(a, SizeOf(Single));
a^ := 1.1;
// Call func declared as - someFunc(aIn: PSingle);
someFunc(#a); // <<-- Bug here. I mistakely added # while porting.
// someFunc needs PSingle, but gets a PPSingle instead
In the example, there's erroneous # inserted. Program does not crash, just deals with that erroneous data and keeps running. I need a way of finding such cases where "Pointer to a Pointer to a Value" gets passed instead of "Pointer to a Value".
How do you track down pointer bugs like these?
The "typed # operator" compiler option is designed to detect exactly that kind of mistake. When it's disabled, the expression #a has type Pointer, which is compatible with all pointer types. Enable the option, and the same expression has type ^PSingle, which is not compatible with the expected PSingle.
I recommend turning on that option in all projects; it baffles me that Delphi doesn't make that option the default all the time.
You can modify the state of that option within your code with the $T+ and $T- compiler directives.
Another thing you can do is convert your code to use more idiomatic Delphi. For example, pass the argument by reference instead of by pointer value. Change the definition of the argument:
procedure someFunc(var arg: Single);
With that declaration, passing #a will be an error that the compiler will find and forbid. You would instead pass a^, or you could even get rid of the pointer entirely and just declare a as a plain Single rather than PSingle.
Just because the original code was written in C and C-style C++, it doesn't mean your Delphi code has to look like it.
The problem is here:
someFunc(#a);
You are adding a pointer to a pointer not the pointer it self.
Let me make you an example:
uses
Math;
function Somefunc(value: pSingle): Single;
begin
Result := (value^ + 1.1)
end;
procedure TForm23.FormCreate(Sender: TObject);
var
a: pSingle;
b: Single;
begin
GetMem(a, SizeOf(Single));
a^ := 1.1;
//Example 1:
b := Somefunc(a);
Caption := BoolToStr(CompareValue(2.2, b, 0.00001) = 0., True); //Caption: True
//Example 2:
b := Somefunc(#a); //NOTE #a
Caption := BoolToStr(CompareValue(1.1, b, 0.00001) = 0., True); //Caption: True
FreeMem(a);
end;
As you see in the first example the actual value are changed, while in example 2 the value og a remains unchanged because you parse the pointer to the pointer and therefor it is the pointer you chanhe and not the value.

How can I receive a string from FPC DLL? [duplicate]

This question already has answers here:
Need simple demo call Delphi DLL in C++
(2 answers)
Closed 8 years ago.
How can I receive a string from a FPC DLL? I would like to send two pointers concat them and receive the result in another string in Delphi.
library Test;
{$mode Delphi}
uses
Classes;
function Concat(const S1, S2: PWideChar): String; cdecl;
begin
Result := S1 + S2;
end;
exports
Concat name 'Concat';
begin
end.
In Delphi, a String is a complex, structured type with many details managed for you by the compiler and RTL 'magic' that hides these details. In particular, for 'long strings' there is a reference count and a length and, depending on the Delphi version involved, possibly other information.
Any DLL cannot know the details of precisely what information is required to be returned (or may be present in) any 'string' variables (or results) that an application may require. The DLL may not even be called by a Delphi program at all, in which case the 'string' type will be quite different again.
For this reason, a DLL will usually choose to deal with strings as simple 'C'-style pointer to char types. That is, some pointer to a null terminated region of memory. The caller of the DLL must then also ensure to exchange 'string' values with the DLL accordingly.
In the case of some function returning a value, the issue is complicated by the fact that allocation of the area of memory required to hold the result must be performed by the caller, with the function in the DLL taking appropriate steps to ensure that the memory supplied is sufficient. Applying these principles in this case results in a DLL routine that might look similar to this:
function Concat(const S1, S2, DEST: PWideChar; const aMaxLen: Integer): Boolean; cdecl;
begin
// left as exercise
end;
This is a simple implementation that returns TRUE if aMaxLen is sufficient to accommodate the concatenated result. You should also consider other behaviours of the function under a variety of conditions (eg. S1 or S2 or both are NIL, aMaxLen is too big, etc).
Whatever implementation choices are made for performing the concatenation (left as an exercise for you), the result of the function call must be to place the result in the buffer pointed to by DEST.
The caller must then also ensure that a buffer of sufficient length is provided and the correct length indicated in the call:
var
a, b, ab: WideString; // Or: String or UnicodeString in Delphi 2009 and later
begin
a := 'foo';
b := 'bar';
// Make sure 'ab' is big enough to hold the concatenated result of a + b
SetLength(ab, Length(a) + Length(b));
if Concat(PWideChar(a), PWideChar(b), PWideChar(ab), Length(ab)) then
// success: ab == 'foobar'
else
// something went wrong
end;
The question has to be asked though: Why are you doing this in an FPC DLL when Delphi already handles the concatenation of strings quite comfortably ? O.o

Error Delphi XE2 - Exception class $C00000005

I am getting this error will debugging a project, which used to be in Delphi 7 and I have been upgrading to Delphi XE2, the same error happens in several methods.
First chance exception at $006DC660. Exception class $C0000005 with message 'access violation at 0x006dc660 read of address 0xffffffff'
This is one of the methods:
PFI = ^TFI;
TFI = record
Id : TToken;
Name : TName;
Parameters : string;
end;
function TListFI.IsIn(S: PChar): PFI;
function SearchName2(Item: PFI):Boolean;
var N1, N2: PChar;
begin
N1:= StrNew(Item^.Name);
N2:= StrNew(S); //Here is the issue
SearchName2:= (StrComp(StrUpper(N1), StrUpper(N2)) = 0);
StrDispose(N1);
StrDispose(N2);
end;
begin
IsIn:= PFI(FirstThat(#SearchName2));
end;
I have googled and I found someone describing a similar problem, and he affirms that when the incremental linker is disabled it works, can someone tell me what and where is it or give some advice to solve this situation.
[EDIT]
Removing the # now gives me the following error in IsIn:= PFI(FirstThat(SearchName2));
E2010 Incompatible types: 'TObject' and 'PFI'
I am adding the FirstThat procedure to see if it may help.
TFuncionColeccion = function (Elemento: TObject): Boolean;
function TColeccion.FirstThat (Rutina: TFuncionColeccion): TObject;
var
i: Integer;
begin
For i:=0 to Count-1 do
if Rutina(Items[i]) then
begin
FirstThat:=Items[i];
exit;
end;
FirstThat:=nil;
end;
It is (and always has been) an error to call local (nested) procedures by pointer, which is clearly what your FirstThat function does. The compiler has to do special things with the stack to call local functions and give them access to the parent scope's variables (S in your code), but the compiler can only know to do those special things when the local function is called directly. The compiler cannot know that the argument to FirstThat will be a local function, so it doesn't include the special code when FirstThat invokes the pointed-to function.
The bottom line is that the stack inside the function doesn't get set up the way it's supposed to, and that means any number of strange symptoms may appear. You'll have to use some other way. Maybe make SearchName2 be a two-argument function, and then write FirstThat to accept S as a parameter that it can forward to the function argument.
You shouldn't need to use the # operator when constructing a function pointer. When you do, the compiler tends to skip type checking, which is what allowed you to pass a local function pointer to FirstThat in the first place. When the function you're passing really matches the required prototype, the compiler will allow you to pass it without the # operator.
You are reporting an access violation in
StrNew(S)
where S is of type PChar. The explanation for that, with probability very close to 1, is that S is not in fact a pointer to null terminated array of WideChar.
In Delphi 7, PChar is an alias for PAnsiChar. That is a pointer to null terminated array of AnsiChar, i.e. 8 bit characters. In Delphi XE2, PChar is an alias for PWideChar, a pointer to null terminated array of WideChar, i.e. 16 bit characters.
It helps to understand what StrNew does. It walks the array until it finds a null character. For 8 bit text that is a single zero byte. For 16 bit text, the null is a zero 16 bit word. Then it allocates a new block of memory of the same length as the input string, and makes a copy into that new memory. The source code is:
function StrNew(const Str: PWideChar): PWideChar;
var
Size: Cardinal;
begin
if Str = nil then Result := nil else
begin
Size := StrLen(Str) + 1;
Result := StrMove(WideStrAlloc(Size), Str, Size);
end;
end;
The only plausible failure mode is that when StrLen walks the array, it attempts an invalid memory read. And that can only happen if your input parameter is invalid. In other words, this must be a programming error on your part.
One possible explanation is that you are in fact passing 8 bit text to this function despite promising to pass 16 bit text. An easy mistake to make, especially if you are not yet fully familiar with the Unicode change. The 8 bit text has a zero terminator, but the byte that follows happens not to be zero. Or the zero byte falls at an odd numbered offset from the start. And then StrNew continues walking the buffer, but now it is off the end and it so happens that it doesn't find a zero word before overrunning into an address that has not been allocated. And that is an access violation.
If that is so then solution will be either:
Change the function's parameter to be of type PAnsiChar, and fix the dubious casting at the call site.
Pass the function 16 bit text as it requires.
In your update you include the address which cannot be read, 0xffffffff. This is -1 in hex. And that would seem to be the most prosaic of errors. Your pointer is completely bogus! Your exact error message can be reproduced with this code: StrNew(PChar(-1)).
I don't have enough information here to tell you why your pointer is bogus. Hopefully you've learnt some debugging and diagnostic techniques that will enable you to solve the problem. At least you now know that the error is in your code.
Assuming that BuscaName2 and SearchName2 are one and the same thing, then you need look no further. Local procedures can only be called from a containing function. As #Rob correctly says, the use of # with procedures is almost always incorrect and is a warning sign of serious problems with your code.

Is there any way to get RTTI hints for a real48 and shortstring variable in a structure where FieldType is nil in TRttiField?

I have discovered what I think is an odd oversight (probably intentional) on the part of the Extended RTTI feature in Delphi.
I would like to dump all the fields in an record type that has about 1500 different fields in it. Yes, seriously.
Some of them are of type real48 and some are shortstring, for those two, it appears that FieldType is nil for these types at runtime:
function TRttiField.GetValue(Instance: Pointer): TValue;
var
ft: TRttiType;
begin
ft := FieldType;
if ft = nil then
raise InsufficientRtti; // This fires!
TValue.Make(PByte(Instance) + Offset, ft.Handle, Result);
end;
If I was willing to assume that all nil-fieldtype fields are in fact real48's, I could simply use the offset and (if the field width is 6) grab a real48 value.
However the second complication is that all shortstring (ie string[30]) types are similarly afflicted.
Has anybody got these two Ancient Pascal Types to work with modern Extended RTTI?
Right now I'm using a best-guess approach, and where that fails I am hardcoding rules by name of the field, but if there was some technique I could use that would get me there without having to write a lot of code to extract information from all these old pascal file-of-records that I am modernizing, I would appreciate a better idea.
Unfortunately Real48 does not have any type info.
You can see that when you try compile this:
program Project1;
begin
TypeInfo(Real48);
end.
The same goes for the string[n] syntax. But there you could probably fix it by defining your own string types like:
type
string30 = string[30];
That alone would not include the rtti for the record field so you need to hack/fix the rtti as I showed here: https://stackoverflow.com/a/12687747/587106

Delphi Compiler Directive to Evaluate Arguments in Reverse

I was really impressed with this delphi two liner using the IFThen function from Math.pas. However, it evaluates the DB.ReturnFieldI first, which is unfortunate because I need to call DB.first to get the first record.
DB.RunQuery('select awesomedata1 from awesometable where awesometableid = "great"');
result := IfThen(DB.First = 0, DB.ReturnFieldI('awesomedata1'));
(as a pointless clarification, because I've got so many good answers already. I forgot to mention that 0 is the code that DB.First returns if it's got something in it, might not have made sense otherwise)
Obviously this isn't such a big deal, as I could make it work with five robust liners. But all I need for this to work is for Delphi to evaluate DB.first first and DB.ReturnFieldI second. I don't want to change math.pas and I don't think this warrants me making a overloaded ifthen because there's like 16 ifthen functions.
Just let me know what the compiler directive is, if there is an even better way to do this, or if there is no way to do this and anyone whose procedure is to call db.first and blindly retrieve the first thing he finds is not a real programmer.
The evaluation order of expressions is commonly undefined. (C and C++ are the same way. Java always evaluates left-to-right.) The compiler offers no control over it. If you need two expressions to be evaluated in a specific order, then write your code differently. I wouldn't really worry about the number of lines of code. Lines are cheap; use as many as you need. If you find yourself using this pattern often, write a function that wraps it all up:
function GetFirstIfAvailable(DB: TDatabaseObject; const FieldName: string): Integer;
begin
if DB.First = 0 then
Result := DB.ReturnFieldI(FieldName)
else
Result := 0;
end;
Your original code probably wouldn't have been what you wanted, even if evaluation order were different. Even if DB.First wasn't equal to zero, the call to ReturnFieldI would still be evaluated. All actual parameters are fully evaluated before invoking the function that uses them.
Changing Math.pas wouldn't help you anyway. It doesn't control what order its actual parameters are evaluated in. By the time it sees them, they've already been evaluated down to a Boolean value and an integer; they're not executable expressions anymore.
The calling convention can affect evaluation order, but there's still no guarantee. The order that parameters are pushed onto the stack does not need to match the order in which those values were determined. Indeed, if you find that stdcall or cdecl gives you your desired evaluation order (left-to-right), then they are being evaluated in the reverse order of the one they're passed with.
The pascal calling convention passes arguments left-to-right on the stack. That means the leftmost argument is the one at the bottom of the stack, and the rightmost argument is at the top, just below the return address. If the IfThen function used that calling convention, there are several ways the compiler could achieve that stack layout:
The way you expect, which is that each argument is evaluated and pushed immediately:
push (DB.First = 0)
push DB.ReturnFieldI('awesomedata1')
call IfThen
Evaluate arguments right-to-left and store the results in temporaries until they're pushed:
tmp1 := DB.ReturnFieldI('awesomedata1')
tmp2 := (DB.First = 0)
push tmp2
push tmp1
call IfThen
Allocate stack space first, and evaluate in whatever order is convenient:
sub esp, 8
mov [esp], DB.ReturnFieldI('awesomedata1')
mov [esp + 4], (DB.First = 0)
call IfThen
Notice that IfThen receives the argument values in the same order in all three cases, but the functions aren't necessarily called in that order.
The default register calling convention also passes arguments left-to-right, but the first three arguments that fit are passed in registers. The registers used to pass arguments, though, are also the registers most commonly used for evaluating intermediate expressions. The result of DB.First = 0 needed to be passed in the EAX register, but the compiler also needed that register for calling ReturnFieldI and for calling First. It was probably a little more convenient to evaluate the second function first, like this:
call DB.ReturnFieldI('awesomedata1')
mov [ebp - 4], eax // store result in temporary
call DB.First
test eax, eax
setz eax
mov edx, [ebp - 4]
call IfThen
Another thing to point out is that your first argument is a compound expression. There's a function call and a comparison. There's nothing to guarantee that those two parts are performed consecutively. The compiler might get the function calls out of the way first by calling First and ReturnFieldI, and afterward compare the First return value against zero.
The calling convention affects the way they are evaluated.
There is not a compiler define to control this.
Pascal is the calling convention you would have to use to get this behavior.
Although I would personally never depend on this type of behavior.
The following example program demonstrates how this works.
program Project2;
{$APPTYPE CONSOLE}
uses SysUtils;
function ParamEvalTest(Param : Integer) : Integer;
begin
writeln('Param' + IntToStr(Param) + ' Evaluated');
result := Param;
end;
procedure TestStdCall(Param1,Param2 : Integer); stdCall;
begin
Writeln('StdCall Complete');
end;
procedure TestPascal(Param1,Param2 : Integer); pascal;
begin
Writeln('Pascal Complete');
end;
procedure TestCDecl(Param1,Param2 : Integer); cdecl;
begin
Writeln('CDecl Complete');
end;
procedure TestSafecall(Param1,Param2 : Integer); safecall;
begin
Writeln('SafeCall Complete');
end;
begin
TestStdCall(ParamEvalTest(1),ParamEvalTest(2));
TestPascal(ParamEvalTest(1),ParamEvalTest(2));
TestCDecl(ParamEvalTest(1),ParamEvalTest(2));
TestSafeCall(ParamEvalTest(1),ParamEvalTest(2));
ReadLn;
end.
This would require you to write your own IfThen Functions.
If you really want this to be a one liner you really can do that in Delphi. I just think it looks ugly.
If (DB.First = 0) then result := DB.ReturnFieldI('awesomedata1') else result := 0;
Can't you change your query to have only one result so avoid to do the 'First' command ?
Just like :
SELECT TOP 1 awesomedata1 from awesometable
In Access...
AFAIK there is no compiler directive to control this. Unless you use the stdcall/cdecl/safecall conventions, parameters are passed left to right on the stack, but because the default register convention can pass parameters in the registers as well, it could happen that a parameter is calculated later an put in a register just before the call. And because only the register order is fixed (EAX, EDX, ECX) for parameters that qualify, registers can be loaded in any order. You could try to force a "pascal" calling convention (you'd need to rewrite the function, anyway) but IMHO is always dangerous to rely on such kind of code, if the compiler can't explicitly guarantee the order of evaluation. And imposing an evaluation order may greatly reduce the number of optimizations available.

Resources