Wednesday, March 2, 2005

575.aspx

.NET CF Clipboard support and SP3

In the past I used keyboard emulation to do cut and paste on the Pocket PC. But, after one of the latest .NET Compact Framework service packs (I think it was SP3) it does not work any more. I cannot even use Ctrl+C, Ctrl+V, Ctrl+X with the keyboard :-( Removing functionality with service packs should be banned by law.


I threw out my old code and used the APIs to get full cut and paste support in my .NET Compact Framework applications. I decided to keep it simple and call the APIs passing the currently active text box as an argument instead of inheriting from, and extending, the built in text box.



UI source code


private void menuItemCopy_Click(object sender, System.EventArgs e)


{


      pocketone.UI.Clipboard.Copy(getActiveTextBox());


}


private void menuItemPaste_Click(object sender, System.EventArgs e)


{


      pocketone.UI.Clipboard.Paste(getActiveTextBox());


}


 


private void menuItemUndo_Click(object sender, System.EventArgs e)


{


      pocketone.UI.Clipboard.Copy(getActiveTextBox());


}


 


private void menuItemSelectAll_Click(object sender, System.EventArgs e)


{


      getActiveTextBox().SelectAll();


}


 


private void menuItemCut_Click(object sender, System.EventArgs e)


{


      pocketone.UI.Clipboard.Cut(getActiveTextBox());


}


 


/// <summary>


/// Get the currently active textbox


/// </summary>


/// <returns></returns>


private TextBox getActiveTextBox()


{


      TextBox activeTextBox = null;


      foreach (Control ctrl in this.Controls)


      {


            if (ctrl is TextBox)


            {


                  if (ctrl.Focused)


                  {


                        activeTextBox = (TextBox) ctrl;


                        break;


                  }


            }


      }


 


      return activeTextBox;


}



Note: Make sure you disable the copy/paste etc menus if no TextBox has the focus (or add error handling). Something like this does the trick:


private void menuItemEdit_Popup(object sender, System.EventArgs e)


{


      bool enableOperations = (null != getActiveTextBox());


      this.menuItemCopy.Enabled = enableOperations;


      this.menuItemCut.Enabled = enableOperations;


      this.menuItemPaste.Enabled = enableOperations;


      this.menuItemSelectAll.Enabled = enableOperations;


}



Clipboard class source code


/// <summary>


/// The Clipboard class is based on code from


/// http://www.opennetcf.org/Forums/topic.asp?TOPIC_ID=125


/// </summary>


public class Clipboard


{


     


      #region Win32 API ------------------------------------------------------------


      private const uint CF_UNICODETEXT   = 13;


 


      [DllImport("Coredll.dll")]


      private static extern bool OpenClipboard(IntPtr hWndNewOwner);


 


      [DllImport("Coredll.dll")]


      private static extern bool CloseClipboard();


 


      [DllImport("Coredll.dll")]


      private static extern bool EmptyClipboard();


 


      [DllImport("Coredll.dll")]


      private static extern bool IsClipboardFormatAvailable(uint uFormat);


 


      [DllImport("Coredll.dll")]


      private static extern IntPtr GetClipboardData(uint uFormat);


 


      [DllImport("Coredll.dll")]


      private static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);


 


      [DllImport("Coredll.dll")]


      private static extern IntPtr LocalAlloc(int uFlags, int uBytes);


      #endregion -------------------------------------------------------------------


 


      #region Internal support functions


      private static IntPtr hMem = IntPtr.Zero;      


 


      /// <summary>


      /// Copy data from string to a pointer


      /// </summary>


      /// <param name="dest"></param>


      /// <param name="src"></param>


      private unsafe static void CopyToPointer(IntPtr dest, string src)


      {


            int x;


            char* pDest = (char*) dest.ToPointer();


 


            for (x = 0; x < src.Length; x++)


            {


                  pDest[x] = src[x];


            }


            pDest[x] = '\0';  // Add the null terminator.


      }


 


      /// <summary>


      /// Convert a pointer to string


      /// </summary>


      /// <param name="src"></param>


      /// <returns></returns>


      private unsafe static string ConvertToString(IntPtr src)


      {


            int x;


            char* pSrc = (char*) src.ToPointer();


            StringBuilder sb = new StringBuilder();


 


            for (x = 0; pSrc[x] != '\0'; x++)


            {


                  sb.Append(pSrc[x]);


            }


            return sb.ToString();


      }


      #endregion


 


      #region Public methods


      /// <summary>


      /// Check if data is available on the clipboard


      /// </summary>


      public static bool IsDataAvailable


      {


            get


            {                      


                  return IsClipboardFormatAvailable(CF_UNICODETEXT);


            }


      }


 


      /// <summary>


      /// Set data on the clipboard


      /// </summary>


      /// <param name="strText"></param>


      /// <returns></returns>


      public unsafe static bool SetData(string strText)


      {


            if (OpenClipboard(IntPtr.Zero) == false)


            {


                  return false;


            }


 


            hMem = LocalAlloc(0, ((strText.Length + 1) * sizeof(char)));


            if (hMem.ToInt32() == 0)


            {


                  return false;


            }


 


            CopyToPointer(hMem, strText);


 


            EmptyClipboard();


 


            SetClipboardData(CF_UNICODETEXT, hMem);


 


            CloseClipboard();


 


            return true;


      }


 


      /// <summary>


      /// Get data from the clipboard


      /// </summary>


      /// <returns></returns>


      public static string GetData()


      {


            IntPtr hData;


            string strText;


 


            if (IsDataAvailable == false)


            {


                  return null;


            }


 


            if (OpenClipboard(IntPtr.Zero) == false)


            {


                  return null;


            }


 


            hData = GetClipboardData(CF_UNICODETEXT);


            if (hData.ToInt32() == 0)


            {


                  return null;


            }


 


            strText = ConvertToString(hData);


 


            CloseClipboard();


 


            return strText;


      }


 


      public static void Cut(TextBox txtBox)


      {


            // Copy the data to the clipboard


            SetData(txtBox.SelectedText);


 


            // Remove selected text


            txtBox.SelectedText = "";


           


      }


                 


      public static void Copy(TextBox txtBox)


      {


            // Copy the data to the clipboard


            SetData(txtBox.SelectedText);            


      }


 


      public static void Paste(TextBox txtBox)


      {                


            if (IsDataAvailable)


            {


                  txtBox.SelectedText = GetData();


            }


           


      }


      #endregion
}

1 comment: