Database Reverse Engineering - Felix John COLIBRI. |
- abstract : This project rebuilds the schema of a Database by analyzing all the .DFMs of the project
- key words : Database, Schema, .DFM, parser, reverse engineering
- software used : Windows XP, Delphi 6
- hardware used : Pentium 1.400Mhz, 256 M memory, 140 G hard disc
- scope : Delphi 1 to 2005 for Windows, Kylix
- level : Delphi developer
- plan :
1 - Introduction
One of our customers wanted to upgrade a previous project where the Database was build over the years. There was no Entity Relation diagram or other document presenting the structure of the Tables.
To recover or build from an existing application the schema, we basically have 3 options: - analyze the data, by querying the Server
- analyze the SQL Scripts which were used to create the Base
- analyze the programs which manipulate the Base
The first alternative is the best, since it is exhaustive. If some table exist at all, they must be in the files somewhere.
The second only work if some Scripts were used, and if they present a good coverage of all the tables. We all know that in Delphi, we can build Tables by code, and this would not be in any Sql Script.
The third is also an imperfect solution, since the Delphi application may not manipulate all the tables in the Base. You can analyze the Delphi source code, looking for the tDataSet and tField descendents. This solution can also be
used when you do not have the source code, and not the Database files: you can extract the .DFM from the .EXE (since the .DFM is a Windows Resource), and from this .DFM you can recover some information on the tables. We will now examine
how this can be done.
2 - The Delphi Dfm Parser 2.1 - Assumptions We assume that we have the source code of an application, with many forms. The
projects then contains .DFM files corresponding to the Forms and DataModules. Those DFMs contain the tDataSet and tField names and types, as well as the static SQL requests.
We will use our .DFM parser. We therefore also assume that the .DFM are in TEXT format. If they are in binary format, you can:
- either use the Delphi IDE and use the "save as txt" menu option from the Form's contextual menu
- or use the CONVERT.EXE located in the Delphi BIN folder directly from the
command line or by using our .DFM binary to txt utility.
2.2 - The .DFM content
To understand what can be gleaned from the .DFM, let us build a simple tForm with at tTable and a tIbQuery. This sample tForm contained:
- a tTable linked to DBDEMO and with a TableName set to "ANIMALS.DBF", and all the persistent fields were created
- a tIbQuery:
- we dropped a tIbDataBase, connected it to EMPLOYEE.GDB
- we dropped a tIbTransaction and connected it to the tIbDatabase
- we dropped a tIbQuery, connected it to the tIbDatabase, and set the SQL request to "SELECT * FROM CUSTOMER", and created the persistent fields
The whole unit sample.pas (but not the EMPLOYEE.GDB base) is in the _data folder, and in the attached .ZIP. Here is the content of the corresponding .DFM (partial):
object Form1: TForm1
Left = 272 ... object Table1: TTable
DatabaseName = 'DBDEMOS' TableName = 'animals.dbf'
Left = 16 Top = 8
object Table1NAME: TStringField
FieldName = 'NAME' Size = 10
end object Table1SIZE: TSmallintField
FieldName = 'SIZE' end ...
end object IBDatabase1: TIBDatabase
Connected = True DatabaseName = '..\employee.gdb'
Params.Strings = ( 'user_name=SYSDBA'
'password=masterkey') LoginPrompt = False
DefaultTransaction = IBTransaction1 ... end
object IBTransaction1: TIBTransaction Active = True
DefaultDatabase = IBDatabase1 AutoStopAction = saNone ...
end object IBQuery1: TIBQuery
Database = IBDatabase1 Transaction = IBTransaction1
BufferChunks = 1000 CachedUpdates = False
SQL.Strings = (
'select * from CUSTOMER') Left = 120
Top = 8 object IBQuery1CUST_NO: TIntegerField
FieldName = 'CUST_NO'
Origin = 'CUSTOMER.CUST_NO'
Required = True end
object IBQuery1CUSTOMER: TIBStringField
FieldName = 'CUSTOMER'
Origin = 'CUSTOMER.CUSTOMER'
Required = True Size = 25
end ... end end |
A quick analysis tells us that: - for the tTable
- the tTable.TableName contains the Server Table name
- the tFields are nested within the tTable, and each tField contains the
column name, the Delphi type and additional parameters (like Size)
- for the tIbQuery:
- the tIbQuery.SQL.Strings contains the request
- the Table name is nested in the SQL request (in the FROM clause)
- there are some additional field types, like tIbStringField
2.3 - The extraction strategy
When we analyze a project, the tDataSet descendents might be scattered in several tForms and tDataModules. We cannot hope to find all the information in a single .DFM. In addition:
- several tTable components might reference the same Table
- for the tQueries, the Table name is hidden (in the SQL) and the request might even correspond to several tables (a join)
To extract all possible information on each Table, we must sort the information by Table name. The analyzer works like this: - all the .DFM in a path are parsed
- for each .DFM
- the complete c_dfm_object tree is built
- the tree is then analyzed to find tDataSet components
- for each tDataSet component, the key is extracted:
- tTable.TableName
- tQuery.SQL.Strings
- all the tFields corresponding to this key are added in an object with this key
2.4 - The tDataSet list To collect the information on each Table, we use a simple list structure. For
each c_dataset cell: - the key is the tTable.TableName or tQuery.SQL.Strings
- the fields are saved in a list of c_fields, containing each the name of the
column and its type and parameters, if any.
For instance, the result of our tool on the sample form is:
animals.dbf
NAME ftString 10
SIZE ftSmallint 0
WEIGHT ftSmallint 0
AREA ftString 0
BMP ftBlob 0
select * from CUSTOMER
CUST_NO ftInteger 0
CUSTOMER ftUnknown 0
CONTACT_FIRST ftUnknown 0
CONTACT_LAST ftUnknown 0
PHONE_NO ftUnknown 0
ADDRESS_LINE1 ftUnknown 0
ADDRESS_LINE2 ftUnknown 0
CITY ftUnknown 0
STATE_PROVINCE ftUnknown 0
COUNTRY ftUnknown 0
POSTAL_CODE ftUnknown 0
ON_HOLD ftUnknown 0
|
2.5 - Table Relationships In addition to the extraction of all Tables with their columns, it certainly would be interesting to find all links between tables.
This is embodied in Delphi Master / Detail relationships. Basically there are 2 techniques to link 2 Tables: - for tTables
- the tDetailTable.MasterSource property contains the MasterDataSource value
- the tDetailTable.MasterFields property contains a semi-colon separated list of the linking fields
- for tQueries:
- the tDetailQuery.DataSource property contains the MasterDataSource
value
- the tDetailQuery.SQL contains a parametrized query specifying which columns are used for the linking fields
Using the MastApp project from DbDemo, we have built a small tForm with both
kinds of Master Detail links:
Here is the corresponding .DFM:
object Form1: TForm1 Left = 275 ...
object Table1: TTable DatabaseName = 'DBDEMOS'
TableName = 'orders.db' ... end
object DataSource1: TDataSource DataSet = Table1
... end object Table2: TTable
DatabaseName = 'DBDEMOS' IndexFieldNames = 'OrderNo'
MasterFields = 'OrderNo' MasterSource = DataSource1
TableName = 'items.db' ... end
object Query1: TQuery DatabaseName = 'DBDEMOS'
DataSource = DataSource1 SQL.Strings = (
'SELECT *' ' FROM "ITEMS.DB"'
' WHERE OrderNo= :OrderNo') ... end
... end |
Notice that - for the tTable detail
- for the tDetailTable "Table2", the MasterDataSource value points to "DataSource1", and this tDataSource.DataSet points to the master tTable: "Table1"
- the tDetailTable.IndexFieldNames "OrderNo" and tDetailTable.MasterFields "OrderNo" tell us which are the linked columns
- for tQueries:
- for the tDetailQuery "Query1", the DataSource property points to "DataSource1", and this tDataSource.DataSet points to the master tTable: "Table1"
- the tDetailQuery.SQL contains the parametrized query with both link colums ("OrderNo" for "Items.Db" and ":OrderNo" for the master)
To recover the link: - we have to go thru the masterSource:
tDetailDataset -> tMasterDataSource -> tMasterDataSet - we have to transform the link into Table links. All .Dfm links use the component names:
"Table2" -> "DataSource1"-> "Table1" and NOT "Items.Db" -> -> "Orders.Db" This causes a problem, since when we analyze several tForms, the key we are
using for each c_dataset is the Table name ("Orders.Db"), which might correspond to several tTable.Names ("SortOrdersByDate", "Orders", "Table15" "FindMaxOrderNumber" etc).
Therefore the link analysis must be performed on a form by form basis, temporarily attaching the list of tDataSet names to each c_dataset in order to find the master detail links.
2.6 - The c_dataset list
The structure has the following requirements: - it is a list of c_dataset
- each c_dataset
- has as key either the Table name (ORDERS.DB) or the Sql request (SELECT * FROM "orders.db")
- contains a list of c_field, each field having a name, a tFieldType and some parameters
- contains a list of tDataSet.Name used to find the master detail links during a single .DFM analysis
- has a possible c_master_dataset_ref link and the link column names
So this is simply a double list (a list of lists). As usual, we use our tStringList encapsulation to generate this class combination.
Here are the CLASS definitions: c_field= // one "field"
Class(c_basic_object)
// -- m_name:
m_field_type: tFieldType;
m_field_size: Integer;
Constructor create_field(p_name: String;
p_field_type: tFieldType; p_field_size: Integer);
function f_display_field: String;
Destructor Destroy; Override;
end; // c_field
c_dataset_list= Class; // forwar
c_dataset= // one "dataset"
Class(c_basic_object)
// -- m_name: the Server NAME or the SQL request
m_c_parent_dataset_list: c_dataset_list;
m_c_field_list: tStringList;
// -- a list, since one server Table can be references by
// -- several tDatasets in a tForm
m_c_component_name_list: tStringList;
// -- Master / Detail
m_master_datasource: String;
m_c_master_dataset_ref: c_dataset;
m_did_resolve: Boolean;
Constructor create_dataset(p_name: String;
p_c_parent_dataset_list: c_dataset_list);
function f_c_self: c_dataset;
function f_display_dataset: String;
function f_field_count: Integer;
function f_c_field(p_field_index: Integer): c_field;
function f_index_of(p_field_name: String): Integer;
function f_c_find_by_field(p_field_name: String): c_field;
procedure add_field(p_field_name: String; p_c_element: c_field);
function f_c_add_field(p_field_name: String;
p_field_type: tFieldType; p_field_size: Integer): c_field;
function f_c_add_unique_field(p_field_name: String;
p_field_type: tFieldType; p_field_size: Integer): c_field;
procedure display_field_list;
procedure display_detailed_dataset_fields;
procedure display_detailed_dataset; Virtual;
Destructor Destroy; Override;
end; // c_dataset
c_dataset_list= // "dataset" list
Class(c_basic_object)
m_c_dataset_list: tStringList;
Constructor create_dataset_list(p_name: String);
function f_dataset_count: Integer;
function f_c_dataset(p_dataset_index: Integer): c_dataset;
function f_index_of(p_dataset_index: String): Integer;
function f_c_find_by_dataset(p_dataset_index: String): c_dataset;
function f_c_find_by_dataset_component_name(p_dataset_component_name: String): c_dataset;
procedure add_dataset(p_dataset_index: String; p_c_dataset: c_dataset);
function f_c_add_dataset(p_dataset_index: String): c_dataset;
function f_c_add_unique_dataset(p_dataset_index: String): c_dataset;
procedure display_dataset_list;
procedure display_detailed_dataset_list;
procedure extract_sql(p_full_file_name: String);
Destructor Destroy; Override;
end; // c_dataset_list |
The c_dataset CLASS has two descendent, a c_dataset_table and a c_dataset_query. This allows to adapt the differences in the tDataSet types.
2.7 - The extraction
To fill the c_dataset list, we parse the .DFM, which yields a c_dfm_object tree. We have created a separate CLASS which takes this tree and extracts the tDataSet part:
- the definition of the c_analyze_db class is :
c_analyze_db= class(c_basic_object)
m_c_dataset_list_ref: c_dataset_list;
Constructor create_analyze_db(p_name: String);
procedure analyze(p_c_dfm_object: c_dfm_object);
end; // c_analyze_db |
- the method which adds c_dataset elements is:
procedure c_analyze_db.analyze(p_c_dfm_object: c_dfm_object);
// ... begin // analyze
analyze_recursive(0, p_c_dfm_object); resolve_master_detail;
end; // analyze | - and here we show how we fill the tTable part:
procedure analyze_recursive(p_level: Integer; p_c_dfm_object: c_dfm_object);
procedure add_fields(p_c_dfm_object_list: c_dfm_object_list; p_c_dataset: c_dataset);
var l_dfm_object_index: Integer;
l_field_type: tFieldType; begin
with p_c_dfm_object_list do
for l_dfm_object_index:= 0 to f_dfm_object_count- 1 do
with f_c_dfm_object(l_dfm_object_index) do
begin
l_field_type:= f_field_type_name_to_field_type(m_name);
if l_field_type in [ftString]
then p_c_dataset.f_c_add_unique_field(
f_find_property_value('FieldName'),
l_field_type,
f_string_to_integer(f_find_property_value('Size')))
else p_c_dataset.f_c_add_unique_field(
f_find_property_value('FieldName'),
l_field_type, 0);
end; end; // add_fields
procedure analyze_table; var // l_property_index: Integer;
l_table_name: String;
l_index_of_table: Integer;
l_c_dataset_table: c_dataset_table; begin
with p_c_dfm_object do begin
l_table_name:= f_find_property_value('TableName');
if l_table_name<> ''
then begin
l_index_of_table:= m_c_dataset_list_ref.f_index_of(l_table_name);
if l_index_of_table< 0
then begin
l_c_dataset_table:= c_dataset_table.create_dataset_table(l_table_name,
m_c_dataset_list_ref);
m_c_dataset_list_ref.add_dataset(l_table_name, l_c_dataset_table);
end
else l_c_dataset_table:= c_dataset_table(m_c_dataset_list_ref.f_c_dataset(l_index_of_table));
l_c_dataset_table.m_c_component_name_list.Add(m_object_name);
// -- check whether "DataSource"
l_c_dataset_table.m_master_datasource:= f_find_property_value('MasterSource');
l_c_dataset_table.m_masterfields:= f_find_property_value('MasterFields');
add_fields(m_c_dfm_object_list, l_c_dataset_table);
end
else display(' NO_TABLE_NAME');
end; // with p_c_dfm_object
end; // analyze_table procedure analyze_query;
begin // ...
end; // analyze_query procedure recurse;
begin // ...
end; // recurse begin // analyze_recursive
with p_c_dfm_object do begin
if (LowerCase(m_name)= 'ttable') or (m_name= 'TIBTable')
then analyze_table else
if (m_name= 'TQuery') or (LowerCase(m_name)= 'tibquery')
then analyze_query
else recurse;
end; // with p_c_dfm_object end; // analyze_recursive |
- and the method which finds the Master Detail links:
procedure resolve_master_detail;
// -- if a tTable or tQuery reference a datasource, find its associated tDataset
var l_dataset_index: Integer;
l_c_dfm_datasource: c_dfm_object;
l_master_dataset: String;
l_c_dfm_master_dataset: c_dfm_object;
l_dataset_name: String; begin
with m_c_dataset_list_ref do
for l_dataset_index:= 0 to f_dataset_count- 1 do
with f_c_dataset(l_dataset_index) do
if m_master_datasource<> ''
then begin
if not m_did_resolve
then begin
// -- search this tDataSource in the .DFM
with p_c_dfm_object do
begin
l_c_dfm_datasource:= m_c_dfm_object_list.f_c_find_by_dfm_object_name(m_master_datasource);
if l_c_dfm_datasource<> Nil
then begin
// -- get the "DataSet" property value
l_master_dataset:= l_c_dfm_datasource.f_find_property_value('DataSet');
// -- now find the Master Dataset
l_c_dfm_master_dataset:=
m_c_dfm_object_list.f_c_find_by_dfm_object_name(l_master_dataset);
if l_c_dfm_master_dataset<> Nil
then begin
l_dataset_name:= l_c_dfm_master_dataset.m_object_name;
m_c_master_dataset_ref:=
m_c_dataset_list_ref.f_c_find_by_dataset_component_name(l_dataset_name);
end;
end;
end;
// -- do not try to resolve in another form
m_did_resolve:= True;
end;
end; end; // resolve_master_detail |
2.8 - The project Here is a snapshot of the main form:
2.9 - Mini Manual To achieve the previous result:
| copy the DataMod.Dfm from the Mastapp demo project (in Program Files\Borland\Delphi\demos\db\) or any other .DFM containing some tDatasets. |
| click Datamod.Dfm in the fFileListBox. | | this parses the .Dfm.
| | you may visualize the c_dfm_object tree by clicking on "display_object_tree_" |
| now the interesting part: to create and fill the c_dataset list, click on "extract_" | |
the c_dataset list is filled using the last c_dfm_object tree | | to view the extracted datasets - click "display_list_".
- check "Fields_" before the list if you wish to see all the fields
| | to view only the Sql requests, click "extract_sql_" |
To extract the Table content from a complete project, all the .DFMs have to be visisted. And the analysis must be performed after each visit. To do that: |
navigate to the directory where the .DFMs are located | | check "extract__" |
| click "all_dir_" or "all_dir_recursive_" | |
display with "display_list_" or extract the SQL with "extract_sql_" |
2.10 - Schema display Using the results from the extraction on the MastApp tDataModule, and manually
separating the tTable and the tQueries, we obtained the following results: - for the tTable (without the detail of the fields):
NEXTCUST =NextCust PARTS =Parts VENDORS =Vendors ORDERS =Orders OrdByCust
^CustMasterSrc -> CUSTOMER[CustNo] CUSTOMER =CustByOrd Cust CustByComp ITEMS =Items
^OrdersSource -> ORDERS[OrderNo] NEXTORD =NextOrd EMPLOYEE =Emps |
- for the tQueries (showing only the Sql requests):
SELECT *
FROM parts WHERE (parts.OnOrder > parts.OnHand)
SELECT MAX (ItemNo) FROM Items
WHERE OrderNo = :OrderNo SELECT Customer.CustNo, Customer.Company, Customer.LastInvoiceDate, Customer.Phone
FROM customer WHERE (customer.LastInvoiceDate >= :FromDate)
AND (customer.LastInvoiceDate <= :ToDate) SELECT *
FROM customer ORDER BY LastInvoiceDate DESCENDING
SELECT * FROM orders WHERE (SaleDate >= :FromDate)
AND (SaleDate <= :ToDate) ORDER BY SaleDate
|
A quick analysis shows the following Master / Detail relations ships - Customer -> Orders
- Items -> Orders
There is no trace in the .Dfm about any Items / Parts, or the Employee / Orders link. Anyway we can produce a simple diagram showing the Tables used by MastApp:
Note that this diagram could be automatically constructed using the extracted information and a topological sort (cf Niklaus WIRTH) on the Master / Detail relations.
2.11 - What is Missing ? Our tool is limited in several ways:
- we have limited our extraction to some tDataSet descendents: tTable, tQuery and tIbQuery. You can easily add other if they need special handling
- similarily we only handled some tFieldTypes, and did not spend much time on examining the different parameter types. For instance the tIbStringField is not recognized
- other valuable informations about tDataSets could be extracted: constraints, indexes etc
- the tQuery tDataSets could add some information to the Tables, but this
would require analyzing the detail of the SQL request (which table, which columns etc). It so happened that after launching the tool on our customer's project, no significant information could be gained from such information
(like in the above MastApp example). So we did not make any development in this area
In addition, Database Schema extraction using on the .DFMs only relies on many
assumptions, and if they are wrong, the whole approach will be quite partial. What could we miss using this technique ? - first of all, the Delphi project we are analyzing might only manipulate a small part of the Tables of a Base
- and for each Table, only the fields relevant to the Delphi Project are analyzed. Some other fields might be present in the Tables.
- the extraction depends on PERSISTENT fields. If the programmer used hard
code access (tDataSet.Fields[n] or tDataSet.FieldByName('xxx')) this will not be extracted. A much more difficult .PAS extraction would be required. The same is true if the programmer created dynamic tables
(tTable.CreateTable)
- the .DFM also converts all field formats into a Delphi common format. For instance, the numeric type are handled by Delphi with tIntegerField,
tFloatFields etc, but the Server might have native numeric types which do not exactly match the Delphi types. This is the case, for instance, for xBase files. The same goes with Booleans or Dates, which are not present in
all Database native types.
However most Sql Server engines (Oracle, Sql Server, Interbase) now all use 16 bit, 32 bit integers, single and double floats, strings of some
kinds, and normalized dates, which all are faithfully represented by Delphi field types. So using only the Delphi field types is not that risky.
3 - Download the Sources
Here are the source code files:
Those .ZIP files contain: - the main program (.DPR, .DOF, .RES), the main form (.PAS, .DFM), and any
other auxiliary form
- any .TXT for parameters
- all units (.PAS) for units
Those .ZIP - are self-contained: you will not need any other product (unless expressly mentioned).
- can be used from any folder (the pathes are RELATIVE)
- will not modify your PC in any way beyond the path where you placed the .ZIP (no registry changes, no path creation etc).
To use the .ZIP:
- create or select any folder of your choice
- unzip the downloaded file
- using Delphi, compile and execute
To remove the .ZIP simply delete the folder.
As usual:
- please tell us at fcolibri@felix-colibri.com if you found some errors, mistakes, bugs, broken links or had some problem downloading the file. Resulting corrections will
be helpful for other readers
- we welcome any comment, criticism, enhancement, other sources or reference suggestion. Just send an e-mail to fcolibri@felix-colibri.com.
- or more simply, enter your (anonymous or with your e-mail if you want an answer) comments below and clic the "send" button
- and if you liked this article, talk about this site to your fellow developpers, add a link to your links page ou mention our articles in
your blog or newsgroup posts when relevant. That's the way we operate: the more traffic and Google references we get, the more articles we will write.
4 - Conclusion
We presented a tool which analyzes all the .DFM of a project and extracts the tDataSet information, providing a Database schema.
5 - Other Papers with Source and Links
Database |
database reverse engineering |
Extraction of the Database Schema by analyzing the content of the application's .DFMs | sql parser |
Parsing SQL requests in Delphi, starting from an EBNF grammar for SELECT, INSERT and UPDATE | ado net tutorial |
a complete Ado Net architectural presentation, and projects for creating the Database, creating Tables, adding, deleting and updating rows, displaying the data in controls and DataGrids, using in memory DataSets, handling Views, updating the Tables with a DataGrid
| turbo delphi interbase tutorial |
develop database applications with Turbo Delphi and Interbase. Complete ADO Net architecture, and full projects to create the database, the Tables, fill the rows, display and update the values with DataGrids. Uses the BDP |
bdp ado net blobs | BDP and Blobs : reading and writing Blob fields using the BDP with Turbo Delphi |
interbase stored procedure grammar |
Interbase Stored Procedure Grammar : The BNF Grammar of the Interbase Stored Procedure. This grammar can be used to build stored procedure utilities, like pretty printers, renaming tools, Sql Engine conversion or ports |
using interbase system tables |
Using InterBase System Tables : The Interbase / FireBird System Tables: description of the main Tables, with their relationship and presents examples of how to extract information from the schema |
eco tutorial |
Writing a simple ECO application: the UML model, the in memory objects and the GUI presentation. We also will show how to evaluate OCL expressions using the EcoHandles, and persist the data on disc |
delphi dbx4 programming |
the new dbExpress 4 framework for RAD Studio 2007 : the configuration files, how to connect, read and write data, using tracing and pooling delegates and metadata handling |
blackfishsql |
using the new BlackfishSql standalone database engine of RAD Studio 2007 (Win32 and .Net) : create the database, create / fill / read Tables, use Pascal User Defined Functions and Stored Procedures |
rave pdf intraweb |
how to produce PDF reports using Rave, and have an Intraweb site generate and display .PDF pages, with multi-user access |
embarcadero er studio |
Embarcadero ER Studio tutorial: how to use the Entity Relationship tool to create a new model, reverse engineer a database, create sub-models, generate reports, import metadata, switch to Dimensional Model | | |
Web |
sql to html | converting SQL ascii request to HTML format
| simple web server |
a simple HTTP web Server and the corresponding HTTP web Browser, using our Client Server Socket library |
simple cgi web server |
a simple CGI Web Server which handles HTML <FORM> requests, mainly for debugging CGI Server extension purposes |
cgi database browser | a CGI extension in order to display and modify a Table using a Web Browser |
whois | a Whois Client who requests information about owners of IP adresses. Works in batch mode. |
web downloader |
an HTTP tool enabling to save on a local folder an HTML page with its associated images (.GIF, .JPEG, .PNG or other) for archieving or later off-line reading |
web spider | a Web Spider allowing to download all pages from a site, with custom or GUI filtering and selection. |
asp net log file |
a logging CLASS allowing to monitor the Asp.Net events, mainly used for undesrtanding, debugging and journaling Asp.Net Web applications |
asp net viewstate viewer |
an ASP.NET utility displaying the content of the viewtate field which carries the request state between Internet Explorer and the IIS / CASSINI Servers |
rss reader |
the RSS Reader lets you download and view the content of an .RSS feed (the entry point into somebody's blog) in a tMemo or a tTreeView. Comes complete with an .HTML downloader and an .XML parser |
news message tree |
how to build a tree of the NNTP News Messages. The downloaded messages are displayed in tListBox by message thread (topic), and for each thread the messages are presented in a tTreeVi"ew |
threaded indy news reader |
a NewsReader which presents the articles sorted by thread and in a logical hierarchical way. This is the basic Indy newsreader demo plus the tree organization of messages |
delphi asp net portal programming |
presentation, architecture and programming of the Delphi Asp Net Portal. This is a Delphi version of the Microsoft ASP.NET Starter Kit Web Portal showcase. With detailed schemas and step by step presentation, the Sql scripts and binaries of the Database
| delphi web designer |
a tiny Delphi "RAD Web Designer", which explains how the Delphi IDE can be used to generate .HTML pages using the Palette / Object Inspector / Form metaphor to layout the page content |
intraweb architecture |
the architecture of the Intraweb web site building tool. Explains how Delphi "rad html generator" work, and presents the CLASS organization (UML Class diagrams) |
ajax tutorial |
AJAX Tutorial : writing an AJAX web application. How AJAX works, using a JavaScript DOM parser, the Indy Web Server, requesting .XML data packets - Integrated development project |
asp net master pages |
Asp.Net 2.0 Master Pages : the new Asp.Net 2.0 allow us to define the page structure in a hierarchical way using Master Pages and Content Pages, in a way similar to tForm inheritance |
delphi asp net 20 databases |
Asp.Net 2.0 and Ado.Net 2.0 : displaying and writing InterBase and Blackfish Sql data using Dbx4, Ado.Net Db and AdoDbxClient. Handling of ListBox and GridView with DataSource components
| asp net 20 users roles profiles |
Asp.Net 2.0 Security: Users, Roles and Profiles : Asp.Net 2.0 offers a vaslty improved support for handling security: new Login Controls, and services for managing Users, grouping Users in Roles, and storing User preferences in Profiles
| bayesian spam filter |
Bayesian Spam Filter : presentation and implementation of a spam elimination tool which uses Bayesian Filtering techniques | | |
TCP/IP |
tcp ip sniffer | project to capture and display the packets travelling on the Ethernet network of your PC. |
sniffing interbase traffic |
capture and analysis of Interbase packets. Creation of a database and test table, and comparison of the BDE vs Interbase Express Delphi components |
socket programming | the simplest Client Server example of TCP / IP communication using Windows Sockets with Delphi |
delphi socket architecture |
the organization of the ScktComp unit, with UML diagrams and a simple Client Server file transfer example using tClientSocket and tServerSocket | | |
Object Oriented Programming Components |
delphi virtual constructor |
VIRTUAL CONSTRUCTORS together with CLASS references and dynamic Packages allow the separation between a main project and modules compiled and linked in later. The starting point for Application Frameworks and Plugins
| delphi generics tutorial |
Delphi Generics Tutorial : using Generics (parameterized types) in Delphi : the type parameter and the type argument, application of generics, constraints on INTERFACEs or CONSTRUCTORs | |
| UML Patterns |
the lexi editor |
delphi source code of the Gof Editor: Composite, Decorator, Iterator, Strategy, Visitor, Command, with UML diagrams |
factory and bridge patterns |
presentation and Delphi sources for the Abstract Factory and Bridge patterns, used in the Lexi Document Editor case study from the GOF book |
gof design patterns |
delphi source code of the 23 Gof (GAMMA and other) patterns: Composite, Decorator, Iterator, Strategy, Visitor, Command | | |
| Graphic |
delphi 3d designer |
build a 3d volume list, display it in perspective and move the camera, the screen or the volumes with the mouse. |
writing a flash player |
build your own ShockWave Flash movie Player, with pause, custom back and forward steps, snapshots, resizing. Designed for analyzing .SWF demos. | | |
Utilities |
the coliget search engine |
a Full Text Search unit allowing to find the files in a directory satisfying a complex string request (UML AND Delphi OR Patters) |
treeview html help viewer |
Treeview .HTML Help Viewer : the use of a Treeview along with a WebBrowser to display .HTML files alows both structuring and ordering of the help topics. This tool was used to browse the Delphi PRISM Wiki help. | |
| Delphi utilities |
delphi net bdsproj |
structure and analysis of the .BDSPROJ file with the help of a small Delphi .XML parser | dccil bat generator
| generation of the .BAT for the Delphi DCCIL command line compiler using the .BDSPROJ | dfm parser |
a Delphi Project analyzing the .DFM file and building a memory representation. This can be used for transformations of the form components |
dfm binary to text | a Delphi Project converting all .DFM file from a path from binary to ascii format |
component to code |
generate the component creation and initialization code by analyzing the .DFM. Handy to avoid installing components on the Palette when examining new libraries |
exe dll pe explorer |
presents and analyzes the content of .EXE and .DLL files. The starting point for extracting resources, spying .DLL function calls or injecting additional functionalities |
dll and process viewer |
analyze and display the list of running processes, with their associated DLLs and Memory mapped files (Process Walker) | | |
Controls |
find memo | a tMemo with "find first", "find next", "sort", "save" capabilities | | |
|
6 - The author
Felix John COLIBRI works at the Pascal Institute. Starting with Pascal in 1979, he then became involved with Object Oriented Programming, Delphi, Sql, Tcp/Ip, Html, UML. Currently, he is mainly
active in the area of custom software development (new projects, maintenance, audits, BDE migration, Delphi
Xe_n migrations, refactoring), Delphi Consulting and Delph
training. His web site features tutorials, technical papers about programming with full downloadable source code, and the description and calendar of forthcoming Delphi, FireBird, Tcp/IP, Web Services, OOP / UML, Design Patterns, Unit Testing training sessions. |