dzMdbViewer 1.0.2 released

 Delphi  Comments Off on dzMdbViewer 1.0.2 released
Sep 302016
 

dzMdbViewer is a small tool I wrote, when I was stuck without a MS Access installation but needed to have a look into a .MDB file (and later .ACCDB file, if the Access Database Engine 2012 is installed).

It can open these files and display a list of queries and tables stored in them as well as the data they contain.

Table Data

Also, for tables, it can show the field definitions.

Table Definition

Today I added support for command line parameters, so it can be used as the default program for opening these kind of files. Download it from SourceForge. The source code is available too. (I got tired of the inconveniences of Mercurial, so I moved this project to Subversion.)

First steps with REST and JSON

 Delphi  Comments Off on First steps with REST and JSON
Sep 252016
 

I must admit that I haven’t done much programming regarding the web. There was an attempt to write an RSS reader some time back and there is my virtual radio alarm clock (with which I’m currently listening to SWR3). But this is my first try to do something with REST and JSON. The server side is provided by the Delphi Dabbler SWAG archive the client is written with Delphi 10.1 Berlin.

At first I tried to make sense from the tutorial provided by Embarcadero but I found it rather confusing and it stops exactly when actually trying to access the data returned in a meaningful way.

So, I threw away the TRESTxxx components I had put on the form and went back to some actual programming rather than dropping components and setting properties without understanding what I am doing. Here is what I ended up with:

swagbrowser

The program itself consists of two parts: Requesting data from the server and interpreting its answers. Requests are sent via http using a TidHttp object which is dynamically created and destroyed for each request.

procedure Tf_DelphiDabblerSwag.doRequest(const _Command: string; out _Response: TJSONObject);
var
  HTTP: TIdHTTP;
  JSON: string;
begin
  HTTP := TIdHTTP.Create(nil);
  try
    JSON := HTTP.Get('http://swag.delphidabbler.com/api/v1/' + _Command);
//    m_Result.Lines.text := JSON;
  finally
    FreeAndNil(HTTP);
  end;
  _Response := TJSONObject.ParseJSONValue(JSON) as TJSONObject;
end;

It expects a Command which is simply sent to the server by appending it to the API url as described in the documentation.

It returns a TJSONObject which is then interpreted by the caller. (I don’t do much error handling here, it’s merely a learning experiment.)

The API is simple, it knows only 4 different commands:

  • categories
  • snippet
  • snippet-count
  • snippets

I implemented each of them as a method:

categories

procedure Tf_DelphiDabblerSwag.RequestCategories(_Categories: TObjectList<TIdTitleObj>);
var
  JObj: TJSONObject;
  JCategories: TJSONArray;
  i: Integer;
  JCategory: TJSONObject;
  Category: TIdTitleObj;
begin
  doRequest('categories', JObj);
  try
    m_Result.Lines.Add('status: ' + JObj.GetValue('status').Value);
    m_Result.Lines.Add('command: ' + JObj.GetValue('command').Value);
    JCategories := JObj.Get('categories').JsonValue as TJSONArray;
    for i := 0 to JCategories.Count - 1 do begin
      JCategory := JCategories.Items[i] as TJSONObject;
//        m_Result.Lines.Add(Format('Category: (ID: %s, Title: %s', [JCategory.GetValue('id').Value, JCategory.GetValue('title').Value]));
      Category := TIdTitleObj.Create(JCategory.GetValue('id').Value, JCategory.GetValue('title').Value);
      _Categories.Add(Category);
    end;
  finally
    FreeAndNil(JObj);
  end;
end;

The first thing the program does is getting a list of all categories. For that it sends the “category” command to the server and interprets its response.

{
  "status":"ok",
  "command":"categories",
  "categories":[
    {
      "id":"ANSI",
      "title":"ANSI Control & Ouput"
    },
    {
      "id":"ARCHIVES",
      "title":"Archive Handling"
    },

    ... more category elements ...

  ]
}

All categories are stored in a TObjectList and returned to the caller. It took me a while to figure out how to access the array of categories: You access a name value entry and type cast it to TJSONArray. After I understood that, everything else was easy.

snippets

Next is getting a list of all snippets of a category.

procedure Tf_DelphiDabblerSwag.RequestSnippets(const _CategoryId: string; _Snippets: TObjectList<TIdTitleObj>);
var
  JObj: TJSONObject;
  i: Integer;
  JSnippets: TJSONArray;
  JSnippet: TJSONObject;
  Snippet: TIdTitleObj;
begin
  _Snippets.Clear;
  doRequest('snippets/' + _CategoryId + '?fields=id,title', JObj);
  m_Result.Lines.Add('status: ' + JObj.GetValue('status').Value);
  m_Result.Lines.Add('command: ' + JObj.GetValue('command').Value);
  JSnippets := JObj.Get('snippets').JsonValue as TJSONArray;
  for i := 0 to JSnippets.Count - 1 do begin
    JSnippet := JSnippets.Items[i] as TJSONObject;
    Snippet := TIdTitleObj.Create(JSnippet.GetValue('id').Value, JSnippet.GetValue('title').Value);
//    m_Result.Lines.Add(Format('Snippet: (ID: %s, Title: %s', [JSnippet.GetValue('id').Value, JSnippet.GetValue('title').Value]));
    _Snippets.Add(Snippet);
  end;
end;

The “snippets” command needs a some parameters:

  • The id of the category
  • The fields we are interested in

They are appended to the command.

Then again, we simply parse the result and return it in a TObjectList.

{
  "status":"ok",
  "command":"snippets",
  "snippets":[
    {
      "id":491,
      "title":"Getting the Line number in a memo Field",
    },
    {
      "id":492,
      "title":"Capturing the Desktop to a form",
    },
    {
      "id":493,
      "title":"File Copying in DELPHI",
    },{
      "id":494,
      "title":"File Manager Drag\/Drop",
    }
  ]
}

snippet

The last part is getting a snippet’s text.

procedure Tf_DelphiDabblerSwag.RequestSnippetText(const _SnippetId: string; out _Text: string);
var
  JObj: TJSONObject;
  JSnippet: TJSONObject;
begin
  doRequest('snippet/' + _SnippetId + '?fields=source_code', JObj);
  try
    m_Result.Lines.Add('status: ' + JObj.GetValue('status').Value);
    m_Result.Lines.Add('command: ' + JObj.GetValue('command').Value);
    JSnippet := JObj.GetValue('snippet') as TJSONObject;
    m_Snippet.Lines.Text := JSnippet.GetValue('source_code').Value;
  finally
    FreeAndNil(JObj);
  end;
end;

The “snippet” command requires a snipped id and we also must specify the fields we want to get. In this case we only want the source_code.

{
  "status":"ok",
  "command":"snippet",
  "snippet":{
    "source_code":"\r\n{This way uses a File stream.}\r\nProcedure ..."
  }
}

The response is then parsed and returned as a string. Note that “snippet” is an object, so in order to get the source code we need to type cast the snippet value to a TJSONObject before we can access its source_code value.

That’s about it. The rest of the program is a few event handlers that call the methods described above and fill the result into the GUI. I won’t get into that, it’s boring.

The source code is available for download here and in case you simply want to browse the SWAG archive using that program, there is also a precompiled executable

As I already said in the title: These are my first steps. I’m pretty satisfied with the result, but I’m sure I made some mistakes and there are probably easier ways to implement this.

Hotfix for GExperts crashing with Delphi 10.1 update 1

 none  Comments Off on Hotfix for GExperts crashing with Delphi 10.1 update 1
Sep 242016
 

GExperts 1.38 experimental twm 2016-09-18 has a few issues with Delphi / Rad Studio 10.1 Berlin Update 1. Simply recompiling the DLL made them go away for me, so I provide the recompiled DLL as a hotfix for this release. Go the release page to get it.

GExperts 1.38 experimental twm 2016-09-18 released

 Delphi, GExperts  Comments Off on GExperts 1.38 experimental twm 2016-09-18 released
Sep 182016
 

Since apparently Erik needs more time for the official GExperts 1.39 release, here is another experimental test release. Please report any bugs you may find (preferentially in the GExperts community on Google+ or the bug tracker on SourceForge)

Again, I have built installers for each Delphi version. These installers should install everything that is necessary, including the files for the Code Formatter.

Apart from several bugfixes I have added three new experts:

  • There is the Warn Directives Expert which allows you to select a warn directive like SYMBOL_PLATFORM and insert it as {$WARN SYMBOL_PLATFORM OFF}, {$WARN SYMBOL_PLATFORM ON}, {$WARN SYMBOL_PLATFORM DEFAULT} or {$WARN SYMBOL_PLATFORM ERROR}.
  • Then there is the IfDEF Expert which alows you to insert various IFDEF, IF or IFOPT directives. It automatically scans for include files in the current unit and offers the conditional defines from there as well. You can also add another include file from the search path and if you add directives for conditional defines from it, the expert will automatically add an {$I <filename>} directive to the unit.
  • And last but not least there is the Add to Formatter Capitalization Expert which allows you to add the current identifier to the code formatter’s captitalization file without clicking your way through the various configuration dialog levels.

GExperts IFDEF Expert

Head over to the Experimental GExperts page to download it.

GExperts IFDEF Expert support for include files

 Delphi, GExperts  Comments Off on GExperts IFDEF Expert support for include files
Sep 162016
 

The GExperts IFDEF expert now supports include files.

GExperts IFDEF Expert

For each include file in the current unit it displays an additional tab containing all symbols defined in that include file with {$DEFINE }, {$UNDEF } and the usual disabled notation of these {.$DEFINE }, {.$UNDEF }. It searches for the include files in the search path of the project and – like the compiler – uses the first one it finds.

Compiling GExperts

 none  Comments Off on Compiling GExperts
Sep 072016
 

Several times people have asked me how to compile their own GExperts dll. It’s really simple, here is how.

CompilingGExperts

Colin Wilson’s XN Resource Editor

 Delphi  Comments Off on Colin Wilson’s XN Resource Editor
Aug 072016
 

A really useful tool that I have used for many years, was Colin Wilson’s XN Resource Editor.

XNResourceEditor

Before he apparently disappeared from the face of the earth, Colin was so kind to release the source code under the MPL on his homepage. Unfortunately this page now is also gone, only a few snapshots in the Internet Archive remain. Even more unfortunately the source code archive is not complete. It’s missing quite a few components and utility units.

I have started to try and recompile XN Resource Editor several times, usually because I stumbled upon yet another copy of its source code somewhere on the Internet, in the vain hope that this time it might be complete. The latest was in Stefan Sundin’s github repository. Unfortunately it turned out that – even though he claims that the repository contains all prerequisites – several files were missing, in particular the VirtualTreeView extension written by Colin.

This time I went back to the Internet Archive and tried to find a snapshot that contains the files necessary. It turned out that they were all there, just not in the same snapshot.

To cut a long story short: I managed to dig the complete source code of XN Resource Editor out of the Internet Archive of his homepage. While I am not 100% sure that it is the latest version, it at least compiles and seems to work. I put everything into the svn repository of the new XN Resource Editor project on SourceForge. It contains everything necessary, including the TNTComponents Suite and Virtual Treeview.

There is a !Readme.txt file describing the steps necessary to compile the program (You also need Delphi 2006 for that). Or, if you just need the executable and can’t find it anywhere else, look here.

Specifying a date for MS SQL Server

 SQL  Comments Off on Specifying a date for MS SQL Server
Jul 272016
 

Today I had the “pleasure” to fix a problem in a customer’s SQL server database where some records had wrong values in date fields. The theory is quite simple. Find out which records are affected (there were only 7 of them) and correct the problem with a statement like this:

update tablename
set datefield='2008-02-14'
where someotherfield='somestringvalue'

Unfortunately the SQL server complained that it could not convert the string to a date. Google didn’t really help much because apparently it works like this for everybody else but me. But I found a hint how to test it quite simply:

select isdate('2008-02-14')

After a bit of try and error if found the problem:

The server did not actually assume a date of the form yyyy-mm-dd to be ISO 8601 as every human probably would. It assumed it to be yyyy-dd-mm so

select isdate('2008-14-02')

worked.

Americans! With yy/dd/mm You have given the world the most stupid date format ever, but Microsoft managed to top even that with yyyy-dd-mm.

So, eventually I used

update tablename
set datefield='2008-14-02'
where someotherfield='somestringvalue'

and it worked.

EDIT:

As Stefan Glienke pointet out in this Google+ post the order of y,m,d in a date is configurable with SET DATEFORMAT

So apparently on the machine I was working on it was set to

SET DATEFORMAT ydm

and I could have fixed the problem with

SET DATEFORMAT ymd