Someway to override Delphi default procedures at Design Time? - delphi

Someway to override Delphi default procedures at Design Time ?
I need to override the InstanceSize at design time, I did it runtime using FastCode method:
FastcodeAddressPatch(FastcodeGetAddress(#SInstanceSize), #TWinControl.RfInstanceSize);
But, is there some way to do it at Design time ?
Tks in advice

"Design time" is really just "run time," but in the context of the IDE instead of the context of your program. Put your code in a design-time package and load it in the IDE. The IDE will call all the Register procedures in your package's units, at which time you can run whatever code you need.
Make a new package project (.dpk file).
Set project preferences so it's a design-time package.
Add a new, blank unit to it.
Add a procedure to the interface section named Register. It must have a capital R and the rest lowercase.
Implement that procedure however you want (such as by putting your call to FastcodeAddressPatch there).
Compile and install the package.
I'm a little wary about what it looks like you're trying to do in step 5, but I'll let you work that out for yourself.

If by "at design-time" you mean "change the way your components behave while in the Form Designer", that's something you really shouldn't be trying to do. The Form Designer is part of the IDE, which is all Delphi code being run in BDS.exe. If you alter TObject under the Form Designer, you alter it for the entire IDE, with potentially disastrous results.

Related

Referencing a type from a package library in Delphi

I have inherited a legacy Delphi project for which I have to do a code modification. But to start with, I have problem compiling the project into a "correct" application. As I am not familiar with Delphi, I am not sure what is missing.
So far, the only changes I have done are around PATH for references and packages wherever I could find an absolute path that was different on my PC. It is compiling and running. However, one of the variable remains "incorrectly" initialized at run-time (value is nil). I am a bit surprised because I have not changed anything in the code, that is from an application otherwise running.
The type of this variable is defined in a package library (for which I have the code as well, that compiles, and that is in the list of "Packages" checked in the Project Options.
Some code sample:
Unit Unit3
interface
uses
VCLZ;
TFrmCCB = class(TForm)
vz: TVCLZ;
implementation
procedure TFrmCCB.FormCreate(Sender: TObject)
var
[...]
begin
vz.SetPath := 'C:\'; //at this point vz is nil
Do I have to add some code to get vz to not be nil, or does it look like a configuration problem with the definition not found at run time or something like that? I would seem strange that something is missing in the code though, as I have not done any change there yet and the program is otherwise running.
It sounds like vz: TVCLZ is a component on a form.
When you first open the form if you don't have the component (package) installed in the IDE it asks you if you want to remove the component (because the IDE doesn't know how to render/instantiate it at design-time). If you choose to remove it the code associated with that component remains.
So you remain with something similar to what you have. The form doesn't create the component at run-time (because it doesn't have it anymore) the vz member remains uninitialized.
So, you have to get the sources of the project with the component on the form and be careful not to delete it.
Or, you care create the instance yourself. At FormCreate just create it: vz := TVCLZ.Create(Self); before you use it. But keep in mind that all the properties set in design will be lost and you have to set them manually in code.

How to keep the generated TLB file neat?

Hi I use interop to call C# code in Delphi.
C# code has a binary and in Delphi 5 Menu: Project-->Import Type Library
Click Add to add the tlb file: XXXX.tlb
Unit dir name: input the path where the delphi XXX_TLB.pas file is generated.
If the C# dll, tlb and delphi XXX_TLB.pas has already been there. Now I add one more function in C# code and hope Delphi can call this function as well. I need to recompile c# and regenerate delphi XXX_TLB.pas file. But by following the above steps, I see the newly generated XXX_TLB.pas includes my newly added function, but looks like the functions order in XXX_TLB.pas is totally different from before.
For example, in my C# binary I have function:
func1();
func2();
func3();
func4();//newly added
In the old XXX_TLB.pas, the function order is:
func1();
func2();
func3();
Now XXX_TLB.pas is like this:
func1();
func3();
func4();
func2();
The XXX_TLB.pas can still be used, looks like no functionality difference, but when I check in to tfs, I see it changes a lot from pervious version. Is there a way to keep this new XXX_TLB.pas the same order as before but add my function as well? How to do that? Thanks!
You cannot hope to keep the changes to a minimum unless you start writing the .pas file yourself. That sounds like a worse option.
Probably what is happening is that you have changed version of either one of your compilers since the last time you imported. Otherwise one would expect minimal differences.
Just check it in with a comment stating which versions of compiler and .ocx/.dll were used.
You can't, as far as I know.
I most cases, I'm able to consider them as a sort of "black box" anyway, and only occasionally have to peek in them to find a specific declaration.

How to filter Delphi 2010 compiler output (hints)?

I'm trying to get rid of some hints(*) the Delphi compiler emits. Browsing through the ToolsAPI I see a IOTAToolsFilter that looks like it might help me accomplish this through it's Notifier, but I'm not sure how to invoke this (through what xxxServices I can access the filter).
Can anyone tell me if I´m on the right track here? Thanks!
(*) In particular, H2365 about overridden methods not matching the case of the parent. Not so nice when you have about 5 million lines of active code with a slightly different code convention than Embarcadero's. We've been working without hints for months now, and we kinda miss 'm. :-)
Even if you could query BorlandIDEServices for IOTAToolsFilter, that interface isn't going to help you do what you're asking. That interface was introduced as part of a mechanism for adding additional build tools (compilers, etc.) to the IDE (before the IDE used MSBuild). It allowed you to write a custom "filter" to handle output from a particular build tool, but it would not let you apply a filter to one of the built-in tools (like the delphi compiler).
The reason the Supports(BorlandIDEServices, IOTAToolsFilter, OTAToolsFilter) call fails in Delphi2010 is that once MSBuild support was added to the IDE, the old way of adding build tools to the IDE was disabled, and the BorlandIDEServices interface no longer supported IOTAToolsFilter.
The declaration of IOTAToolsFilter should probably have been marked deprecated in ToolsAPI.pas (or least it should have been mentioned in the source code comment that it is no longer supported).
As far as your desire to filter a particular hint, I'm not aware of a way to do that via the ToolsAPI. It seems like a reasonable thing that can be added to IOTAMessageServices (the ability to enumerate, filter, and possibly change the messages in the IDE's Message View). I would enter a request in QualityCentral for that.
Also, please vote for QC #35774 (http://qc.embarcadero.com/wc/qcmain.aspx?d=35774), as if that were implemented, you would not need to use the ToolsAPI for this sort of thing.
According to http://docwiki.embarcadero.com/RADStudio/en/Obtaining_Tools_API_Services it should be possible to access it directly using BorlandIDEServices, eg:
var
OTAToolsFilter: IOTAToolsFilter;
begin
if Supports(BorlandIDEServices, IOTAToolsFilter, OTAToolsFilter) then
ShowMessage('supports IOTAToolsFilter')
else
ShowMessage('IOTAToolsFilter NOT supported');
end;
However this doesn't return the desired interface in Delphi 2010 (you'll get the not supported message), so there's either an error in the documentation, or an error in BorlandIDEServices not returning the correct interface.

Delphi: Prevent method names from appearing in executables

I am writing a class to handle security in my executable (checking serials, trial date check etc). After I compile the executable (even in Release build, with all debug and RTTI generation turned off), when I open it in NotePad and search the method name in the raw data, I can see all the names of the methods that assemble my class. There are no published members in any class in the code base.
This is bad for protection. Is there any way to tell Delphi not to store method names in the executable ? Why is it storing them at all if there is no RTTI needed and no COM explosion? Is there any compiler option controlling this?
It may be that ANY method of ANY class in the target executable is stored inside the executable in text form. Apparently this is caused by the extended RTTI being turned on by default for all classes in Delphi 2010.
If you are asking about the extended RTTI in Delphi 2010, it can be switched off by
{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}
see also docwiki.
Also strip relocations, take up the following in the project's dpr file:
{$IFDEF RELEASE}
// Leave out Relocation Table in Release version
{$SetPEFlags IMAGE_FILE_RELOCS_STRIPPED}
{$ENDIF RELEASE}
... and don't forget to turn off "td 32 debug info" (in older versions) or debug info in the linker tab in later ones.
What you probably will see is your form definition as a resource (eg the binary represetation of the DFM files of your project).
If you don't want to show these (for the serial info screen etc) you shouldcreate these forms "in code". Eg create a TForm, place a TButton and TEdit onto it, attach the event handlers in code.
To do this in a handly way: start with a form and create the DFM. When vieing the form, choose View as text from the context menu and you will know what things you should copy into code. And make sure NOT to place any varaiablerefernces under de published (always put public/protected/private as the first line within your class definition.

Replace function units

I am writing a unit test infrastructure for a large Delphi code base. I would like to link calls to pure functions in SysUtils.FileExists for example to a "MockSysUtils.FileExists" instead.
Creating a SysUtils unit with the same interface is not appreciated by the compiler.
What I am thinking of is to hook in my mock function at runtime. Is this possible nowadays?
Any other suggestions?
Regards,
Peter
Replacing a function at runtime is difficult but usually technically possible. "All" you need to do is:
take the address of the function in question
disassemble the first 5 bytes or so (to check for a RET instruction - very small routines may abut another routine, preventing you from replacing it)
change its page protection (with VirtualProtect) to be writable
rewrite the first 5 bytes with a JMP rel32 instruction (i.e. E9 <offset-to-your-func>)
implement your version function as normal, making sure it has the same arguments and calling convention as the function you are mocking
An easier approach would be to link against a different version of SysUtils.pas. That will require you to also recompile all the units in the RTL and VCL that depend on SysUtils.pas, but it is likely quite a bit easier than the function intrumentation approach described above.
The easiest approach is the language-level one, where either you don't directly rely on SysUtils at all (and so can switch at a higher level), or you modify the uses declaration to conditionally refer to a different unit.
You can do it with MadCodeHook. Use the HookCode function, give it the address of the function you want to replace and the address of the function you want to be called instead. It will give you back a function pointer that you can use for calling the original and for unhooking afterward. In essence, it implements the middle three steps of Barry's description.
I think MadCodeHook is free for personal use. If you're looking for something freer than that, you can try to find an old version of the Tnt Unicode controls. It used the same hooking technique to inject Unicode support into some of the VCL's code. You'll need an old version because more recent releases aren't free anymore. Find the OverwriteProcedure function in TntSystem.pas, which is also where you'll find examples of how to use it.
Code-hooking is nice because it doesn't require you to recompile the RTL and VCL, and it doesn't involve conditional compilation to control which functions are in scope. You can hook the code from your unit-test setup procedure, and the original code will never know the difference. It will think it's calling the original FileExists function (because it is), but when it gets there, it will immediately jump to your mocked version instead.
You could also just add a unit that only contains the functions you want to mock to the test unit's uses clause. Delphi will always use the function from the unit that is listed last. Unfortunately this would require you to change the unit you want to test.
Your Mock-Sysutils unit:
unit MockSysutils;
interface
function FileExists(...) ...
...
end.
Your unit, you want to test:
unit UnitTotest;
interface
uses
Sysutils,
MockSysUtils;
...
if FileExists(...) then
FileExists will now call the version from MockSysutils rather than from Sysutils.
Thanks,
yes, it would be great to have TSysUtils class for example instead that I could inherit with my MockSysUtils. But, that is not the case and the code base huge. It will be replaced bit by bit, but I wondered if there was a quick-start solution.
The first approach is ok for one function perhaps, but not in this case I guess.
I will go for the second approach.
This is slightly way out there but here is another alternative.
When building your unit tests and your main codebase to go with it, you could grep all the functions you wish to replace and specify the unit to use
Instead of
fileexists(MyFilename);
you could grep fileexists and replace with
MockTests.fileexists(MyFileName);
If you did this at build time (using automated build tools) it could easily be done and would provide you with the greatest flexibility. You could simply have a config file that listed all the functions to be replaced.

Resources