Solution for POOM Linker Error

April 4, 2009

I was trying to build sample code from MSDN that displays the Pocket Outlook version and demonstrates  POOM initialization and basic usage on interfaces. I copied and pasted the code into a cpp file of a sample Win32 Smart device project.  Expecting that I am all done, I gave a build. But the build failed and the linker threw the following error messages.

Sample.obj : error LNK2001: unresolved external symbol CLSID_Application
Sample.obj : error LNK2001: unresolved external symbol IID_IPOutlookApp

Quick google search didn’t get any useful results until I tried the following.

Solution

The solution was to replace #define INITGUID with #include <initguid.h> and the build passed.

Original Sample code from MSDN

#define INITGUID  // Replace this by #include <initguid.h>
#include <windows.h>
#include <pimstore.h>

HRESULT hr;
IPOutlookApp * polApp;

// Initialize COM for Pocket Outlook.
if (FAILED(CoInitializeEx(NULL, 0))) return FALSE;

// Get the application object.
hr = CoCreateInstance(CLSID_Application,
NULL,
CLSCTX_INPROC_SERVER,
IID_IPOutlookApp,
(LPVOID*)&polApp);
if (FAILED(hr)) return FALSE;

// Log on to Pocket Outlook.
hr = polApp->Logon(NULL);
if (FAILED(hr)) return FALSE;

// Get the version and display it in a message box.
BSTR pwszVersion = NULL;
polApp->getVersion(&pwszVersion);
MessageBox(NULL, pwszVersion, TEXT(“POOM Version”), MB_SETFOREGROUND |
MB_OK);

// Free the version string.
SysFreeString(pwszVersion);
// Note: For Palm-size PC version 1.0 use the Application method:
// polApp->SysFreeString(pwszVersion).

// Log off and release the application object.
polApp->Logoff();
polApp->Release();
return TRUE;


Windows Mobile Phone Signal Strength

March 9, 2009

There is no API to determine the current signal strength of the phone radio on a Windows Mobile Phone Device. But as the signal value changes, its updated in the registry at the following location.

[HKEY_LOCAL_MACHINE\System\State\Phone]

Signal Strength Raw” value under the above key stores signal strength value in percentage (0 – 100).

You might want to know in your application when signal strength status changes.  Polling registry is a resource intensive operation and should be avoided. Instead you can use RegistryNotifyCallback function provided by State and Notifications Broker mechanism. This powerful feature is available since WM 5.0 and gives applications an easy way to get notified when a particular registry value changes. Read more about it in MSDN.

http://msdn.microsoft.com/en-us/library/aa455748.aspx


Programmatically capture images with Camera application

March 6, 2009

While developing an application I found that following methods can be used to launch the Camera capture application.

I have seen the following code work on WM 5.0 device:

SHELLEXECUTEINFO ExecInfo = {0};
ExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ExecInfo.lpFile = L”\\windows\\pimg.exe”;
ExecInfo.lpParameters = L”-camerakey”;
ExecInfo.lpVerb = L”open”;
ShellExecuteEx(&ExecInfo);

And following code on WM 6.0 device:

void ShowCameraCapture()
{

SHCAMERACAPTURE shcc;

// Set the SHCAMERACAPTURE structure.
ZeroMemory(&shcc, sizeof(shcc));
shcc.cbSize = sizeof(shcc);
shcc.hwndOwner = hwndOwner;
shcc.pszInitialDir = NULL;
shcc.pszDefaultFileName = NULL;
shcc.pszTitle = TEXT(“PK Camera”);
shcc.VideoTypes = CAMERACAPTURE_VIDEOTYPE_ALL;
shcc.nResolutionWidth = 0;
shcc.nResolutionHeight = 0;
shcc.nVideoTimeLimit = 0;
shcc.Mode = CAMERACAPTURE_MODE_STILL;

// Launch the Camera Capture screen
SHCameraCapture(&shcc);

}

You can fillup the fields of SHCAMERACAPTURE structure for controlling many aspects of camera operations. Look into MSDN for details.


How to show Control Panel applets on Windows Mobile?

February 7, 2009

Windows Mobile Control Panel applets are normal dlls renamed with special extension .cpl. They are actually loaded by ctlpnl.exe process.

Following code snipped is what you need if you want to show a Control Panel applet from your program. This way you make it easy for your user to change desired settings, without any “complex” navigation.

BOOL ShowControlPanelApplet(int id)
{
TCHAR    szParams[32];
SHELLEXECUTEINFO execinfo = {0};
memset(&execinfo, 0, sizeof(execinfo));
execinfo.cbSize=sizeof(execinfo);
execinfo.lpFile=TEXT(“\\windows\\ctlpnl.exe”);
execinfo.lpVerb=TEXT(“open”);
// Id value determines which control applet will be launched
// For e.g. 23 for bluetooth applet
wsprintf(szParams, L”cplmain.cpl,%d”, id);
execinfo.lpParameters = szParams;
BOOL bRet=ShellExecuteEx(&execinfo);
return bRet;
}

The parameter id refers to the control panel applet that you want to show. Below is the table of id values and the corresponding applet names.

Control Panel Applet Id Values

1    Password
2    Owner Information
3    Power
4    Memory
5    About
6    Brightness
7    Screen
8    Input
9    Sounds & Notifications
10    Remove Programs
11    Menus
12    Buttons
13    Today
14
15    Beam
16    Clocks & Alarms
17    Configure Network Adapters
18    Regional Settings
19    Connections
20
21
22    Manage Certificates
23    Bluetooth
24    Error Reporting
25    GPS Settings
26
27    USB to PC


Launch application with ShellExecuteEx API

January 7, 2009

It easy to launch an application and pass parameters using ShellExecuteEx API.  Following is a wrapper which prepares SHELLEXECUTEINFO structure and then calls ShellExecuteEx.

BOOL LaunchApplication(TCHAR* pStrPath, TCHAR* pStrParams)
{
SHELLEXECUTEINFO    shell_exec_info = {0};
shell_exec_info.cbSize = sizeof(SHELLEXECUTEINFO);
shell_exec_info.lpVerb = L”open”;
shell_exec_info.lpFile = pStrPath;
shell_exec_info.lpParameters = pStrParams;
shell_exec_info.fMask = SEE_MASK_NOCLOSEPROCESS;
return ShellExecuteEx(&shell_exec_info);
}

Another way which is more powerful but could be more complicated is to use CreateProcess API.


Programatically create icons from bmp, jpg, png, gif files in your native Windows Mobile applications

December 17, 2008

This post show how you can create and load icons (HICON) from bmp, png, jpg, gif files in your Windows  Mobile applications. Sample code here assumes that source files have 32×32 dimensions and generated icons will also be on same dimensions.

Procedure:

1. Load the source image file into memory and get HBITMAP handle. To accomplish this use GetBitmapHandle function below.

HBITMAP GetBitmapFromFile(TCHAR* pFileName)
{
HBITMAP hbm = NULL;
OSVERSIONINFO osverinfo = {0};

// Get OS version
GetVersionEx(&osverinfo);

if (osverinfo.dwMajorVersion < 4)
{
hbm = SHLoadImageFile(pFileName);
if (hbm == NULL)
{
hbm = SHLoadDIBitmap(pFileName); // works only for bmp
}
}
else
{
// Use imaging library
IImagingFactory *pImgFactory = NULL;
IImage *pImage = NULL;

// Initialize COM
CoInitializeEx(NULL, COINIT_MULTITHREADED);

// Create the imaging factory.
if (SUCCEEDED(CoCreateInstance (CLSID_ImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IImagingFactory,
(void **)&pImgFactory)))
{
//// Load the image from the JPG file.
if (SUCCEEDED(pImgFactory->CreateImageFromFile(pFileName, &pImage)))
{
// Draw the image.
RECT rc = { 0, 0, 32, 32};
// Get the Desktop HDC
HDC hDC = GetDC(NULL);

// Create Compatible DC and Bitmap
HDC memDC = CreateCompatibleDC ( hDC );
hbm = CreateCompatibleBitmap ( hDC, 32, 32 );

// Select HBITMAP into memory DC
SelectObject ( memDC, hbm);

// Draw the image on the memDC
pImage->Draw(memDC, &rc, NULL);

// Release desktop DC
ReleaseDC(NULL, hDC);

pImage->Release();
}

pImgFactory->Release();
}
// Ununitialize COM
CoUninitialize();
}

// return the HBITMAP handle
return hbm;
}

2. Fillup ICONINFO strcuture and call CreateIconIndirect() API to retrieve HICON handle.

// Create an icon
ICONINFO iconinfo = {0};
iconinfo.fIcon = TRUE;
iconinfo.hbmMask  = hBitmap;
iconinfo.hbmColor = hBitmap;

HICON hCustomIcon = CreateIconIndirect(&iconinfo);

// Use hCustomIcon any way you want…..


Programmatically display system tray icon on Windows Mobile

December 13, 2008

As a Windows Mobile user you would see have some application specific icons near to the bottom right corner of the Today screen. It give users ability to directly launch the application or show an menu with more choices.

Tray icons on Today screen (Dell Axim)

Tray icons on Today screen (Dell Axim)

This post discusses the steps and code to put your own icon in the system tray.  I will also provide a solution to a common issue with Windows Mobile whereby its not easy to know the coordinates of the icon or the coordinates where the user might have tapped within the tray area.

okay…I will take an example of a Win32 native application. The concepts will hold good even if you are programming with some other framework.

1. Declare some variables and function prototypes

// some required defines
#define WM_SYSTRAY_MSG    WM_USER+1
#define ID_TRAY            1

// some variables
static NOTIFYICONDATA    g_structNotifyIconData = {0};
static HWND                g_hWndMain = NULL;
static HWND                g_hWnd = NULL;
static WNDPROC            g_fnProc = NULL;
static DWORD            g_dwTapPos = 0;

LRESULT DesktopExplorerWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

2. Implement a wrapper function to show and hide tray icon.

BOOL ShowTrayIcon(HWND hWnd, BOOL bShowIcon)
{
BOOL bRet = FALSE;

g_structNotifyIconData.cbSize = sizeof(NOTIFYICONDATA);
g_structNotifyIconData.hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_SHOWTRAYICON));
g_structNotifyIconData.hWnd = hWnd;
g_structNotifyIconData.uCallbackMessage = WM_SYSTRAY_MSG;
g_structNotifyIconData.uFlags = NIF_MESSAGE | NIF_ICON;
g_structNotifyIconData.szTip[0] = ”;
g_structNotifyIconData.uID = ID_TRAY;

if (bShowIcon)
bRet = Shell_NotifyIcon(NIM_ADD, &g_structNotifyIconData);
else
bRet = Shell_NotifyIcon(NIM_DELETE, &g_structNotifyIconData);

return bRet;
}

Above function fills up fields in NOTIFYICONDATA structure, setting the icon resource handle, parent window handle, callback message identifier, flags specifying that uCallbackMessage and icon information is being set and an user defined ID value.

3. Call ShowTrayIcon function in WM_CREATE handler

In the WM_CREATE  handler portion of the main WndProc function, call ShowTrayIcon(hWnd, TRUE).

case WM_CREATE:

ShowTrayIcon(hWnd, TRUE);

4. Add handler for WM_SYSTRAY_MSG

WM_SYSTRAY_MSG will be sent to the main window procedure (WndProc) when the user taps or clicks on the icon. We must add the following code to make some good use of the icon.

switch (message)
{
case WM_SYSTRAY_MSG:
{
switch (lParam)
{
case WM_LBUTTONDOWN:
if (ID_TRAY == wParam)
{
BOOL bRet = FALSE;
POINT pt = {0};
HMENU hTrayMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_TRAY_MENU));
if (hTrayMenu)
{
HMENU hSubMenu = GetSubMenu(hTrayMenu, 0);
pt.x = LOWORD(g_dwTapPos);
pt.y = HIWORD(g_dwTapPos);
bRet = TrackPopupMenu(hSubMenu, TPM_CENTERALIGN | TPM_BOTTOMALIGN, pt.x, pt.y, 0, hWnd, NULL);
dwError = GetLastError();
DestroyMenu(hSubMenu);
DestroyMenu(hTrayMenu);
}
}
}
}
break;

Here we know that user has tapped on the icon area. As a result we can do anything that we might want. Here I an showing up a popup menu using TrackPopupMenu API. g_dwTapPos variable contains the x & y position where the user tapped on the system tray area. We will see later how we get the information in g_dwTapPos. Note that GetCursorPos() does not get us this position value on Windows Mobile whereas it works on Windows desktop.

5. Getting the tap coordinates on system tray icon

One way I found to know the coordinates where the user tapped or clicked on the taskbar is to subclass the DesktopExplorerWindow and trap WM_CANCELMODE message. In the handler for WM_CANCELMODE, calling GetMessagePos() will return the position into a g_dwTapPos variable.

//
// DesktopExplorerWindow
//
LRESULT DesktopExplorerWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// Trap WM_CANCELMODE message
// This will get us the point at which tap occurred
case WM_CANCELMODE:
g_dwTapPos = GetMessagePos();
break;
}

return ::CallWindowProc(g_fnProc, hWnd, msg, wParam, lParam);
}

BOOL HookDesktopExplorerWindow()
{
if(g_fnProc)
return FALSE;

g_hWnd = ::FindWindow(_T(“DesktopExplorerWindow”), NULL);
if(g_hWnd)
{
g_fnProc = (WNDPROC)::SetWindowLong(g_hWnd, GWL_WNDPROC, (LONG)DesktopExplorerWindowProc);
}

return g_hWnd != NULL;
}

BOOL FreeDesktopExplorerWindow()
{
if(!g_fnProc)
return FALSE;

::SetWindowLong(g_hWnd, GWL_WNDPROC, (LONG)g_fnProc);
g_fnProc = NULL;

return TRUE;
}

HookDesktopExplorerWindow can be called from WM_CREATE handler in main Window procedure before calling ShowTrayIcon. FreeDesktopExplorerWindow can be called from WM_DESTROY handler in main Window procedure.

See below how the icon and popup menu shows up in my sample application.

Sample application showing System Tray Icon

Sample application showing System Tray Icon


Setting ES_MULTILINE of a CEditView derived class

December 5, 2008

CEditView class provides functionality of a Windows edit control to MFC applications. If ES_MULTILINE style is set, the edit control shows as many lines as possible to display the embedded text. Otherwise the whole text string is shown on the first line and if required, horizontal scrollbar is also shown.

ES_MULTILINE is one of those edit control styles which can not be changed if an instance of the class is already created. Basically there is no easy way to turn this style on and off once the object has been created. If your class is derived from CEditView and you want to turn on this style, override the PreCreateWindow method of the base class and modify the style field to set ES_MULTILINE.

BOOL CPreView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Add your specialized code here and/or call the base class
cs.style |= ES_MULTILINE | ES_AUTOVSCROLL;
return CEditView::PreCreateWindow(cs);
}

Since derived class implementation is called before the base class implementation, the style is set before the object is created. This method can be used to set other styles also.


Where do I find RAPI header files and libs?

November 15, 2008

To use Remote API (RAPI) calls in your desktop application, you must include rapi.h or rapi2.h and link to rapi.lib. But these are not referred by standard paths of the Windows Mobile SDK.

Locations of these files has changed over time with SDK releases.

WM 6.0 SDK:

\Program Files\Windows Mobile 6 SDK\Activesync\inc
\Program Files\Windows Mobile 6 SDK\Activesync\Lib

WM 5.0 SDK R2

\Program Files\Windows Mobile 5.0 SDK R2\Samples\PocketPC\ActiveSync\Inc
\Program Files\Windows Mobile 5.0 SDK R2\Samples\PocketPC\ActiveSync\Lib

WM 5.0 SDK

\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Pocket PC SDK\Activesync\Inc
\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Pocket PC SDK\Activesync\Lib

As you see rapi header and lib files are always located under ActiveSync subfolder. It is because ActiveSync must be installed on the target computer for RAPI functions to work.  Installation of ActiveSync installs rapi.dll which actually implements all RAPI functions. It’s always good to confirm the presence of rapi.dll before making any RAPI calls.


A quirk with Visual Studio 2008 Resource Editor

November 1, 2008

Currently I am working on a MFC application (Yes..I like using MFC and it has improved a lot with Visual Studio 2008. I can talk a lot about MFC but I will keep it for some other time).

For this application I used AppWizard to generate skeleton code for the SDI application. One of the first things I wanted to change was the text for File menu and texts for menu items under this menu. I opened the .rc file in resource editor and went to the File menu, selected and right-clicked on it and opened the Properties window. There I changed value of Caption field from File to Topic. I saved the files and hit the build button. I saw the Compiling Resources message on the build output pane and was sure that the job was done. Once build got over, I launched the program and could not believe what I saw. Menu bar text still showed File instead of Topic.

I quickly opened the .rc file in notepad and verified that the text had actually changed from File to Topic. I had no idea.

I tried changing the text for menu items and they also didn’t seem to change. What was going on there?

Workaround

Looking for the solution, I got this workaround. I will use this as long as I don’t get the real solution.

1. Workaround is to change the ID of any menu item under File menu. Say, ID_FILE_NEW to ID_HELLO_NEW.

2. Save the resources and perform the build.

3. Launch the application. You should see the new text taking effect.

4. You can now revert the changed ID to original one and again perform the build.