Home > Managed Code, Native Code, Windows Mobile > Sending SMS message in Windows CE

Sending SMS message in Windows CE

Download the source code

Today I will show the way to send SMS message in Windows CE and Windows Mobile, using C++ and P/Invoke in .NET CF. It’s pretty simple…

In Windows CE environment, SMS fuction is handled by “sms.dll”, but in Windows Mobile 2005 and later, it’s handled (in a much more simpler way) by “cemapi.dll”. The “cemapi.dll” is not documented very well, in the other hand, you can find lots of information about “sms.dll” on MSDN.

Concretely, we will use the SendSmsMessage function in cemapi.dll, and SmsOpen, SmsSendMessage, SmsClose in sms.dll, depend on the platform we are running.

In .NET CF, we can use the late-binding DllImport to use both library, in C++, we use dynamic library loading (LoadLibrary, GetProcAddress, FreeLibrary…) to complete the task.

This is the source code in .NET CF:

internal static bool SendMessage_WM2k3(string destination, string message)
{
 // SEND = 2, RECEIVE = 1
 IntPtr handle;
 IntPtr intPtr = IntPtr.Zero;

 if (SmsOpen("Microsoft Text SMS Protocol", 2, out handle, ref intPtr) == 0)
 {
 byte[] array = new byte[0x204];
 if (destination.StartsWith("+"))
 {
 BitConverter.GetBytes(1).CopyTo(array, 0);
 }
 Encoding.Unicode.GetBytes(destination).CopyTo(array, 4);
 int dwProviderSpecificDataSize = 0xa4;
 byte[] buffer2 = new byte[dwProviderSpecificDataSize];
 BitConverter.GetBytes(1).CopyTo(buffer2, 4);    // messageclass = 1

 int messageId;
 if(SmsSendMessage(handle, null, array, null, message, message.Length * 2, buffer2, dwProviderSpecificDataSize, 0, 0, out messageId) == 0)
 {
 SmsClose(handle);
 return true;
 }
 }
 return false;
}

static Thread m_SendSMSThread;
static string m_sRecipientPhone;
static string m_sSMSContent;

private static void SendSMS()
{
 CultureInfo culture = CurrentCulture;

 if(Environment.OSVersion.Version.Major < 5)     // WM 2k3 and previous
 {
 if(!SendMessage_WM2k3(m_sRecipientPhone, m_sSMSContent))
 {
 MessageBox.Show("Error");
 }
 else
 {
 MessageBox.Show("Success");
 }
 }
 else
 {
 if(SendSMSMessage(m_sRecipientPhone, m_sSMSContent, false) != 0)
 {
 MessageBox.Show("Error");
 }
 else
 {
 MessageBox.Show("Success");
 }
 }
}

public static void SendSMS(string recipient, string sContent)
{
 m_sRecipientPhone = recipient;
 m_sSMSContent = sContent;
 m_SendSMSThread = new Thread(SendSMS);
 m_SendSMSThread.Start();
}

[DllImport("cemapi.dll", EntryPoint = "#48", SetLastError = true)]
public static extern int SendSMSMessage(string RecipientAddress, string MessageText, bool DeliveryReportRequested);

[DllImport("sms.dll")]
private static extern int SmsSendMessage(IntPtr smshHandle, byte[] psmsaSMSCAddress, byte[] psmsaDestinationAddress, byte[] pstValidityPeriod, string pbData, int dwDataSize, byte[] pbProviderSpecificData, int dwProviderSpecificDataSize, int smsdeDataEncoding, int dwOptions, out int psmsmidMessageID);

[DllImport("sms.dll")]
private static extern int SmsOpen(string ptsMessageProtocol, int dwMessageModes, out IntPtr psmshHandle, ref IntPtr phMessageAvailableEvent);

[DllImport("sms.dll")]
private static extern int SmsClose(IntPtr smshHandle);

and here for C++:

private:
 // function for "cemapi.dll"
 typedef int (__cdecl *SendSMSMessage)(
 LPCTSTR sDest,
 LPCTSTR sContent,
 BOOL bDeliveryReportRequest);

 // 3 functions for "sms.dll"
 typedef struct sms_address_tag {
 INT smsatAddressType;
 TCHAR ptsAddress[256];
 } SMS_ADDRESS, *LPSMS_ADDRESS;

 typedef LONG (__cdecl *SmsSendMessage) (
 const DWORD smshHandle,
 const SMS_ADDRESS * const psmsaSMSCAddress,
 const SMS_ADDRESS * const psmsaDestinationAddress,
 const BYTE * const pstValidityPeriod,
 const BYTE * const pbData,
 const DWORD dwDataSize,
 const BYTE * const pbProviderSpecificData,
 const DWORD dwProviderSpecificDataSize,
 const INT smsdeDataEncoding,
 const DWORD dwOptions,
 DWORD * psmsmidMessageID);

 typedef HRESULT (__cdecl *SmsOpen) (
 const LPCTSTR ptsMessageProtocol,
 const DWORD dwMessageModes,		// SEND = 2, RECEIVE = 1
 DWORD* const psmshHandle,
 HANDLE* const phMessageAvailableEvent
 );

 typedef HRESULT (__cdecl *SmsClose) (
 const DWORD smshHandle
 );

 // used when pass info to thread
 typedef struct sms_sending_info {
 CString sDest;
 CString sContent;
 } SMS_SENDING_INFO;

static BOOL SendSMS_WM2k3(HMODULE hDll, CString sDest, CString sContent)
{
 SmsOpen procOpen = (SmsOpen)GetProcAddress(hDll, L"smsopen");
 SmsSendMessage procSend = (SmsSendMessage)GetProcAddress(hDll, L"smssendmessage");
 SmsClose procClose = (SmsClose)GetProcAddress(hDll, L"smsclose");

 BOOL bSuccess = FALSE;

 if(procOpen && procSend && procClose)
 {
 DWORD smsHandle = 0;
 HANDLE hEvent = NULL;

 TRACE(L"GetProcAddress: (SmsOpen, SmsSendMessage, SmsClose) OK.\n");

 if(0 == (procOpen)(L"Microsoft Text SMS Protocol", 2, &smsHandle, &hEvent))
 {
 SMS_ADDRESS smsAdd;
 smsAdd.smsatAddressType = (sDest[0] == L'+') ? 1 : 0;
 int i;
 for(i = 0; i < sDest.GetLength() && i < 256; ++i)
 {
 smsAdd.ptsAddress[i] = sDest[i];
}
smsAdd.ptsAddress[i] = L'';
DWORD dwProviderSpecificDataSize = 0xa4;
BYTE* buffer2 = new BYTE[dwProviderSpecificDataSize];
memset(buffer2, 0, dwProviderSpecificDataSize);
buffer2[4] = 1; // messageclass = 1
 DWORD messageId;
 TRACE(L"SmsOpen OK\n");
if( 0 == (procSend)(smsHandle, NULL, &smsAdd, NULL, (BYTE*)sContent.GetBuffer(), sContent.GetLength() * 2, buffer2, dwProviderSpecificDataSize, 0, 0, &messageId))
{
TRACE(L"SmsSendMessage OK\n");
 (procClose)(smsHandle);
 bSuccess = TRUE;
}
sDest.ReleaseBuffer();
delete buffer2;
sContent.ReleaseBuffer();
}
}
return bSuccess;
}

static BOOL SendSMS_WM2k5(HMODULE hDll, CString sDest, CString sContent)
 {
 SendSMSMessage procSending = (SendSMSMessage)GetProcAddress(hDll, L"sendsmsmessage");
if(procSending)
 {
 TRACE(L"GetProcAddress: SendSMSMessage OK.\n");
 return ((procSending)(sDest, sContent, FALSE) == 0);
 }
 return FALSE;
}

static UINT ThreadSendSMS(LPVOID params)
{
 SMS_SENDING_INFO* info = (SMS_SENDING_INFO*)params;
 HINSTANCE hDllHandle = LoadLibrary(L"cemapi.dll");
 BOOL bRet;
 if(hDllHandle)
 {
 TRACE(L"SendSMS in cemapi.dll\n");
 bRet = SendSMS_WM2k5(hDllHandle, info->sDest, info->sContent);
 FreeLibrary(hDllHandle);
 }

 if(!hDllHandle || !bRet)
 {
 hDllHandle = LoadLibrary(L"sms.dll");
 if(hDllHandle)
 {
 TRACE(L"SendSMS in sms.dll\n");
 bRet = SendSMS_WM2k3(hDllHandle, info->sDest, info->sContent);
 FreeLibrary(hDllHandle);
 }
 else
 {
 bRet = FALSE;
 }
 }

 delete info;

 MessageBox(NULL, (bRet) ? L"Success" : L"Failed",
 "SMSSending", MB_ICONINFORMATION | MB_OK);

 return S_OK;
}

public:
static BOOL SendSMS(CString sDest, CString sContent)
{
 int i = 0;
 SMS_SENDING_INFO* info = new SMS_SENDING_INFO();
 info->sDest = sDest;
 info->sContent = sContent;

 while((NULL == AfxBeginThread(AFX_THREADPROC(ThreadSendSMS), info)) && i < 3)
 {
 ++i;
 }
 return (i!=3);
}

Update 17/04/2009:

I upload the source code here for people who want to take a quick test…

Advertisements
  1. Afriza
    09/04/2009 at 2:57 PM

    Hi, I saw in MSDN ( http://msdn.microsoft.com/en-us/library/aa923033.aspx ) that SmsOpen() requires Windows Embedded CE 6.0 and later. Is there any way to send SMS using WinCE 5.0 and older?

  2. phvu
    09/04/2009 at 9:13 PM

    Hi Afriza,
    I tested above code on both Windows Mobile 2003, Windows Mobile 2005 and Windows Mobile 6.1, and it does work well. Since I never ever worked on a real WinCE device, I’m not sure about this.

    In your link, I saw that sms.dll is supported on Windows Mobile 2002 and later, so if u r working on Windows Mobile, you can easily modify my code to achieve this task. In case you are working with Windows CE, well, you can take a test, and see does it work…

  3. Uk
    16/04/2009 at 3:43 PM

    Please could you provide the complete source and the binary for Sending SMS on windows 2003 in c++

  4. Uk1
    16/04/2009 at 3:44 PM

    Please could you provide the complete source and the binary for Sending SMS on windows 2003 in c++

  5. phvu
    17/04/2009 at 2:58 PM

    Well Uk,
    I’ve just uploaded the source code to SkyDrive. You can find the link in the end of the post. Give it a test, and please tell me if it works 😉
    Wait to hear from u 😀

  6. barbod
    20/04/2009 at 12:42 PM

    hi, when i use this code with HTCTouch-WindowsMobile 6
    , it send Flash SMS !!!
    how can i send normal sms with this code???

  7. phvu
    20/04/2009 at 8:43 PM

    hi barbod,
    After a little bit of researching, i saw that the wrapper System.WindowMobile.PocketOutlook from Microsoft does use SendSMSMessage (in cemapi.dll) like i did above. So i believe that this is the right way to send message in Windows Mobile.

    About the flash SMS u’ve just mentioned, since i’m stay at home and i don’t have a WM6 device right now, so i will give it a test with that device at my office. Maybe in 1 or 2 days more i will reply about this problem.

    In the mean time, you can try pass “TRUE” as the 3rd parameter to the function SendSmsMessage. By default, i pass “FALSE” for this parameter, but replace by “TRUE” may resolve the problem.

  8. 22/10/2009 at 5:31 PM

    hi
    Thanks alot. Thanks for Sharing this article is so gud and its fantastic. I tested above code on both Windows Mobile 2003, Windows Mobile 2005 and Windows Mobile 6.1, and it does work well. Can u tell me how can i SMS on windows 2003 in c++

  9. phvu
    23/10/2009 at 12:04 AM

    I absolutely have no idea with “Windows 2003”. Did you mean “Windows Server 2003”? Well, in this case, I think you can use some of free SMS services out there. And btw, it’s not the case this post is discussing at all 😀

  10. jim23
    10/08/2010 at 4:51 PM

    I tested the C# code and its working fine in my PDA,but the cpp code is not working.Is it because of the POcket PC 2003 SDK?

  11. jim23
    10/08/2010 at 6:17 PM

    I changed the SDK to Windows Mobile 5.0 Pocket PC SDK and also changed the ‘Additional options’ under

    Project->Properties->Configuration properties->Linker->Command Line
    to /subsystem:windowsce,5.01.
    Then the code was debugged successfully..
    but when it is executed on Windows Mobile device(PDA),its shows SMSSending_CPP.exe is not a valid Pocket PC application.
    Deploy getting failed?May I know a solution for this?

  12. phvu
    11/08/2010 at 9:11 PM

    Hi Jim23,
    could you please tell me the detail configuration of your PDA?

  13. jim23
    12/08/2010 at 2:14 PM

    now there is no problem with the exe…but the sms is not being sent with the cpp code..it shows the ‘Send SMS failed’ message.

  14. jim23
    12/08/2010 at 4:12 PM

    PDA uses Windows Mobile 6.1 version

  15. phvu
    12/08/2010 at 5:32 PM

    Hi Jim23, did you mean you run the code on an emulator? In that case, you definitely can not send any SMS message. If you run the code on a real PDA, and it does not send anything, please check the balance, SMS center configuration etc…

  16. phvu
    12/08/2010 at 5:34 PM

    At last, if everything is okie, you should try to replace every “TRACE” line in the source code to display a message box, then you can check what’s wrong with it.

  17. jim23
    13/08/2010 at 11:34 AM

    no,I tested on the device itself…Have you tested the cpp code on a Windows Mobile 6 device before?

  18. jim23
    13/08/2010 at 1:32 PM

    In the SendSMS_WM2k5() ,the address of the function “sendsmsmessage” in the cemapi.dll is not being loaded.

  19. phvu
    13/08/2010 at 3:50 PM

    I just test the code on an HTC Hero (or Viva, I don’t remember exactly the brand name) running Win Mobile 6.1. I cannot warranty it works well on every model, so I would like to know the exactly name of your device.

    In the code flow, you can see if it cannot send by cemapi.dll, it should try SendSMS_WM2k3(). Did you see any notification in SendSMS_WM2k3()?

  20. jim23
    13/08/2010 at 4:24 PM

    The device is a HTC Touch Diamond P3 model.Well,its failing at the SendSMS_WM2k3() too.What could be wrong if there was no problem in invoking the methods of cemapi.dll and sms.dll using the C# code in the same device?

  21. phvu
    13/08/2010 at 4:35 PM

    The only difference between the C# and C++ code is in the way we invoke APIs. In C#, this is done automatically by .NET CF’s P/Invoke mechanism, while in C++, we manually LoadLibrary/GetProcAddress and all of these stuffs.

    Since your device is a WinMobile 6.1, so I suppose it should go to SendSMS_WM2k5(). In this fuction, you can try to use GetLastError() after each call to the native API to see what’s really happens…

  22. jim23
    16/08/2010 at 1:07 PM

    Hi Phvu,I m getting error code 57 in SendSMS_WM2k5().Where am I going wrong?The procedure ‘SendSMSMessage’ in cemapi.dll is not getting called.

  23. phvu
    16/08/2010 at 1:25 PM

    As I can see on MSDN:
    http://msdn.microsoft.com/en-us/library/ms960717.aspx
    and
    http://msdn.microsoft.com/en-us/library/ms932980.aspx,
    error code 57 means “A network adapter hardware error occurred.”, but I do not really know why do we have to deal with the network adapter here.

    In this situation, I guess there is a problem with the device, or the WinMobile OS itself. Do you have any other WinMobile 6.1 device? Have you tested the CPP code on it?

    You also can try to find the file “cemapi.dll” on your device, then use programs like Dependency Walker to check if the cemapi.dll exports any function like “SendSMSMessage”. Note to check carefully, since any typo-error in the function name or arguments may makes the GetProcAddress call failed.

    The cemapi.dll is in the /Windows or /Windows/System directory on your device, it maybe set to be hidden, so you will have to turn on the hidden file option.

    Dependency Walker is a free utility to examine DLL/EXE files. You can google it.

  24. evren
    09/12/2010 at 11:20 PM

    hi I have project about smart home using pda and 8051 microcontroller

    how can I read income sms message from pocket pc in visaul stdio with c# language

    please help me

  25. phvu
    09/12/2010 at 11:34 PM

    Hi evren,
    It depends on the version of your device, I mean are you working on Pocket PC with Windows Mobile 5.0, 6.0 or 6.5? Are you using .NET Compact Framework etc…

    Since you have said you will use C#, I suppose you are going to work with a modern version of Windows Mobile OS, with .NET Compact Framework. If this is your case, you can use Windows CE API for SMS, which is described here: http://msdn.microsoft.com/en-us/library/aa920513.aspx. In .NET CF, you will need some P/Invoke declarations to call these APIs. I think the function of receiving SMS message is SmsReadMessage.

    In the case you are not working with WinMobile OSes and .NET CF, you can do some low-level codes, which directly communicates with the GSM modem inside the pocketPC. This is done by using AT Commands. You can google it. If I’m right, there are some great wrapper of AT Commands for easy communicating with GSM devices.

    Should you have any problems, tell me if I can help 🙂

  26. csg
    13/01/2011 at 11:28 PM

    Hi,

    I’m getting an 87′ (invalid parameter) Error in line 91 ( (SendSMSMessage)GetProcAddress(hDll, L”sendsmsmessage”) ). Any ideas? It driving me nuts…. 😀

  27. phvu
    13/01/2011 at 11:39 PM

    Hi csg,
    It seems the second parameter (L”sendsmsmessage”) is wrong. What is your test platform?
    I recommend you using Dependency Walker to check sms.dll on your device (copy sms.dll from the device to your PC, then open it in Dependency Walker) to see if it exports sendsmsmessage function. Every vendor can re-write WinCE, makes some changes… and perhaps your sms.dll doesn’t export this function, or exports it under a different name (SendSmsMessage, Sendsmsmessage…) Please note that the function name is case-sensitivity.

    Let me know if it work or not.

  28. csg
    25/01/2011 at 10:43 PM

    Hey phvu,

    any idea how I can copy the dlls from windows mobile? Either total commander, activesynch via pc or local copy functions are able to. The system just prohibits it. Realy annoying. :/

  29. phvu
    28/01/2011 at 7:34 PM

    Hi csg,
    Do you see the “sms.dll” on your device? (Use Explorer on your Windows Mobile Phone device to check). If it is there, hence the error might caused by security configuration of ActiveSync or the mobile phone itself. Perhaps you should try to decrease the security level and copy it again. As I remember, I copied it without problems with my device.

  30. Sridhar
    06/04/2011 at 5:31 PM

    How do you i contact you .. i need a help from you ? Please provide me your MSN

  31. phvu
    06/04/2011 at 8:42 PM

    Hi Sridhar,
    I don’t use MSN regularly. You can reach me on Skype: phoaivu

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: