menu
  Home  ==>  papers  ==>  db  ==>  database_reverse_engineering   

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 Form1TForm1
  Left = 272
  ...
  object Table1TTable
    DatabaseName = 'DBDEMOS'
    TableName = 'animals.dbf'
    Left = 16
    Top = 8
    object Table1NAMETStringField
      FieldName = 'NAME'
      Size = 10
    end
    object Table1SIZETSmallintField
      FieldName = 'SIZE'
    end
    ...
  end

  object IBDatabase1TIBDatabase
    Connected = True
    DatabaseName = '..\employee.gdb'
    Params.Strings = (
      'user_name=SYSDBA'
      'password=masterkey')
    LoginPrompt = False
    DefaultTransaction = IBTransaction1
    ...
  end
  object IBTransaction1TIBTransaction
    Active = True
    DefaultDatabase = IBDatabase1
    AutoStopAction = saNone
    ...
  end
  object IBQuery1TIBQuery
    Database = IBDatabase1
    Transaction = IBTransaction1
    BufferChunks = 1000
    CachedUpdates = False
    SQL.Strings = (
      'select  * from CUSTOMER')
    Left = 120
    Top = 8
    object IBQuery1CUST_NOTIntegerField
      FieldName = 'CUST_NO'
      Origin = 'CUSTOMER.CUST_NO'
      Required = True
    end
    object IBQuery1CUSTOMERTIBStringField
      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 Form1TForm1
  Left = 275
  ...
  object Table1TTable
    DatabaseName = 'DBDEMOS'
    TableName = 'orders.db'
    ...
  end
  object DataSource1TDataSource
    DataSet = Table1
    ...
  end

  object Table2TTable
    DatabaseName = 'DBDEMOS'
    IndexFieldNames = 'OrderNo'
    MasterFields = 'OrderNo'
    MasterSource = DataSource1
    TableName = 'items.db'
    ...
  end

  object Query1TQuery
    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_typetFieldType;
            m_field_sizeInteger;

            Constructor create_field(p_nameString;
                p_field_typetFieldTypep_field_sizeInteger);
            function f_display_fieldString;
            Destructor DestroyOverride;
          end// c_field

 c_dataset_listClass// forwar
 c_dataset// one "dataset"
            Class(c_basic_object)
              // -- m_name: the Server NAME or the SQL request
              m_c_parent_dataset_listc_dataset_list;
              m_c_field_listtStringList;

              // -- a list, since one server Table can be references by
              // --   several tDatasets in a tForm
              m_c_component_name_listtStringList;

              // -- Master / Detail
              m_master_datasourceString;
              m_c_master_dataset_refc_dataset;
              m_did_resolveBoolean;

              Constructor create_dataset(p_nameString;
                  p_c_parent_dataset_listc_dataset_list);

              function f_c_selfc_dataset;
              function f_display_datasetString;

              function f_field_countInteger;
              function f_c_field(p_field_indexInteger): c_field;
              function f_index_of(p_field_nameString): Integer;
              function f_c_find_by_field(p_field_nameString): c_field;
              procedure add_field(p_field_nameStringp_c_elementc_field);
              function f_c_add_field(p_field_nameString;
                  p_field_typetFieldTypep_field_sizeInteger): c_field;
              function f_c_add_unique_field(p_field_nameString;
                  p_field_typetFieldTypep_field_sizeInteger): c_field;
              procedure display_field_list;

              procedure display_detailed_dataset_fields;
              procedure display_detailed_datasetVirtual;

              Destructor DestroyOverride;
            end// c_dataset

 c_dataset_list// "dataset" list
                 Class(c_basic_object)
                   m_c_dataset_listtStringList;

                   Constructor create_dataset_list(p_nameString);

                   function f_dataset_countInteger;
                   function f_c_dataset(p_dataset_indexInteger): c_dataset;
                   function f_index_of(p_dataset_indexString): Integer;
                   function f_c_find_by_dataset(p_dataset_indexString): c_dataset;
                   function f_c_find_by_dataset_component_name(p_dataset_component_nameString): c_dataset;
                   procedure add_dataset(p_dataset_indexStringp_c_datasetc_dataset);
                   function f_c_add_dataset(p_dataset_indexString): c_dataset;
                   function f_c_add_unique_dataset(p_dataset_indexString): c_dataset;
                   procedure display_dataset_list;
                   procedure display_detailed_dataset_list;

                   procedure extract_sql(p_full_file_nameString);

                   Destructor DestroyOverride;
                 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_dbclass(c_basic_object)
                     m_c_dataset_list_refc_dataset_list;

                     Constructor create_analyze_db(p_nameString);
                     procedure analyze(p_c_dfm_objectc_dfm_object);
                   end// c_analyze_db

  • the method which adds c_dataset elements is:

    procedure c_analyze_db.analyze(p_c_dfm_objectc_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_levelIntegerp_c_dfm_objectc_dfm_object);

      procedure add_fields(p_c_dfm_object_listc_dfm_object_listp_c_datasetc_dataset);
        var l_dfm_object_indexInteger;
            l_field_typetFieldType;
        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_indexdo
              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_nameString;
            l_index_of_tableInteger;
            l_c_dataset_tablec_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_namel_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_listl_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_indexInteger;
          l_c_dfm_datasourcec_dfm_object;
          l_master_datasetString;
          l_c_dfm_master_datasetc_dfm_object;
          l_dataset_nameString;
      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_indexdo
              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
    Name :
    E-mail :
    Comments * :
     

  • 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
Debug and Test
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
Helper units
windows environment read and write Windows Environment strings
stdin stdout send and receive strings from a GUI application to a CONSOLE application




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.
Created: nov-04. Last updated: dec-15 - 99 articles, 220 .ZIP sources, 1068 figures
Copyright © Felix J. Colibri   http://www.felix-colibri.com 2004 - 2015. All rigths reserved
Back:    Home  Papers  Training  Delphi developments  Links  Download
the Pascal Institute

Felix J COLIBRI

+ Home
  + articles_with_sources
    + database
      + interbase
      – firebird_trans_simulator
      + sql_server
      + bdp
      – db_refactoring
      – sql_parser
      – sql_to_html
      – sniffing_interbase
      – eco_tutorial
      – dbx4_programming
      – blackfishsql
      – rave_pdf_intraweb
      – rave_reports_tutorial
      – rave_reports_video
      – embarcadero_er/studio
      + firedac
      – bde_unidac_migration
    + web_internet_sockets
    + oop_components
    + uml_design_patterns
    + debug_and_test
    + graphic
    + controls
    + colibri_utilities
    + colibri_helpers
    + delphi
    + firemonkey
    + compilers
  + delphi_training
  + delphi_developments
  + sweet_home
  – download_zip_sources
  + links
Contacts
Site Map
– search :

RSS feed  
Blog