Luckily there is a way to intercept incoming text messages without installing any patch. However, you will have to make some code changes to your application. The idea is that, although the .NET MessageInterceptor class does not work, the SDK MapiRule sample (C:\Program Files\Windows Mobile 6.5.3 DTK\Samples\Common\CPP\Win32\MapiRule) works just fine. This post shows you how to modify the MAPIRule sample code to integrate it with your .NET project
Modifying MAPIRule.dll
You will not have to touch most of the MAPIRule code, except for modifying the GUID (important!) and the ProcessMessage() function (the sample just displays the incoming text message received in a MessageBox). Although you can parse the incoming message and process it directly inside ProcessMessage(), I decided on the following to make things clearer:
- When MapiRule.dll received a new SMS message in ProcessMessage(), it simply send a Win32 message via SendMessage to the host application.
- Upon received the specific Win32 message, host application, which is a .NET application, will decide on whether or not to intercept the new SMS message (it will not appear in phone Inbox) or let the default messaging application handle it.
- Based on the result of SendMessage(), MapiRule.dll will act accordingly.
{
............
TCHAR msgInfo[500];
COPYDATASTRUCT cds;
// we concatenate the sender number and the message text, to be sent to the host application
memset(msgInfo, 0, sizeof(msgInfo));
wcscpy(msgInfo, pspvEmail->Value.lpszW);
wcscat(msgInfo, L"\n");
wcscat(msgInfo, pspvSubject->Value.lpszW);
//length for the recipient to know
cds.dwData = wcslen(pspvEmail->Value.lpszW) + wcslen(pspvSubject->Value.lpszW) + 1;
cds.cbData = sizeof(msgInfo); //msg size in bytes
cds.lpData = &msgInfo; //pointer to the information to be sent
// tell the main app about the text message
if (SendMessage(newMsgWin, WM_COPYDATA, 0, (LPARAM) &cds) == (LRESULT) 1)
{
// a LRESULT of 1 means that the message was processed by parent application
// so we delete the message and mark it as handled so it won't show up in Inbox
hr = DeleteMessage(pMsgStore, pMsg, cbMsg, lpMsg, cbDestFolder, lpDestFolder, pulEventType, pHandled);
}
else
{
// other LRESULT means message not handled by main app, pass it on
*pHandled = MRC_NOT_HANDLED;
}
............
}
Everything is straightforward, except that the lpData member of COPYDATASTRUCT structure has to be part of the structure memory area. This explains why an array of TCHAR, an not LPWSTR is used. If this is not followed, application may work or crash randomly without any indication why.
UPDATE (26 May 2012): As suggested by a reader, the above code may have problem with Unicode messages since sizeof(wchar_t) is 2 on Windows, resulting in incorrect value for the data length, dwData. If you have problems with truncated messages, try this:
cds.dwData = 2*wcslen(pspvEmail->Value.lpszW) + 2*wcslen(pspvSubject->Value.lpszW) + 1;
The updated MAPI DLL with the fix can be downloaded from here
The .NET code is as follows:
[StructLayout(LayoutKind.Sequential)]
private struct CopyDataStruct
{
public int IntData;
public int Length;
[MarshalAs(UnmanagedType.LPWStr)]
public string Data;
}
private struct CopyDataStruct
{
public int IntData;
public int Length;
[MarshalAs(UnmanagedType.LPWStr)]
public string Data;
}
public class NewMsgWindow : MessageWindow
{
{
..........
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_COPYDATA) //we received a message telling us that there is an incoming SMS
{
CopyDataStruct cs = (CopyDataStruct)Marshal.PtrToStructure(m.LParam, typeof(CopyDataStruct));
if (cs.Data.Contains(delim))
{
string sender = cs.Data.Split(delim)[0];
string messageText = cs.Data.Split(delim)[1];
if (true)
{
// a LRESULT of 1 marks message as processed.
// and native msg app will not show msg in Inbox
m.Result = new IntPtr(1);
}
else
// Other LRESULT indicates we did not intercept the message
// and the message will be passed on to native messaging application.
m.Result = new IntPtr(0);
}
}
.......
}{
if (m.Msg == WM_COPYDATA) //we received a message telling us that there is an incoming SMS
{
CopyDataStruct cs = (CopyDataStruct)Marshal.PtrToStructure(m.LParam, typeof(CopyDataStruct));
if (cs.Data.Contains(delim))
{
string sender = cs.Data.Split(delim)[0];
string messageText = cs.Data.Split(delim)[1];
if (true)
{
// a LRESULT of 1 marks message as processed.
// and native msg app will not show msg in Inbox
m.Result = new IntPtr(1);
}
else
// Other LRESULT indicates we did not intercept the message
// and the message will be passed on to native messaging application.
m.Result = new IntPtr(0);
}
}
.......
The challenge is to receive the WM_COPYDATA message and marshal it back to a string. Most sample codes use GetLParam(), but as this is not supported by .NET CF, we have to use Marshal.PtrToStructure(). As commented, the .NET code will response with a result of either 1 or 0.
Source code
The sample code is here. Some part of the code was taken from the Remote Tracker open source project which also intercepts incoming text messages. Remote Tracker source code, however, parses the text message directly inside MapiRule.dll.
Setting up
Some registry keys need to be modified for MapiRule.dll to be used. This can either be done via a CAB file, or via the CreateInterceptorMethod2() method in the code. A reboot is needed for changes to take effect. If you need to change MapiRule.dll, you will have to remove the registry keys via RemoveInterceptorMethod2(), reboot the device, update the dll, call CreateInterceptorMethod2() and reboot again! Terminating poutlook.exe and tmail.exe may also help to reduce the number of restarts on some devices. This makes the development process very time consuming. Debugging MapiRule.dll is possible by attaching the debugger to tmail.exe.
Issues
There are still some minor issues yet to be solved. On HTC HD2, for some reasons, all text messages received will have the string " - GSM" appended at the end (refer to this discussion). Also, the total length of the sender name and the message text cannot exceed 500 since the TCHAR array length is hard coded. If you need to receive longer text message, the interprocess communication algorithm has to be modified to send and receive the text message part by part. You cannot simply increase the array length, as it will cause a stack fault.
Last but not least, the approach described here works on all devices, including HTC Devices. So it can be used as a replacement for the MessageInterceptor class. In a sense, it's better as you can decide, at the point of receiving, which message to be processed, instead of pre-creating a set of MessageInterceptor conditions and re-creating them should the interception conditions change.
nice, but i cant get a message longer than 150 chars to fire - which doesn't even approach the 500 hard limit. the ProcessMessage is not hit when the length of the sender and the subject is more than 150. any combinationd of subject
ReplyDeleteAre you sure ProcessMessage() does not get hit at all when combined length is more than 150 chars? It may have been called, but crashed half-way due to overflow before reaching SendMessage(), so the .NET side was never notified. Place a MessageBox() at the first line of ProcessMessage() to make sure it gets called. On my phone, I have no problems with long text messages, up to the hard-coded limit.
ReplyDeleteall]emulators and my device htc leo starts to rebbot when i click intercept. :(
ReplyDeleteSorry for bad english.
Sorry :) i full idiot
ReplyDeleteIt is possible to receive messages only from no"55555" for example, or with text "sometext" in body? How to set filter?
ReplyDeleteHi. The Start Intercept button will set up the necessary registry keys and reboot the phone for changes to take effect. Once the program starts again after the phone reboots, it will be able to intercept incoming messages.
ReplyDeleteIf you want to clean up the registry keys created by Start Intercept, click on Stop Intercept. The phone will reboot again to apply the changes.
You can set a filter by using the following code snippet from the article:
if (sender == "55555" && messageText.Contains("sometext"))
{
// mark message as processed.
// and native msg app will not show msg in Inbox
m.Result = new IntPtr(1);
}
else
{
// indicate we did not intercept the message
// and the message will be passed on to native messaging application.
m.Result = new IntPtr(0);
}
Thank you very much! I copy code to WM 6.5, and it's works! May be you know why Cellular Emulator dont work with WM 6.5 QVGA Emulator? I cant find information about it, or links are broken :(
ReplyDeleteHi
ReplyDeleteGlad you got it working. I have no problems running Cellular Emulator with WM 6.5 emulator on my laptop. Notice that besides the WM 6.5 DTK, you need to have at least WM 6.0 SDK installed on the same machine, and the cellular emulator COM port configured properly for the emulator to have phone capabilities.
Thank you for answer!
ReplyDeleteWM 6.0 SDK already installed in system, and Cellular Emulator configured for COM3 port. Sms and telephone working fine on WM 6.0 Emulator, but not in 6.5 QVGA version. I tryed to edit config xml file manuality, but - no results. So i use WM 6 Professional emulator only :(
Seems i only get the first few characters of the message Invalid WM_COPYDATA message. Received: +3165xxx253
ReplyDelete(fingered some numbers)
any idea as to why?
Hi. In the WndProc function where the Win32 message WM_COPYDATA is received, check if the data received contain the original SMS:
ReplyDeleteif (m.Msg == WM_COPYDATA)
{
CopyDataStruct cs = (CopyDataStruct)Marshal.PtrToStructure(m.LParam, typeof(CopyDataStruct));
Debug.WriteLine(cs.data)
...}
Ideally cs.data should contain the sender number and the original message.
I realy hate being a noob at things cuz i can't stand when other people can't comprehend simple directions but this is really throwing me for a loop. The reason why I need this is because right now i have a hd2. The normal message app is okay and everything but id rather use SMSAtHand. When I disable htc messaging i can use smsathand normally. But when htc messaging is enabled and i try to send a message through sms at hand it stays in my outbox until i send a message through the regular htc messaging app,at that time all of the failed messages through sms at hand will all send at once. Id rather have htc messaging enabled so that i can recieve mms through it. So before I rack my brain going over the instructions again, I would like to know if this post would be my solution to my problem. The problem being that I can not have htc messaging enabled and still send messages through sms at hand
ReplyDeleteUpon reading my last comment I'd like to add, do you think there is anyway to have outlook(or whatever program is used to send texts when htc messaging is disabled)still send texts while htc messaging is enabled?
ReplyDeleteOne last last thing I just installed arcsoft mms with htc messaging disabled. however when i try to compose a new mms, nothing happens... does arcsoft work with hd2? I sincerely apologize for the small overload of comments but Im trying to explain my problem and suitables solutions as thoroughly as possible. Thank you for reading and any help/info is greatly welcomed!
ReplyDeleteHi. The post is meant for developers to develop applications that handle incoming messages on affected phones. If you want to patch existing applications, please use the patch at http://forum.xda-developers.com/showthread.php?t=556614 to disable HTC Messaging.
ReplyDeleteI am afraid you can't have HTC Messaging enabled and expect SMSAtHand to be working. If you want to send MMS, you can try ArcSoft MMS Client.
There are a few versions of ArcSoft MMS client available, you need to look for one that can work on your phone. I would suggsest trying this http://www.mobinauts.com/topic/109757-official-thread-for-htc-hd2-part-5/page__st__490.
Let me know if you get it working :)
Ive been playing around with arcsoft for a minute now. i have htc messaging disabled(soft reset), installed arcsoft(soft reset) but whenever i go to messages and then to new mms nothing comes up, then i try new sms (it loads) and then i try to insert a picture, nothing (again)pops up. any ideas?
ReplyDeleteTry the official ROM upgrade at http://www.htc.com/sea/SupportDownload.aspx?p_id=297&cat=2&dl_id=854. Some says it has fixed the SMS interception problems so no patch or Arcsoft MMS is necessary - you can just use HTCMessaging with SMSAtHand.
ReplyDeleteYou can also try the Miri ROM or the Topix ROM here http://htcpedia.com/Topix_1_8_4_rom_hd2/reviews/rom-builds.html
They are both custom built ROM that may help.
Thank You so very much for the swift replies! I'm actually on a Miri Rom. Miri & Dinik v19. I just hard reset, task 29, flashed the rom to see if the intercept was patched in the newest htc messaging. It seems as it isnt. As of right now, I would be satisfied with just getting arcsoft to work. I've finally been able to get to the composing screen to select my message, but it never sends. Well, it says its sending but never completely sends....
ReplyDeleteYou're welcome and thanks for reading my blog :)
ReplyDeleteI think if you're able to get to the point where Arcsoft starts to send MMS, you're almost there. It seems as if arcsoft could not locate the correct MMSC settings for your device. First check Arcsoft client for any MMSC settings. If not, you can configure manually. Open the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Arcsoft\ArcSoft MMS UA\Config and set the correct values for your operator.
Wow!!! Thank You so very much. Its like I can finally have my pie (cuz we all know pie is much better than cake)and eat it too!! A thousand praises. after all of this searching you are the only person to point me to the registry and I appreciate you taking the time to not only respond, but also respond so promptly and to a comment that in the end didnt have much to do with the original thread. Again, thank you!!
ReplyDeleteGreat! Glad that I could help :)
ReplyDeleteLet me know if you need any other information. Cheers.
Thanks for your article.
ReplyDeleteIs there also a solution for reading sms messages from the inbox of HTC phone which uses HTC sense.
Thanks,
Andre van Wieringen
It does not matter if the phone has HTC sense or not, you will need to use Messaing API (MAPO), either from C++ or from .NET to read SMS Inbox. This codeproject article provides excellent code sample http://www.codeproject.com/KB/windows/PocketPCandSmartphone.aspx
ReplyDeleteyou can enjoy unlimited text messaging through online message packages.
ReplyDeleteHi, Can you advise me please?
ReplyDeleteMaybe I am doing something wrong.
1) From solution I removed C++ project (because I do not want to recompile a DLL, I want to use original one.)
2) Than I opened solution (only C# project TestMsgInterceptor) and added MessageBox.Show(“I am here”) to method msgWin_OnNewTextMessage() . Than I rebuild project.
3)I copied TestMsgInterceptor.exe and RTRule.dll to one (new) folder on my HTC HD2.
4) Thank I executed TestMsgInterceptor.exe and "Start Intercept" button. After reboot of my mobile I started TestMsgInterceptor.exe again and waited for incoming SMS …. SMS received by HTC HD2 standard service, the MessageBox.Show(“I am here”) has not been Shown.
Can you advise me why? What can be wrong?
Thanks,
Martin
BTW: please aswer
Hi, when I tested this on a HTC HD2 a few years back, all worked.
ReplyDeleteChecked if the Start Intercept button did what it is supposed to do, that is, to set up the required registry keys for the DLL. Make sure that the path to the DLL is correct. The DLL is a COM API for the Messaging API (MAPI). It needs to be COM-registered for things to work - which is why you need a reboot.
Try to make the project work as-is first before attempting to modify it.
Hope this helps.
Hi,
ReplyDeleteyes, that it is a reason why I did not want to recompile DLL :-)
If I would like to use original TestMsgInterceptor.exe than please, how (in HTC HD2) I can see outcome of Debug.WriteLine(sender) ....as it is used in msgWin_OnNewTextMessage()?
Thanks so much.
Martin
Hi, you can run it in Debug Mode and see the error in debug output. Or you can change it to MessageBox.Show() and view it without the debugger.
ReplyDeleteTake note that there is no way for it to work if the DLL is not COM-registered properly. Try to make the original source code work first.
Hi. I played with code and problem is here:
ReplyDeleteThe WndProc() method in C# code is been called when SMS received, but cs.Data contains always half of text of original SMS.
Susspicious is that cs.Length value is same as number of chars which *should be* stored in cs.Data :-) So cs.Length is 40 but in cs.Data are only 20 chars.
And now say me why? :-)
Thanks,
Martin
Hi Martin,
ReplyDeleteDo you mean that the message sender was displayed properly and the body cut into half? The design was to merge both into a single cs.data string, separated by "\n".
Do you also happen to have Unicode characters in the message text? Take note that sizeof(wchar_t) on Windows is 2 bytes, which may not have been handled properly (I only tested with ANSI characters). Check the ProcessMessage function in the C++ library to make sure that the message is received properly. If yes, the problem is with the passing of the message from the DLL to the C# code
I suspect the following line:
cds.dwData = wcslen(pspvEmail->Value.lpszW) + wcslen(pspvSubject->Value.lpszW) + 1;
Try this (or try some big numbers first)
cds.dwData = 2*wcslen(pspvEmail->Value.lpszW) + 2*wcslen(pspvSubject->Value.lpszW) + 1;
Let me know if you manage to fix it.
Thanks for trying :)
Hi.
ReplyDeleteyes, alwayes the text is cut to half. The several chars from this half is being used by phone number.
This is really same approach I wanted to use :-)
Unfortunatelly I have no C++ compiler ;-(
Can you compile it?
BTW: For Win32 I am using MS Visual Studio Express C#, and for C# mobile development I am using free ware ShrapDevelop http://www.icsharpcode.net/opensource/sd/
Thanks,
Martin
Hi Martin,
ReplyDeleteThanks for getting back,
Unfortunately, I do not have access to Visual Studio at the moment (on a netbook now), so I am unable to re-compile the DLL for you. There is a free express version of Visual Studio (VB, C# and C++ as well), but that doesn't support mobile development. If you don't have the full version of Visual Studio 2008 Professional or Enterprise (which is the last version to support Windows Mobile), you can search for Visual Studio 2008 Beta. The edition is free and there are some websites still offering it, legally :) You should also have the various Windows Mobile SDKs (available for free from Microsoft) installed in order to recompile the DLL.
Hi,
ReplyDeletethanks for answer.
please, will you have access to VS C++ in near future? You know sometimes is better to wait few days than immediately to start installing that and that :-)
BTW my email to simplify communication: email.pro.me@gmail.com
Thanks, Martin
Hi,
ReplyDeleteI will try to recompile the DLL and update the article when I have the time too, hopefully within the next few days. Meanwhile, try to look for Visual Studio 2008 Beta - installing it and compiling the code should be easy. You'll learn new things too! :)
Hi,
ReplyDeletefinally I compiled it and it /* cds.dwData = 2*wcslen(pspvEmail->Value.lpszW) + 2*wcslen(pspvSubject->Value.lpszW) + 1; */ works :-)
I had to find MS Visual Studion 2008 Trial on some mirror servers of Microsoft, and than compiled it.
Let me know if you want "new" DLL from me. I can send it to you.
Thanks & regards,
Martin
Hi Martin,
ReplyDeleteI am glad my suggestions work for you and thanks so much for getting back. I believe it will help other with similar problems. If you have time, upload the DLL somewhere (dropbox perhaps) and send me the link.
Good luck :)
Hi,
ReplyDeletethe updated DLL is here
http://meteo.webz.cz/Mobil/RTRuleWide.dll
regards,
Martin
Hi Martin,
ReplyDeleteThank you for the DLL. I have downloaded it and updated the article accordingly.
Cheers