Thursday 8 September 2011

.Net custom control locks up when losing focus

Today I had to solve an interesting problem.

If a DataGridView, has the focus and is embedded in a custom control which is hosted by a native windows or MFC dialog, and the Dialog loses focus then the app locks up.

This happens because the focus management system is looking for the control which is losing the focus but can't find it.

The symptoms are 100% CPU usage (on one core) and if you use Spy or Spy++ you will see a flood of WM_GETDLGCODE messages to the control.

The cure is to set the WS_EX_CONTROLPARENT extended style on the DataGridView. To do this handle the HandleCreated event for the DataGridView and add the WS_EX_CONTROLPARENT extended style. Eg

void Grid_HandleCreated(object sender, EventArgs e)
{
   Control grid = sender as Control;
   if (grid != null && grid.Handle != IntPtr.Zero)
      NativeWindowAPI.ModifyStyleEx(grid.Handle, 0, NativeWindowAPI.WS_EX_CONTROLPARENT);
}

This uses my NativeWindowAPI class which I use to wrap Windows APIs.

class NativeWindowAPI
{
   [DllImport("User32.dll", CharSet = CharSet.Ansi)]
   extern static Int32 SetWindowLong(IntPtr hWnd, int nIndex, Int32 dwNewLong);
 
   [DllImport("User32.dll", CharSet = CharSet.Ansi)]
   extern static Int32 GetWindowLong(IntPtr hWnd, int nIndex);
 
   const Int32 GWL_EXSTYLE = -20;
 
   public const Int32 WS_EX_DLGMODALFRAME = 0x00000001;
   public const Int32 WS_EX_NOPARENTNOTIFY = 0x00000004;
   public const Int32 WS_EX_TOPMOST = 0x00000008;
   public const Int32 WS_EX_ACCEPTFILES = 0x00000010;
   public const Int32 WS_EX_TRANSPARENT = 0x00000020;
   public const Int32 WS_EX_MDICHILD = 0x00000040;
   public const Int32 WS_EX_TOOLWINDOW = 0x00000080;
   public const Int32 WS_EX_WINDOWEDGE = 0x00000100;
   public const Int32 WS_EX_CLIENTEDGE = 0x00000200;
   public const Int32 WS_EX_CONTEXTHELP = 0x00000400;
   public const Int32 WS_EX_RIGHT = 0x00001000;
   public const Int32 WS_EX_LEFT = 0x00000000;
   public const Int32 WS_EX_RTLREADING = 0x00002000;
   public const Int32 WS_EX_LTRREADING = 0x00000000;
   public const Int32 WS_EX_LEFTSCROLLBAR = 0x00004000;
   public const Int32 WS_EX_RIGHTSCROLLBAR = 0x00000000;
   public const Int32 WS_EX_CONTROLPARENT = 0x00010000;
   public const Int32 WS_EX_STATICEDGE = 0x00020000;
   public const Int32 WS_EX_APPWINDOW = 0x00040000;
   public const Int32 WS_EX_OVERLAPPEDWINDOW = (0x00000100 | 0x00000200);
   public const Int32 WS_EX_PALETTEWINDOW = (0x00000100 | 0x00000080 | 0x00000008);
   public const Int32 WS_EX_LAYERED = 0x00080000;
   public const Int32 WS_EX_NOINHERITLAYOUT = 0x00100000;
   public const Int32 WS_EX_LAYOUTRTL = 0x00400000;
   public const Int32 WS_EX_NOACTIVATE = 0x08000000;
 
   public static void ModifyStyleEx(IntPtr hWnd, Int32 remove, Int32 add)
   {
      Int32 res = GetWindowLong(hWnd, GWL_EXSTYLE);
 
      res &= ~remove;
      res |= add;
 
      SetWindowLong(hWnd, GWL_EXSTYLE, res);
   }
}

Thursday 18 August 2011

Detecting SQL Server from wix installer

When creating an installer using wix (3.5 or later) some times you need to detect if the machine you are installing on has some form of SQL Server installed.

The following check for a 32 bit version of various kinds of SQL Server

<property id="SQLEXPRESS2005">
<registrysearch id="SQLExpress2005"
   key="Software\Microsoft\Microsoft SQL Server\90\Tools\ClientSetup\CurrentVersion"
   name="CurrentVersion"
   root="HKLM"
   type="raw" win64="no">
</registrysearch>
</property>

<property id="SQLEXPRESS2008">
<registrysearch id="SQLExpress2008"
   key="Software\Microsoft\Microsoft SQL Server\Instance Names\SQL"
   name="SQLEXPRESS"
   root="HKLM"
   type="raw"
   win64="no">
</registrysearch>
</property>

<property id="SQLSERVER">
<registrysearch id="SQLServer2005orLater"
   key="Software\Microsoft\Microsoft SQL Server\Instance Names\SQL"
   name="MSSQL"
   root="HKLM"
   type="raw"
   win64="no">
</registrysearch>
</property>

The following check for a 64 bit version of various kinds of SQL Server

<property id="SQLEXPRESS2005X64">
<registrysearch id="SQLExpress2005x64"
   key="Software\Microsoft\Microsoft SQL Server\90\Tools\ClientSetup\CurrentVersion"
   name="CurrentVersion"
   root="HKLM"
   type="raw" win64="yes">
</registrysearch>
</property>

<property id="SQLEXPRESS2008X64">
<registrysearch id="SQLExpress2008x64"
   key="Software\Microsoft\Microsoft SQL Server\Instance Names\SQL"
   name="SQLEXPRESS"
   root="HKLM"
   type="raw"
   win64="yes">
</registrysearch>
</property>

<property id="SQLSERVERX64">
<registrysearch id="SQLServer2005x64orLater"
   key="Software\Microsoft\Microsoft SQL Server\Instance Names\SQL"
   name="MSSQL"
   root="HKLM"
   type="raw"
   win64="yes">
</registrysearch>
</property>

The magic lines are win64="yes" to force a search of the 64 bit registry and win64="no" to search the 32 bit registry.

12/03/2013 Note: I've just noticed that the above bits don't work with WIX 3.7. They need the case of the elements and attributes changing to camel case.

Thursday 27 January 2011

Setting the initial screen scaling in iPhone, iPod and iPad

To try and force the contents of a page to fit the width of an iPhone, iPod touch or iPad screen rather than scale the view to fit the window, add the following to the head section of an html page

<meta name="viewport" content="width=device-width" >

Friday 7 January 2011

Centering divs etc in CSS

Most objects in an html file can be centred using CSS simply by giving it a width and setting the margins to auto.

eg
.centered {
width: 80%;
margin-left:auto;
margin-right:auto;
}