Small Windows Mobile/CE application for debug or test purpose

Published:
Updated:
When I was a beginner in Windows Mobile programming, even for small test I used to create a single MFC dialog-based application with one button, and put my test code in the OnLButtonDown method.

For Pocket PC it worked fine, on some Windows CE device that, sometimes, didn't have the MFC DLLs, this application even didn't start. For the first Microsoft Smartphones I needed to use another wizard, another resource file, special control compilation definitions, and so, many configurations.

Now I know that it is unbelievably easy to make a small application without any GUI or just with a message box that can be compiled for any Microsoft Mobile or CE platform and simply works. It allows me to be concentrated on the research or testing task and do not waste time on GUI arrangements, and project configurations compilation definitions, pre-compiled headers and other wizard generated stuff.

Here are the steps to create this smallest Windows Mobile/CE application:

1. Begin a project in VS2005.


In Visual Studio, in the "File" menu choose "New" and then "Project..." (Picture 1).

Picture 1. Begin a project in VS2005.
In the wizard, in Visual C++ section choose "Smart Device" item and on this page choose "Win32 Smart Device Project" (Picture 2).

Picture 2. New Project Wizard.

Set the solution name and press "Ok".

2. Smart Device Project Wizard.


You see the standard wizard for the Smart Device project. Don't click on "Finish" - we need to change few default options (Picture 3).

Picture 3. Smart Device Project Wizard.

Choose "Platforms" and add the platforms you need. I always add Windows Mobile 5 and 6 and even "old-fashion" Smartphone 2003 (Picture 4).

Picture 4. Platforms.
Press "Next" to go to the "Application Settings" page (Picture 5).

Picture 5. Application Settings.
Check "Empty project" checkbox and now press "Finish" (Picture 6).

Picture 6. Application Settings. Empty project.

3. Add new item.


We have the solution and the project, but there are no source code files To make one, I'm adding (Picture 7) "New Item..." to the Source Files - choose "Add" in the popup menu and "New Items..." in the next popup.

Picture 7. Add new item.
Be sure that you have "Code" item selected in the "Visual C++" tree and "C++ File (.cpp)" in the Templates page. Set name for the cpp-file (for example, main) and press "Add" button (Picture 8).

Picture 8. Add new cpp-file.

4. Solution.


Empty source file added. We need to add few lines of code (Picture 9).

Picture 9. Solution.
Let's add the following source code:
#define WINVER _WIN32_WCE
                      
                      #include <windows.h>
                      #include "tracer.h"
                      
                      HINSTANCE	g_hInstance = NULL;
                      
                      int WINAPI WinMain(HINSTANCE hInstance,
                      				   HINSTANCE hPrevInstance,
                      				   LPWSTR    lpCmdLine,
                      				   int       nCmdShow)
                      
                      {
                      	UNREFERENCED_PARAMETER(hPrevInstance);
                      	UNREFERENCED_PARAMETER(lpCmdLine);
                      	UNREFERENCED_PARAMETER(nCmdShow);
                      
                      	// store the hInstance in global
                      	g_hInstance = hInstance;
                      
                      	return 0;
                      }

Open in new window


The code is trivial - the standard main function that does nothing, windows.h file included, and one define set WINVER _WIN32_WCE.

You can compile this code, launch the executable on your device or in emulator - the application does nothing and shows nothing. It is just a wrapper (or template) for your future test applications.

Note: if you use Pocket PC 2003, you need to make one change in the project settings. It is "Buffer Security Check" on "Code Generation" page in C/C++ section. The value of this field should be "No (/GS-)" (Picture 10).

Picture 10. Buffer security check settings for Pocket PC 2003.
For example this program will show the memory usage:

#define WINVER _WIN32_WCE
                      
                      #include <windows.h>
                      #include "tracer.h"
                      
                      HINSTANCE	g_hInstance = NULL;
                      
                      int WINAPI WinMain(HINSTANCE hInstance,
                      				   HINSTANCE hPrevInstance,
                      				   LPWSTR    lpCmdLine,
                      				   int       nCmdShow)
                      
                      {
                      	UNREFERENCED_PARAMETER(hPrevInstance);
                      	UNREFERENCED_PARAMETER(lpCmdLine);
                      	UNREFERENCED_PARAMETER(nCmdShow);
                      
                      	// store the hInstance in global
                      	g_hInstance = hInstance;
                      
                      	MEMORYSTATUS mem_status = { 0 };
                      	GlobalMemoryStatus(&mem_status);
                      
                      	WCHAR szText[MAX_PATH] = { 0 };
                      	_snwprintf(szText, MAX_PATH, L"Memory use: %d%", mem_status.dwMemoryLoad);
                      
                      	::MessageBox(NULL, szText, L"Test", MB_OK);
                      
                      	return 0;
                      }

Open in new window


Picture 11. Running application.
If you have a simple tracer, for example, as the one below:

#ifndef _TRACER_HEADER_
                      #define _TRACER_HEADER_
                      
                      #include <stdlib.h>
                      #include <wchar.h>
                      
                      inline void __cdecl Tracer(LPCWSTR lpszFormat, ...)
                      {
                      	va_list args;
                      	va_start(args, lpszFormat);
                      
                      	int nBuf = 0;
                      	WCHAR szBuffer[1024];
                      	ZeroMemory(szBuffer, 1024 * sizeof(WCHAR));
                      
                      	nBuf = _vsnwprintf(szBuffer+nBuf, 1024, lpszFormat, args);
                      	static HANDLE hFile = INVALID_HANDLE_VALUE;
                      	if (hFile == INVALID_HANDLE_VALUE) 
                      	{
                      		WCHAR szFileName[MAX_PATH];
                      		ZeroMemory(szFileName, MAX_PATH * sizeof(WCHAR));
                      		::GetModuleFileName(GetModuleHandle(NULL), szFileName, MAX_PATH);
                      		int nLength = lstrlen(szFileName);
                      		while (nLength > 0)
                      		{
                      			nLength--;
                      			if(szFileName[nLength] == TCHAR('.'))
                      				break;
                      		}
                      		szFileName[nLength + 1] = 0;
                      		wcsncat(szFileName, L"txt", MAX_PATH - 2);
                      		hFile = ::CreateFileW(szFileName, GENERIC_WRITE | GENERIC_READ,
                      			FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
                      		if (hFile != INVALID_HANDLE_VALUE) 
                      		{
                      			DWORD nErr = GetLastError();
                      			DWORD nWritten = 0;
                      
                      			SetFilePointer(hFile, 0, 0, FILE_END);
                      
                      			if (nErr != ERROR_ALREADY_EXISTS)
                      			{
                      				char szHeader[2] = { (char)0xFF, (char)0xFE };
                      				::WriteFile(hFile, szHeader, 2, &nWritten, NULL);
                      			}
                      
                      			::WriteFile(hFile, L" ", 1 * sizeof(WCHAR), &nWritten, NULL);
                      			WCHAR sz[2] = { WCHAR(13), WCHAR(10) };
                      			::WriteFile(hFile, sz, 4, &nWritten, NULL);
                      		}
                      	}
                      
                      	if (hFile != INVALID_HANDLE_VALUE) 
                      	{
                      		DWORD nLength = wcslen(szBuffer) * sizeof(WCHAR);
                      		DWORD nWritten = 0;
                      		::WriteFile(hFile, szBuffer, nLength, &nWritten, NULL);
                      		WCHAR sz[2] = { WCHAR(13), WCHAR(10) };
                      		::WriteFile(hFile, sz, 4, &nWritten, NULL);
                      		FlushFileBuffers(hFile);
                      	}
                      
                      #ifndef _WIN32_WCE
                      
                      	::OutputDebugStringW(szBuffer);
                      	::OutputDebugStringW(L"\r\n");
                      
                      #endif
                      
                      	va_end(args);
                      }
                      
                      
                      #endif

Open in new window


you can use it instead of the message box. For example, the following code will detect how many memory you can allocate on your device with function malloc():
#define WINVER _WIN32_WCE
                      
                      #include <windows.h>
                      #include "tracer.h"
                      
                      HINSTANCE	g_hInstance = NULL;
                      
                      int WINAPI WinMain(HINSTANCE hInstance,
                      				   HINSTANCE hPrevInstance,
                      				   LPWSTR    lpCmdLine,
                      				   int       nCmdShow)
                      
                      {
                      	UNREFERENCED_PARAMETER(hPrevInstance);
                      	UNREFERENCED_PARAMETER(lpCmdLine);
                      	UNREFERENCED_PARAMETER(nCmdShow);
                      
                      	// store the hInstance in global
                      	g_hInstance = hInstance;
                      
                      	MEMORYSTATUS mem_status = { 0 };
                      	GlobalMemoryStatus(&mem_status);
                      	Tracer(L"Total physical memory %d\n", mem_status.dwTotalPhys);
                      	Tracer(L"Memory usage %d\n", mem_status.dwMemoryLoad);
                      
                      	LPVOID p = NULL;
                      	DWORD nDelta = 1024 * 1024;
                      	DWORD nSize = 0;
                      	do 
                      	{
                      		if (p != NULL)
                      		{
                      			free(p);
                      			p = NULL;
                      		}
                      		nSize += nDelta;
                      		p = malloc(nSize);
                      		if (p != NULL)
                      			Tracer(L"p= %p, %d bytes allocated\n", p, nSize);
                      	} while(p != NULL);
                      
                      	if (p != NULL)
                      	{
                      		free(p);
                      		p = NULL;
                      	}
                      
                      	return 0;
                      }

Open in new window


The log-file made on the Windows Mobile 6 Classic emulator will show that you can allocate almost 30MB. HTC Diamond with Windows Mobile 6.1.4 allowed for such small application to allocate 26,214,400 bytes.

Please do not test this code under Windows CE 6.0: the memory management changed in this version and this code may cause a problem.
2
6,136 Views

Comments (2)

Kevin CrossChief Technology Officer
CERTIFIED EXPERT
Most Valuable Expert 2011

Commented:
Nice work, pgnatyuk!
You have my vote above.
evilrixEngineering Manager
CERTIFIED EXPERT

Commented:
Voted yes above.

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.