Summer is here, and this year we are lucky enough to have two interns – Jason and Nuo – working with us on the Windows Mobile SDK Content Publishing team. We’ve put these lucky individuals to work by asking them to create some Starter Kit code samples.
Over the next few months, I’ll encourage them to post about their adventures here on this blog. At the moment, they’re focusing on the technical side of their projects, but I hope they’ll start to talk a little more about themselves, and what life is like here at Microsoft as an intern.
But now, here is the first installment. Enjoy, and please feel free to leave them feedback!
Jason
My name is Jason Kim, a Programmer Writer intern at Microsoft Windows Mobile & Embedded Devices group.
For this summer, I am going to do a starter kit for Windows Mobile 6.
It will be a "Journal Manager" using AJAX, SQL CE, and .NET framework.
Features include addition of a new record, deletion of a record, viewing a record, and searching records.The most interesting part would be in searching, where the application would be able to handle keyword searches, *not just EXACT word match searches* and show the updated result at each keystroke.
It would be done using AJAX as the user interface, while data is stored in SQL, and manipulated by .net framework.
Here is the overall diagram on how this application would work:
The biggest issue is on the local server part. The application should not depend on external connections and somehow, local server must be created within the device to handle services.
So far, I have two findings and three options.
1 HTTPD (Web Server) : This is an optional component of Windows Mobile 6 SDK. However, there are limitations. Biggest short coming is the lack of support for server side scripting. So, I am not able to execute scripts on local device. (kind of beats my purpose…) I am still researching on any le-way to overcome this problem, but it seems highly unlikely I will find one. If anyone could help, that would be TERRIFIC.
2 Local Server Framework / Fake Server Framework : This is an included tool in the SDK. It should be able to provide local services for managed and native code. Anyways, so far, I have not had a huge success because it seems to lack a function that it should have (stated in documents,) namely FakeServer class’s SetRequestCallback function.
3 HTML CONTROL: If all above fails, HTML control would be the only way. Unless I give up on the AJAX on local server part.
Anyways, it is Friday and I am ready for a break. Any additional feature suggestions and/or solutions to my LOCAL SERVER mystery, feel free to let me know.
Nuo
Hi. This is Nuo Yan, a new intern from Content Publishing Team of Mobile and Embedded Devices Product Group. I’ve been in this team for about two weeks. Every team member is very nice – though I’ve met a lot of difficulties in the very beginning time, all of them offered their help to get me all set to start smoothly. I applied to be here this summer is because application development for Mobile and Devices is a new field to me. I never had similar experiences before and really want to learn something in this field. I’m also going to learn the process of technical content publishing, and learn more about Mobile Communication Business at Microsoft in general.
My project here during the summer is to develop a Windows Mobile starter kit. I choose to do an interesting Tic Tac Toe game with the new Windows Mobile Ink APIs provided in Windows Mobile 6 SDK. Since at the present time there is no managed code support for Windows Mobile Ink APIs yet, so I will do it in native C++ as a Win32 smart device application.
The basic idea of the project is to allow a user to play Tic Tac Toe with computer AI or another user by drawing X or O’s on the application interface.
After my computer has been all set up, I implemented a basic window, ink window (aka. signature area), the IInkOverlay API which is an Ink collector. By doing so user can draw ink on ink area of the screen.
The way I implemented IInkOverlay is really easy, like the sample in the SDK documentation. Declare one as global variable since many functions will need it. I declare an array of IInkOverlay* as global variable because I know I will need to use multiple ones in the future. Then after creating an ink window, I create an instance of the IInkOverlay object and do some error checking:
//create an instance of IInkOverlay object
hr = :: CoCreateInstance(CLSID_InkOverlay,
NULL,
CLSCTX_INPROC_SERVER,
IID_IInkOverlay,
(void **)&g_pInkOverlay[0])
// ensure there's no error
ASSERT(SUCCEEDED(hr));
Then attach it to the ink window and enable it:
//attach the IInkOverlay object to the ink
//child window, enable it, and make sure there is no error
hr = g_pInkOverlay[0]->put_hWnd((long)hWndInk);
hr = g_pInkOverlay[0]->put_Enabled(VARIANT_TRUE);
Now the user can write ink on the window.
In order to make recognition working, I created a function named DoRecognize(HWND hwnd). The mechanism of this function is easy to understand too. In it there needs to be an IInkDisp object, to store IInkStrokes objects; an IInkStrokes object, which is a collection of IInkStrokeDisp object; and a BSTR for storing the recognition result.
//an IInkDisp object, which is a container of strokes (point)
//data (IInkStrokes objects).
IInkDisp* pInkDisp = NULL;
//an IInkStrokes object, which is a collection of
//IInkStrokeDisp object.
IInkStrokes* pInkStrokes = NULL;
//The recognition result, stores in a string
BSTR StringRecognitionResult = NULL;
Then get ink from the global IInkOverlay object to the IInkDisp object:
//get ink from IInkOverlay object
//and place data in the IInkDisp object
g_pInkOverlay[0]->get_Ink(&pInkDisp);
//get the strokes in the IInkDisp object
//and place it into the IInkStrokes object
pInkDisp ->get_Strokes(&pInkStrokes);
//Get the best recognition result to the BSTR
pInkStrokes->ToString(&StringRecognitionResult);
Then use whatever way to display the BSTR, basic recognition is working.
After implementing basic recognition for one window, it’s time to extend it to multiple windows.
For the Tic Tac Toe game, there are several ways to implement the main game interface. Some examples: to implement 1 ink window, split it to 9 rectangles and implement 9 IInkOverlay objects; or to implement 9 child windows on a parent window, with 9 IInkOverlay objects.
Implementing 1 ink window definitely saves system resources, however, implementing 9 windows can make the implementation of game logic, screen size adaptation, etc fewer complexes and make the code easier to understand. As this project is a starter kit, a code sample, I decided to do it in the 9 windows way.
The first design of the recognition feature for multiple windows I made was to use a timer to trigger the recognition to begin. That is, after the user first writes something in a window accepts ink, timer begins to count and after a specific amount of time, recognition begins. However, after several tests I realized this will only work for 1 window but not for 9 (unless to make several timers and make code extremely messy). The reason is SetTimer and TimerProc functions both have fixed number of parameters. I don’t have a way to pass the IInkOverlay object attached to a specific window to the recognition function.
Then I changed the design to use event handlers. I use Remote Spy++ to watch what messages are sent when I write ink on the ink window. Surprisingly, they are just nothing more than some button down (WM_LBUTTONDOWN), mouse move (WM_MOUSEMOVE), and button up (WM_LBUTTONUP) messages. So I add some code to WM_LBUTTONUP event handler to call the recognition function. However, this caused a problem that DoRecognize function is called when WM_LBUTTONUP happened on every window of the program. I definitely don’t want it to go this way. I only want the function to be called when user writes something in 1 of the 9 ink windows. So I created a separate window class and a window procedure for all of the child windows, then call DoRecognize function under the child window procedure’s WM_LBUTTONUP clause. I use child window handler (hwnd) to differentiate which window the user writes on; and I added an integer parameter for DoRecognize function to enable DoRecognize to do recognition for the correct IInkOverlay object. Now DoRecognize(HWND hwnd) becomes DoRecognize(HWND hwnd, int c).
Then in DoRecognize function, I added a loop for attaching the 9 ink collector (IInkOverlay) objects to each child window as the following:
for(int i=0; i<9; i++)
{
//create IInkOverlay object
(void **)&g_pInkOverlay[i]);
//ensure there's no error
hr = g_pInkOverlay[i]->put_hWnd((long)hWndInk[i]);
//ensure no error
hr = g_pInkOverlay[i]->put_Enabled(VARIANT_TRUE);
}
By doing so, user can write ink strokes on all of the 9 ink areas. The recognition part of it doesn’t change much, except that the correct IInkOverlay object of the 9 need to be specified. Remember I had an array of 9 IInkOverlay objects, so I write the following code in DoRecognize:
g_pInkOverlay[c]->get_Ink(&pInkDisp);
Then basic recognition now works for all nine windows.
I was happy when I hit [F5] to run it and wrote an O on a ink window then it recognized well. However, when I tried to write X, it began recognition right after I wrote the first stroke. I realized what the problem was: WM_LBUTTONUP happens when the user finished writing the first stroke, and DoRecognition(hwnd) was called right away to begin recognition. I thought about several ways to solve this problem: 1. Have a global counter to determine the number of strokes the user writes, if it’s more than two, clear ink area; 2. Test for the first stroke of X and see what it can possibly recognizes, record these cases, then set DoRecognize(hwnd) to wait for the user to input the second stroke if it realizes the first stroke is in those possible cases; 3. Create additional inking objects, store the first stroke result, if it’s not o or O, then store the second stroke result and add them together to see whether it’s X or not.
After a careful thinking, the first way will not work. I implemented the second way at this time because the third way will have additional overheads for system resources and affect respond time for recognition. My current logic for control statements in DoRecognize(HWND hwnd) is like:
if (x, X, o or O)
clear ink window and proceed
else if (all the tested cases for possible recognition of X’s first stroke)
do nothing and tell user to continue writing
else
clear ink window and tell user only to write X or O’s
Currently this solution works well.
The next step will be implementing a basic user vs user game AI. There will be a lot of ways for doing that, and I will talk something about how I’m doing that in the next entry.
Let me know if you have any good idea and suggestion about the project.
Thanks,
Nuo Yan