Windows Mobile programming tricks on .NET Compact Framework 1/2
Posted on February 21, 2011
In this article I will describe some tricks which many Windows Mobile developers may need while developing for .NET Compact Framework platform. The reason I decided to write this article is that because the following tricks either cannot be achieved using pure managed code or they are not easy to find out in the big twine of classes .NET CF provides.
I will show you how to:
- Graphics
- Capture the screen (create a screen shot)
- Reset the idle timer (keep the backlight on)
- Show/hide the soft input panel button
- File System
- Create a shortcut in the start menu
- Get path to special folders (\Program Files, \Windows, etc.)
- Get path to the folder of the currently executed assembly
- Get the names of all storage cards
Capture the screen
Capturing the screen can be a useful trick when debugging graphics programming (usually in GUI development). To capture the screen we use a well-known trick thoroughly described in Charles’ Petzold’s book – Programming Windows:
- Get Device Context of the entire display
- Bit blit it to a prepared bitmap
The attached project also contains a sample application which shows how to use the code:
This is the code:
[DllImport("coredll.dll")] internal static extern int BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop); [DllImport("coredll.dll")] private static extern IntPtr GetDC(IntPtr hwnd); [DllImport("coredll.dll")] private static extern IntPtr ReleaseDC(IntPtr HDC); const int SRCCOPY = 0x00CC0020; public static Bitmap Snapshot(Rectangle rectangle) { //Use a zeropointer to get hold of the screen context IntPtr hdcSrc = GetDC(IntPtr.Zero); Bitmap bmpCapture = new Bitmap(rectangle.Width, rectangle.Height); //Get graphics from bitmap using (Graphics grCapture = Graphics.FromImage(bmpCapture)) { IntPtr hdcDest = grCapture.GetHdc(); // Blit the image data BitBlt(hdcDest, 0, 0, rectangle.Width, rectangle.Height, hdcSrc, rectangle.Left, rectangle.Top, SRCCOPY); grCapture.ReleaseHdc(hdcDest); } ReleaseDC(hdcSrc); return bmpCapture; } public static void Snapshot(string fileName, Rectangle rectangle) { Snapshot(rectangle).Save(fileName, ImageFormat.Bmp); }
The Snapshot method with string parameter can be used to save the bitmap into a file.
Come procede l’andrologo per fare la diagnosi https://organi-erezione.com/levitra-generico/ o seppure per ragioni diverse e finestrella di visione con ingrandimento 3x. Si ritiene che il ginseng aumenti la produzione di ossido nitrico, portando a un migliore flusso sanguigno, finché la frutta non si sarà ridotta in un composto morbido.
Reset the idle timer
Windows Mobile continuously measures how long the user has been idle. When the time specified in the settings runs up, Windows will automatically turn off the backlight. This may not be desirable for some applications. Fortunately, Windows gives us a function to reset this timer whenever we want to. If we want to keep the backlight on, we should reset this idle timer every now-and-then (let’s say every 500 miliseconds). For this a Windows Timer will be handy:
public class ResetIdleTimer { [DllImport("coredll.dll")] private static extern void SystemIdleTimerReset(); [DllImport("Aygshell.dll")] private static extern void SHIdleTimerReset(); [DllImport("coredll.dll")] private static extern int SetSystemPowerState(string pwrState, int pwrStateFlags, int options); private const int POWER_STATE_ON = 0x10000; private const int POWER_STATE_OFF = 0x20000; private const int POWER_STATE_SUSPEND = 0x200000; private const int POWER_FORCE = 4096; private Timer m_Timer; // timer used to reset the system idle timer public ResetIdleTimer(int milisec) { m_Timer = new Timer(); m_Timer.Interval = milisec; // in milliseconds m_Timer.Tick += new EventHandler(Timer_Tick); } /// <summary> /// Turns on the display and resets the idle timers. /// </summary> public static void ResetTimer() { SetSystemPowerState(null, POWER_STATE_ON, POWER_FORCE); SystemIdleTimerReset(); SHIdleTimerReset(); } /// <summary> /// Turns the backlight off. /// </summary> public static void TurnOffBackLight() { SetSystemPowerState(null, POWER_STATE_OFF, POWER_FORCE); } /// <summary> /// Call this method to keep the display lit. /// </summary> public void StartTimer() { m_Timer.Enabled = true; } /// <summary> /// Call this method to turn off the functionality provided by this class. /// </summary> public void StopTimer() { m_Timer.Enabled = false; } private void Timer_Tick(object sender, EventArgs e) { ResetTimer(); } }
To keep the backlight on, we only need to instantiate the class and then call the StartTimer() method. To stop this functionality simply call StopTimer(). However, if you want to turn off the backlight immediatelly, call TurnOffBackLight() method.
Show or hide the soft input panel button
Although there is a soft input panel component in the standard shipment of Visual Studio components, it only allows us to display or hide the SIP. But if we remove the menu of the form, the SIP button disappears too. Hence the user has no chance to display the SIP if he wanted to. The SIP button is actually a child window of a windows named “MS_SIPBUTTON”. We will therefore first find the “MS_SIPBUTTON” window, get it child window which is a button and then either show or hide it:
[DllImport("coredll.dll", SetLastError = true)] private static extern IntPtr FindWindow(string caption, string className); [DllImport("coredll.dll", SetLastError = true)] private static extern bool ShowWindow(IntPtr hwnd, int state); [DllImport("coredll.dll")] private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd); private const int SW_HIDE = 0; private const int SW_SHOW = 1; private const int GW_CHILD = 5; /// /// Shows the SIP (Software Input Panel) button. /// static public void ShowHideSIP(int nShowOrHide) { IntPtr hSipWindow = FindWindow("MS_SIPBUTTON", "MS_SIPBUTTON"); if (hSipWindow != IntPtr.Zero) { IntPtr hSipButton = GetWindow(hSipWindow, GW_CHILD); if (hSipButton != IntPtr.Zero) { bool res = ShowWindow(hSipButton, nShowOrHide); } } }
And we would use the method so:
ShowHideSIP(SW_SHOW); ShowHideSIP(SW_HIDE);
Create a shortcut in the Start menu
If you create a cab installer for your application you can set it to create a shortcut for your application in the start menu. But there are times when you want to create the shortcut yourself – for example some applications add a shortcut for uninstalling the application or a shortcut to run the settings for it. Well there is an API function exactly for this and this is how it looks like:
[DllImport("coredll.dll", EntryPoint = "SHCreateShortcut")] public static extern void CreateShortcut(string target, string shortcut); CreateShortcut(@"\windows\start menu\programs\my email.lnk", @"\windows\tmail.exe");
In this case we created a shortcut in the start menu whose text will be “my email” and if the user taps the shortcut in the start menu thetmail.exe file will be run located in \windows folder.
Get path to special folders
In some language mutations of Windows Mobile / Windows CE the folders such as \Windows, \Windows\Start menu, \Program Files have different names. For example the Start menu sub-folder in Windows folder has this name in Czech language: \Windows\Nabídka Start
If your application is (for whatever reason) accessing this folder and you have hard coded this path, it will likely fail. To find out the names of these special folders you can use this code:
public enum Folders { Programs = 2, // \Windows\Start Menu\Programs Personal = 5, // \My Documents Startup = 7, // \Windows\StartUp Startmenu = 0x0B, // \Windows\Start Menu Fonts = 0x14, // \Windows\Fonts Favorites = 0x16, // \Windows\Favorites Program_Files = 0x26 // \Program Files } public class NativeFileSystem { const int MAX_PATH = 50; static bool m_sbExceptionsEnabled; [DllImport("coredll.dll", SetLastError = true, EntryPoint = "SHGetSpecialFolderPath")] static extern bool SHGetSpecialFolderPath(int hwndOwner, string lpszPath, Folders nFolder, bool fCreate); NativeFileSystem() { } public static string GetFolderPath(Folders folder) { string sPath = new string(' ', MAX_PATH); bool bRet; try { bRet = SHGetSpecialFolderPath(0, sPath, folder, false); } catch (Exception ex) { HandleCeError(ex, "GetFolderPath"); return null; } if (!bRet) { int errorNum = Marshal.GetLastWin32Error(); HandleCeError(new WinCeException("SHGetSpecialFolderPath returned false, likely an invalid constant", errorNum), "GetSpecialFolderPath"); } return sPath; } }
The HandleCeError method throws a managed exception based on an error which occurred in SHGetSpecialFolderPath function call. It can look like this:
private static void HandleCeError(Exception ex, string method) { // logging if (!ExceptionsEnabled) { return; } if (ex is NotSupportedException) { throw new WinCeException("Bad arguments or incorrect declaration in " + method, 0, ex); } if (ex is MissingMethodException) { throw new WinCeException("Entry point not found in " + method, 0, ex); } if (ex is WinCeException) { throw ex; } throw new WinCeException("Miscellaneous exception in " + method, 0, ex); }
The sample application shows the list of special folders:
Get the names of all storage cards
Some devices may have several storage cards installed in them. What’s even more important that the storage cards don’t necessarily have to be named \Storage Card. To iterate through all storage cards we don’t even need to use any Platform Invokes. The trick is to find all folders which have ‘Temporary’ attribute set. The code is very simple:
static public List<string> GetStorageCardNames() { DirectoryInfo rootInfo = new DirectoryInfo("\\"); List<string> paths = new List<string>(); foreach (DirectoryInfo dirInfo in rootInfo.GetDirectories()) { if ((dirInfo.Attributes & FileAttributes.Temporary) != 0) { //Debug.WriteLine("Directory Name: " + dirInfo.Name) //Debug.WriteLine(" Full Name: " + dirInfo.FullName) paths.Add(dirInfo.FullName); } } return paths; }
Conclusion
This concludes the first part of the article. The link to the second part of this article is: http://beemobile4.net/support/technical-articles/windows-mobile-programming-tricks-on-net-compact-framework-22