.Net Compact Framework 高级篇(1)

本篇文章主要讲述短信拦截的一些方法,虽然该方法不是最理想的方法,但仍然能够达到相同的功效。作为高级篇的第一篇文章,希望文中的一些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)。则不会截获。 代码如下:、

 

代码
1 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 }

 

 

 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 try
24 {
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 else
40 {
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 else
79 {
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 finally
108 {
109 this.listBox1.Items.Add("Result: " + res.ToString());
110 SimDeinitialize(hSim);
111 }
112 }

 

 

在DllImport中定义SetLastError,这样在调用API出错时,可以通过Marshal.GetLastWin32Error()来取得ErrorCode。 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)

 

代码
1[StructLayout(LayoutKind.Sequential)]
2
public struct SystemTime
3{
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 SimMessageTag
32{
33
public int cbSize; // Size of the structure in bytes
34public int dwParams; //Indicates valid parameter values
35
36[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
37
public string lpszAddress; //An array that contains the actual phone number
38
39
public int dwAddressType; //A SIM_ADDRTYPE constant
40/**//*
41SIM_ADDRTYPE_UNKNOWN = Unknown.
42SIM_ADDRTYPE_INTERNATIONAL = International number.
43SIM_ADDRTYPE_NATIONAL 0ne National = number.
44SIM_ADDRTYPE_NETWKSPECIFIC Network = specific number.
45SIM_ADDRTYPE_SUBSCRIBER Subscriber = number
46(protocol-specific).
47SIM_ADDRTYPE_ALPHANUM Alphanumeric = address.
48SIM_ADDRTYPE_ABBREV Abbreviated = number.
49
*/
50
51
public int dwNumPlan; //A SIM_NUMPLAN constant
52/**//*
53SIM_NUMPLAN_UNKNOWN = Unknown.
54SIM_NUMPLAN_TELEPHONE = ISDN/telephone numbering plan
55(E.164/E.163).
56SIM_NUMPLAN_DATA = Data numbering plan (X.121).
57SIM_NUMPLAN_TELEX = Telex numbering plan.
58SIM_NUMPLAN_NATIONAL = National numbering plan.
59SIM_NUMPLAN_PRIVATE = Private numbering plan.
60SIM_NUMPLAN_ERMES ERMES = numbering plan (ETSI DE/PS 3 01-3).
61
*/
62
63
public SystemTime stReceiveTime; //Timestamp for the incoming message
64
65
public int cbHdrLength; //Header length in bytes
66
67[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
68
public byte[] rgbHeader; //An array containing the actual header data
69
70[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
71
public string lpszMessage; //An array containing the actual message data
72}

 

 

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

posted @ 2010-12-01 15:35  Wolves  阅读(214)  评论(0编辑  收藏  举报