Friday, August 29, 2008

What does DTM_BROWSERDISPATCH gives you?

Well,as some documentations state it gives you IBrowser,IBrowser2,IBrowser3 interfaces.
Remember they are different from IWebBrowser and IWebBrowser2 interfaces.
But where are the definitions of these interfaces?
Well actually from win ce 4.2,there are no such interfaces found in your SDK.So you have to use older SDKs found in for example PocketPC 2000/2002,and copy/paste them into your header file.
Unfortunately Microsoft also uses another interface to negotiate with HTML Document viewer,which there is no documentation for it.Interace GUID is {698e3fcb-70c3-11d0-81e8-00a0c90ad20a} but so far i haven't find any documentation for it.

But why do i need all these?
The problem is with Images.With use of DTM_SETIMAGE you can only give HTML Viewer a handle to your bitmap.The problem is i want to display it as transparent bitmap and so far i haven't find any way.
And tracing DTM_SETIMAGE,it gives these information to that undocumented interface.So i still don't know how can i use HTML Viewer with transparent images.

Wednesday, August 20, 2008

Why there is no information on....?

Why there is no information anywhere on BI_FOURCC ?
Why there is no information anywhere on BI_ALPHABITS ?
Why there is no information on 32 bit Bitmaps?
Why there is no information anywhere on How to embed OLE Browser on your application?
Why there is no information on How to use Memory bitmaps inside your OLE Browser?
Why there is no information on RIL interfaces?
Why there is no information on How to send SMS using RIL?
And why Windows Mobile development requires this much of undocumented information?
And Why Microsoft's own applications completely use different set of unnamed/undocumented APIs?

Well,actually i am really angry,but hey,i managed to find some information on some of questions above.
Hope i can share them with you.

Thursday, August 7, 2008

PocketPC Threaded Messaging (SMS) for everyone!

Microsoft added threaded messaging in WM6.1 but there is no way to use threaded messaging on earlier versions of windows mobile like wm5 and wm6.

But things have changed now!

SmileySMS can bring threaded messaging to wm5,wm6 devices and also to wm6.1 devices with support for smileys!

Here is the nice and sexy screenshot of newer versions of SmileySMS.

How do you know SMS belong to which folder in MAPI?

Well,somethimes you might want to know that this SMS is in which folder,for example in Drafts folder,in Inbox folder or...?
A quick not is that never rely on results from PR_DISPLAY_NAME because names like "Inbox","Drafts Folder" can be localized.
Here is the code snippet i use.
You have to use it like this.

if (isFolderTypeSame(pSession,pFolder,PR_CE_IPM_INBOX_ENTRYID))

You can use these values for third parameter.

bool isFolderTypeSame(IMAPISession *m_pSession,LPMAPIFOLDER pFolder,ULONG _PR_FOLDERTYPE)
CComPtr<IMsgStore> pms ;
ULONG cItems;
SizedSPropTagArray(2, rgtagsFldr) = {2 , PR_OWN_STORE_ENTRYID,PR_ENTRYID};
ULONG entryid[] = { 1, _PR_FOLDERTYPE };
LPSPropValue fldrprops=NULL,msgstoreprops = NULL;
ULONG result=0;

// This method assumes that the CALLER already logged on to a MAPISession
if (!m_pSession)

// Now request the PR_OWN_STORE_ENTRYID on the folder. This is the
// ENTRYID of the message store that owns the folder object.
hr = pFolder->GetProps((SPropTagArray *) &rgtagsFldr, MAPI_UNICODE, &cItems, &fldrprops);

// Now open the message store object.
hr = m_pSession->OpenEntry(fldrprops[0].Value.bin.cb,(LPENTRYID)fldrprops[0].Value.bin.lpb,NULL,
0, NULL, (LPUNKNOWN*)&pms);

// Get the ENTRYID of the wastebasket for the message store
hr = pms->GetProps((LPSPropTagArray)entryid, MAPI_UNICODE, &cItems, &msgstoreprops);


return result;

How to create and send SMS using MAPI?

Here is a code snippet i use to create and send my SMS in SmileySMS program.
From my experience,using fewer properties for ModifyRecipients or SetProps will make it fail on some devices.

IMsgStore *FindInboxSMSStore(IMAPISession *pSession)
const SizedSPropTagArray (2, spta) = { 2, PR_DISPLAY_NAME, PR_ENTRYID };
SRowSet *prowset = NULL;
CComPtr<IMAPITable> ptbl;
CComPtr<IMsgStore> pStore;

// Get the table of accounts
hr = pSession->GetMsgStoresTable(0, &ptbl);
// set the columns of the table we will query
hr = ptbl->SetColumns((SPropTagArray *) &spta, 0);

while (TRUE)
hr = ptbl->QueryRows (1, 0, &prowset);
if ((hr != S_OK) || (prowset == NULL) || (prowset->cRows == 0))

ASSERT (prowset->aRow[0].cValues == spta.cValues);
SPropValue *pval = prowset->aRow[0].lpProps;

ASSERT (pval[0].ulPropTag == PR_DISPLAY_NAME);
ASSERT (pval[1].ulPropTag == PR_ENTRYID);

if (!_tcscmp(pval[0].Value.lpszW, TEXT("SMS")))
// Get the Message Store pointer
hr = pSession->OpenMsgStore(0, pval[1].Value.bin.cb, (LPENTRYID)pval[1].Value.bin.lpb, 0, 0, &pStore);
FreeProws (prowset);

return pStore;
// Free the previous row
FreeProws (prowset);
prowset = NULL;
FreeProws (prowset);
return NULL;

HRESULT CreateSendSMSMessage(IMAPISession *spSession,LPCTSTR lpszToNumber, LPCTSTR lpszToDisplay,LPCTSTR lpszMessage,IMessage** pMsg)
CComPtr<IMsgStore> spMsgStore;
ULONG cItems;
ULONG rgtagsMsgStore[] = { 1, PR_CE_IPM_DRAFTS_ENTRYID };
LPSPropValue rgprops;

spMsgStore = FindInboxSMSStore(spSession);
if (spMsgStore == NULL)
return S_FALSE;

CComPtr<IMAPIFolder> spFolder;

hr = spMsgStore->GetProps((LPSPropTagArray)rgtagsMsgStore, MAPI_UNICODE, &cItems, &rgprops);
if (FAILED(hr))
return hr;

hr = spSession->OpenEntry(rgprops[0].Value.bin.cb,(LPENTRYID)rgprops[0].Value.bin.lpb,
NULL, 0, NULL, (LPUNKNOWN*)&spFolder);
if (FAILED(hr))
return hr;


hr = spFolder->CreateMessage(NULL, 0 ,&(*pMsg));
if (FAILED(hr))
return hr;

int cb;
LPSRowSet pRowSet = NULL;
LPSPropValue pVal = NULL;

// * 5 because there are 5 props
cb = sizeof(SRowSet) + sizeof(SPropValue) * 5; // SRowSet includes one SRow.

// Now allocate a buffer.
CPR((pb = new BYTE[cb]))

// Copy the properties over.
pRowSet = (LPSRowSet)pb;
pVal = (LPSPropValue)(pb + ( sizeof(SRowSet) + sizeof(SRow) ));

// initialize
pRowSet->aRow[0].cValues = 0;
pRowSet->aRow[0].lpProps = pVal;

// begin filling the values
pVal->ulPropTag = PR_RECIPIENT_TYPE;
pVal->Value.ul = MAPI_TO;

pVal->ulPropTag = PR_EMAIL_ADDRESS;
pVal->Value.lpszW = (LPWSTR)lpszToNumber;

pVal->ulPropTag = PR_DISPLAY_NAME;
pVal->Value.lpszW = (LPWSTR)lpszToDisplay;

pVal->ulPropTag = PR_ADDRTYPE;
pVal->Value.lpszW = L"SMS";

pVal->ulPropTag = PR_MESSAGE_CLASS;
pVal->Value.lpszW = (LPTSTR)L"IPM.SMStext";

pRowSet->cRows = 1;

hr = (*pMsg)->ModifyRecipients(MODRECIP_ADD, (LPADRLIST)pRowSet);

// now we set the additional properties for the
// message
SPropValue props[6];

ZeroMemory(&props, sizeof(props));

// first set the subject of the message
// as the sms we are going to send
props[0].ulPropTag = PR_SUBJECT;
props[0].Value.lpszW = (LPWSTR)lpszMessage;

props[1].ulPropTag = PR_MSG_STATUS;
props[1].Value.ul = MSGSTATUS_RECTYPE_SMS;

props[2].ulPropTag = PR_SENDER_ADDRTYPE;
props[2].Value.lpszW = L"SMS";

props[3].ulPropTag = PR_MESSAGE_CLASS;
props[3].Value.lpszW = L"IPM.SMStext";

props[4].ulPropTag = PR_MESSAGE_FLAGS;

props[5].ulPropTag = PR_SENDER_EMAIL_ADDRESS;
props[5].Value.lpszW = (LPWSTR)lpszToNumber;

hr = (*pMsg)->SetProps(sizeof(props) / sizeof(props[0]), (LPSPropValue)&props, NULL);
if (FAILED(hr))
return hr;

// having set all the required fields we can now
// pass the message over to the msgstore transport
// to be delivered.
//hr = (*pMsg)->SubmitMessage(0);
//if (FAILED(hr))
//return hr;
delete [] pb;
return FALSE;

Monday, July 7, 2008

3D AltTab

Well,here is another program of mine.
This program rotates between current running applications.
For using it,i recommend assigning a hardware key to it and use it to rotate your device.

Here is a video clip posted on youtube,demonstrating program.

You can download it from here.

Wednesday, April 23, 2008

VMware Project North Star Beta (Thinstall)

I really liked this product.check it out!

Saturday, February 23, 2008

MAPI and SMS delivery reports?

Well,Have you ever wanted to Send SMS using MAPI?

Well it is not that hard,you simple call IMessage->SubmitMessage(0);

But what about delivery reports?

Just set these two properties using IMessage->SetProps to true!


Here is code snippet ::

props[0].Value.b = TRUE;

props[1].Value.b = TRUE;

hr = spMessage->SetProps(2, (LPSPropValue)&props, NULL);

Tuesday, September 25, 2007

SmileySMS and En2FaMail are now v1.53

Lots of changes happened during past month,and now both applications have plugins for Inbox,so you can also see smiles (and in case of En2FaMail,you Persian text + smilies) in you inbox too!

Hope you enjoyed this program so far!
Here i attached my updated Pictures of these programs.



Thursday, September 13, 2007

MAPI : how to delete a message(or move it into trash)?

I think deleting a message is rather easy,but i find moving a message instead to trash or wastebasket folder is not that easy.
Here is a function i use to determine the wastebasket folder.So i can use IFolder,CopyMessages routine with MAPI_MOVE flag to move my message there!

HRESULT GetWastebasketForFolder(IMAPISession *m_pSession,LPMAPIFOLDER pFolder,
LPMAPIFOLDER* ppfldrWastebasket)
IMsgStore* pms = NULL;
ULONG cItems;
ULONG rgtagsFldr[] = { 1, PR_OWN_STORE_ENTRYID };
LPSPropValue rgprops = NULL;

// This method assumes that the CALLER already logged on to a MAPISession
if (!m_pSession)

// Now request the PR_OWN_STORE_ENTRYID on the folder. This is the
// ENTRYID of the message store that owns the folder object.
hr = pFolder->GetProps((LPSPropTagArray)rgtagsFldr, MAPI_UNICODE, &cItems, &rgprops);

CBR(PR_OWN_STORE_ENTRYID == rgprops[0].ulPropTag);

// Now open the message store object.
hr = m_pSession->OpenEntry(rgprops[0].Value.bin.cb,

rgprops = NULL;

// Get the ENTRYID of the wastebasket for the message store
hr = pms->GetProps((LPSPropTagArray)rgtagsMsgStore, MAPI_UNICODE, &cItems, &rgprops);

// Now open the correct wastebasket and return it to the caller.
CBR(PR_IPM_WASTEBASKET_ENTRYID == rgprops[0].ulPropTag);

hr = m_pSession->OpenEntry(rgprops[0].Value.bin.cb,
NULL, 0, NULL, (LPUNKNOWN*)ppfldrWastebasket);


return hr;

and you call it like this :

pFolder is a folder where you message is.
And moving is done like this.
pFolder->CopyMessages(&lst, NULL, pWasteBasket, 0, NULL, MAPI_MOVE);

Probably you might know that lst is ENTRYLIST and you construct it like this!
lst.cValues = 1;
sbin.cb = pspvEntryID->Value.bin.cb;
sbin.lpb = (LPBYTE) pspvEntryID->Value.bin.lpb;
lst.lpbin = &sbin;

And pspvEntryID is what i get from calling GetProps to getting this message property ids.

Saturday, September 8, 2007

SmileySMS Program

Well,i removed the Persian/fingilish translations materials from En2FaMail program,and released another program called SmileySMS in xda-developers today.

Here are list of things that this program do:

- Shows and displays smilies found in SMS texts.
- Assign .mp3,.ogg,.wav,.mod and other popular music file formats as your SMS ring tones.
- Remove phone number from the title of SMS notification,when the contact is known.
- Replace number in body of delivery report with the name of contact.
- Show pictures of contacts in SMS notification.
- Easier to use menus for working with SMS notifications.
- WM5.0 like notifications for WM2003 users.
- Support for vibrate.
- All features(including program) are configurable through control panel.

And of course En2FaMail does all these too.

Vibrating your PocketPC device!

How to vibrate a PocketPC WM5.0 or 2003 device?

In smartphone platforms there is a Vibrate API which you can use.
Although MSDN mentioned that it exist in WM5.0,it isn't.
There was a mistake in MSDN documentations.

Searching all over internet I find that there are 2 ways to achieve this.
One way is to use Notify functions like CeSetUserNotificationEx,and setting trigger time to now.
But unless you display a dialog(using PUN_DIALOG),you can't use it and also it seems user settings override your program settings!

Another way is using NLed functions.
Although all people in Google groups and also Microsoft MVPs,mentioned there is no way to know the led number of vibrator,I find out when you use NLedGetDeviceInfo on a Led slot,and the lCycleAdjust is -1, it is your device vibrator's led number!

Here is the code I've written to use vibrate of my device!
I also checked it on some other devices and they all worked!

void LedOn(int id)
if (id < 0)
settings.LedNum= id;
settings.OffOnBlink= 1;
NLedSetDevice(NLED_SETTINGS_INFO_ID, &settings);

void LedOff(int id)
if (id < 0)
settings.LedNum= id;
settings.OffOnBlink= 0;
NLedSetDevice(NLED_SETTINGS_INFO_ID, &settings);

int GetVibratorLedNum(void)//-1 means no vibrator
int wCount = 0,VibrLed = -1;

if(NLedGetDeviceInfo(NLED_COUNT_INFO_ID, (PVOID) &nci))
wCount = (int) nci.cLeds;

for (int i=0;i<wCount;i++)
sup.LedNum = i;
if (sup.lCycleAdjust == -1)
VibrLed = i;
return VibrLed;
}- param1 + 1

You also need to add these to your source files!

extern "C" {
BOOL WINAPI NLedGetDeviceInfo( UINT nInfoId, void *pOutput );
BOOL WINAPI NLedSetDevice( UINT nDeviceId, void *pInput );

Also note that most PocketPcs do not support vibrators,mostly PocketPc Phone editions do.