In Delphi you write a function in 'implementation' and then you have to put that function in the 'interface' section also. Tedious but luckily there is a shortcut for that: press Ctrl+Shift+C and Delphi will automatically do it. (Well this is a bit unreliable as it only works if you are a bit lucky.... but works in MOST cases)
http://docwiki.embarcadero.com/RADStudio/Rio/en/Using_Class_Completion
C++ with its obnoxious header files makes this job even more unpleasant. But there is no Ctrl+Shift+C to help you. Can you automate this job, like in Delphi?
Related
Just upgraded from Delphi XE to Tokyo, and was hoping for some updated IDE features.
One nice to have feature would be automatically providing options to add a unit to the uses clause. For example, if you reference something in code that isn't in a uses, it would be nice if the IDE prompted you to add the related unit(s).
For example, keeping it simple, in IntelliJ, you might declare a Button, but not yet have added the associated Library to the Import clause.
When this happens, the offending line is highlighted (just like in Delphi), but the IDE will let you add the necessary library with an Alt-Enter. If there are multiple libraries (it knows about it) it will prompt you for the one you want.
Anything like this for Delphi?
Delphi 2007 and later versions support this for most types that it knows about (in the search or library path). (It may have been available in D2005/2006; I don't have them installed anywhere now to check. I know it was not in Delphi 7.)
Put in the type, and use the Refactor menu (Refactor->Find Unit) or press Ctrl+Shift+A.
Here's an example:
It's not 100% effective, but it's a vast improvement over the old way.
(And yes, I know about TArray<string>, before someone chimes in. I just grabbed a quick type that I knew wouldn't be in the default VCL form uses clause for an example.)
When you compile a DLL in Delphi XE6, it automatically exports the function TMethodImplementationIntercept from System.Rtti.pas. I tried to find a way to avoid this export but didn't find any configuration or compiler directive that could do the trick.
The System.Rtti unit is nearly impossible to avoid because it's used indirectly by almost everything in delphi.
Is there a way to avoid exporting this function when building a DLL in XE6?
The code in the System.Rtti unit looks like this:
{ This function has been added to be used from .s .c files in order to avoid use mangled names}
procedure TMethodImplementationIntercept(const obj:TMethodImplementation; AFrame: Pointer); cdecl;
begin
obj.Intercept(AFrame);
end;
exports TMethodImplementationIntercept;
This function and the exports directive, were added in XE5.
Is there a way to avoid exporting this function when building a DLL in XE6?
If your library includes the System.Rtti unit then the DLL will export that function. If you want to produce a DLL that does not export the function I can see the following options:
Use an older version of Delphi.
Don't include System.Rtti in your library.
Use a modified version of System.Rtti that does not export the function.
Modify the DLL after it has been produced to remove the function from the PE export table.
The first two options seem to me to be not very appealing. The third option seems attractive but I think it might turn out to be difficult to make work. It seems that this long standing trick no longer works. I've not yet been able to re-compile an RTL unit and avoid the dreaded X was compiled with a different version of Y error.
So that leaves the final option. Again, not massively attractive. You may well decide to just suck it up and accept this stray export. Perhaps a QC report might put a little pressure on Embarcadero to reconsider this decision.
For what it is worth, in my opinion no compiler library code should ever unconditionally export a function. It should be the consumer of the library rather than the implementer of the library that takes that decision.
http://en.wikipedia.org/wiki/REPL Read–eval–print_loop
Is there such a thing for Delphi ?
It would be rather useful to explore DLLs such as Windows APi and sketch their usage, when dealing with border cases scarcely documented.
I tried pascal scripts, such as one in Cnwizards, but it is much less comfortable.
For example it cannot use units like Windows.pas and you had to make some strange stubs of your own for it.
And anyway, those scripts are less easy to use for "try this try that" scenario than Repl.
For Delphi objects most clsoe thing it to pause on breakpoint and use Evaluate/Modify window, but it only works with Delphi objects, not DLLs; it cannot make temporary vars to cache values and such.
It's not really what you're looking for, because Delphi is a statically typed, compiled language, but if you really insist on being able to type some pascal in and see if it does anything, you can try the TJvInterpreter component that comes in the Jedi VCL.
Note that the experience is nothing like using python. You can't just type "uses module" and hit enter, because pascal units must be complete before they can even be interpreted by JvInterpreter, and the JvInterpreter needs you to write a wrapper for every single other unit you want to import. You would go crazy. I'm not seriously advising anybody to try to build a REPL around TJvInterpreter.
The "interactive magic" element of Delphi is called the "designtime environment" and the way we build using "components". We don't even do that bit by writing code much, we do it all visually with our mouse and keyboard. It's called RAD (rapid application development) and is powered by the VCL (visual component library) in Delphi, and (like REPL) is one of the many ways of doing very-rapid development.
The other thing we have that is a lot like a REPL is this button in Delphi:
You click it, after creating a new empty project, and whatever code you added to your new empty project is built and running in less than a second. Close enough to a REPL for me. It's kind of like binary executable instant bliss.
Write one line. Build and run (1 second). Instant.
To maintain its project, Delphi sometimes adds or removes stuff from the DPR file (project source). I quite like to format my stuff in the DPR as if it is an ordinary unit, for example to group together the 'used' frame references and project source files. I make copies of it and can go back when this happens but every so often, I'll notice that the DPR has had all its source file references smashed into a single block.
Anyone else suffer from this? Is there any way of preventing this from happening (other than a read-only file).
Thanks
What I do for most of my projects is to have these 2 files:
MyProgram.dpr
MyProgramUnit.pas
MyProgramUnit has a public method Main that contains all the logic from the .dpr (including any conditional defines)
MyProgram just calls Main.
Edit 1:
You can put uses lists in MyProgramUnit.pas, but they don't automatically become part of your project.
That might or might not be an issue, it depends if you like having Delphi finding units in a search path, or add files to your project to make them visible.
What you can do, is to document the uses-lists in MyProgramUnit.pas and group them by cause. This is what I normally do in most units anyway, not only in the main unit.
Edit 2:
Don't go the {$I MyIncludeFile.inc} way.
Delphi - especially the IDE - is bad with include files. Code Completion, etc, fail at irregular places.
I've been heavy on include files in the past; not so any more. I even stopped using them for defines, and moved from {$IFDEF define} ... {$ENDIF} towards {$IF Constant1 >= Constant2} ... {$IFEND}.
The .dpr is a normal Delphi file, alright, but once it is opened in the IDE, it is more or less "owned" by the IDE. There is no way to stop the IDE from adding or removing code from it, when the IDE thinks that is necessary (e.g. when you added a unit, changed some settings, etc.). That can also mean it reformats parts of the code.
If you want "immutable" code, put it in a unit.
I think Rudy's got this one right.
IMO, it's wiser to keep hands off the dpr uses block in the editor - the project manager is designed to do that - by hand you're liable to corrupt your project settings and introduce some hard to track down bugs in large projects. As for formatting, in Delphi XE there is autoformat that will do your whole project and is configurable.
I often edit the 'program' section of the dpr (that also requires some knowledge and caution) but not the uses block.
One additional point: some of what happens in the dpr can be controlled from your project options settings.
HTH
Personally I make a copy of my uses clause in a giant comment at end of my DPR file.
So when Delphi modifies it, I "restore" it from the comment.
Of Course I have to be cautious of maintaining my "uses comment" up to date.
Note :
I'm using external tools that scan the project file so I cannot use the "external unit" approach, although it seems the cleanest solution.
Following up on this question, I'm working on a large Delphi 7 codebase which was not written very nicely.
I'm looking at code like this, as a small example:
if FMode=mdCredit then begin
Panel8.Caption:='Credit';
SpeedButton3.Enabled:=false;
SpeedButton4.Enabled:=false;
SpeedButton5.Enabled:=false;
SpeedButton5.Enabled:=false;
SpeedButton6.Visible:=False;
SpeedButton10.Visible:=False;
end;
Followed by another 6 very similar blocks. The whole thing is in this style.
So I'm thinking that this would be much easier to read if the controls were named sensibly.
I could just use a global search and replace, but I'll run into problems when multiple forms use the same names, and also I'd have to be careful to change (eg) SpeedButton10 before SpeedButton1.
Is there some plugin which has the ability to perform a "smart" rename for me?
Edit:
Sorry, I should have mentioned this before: I tried both GExperts and Castalia's "Rename Component" feature, but they both seem to be intended for use when adding the component to the form initially.
They don't do a search+replace in the code, or rename existing events (SpeedButtonXClick() -> cmdCreditClick()).
Have I missed something?
Not exactly a plug-in, but you can use one of the more recent versions of Delphi and the refactoring feature in there. Maybe you could use the free Turbo Edition . . .
You might try ModelMaker for Delphi 7. It has refactoring support that might work for you.
The Rename Symbol refactoring in recent Delphi versions will work across units in a project. Since you say Delphi 7 I guess that's not going to help you, and in the past I've just used TextPad, a great editor that (like many others) will do powerful search/replace across files (with or without confirmation).
HTH
Edit: Craig's right - GExperts will do this, as will Castalia.
I think GExperts has a search and replace like this.
Don't know if it can work in your case, but you could try to load your project in a later version of Delphi that has the refactoring capability and use it to change the components names while taking care of all the dependencies. Then you just have to do a diff and see what has been changed.
Why not use Sync Edit? Its part of the IDE (at least in 2006+):
The Sync Edit feature lets you simultaneously edit indentical identifiers in selected code. For example, in a procedure that contains three occurrences of label1, you can edit just the first occurrence and all the other occurrences will change automatically.
(copied from the BDS2006 Help)
You will have to rename your components first, but it takes the pain out of most of this. I prefer the GExperts wizard of renaming components as they are added to the form, but as you pointed out, it only works when the component is added to the form, and doesn't reach into the individual usages of the components in code. The reason for the renaming of the components first is that when you select the entire block of code to do the rename, it won't make the appropriate changes in the dfm file...just your locally selected code block.
To use the feature, select your entire implementation block, then press the button in the gutter that has two pencils "linked" by a line...then press tab until you get the first one you want to edit...when you change its name, it will change globally in the rest of your source file. Press ESC when your done.