Filter multiple criteria in Windows Explorer

 Windows, Windows 7, Windows 8.1  Comments Off on Filter multiple criteria in Windows Explorer
Nov 092016
 

Note to self: It is possible to filter on multiple criteria – e.g. extensions – in Windows Explorer by combining them with OR:

.txt OR .doc
  • The OR must be written all upper case (AND is also possible).
  • *.txt will not work
  • It will search recursively
  • A semicolon (as in file filters) does not work.

More on filtering, grouping and searching here.

Force “unidentified networks” to be private or public in Windows 7

 Windows, Windows 7  Comments Off on Force “unidentified networks” to be private or public in Windows 7
Oct 282016
 

Windows 7 has got an annoying feature that categorises network connections to be public, home or work networks. This might work for others but it has never worked for me. Even worse, for some reason the link that usually allows the user to change the network type sometimes is not available.

Microsoft even has got Knowledge base entry KB2578723 for that problem, which unfortunately didn’t work for me. I could change the current network, but after a reboot it again categorised the same network as unidentified network and public.

The solution is described in this article on sevenforums.com. Either use the Local Security Policy editor or RegEdit to change the setting how to treat unidentified networks. This setting is usually missing from the registry, so the keys must be created first. The easiest way to do that is the .reg file you can download from the page linked above. It looks like this:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\CurrentVersion\NetworkList\Signatures\010103000F0000F0010000000F0000F0C967A3643C3AD745950DA7859209176EF5B87C875FA20DF21951640E807D7C24]
"Category"=dword:00000001

As I said: the registry keys don’t exist by default. Creating them manually is difficult because of the long number Microsoft chose to use, so it was either the Policy Editor or the .reg file for me. I took the Policy Editor approach but later verified that it created the registry entry shown above, so it’s probably safe to just use the .reg file.

Drawing a Bitmap on a Paintbox in Delphi

 none  Comments Off on Drawing a Bitmap on a Paintbox in Delphi
Oct 252016
 

Yes, I know, this is far from news, but since I just spent several hours trying to find out why my code didn’t work, I’ll document it here so I can look it up later.

There are various ways to draw a bitmap on a paintbox in Delphi. I’ll focus on the Windows API function StretchBlt.

  // first, get the bitmap from somewhere
  if not GetBitmap(FPreviewBmp) then
    FPreviewBmp.Assign(nil);

  // calculate the available size to display the bitmap
  // keeping the aspect ratio
  cnv := pb_Preview.Canvas;
  BoxWidth := pb_Preview.Width;
  BoxHeight := pb_Preview.Height;
  BmpWidth := FPreviewBmp.Width;
  BmpHeight := FPreviewBmp.Height;
  HeightFactor := BoxHeight / BmpHeight;
  WidthFactor := BoxWidth / BmpWidth;
  if HeightFactor > WidthFactor then
    Factor := WidthFactor
  else
    Factor := HeightFactor;
  // we do not want to enlarge the picture
  if Factor > 1 then
    Factor := 1;
  // calculate size and offsets so it is shown centered
  BmpWidth := Trunc(BmpWidth * Factor);
  BmpHeight := Trunc(BmpHeight * Factor);
  BmpTop := (BoxHeight - BmpHeight) div 2;
  BmpLeft := (BoxWidth - BmpWidth) div 2;
  // set the StretchBlt mode (you basically always want COLORONCOLOR)
  SetStretchBltMode(cnv.Handle, COLORONCOLOR);
  // draw the bitmap to the paintbox
  // note that you need to use the Canvas handle of the bitmap,
  // not the handle of the bitmap itself
  Res := StretchBlt(
    cnv.Handle, BmpLeft, BmpTop, BmpWidth, BmpHeight,
    FPreviewBmp.Canvas.Handle, 0, 0, FPreviewBmp.Width, FPreviewBmp.Height,
    SRCCOPY);
    if not Res then begin
      err := GetLastError;
      cnv.TextOut(0, 0, Format('LastError: %d %s', [err, SysErrorMessage(err)]));
    end;

It took me hours to find out why in my original code StretchBlt failed with error code 6 (The handle is invalid). It was very simple:
StretchBlt must be passed FPreviewBmp.Canvas.Handle rather than FPreviewBmp.Handle.

After changing that, it simply worked.

Writing large INI files

 Delphi, GExperts  Comments Off on Writing large INI files
Oct 232016
 

INI files, once the most used way for storing program configurations, are still popular due to their simplicity. Delphi offers two ways for accessing them:

If you only want to read or write a few values, it’s fine to use TIniFile. The underlying Windows API functions have a size limit of 64 KB though, which you might or might not reach. Once you reach it, you will experience very odd behaviour. I could not find any official documentation on whether this limit has been lifted in recent versions of Windows.

TMemIniFile does not suffer from that restriction, but it has its own: First, it might have worse performance if you only read or write a few values, because it reads the full file into memory. It also ignores any comments marked by ‘;’, so writing the file back will remove these comments. (You can still use a different comment marker e.g. // or # though.) And don’t forget to call UpdateFile if you changed it! Otherwise your changes are lost.

For writing large INI files, don’t even consider using TIniFile. It takes forever! But what about TMemIniFile? It’s much faster, but is it as fast as possible? No, it’s not. Here are two methods for writing an INI file that are even faster:

  • TStringList – but only if you recreate the full file anyway and the entries are simple
  • TFastIniFile – if you want to use a 3rd party library

The GExperts Class Browser expert writes .gex files which are INI files with a different extension to store the class list it retrieved from source files. These .gex files can be large e.g. if you add the VCL directory of Delphi 2007 the resulting file is 68 KB and contains 617 entries. The class browser used to use TIniFile to read and write these files. Here are my timing results:

Writing with TIniFile took 2,368 s
Writing with TMemIniFile took 0,236 s
Writing with TMemIniFile.SetStrings took 0,005 s
Writing with TStringList.SaveToFile took 0,004 s

So, there is a factor of 10 between TMemIniFile and TIniFile and a factor of *drumroll* 50 between TStringList and and TMemIniFile. Changing the code from TIniFile to TStringList sped up that code by a factor of whooping 500! And since these files tend to get large that’s significant.

But what if you don’t rewrite the whole file? If you just want to, say, add a new section with 100 entries to it? Yes, you could still use TStringList but that would be rather inconvenient. INI files are mostly about convenience. So I looked for a faster implementation and found TFastIniFile by Pieter Zijlstra. According to Pieter it has been updated to Delphi XE4. I tested it with Delphi 2007 and the results are impressive. It’s nearly as fast as using a TStringList and has a few features that TMemIniFile has not: It preserves comments and blank lines. It supports inline comments. Here is the result of the speed benchmark from the demo program he supplies:

(Re)write 400 sections each with 10 ident=value’s
TIniFile 25,333 s 87224 Kb
TMemIniFile 0,037 s 88504 Kb
TFastIniFile ANSI 0,008 s 88504 Kb
TFastIniFile 0,010 s 88504 Kb

I didn’t use it in GExperts because it was not necessary but it might be well worth checking out if your program routinely works with large INI files.

My thanks to Daniela Osterhagen for reminding me that writing an INI file can easily be done with a TStringList.

Getting the system boot time in Windows

 Windows  Comments Off on Getting the system boot time in Windows
Oct 132016
 

Today I needed to get the system boot time of my computer.

You can either open the system log and look for the entries a Windows start up writes there, or you can let a tool do the work:

@echo off
systeminfo | find "System Boot Time"
pause

In my case the result looks like this:

System Boot Time:          13.10.2016, 09:14:50
Press any key to continue . . .

There are a lot more options, detailed in this answer on StackOverflow.

New GExperts IDE form enhancement for the Goto dialog

 Delphi, GExperts  Comments Off on New GExperts IDE form enhancement for the Goto dialog
Oct 092016
 

GExperts has got several options to enhance various IDE forms. They can be enabled and disabled on the configuration dialog’s IDE tab.

gexperts-ide-enhancement-goto-dialog

There is now a new one: Enhance Goto dialog. It’s the dialog you get when selecting Search -> Go to Line Number which looks like this in it’s original full glory:

delphi-ide-goto-dialog

It hasn’t changed since Delphi 1 (OK, I’m not sure about Delphi 1, but definitely not since Delphi 6), including such meaningful component names as Label1 and Bevel1.

This is how it looks when you enable the new enhancement:

gexperts-ide-enhanced-goto-dialog

As you can see I have added a listbox which is filled with the interesting positions in a unit:

  • Unit
  • Interface
  • Interface Uses
  • Implementation
  • Implementation Uses
  • Initialization (or Begin)
  • Finalization
  • End.

You can simply press the up or down arrow to select them and the corresponding line number will automatically entered for you. But manually entering a line number or selecting one from the combobox’s dropdown list still works as before.

In addition, I have fixed several form positioning bugs in the Delphi IDE in a multi monitor setup, where dialogs were always placed on the primary monitor regardless of where the IDE window was located.

  • In Delphi 2005 to 2007 it was the Search -> Replace dialog
  • In Delphi 2009 to 10 Seattle it were the File -> New -> Other and the Project -> Resources And Images dialogs

If you enable “Enhance IDE dialogs (and fix form positioning bugs)”, these dialogs will now be moved to the monitor of the IDEs main window.

There is no release yet, so if you want these goodies, you’ll have to compile GExperts yourself.

Delphi Live Templates: raise exception.CreateFmt

 Delphi  Comments Off on Delphi Live Templates: raise exception.CreateFmt
Oct 052016
 

Delphi (XE2) comes with various predefined so called live templates which you can display with View->Templates. One of them is called “raise” and expands to

raise exception.Create('Error Message');

I don’t know about you but I use Exception.CreateFmt much more often than simply Exception.Create, so it annoys the hell out of me when every time I type raise I get the simple Create call and have to edit it. Also, I usually use DxGetText to translate my error messages using the _() function. So I have to add that as well.

Today I got tired of this and simply changed the template:

  1. Since you cannot edit the predefined templates, the first thing you do, is open it and copy the whole text into the clipboard.
  2. Add a new template and paste the text into it.
  3. Change it to your liking.
  4. Save it with the same file name but to the directory for user defined code templates, which is [your documents folder]\RAD Studio\code_templates.

That’s it, now the new user defined template will be called rather than the predefined one.

Now to the template itself. This is the original template:

<?xml version="1.0" encoding="utf-8" ?>
<codetemplate	xmlns="http://schemas.borland.com/Delphi/2005/codetemplates"
				version="1.0.0">
<template name="raise" invoke="auto">
  <description>
	Create and raise an instance of an Exception class
  </description>
  <author>
	Embarcadero (with thanks to Erik Berry)
  </author>
  <point name="exception">
	<script language="Delphi">InvokeCodeCompletion;</script>
	<text>Exception</text>
	<hint>Exception class</hint>
  </point>
  <point name="errormessage">
	<text>Error Message</text>
	<hint>Exception Message</hint>
  </point>
  <code language="Delphi" context="methodbody" delimiter="|">
   <![CDATA[raise |exception|.Create('|errormessage|');|end|]]>
  </code>
</template>
</codetemplate>

And this is my changed template:

<?xml version="1.0" encoding="utf-8" ?>
<codetemplate	xmlns="http://schemas.borland.com/Delphi/2005/codetemplates"
				version="1.0.0">
<template name="raise" invoke="auto">
  <description>
	Create and raise an instance of an Exception class
  </description>
  <author>
	Embarcadero (with thanks to Erik Berry)
  </author>
  <point name="exception">
	<script language="Delphi">InvokeCodeCompletion;</script>
	<text>Exception</text>
	<hint>Exception class</hint>
  </point>
  <point name="errormessage">
	<text>Error Message</text>
	<hint>Exception Message</hint>
  </point>
  <point name="parameters">
	<text>Parameters</text>
	<hint>Parameters go here</hint>
  </point>
  <code language="Delphi" context="methodbody" delimiter="|">
   <![CDATA[raise |exception|.CreateFmt(_('|errormessage|'), [|parameters|]);|end|]]>
  </code>
</template>
</codetemplate>

As you can see, I changed Create to CreateFmt, added the call to _() and also added a point element “parameters” for entering the parameters for the format specifiers, which is then referenced in the code element.

You can find more about live templates here:

GExperts 1.38 experimental twm 2016-10-03 released

 Delphi, GExperts  Comments Off on GExperts 1.38 experimental twm 2016-10-03 released
Oct 032016
 

I must admit I’m getting tired of waiting for Erik to make a new official GExperts release. So, here is another experimental one.

The motive for making this release is twofold:

  1. The Delphi 10.1 Berlin update 1 for which I released a hotfix
  2. A bug I discovered and fixed yesterday that caused GExperts to crash with an access violation when the IDE was exiting (I’ve only seen this in Delphi 10.1 Berlin update 1 so far, but it could happen in any version.)

There are also some other changes / bugfixes:

  • The Make Relative and Make Absolute buttons on the search path dialog (only visible if you switch to Memo) did not convert the content of the edit control. This might also solve the problem that sometimes the content of the edit control was added to the search path when the dialog was closed, resulting in duplicate entries.
  • Make Absolute also converted entries starting with $(BDS) which was definitely not what you want.
  • I replaced the dialog that was shown by the Change Case expert with a popup menu. Basically the usage remains unchanged because the popup menu uses the same accelerator chars and it also remembers the last option you picked and makes it the default entry which you can select by pressing Enter. (Yes, I known the vote on this feature was undecided, but I did i anyway, just for the hell of it.)
  • There is a new Convert Strings editor expert. It is my first try to replace the existing Paste Strings As, Copy Raw Strings and Convert Raw Strings experts with something that’s easy to use without actually having to memorise how they work. It can probably still be improved.
    gexperts_convert-strings
  • Bugfix: The Uses Clause Manager no longer removes units and adds them to the end of the list when adding or removing unit prefixes.
  • Bugfix by
    Jeroen Wiert Pluimers
    for Add/Remove Unit Prefixes not catching generics.collections
  • Another improvement by Jeroen Wiert Pluimers to fix the case of the unit names to match the actual file names in the Add/Remove Unit Prefixes functioality.
  • Some internal refactoring e.g. I got rid of the FParser field in TUsesManager because that field was only ever used in a single method

One last thing I always wondered about: Several Embarcadero employees are blogging regularly about what happened in other blogs and which tools were updated. My posts about GExperts releases were only mentioned once but usually ignored. So I wonder whether this is somehow on purpose. Is it me? (I sometimes post quite critical things about Deplhi and Embarcadero on G+.) Is it GExperts? (It still supports old Delphi versions back to Delphi 6. I can understand that Embarcadero would like people to have yet another reason to upgrade to the latest and (in my opinion not always so) greatest Delphi version.)

Head over to the Experimental GExperts page to download the latest release it.

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