`
ihuashao
  • 浏览: 4744596 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

从 Microsoft .NET Framework 精简版访问电话 API

阅读更多

从 Microsoft .NET Framework 精简版访问电话 API


Derek Mitchell
DEVBUZZ.COM, Inc.
2003年4月

适用于:
Microsoft® .NET Framework 精简版 1.0
Microsoft Visual Studio® .NET 2003

摘要:学习如何从基于 .NET Framework 精简版的应用程序访问电话 API。

下载 PhoneAPI.msi(英文)

目录

简介

本文旨在通过另外一个示例,说明在用 C# 和 VB.NET 编写的托管代码中调用本机 Microsoft® Win32® API 是大有裨益的。下面,我们看看 Pocket PC Phone Edition 支持的通用电话 API。

使用 C# 创建电话呼叫

本文下面所引用的所有代码都可以从此处下载(英文)。创建呼叫是一个基本操作;我们传递 PhoneMakeCall (Win32 API),它是一个字符串,指示目标地址以及是否需要在呼叫前确认等操作。我们需要进行多项声明。

private static long PMCF_DEFAULT               = 0x00000001;private static long PMCF_PROMPTBEFORECALLING   = 0x00000002;

然后定义一个对我们的目的用途不太大的结构。

private struct PhoneMakeCallInfo   {      public IntPtr cbSize;      public IntPtr dwFlags;      public IntPtr pszDestAddress;      public IntPtr pszAppName;      public IntPtr pszCalledParty;      public IntPtr pszComment;   }

cbSize 表明 PhoneMakeCallInfo 结构的大小。dwFlags 是一个选项位,用于指定呼叫前是否提示用户。pszDestAddress 是一个指针,指向要拨打的电话号码。当前不支持 pszAppName。pszCalledParty 为可选项,表示被叫方的姓名,大小有限。当前不支持 pszComment。现在,我们激活 PInvoke 并调用 DLLImport,以便访问 API 函数 PhoneMakeCall。

[DllImport("phone.dll")]private static extern IntPtr PhoneMakeCall(ref PhoneMakeCallInfo ppmci);

为了方便起见,我们包含了一个辅助函数,以便省略拨号前确认 Boolean。

/// <summary>/// 拨打指定的电话号码。/// </summary>/// <param name="PhoneNumber">要拨打的电话号码。</param>public static void MakeCall(string PhoneNumber){MakeCall(PhoneNumber, false);}

下面介绍一下 MakeCall 的功能。简而言之,我们将 PhoneNumber 参数(作为字符串传递)分割成一个字符数组。

PhoneNumber += '\0';char[] cPhoneNumber = PhoneNumber.ToCharArray();

指向字符数组在内存中的内存地址,并为此变量加上 fixed 关键字,表示不希望内存回收器移动固定括号内的内容。

   PhoneMakeCallInfo info = new PhoneMakeCallInfo();   info.cbSize = (IntPtr)Marshal.SizeOf(info);   info.pszDestAddress = (IntPtr)pAddr;   if (PromptBeforeCall)   {      info.dwFlags = (IntPtr)PMCF_PROMPTBEFORECALLING;   }   else   {      info.dwFlags = (IntPtr)PMCF_DEFAULT;   }

创建一个新的 PhoneMakeCallInfo 结构实例,指示是否希望在拨号之前进行确认以及是否将电话号码插入 pszDestAddress 字段。最后,我们将该结构实例作为引用传入 PhoneMakeCall。此函数使用 unsafe 关键字进行了修饰,因为它使用指针和直接内存访问。

使用 VB.NET 创建电话呼叫

用 VB.NET 编写的 MakeCall 代码与使用 C# 编写的代码相似(详细代码如上文所示),几乎不需要太大的改动。我们使用 IntPtr 变量保存多数函数的值。两者的不同之处在于,在 MakeCall 的前向声明中,我们指定 PhoneMakeCallInfo 结构实例将作为引用传递。

    <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 cPhoneNumber() As Char = PhoneNumber.ToCharArray()Dim pAddr() As Char = cPhoneNumberDim info As PhoneMakeCallInfo = New PhoneMakeCallInfoinfo.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(info)Dim iPhoneNumber As IntPtr = Marshal.AllocHLocal(cPhoneNumber.Length)        System.Runtime.InteropServices.Marshal.Copy(cPhoneNumber, 0,           iPhoneNumber, cPhoneNumber.Length)info.pszDestAddress = iPhoneNumber

将 pszDestAddress 成员指向此内存空间并设置拨号前确认选项后,将此结构实例传入 PhoneMakeCall。

If PromptBeforeCall Then   info.dwFlags = PMCF_PROMPTBEFORECALLINGElse   info.dwFlags = PMCF_DEFAULTEnd 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();         rec.cbSize = (IntPtr)Marshal.SizeOf(rec);         res = SimGetRecordInfo(hSim, (IntPtr)SERVICE_PROVIDER, ref rec);         if (res != IntPtr.Zero)            throw new Exception("无法从 SIM 中读取服务提供程序的信息");

然后,我们分配一个字节数组,用于存储 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];         int nPos = 0;         // 删除非 ASCII 字符         for (int i = 0; i < (int)dwBytesRead; i ++)         {            if (((int)bData[i] > 19) && ((int)bData[i] < 125))            {               bScrubbed[nPos] = bData[i];               nPos++;            }         }

然后取消初始化 SIM 并释放其资源。

      SimDeinitialize(hSim);

最后,返回“已删除”字节缓冲区的字符串表示形式。

使用 VB.NET 访问 SIM 信息

初始类声明与 C# 中的声明相同:

    Private Shared SERVICE_PROVIDER As Long = &H6F46    <StructLayout(LayoutKind.Sequential)> _    Public Structure SimRecord        Public cbSize As IntPtr        Public dwParams As IntPtr        Public dwRecordType As IntPtr        Public dwItemCount As IntPtr        Public dwSize As IntPtr    End Structure    <System.Runtime.InteropServices.DllImport("sms.dll")> _Private Shared Function SmsGetPhoneNumber(ByVal psmsaAddress As IntPtr) As   IntPtr    End Function    <System.Runtime.InteropServices.DllImport("cellcore.dll")> _Private Shared Function SimInitialize(ByVal dwFlags As IntPtr, ByVal   lpfnCallBack As IntPtr, ByVal dwParam As IntPtr, ByRef lphSim As IntPtr)   As IntPtr    End Function    <System.Runtime.InteropServices.DllImport("cellcore.dll")> _Private Shared Function SimGetRecordInfo(ByVal hSim As IntPtr, ByVal   dwAddress As IntPtr, ByRef lpSimRecordInfo As SimRecord) As IntPtr    End Function    <System.Runtime.InteropServices.DllImport("cellcore.dll")> _Private Shared Function SimReadRecord(ByVal hSim As IntPtr, ByVal   dwAddress As IntPtr, ByVal dwRecordType As IntPtr, _ByVal dwIndex As IntPtr, ByVal lpData() As Byte, ByVal dwBufferSize As   IntPtr, ByRef lpdwBytesRead As IntPtr) As IntPtr    End Function    <System.Runtime.InteropServices.DllImport("cellcore.dll")> _Private Shared Function SimDeinitialize(ByVal hSim As IntPtr) As IntPtr    End Function

GetPhoneNumber 函数相当于 C# 实现。首先创建缓冲区空间,并使用 P/Invoke 调用 SmsGetPhoneNumber 函数。

   Dim phoneaddr As PhoneAddress = New PhoneAddress   Dim buffer(512) As Byte   Dim pAddr() As Byte = buffer   Dim ipAddr As IntPtr = Marshal.AllocHLocal(pAddr.Length)   Dim res As IntPtr = IntPtr.Zero   Try      res = SmsGetPhoneNumber(ipAddr)   Catch ex As Exception      MessageBox.Show(ex.Message)   End Try   If (res.ToInt32 <> 0) Then      Throw New Exception("无法从 SIM 中获取电话号码")   End If

然后从返回的结构中获取地址类型信息。

   phoneaddr.AddressType =      System.Runtime.InteropServices.Marshal.ReadInt32(ipAddr)

将返回的电话号码缓冲区转换为一个字符串,然后返回完整的 PhoneAddress 结构。

GetServiceProvider 函数的情况也与 C# 版本中的情况非常相似。

   Dim hSim, res As IntPtr   hSim = IntPtr.Zero   Dim temp As Long   res = SimInitialize(IntPtr.Zero, Nothing, IntPtr.Zero, hSim)   If (res.ToInt32 <> 0) Then      Throw New Exception("无法初始化 SIM。")   End If

首先初始化 SIM,以便从中检索数据。

   Dim rec As SimRecord = New SimRecord   rec.cbSize =      Marshal.AllocHLocal(System.Runtime.InteropServices       .Marshal.SizeOf(temp))   rec.cbSize = IntPtr.op_Explicit(System.Runtime.InteropServices     .Marshal.SizeOf(rec))

创建一个新的 SimRecord 结构实例且只设置 cbSize 成员(并用 SimRecord 结构的大小填充该成员)。

   res = SimGetRecordInfo(hSim, IntPtr.op_Explicit(SERVICE_PROVIDER), rec)   If (res.ToInt32 <> 0) Then      Throw New Exception("无法从 SMS 中读取服务提供程序的信息。")   End If

调用 SimGetRecordInfo,获取包含 SERVICE_PROVIDER 数据的 SIM 记录的句柄。

   Dim bData((rec.dwSize).ToInt32 + 1) As Byte   Dim dwBytesRead As IntPtr = IntPtr.Zero   res = SimReadRecord(hSim, IntPtr.op_Explicit(SERVICE_PROVIDER),     rec.dwRecordType, IntPtr.Zero, bData,      IntPtr.op_Explicit(bData.Length), dwBytesRead)   If (res.ToInt32 <> 0) Then     Throw New Exception("无法从 SMS 中读取服务提供程序。")End If

然后,正如在 C# 代码中执行的操作一样,必须从产生的字节缓冲区中删除任何非 ASCII 字符,然后转换为字符串并返回该字符串值。

        Dim bScrubbed(dwBytesRead.ToInt32) As Byte        Dim nPos As Int32 = 0        Dim i As Int32        '删除非 ASCII 字符        For i = 0 To dwBytesRead.ToInt32            If bData(i) > 19 And bData(i) < 125 Then                bScrubbed(nPos) = bData(i)                nPos = nPos + 1            End If        Next i        SimDeinitialize(hSim)        Return System.Text.ASCIIEncoding.ASCII.GetString(bScrubbed, 0,          bScrubbed.Length)

代码使用

要使用 C# 从代码中创建电话呼叫,请调用:

Microsoft.Wireless.Phone.MakeCall("电话号码");

要使用 C# 从代码中获取 SIM 用户的电话号码,请调用:

Microsoft.Wireless.Sim.GetPhoneNumber()(该函数返回一个字符串)

要使用 C# 从代码中获取 SIM 用户的服务提供程序,请调用:

Microsoft.Wireless.Sim.GetServiceProvider()(该函数返回一个字符串)

要使用 VB.NET 从代码中创建电话呼叫,请调用:

Phone.MakeCall("电话号码");

要使用 VB.NET 从代码中获取 SIM 用户的电话号码,请调用:

Sim.GetPhoneNumber()(该函数返回一个字符串)

要使用 VB.NET 从代码中获取 SIM 用户的服务提供程序,请调用:

Sim.GetServiceProvider()(该函数返回一个字符串)

小结

本文旨在进一步说明从托管代码中调用重要的 Win32 API 函数类是非常有用且非常容易的。文中简要介绍了电话 API 类的使用。很明显,使用 P/Invoke 可以更好地利用 Win32 API 编程的功能。 <!-- END TOTAL PAGE CONTENT -->


分享到:
评论

相关推荐

    VS.NET和.NET Framework 精简版入门

    1. **系统需求**:明确列出运行VS.NET和.NET Framework精简版所需的最低硬件和软件配置,包括处理器速度、内存大小、操作系统版本等。 2. **安装指南**:详述如何下载、安装这两个工具,并可能包含任何特定的安装...

    Microsoft .NET Framework 4.6.rar

    Microsoft .NET Framework 4.6 是微软公司推出的一款重要的开发平台,它为Windows应用程序提供运行环境和支持服务。这个框架是.NET开发的核心组成部分,允许开发者使用多种编程语言(如C#、VB.NET、F#和C++/CLI)来...

    pocket pc 调用本地电话API

    从Microsoft .NET Framework 精简版访问电话API

    Microsoft.NET Compact Framework 微软 移动 开发 Windows Mobile

    《Microsoft.NET Compact Framework:微软移动开发的基石》 .NET Compact Framework是微软为移动设备和嵌入式系统设计的一个精简版.NET Framework,它为开发者提供了一个在Windows Mobile、Windows CE(包括Wince)...

    en_microsoft_.net_framework_4_for_server_core_x64_sc_640395.exe.zip

    标题中的"en_microsoft_.net_framework_4_for_server_core_x64_sc_640395.exe.zip"指的是微软的.NET Framework 4的一个特定版本,面向Server Core x64环境。这个文件是一个ZIP压缩包,包含有安装程序"en_microsoft_...

    microsoft net compact framework

    微软.NET Compact Framework是微软公司为嵌入式设备和移动设备开发的一款框架,它允许开发者在这些平台上构建和运行.NET应用程序。这个框架是.NET Framework的一个精简版本,针对资源有限的设备进行了优化,如...

    vs2003+.net移动应用开发

    即使开发的是托管代码,.NET Framework精简版也允许开发者集成非托管代码中存储的功能和子例程,例如Windows CE API。这意味着开发者可以充分利用现有的DLL和其他资源,无需完全依赖于.NET Framework。 ### 5. 用户...

    .net精简框架程序设计(VB.NET)

    1. **精简框架特性**:了解.NET精简框架与完整版.NET Framework的区别,如类库的缩减、内存管理的优化以及对特定API的支持。 2. **VB.NET基础**:掌握VB.NET的基本语法,包括变量声明、控制结构(如条件语句和循环...

    .NET Compact Framework 2.0.zip

    .NET Compact Framework 2.0是微软为嵌入式设备和移动平台开发的一个精简版.NET框架,主要用于掌上电脑(PDA)、智能手机和其他资源有限的设备。这个框架为开发者提供了在这些平台上构建和运行.NET应用程序的能力,...

    用[1].NET精简版2.0和SQL+Server+2005打造强力智能客户端

    标题中的“用.NET精简版2.0和SQL Server 2005打造强力智能客户端”指的是使用微软的.NET Framework 2.0精简版以及SQL Server 2005来构建高性能、功能丰富的桌面应用程序。这个过程涉及到多个IT领域的知识点,包括...

    net framework3.5.NET3.5手动安装包.zip

    在Windows 7和Windows 10系统中,.NET Framework 3.5是默认包含的,但在某些更新或精简版系统中可能未被预装,导致用户在尝试运行依赖此版本的软件时会遇到问题。 标题中的"NET Framework3.5.NET3.5手动安装包.zip...

    TapiLib.rar

    这篇从Microsoft .NET Framework 精简版访问电话API&gt;&gt;文章提供的示例中封装的Sim类中就有提供一个Sim.GetPhoneNumber()方法方便获取本机号码。 但是考虑到这个号码是可修改的且可以有很多个(通过PDA中提供的SIM管理...

    Microsoft.CompactFramework.CSharp

    【标题】:微软.NET Compact Framework C#开发详解 【描述】:Microsoft.NET Compact Framework是微软为小型设备如Windows CE(Windows Embedded Compact)操作系统提供的一种框架,它允许开发者使用C#和Visual ...

    Linker 让.net程序免于Framework安装的工具

    .NET Framework是一种由微软开发的运行时环境,它提供了执行.NET应用程序所需的各种服务,包括类型安全、垃圾回收、内存管理等。然而,.NET Framework本身体积较大,如果用户机器上没有安装相应版本的框架,就需要在...

    <.net 精简框架程序设计>

    .NET精简框架(.NET Compact Framework)是微软为嵌入式设备和移动设备设计的一个轻量级版本,它提供了.NET Framework的核心功能,但针对这些设备的内存和性能限制进行了优化。 首先,C#和VB.NET是.NET Framework的...

    微软.net精简框架最常见问题及回答.doc

    【微软.NET精简框架最常见问题及回答】 微软.NET精简框架是专为资源有限的嵌入式设备设计的一个轻量级版本的.NET框架。它提供了.NET Framework的核心功能,但针对移动设备和嵌入式系统进行了优化,以适应其硬件限制...

    Net Compact Framework SP2

    .NET Compact Framework (NET CF) 是微软为小型设备如个人数字助手(PDA)、智能手机和其他嵌入式系统设计的一个精简版.NET框架。它允许开发者使用.NET Framework相同的编程语言和工具,如C#和Visual Studio,来构建...

    微软.NET手持设备开发工具包基础篇

    《微软.NET手持设备开发工具包基础篇》这篇文章主要介绍了微软.NET Compact Framework的基础知识,它是针对手持设备开发的一种精简版的.NET框架。该框架与Smart Device Extensions (SDE) for Visual Studio .NET结合...

    [原版计算机类书籍]Sams.Microsoft.Dot.NET.Compact.Framework.Kick.Start.rar

    .NET Compact Framework是微软为嵌入式设备和移动设备设计的一个精简版本的.NET Framework,它提供了开发和运行.NET应用程序的能力,特别是在资源有限的设备上。这本书的目的是帮助读者快速入门,掌握在移动设备上...

    Programming the .NET Compact Framework in C#

    .NET Compact Framework是微软为小型设备和嵌入式系统设计的一个精简版.NET Framework,它提供了.NET Framework的核心功能,但体积更小,更适合资源有限的设备。这本书将引导读者了解如何在这些平台上利用C#的强大...

Global site tag (gtag.js) - Google Analytics