Friday, February 13, 2009

Accelerate the Performance of Windows Vista

Windows Vista consume much more resources than previous version of Windows.  You will get better performance and experience if you add more RAM to your PC.  Here are some tips you may follow to enhance user experience in Windows Vista if you have limited resources.

Switch to Window Classic Theme

Windows Vista use Windows Vista or AERO Theme by default.  You may switch to Windows Classic Theme for much smooth UI experience with the lose of nice glass effect of Windows Vista Theme.

Turn off Zip Folders

Windows Vista will treat zip file as a zip folder show in Windows Explorer's folder panel.  The ZIP folder slow down the performance of Windows Explorer contain ZIP files.  It may also create temporary files in your %TEMP% folder.  You may disable it if you have other File Compression Utility like WinZIP/WinRAR/7-Zip.

Merge the following Registry Script into Window Registry in privilege account and restart your PC:

Windows Registry Editor Version 5.00

[-HKEY_CLASSES_ROOT\CLSID\{E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31}]

[-HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}]

To turn on Zip Folder back, run the following script in privilege account and restart your PC:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\CLSID\{E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31}]
@="CompressedFolder"

[HKEY_CLASSES_ROOT\CLSID\{E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31}\DefaultIcon]
@=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,\
  00,5c,00,73,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,7a,00,69,00,\
  70,00,66,00,6c,00,64,00,72,00,2e,00,64,00,6c,00,6c,00,00,00

[HKEY_CLASSES_ROOT\CLSID\{E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31}\Implemented Categories]

[HKEY_CLASSES_ROOT\CLSID\{E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31}\Implemented Categories\{00021490-0000-0000-C000-000000000046}]
@=hex(0):

[HKEY_CLASSES_ROOT\CLSID\{E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31}\InProcServer32]
@=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,\
  00,5c,00,73,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,7a,00,69,00,\
  70,00,66,00,6c,00,64,00,72,00,2e,00,64,00,6c,00,6c,00,00,00
"ThreadingModel"="Apartment"

[HKEY_CLASSES_ROOT\CLSID\{E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31}\ProgID]
@="CompressedFolder"

[HKEY_CLASSES_ROOT\CLSID\{E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31}\ShellFolder]
"Attributes"=dword:200001a0
"UseDropHandler"=""

[HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}]
@="Cabinet File"

[HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}\CLSID]
@="{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}"

[HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}\DefaultIcon]
@="cabview.dll,0"

[HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}\Implemented Categories]

[HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}\Implemented Categories\{00021490-0000-0000-C000-000000000046}]

[HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}\InProcServer32]
@="cabview.dll"
"ThreadingModel"="Apartment"

[HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}\Shell]
@="none"

[HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}\Shell\find]
"SuppressionPolicy"=dword:00000080

[HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}\Shell\find\command]
@=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,\
  00,5c,00,45,00,78,00,70,00,6c,00,6f,00,72,00,65,00,72,00,2e,00,65,00,78,00,\
  65,00,00,00

[HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}\Shell\find\ddeexec]
@="[FindFolder(\"%l\", %I)]"

[HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}\Shell\find\ddeexec\application]
@="Folders"

[HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}\Shell\find\ddeexec\topic]
@="AppProperties"

[HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}\Shell\Open]

[HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}\Shell\Open\Command]
@=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,\
  00,5c,00,45,00,78,00,70,00,6c,00,6f,00,72,00,65,00,72,00,2e,00,65,00,78,00,\
  65,00,20,00,2f,00,69,00,64,00,6c,00,69,00,73,00,74,00,2c,00,25,00,49,00,2c,\
  00,25,00,4c,00,00,00
"DelegateExecute"="{11dbb47c-a525-400b-9e80-a54615a090c0}"

[HKEY_CLASSES_ROOT\CLSID\{0CD7A5C0-9F37-11CE-AE65-08002B2E1262}\ShellFolder]
"Attributes"=dword:680001a0

Clear your Temporary Files in %TEMP% folders

Temporary files take up your hard drive spaces.  Check and clean it regularly:

  1. Click Start | Run...
  2. Type: %TEMP%, press OK button
  3. A Windows Explorer will show the temporary folders.  Select and delete files and folders that you think should be removed.

Reference:

  1. How do I turn off Compressed Folders (built-in support for ZIP files) in Windows Vista and XP?

Saturday, February 07, 2009

Flash your motherboard BIOS to the updated version

MotherBoard BIOS get updated from time to time from vendor for the fixed.  Some unusual and performance issues happening to your OS may be BIOS's bug.  It is always encourage to update your BIOS to the latest available version.

Performing BIOS update need extra care.  Here are some rules to follow:

  1. During the flashing period, your PC must always stay on with power.  Any power failure in between may make your PC totally un-bootable
  2. Always check current BIOS version with the latest version to make sure you download and updated with correct one.

In old day, the BIOS update file size always fit to a 1.44MB floppy disk.  We just create a floppy image from the BIOS flash disk image and boot from the floppy disk will complete the update task easily.  However, PC do not equipped with 1.44MB floppy drive nowadays.

BIOS flash file size is getting bigger now can't fit into a 1.44MB floppy disk.  Vendor may recommend user create a bootable USB flash drive and copy the files into it and boot your PC from bootable USB flash drive.  Other vendors may have a utility to install a software into your Windows Operating System to perform update.

For me, I like the bare bone method that just run a simple flash .EXE utility on DOS.  However booting from DOS is not easy now.  One easy option is:

  1. Create a PXE environment in your network
  2. Setup a DOS image that support network in PXE boot option.
  3. Copy flash utilities and BIOS file in network share folder
  4. Boot your PC from PXE environment and select the DOS image
  5. Run the flash utility

This purely network BIOS updating solution should works usually.

Thursday, February 05, 2009

Delphi: Design Multi-Threaded SDI Application

SDI (Single Document Interface) has been pushed by Microsoft Office years ago.  Previously, it was MDI (Multiple Document Interface) in few older Office Suite.  Delphi Win32 VCL Form Application support MDI natively.  It requires some works to get SDI done in Delphi.

A new document interface model: Tabbed Browsing has been pushed by Firefox that grab lot of attention too.  A more recent Google Chrome can even undock a tab to make it as a separate desktop window.

It is no doubt that SDI has some advantages over MDI.  Research shows that using more than one desktop do improve productivity of user.  Dual-View environment will become popular in end user's day to day work.  MDI application can't utilize multi-desktop environment.  It may only show on one desktop only.  However, SDI doesn't has the restriction and may fully utilize multi-desktop environment.  Perhaps, the only drawback is the over created SDI window flow on desktop may irritate user's eye.

Show form as a separate desktop button

By default, all newly form create form may just show as is flowing on desktop.  There is only one desktop button for the VCL application you launch regardless of how many forms you created.  Running the following code for each form instance will create a desktop button:

procedure TChildForm.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  with Params do begin
    ExStyle := ExStyle or WS_EX_APPWINDOW;
  end;
end;

Now, all TChildForm instances will have separate desktop button.  That makes your application start looks like SDI.

Make it more like SDI

After play around with the above application for while, you start notice few things:

  1. If my child form overlap the main form, my main form always stay behind the child form
  2. Minimize main form will minimize all child forms and desktop button shrink to only one.
  3. Press Alt-Tab to bring the window selector doesn't show all correct number of main form and child form windows.

This is because all child form instance's WndParent handle is set to Application.Handle or Application.MainformHandle.  To overcome above problems, we can code like this:

procedure TChildForm.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  with Params do begin
    ExStyle := ExStyle or WS_EX_APPWINDOW;
    WndParent := GetDesktopwindow;
  end;
end;

Now all main form and child form behave similar and independent on your desktop.  Only different is closing the main form will close all child forms and end the process.

Child Form invoke modal form freeze whole application

So far, you should happy with the new SDI looks.  It works great.  But if your child form run the following codes:

begin
  ShowMessage('Modal Form Launched');
end;

begin
  raise Exception.Create('Exception raised');
end;

You will notice that you can't activate other child form or main form anymore.  This reason behind this is simple.  TCustomForm.ShowModal is running in a repeat until loop waiting for the form to return a ModalResult:

function TCustomForm.ShowModal: Integer;
begin
  ...
  Application.ModalStarted;
  try
    ...
    try
      Show;
      try
        ModalResult := 0;
        repeat
          Application.HandleMessage;
          if Application.Terminated then ModalResult := mrCancel else
            if ModalResult <> 0 then CloseModal;
        until ModalResult <> 0;
        ...
      finally
        Hide;
      end;
    finally
      ...
    end;
  finally
    Application.ModalFinished;
  end;
end;

For simple message dialog like ShowMessage or exception dialog, we may use Windows.MessageBox to prevent the freezing by introduce a parent form handle to the API function.

Other modal dialog may need extra coding to prevent the freezing is mimic TForm.ShowModal by using TForm.Show method instead.  The following code reveals a possible solution:

procedure ShowOwnModal(const aParentForm: TCustomForm; const aForm: TForm;
    const Proc: TProc<TModalResult>);
begin
  aForm.PopupParent := aParentForm;
  aForm.Show;

  aParentForm.Enabled := False;
  try
    while aForm.Visible do
      Application.HandleMessage;
  finally
    aParentForm.Enabled := True;
  end;

  Proc(aForm.ModalResult);
end;

procedure TChildForm.btnModalFormClick(Sender: TObject);
var F: TForm;
begin
  F := TModalForm.Create(Self);
  try
    ShowOwnModal(Self, F,
      procedure(M: TModalResult)
      begin
        if M = mrOK then
          ShowMessage('OK pressed')
        else
          ShowMessage('Cancel pressed');
      end
    );
  finally
    F.Free;
  end;
end;

We may reuse procedure ShowOwnModal else where in code that need to mimic ShowModal.  Furthermore, the ShowOwnModal strategy allow us to retain the classic coding style of using ShowModal in try...finally block:

F := TModalForm.Create(Self);
try
  if F.ShowModal = mrOK then
    ...
finally
  F.Free;
end;

Child form running lengthy task freeze whole application

If the child form is running a task that takes a while to complete.  Whole application will freeze.  This doesn't seems to be a acceptable behavior as user may have a perception that each child window should work independently from others.

A straight solution to the problem is using thread to run the task.

Hybrid Mode: Working with SDI and MDI together

There is an obvious disadvantage with SDI mode.  If too many SDI form has been open on desktop, user desktop getting messy and become harder for user to find and switch form.  It is also harder for user to identify a window was instantiated from which application.  In this scenarios, user may miss the classic MDI mode that collect all related forms under one roof.

Perhaps a solution would be mixing both mode together.  If we make MDI as a primary mode, all new instantiated window will become MDI child form by default.  There is a gadget to switch the MDI child form to SDI form floating on desktop window and vice versa allowing user working on multi-desktop environment.  This design may be a favor solution for user who need SDI in ad-hoc manner.

The following code reveal a possible design:

type
  TfmMDIChild = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  end;

procedure TfmMDIChild.Button1Click(Sender: TObject);
begin
  Self.FormStyle := fsNormal;
end;

procedure TfmMDIChild.Button2Click(Sender: TObject);
begin
  Self.Hide;   // Hide the form first else CreateParams will invoke twice
  Self.FormStyle := fsMDIChild;
end;

procedure TfmMDIChild.CreateParams(var Params: TCreateParams);
begin
  inherited;
  if FormStyle = fsNormal then begin
    with Params do begin
      ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
      WndParent := GetDesktopWindow;
    end;
  end else if FormStyle = fsMDIChild then begin
    Params.Width := Self.Width;
    Params.Height := Self.Height;
  end;
end;

The form provide 2 buttons allowing user to switch from MDI to SDI and SDI to MDI.  CreateParams will be invoked if FormStyle has changed.

Reference:

  1. Newsgroup: borland.public.delphi.objectpascal. Topic: SDI ShowModal howto? Author: Peter Below (TeamB)
  2. WebSite: About.Com: Delphi Programming. Topic: A more Powerful Delphi Form, TaskBar Button for every Delphi Form. Author: Zarko Gajic
  3. Newsgroup: borland.public.delphi.nativeapi.win32. Topic: How do I add a form to the taskbar?
  4. http://delphi.newswhat.com/geoxml/forumhistorythread?groupname=borland.public.delphi.language.delphi.general&messageid=40a1ffb8@newsgroups.borland.com
  5. Win32 user interface work is inherently single-threaded
  6. Newsgroup: Embarcadero Discussion Forums.Delphi.Language.Win32. Topic: Show a modal form freeze whole SDI application