Introduction
Many Windows Mobile developers writing in .NET have heard or read Chris Kraft's remarkable cycle of posts “30 Days of .NET [Windows Mobile Applications]”. I decided to start a cycle of translations of these posts, but to make it more interesting, the articles will provide not only the translation of the original post from Chris's blog with examples in C #, but also the translation of articles from Christopher Fairbairn - an enthusiast who decided to port all of Chris's examples to C ++ ! Currently, 8 out of 30 applications have been ported, but this is also very good.
When translating, I will try to minimize the irrelevant lyrical digressions, because the “water” in the translation becomes even more fluid and it becomes impossible to read :)
So let's get started - the first application, the
countdown to midnight .
')
Chris Kraft. C #
The original is
here .
One of the goals that I set for myself in this series of articles is to create an application on the day of publication. It does not leave me a choice, I'm not sure that I will have time, but it only adds fun. I have a life, but between family, friends, career, hobbies and dreams, there is not so much time as I sometimes would like. So developing one application a day, I’ll find out at the same time how much time I usually have free time.
How many minutes to midnight

A simple application, but I would venture to call it useful. At first, I thought that I would display the data in a format, for example, “2 hours 45 minutes 38 seconds”, but I decided that it was too simple, so I would use progress bars because they would add, say, a little "Weight".
But even after using progress bars, the app looked too sterile. Using one of the palettes from the site
http://www.colourlovers.com/ , I painted the application a little.
Very quickly, I realized that there is a small problem. From my point of view, perhaps subjective, the progress bar was wrong.
progressBarHours.Value = timeSpan.Hours; should have been
progressBarHours.Value = 24 - timeSpan.Hours; . As soon as I made this change, everything immediately fell into place.
Upper progress bar did not please me. It should have shown the total time until the end of the day, but there was not enough room for one more headline. There is a saying "the best is the enemy of the good." I understand it so that
if you always try to strive to achieve the ideal, nothing good will ever come out of it . As a result, I broke the form into logical sections by setting different colors of the background at the bottom panels.
All that remained to do was the
total number of minutes remaining . Depending on the calculations used, sometimes it was something like "
X.666666666 of 1440 total minutes left ". Fortunately, there is a simple solution - custom number formatting:
timeSpan.TotalMinutes.ToString ("#. 0") .
Note translator: In the original, there is no code insertion, however I put it (everything else is done with the mouse in the studio):
private void timer_Tick( object sender, EventArgs e)
{
TimeSpan timeSpan = DateTime .Now.Date.AddDays(1) - DateTime .Now;
labelHours.Text = string .Format( "{0} of 24 hours left" , timeSpan.Hours);
labelMinutes.Text = string .Format( "{0} of 60 minutes left" , timeSpan.Minutes);
labelSeconds.Text = string .Format( "{0} of 60 seconds left" , timeSpan.Seconds);
labelTotalMinutes.Text = string .Format( "{0} of 1440 total minutes left" ,
timeSpan.TotalMinutes.ToString( "#.0" ));
labelTotalSeconds.Text = string .Format( "{0} of 86400 total seconds left" ,
timeSpan.TotalSeconds);
progressBarTotal.Value = 86400 - ( int ) timeSpan.TotalSeconds;
progressBarHours.Value = 24 - timeSpan.Hours;
progressBarMinutes.Value = 60 - timeSpan.Minutes;
progressBarSeconds.Value = 60 - timeSpan.Seconds;
progressBarTotalMinutes.Value = 1440 - ( int ) timeSpan.TotalMinutes;
progressBarTotalSeconds.Value = 86400 - ( int ) timeSpan.TotalSeconds;
}
* This source code was highlighted with Source Code Highlighter .
C # source code:
minutes2Midnight.zip .
Christopher Fairbairn. C ++
The original is
here .
Interface development
The easiest way to create a small C ++ application is to use the dialog-based interface.
As with
System.Windows.Forms based applications, in C ++ there is a clear separation between design and code. The design of one or more dialogs is in the resource file (* .rc), while the code is in * .cpp files. Each dialog resource gets its ID, for example IDD_MYDIALOG, which allows you to access it from code.
To display the dialog, we will use the
DialogBox API:
DialogBox (hInstance, (LPCSTR) IDD_MYDIALOG, NULL, MyDialogProc);
This call will display a dialog with the IDD_MYDIALOG identifier and wait for it to be closed. The last parameter is the name of the dialog procedure. The procedure you write will process the messages sent to the dialog box. These messages are similar to events and virtual methods of classes such as
System.Windows.Forms.Control .
The basic structure of the dialog procedure will be as follows:
INT_PTR CALLBACK MyDialogProc(HWND hDlg,
UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
// this is similar to the Load event so we
// can perform dialog initialisation code here
break ;
case WM_CLOSE:
// this is similar to the Close event so we
// can perform dialog shutdown logic here
break ;
...
}
}
* This source code was highlighted with Source Code Highlighter .
Headlines
The equivalent for
System.Windows.Forms.Label is
static control.
In order to interact with the control, placed in the dialogue, it is necessary to obtain its descriptor. Within a Win32 application, controls are a special form of a window, and controls are made of them by the fact that they have a parent window. To get the descriptor, we will use the
GetDlgItem method, passing as parameters the descriptor of our dialog and the identifier of the control that we assigned in the resource editor.
// Get the window handle for the control
// with an ID of IDC_MESSAGE
HWND hwndCtrl = GetDlgItem(hWnd, IDC_MESSAGE);
* This source code was highlighted with Source Code Highlighter .
After receiving the handle, we can send messages. This is equivalent to assigning properties to .net controls. In some cases, we even have helper functions that slightly simplify manipulations. For example, we can change the header text using the
SetWindowText function:
// Change the label to display "Hello World"
SetWindowText(hwndCtrl, L "Hello World" );
* This source code was highlighted with Source Code Highlighter .
Progress Bars
Interaction with progress bars is almost no different from interaction with static controls, with the only difference being that progress bars understand a different set of messages. For example, to set the minimum and maximum, we can send a
PBM_SETRANGE or
PBM_SETRANGE32 message as follows:
// Set the progress bar referenced by 'hWndCtrl'
// to have the range 25 to 75
SendMessage(hWndCtrl, PBM_SETRANGE, 0, MAKELPARAM(25, 75));
* This source code was highlighted with Source Code Highlighter .
Is it possible, looking in the documentation on PBM_SETRANGE and PBM_SETRANGE32, to understand why there are two ways to set a minimum and a maximum? Here is one of the clearest examples of what the Compact Framework abstracts from.
To set the current value of the progress, use the
PBM_SETPOS message:
// Set the progress bar referenced by 'hWndCtrl'
// to the value 45
SendMessage(hwndCtrl, PBM_SETPOS, 45, 0);
* This source code was highlighted with Source Code Highlighter .
Timers
Instead of just dragging the timer onto the form, the C ++ programmer should create a timer on his own:
// Create a timer with ID 1234 and
// an interval of 1000 milliseconds (1 second)
SetTimer(hWnd, 1234, 1000, NULL);
* This source code was highlighted with Source Code Highlighter .
When the timer is no longer needed, use the corresponding KillTimer function:
// Stop the timer with ID 1234
KillTimer(hWnd, 1234);
* This source code was highlighted with Source Code Highlighter .
As you can see from the example, timers are associated with a window, so every time the timer is triggered, the window receives a
WM_TIMER message, which is essentially equivalent to the
Timer.Tick event in .NET.
case WM_TIMER:
if (wParam == 1234)
{
// timer 1234's interval has occurred so
// we can do something here...
}
break ;
* This source code was highlighted with Source Code Highlighter .
Each timer is assigned its own identifier so that it can work with more than one timer. For these purposes, the WM_TIMER message is passed as a parameter to the timer identifier.
Coloring the background
For a logical separation of the interface, Chris colored the parts of the form in different colors. The easiest way to achieve the same is to process the
WM_PAINT message, which is sent by the system when it is time to draw the content. Draw 3 rectangles using the
FillRect method:
// Define a rectangle at x=40, y=10 with size 40x10
RECT rcBounds;
rcBounds.top = 10;
rcBounds.bottom = 20;
rcBounds.left = 40;
rcBounds.right = 80;
// Create a red brush and fill the
// area of the rectangle
HBRUSH hbrRed = CreateSolidBrush(RGB(255, 0, 0));
FillRect(hdc, &rcBounds, hbrRed);
DeleteObject(hbrRed);
* This source code was highlighted with Source Code Highlighter .
Graphical methods in general are called GDI (Graphical Drawing Interface) and you will notice that they have a lot in common with the
System.Drawing namespace. Compare
CreateSolidBrush and
System.Drawing.SolidBrush .
Time calculation
Due to the lack of an equivalent
System.DateTime structure, time will have to be calculated in more complex ways.
To get the current time, we will use the
GetLocalTime function, which will return the
SYSTEMTIME structure. This structure is not able to calculate anything on its own, so
let's use the
SystemTimeToFileTime function, which converts data into a
FILETIME structure, which is a 64-bit integer storing the number of 100-nanosecond intervals since January 1, 1601.
With this number, we can perform simple mathematical operations. For example, we can get how much time has passed since the beginning of the day, or how much is left to its end:
__int64 amount_of_today_past = current_time % ONE_DAY;
__int64 amount_of_today_left = ONE_DAY - amount_of_today_past;
* This source code was highlighted with Source Code Highlighter .
From the obtained value it is already quite easy to get hours, minutes and seconds. For example, the following calculation returns the same as
TimeSpan.Minutes :
__int64 minutes = (amount_of_today_left / ONE_MINUTE) % 60
* This source code was highlighted with Source Code Highlighter .
C ++ example can be downloaded here:
minutes2midnight.zip .