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) ? CMultiLang::sMsgSMSSuccess() : CMultiLang::sMsgSMSFail(),
			CMultiLang::sAppName(), 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…


9 Responses to “Sending SMS message in Windows CE”

  1. Afriza Says:

    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 Says:

    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 Says:

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

  4. Uk1 Says:

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

  5. phvu Says:

    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 :D

  6. barbod Says:

    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 Says:

    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. Sending SMS Says:

    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 Says:

    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 :D

Leave a Reply