.Net Compact Framework 高级篇(1)
http://www.cnblogs.com/appleseeker/archive/2008/03/29/1129031.html
本篇文章主要讲述短信拦截的一些方法,虽然该方法不是最理想的方法,但仍然能够达到相同的功效。
作为高级篇的第一篇文章,希望文中的一些API的使用方法,能够给更多人予以帮助。
在.net 2.0中,MS就提供了Microsoft.WindowsMobile.PocketOutlook.MessageInterception命名空间,通过使用该命名空间,可以截获短信和邮件的到达消息。
该命名空间中的一些类及属性:
1.MessageInterceptor:监控对象类,一旦添加监控事件后,就会对所有消息进行监控。
2.MessageCondition:监控的过滤筛选条件类,通过设置需要过滤某个字段。
3.MessageInterceptorEventHandler:监控事件,一旦截获某消息,就立即执行该方法。
4.InterceptionAction(枚举):
Notify(提示,但此时系统仍会第一时间处理,自定义处理虽然有效,但肯定不是大家想要的。)
NotifyAndDelete(系统不会做任何处理,直接交给用户自己处理,同时达到的消息,如果用户不处理,则会删除。)
5.MessageProperty(枚举):按照某个属性进行对比
6.MessagePropertyComparisonType(枚举):对比方法
运行程序效果如下:
在Menu菜单下,点击Message Intercepter事件,开始监听。在此,我设置了,当发短消息的用户为Test Man时,将短消息过滤,不会在短消息的收件箱中出现,截获的内容这会在界面上显示。
测试:运行Cellular Emulator程序,输入电话号码及短信内容,发送到模拟器上。
模拟器效果如下:
可以看到消息已经被截获了,且消息内容一致。
如果发送号码为123456788,则不是添加的联系人(Test Man)。则不会截获。
代码如下:
private void menuItem4_Click(object sender, EventArgs e)2
{3
MessageInterceptor msgInterceptor = new MessageInterceptor();4
msgInterceptor.InterceptionAction = InterceptionAction.NotifyAndDelete;5

6
MessageCondition msgCondition = new MessageCondition();7
msgCondition.ComparisonType = MessagePropertyComparisonType.Contains;8
msgCondition.Property = MessageProperty.Sender;9
msgCondition.ComparisonValue = "Test Man";10

11
msgInterceptor.MessageCondition = msgCondition;12

13
msgInterceptor.MessageReceived += new MessageInterceptorEventHandler(msgInterceptor_MessageReceived);14
}15

16
void msgInterceptor_MessageReceived(object sender, MessageInterceptorEventArgs e)17
{18
this.listBox1.Items.Add("Type Name: " + e.Message.GetType().Name);19

20
if (e.Message.GetType() == typeof(SmsMessage))21
{22
SmsMessage sms = (SmsMessage)e.Message;23
this.listBox1.Items.Add("From: " + sms.From.Name);24
this.listBox1.Items.Add("Body: " + sms.Body);25
this.listBox1.Items.Add("Received Tiem: " + sms.Received.ToString("yyyy-MM-dd"));26
}27
if (e.Message.GetType() == typeof(EmailMessage))28
{29
EmailMessage mail = (EmailMessage)e.Message;30

31
this.listBox1.Items.Add("ItemId: " + mail.ItemId.ToString());32
}33
}Tips:
1.使用MessageInterceptor能监视的只是一个属性,如果根据不同用户,指定不同过滤操作的话,就无法实现。
2.一旦将InterceptionAction设为NotifyAndDelete,则系统就不做处理了,接收到的消息,就不会在收件箱中出现,需要自己添加进去(下文会介绍如何实现)
3.可以不设置MessageInterceptor的MessageCondition,这样使得所有消息都截获,然后自己处理,这时,就可以设置更广泛的过滤。
一旦将消息全部截获后,必不可少的会遇到一些不需要过滤的消息,此时,还要将消息重新放入收件箱中。很遗憾,暂时在托管环境中没有相应的操作类,相信MS会在以后的CF版本中会对此进行扩展的。
下面将介绍如何SIM卡的短消息的API。
涉及的API:
SimInitialize方法:初始化SIM卡的对象指针。
SimDeinitialize方法:释放SIM卡指针,类似于Ado里的连接对象,操作完后,关闭对象。
SimGetSmsStorageStatus方法:得到SIM卡里的可以存放的最大消息个数及已存放的消息个数。
SimReadMessage方法:从SIM卡中读取短信(如果SIM卡有短信)。
SimWriteMessage方法:向SIM卡中写入或修改短信。
SimDeleteMessage方法:删除SIM卡中某条短信。
涉及的结构体:
SimMessageTag:定义某条消息中的所有信息。
SystemTime:自定义的一个时间结构体。
在运行的程序中点击Test事件,则会读取SIM卡中所有短信,并且向SIM卡中添加一条短信。
运行该事件前,短信收件箱。
运行结果,读取SIM卡中的短信内容(只有1条)。
查看短信收件箱,该短信已写入。
通过这些API,我们可以很方便的将自己需要的短信写入SIM,而在过滤事件中过滤不需要的。
代码如下:
[DllImport("cellcore.dll", SetLastError=true)]2
private static extern int SimInitialize(int dwFlags, int lpfnCallBack, int dwParam, out int lphSim);3

4
[DllImport("cellcore.dll", SetLastError = true)]5
private static extern int SimDeinitialize(int hSim);6

7
[DllImport("cellcore.dll", SetLastError = true)]8
public static extern int SimGetSmsStorageStatus(int hSim, int dwStorage, ref int lpdwUsed, ref int lpdwTotal);9

10
[DllImport("cellcore.dll", SetLastError = true)]11
private static extern int SimWriteMessage(int hSim, int dwStorage, ref int lpdwIndex, ref SimMessageTag SmsStructType);12

13
[DllImport("cellcore.dll", SetLastError = true)]14
private static extern int SimReadMessage(int hSim, int dwStorage, int lpdwIndex, ref SimMessageTag SmsStructType);15

16
[DllImport("cellcore.dll", SetLastError = true)]17
private static extern int SimDeleteMessage(int hSim, int dwStorage, ref int lpdwIndex);18

19
private void menuItem6_Click(object sender, EventArgs e)20
{21
int hSim = 0, res = 0;22

23
try24
{25
res = SimInitialize((int)SIM_INIT_NONE, 0, (int)SIM_PARAM_MSG_ALL, out hSim);26

27
if (res != 0)28
throw new Exception("Could not initialize SIM");29

30
int used = 0, total = 0;31

32
res = SimGetSmsStorageStatus(hSim, (int)SIM_NUMSMSSTORAGES, ref used, ref total);33

34
if (res == 0)35
{36
this.listBox1.Items.Add("Used: " + used.ToString());37
this.listBox1.Items.Add("Total: " + total.ToString());38
}39
else40
{41
this.listBox1.Items.Add("Last Error: " + Marshal.GetLastWin32Error().ToString());42
}43

44
SimMessageTag message = new SimMessageTag();45

46
int index = 1;47

48
//res = SimDeleteMessage(hSim, (int)SIM_SMSSTORAGE_BROADCAST, ref index);49

50
//if (res != 0)51
//{52
// this.listBox1.Items.Add("Last Error: " + Marshal.GetLastWin32Error().ToString());53
//}54
//this.listBox1.Items.Add("Index: " + index.ToString());55

56
for (int j = 1; j <= used; j++)57
{58
res = SimReadMessage(hSim, (int)SIM_NUMSMSSTORAGES, j, ref message);59
if (res == 0)60
{61
this.listBox1.Items.Add("From: " + message.lpszAddress);62
this.listBox1.Items.Add("CBSize: " + message.cbSize.ToString());63
this.listBox1.Items.Add("Address Type: " + message.dwAddressType.ToString());64
this.listBox1.Items.Add("NumPlan: " + message.dwNumPlan.ToString());65
this.listBox1.Items.Add("Params: " + message.dwParams.ToString());66
char[] header = new char[message.rgbHeader.Length];67
string msg = "";68
for (int i = 0; i < message.rgbHeader.Length; i++)69
{70
header[i] = (char)message.rgbHeader[i];71
msg += header[i].ToString();72
}73
this.listBox1.Items.Add("Header: " + msg);74
this.listBox1.Items.Add("Receive Time: " + message.stReceiveTime.ToString());75
this.listBox1.Items.Add("Message: " + message.lpszMessage);76
this.listBox1.Items.Add("");77
}78
else79
{80
this.listBox1.Items.Add("Last Error: " + Marshal.GetLastWin32Error().ToString());81
}82
}83

84
SimMessageTag msg1 = new SimMessageTag();85
msg1.cbSize = message.cbSize;86
msg1.dwAddressType =1;87
msg1.dwNumPlan = 1;88
msg1.dwParams = 111;89
msg1.lpszAddress = "123456789";90
msg1.stReceiveTime = new global::SystemTime(System.DateTime.Now);91
msg1.lpszMessage = "It is a test mail!";92
msg1.cbHdrLength = 0;93
msg1.rgbHeader = new byte[256];94

95
index = used + 1;96

97
res = SimWriteMessage(hSim, (int)SIM_NUMSMSSTORAGES, ref index, ref msg1);98
if (res != 0)99
{100
this.listBox1.Items.Add("Last Error: " + Marshal.GetLastWin32Error().ToString());101
}102
}103
catch (Exception ex)104
{105
MessageBox.Show(ex.Message);106
}107
finally108
{109
this.listBox1.Items.Add("Result: " + res.ToString());110
SimDeinitialize(hSim);111
}112
}SimInitialize方法的第一个参数,网上很多直接写0,为什么是0,因为常量SIM_INIT_NONE定义为0。
在操作SIM卡消息时的所有方法都需要dwStorage参数,该参数常量定义为:
SIM_NUMSMSSTORAGES = 2,从SIM卡里读取
SIM_SMSSTORAGE_BROADCAST = 1,从设备本地读取
添加一条消息时,该消息结构体的赋值中
dwAddressType = 1 (SIM_ADDRTYPE_INTERNATIONAL)
dwNumPlan = 1 (SIM_NUMPLAN_TELEPHONE)
dwParams = 111 必须设为111,否则添加不了,该数字是属性累加起来的
cbHdrLength = 0 (短信头的长度通常为0)
[StructLayout(LayoutKind.Sequential)]2
public struct SystemTime3
{4
public short wYear;5
public short wMonth;6
public short wDayOfWeek;7
public short wDay;8
public short wHour;9
public short wMinute;10
public short wSecond;11
public short wMilliseconds;12

13
public SystemTime(System.DateTime now)14
{15
wYear = (short)now.Year;16
wMonth = (short)now.Month;17
wDayOfWeek = (short)now.DayOfWeek;18
wDay = (short)now.Day;19
wHour = (short)now.Hour;20
wMinute = (short)now.Minute;21
wSecond = (short)now.Second;22
wMilliseconds = (short)now.Millisecond;23
}24
public override string ToString()25
{26
return string.Format("{0}/{1}/{2}", wYear, wMonth, wDay);27
}28
}29

30
[StructLayout(LayoutKind.Sequential)]31
public struct SimMessageTag32
{33
public int cbSize; // Size of the structure in bytes34
public int dwParams; //Indicates valid parameter values35

36
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]37
public string lpszAddress; //An array that contains the actual phone number38

39
public int dwAddressType; //A SIM_ADDRTYPE constant40
/*41
SIM_ADDRTYPE_UNKNOWN = Unknown.42
SIM_ADDRTYPE_INTERNATIONAL = International number.43
SIM_ADDRTYPE_NATIONAL 0ne National = number.44
SIM_ADDRTYPE_NETWKSPECIFIC Network = specific number.45
SIM_ADDRTYPE_SUBSCRIBER Subscriber = number46
(protocol-specific).47
SIM_ADDRTYPE_ALPHANUM Alphanumeric = address.48
SIM_ADDRTYPE_ABBREV Abbreviated = number.49
*/50

51
public int dwNumPlan; //A SIM_NUMPLAN constant52
/*53
SIM_NUMPLAN_UNKNOWN = Unknown.54
SIM_NUMPLAN_TELEPHONE = ISDN/telephone numbering plan55
(E.164/E.163).56
SIM_NUMPLAN_DATA = Data numbering plan (X.121).57
SIM_NUMPLAN_TELEX = Telex numbering plan.58
SIM_NUMPLAN_NATIONAL = National numbering plan.59
SIM_NUMPLAN_PRIVATE = Private numbering plan.60
SIM_NUMPLAN_ERMES ERMES = numbering plan (ETSI DE/PS 3 01-3).61
*/62

63
public SystemTime stReceiveTime; //Timestamp for the incoming message64

65
public int cbHdrLength; //Header length in bytes66

67
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]68
public byte[] rgbHeader; //An array containing the actual header data69

70
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]71
public string lpszMessage; //An array containing the actual message data72
}Tips:
1.在调查dll的某些API的过程确实很复杂,需要不断尝试,这里推荐大家,一旦调用出错,可以通过Marshal.GetLastWin32Error()来取得ErrorCode,这样可以知道错误类型。在调用API时,尽量多参考其头文件,这样可以很方便了解这些方法中的一些结构体及一些常量。
2.如果运行模拟器的话,向SIM卡里添加短信后,在短信收件箱中不会显示出来,但实际是添加进去了。必须通过关闭电话,然后重新设置电话网络,这样SIM卡会重新加载。实际的设备应该不会这样。
总结:
本文提供给大家在.net cf下如何实现短信拦截的一个思路,该方法确实是可行的,希望大家能够掌握。短信拦截的方法不是唯一的,以后会介绍别的方法。
代码下载(附头文件以便大家能够理解):SmartDeviceOutlookDemo_2008_03_28.rar
cellcore.rar
Author:AppleSeeker
Date:2008-03-29


浙公网安备 33010602011771号