
| <System.Runtime.InteropServices.DllImport("phone.dll")> _ Private Shared Function PhoneMakeCall(ByRef ppmci As PhoneMakeCallInfo) As IntPtr End Function |
我们基本上按照前面的方法处理 PhoneMakeCallInfo 结构。将 PhoneNumber 字符串分割为一个字符数组,然后将 iPhoneNumber 用作内存调整指针写入内存。
|
PhoneNumber.Insert(PhoneNumber.Length, " ") Dim info As PhoneMakeCallInfo = New PhoneMakeCallInfo |
将 pszDestAddress 成员指向此内存空间并设置拨号前确认选项后,将此结构实例传入 PhoneMakeCall。
| If PromptBeforeCall Then info.dwFlags = PMCF_PROMPTBEFORECALLING Else info.dwFlags = PMCF_DEFAULT End If res = PhoneMakeCall(info) |
使用 C# 访问 SIM 信息
虽然称不上是对 Pocket PC Phone Edition 平台上的可用 SIM 访问函数的详细介绍,但我们将通过介绍如何检索 SIM 所有者的主要电话号码和服务提供程序的名称,进一步说明 P/Invoke 的用途。我们首先定义一个结构,用以存放 ping SIM 卡时获得的值,如下所示。
| [StructLayout(LayoutKind.Sequential)] private struct SimRecord { public IntPtr cbSize; public IntPtr dwParams; public IntPtr dwRecordType; public IntPtr dwItemCount; public IntPtr dwSize; } |
因为在本机代码和托管代码之间只能自动封送顺序布局结构,所以我们用顺序布局标记修饰我们的结构。cbSize 是所传递结构的大小。dwParams 是参数值,这里我们并不用担心。dwRecordType 表示记录的格式。选项包括:
|
值 |
说明 |
|---|---|
| SIM_RECORDTYPE_UNKNOWN | 未知的文件类型。 |
| SIM_RECORDTYPE_TRANSPARENT | 单个变长记录。 |
| SIM_RECORDTYPE_CYCLIC | 循环记录集,每个记录具有相同长度。 |
| SIM_RECORDTYPE_LINEAR | 线性记录集,每个记录具有相同长度。 |
| SIM_RECORDTYPE_MASTER | 每个 SIM 都有一个主记录,实际上是主节点。 |
| SIM_RECORDTYPE_DEDICATED | 实际上是作为其他记录的上级记录的“目录”文件。 |
dwItemCount 是记录中的项数。dwSize 是记录中每项的大小。接下来,我们将有许多利用了 DLLImport 的函数声明。
[DllImport("sms.dll")]
private static extern IntPtr SmsGetPhoneNumber(IntPtr psmsaAddress);
检索 SIM 所有者的电话号码。
| [DllImport("cellcore.dll")] private static extern IntPtr SimInitialize(IntPtr dwFlags, IntPtr lpfnCallBack, IntPtr dwParam, out IntPtr lphSim); |
此函数是调用任何 SIM 访问函数所必需的。如果执行成功,则返回一个指向 HSIM 句柄的指针,以便在随后的调用中使用。
| [DllImport("cellcore.dll")] private static extern IntPtr SimGetRecordInfo(IntPtr hSim, IntPtr dwAddress, ref SimRecord lpSimRecordInfo); |
此函数接受从 SimInitialize 返回的 HSIM 句柄以及一个 SIM 地址 (dwAddress) 和一个 SIM 记录结构,并用请求的信息填充此结构。
| [DllImport("cellcore.dll")] private static extern IntPtr SimReadRecord(IntPtr hSim, IntPtr dwAddress, IntPtr dwRecordType, IntPtr dwIndex, byte[] lpData, IntPtr dwBufferSize, ref IntPtr lpdwBytesRead); |
此函数接受从 SimInitialize 返回的 HSIM 句柄,以及一个 SIM 地址 (dwAddress)、一个 dwRecordType(请参见上表)、dwIndex(如果使用 SIM_RECORDTYPE_CYCLIC 或 SIM_RECORDTYPE_LINEAR)、lpData(指向数据缓冲区)、dwBufferSize(表示缓冲区大小)以及 lpdwBytesRead(表示要读取的字节数)。
[DllImport("cellcore.dll")]
private static extern IntPtr SimDeinitialize(IntPtr hSim );
此函数发布在 SimInitialize 中创建的 HSIM 句柄的资源。
我们将实现两种重要的电话 API 调用:获取当前 SIM 所有者的电话号码,并获取 SIM 当前访问的服务提供程序的名称。
在 GetPhoneNumber 中,我们所做的只是定义一个大型字节缓冲区并将其传入 SmsGetPhoneNumber。
| Byte[] buffer = new Byte[516]; fixed (byte* pAddr = buffer) { IntPtr res = SmsGetPhoneNumber((IntPtr)pAddr); if (res != IntPtr.Zero) throw new Exception("无法从 SIM 中获取电话号码"); |
然后获取返回的 PhoneAddress 类型和 PhoneAddress 电话号码。
| byte *pCurrent = pAddr; phoneaddr.AddressType = (AddressType)Marshal.ReadInt32((IntPtr)pCurrent); pCurrent += Marshal.SizeOf(phoneaddr.AddressType); phoneaddr.Address = Marshal.PtrToStringUni((IntPtr)pCurrent); } |
此函数声明为 unsafe,因为我们是直接从内存中的托管代码读取。
在下一个函数 GetServiceProvider 中,我们首先初始化 SIM
| res = SimInitialize(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, out hSim); if (res != IntPtr.Zero) throw new Exception("无法初始化 SIM"); |
然后声明一个 SIM 记录结构实例,并请求在调用 SimGetRecordInfo 时检索包含 SERVICE_PROVIDER 的值的 SimRecord 的句柄。
|
SimRecord rec = new SimRecord(); res = SimGetRecordInfo(hSim, (IntPtr)SERVICE_PROVIDER, ref rec); |
然后,我们分配一个字节数组,用于存储 SIM 记录(包含 SERVICE_PROVIDER 详细信息)的内容。
| byte[] bData = new byte[(int)rec.dwSize + 1]; IntPtr dwBytesRead = IntPtr.Zero; |
然后请求读取 SERVICE_PROVIDER 记录的内容。
| res = SimReadRecord(hSim, (IntPtr)SERVICE_PROVIDER, rec.dwRecordType, IntPtr.Zero, bData, (IntPtr)bData.Length, ref dwBytesRead); if (res != IntPtr.Zero) throw new Exception("无法从 SIM 中读取服务提供程序"); |
然后查看返回的结构,并删除在显示最终结果时可能会破坏代码的任何非标准 ASCII 字符。
|
byte[] bScrubbed = new byte[(int)dwBytesRead]; // 删除非 ASCII 字符 |
然后取消初始化 SIM 并释放其资源。
SimDeinitialize(hSim);
最后,返回“已删除”字节缓冲区的字符串表示形式。
上一篇: Windows CE通讯模式
下一篇: 在.NET Framework精简版中使用XML Web Service
25年牵手相伴,2500台经典机型限量特供,800-858-2883手机400-884-9425