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;

Advertisements

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