How to create Windows Mobile Shortcuts?

November 26, 2008

Shortcuts makes it easy for users to launch applications. Shortcut files have “.lnk” extension and they take up very little storage space. Shortcuts contain information about the application to launch along with any parameter information. They are really handy if predetermined values need to be passed to the application as command line parameters.

[Update] Use MakeShortcut tool from http://www.simprovision.com to create Windows Mobile shortcuts and that too, right from your desktop. Read on if you want to do it on your device.

How to create a Shortcut on the device

- Run Microsoft ActiveSync on your desktop and establish connection with the PDA.
- Right-click on the ActiveSync icon on the desktop Windows taskbar and Click Explore. This will bringup a window showing contents of Mobile Device folder
- Now goto the folder where the executable resides
- Rightclick on the file (say ABC.exe) and a menu pops up. Select Create Shortcut menu item
- This will generate a shortcut (.lnk) file with the name like “Shortcut to ABC.exe”
- You can rename the shortcut to anything that you like
- Move or copy the shortcut if you want it anywhere else on the device

How shortcuts work (Tech stuff for developers)

This section describes the format of a shortcut file. Simply copy the .lnk file to the desktop and open it in your favorite text editor. I use Notepad. The content in the .lnk file will have the following format.

xx#”\{APPLICATION_PATH}{OPTIONAL PARAMETERS}”

where xx is number of characters in the above text excluding xx#.

For e.g.

18#”\Windows\abc.exe”

where 18 is the count of characters after pound character (#) and \Windows\abc.exe is the target application.


Creating diagrams with Dia

November 23, 2008

If you are looking for a tool like Visio for creating diagrams but don’t want to spend any money, well…there is an alternative. Dia is a great tool for creating diagrams like UML, flowcharts or entity relationships. It is developed with GTK+ and is supported on Windows, Linux and Unix. Check out this website for more details and to download the installer for Windows.

UML diagram example (Click to enlarge)

UML diagram example

Tool palette window

Tool palette window


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.


Windows Mobile 6.5

November 14, 2008

To compensate for the delay of Windows Mobile 7, Microsoft is planning to release Windows Mobile 6.5 sometime in second half of 2009. Presumably the upcoming version will enhance the user experience and will be aligned to Windows Mobile 7 feature set. Screen-shots of WM 6.5 are available elsewhere on the web (not sure if they are real) but they look cool.

http://www.windowsfordevices.com/news/NS7535922139.html


Debugging RAPI dlls

November 8, 2008

I hope the following post will be useful.

http://www.42gears.com/blog/?p=214


Sad news: Paul DiLascia is no more

November 7, 2008

If this code works, it was written by Paul DiLascia. If not, I don’t know who wrote it” used to be the starting comment in his source code files. And I say..Yes Paul..your code always worked.

Paul’s articles were source of indepth information on Win32 and MFC programming. I always enjoyed reading his MSJ Q&A columns.

Surely we will miss Paul.

http://www.dilascia.com/


Maximum path-length or filename sizes on Windows

November 5, 2008

MSDOS could understand 8.3 file names only where 8 characters were reserved for filename and 3 for the extension. But Windows NT onwards Windows applications can create or manipulate path lengths of 260 characters, where 259 are actual characters + 1 NULL character. Moreover out of 259 characters, only 256 characters can be used for each component in the path.

C:\<256 character length><NULL>

NTFS actually can actually support 32767 characters in the paths. To handle this in your application, you must use unicode versions of file APIs such as CreateFileW etc and also prepend “\\?\” to the file paths. This tells the APIs to not to enforce 260 character limit.

To handle 32k long paths from the command line prepend “\\?\” to the paths. For e.g. to copy a file from drive c: to drive d: enter the following statement on the command prompt.

copy “\\?\c:\temp\<Long Path>” “\\?\d:\temp\<Another Long Path>”


Windows 7 : Thats after Vista

November 4, 2008

Next version of Microsoft Windows will be called Windows 7. Why “7″ you ask? Well, this will be the seventh release of Windows by Microsoft and it will succeed Vista.

It was earlier codenamed as Blackcomb and Vienna.

According to MS, this version will be compatible with Vista and will have new features and improved performance and kernel. It will be available by end of 2009 or early 2010.

Check out the following official site:

http://www.microsoft.com/windows/windows-7/


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.


Talking to a Windows Mobile device (RAPI 2)

November 1, 2008

Remote API (RAPI) library enables desktop application to perform actions on a Windows CE or a Windows Mobile device. Action can be one of the general purpose ones such as manipulating files on the devices, configuring registry on the device etc. Besides an application can do custom actions on the device by copying a special dll on the device and then calling custom functions implemented in that dll.

RAPI2 is available since Windows CE 5.01. An earlier version, just known as RAPI, is there since Windows CE 1.0. Going forward, its recommended to use RAPI2.

Desktop side functionality is provided by RAPI.dll which is installed when Microsoft ActiveSync is installed on the computer. So before calling any RAPI functions, desktop application should check if RAPI.dll is present on the system. RAPI.dll should not be bundled with the application as you might overwrite the latest version on a user’s computer.

To use RAPI in your native program, your must have basic knowledge of COM (Component Object Model). RAPI consists of the following interfaces which you need to acquire programmatically.

IRAPIDesktop : The connection point container for all devices.

IRAPIDevice : Represents a connected remote device.

IRAPIEnumDevices : Enumerates over all connected devices.

IRAPISession : Provides methods that replace the Remote API (RAPI) functions.

IRAPISink : Implemented by client application to receive connection events.

Sample Code

Access and usage of these interfaces is demonstrated in the code below. CDeviceManager class implements connecting/disconnecting the desktop to a Windows Mobile/CE device. You can use CDeviceManager class in your code to support connect/disconnect functionality and then use IRAPISession to call other functions as desired.

// CDeviceManager.h

#include <Rapi2.h>

#pragma once

class CDeviceManager
{
IRAPIDesktop*        m_pIRapiDesktop;
IRAPIEnumDevices*    m_pIRapiEnumDevices;
IRAPIDevice*        m_pIRapiDevice;
IRAPISession*        m_pIRapiSession;

public:
CDeviceManager(void);
~CDeviceManager(void);
int Connect(void);
bool IsConnected(void);
int Disconnect(void);
int Init(void);
int Deinit(void);
};

// CDeviceManager.cpp

#include “StdAfx.h”
#include “DeviceManager.h”

#define RELEASE_INTERFACE(p)    if (p) {    \
p->Release();    \
p = NULL;    \
}    \

CDeviceManager::CDeviceManager(void)
{
m_pIRapiDesktop = NULL;
m_pIRapiEnumDevices = NULL;
m_pIRapiDevice = NULL;
m_pIRapiSession = NULL;
}

CDeviceManager::~CDeviceManager(void)
{
Deinit();
}

int CDeviceManager::Init(void)
{
HRESULT hr = S_OK;

if (m_pIRapiDesktop == NULL)
{
// Initialize COM.
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);

// Create an instance of the IRAPIDesktop interface.
hr = CoCreateInstance(CLSID_RAPI, NULL, CLSCTX_INPROC_SERVER, IID_IRAPIDesktop, (void**)&m_pIRapiDesktop);

if (m_pIRapiDesktop == NULL)
return ERR_INIT_FAILED;
}

return 0;
}

int CDeviceManager::Deinit(void)
{
RELEASE_INTERFACE(m_pIRapiDesktop);
CoUninitialize();
return 0;
}

int CDeviceManager::Connect(void)
{
int        iRetVal = ERR_SUCCESS;
HRESULT hr = S_OK;

ASSERT(m_pIRapiDesktop);

RELEASE_INTERFACE(m_pIRapiEnumDevices);
RELEASE_INTERFACE(m_pIRapiDevice);
RELEASE_INTERFACE(m_pIRapiSession);

// Call EnumDevices to obtain an enumeration of connected devices.
if (SUCCEEDED(hr) && m_pIRapiDesktop)
{
hr = m_pIRapiDesktop->EnumDevices(&m_pIRapiEnumDevices );
}

if (m_pIRapiEnumDevices == NULL)
{
iRetVal = ERR_DEVICE_ENUM_FAILED;
goto cleanup;
}

// Call Next to get an interface to the device.
if (SUCCEEDED(hr) && m_pIRapiEnumDevices)
{
hr = m_pIRapiEnumDevices->Next(&m_pIRapiDevice);
}

if (m_pIRapiDevice == NULL)
{
iRetVal = ERR_NODEVICE_CONNECTED;
goto cleanup;
}

// Call CreateSession to establish a session with the connected device.
if (SUCCEEDED(hr) && m_pIRapiDevice)
{
hr=m_pIRapiDevice->CreateSession(&m_pIRapiSession);
}

if (m_pIRapiSession == NULL)
{
iRetVal = ERR_CONNECTION_FAILED;
goto cleanup;
}

if (SUCCEEDED(hr) && m_pIRapiSession)
{
// Call CeRapiInit before you call any other IRAPISession methods.
hr = m_pIRapiSession->CeRapiInit();
if (FAILED(hr))
{
hr = m_pIRapiSession->CeRapiGetError();
iRetVal = ERR_CONNECTION_FAILED;
goto cleanup;
}
}

goto success;
cleanup:
RELEASE_INTERFACE(m_pIRapiEnumDevices);
RELEASE_INTERFACE(m_pIRapiDevice);
RELEASE_INTERFACE(m_pIRapiSession);

success:
return iRetVal;
}

bool CDeviceManager::IsConnected(void)
{
if (m_pIRapiDevice)
{
RAPI_DEVICESTATUS Stat;
m_pIRapiDevice->GetConnectStat(&Stat);
if (Stat == RAPI_DEVICE_CONNECTED)
return true;
}

return false;
}

int CDeviceManager::Disconnect(void)
{
if (m_pIRapiSession)
{
m_pIRapiSession->CeRapiUninit();
RELEASE_INTERFACE(m_pIRapiSession);
}

RELEASE_INTERFACE(m_pIRapiEnumDevices);
RELEASE_INTERFACE(m_pIRapiDevice);

return 0;
}

// Error.h

#define        ERR_SUCCESS                0

// Device Manager errors
#define        ERR_DEVICECONN_START    ERR_SUCCESS+1
#define        ERR_INIT_FAILED            ERR_DEVICECONN_START
#define        ERR_DEVICE_ENUM_FAILED    ERR_DEVICECONN_START+1
#define        ERR_NODEVICE_CONNECTED    ERR_DEVICECONN_START+2
#define        ERR_CONNECTION_FAILED    ERR_DEVICECONN_START+3