How to treat non design component initialization errors? - delphi

For start, lets take an exemplification:
You create a new VCL application project in Delphi and put a TIBDataBase and type in the path and name of the database file with the extension .IB ok?
Now, If you you just put example.ib and leave the path behind, when you execute your application without Delphi, it will open the database normally if the .EXE is in the same path as the .IB but if you run your application from Delphi, it will raise an error because it can't find the database file, because Delphi changes the working directory.
Sometimes you want to leave the Active property of that component set to True while you are developing, and them set to False and change it during the start of the application, when you deliver to your client. All that because he/she may want to install in a different path and your application has to find the proper place of the database before open it.
The problem comes when you already delivered to your client and still make some changes everyday on the code. You then have to deploy at least once a day, and sometime you just forget to set that property back to False and when the client receives the update and tries to run it, he/she gets a not found database error.
The question is, how can I handle that error if this opening happens automatically when the component is loaded in memory and the activation of the database does not happens in my own code?

I do not think you are going to find a general solution to preventing run time exceptions from design time property settings without modifying the component or deriving a descendent.
For TIBDatabase, set the property AllowStreamedConnected to False. This stops TIBDataBase from automatically connecting to the database at run time when Connected is True at design time. TIBQuery using this TIBDatabase will not open even it is set Active at design time.
Some other database connection components have similar properties.

Regarding the database issue only: if I understand you correctly, my solution requires you to write an event handler for the 'BeforeConnect' event as shown below:
procedure TDM.SQLConnection1BeforeConnect(Sender: TObject);
var
dir: string;
begin
with TRegIniFile.create (regpath) do // I keep my database locations in the registry
begin // but you can use any method of getting the location
dir:= ReadString ('firebird', progname, '');
free
end;
with sqlconnection1 do
begin
close;
params.values['database']:= dir;
loginprompt:= false;
end;
end;
This way, you can have one location stored in your database for local use, but have different locations for different users.

Related

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).

Opening Paradox database; 'PDOXUSRS.NET' workaround?

I'm writing an application that has to open a preexisting BDE database that has been saved by a third party.
In this application, I currently have a TDatabase (DriverName: STANDARD) with path set correctly in Params.
I can now set Connected to true without an error message.
There is also a TTable with DatabaseName set to the values of the TDatabase and TableName set to the .db-file that lies in the folder (the name was automatically filled in, I only hat to select it).
Now the problem:
If I set Active to true, an error message complains about missing access rights for C:\PDOXUSRS.NET.
I know I could set another path using BDEADMIN, but I need to solve this in my application - I can't expect every customer to do this change.
Furthermore, I have a test machine with the third party application running - it can access the database without any error, while my application throws the aforementioned error. This leads me to the suspicion there might be a workaround.
Is there such a workaround?
I only need read access to the database.
Solved it thanks to the link of bummi
Thank you very much.
Quote:
How to change NET DIR programmatically so it persists
[...]
You should also remember that if you have programs that change their own NET DIR locations at runtime, using either the DbiSetProp function or the NetFileDir property of a TSession component, this will override the NET DIR value in the configuration file.
It pointed me to the possibility of changing the NET DIR in code:
Session.NetFileDir := MyCustomTempDir;
After doing that, Table1.active := true works and the data shows up in a connected TDBGrid.

How do I set an attribute on an ODBC connection via DBExpress?

Justification that you might as well skip reading but is included to filter out people telling me not to do something that I'm not sure of in the first place.
I'm trying to debug some multithreaded database hoopla, it's mostly experimental although if I get it working I'd be a very happy guy. I'm very new to DBExpress (only have been using it for 4-5 hours). I'm not using TSQLConnection or any designtime components because I'm trying to rewrite an existing ODBC32.dll interface in a painless an unnoticed way and once I'm done, I'll expose the rest of the awesomeness. The reason I mention this is because it's very apparent that I'm not using dbexpress in the normal way shown in many of the tutorials.
Here's the question
I'm using the TDBXConnection and connecting to an ODBC datasource, I want to try setting the SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE parameter on my connection, but I don't have a clue where to go about setting that particular parameter.
You've got FDBConnection : TDBXConnection; defined somehwere else so now you've got to:
....
begin
if FDBConnection is TDBXOdbcConnection then
with FDBConnection as TDBXOdbcConnection do
begin
MethodTable.SQLSetEnvAttr(EnvironmentHandle, SQL_ASYNC_ENABLE, Pointer(SQL_ASYNC_ENABLE_ON), 0);
MethodTable.SQLSetEnvAttr(EnvironmentHandle, SQL_ASYNC_DBC_FUNCTIONS, Pointer(SQL_ASYNC_DBC_CAPABLE), 0);
end;
end;
That's pretty painless.
Include Data.DBXODBC and System.ODBC in the uses and you're golden.

Set file as modified using OTA

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. }

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