Set file as modified using OTA - delphi

As we know Build compiles all used units and Compile compiles only changed used units. But when you are working with ifdefs and need to change it a lot of times you must Build the project a lot of times.
If you have to much libraries that you know that this IFDEF will not change the behavior, there is no reason to build this library again.
What I want to do discovery is a way to say to the IDE that some files was changed and call the Compile and not the Build.
How to get the units and every else I know, but some know how to set the unit as modified?
Tks
Couldn't find a why to solve my problem yet. I found a way to set it as modified the problem is that it doesn't force the IDE to build it as I thought it'll.
Some one know what checks is made to an archive be sent to compile ?

Solved in a simpler way. I just deleted the DCU of the file and ok, it'll compile it again. :D
http://paste.ideaslabs.com/show/KCB9cq2Z8c

Let us assume that what you want is to mark editor buffers modified. That assumes there is an editor buffer to modify, which in most cases, there isn't, for most items in your Project. Let's suppose that you ALWAYS have every file in your project open at all times, then perhaps you can tweak those open units, this way.
My thinking is that you would actually need not only to mark editor buffers modified, but also TOUCH all the files on disk that would need to be rebuilt because of the #define change.
To know which files are affected, you would need to read all the files. I think, that the odds of you doing this reliably, over and over again, and faster than just doing a BUILD are pretty slim.
But if you did decide to go for it, you need not only to modify buffer Modified flags, but also, for any other file in the current project group, or which is in a folder included in the search or library path, find any file which might be affected.
You can see perhaps that this is more complex than you first thought.
And, as far as OTA goes, here is IOTAEditor property, Modified, it is read only.
The OTA doesn't want you changing it:
IOTAEditor = interface(IUnknown)
['{F17A7BD0-E07D-11D1-AB0B-00C04FB16FB3}']
...
function GetModified: Boolean;
..
property Modified: Boolean read GetModified;
..
end;
But you could actually modify the buffer CONTENT itself, and that would set the flag.
Use IOTAEditorContent, get the content (IStream), modify it (add a space), then modify it again (take away the space). You have now set the dirty bit (call GetModified just for luck).
I found some sample code from JCL JclStackTraceViewerStackCodeUtils.pas that shows you how to read editor content using IOTAEditorContent:
function GetFileEditorContent(const AFileName: string): IStream;
var
I: Integer;
Module: IOTAModule;
EditorContent: IOTAEditorContent;
begin
Result := nil;
Module := (BorlandIDEServices as IOTAModuleServices).FindModule(AFileName);
if Assigned(Module) then
begin
for I := 0 to Module.ModuleFileCount - 1 do
if Supports(Module.ModuleFileEditors[I], IOTAEditorContent, EditorContent) then
begin
Result := EditorContent.Content;
Break;
end;
end;
end;
After re-reading your question, it seems to me you only want to mark open editor buffers as all changed, and then do a compile, for speed. So you might want to do this: Take the code above, get the IOTAEditorContent using Supports(), and tweak each one.
Update: Short and sweet version: Modifying the buffer isn't sufficient. Plus, you won't have buffers for the files you need to change, plus Touching the file on the disk doesn't do what you want. So no, you can't do exactly what you wanted to do. And even if you could somehow modify the compiler's ability to do Make-style dependency and modification checks, you would probably cause a lot of problems inside the IDE.

On IOTAModule70 = interface(IOTAModule50) I'll find MarkModified:
Description:
{ MarkModifed will mark this module as "modified" without actually indicating
why is it modified (which will cause internal file dates to remain constant).
This will force the IDE to ask to save this module when the user attempts
to close it. It will also clear the "discardability" of a new unnamed
module such as when File|New|Application is selected. }

Related

Loading long strings at runtime and design-time

I would like to define descendants of TPath class for SVG shapes that I use regularly, to register them on the palette instead of having to paste in the object inspector long SVG path strings.
this would also have the advantage of being able to, by changing a single string somewhere, impact all my objects of type TSVGxxx without having to run after them and edit each one after the other.
The first step was done:
TSVGsomeshape = class (TPath)
and in the Loaded:
Data.Data := 'an SVG path';
The problem:
when this path gets too long, Delphi's string literal limitation forces me to break it down and concatenate its bits. Which I would like to avoid.
Resources come to mind. the idea: put all SVG paths into some RC file (simple paste of path as-is, no concatenation hassle), which in turns compiles and generates a RES file.
However, it seems that with paths being loaded as resources, I lose the ability to see those paths when dropping my TSVGxxx at design-time, which sort of defeats the purpose.
Am i over-complicating things, and is there a more simple approach to all of this?
edit 1:
In VCL, the main way of using resources was to add the {$R } rc or res file (I still prefer using the RC one and have it compiled every time, and ignore the generated res from version control).
I would consider for this a single resource file "svg.rc / res", which contains multiple text-only entries describing the path section only of each SVG.
LoadFromStream the resource into a string list, and feed it to the "Data" property, pretty straightforward.
Admittedly, I don't recall ever having done so in a control at design time. This is the first difficulty encountered using resources approach: getting "resource not found".
Is doing so at design time generally doable?
The second difficulty I suppose is more related to FMX, due to the multitude approaches to add resources (deployment menu, resources and images menu, standard {$R } approach). All of which also yielded resource not found at runtime.
I've used the Deployment menu for loading custom fonts, but not multi-key rc files.
How could this be done?
Thanks
PS: i also had a look at SKIA4Delphi, and while great, may be overkill for the simple SVG paths that I am interested in (and also a Google dependency)
Note on tags: while the question does mention SVG and TPath, the problem at its core concerns neither of them, and as such, SVG and FMX tags are omitted.
it ended up working out as per the comments above.
placed the res file in the package's directory (previously had it in search path).
pointed to the res file using {$R myres.res}
loaded the resource string as RC_DATA, not sure if i should have used plain text instead (the resource editor restricted namings to numbers when using string tables)
function TSVGPlus.LoadSVGpath: string;
var RS: TResourceStream;
SL: TSTringList;
begin
RS := TResourceStream.Create(FindClassHInstance(Self.ClassType), 'PLUS', RT_RCDATA);
SL := TStringList.Create;
try
SL.LoadFromStream(RS);
Result := SL.Text;
finally
SL.Free;
RS.Free;
end;
end;
rebuilding the package, the plus shows up at design time
no additional deployment was needed to get the plus sign showing at runtime, be it on Windows or on Android

How to append to an existing file using FireDAC

I would like to write to an existing .csv file not create a new one every time it runs. Here is the code I have so far.
with TFDBatchMoveDataSetReader.Create(FDBatchMove) do begin
DataSet:= Inventory.mInventoryCount;
Optimise:= False;
end;
with TFDBatchMoveTextWriter.Create(FDBatchMove) do
AssignFile(myFile, 'C:\Dataout.csv');
//FileName:= ExtractFilePath('C:\') + 'DataOut.csv';
Append(myfile);
FDBatchMove.Execute
You are not supposed to do writing by yourself. That's what the writer does for you. You need to just control the Mode property and the clear options of the Options option set of the TFDBatchMove to instruct the engine what the writer should do. From what you say it sounds like you are interested in the dmAlwaysInsert mode (which is default) and keeping poClearDest and poClearDestNoUndo options not included in the option set (which is default as well).
Or in other words, FireDAC will append data with no checks to the destination by default, hence the problem you've described could have happen by modifying some of the mentioned settings (or, you just misidentified the issue).

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.

Add code before initialization of units in Delphi

Is there a place where I can add code that will be executed before unit initialization?
The reason I want to do this is I need to change the DecimalSeparator, this has to be done before the initialization of some units. I have put it in the project source, before Application.Initialize but it is too late by then.
As I see it the only choice I have is to put it in the initialization of the unit that needs the DecimalSeparator to be changed, is this the case?
Thanks in advance for any advice.
Initialization order in Delphi is deterministic: units get initialized in the same order as the compiler compiled them, and finalized in the reverse order. The compiler starts at the top of the DPR's uses clause and works its way down, and for each unit it finds, it does the same thing recursively: start at the start of the uses clause, try to compile each used unit that isn't already compiled, then compile the current unit. So if you can get your unit in before any of the other ones get compiled, then it will get initialized first.
If you want to make sure it gets executed first, make a new unit, put your changes in that unit's initialization block, and then make sure it ends up in the DPR before any of the units that will depend on the changes. You might even want to make it the first unit, unless you have other "must be first" units there already, such as replacement memory managers.
Put it into the initialization section of the first unit in your project uses list, that way it will be executed prior to any other initialization code.
A word of warning here.
I've got an application running on the desktop of a logged in user and IN THE MIDDLE of testing the app the DecimalSeparator changed for me, without me restarting the application.
I used to set the
DecimalSeparator := '.';
once in the FormCreate() code, but that seems not the be enough. So now I set it once every time before I use my FormatFloat() function (used only in one place in my application).
I do not know WHY this happens, but probably there are some system-wide parameter changes happening, that reset the char to ',' on my system.
The best way to avoid this is probably to set the decimal separator in windows configuration to '.' to avoid strange problems...

Easiest way to find previous instance of an application

I have rewritten a VB6 application in Delphi. It should have only one instance running. How can I do this with minimum of code?
In VB6 we just have to use one single line of code
>
If App.PrevInstance Then
'Take some action
End If
On goggling I did find a solution but it is very length and we have to mess with .drp file.
I do not want to do that.
I want something simpler.
I have some code along the lines of:
var
AppMutex: THandle;
{ .... }
initialization
// Create the mutex
AppMutex := CreateMutex(nil, True, 'MY-APPLICATION-NAME');
if (AppMutex = 0) or (GetLastError = ERROR_ALREADY_EXISTS) then
begin
MessageDlg('My application is already running on this computer.'#13#10+
'You should close the other instance before starting a new one.',mtError,
[mbOK],0);
Halt;
end;
finalization
// Close the mutex
CloseHandle(AppMutex);
but I'm sure the answers in the thread that #mghie linked to are more helpful/richer features!
Edit: Note you can make this into a small unit in it's own right, then just use that unit in your project(s).
Note that in many cases, the user's expecation will be that launching the second instance results in the first instance being restored and brought to the foreground. Don't expect users to understand the difference between restoring a minimized/hidden app and launching from a shortcut or start menu.
In my experience one cannot decide in general wether an application my be started twice or not. It may be for instance perfectly valid to start the same application if it is started in another folder or under another user account or whatever. On the other hand it might be the case that two different applications may not run together if they are started in the same folder or so.
So besides the different approaches with mutexes and semaphores and handling race conditions, it is the wise selection of the mutex's or semaphore's name that handles the above combinations appropriately.
If an application may not run twice at all, take a GUID like name. You can even use the exe's filename if you can ignore that someone might rename it.
Restricting the one-time-start on a specific folder, you can take the exe path into account, but be aware that due to mappings different pathes may end up at the same exe.

Resources