SIP Button Icon disappears after closing dialogs in NETCF v2 applications

I thought this was something well known by the Mobile Dev Community, but maybe this is not true, since I’ve recently worked on a similar case.. so it may be worth sharing it here!

Under some special circumstances, which weren’t possible to reproduce for Technical Support and NETCF Dev Team at that time (about 2-3 years ago) – also because it was resolved in NETCF v3.5 – it happened that on NETCF v2 applications when a form gains back the focus after it was given to a dialog (MessageBox.Show() or anotherForm.ShowDialog() ), then _sometimes_ that little squared SIP icon at the middle of the menubar at the bottom suddenly disappeared.

That nasty problem was due to some faulty interaction between the OS and the .NET runtime, in any case no longer reproduced with v3.5. In some cases it had sufficed to reset this.Menu (or this.Parent.Menu) to the main menu. But that wasn’t the case in our service request… and also the simple refresh of the form at form’s OnActivated was NOT enough:

 protected override void OnActivated(EventArgs e)
{
     this.Menu = mainMnu;
     this.Refresh();

     base.OnActivated(e);
}

So we had to find a satisfactory temporary solution for NETCF v2 applications (migration to v3.5 was already in progress..). As usual I proposed to play with WINDOWS… :-) and we came up with the following propositions – the first one did the trick! (remember to add error-handling to whatever code I may suggest!!)

  1. FindWindow + ShowWindow

    1.  protected override void OnActivated(EventArgs e)
      {
          IntPtr hSip = FindWindow("MS_SIPBUTTON", "MS_SIPBUTTON");
          if ((hSip != IntPtr.Zero) /*&& (!IsWindowVisible(hSip))) */
          {
              bool retShowWin = ShowWindow(hSip, EShowWindow.SW_SHOW);
          }
          base.OnActivated(e);
      }
      
      
      [DllImport("coredll.dll", SetLastError = true)]
      private static extern IntPtr FindWindow(string _ClassName, string _WindowName);
      
      [DllImport("coredll.dll", SetLastError = true)]
      private static extern bool IsWindowVisible(IntPtr hWnd);
      
      [DllImport("coredll.dll", SetLastError = true)]
      private static extern bool ShowWindow(IntPtr hwnd, EShowWindow nCmdShow);
      
      private enum EShowWindow : uint
      { 
          SW_HIDE = 0,
          SW_SHOWNORMAL = 1,
          //SW_SHOWNOACTIVATE = 4,
          SW_SHOW           = 5 ,
          //SW_MINIMIZE       = 6,
          SW_SHOWNA         = 8 //,
          //SW_SHOWMAXIMIZED  = 11,
          //SW_MAXIMIZE           = 12,
          //SW_RESTORE            = 13
      }
      
    2.   
      
  2. FindWindow + BringWindowToTop

    1.  protected override void OnActivated(EventArgs e)
      {
          IntPtr hSip = FindWindow("MS_SIPBUTTON", "MS_SIPBUTTON");
          if ((hSip != IntPtr.Zero) /*&& (!IsWindowVisible(hSip))) */
          {
              bool retBringWin = BringWindowToTop(hSip);
          }
          base.OnActivated(e);
      }
      
      
      [DllImport("coredll.dll", SetLastError = true)]
      private static extern IntPtr FindWindow(string _ClassName, string _WindowName);
      
      [DllImport("coredll.dll", SetLastError = true)]
      private static extern bool IsWindowVisible(IntPtr hWnd);
      
      [DllImport("coredll.dll", SetLastError = true)]
      private static extern bool BringWindowToTop(IntPtr hWnd);
      
    2.   
      
  3. FindWindow + GetWindowLong

    1.  protected override void OnActivated(EventArgs e)
      {
          IntPtr hSip = FindWindow("MS_SIPBUTTON", "MS_SIPBUTTON");
          if ((hSip != IntPtr.Zero) /*&& (!IsWindowVisible(hSip))) */
          { 
              int style = GetWindowLong(hSip, GWL_STYLE);
              style |= WS_POPUP | WS_VISIBLE;
              int retSetWin = SetWindowLong(hSip, GWL_STYLE, style);
      
              int exstyle = GetWindowLong(hSip, GWL_EXSTYLE);
              exstyle |= WS_EX_ABOVESTARTUP | WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
              retSetWin = SetWindowLong(hSip, GWL_EXSTYLE, exstyle);
          }
          base.OnActivated(e);
      }
      
      
      [DllImport("coredll.dll", SetLastError = true)]
      private static extern IntPtr FindWindow(string _ClassName, string _WindowName);
      
      [DllImport("coredll.dll", SetLastError = true)]
      private static extern bool IsWindowVisible(IntPtr hWnd);
      
      private const int GWL_EXSTYLE = (-20);
      private const int GWL_STYLE = (-16);
      
      [DllImport("coredll", SetLastError = true)]
      private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
      
      [DllImport("coredll", SetLastError = true)]
      private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
      
      private const int
          WS_POPUP = unchecked((int)0x80000000),
          WS_VISIBLE = 0x10000000,
          WS_EX_ABOVESTARTUP = 0x20000000,
          WS_EX_NOACTIVATE = 0x08000000,
          WS_EX_TOOLWINDOW = 0x00000080,
          WS_EX_TOPMOST = 0x00000008;
      

Cheers,

~raffaele