Benjamin

静以修身,俭以养德,非澹薄无以明志,非宁静无以致远。
随笔 - 276, 文章 - 0, 评论 - 196, 引用 - 0
数据加载中……

WINCE下如何实现发短信

#include <sms.h>
#pragma comment(lib,"sms.lib")
void SendSMS1(LPCTSTR lpszMessage, LPCTSTR lpszRecipient,LPCTSTR lpszSMSC,BOOL bSendConfirmation, BOOL bUseDefaultSMSC)
{

 SMS_HANDLE smshHandle; //短信句柄
 SMS_ADDRESS smsaDestination;//接收号码
 TEXT_PROVIDER_SPECIFIC_DATA tpsd;
 SMS_MESSAGE_ID smsmidMessageID;

 // 打开发送句柄
 // 协议字符串,       SMS_MODE_SEND:发送模式 psmshHandle:返回的句柄 phMessageAvailableEvent:通知的事件
 if(FAILED(SmsOpen(SMS_MSGTYPE_TEXT, SMS_MODE_SEND, &smshHandle, NULL)))
 {
  return;
 }


 // Create the destination address
//SMSAT_NATIONAL:国内电话 SMSAT_INTERNATIONAL:国际电话
 smsaDestination.smsatAddressType = SMSAT_UNKNOWN;
 _tcsncpy(smsaDestination.ptsAddress, lpszRecipient, SMS_MAX_ADDRESS_LENGTH);

 // Set up provider specific data
 memset(&tpsd, 0, sizeof(tpsd));
 //tpsd.dwMessageOptions =  PS_MESSAGE_OPTION_NONE;
 tpsd.dwMessageOptions =  PS_MESSAGE_OPTION_STATUSREPORT;//表示需要状态报告
 tpsd.psMessageClass = PS_MESSAGE_CLASSUNSPECIFIED;
//PS_MESSAGE_CLASS0表示短信在被接收后立即显示且不存储在收件箱(称为闪信)
 //PS_MESSAGE_CLASS1表示一般的情况,被接收后存储到收件箱并发送一个确认回短信中心,发送方收到一个已被接收的状态报告。
 tpsd.psReplaceOption = PSRO_NONE;
 //手动清空头信息 
 ZeroMemory(tpsd.pbHeaderData, sizeof(tpsd.pbHeaderData));        
 tpsd.dwHeaderDataSize = 0;
 tpsd.fMessageContainsEMSHeaders = FALSE;
 tpsd.dwProtocolID = SMS_MSGPROTOCOL_UNKNOWN;

 // Send the message, indicating success or failure
 /*
 *smshHandle: SmsOpen打开的句柄
 􀁺 psmsaSMSCAddress: SMSC中心
 􀁺 *psmsaDestinationAddress:发送的目的地址
 􀁺 pstValidityPeriod :发送时间的有效期
 􀁺 *pbData: 信息的内容部分
 􀁺 *dwDataSize: 信息的内容部分的长度
 􀁺 *pbProviderSpecificData:针对运营商的附加数据
 􀁺 *dwProviderSpecificDataSize :附加数据的长度
 􀁺 smsdeDataEncoding :短信编码[SMSDE_OPTIMAL是其
 推荐值]表示由短信中心决定字符的格式
 􀁺 dwOptions :其他选项
 􀁺 psmsmidMessageID: 用于得到系统回执的信息
 SmsGetMessageStatus
 */

//SMSDE_GSM使用7-bit编码
 //SMSDE_UCS2使用16-bit (Unicode)编码
 if(SUCCEEDED(SmsSendMessage(smshHandle, NULL,
  &smsaDestination, NULL, (PBYTE) lpszMessage,
  _tcslen(lpszMessage) * sizeof(TCHAR), (PBYTE) &tpsd,
  sizeof(TEXT_PROVIDER_SPECIFIC_DATA), SMSDE_UCS2,
  SMS_OPTION_DELIVERY_NONE, &smsmidMessageID)))
 {
  //Tstr=L"发送完成";


  //发送完成
  MessageBox(    NULL,L"SEND OK",L"MSG",MB_OK);
 }
 else
 {

  //发送失败
  //Tstr=L"发送失败";
  MessageBox(NULL,L"发送失败",L"MSG",MB_OK);
 }

 // clean up
 VERIFY(SUCCEEDED(SmsClose(smshHandle)));



注意:LPCTSTR 和 PCWSTR是宽字符,所以用16-bit (Unicode)编码。网上的HelloSMS的程序不够严谨,如果照用可能造成短信中心网关把短信给吞掉的情况,程序虽然调用成功,但是就是目标号码收不到短信。函数参数中的后三个参数可以不用或设默认值都可以。

使用Windows CESMS API函数SmsSendMessage可以发送7-bit编码和16-bit编码的短消息(未测试8-bit编码)。单条短消息的最大字符数分别是16070。发送短消息全部为ASCII字符,SMS_DATA_ENCODING参数选择SMSDE_GSMSMSDE_OPTIMAL都可以。发送短消息不全为ASCII字符,SMS_DATA_ENCODING参数选择SMSDE_UCS2SMSDE_OPTIMAL都可以。建议选择SMSDE_OPTIMAL

发送短消息全部为ASCII字符,且字符个数超过160个时,系统会自动将短消息进行分割,但并不是按每条160进行分割,而是按每条153。发送短消息不全为ASCII字符,且字符个数超过70个时,系统会自动将短消息进行分割,但并不是按每条70进行分割,而是按每条67

发送短消息的字符数超过16070时,应该自行进行分割,而不应交由系统进行分割,这样可以最大限度的利用单条短消息的最大字符数分别是16070的条件.

上面的代码是通过MAPI来实现,任意一部有SIM卡的PDA/PPC上都已运行。


下面的代码是通过串口和AT指令来发送短信,需要有Gms Modem 才可以运行。
HANDLE hSerial;
 int res;
 unsigned long bytes;
 
 //COM1 COM2 COM4
 hSerial = CreateFile(_T("COM1:"), GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
 
 
 
 if(hSerial == NULL)
 {
  ///L"串口打开失败";
  return;
 }
 ///配置串口
 DCB  PortDCB;   
 PortDCB.DCBlength = sizeof(DCB);
 // 默认串口参数
 GetCommState(hSerial, &PortDCB);
 PortDCB.BaudRate =115200 ; // baud
 PortDCB.ByteSize = 8;     // Number of bits/byte, 4-8
 PortDCB.Parity = NOPARITY;
 PortDCB.StopBits = ONESTOPBIT; 
 PortDCB.fBinary=TRUE;
 if (! SetCommState(hSerial, &PortDCB))
 {
  ///L"配置串口失败";
  return;
 }
 ////配置超时值
 COMMTIMEOUTS  CommTimeouts;
 GetCommTimeouts(hSerial, &CommTimeouts);
 CommTimeouts.ReadIntervalTimeout = 100; 
 CommTimeouts.ReadTotalTimeoutMultiplier = 100; 
 CommTimeouts.ReadTotalTimeoutConstant = 100;   
 CommTimeouts.WriteTotalTimeoutMultiplier =100; 
 CommTimeouts.WriteTotalTimeoutConstant = 100;   
 if (!SetCommTimeouts(hSerial, &CommTimeouts))
 {
  
  return;
                
 
 //设置串口“感兴趣”的事件
 SetCommMask(hSerial, EV_RXCHAR);
 
 //设置输入输出缓冲区
 SetupComm(hSerial, 1024, 1024);
 
 //初始化缓冲区中的信息
 PurgeComm(hSerial, PURGE_TXCLEAR|PURGE_RXCLEAR);
 
//-------------------------------------串口设置完毕----------------------------------------


 UpdateData(TRUE);

 char str_last[2000];
 int num_Length=0;
 int context_length=0;
 TCHAR tmp[2];
 int i=0;
 char addr[100]="0891683108100005F0";//短信中心号码 
 char phone[100]="11000D91";
 char msg[1000];
// unsigned char *msg_tmp;
 unsigned char msg_tmp[1000];

 
 char str_tmp[100]="";
 char str_tmp2[50]="000800";

 num_Length=m_num.GetLength();
 context_length=m_context.GetLength();

 m_num=L"86"+m_num;
 if(num_Length%2){m_num=m_num+L"F";}


 for (i=0; i <(m_num.GetLength()); )  //处理 目标电话号码 奇偶换位
 {
  phone[i+9] = m_num.GetAt(i);
  phone[i+8] = m_num.GetAt(i+1);
  i+=2;
 }

WideCharToMultiByte(CP_ACP, 0, m_context, m_context.GetLength(), str_tmp, 160, NULL, NULL);

// msg_tmp=(unsigned char *)malloc(sizeof(unsigned char ));
 gsmEncodeUcs2(str_tmp,msg_tmp,context_length);//UCS2编码

 for(i=0;i<context_length*2;i++)//将编后的码转换为16进制以进行传输 前两位预留
 {
  wsprintf(tmp, L"%02X", msg_tmp[i]);
  msg[2*i+2]=tmp[0];
  msg[2*i+3]=tmp[1];
 
 }
 
 
 wsprintf(tmp, L"%02X", context_length*2);//前两位存储msg的长度
 msg[0]=tmp[0];
 msg[1]=tmp[1];

//-------------------------------addr phone msg 全部就绪----------------------------
// 最终信息为 str_last=addr+phone+000800+msg 

 for(i=0;i<18 ;i++)
 {
  str_last[i]=addr[i];
 }
 
 for(i=0;i<22 ;i++)
 {
  str_last[i+18]=phone[i];
 }
 

 for(i=0;i<6 ;i++)
 {
  str_last[i+40]=str_tmp2[i];
 }
 
 for(i=0;i<context_length*4+2 ;i++)
 {
  str_last[i+46]=msg[i];
 }

 str_last[i+46]='\32';

 
//--------------------------开始发送-------------------------------------------- 
 
 char str1[100]="AT+CMGS=25\r";
 wsprintf(tmp, L"%02d",(context_length*4+30)/2);//计算需要发送的字节

 str1[8]=tmp[0];
 str1[9]=tmp[1];

 char str2[100]="";
 res=WriteFile(hSerial,str1,100,&bytes,NULL);
 res=ReadFile(hSerial,str2,100,&bytes,NULL);
 
 

 char str3[100]="";
 res=WriteFile(hSerial,str_last,1000,&bytes,NULL);
 res=ReadFile(hSerial,str3,100,&bytes,NULL);
//----------------------------发送结束------------------------------------------------------- 

// free(msg_tmp);
 CloseHandle(hSerial); 
}

BOOL CSendMessage2::OnInitDialog()
{
 CDialog::OnInitDialog();
 
 // TODO: Add extra initialization here
// m_num=L"15010657623";
 m_num=L"13811916883";

// m_context=L"1192323 392486";
 m_context=L"工作愉快!";
 UpdateData(false);  
 return TRUE;

网上的HelloSMS的发送短信代码,有不完善的地方。用它来发短信可能会有问题,下面这段代码是我对它的一个改进,基本可以运行在实际的项目中:
////////////////////////////////////////////////////////////////////////////
//                         发送短信
//lpszSMSC:短信中心号码  lpszRecipient:接收号码(目标号码)
//lpszMessage:发送短信内容
//bUseDefaultSMSC:目标地址 
//bSendConfirmation:消息发送选项
////////////////////////////////////////////////////////////////////////////
void CCellGuardApp::SendSMS( LPCTSTR lpszMessage, LPCTSTR lpszRecipient,LPCTSTR lpszSMSC,BOOL bSendConfirmation, BOOL bUseDefaultSMSC)
{
 SMS_HANDLE smshHandle; //短信句柄
 SMS_ADDRESS smsaDestination;//接收号码
 TEXT_PROVIDER_SPECIFIC_DATA tpsd;
 SMS_MESSAGE_ID smsmidMessageID;

 // 打开发送句柄
 // 协议字符串,       SMS_MODE_SEND:发送模式 psmshHandle:返回的句柄 phMessageAvailableEvent:通知的事件
 if(FAILED(SmsOpen(SMS_MSGTYPE_TEXT, SMS_MODE_SEND, &smshHandle, NULL)))
 {
  return;
 }

 // Create the destination address
 smsaDestination.smsatAddressType = SMSAT_UNKNOWN;
 _tcsncpy(smsaDestination.ptsAddress, lpszRecipient, SMS_MAX_ADDRESS_LENGTH);

 // Set up provider specific data
 memset(&tpsd, 0, sizeof(tpsd));
 //tpsd.dwMessageOptions =  PS_MESSAGE_OPTION_NONE;
 tpsd.dwMessageOptions =  PS_MESSAGE_OPTION_STATUSREPORT;
 tpsd.psMessageClass = PS_MESSAGE_CLASSUNSPECIFIED;
 tpsd.psReplaceOption = PSRO_NONE;
 //tpsd.dwHeaderDataSize = 0;
 ZeroMemory(tpsd.pbHeaderData, sizeof(tpsd.pbHeaderData));        
 tpsd.dwHeaderDataSize = 0;
 tpsd.fMessageContainsEMSHeaders = FALSE;
 tpsd.dwProtocolID = SMS_MSGPROTOCOL_UNKNOWN;

 // Send the message, indicating success or failure
 if(SUCCEEDED(SmsSendMessage(smshHandle, NULL,
  &smsaDestination, NULL, (PBYTE) lpszMessage,
  _tcslen(lpszMessage) * sizeof(TCHAR), (PBYTE) &tpsd,
  sizeof(TEXT_PROVIDER_SPECIFIC_DATA), SMSDE_UCS2,
  SMS_OPTION_DELIVERY_NONE, &smsmidMessageID)))
 {
  //Tstr=L"发送完成";
  //发送完成
  ;
 }

 // clean up
 VERIFY(SUCCEEDED(SmsClose(smshHandle)));
}

posted on 2008-04-10 11:17 Benjamin 阅读(3409) 评论(3)  编辑 收藏 引用 所属分类: PDA/PPC开发

评论

# re: WINCE下如何实现发短信  回复  更多评论   

Thank you!
通过看你的介绍把我的一个问题解决了!

不胜感激啊!
2009-03-09 17:23 | Sandy

# re: WINCE下如何实现发短信  回复  更多评论   

弄错了一个参数
PS_MESSAGE_CLASSUNSPECIFIED

这个参数设置以后,短信发出去了,但是却引起了tmail.exe的异常

不知道什么原因造成的
2009-03-09 19:30 | Sandy

# re: WINCE下如何实现发短信  回复  更多评论   

但是WINCE开发包中没有 sms.h 啊,windows mobile中倒是有
2009-07-10 11:04 | hou

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理