<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>好贴子可不能找不到了</title><link>http://blog.vckbase.com/teky/category/963.html</link><description>收藏好贴</description><managingEditor>teky </managingEditor><dc:language>zh-CHS</dc:language><generator>.Text Version 0.958.2004.214</generator><item><dc:creator>teky </dc:creator><title>改进基于 Microsoft .NET Framework 精简版应用程序窗体的加载性能</title><link>http://blog.vckbase.com/teky/articles/24681.html</link><pubDate>Wed, 28 Feb 2007 02:52:00 GMT</pubDate><guid>http://blog.vckbase.com/teky/articles/24681.html</guid><wfw:comment>http://blog.vckbase.com/teky/comments/24681.html</wfw:comment><comments>http://blog.vckbase.com/teky/articles/24681.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://blog.vckbase.com/teky/comments/commentRss/24681.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/teky/services/trackbacks/24681.html</trackback:ping><description>&lt;A href="http://www.microsoft.com/china/MSDN/library/archives/library/dnnetCOMp/html/netcfimproveformloadperf.asp"&gt;http://www.microsoft.com/china/MSDN/library/archives/library/dnnetCOMp/html/netcfimproveformloadperf.asp&lt;/A&gt;&lt;BR&gt;&lt;BR&gt;
&lt;H1&gt;改进基于 Microsoft .NET Framework 精简版应用程序窗体的加载性能&lt;/H1&gt;&lt;FONT class=90v&gt;&lt;BR&gt;Neil Cowburn&lt;BR&gt;Content Master Ltd &lt;BR&gt;2003年3月 
&lt;P&gt;适用于：&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Microsoft&amp;#174; .NET Framework 精简版 1.0&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Microsoft Visual Studio&amp;#174; .NET 2003&lt;/P&gt;
&lt;P&gt;&lt;B&gt;摘要&lt;/B&gt;：学习如何通过一些简单的优化技术来减少 .NET Framework 精简版 Windows 窗体应用程序加载所需的时间。 &lt;/P&gt;
&lt;H4 class=dtH1&gt;目录&lt;/H4&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://www.microsoft.com/china/MSDN/library/archives/library/dnnetCOMp/html/netcfimproveformloadperf.asp#netcfimproveformloadperf_topic1" target=_self&gt;简介&lt;/A&gt; 
&lt;LI&gt;&lt;A href="http://www.microsoft.com/china/MSDN/library/archives/library/dnnetCOMp/html/netcfimproveformloadperf.asp#netcfimproveformloadperf_topic2" target=_self&gt;测量性能&lt;/A&gt; 
&lt;LI&gt;&lt;A href="http://www.microsoft.com/china/MSDN/library/archives/library/dnnetCOMp/html/netcfimproveformloadperf.asp#netcfimproveformloadperf_topic3" target=_self&gt;减少方法调用的数目&lt;/A&gt; 
&lt;LI&gt;&lt;A href="http://www.microsoft.com/china/MSDN/library/archives/library/dnnetCOMp/html/netcfimproveformloadperf.asp#netcfimproveformloadperf_topic4" target=_self&gt;自上而下地创建控件&lt;/A&gt; 
&lt;LI&gt;&lt;A href="http://www.microsoft.com/china/MSDN/library/archives/library/dnnetCOMp/html/netcfimproveformloadperf.asp#netcfimproveformloadperf_topic5" target=_self&gt;更多信息&lt;/A&gt; &lt;/LI&gt;&lt;/UL&gt;
&lt;H2 class=dtH1&gt;&lt;A name=netcfimproveformloadperf_topic1&gt;&lt;/A&gt;简介&lt;/H2&gt;
&lt;P&gt;默认的 Forms Designer（窗体设计器）生成的代码不能始终创建适用于创建 Microsoft&amp;#174; Windows&amp;#174; 窗体的最优代码。但是，执行一些操作可以帮助优化生成的代码。通过编写自己的窗体初始化代码，可以改进窗体的加载性能。&lt;/P&gt;
&lt;P&gt;此外，通过重新排列和/或覆盖由 Microsoft Visual Studio&amp;#174; .NET 中的 Forms Designer（窗体设计器）生成的代码，可以显著提高应用程序整个窗体的加载性能。&lt;/P&gt;
&lt;BLOCKQUOTE class=dtBlock&gt;&lt;B class=le&gt;警告：&lt;/B&gt;请勿在修改 InitializeComponent 后使用设计器。&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE class=dtBlock&gt;InitializeComponent 方法前有一个注释，警告您不要修改代码。如果修改 &lt;CODE class=ce&gt;InitializeComponent&lt;/CODE&gt; 方法中的代码，将无法再使用 Forms Designer（窗体设计器）。如果使用 Forms Designer（窗体设计器），所做的修改将丢失。只应在开发的最后阶段，完成所有设计工作后，再执行这些优化。&lt;/BLOCKQUOTE&gt;
&lt;P&gt;本文假定您在 Microsoft .NET Framework 精简版和 Microsoft Visual C#&amp;#174; .NET 方面有一定的使用经验，并且已安装了 Visual Studio .NET 2003。&lt;/P&gt;
&lt;H2 class=dtH1&gt;&lt;A name=netcfimproveformloadperf_topic2&gt;&lt;/A&gt;测量性能&lt;/H2&gt;
&lt;P&gt;要测量窗体初始化代码的性能，可以使用一个简单的测试来测量初始化窗体控件所需的时间。通过记录调用 &lt;CODE class=ce&gt;InitializeComponent&lt;/CODE&gt; 方法前后系统计时器的刻度计数，可以记录初始化窗体控件所需的时间。为此，您可以通过 &lt;B&gt;Platform Invoke&lt;/B&gt; (P/Invoke) 使用 coredll.dll 中的 &lt;CODE class=ce&gt;GetTickCount()&lt;/CODE&gt; API 调用。&lt;/P&gt;&lt;PRE class=code&gt;// GetTickCount() 的 API 原型
[DllImport("coredll.dll", EntryPoint="GetTickCount")]
public static extern uint GetTickCount();
// 窗体构造函数
public Form1()
{
    uint startTickCount, endTickCount, timeTaken;
    // 调用 GetTickCount 获取起始刻度计数
    startTickCount = GetTickCount();
    // 初始化窗体中的控件
    InitializeComponent();
    // 再次调用 GetTickCount 获取最终的刻度计数
    endTickCount = GetTickCount();
    // 计算初始化控件所用的时间（以毫秒为单位）
    timeTaken = startTickCount - endTickCount;
    // 在消息框中显示所用的时间
    MessageBox.Show("加载时间：" + timeTaken.ToString() + "毫秒");
}
&lt;/PRE&gt;
&lt;H2 class=dtH1&gt;&lt;A name=netcfimproveformloadperf_topic3&gt;&lt;/A&gt;减少方法调用的数目&lt;/H2&gt;
&lt;P&gt;提高窗体加载性能的方法之一是减少窗体初始化期间生成的方法调用的数目。例如，Forms Designer（窗体设计器）生成的用于设置控件的位置和大小的代码使用两个方法调用来设置这些属性，如下所示：&lt;/P&gt;&lt;PRE class=code&gt;    this.textBox1.Location = &lt;CODE&gt;&lt;B class=cfe&gt;new&lt;/B&gt;&lt;/CODE&gt; Point(10,20);
    this.textBox1.Size = &lt;CODE&gt;&lt;B class=cfe&gt;new&lt;/B&gt;&lt;/CODE&gt; Size(72,23);
&lt;/PRE&gt;
&lt;P&gt;使用 Bounds 属性可以将这两个方法调用统一成一个方法调用：&lt;/P&gt;&lt;PRE class=code&gt;    this.textBox1.Bounds = &lt;CODE&gt;&lt;B class=cfe&gt;new&lt;/B&gt;&lt;/CODE&gt; Rectangle(10,20,72,23);
&lt;/PRE&gt;
&lt;P&gt;要显示可实现的性能增益，请考虑创建一个窗体，其中包含 1 个 MenuBar、1 个 TabControl 控件、5 个 TabPage（各包含 7 个 Label、7 个 Button 和 7 个 TextBox）。总共是 112 个控件。此应用程序是使用 Release（发行）配置文件生成的，并部署到 Pocket PC 2002 仿真器，此应用程序在仿真器中运行 5 次，下面是整理的各次运行时间的比较。&lt;/P&gt;
&lt;P class=label&gt;&lt;B&gt;表 1：Forms Designer（窗体设计器）生成的代码计时&lt;/B&gt;&lt;/P&gt;
&lt;TABLE class=data&gt;
&lt;TBODY&gt;
&lt;TR vAlign=top&gt;
&lt;TH class=data align=left width="50%"&gt;第次&lt;/TH&gt;
&lt;TH class=data align=left width="50%"&gt;初始化控件的时间（毫秒）&lt;/TH&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;1&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;14275&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;2&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;13950&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;3&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;15475&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;4&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;15175&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;5&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;14325&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;&lt;B&gt;平均时间（毫秒）：&lt;/B&gt;&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;&lt;B&gt;14630&lt;/B&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;BLOCKQUOTE class=dtBlock&gt;&lt;B class=le&gt;注意：&lt;/B&gt;在实际设备上获得的性能要远高于此。&lt;/BLOCKQUOTE&gt;
&lt;P&gt;应用上述的方法调用优化时，将记录以下计时：&lt;/P&gt;
&lt;P class=label&gt;&lt;B&gt;表 2：方法调用优化的代码计时&lt;/B&gt;&lt;/P&gt;
&lt;TABLE class=data&gt;
&lt;TBODY&gt;
&lt;TR vAlign=top&gt;
&lt;TH class=data align=left width="50%"&gt;第次&lt;/TH&gt;
&lt;TH class=data align=left width="50%"&gt;初始化控件的时间（毫秒）&lt;/TH&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;1&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;13225&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;2&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;13850&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;3&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;13000&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;4&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;13625&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;5&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;13100&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;&lt;B&gt;平均时间（毫秒）：&lt;/B&gt;&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;&lt;B&gt;13360&lt;/B&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;与 Forms Designer（窗体设计器）生成的代码相比，性能提高了将近 9%。&lt;/P&gt;
&lt;H2 class=dtH1&gt;&lt;A name=netcfimproveformloadperf_topic4&gt;&lt;/A&gt;自上而下地创建控件&lt;/H2&gt;
&lt;P&gt;提高性能的另一种方法是在控件树中自上而下地初始化控件。例如，如果有一个包含许多控件的面板控件，请先创建面板，然后在面板上添加控件。同样，设置控件的父属性而不是添加至控件集合，也可以提高性能。例如，请考虑在面板的控件集合中添加一个文本框：&lt;/P&gt;&lt;PRE class=code&gt;// 优化前
// 创建一个新面板和文本框控件
Panel panel1 = &lt;CODE&gt;&lt;B class=cfe&gt;new&lt;/B&gt;&lt;/CODE&gt; Panel();
TextBox textBox1 = &lt;CODE&gt;&lt;B class=cfe&gt;new&lt;/B&gt;&lt;/CODE&gt; TextBox();
// 设置 TextBox 控件的 Text 属性
textBox1.Text = "我的文本";
// 将 TextBox 添加至面板的控件集合中
panel1.Controls.Add(&lt;CODE&gt;&lt;B class=cfe&gt;this&lt;/B&gt;&lt;/CODE&gt;.textBox1);
// 将面板添加至窗体的控件集合中
&lt;CODE&gt;&lt;B class=cfe&gt;this&lt;/B&gt;&lt;/CODE&gt;.Controls.Add(panel1);
... // 在此处添加后续控件
&lt;/PRE&gt;
&lt;P&gt;使用自上而下和父级处理技术优化此代码片断将生成以下代码片断：&lt;/P&gt;&lt;PRE class=code&gt;// 优化后
// 创建一个新面板和文本框控件
Panel panel1 = &lt;CODE&gt;&lt;B class=cfe&gt;new&lt;/B&gt;&lt;/CODE&gt; Panel();
TextBox textBox1 = &lt;CODE&gt;&lt;B class=cfe&gt;new&lt;/B&gt;&lt;/CODE&gt; TextBox();
// 使当前窗体成为面板的父级
&lt;CODE&gt;&lt;B class=cfe&gt;this&lt;/B&gt;&lt;/CODE&gt;.panel1.Parent = &lt;CODE&gt;&lt;B class=cfe&gt;this&lt;/B&gt;&lt;/CODE&gt;;
// 使面板成为 TextBox 的父级
&lt;CODE&gt;&lt;B class=cfe&gt;this&lt;/B&gt;&lt;/CODE&gt;.textBox1.Parent(&lt;CODE&gt;&lt;B class=cfe&gt;this&lt;/B&gt;&lt;/CODE&gt;.panel1);
// 设置 TextBox 控件的 Text 属性
textBox1.Text = "我的文本";
... // 在此处添加后续控件
&lt;/PRE&gt;
&lt;P&gt;综合使用以上技术对深层嵌套的控件层次结构具有重要影响。&lt;/P&gt;
&lt;P&gt;通过自上而下创建控件并重新分配父关系来优化 &lt;B&gt;InitializeComponent&lt;/B&gt; 方法中的代码，将生成以下数据：&lt;/P&gt;
&lt;P class=label&gt;&lt;B&gt;表 3：自上而下优化的代码计时&lt;/B&gt;&lt;/P&gt;
&lt;TABLE class=data&gt;
&lt;TBODY&gt;
&lt;TR vAlign=top&gt;
&lt;TH class=data align=left width="50%"&gt;第次&lt;/TH&gt;
&lt;TH class=data align=left width="50%"&gt;初始化控件的时间（毫秒）&lt;/TH&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;1&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;7425&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;2&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;7450&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;3&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;7225&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;4&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;7375&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;5&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;7500&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;&lt;B&gt;平均时间（毫秒）：&lt;/B&gt;&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;&lt;B&gt;7395&lt;/B&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;与默认的 Forms Designer（窗体设计器）生成的代码相比，性能提高了将近 49%。&lt;/P&gt;
&lt;P&gt;如果将两种优化技术组合使用，将获得以下计时结果：&lt;/P&gt;
&lt;P class=label&gt;&lt;B&gt;表 4：组合后的优化代码计时&lt;/B&gt;&lt;/P&gt;
&lt;TABLE class=data&gt;
&lt;TBODY&gt;
&lt;TR vAlign=top&gt;
&lt;TH class=data align=left width="50%"&gt;第次&lt;/TH&gt;
&lt;TH class=data align=left width="50%"&gt;初始化控件的时间（毫秒）&lt;/TH&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;1&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;6625&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;2&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;6600&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;3&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;6575&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;4&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;6475&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;5&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;6750&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD class=data width="50%"&gt;&lt;B&gt;平均时间（毫秒）：&lt;/B&gt;&lt;/TD&gt;
&lt;TD class=data width="50%"&gt;&lt;B&gt;6605&lt;/B&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;与 Forms Designer（窗体设计器）生成的代码相比，将方法调用优化与自上而下的控件初始化技术组合使用可以使整体性能提高将近 55%。如果应用程序包含复杂的窗体，并且您希望提高窗体的加载性能，则在代码中应用这些优化将很有帮助。&lt;/P&gt;
&lt;H2 class=dtH1&gt;&lt;A name=netcfimproveformloadperf_topic5&gt;&lt;/A&gt;更多信息&lt;/H2&gt;
&lt;P&gt;有关其他信息，请参阅以下资源： 
&lt;UL type=disc&gt;
&lt;LI&gt;&lt;A href="http://mobility.microsoftdev.com/"&gt;Microsoft Mobility Developer Communities&lt;/A&gt;（英文） &lt;/LI&gt;&lt;/UL&gt;&lt;!-- END TOTAL PAGE CONTENT --&gt;&lt;/FONT&gt;&lt;img src ="http://blog.vckbase.com/teky/aggbug/24681.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>teky </dc:creator><title>从桌面移动到设备：多线程和用户界面</title><link>http://blog.vckbase.com/teky/articles/24089.html</link><pubDate>Fri, 19 Jan 2007 02:48:00 GMT</pubDate><guid>http://blog.vckbase.com/teky/articles/24089.html</guid><wfw:comment>http://blog.vckbase.com/teky/comments/24089.html</wfw:comment><comments>http://blog.vckbase.com/teky/articles/24089.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://blog.vckbase.com/teky/comments/commentRss/24089.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/teky/services/trackbacks/24089.html</trackback:ping><description>&lt;H1&gt;从桌面移动到设备：多线程和用户界面&lt;/H1&gt;
&lt;P&gt;&lt;A href="http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx?mfr=true"&gt;http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx?mfr=true&lt;/A&gt;&lt;/P&gt;
&lt;H2 class=subtitle&gt;&lt;/H2&gt;
&lt;DIV class=date&gt;发布日期： 2/5/2005&lt;SPAN class=datePipe&gt; | &lt;/SPAN&gt;更新日期： 2/5/2005&lt;/DIV&gt;
&lt;DIV class=overview&gt;
&lt;P&gt;Jim Wilson&lt;BR&gt;&lt;A href="http://www.jwhedgehog.com/" target=_blank&gt;JW Hedgehog, Inc.&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;适用于：&lt;BR&gt;Microsoft&amp;#174; .NET Compact Framework&lt;/P&gt;
&lt;P&gt;&lt;B&gt;摘要：&lt;/B&gt;本文帮助开发人员克服他们在使用后台线程与用户界面进行交互时 Microsoft .NET Compact Framework 的局限性。从 Microsoft 下载中心下载 &lt;A href="http://download.microsoft.com/download/7/1/2/7127cb43-8ca2-4f24-bc13-9367ac401f49/UI%20Safe%20Invoker%20Code%20Sample.msi"&gt;UI Safe Invoker Code Sample.msi&lt;/A&gt;。&lt;/P&gt;&lt;/DIV&gt;
&lt;CENTER&gt;&lt;IMG title="" height=6 alt=* src="http://img.microsoft.com/library/gallery/templates/MNP2.Common/images/3squares.gif" width=30 border=0&gt;&lt;/CENTER&gt;
&lt;DIV style="HEIGHT: 18px"&gt;&lt;/DIV&gt;
&lt;H5 style="PADDING-TOP: 2px"&gt;本页内容&lt;/H5&gt;
&lt;TABLE style="MARGIN-TOP: 7px; MARGIN-BOTTOM: 12px" cellSpacing=0 cellPadding=0 border=0&gt;
&lt;TBODY&gt;
&lt;TR vAlign=top&gt;
&lt;TD&gt;&lt;A href="http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx#EGC"&gt;&lt;IMG height=9 alt=简介 hspace=4 src="http://www.microsoft.com/library/gallery/templates/MNP2.Common/images/arrow_px_down.gif" width=7 vspace=2 border=0&gt;&lt;/A&gt;&lt;/TD&gt;
&lt;TD class=onThisPage&gt;&lt;A href="http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx#EGC"&gt;简介&lt;/A&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD&gt;&lt;A href="http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx#EOC"&gt;&lt;IMG height=9 alt=多线程和用户界面基础知识 hspace=4 src="http://www.microsoft.com/library/gallery/templates/MNP2.Common/images/arrow_px_down.gif" width=7 vspace=2 border=0&gt;&lt;/A&gt;&lt;/TD&gt;
&lt;TD class=onThisPage&gt;&lt;A href="http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx#EOC"&gt;多线程和用户界面基础知识&lt;/A&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD&gt;&lt;A href="http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx#EXAAC"&gt;&lt;IMG height=9 alt=构建更好的类 hspace=4 src="http://www.microsoft.com/library/gallery/templates/MNP2.Common/images/arrow_px_down.gif" width=7 vspace=2 border=0&gt;&lt;/A&gt;&lt;/TD&gt;
&lt;TD class=onThisPage&gt;&lt;A href="http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx#EXAAC"&gt;构建更好的类&lt;/A&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR vAlign=top&gt;
&lt;TD&gt;&lt;A href="http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx#EAOAC"&gt;&lt;IMG height=9 alt=小结 hspace=4 src="http://www.microsoft.com/library/gallery/templates/MNP2.Common/images/arrow_px_down.gif" width=7 vspace=2 border=0&gt;&lt;/A&gt;&lt;/TD&gt;
&lt;TD class=onThisPage&gt;&lt;A href="http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx#EAOAC"&gt;小结&lt;/A&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;A name=EGC&gt;&lt;/A&gt;
&lt;H2&gt;简介&lt;/H2&gt;
&lt;P&gt;当北美春季会议接近结束的时候我正在撰写本月的专栏。MDC Canada、MDC United States、Tech-Ed 以及 Embedded Developer Conference 等会议的出席率都非常高。我发现在这些活动中与那么多人会面交流使我大增见识。很多人开发移动应用程序已经好多年了，但更多的人对移动性还很陌生。大多数是传统企业的开发人员，他们对用 Microsoft&amp;#174; .NET Framework 构建桌面应用程序很有经验，并且现在开始使用 Microsoft .NET Compact Framework 构建设备应用程序。&lt;/P&gt;
&lt;P&gt;您们中间那些使用 .NET Compact Framework 和 .NET Framework 的人都非常清楚：由于处理能力或者大小方面的原因，尽管这两者之间有很多共同点，但还是忽略了一些特性。尽管这些方面大多数都不会有问题，但一些重要方面足以产生挑战。&lt;/P&gt;
&lt;P&gt;会议上，我在和企业开发人员的谈话中发现，当使用 .NET Framework 的开发人员转向使用 .NET Compact Framework 时，他们好像一般会在两个方面遇到问题。第一个问题是从后台线程与用户界面 (UI) 交互。另一个问题就是管理复杂的部署，尤其是那些涉及全局程序集缓存和转发版本的部署。&lt;/P&gt;
&lt;P&gt;两个问题都非常重要并且都有点棘手，因此我将在本专栏中分两个版次进行讨论。本月专栏将焦点集中在：当从后台线程与 UI 交互时，克服 .NET Compact Framework 的局限性。下个月本专栏将专门讨论部署，即全局程序集缓存以及转发版本。&lt;/P&gt;
&lt;DIV style="MARGIN-TOP: 3px; MARGIN-BOTTOM: 10px"&gt;&lt;A href="http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx#top"&gt;&lt;IMG height=9 alt=返回页首 src="http://www.microsoft.com/library/gallery/templates/MNP2.Common/images/arrow_px_up.gif" width=7 border=0&gt;&lt;/A&gt;&lt;A class=topOfPage href="http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx#top"&gt;返回页首&lt;/A&gt;&lt;/DIV&gt;&lt;A name=EOC&gt;&lt;/A&gt;
&lt;H2&gt;多线程和用户界面基础知识&lt;/H2&gt;
&lt;P&gt;&lt;B&gt;构建一个不稳定的应用程序&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;您们中的许多人可能已经熟悉从后台线程与 UI 交互的相关问题，但作为一种复习，让我们快速回顾一下。考虑下面的代码示例。&lt;/P&gt;&lt;PRE class=codeSample&gt;class MyForm : Form{
  ListBox lbData ;
  MyForm() {
    InitializeComponent(); // Create form controls

    Work1_(); // Call Work1_ on the current thread
  }
  void Work1_(){
    StreamReader rdr1 = new StreamReader(@"\My Documents\DataFile.dat");
    string line = rdr1.ReadLine();
    while(line != null) {
      lbData.Items.Add(line); // Populates the list box as expected
      line = rdr1.ReadLine();
    }
  } 
}
&lt;/PRE&gt;
&lt;P&gt;这是一个非常简单的示例，但是它表示了智能设备开发人员所面临的共同问题：需要用数据填充应用程序 UI，检索这些数据可能会非常耗时。在该示例中，应用程序创建了一个包含有列表框的窗体，然后调用函数 &lt;B&gt;Work1_&lt;/B&gt; 来用某个文件的内容填充列表框。&lt;/P&gt;
&lt;P&gt;如果该文件很小，那么毫无意外，该应用程序会运行的非常好。但是，如果读取数据的过程所花时间过长，那么呈现给用户的应用程序可能会无响应甚至会冻结。如果将应用程序修改为从低带宽的无线连接中读取数据，应用程序的无响应性则更需要关注。&lt;/P&gt;
&lt;P&gt;我们必须确保开发人员执行一项冗长的任务时 UI 要保持响应性的一种方法是，将该任务转移给一条后台线程。这不会使实际任务的运行速度更快，但是通过长时间运行的任务在后台运行期间允许应用程序的其他部分继续进行，它确实提供了一种响应性更好的用户体验。 &lt;/P&gt;
&lt;P&gt;通过使用 &lt;B&gt;Thread&lt;/B&gt; 类和 &lt;B&gt;ThreadStart&lt;/B&gt; 委托在后台线程中执行 &lt;B&gt;Work1_&lt;/B&gt;，我们可以轻松地将应用程序修改为使用多线程。&lt;/P&gt;&lt;PRE class=codeSample&gt;class MyForm : Form{
  ListBox lbData ;
  MyForm() {
    InitializeComponent(); // Create form controls

    Thread t = new Thread(new ThreadStart(Work1_));
    t.Start() ; // Runs Work1_ on a background thread
  }
  void Work1_(){
    StreamReader rdr1 = new StreamReader(@"\My Documents\DataFile.dat");
    string line = rdr1.ReadLine();
    while(line != null) {
      lbData.Items.Add(line); // This line is unstable
      line = rdr1.ReadLine();
    }
  } 
}
&lt;/PRE&gt;
&lt;P&gt;好消息是，长时间运行的任务现在在后台运行，因此不会延时或者冻结 UI。坏消息是，在引入多线程之前很稳定的应用程序现在好像会随机发生崩溃。实际上，程序很不稳定，所以我们不可能成功地部署它。&lt;/P&gt;
&lt;P&gt;问题在于 Microsoft .NET 中所有的 Microsoft Windows 窗体控件都有所谓的线程关系，意思是说，它们的属性和方法只能由运行在创建该控件的同一个线程上的代码调用。对于本例的情况，&lt;B&gt;lbData&lt;/B&gt; 是在主应用程序线程上创建的，但却是从一个后台线程调用 &lt;B&gt;lbData.Items.Add&lt;/B&gt; 的。从后台线程调用 &lt;B&gt;lbData.Items.Add&lt;/B&gt; 会导致数据损坏。&lt;/P&gt;
&lt;P&gt;&lt;B&gt;注&lt;/B&gt;&lt;B&gt;&lt;/B&gt;有关 Windows 窗体控件和多线程需要特殊考虑的具体原因，请参阅 Chris Sells 的文章 &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnforms/html/winforms06112002.asp" target=_blank&gt;Safe, Simple Multithreading in WinForms&lt;/A&gt;。本文的目标是 .NET Framework 完全版，因此该文章提供的一些解决方案不适用于 .NET Compact Framework，但 Chris 对问题的描述极为不错。&lt;/P&gt;
&lt;P&gt;&lt;B&gt;亡羊补牢&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;为了使我们的应用程序重新稳定，我们需要修改代码，这样所有与列表框的交互都会在主应用程序线程上发生。通过使用列表框上的 &lt;B&gt;Invoke&lt;/B&gt; 方法，我们可以修改代码。&lt;B&gt;Invoke&lt;/B&gt; 方法由 &lt;B&gt;System.Windows.Forms.Control&lt;/B&gt; 基类提供，因此由所有的 Windows 窗体控件公开。&lt;B&gt;Control.Invoke&lt;/B&gt; 方法在最初创建控件的线程上运行某个委托，允许该委托安全地与控件交互。&lt;/P&gt;
&lt;P&gt;&lt;B&gt;注&lt;/B&gt;&lt;B&gt;&lt;/B&gt;.NET Framework 实现可以运行任何委托，与此不同，&lt;B&gt;Control.Invoke&lt;/B&gt; 的 .NET Compact Framework 实现只支持 &lt;B&gt;EventHandler&lt;/B&gt; 委托。&lt;/P&gt;&lt;PRE class=codeSample&gt;class MyForm : Form{
  ListBox lbData ;
  MyForm() {
    InitializeComponent(); // Create form controls

    Thread t = new Thread(new ThreadStart(Work1_));
    t.Start() ; // Runs Work1_ on a background thread
  }

private Queue qData = new Queue(); // Visible to all member functions on all threads

  void Work1_(){
    // Wrap AddItem in delegate
    EventHandler eh = new EventHandler(AddItem);
    StreamReader rdr1 = new StreamReader(@"\My Documents\DataFile.dat");
    string line = rdr1.ReadLine();
    while(line != null) {
      lock(qData){ // Synchronize queue acess
        qData.Enqueue(line); // Store line value in queue
      }
      lbData.Invoke(eh); // Transfer control to thread that created lbData
      line = rdr1.ReadLine();
    }
  } 

  void AddItem(object o, EventArgs e)
  {
    string line = null;
    lock(qData){ // Synchronize queue acess
      line = (string)qData(); // Get data from queue
    }
    lbData.Items.Add(line); // Update list box
  }
}
&lt;/PRE&gt;
&lt;P&gt;应用程序又稳定了。通过将修改列表框内容的代码移动到 &lt;B&gt;AddItem &lt;/B&gt;函数中，并将它包装到一个 &lt;B&gt;EventHandler&lt;/B&gt; 委托中，我们已经将后台任务从它与 UI 的交互中分离出来。循环的每次传递期间，&lt;B&gt;Work1_&lt;/B&gt; 将从文件读取的数据放置到 &lt;B&gt;qData&lt;/B&gt; 队列中并调用 &lt;B&gt;lbData.Invoke&lt;/B&gt; 来运行包装 &lt;B&gt;AddItem&lt;/B&gt; 函数的 &lt;B&gt;EventHandler&lt;/B&gt; 委托。每次调用 &lt;B&gt;lbData.Invoke&lt;/B&gt; 会挂起运行后台线程，直到主应用程序线程完成运行 &lt;B&gt;AddItem&lt;/B&gt; 方法。&lt;B&gt;AddItem&lt;/B&gt; 运行在主应用程序线程上，它从队列中提取值并将其安全地添加到列表框中。&lt;/P&gt;
&lt;P&gt;&lt;B&gt;克服局限性&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;对于简单的线程方案，&lt;B&gt;Control.Invoke &lt;/B&gt;的 .NET Compact Framework 实现很适用，但与 .NET Framework 实现相比却具有明显的局限性。&lt;/P&gt;
&lt;P&gt;&lt;B&gt;传递参数&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;首先，.NET Framework 提供了 &lt;B&gt;Control.Invoke&lt;/B&gt; 的一种重载，它接受一个对象数组。用该对象数组将参数传递给执行的委托。&lt;/P&gt;
&lt;P&gt;通过使用 .NET Framework 中的 &lt;B&gt;Control.Invoke&lt;/B&gt; 重载，我们不再需要使用队列或者任何其他的数据结构在线程之间共享数据。数据可以只是作为委托调用的一部分而传递，明显地简化了在后台与 UI 线程之间的数据传递。&lt;/P&gt;
&lt;P&gt;使用 &lt;B&gt;Control.Invoke&lt;/B&gt; 重载生成下面 &lt;B&gt;Work1_&lt;/B&gt; 与 &lt;B&gt;AddItem&lt;/B&gt; 的实现。&lt;/P&gt;&lt;PRE class=codeSample&gt;  void Work1_(){
    // Wrap AddItem in delegate
    EventHandler eh = new EventHandler(AddItem);
    StreamReader rdr1 = new StreamReader(@"\My Documents\DataFile.dat");
    string line = rdr1.ReadLine();
    while(line != null) {
      lbData.Invoke(eh, new object[]{line, EventArgs.Empty}); // Pass to AddItem
      line = rdr1.ReadLine();
    }
  } 

  // o receives the reference to line, e receives EventArgs.Empty
  void AddItem(object o, EventArgs e)
  {
    string line = (string) o; // Upcast o
    lbData.Items.Add(line);  // Add to list box
  }
&lt;/PRE&gt;
&lt;P&gt;&lt;B&gt;异步执行&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;另一个主要不同点是，台式计算机支持 &lt;B&gt;Control.BeginInvoke&lt;/B&gt;，这样委托可以异步执行。在我们的应用程序中，每次调用 &lt;B&gt;lbData.Invoke&lt;/B&gt; 时，后台线程就挂起执行，直到 &lt;B&gt;AddItem&lt;/B&gt; 方法结束。结果是，循环的每次迭代中应用程序被迫导致一个线程上下文切换。&lt;/P&gt;
&lt;P&gt;一般情况下，我们希望将线程上下文切换降低到最低限度，因为执行它的成本相当高；首选的做法是允许操作系统选择何时发出线程上下文切换。用 .NET Framework 中的 &lt;B&gt;Control.BeginInvoke&lt;/B&gt; 替代 &lt;B&gt;Control.Invoke&lt;/B&gt; 调用消除了这种不得已的线程上下文切换，并允许后台线程继续处理，直到操作系统决定执行一个线程上下文切换并运行委托。&lt;/P&gt;
&lt;P&gt;为了更新 &lt;B&gt;Work1_&lt;/B&gt; 方法来异步运行 &lt;B&gt;AddItem&lt;/B&gt; 委托，我们只需使用 &lt;B&gt;lbData.BeginInvoke&lt;/B&gt; 替代对 &lt;B&gt;lbData.Invoke&lt;/B&gt; 的调用。&lt;/P&gt;&lt;PRE class=codeSample&gt;lbData.BeginInvoke(eh, new object[]{line, EventArgs.Empty});
&lt;/PRE&gt;
&lt;DIV style="MARGIN-TOP: 3px; MARGIN-BOTTOM: 10px"&gt;&lt;A href="http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx#top"&gt;&lt;IMG height=9 alt=返回页首 src="http://www.microsoft.com/library/gallery/templates/MNP2.Common/images/arrow_px_up.gif" width=7 border=0&gt;&lt;/A&gt;&lt;A class=topOfPage href="http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx#top"&gt;返回页首&lt;/A&gt;&lt;/DIV&gt;&lt;A name=EXAAC&gt;&lt;/A&gt;
&lt;H2&gt;构建更好的类&lt;/H2&gt;
&lt;P&gt;我们在构建多线程设备应用程序时，.NET Compact Framework &lt;B&gt;Control&lt;/B&gt; 类缺乏支持传递参数以及异步执行增加了复杂性并降低了效率。我发现这种不支持是一个特别重要的问题，因为智能设备应用程序一般都使用多线程。同时，智能设备的资源往往有限，这使得简单、有效的多线程非常重要。&lt;/P&gt;
&lt;P&gt;因为我们没有使用 .NET Compact Framework 源代码，因此我们不能合理地向 .NET Compact Framework &lt;B&gt;Control&lt;/B&gt; 类添加对参数和异步委托执行的支持。但是，我们可以构建一个提供这些功能的新类。我将该类称为 &lt;B&gt;UISafeInvoker&lt;/B&gt;。&lt;/P&gt;
&lt;P&gt;&lt;B&gt;注&lt;/B&gt;&lt;B&gt;&lt;/B&gt;本月专栏随附的下载包括 &lt;B&gt;UISafeInvoker&lt;/B&gt; 的完整源代码以及一个演示其用法的应用程序。&lt;/P&gt;
&lt;P&gt;一言以蔽之，&lt;B&gt;UISafeInvoker&lt;/B&gt; 是一个与线程有关的 .NET Compact Framework 类，它提供了行为与 .NET Framework &lt;B&gt;Control&lt;/B&gt; 类的 &lt;B&gt;Invoke&lt;/B&gt; 与 &lt;B&gt;BeginInvoke&lt;/B&gt; 方法类似的 &lt;B&gt;Invoke&lt;/B&gt; 与 &lt;B&gt;BeginInvoke &lt;/B&gt;方法。虽然不是 &lt;B&gt;Control&lt;/B&gt; 类的一部分，但 &lt;B&gt;UISafeInvoker.Invoke&lt;/B&gt; 与 &lt;B&gt;UISafeInvoker.BeginInvoke&lt;/B&gt; 方法的使用却非常简单。&lt;/P&gt;
&lt;P&gt;&lt;B&gt;注&lt;/B&gt;&lt;B&gt;&lt;/B&gt;本专栏的作者提供了 &lt;B&gt;UISafeInvoker&lt;/B&gt; 的代码示例。Microsoft 不提供对这些代码的支持，对该类的使用也没有明确或暗示的任何担保。&lt;/P&gt;
&lt;P&gt;与可以执行任何种类委托的台式机的 &lt;B&gt;Control.Invoke&lt;/B&gt; 与 &lt;B&gt;BeginInvoke&lt;/B&gt; 方法不同，&lt;B&gt;UISafeInvoker&lt;/B&gt; 和 .NET Compact Framework &lt;B&gt;Control.Invoke&lt;/B&gt; 与 &lt;B&gt;BeginInvoke&lt;/B&gt; 方法一样，只支持 &lt;B&gt;EventHandler&lt;/B&gt; 委托。因为 &lt;B&gt;UISafeInvoker&lt;/B&gt; 仅支持一种委托类型，因此不需要使用对象数组来传递参数。相反，&lt;B&gt;Invoke&lt;/B&gt; 与 &lt;B&gt;BeginInvoke&lt;/B&gt; 接受直接传递给 &lt;B&gt;EventHandler&lt;/B&gt; 委托中对应参数的对象和 &lt;I&gt;EventArgs&lt;/I&gt; 参数。这里是每种方法的签名。&lt;/P&gt;&lt;PRE class=codeSample&gt;void Invoke(EventHandler eh, object obj, EventArgs eArgs);
IAsyncResult BeginInvoke(EventHandler eh, object obj, EventArgs eArgs);
&lt;/PRE&gt;
&lt;P&gt;使用 &lt;B&gt;UISafeInvoker&lt;/B&gt; 就是简单地在 &lt;B&gt;Form&lt;/B&gt; 类中声明一个引用，并在 Form 构造函数中创建一个实例。创建之后，&lt;B&gt;UISafeInvoker&lt;/B&gt; 就内部跟踪创建它的线程，因此 &lt;B&gt;Invoke&lt;/B&gt; 和 &lt;B&gt;BeginInvoke&lt;/B&gt; 方法可以在同一个线程上运行期望的委托。作为 Form 构造函数的一部分而创建 &lt;B&gt;UISafeInvoker&lt;/B&gt;，并且是在与所有窗体控件相同的线程上创建；因此，&lt;B&gt;Invoke&lt;/B&gt; 或者 &lt;B&gt;BeginInvoke&lt;/B&gt; 方法运行的任何委托都可以安全地更新 UI 控件。&lt;/P&gt;
&lt;P&gt;这里是使用 &lt;B&gt;UISafeInvoker&lt;/B&gt; 更新后的测试应用程序。&lt;/P&gt;&lt;PRE class=codeSample&gt;class MyForm : Form{
  ListBox lbData ;
  UISafeInvoker invoker ; // Declare UISafeInvoker
  MyForm() {
    InitializeComponent();
    invoker = new UISafeInvoker(); // Create UISafeInvoker on main UI thread

    Thread t = new Thread(new ThreadStart(Work1_));
    t.Start() ; // Runs Work1_ on a background thread
  }
  void Work1_(){
    // Wrap AddItem in delegate
    EventHandler eh = new EventHandler(AddItem);
    StreamReader rdr1 = new StreamReader(@"\My Documents\DataFile.dat");
    string line = rdr1.ReadLine();
    while(line != null) {
      invoker.BeginInvoke(eh, line, EventArgs.Empty); // Pass to AddItem
      line = rdr1.ReadLine();
    }
  } 

  // o receives the reference to line, e receives EventArgs.Empty
  void AddItem(object o, EventArgs e)
  {
    string line = (string) o; // Upcast o
    lbData.Items.Add(line);  // Add to Listbox
  }
}
&lt;/PRE&gt;
&lt;P&gt;对于 &lt;B&gt;UISafeInvoker&lt;/B&gt;，我们的 .NET Compact Framework 应用程序已经克服了 .NET Compact Framework &lt;B&gt;Control.Invoke&lt;/B&gt; 方法的局限性，现在可以提供简单、有效的线程内通信了。这种通信类似于 .NET Framework 中的通信，不需要额外的数据结构或者复杂的编码。&lt;/P&gt;
&lt;P&gt;&lt;B&gt;使用窗口消息&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;在内部，&lt;B&gt;UISafeInvoker&lt;/B&gt; 非常简单，因为它仅完成两件事情：跟踪创建它的线程并提供一种在线程之间传输数据的可靠方法。&lt;/P&gt;
&lt;P&gt;这种解决方案 &amp;#8212; 虽然听起来有些陈旧 &amp;#8212; 是基于窗口消息的。Windows 操作系统创建的所有窗口都有一个消息队列。应用程序可以通过使用 Microsoft Win32_ SDK 函数 &lt;B&gt;SendMessage&lt;/B&gt; 和 &lt;B&gt;PostMessage&lt;/B&gt; 将消息放置到该队列中。这些函数允许应用程序传递一个标识执行操作的整数标志和两个过去被称为 WParam 与 LParam 的消息定义数据值。&lt;/P&gt;
&lt;P&gt;除了有一个主要的不同点，&lt;B&gt;SendMessage&lt;/B&gt; 和 &lt;B&gt;PostMessage&lt;/B&gt; 函数基本上是一样的。&lt;B&gt;SendMessage&lt;/B&gt; 将消息放置到窗口消息队列中，并阻止消息直到窗口完成对它的处理。&lt;B&gt;PostMessage&lt;/B&gt; 将消息放置到窗口消息队列中并立即返回。&lt;B&gt;SendMessage&lt;/B&gt; 和 &lt;B&gt;PostMessage&lt;/B&gt; 可以由任何线程调用，但是窗口总是在创建该窗口的线程上处理消息。这种行为隐含地解决了线程跟踪和在线程间传输数据的问题。&lt;/P&gt;
&lt;P&gt;所有的 UI 控件都是窗口，但是应用程序也可以创建隐藏的窗口，它们能够处理消息，但在屏幕上不会呈现任何可见物。&lt;B&gt;MessageWindow&lt;/B&gt; 类向 .NET Compact Framework 公开了实现隐藏窗口的功能。&lt;/P&gt;
&lt;P&gt;&lt;B&gt;注&lt;/B&gt;&lt;B&gt;&lt;/B&gt;如果您对消息队列和消息处理如何工作的细节感兴趣，请参阅 &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/Windowing/MessagesandMessageQueues/AboutMessagesandMessageQueues.asp" target=_blank&gt;About Messages and Message Queues&lt;/A&gt;。有关 &lt;B&gt;MessageWindow&lt;/B&gt; 类的更多信息，请参阅 &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/win_ce/html/pwc_CompactFrameworkUniqueClasses.asp" target=_blank&gt;Compact Framework Unique Classes&lt;/A&gt;。&lt;/P&gt;
&lt;P&gt;从根本上说，&lt;B&gt;UISafeInvoker&lt;/B&gt; 只是封装了一个隐藏窗口和对 &lt;B&gt;SendMessage&lt;/B&gt; 和 &lt;B&gt;PostMessage&lt;/B&gt; 的调用。这里是 &lt;B&gt;UISafeInvoker&lt;/B&gt; 实现的框架。&lt;/P&gt;&lt;PRE class=codeSample&gt;public class UISafeInvoker : MessageWindow
{
  const int WM_USER = 1024; // Traditional start of application-defined messages
  const int WM_INVOKEMETHOD = WM_USER + 1; // Our special message

  // Handle window message processing
  protected override void WndProc(ref Message m)
  {
    base.WndProc (ref m);
    if (m.Msg == WM_INVOKEMETHOD)
    {
      // Get data from message
      // Run delegate
    }
  }

  // Instigate delegate execution and wait for completion
  public void Invoke(EventHandler eh, ...)
  {
    Message m = Message.Create(this.Hwnd, 
                               WM_INVOKEMETHOD, ...);
    MessageWindow.SendMessage(ref m);
  }

  // Instigate delegate execution and return immediately
  public void BeginInvoke(EventHandler eh, ...)
  {
    Message m = Message.Create(this.Hwnd, 
                               WM_INVOKEMETHOD, ...);
    MessageWindow.PostMessage(ref m);
  }
}
&lt;/PRE&gt;
&lt;P&gt;&lt;B&gt;Invoke&lt;/B&gt; 和 &lt;B&gt;BeginInvoke&lt;/B&gt; 方法都向包含有关运行委托信息的隐藏窗口发送消息。由于 &lt;B&gt;Invoke&lt;/B&gt; 方法使用 &lt;B&gt;SendMessage &lt;/B&gt;，因此是同步运行。&lt;B&gt;BeginInvoke&lt;/B&gt; 提供异步执行，因为 &lt;B&gt;PostMessage&lt;/B&gt; 将消息放置到窗口消息队列中并立即返回。&lt;/P&gt;
&lt;P&gt;每次隐藏窗口接收到一条消息就会调用 &lt;B&gt;WndProc&lt;/B&gt; 方法，它负责运行期望的委托。由于它是作为窗口消息处理的一部分而调用的，因此创建该窗口的线程总是执行 &lt;B&gt;WndProc&lt;/B&gt; 方法。因为总是在同一个线程上运行代码，所以它运行的委托可以安全地与在同一个线程上创建的 UI 控件进行交互。&lt;/P&gt;
&lt;P&gt;&lt;B&gt;在线程之间传递数据&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;&lt;B&gt;UISafeInvoker&lt;/B&gt; 实现的一个复杂方面就是将数据从 &lt;B&gt;Invoke&lt;/B&gt; 与 &lt;B&gt;BeginInvoke&lt;/B&gt; 方法传递到 &lt;B&gt;WndProc&lt;/B&gt; 方法。为了使用 &lt;B&gt;SendMessage&lt;/B&gt; 或者 &lt;B&gt;PostMessage&lt;/B&gt; 将数据发送给隐藏窗口，我们首先需要定义一个类，该类包含将引用存储到 &lt;B&gt;EventHandler&lt;/B&gt; 委托以及对象和 &lt;B&gt;EventHandler&lt;/B&gt; 委托期望的 &lt;I&gt;EventArgs&lt;/I&gt; 参数等必需信息。&lt;/P&gt;&lt;PRE class=codeSample&gt;class InvokerData{
  public EventHandler eventHandler;
  public object obj;
  public EventArgs eventArgs;
}
&lt;/PRE&gt;
&lt;P&gt;然后，&lt;B&gt;Invoke&lt;/B&gt; 和 &lt;B&gt;BeginInvoke&lt;/B&gt; 实现可以填充 &lt;B&gt;InvokerData&lt;/B&gt; 类的一个实例，并使用 &lt;B&gt;SendMessage&lt;/B&gt; 或者 &lt;B&gt;PostMessage&lt;/B&gt; 将这些信息发送给 &lt;B&gt;WndProc&lt;/B&gt; 方法。&lt;/P&gt;
&lt;P&gt;问题是，&lt;B&gt;InvokerData&lt;/B&gt; 是一个存储在 .NET Compact Framework 托管内存空间中的 .NET 类。&lt;B&gt;SendMessage&lt;/B&gt; 和 &lt;B&gt;PostMessage&lt;/B&gt; 的实现以及窗口消息队列由底层的 Windows 操作系统来处理，操作系统位于 .NET Compact Framework 托管内存空间之外。&lt;/P&gt;
&lt;P&gt;请记住，.NET Compact Framework 主动地跟踪和管理着所有应用程序对象的内存。它可以将对象在内存中从一个位置移动到另一个位置，并且它删除没有活动 .NET 引用指向的任何对象。 &lt;/P&gt;
&lt;P&gt;我们使用 &lt;B&gt;SendMessage&lt;/B&gt; 和 &lt;B&gt;PostMessage&lt;/B&gt; 的复杂性在于，如果我们将 &lt;B&gt;InvokerData&lt;/B&gt; 对象引用作为参数传递给这些函数中的一个，那么该对象的当前地址将被直接复制到隐藏窗口消息队列中。Windows 操作系统实现的窗口消息队列位于 .NET Compact Framework 托管内存空间之外；因此，.NET Compact Framework 不知道应用程序仍旧保存着 &lt;B&gt;InvokerData&lt;/B&gt; 对象地址的事实，并计划再次使用它。 &lt;/P&gt;
&lt;P&gt;当隐藏窗口最终处理消息时，地址从窗口消息队列中复制到由 &lt;B&gt;UISafeInvoker&lt;/B&gt;&lt;B&gt;WndProc&lt;/B&gt; 函数接收的 .NET Compact Framework &lt;B&gt;Message&lt;/B&gt; 结构中。在地址被复制到消息队列中并传递回 &lt;B&gt;WndProc&lt;/B&gt; 函数期间，.NET Compact Framework 垃圾回收器可能会移动甚至可能会删除 &lt;B&gt;InvokerData&lt;/B&gt; 对象。&lt;/P&gt;
&lt;P&gt;为了避免这种潜在的危险情况，我们可以只要求 .NET Compact Framework 为我们提供一种表示 &lt;B&gt;InvokerData&lt;/B&gt; 对象安全传输到 .NET 环境之外并且我们返回时仍旧有效的标记。为此，我们可以使用 &lt;B&gt;GCHandle&lt;/B&gt; 结构。&lt;/P&gt;
&lt;P&gt;&lt;B&gt;GCHandle&lt;/B&gt; 结构可以方便地创建一种表示 .NET 对象被安全传递到 .NET 环境之外并且稍后可以用来找到同一个对象的标记。拥有 &lt;B&gt;GCHandle&lt;/B&gt; 结构的 .NET 对象可以防止该对象被作为垃圾回收。&lt;B&gt;GCHandle&lt;/B&gt; 结构还可以安全地来回转换成 &lt;B&gt;IntPtr&lt;/B&gt;，使得使用 &lt;B&gt;SendMessage&lt;/B&gt; 和 &lt;B&gt;PostMessage&lt;/B&gt; 非常简单。&lt;/P&gt;
&lt;P&gt;既然我们有了 &lt;B&gt;GCHandle&lt;/B&gt;，因此这里是完整的 &lt;B&gt;UISafeInvoker.Invoke&lt;/B&gt; 方法；&lt;B&gt;UISafeInvoker.BeginInvoke&lt;/B&gt; 除了使用 &lt;B&gt;PostMessage&lt;/B&gt; 之外，基本上是相同的。&lt;/P&gt;&lt;PRE class=codeSample&gt;public void Invoke(EventHandler eh, object obj, EventArgs e){
  InvokerData d = new InvokerData() ;
  d.eventHandler eh; 
  d.obj = sender;
  d.eventArgs = e;

  GCHandle dataHandle = GCHandle.Alloc(d); // Get token to InvokerData
  IntPtr iPtr = (IntPtr) dataHandle; // Cast to IntPtr
  Message m = Message.Create(this.Hwnd, WM_INVOKEMETHOD, IntPtr.Zero, iPtr);
  MessageWindow.SendMessage(ref m);
}
&lt;/PRE&gt;
&lt;P&gt;我们的 &lt;B&gt;WndProc&lt;/B&gt; 实现然后就可以使用包含在接收消息内的 &lt;B&gt;GCHandle&lt;/B&gt; 结构来检索 &lt;B&gt;InvokerData&lt;/B&gt; 实例。 &lt;/P&gt;
&lt;P&gt;&lt;B&gt;注&lt;/B&gt;&lt;B&gt;&lt;/B&gt;在不再需要该结构时，&lt;B&gt;WndProc&lt;/B&gt; 函数必须调用 &lt;B&gt;GCHandle&lt;/B&gt; 结构上的 &lt;B&gt;Free&lt;/B&gt; 方法。如果没有调用 &lt;B&gt;Free&lt;/B&gt; 方法，.NET Compact Framework 内存管理器就无法知道我们不再需要 &lt;B&gt;GCHandle&lt;/B&gt;，并且将不能清除相关的对象。&lt;/P&gt;&lt;PRE class=codeSample&gt;protected override void WndProc(ref Message m)
{
  base.WndProc (ref m);
  if (m.Msg == WM_INVOKEMETHOD)  {
    GCHandle h = (GCHandle) m.LParam;// Cast IntPtr back to GCHandle
    InvokerData d = (InvokerData) h.Target; // Get the InvokerData instance
    h.Free(); // Indicate that we are finished with GCHandle

    d.eventHandler(d.obj, d.eventArgs); // Call the delegate passing the parameters
  }
}
&lt;/PRE&gt;
&lt;DIV style="MARGIN-TOP: 3px; MARGIN-BOTTOM: 10px"&gt;&lt;A href="http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx#top"&gt;&lt;IMG height=9 alt=返回页首 src="http://www.microsoft.com/library/gallery/templates/MNP2.Common/images/arrow_px_up.gif" width=7 border=0&gt;&lt;/A&gt;&lt;A class=topOfPage href="http://www.microsoft.com/china/msdn/library/mobility/mobileapp/multithreadui.mspx#top"&gt;返回页首&lt;/A&gt;&lt;/DIV&gt;&lt;A name=EAOAC&gt;&lt;/A&gt;
&lt;H2&gt;小结&lt;/H2&gt;
&lt;P&gt;.NET Framework 与 .NET Compact Framework 之间有许多不同点。大多数差别都是细微的；有些更为复杂，另外还需要一点创造性。虽然从后台线程与 UI 进行交互是一种更为复杂的情况，我们的 &lt;B&gt;UISafeInvoker&lt;/B&gt; 类为我们提供了在线程之间传递参数并异步运行委托的能力，正如 .NET Framework 一样。&lt;/P&gt;
&lt;P&gt;在我结束之前，我想感谢参加我的本季会议的每个人。我希望您们喜欢参加这个会议，就像我乐意为会议做事一样，也希望在下季的会议上看到各位。同时，我希望您们每月都会继续参加进来。&lt;/P&gt;
&lt;P&gt;我还想特别感谢所有那些询问我这么多重要问题的人们。和每位进行交流并聆听人们在实际工作中遇到的问题就是我工作中最有价值的一部分。如果您有任何问题或者主题，并且希望在 &lt;I&gt;You Can Take It with You&lt;/I&gt; 中进行讨论，请给我发送邮件到 &lt;A href="mailto:jimw@jwhh.com"&gt;&lt;EM&gt;jimw@jwhh.com&lt;/EM&gt;&lt;/A&gt;。&lt;/P&gt;
&lt;P&gt;请下个月加入进来，那时我们将考察 .NET Framework 开发人员转移到 .NET Compact Framework 的另一个共同难题：部署，即全局程序集缓存以及转发版本。&lt;/P&gt;
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/library/?url=/library/en-us/dntake/html/yctiwy_multithreadingandui.asp" target=_blank&gt;转到原英文页面&lt;/A&gt;&lt;/P&gt;&lt;img src ="http://blog.vckbase.com/teky/aggbug/24089.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>teky </dc:creator><title>SmartPhone手机上查看QQ天气预报</title><link>http://blog.vckbase.com/teky/articles/23324.html</link><pubDate>Fri, 01 Dec 2006 08:42:00 GMT</pubDate><guid>http://blog.vckbase.com/teky/articles/23324.html</guid><wfw:comment>http://blog.vckbase.com/teky/comments/23324.html</wfw:comment><comments>http://blog.vckbase.com/teky/articles/23324.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://blog.vckbase.com/teky/comments/commentRss/23324.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/teky/services/trackbacks/23324.html</trackback:ping><description>&lt;P&gt;&lt;FONT face=宋体 size=2&gt;智能手机应用程序开发是软件开发的一个新的热点，但如何才能跨入这道门楣呢？今天我通过为自己的多普达565手机添加一个天气预报程序来向大家讲解一下。我们都知道QQ有一个免费提供给Blog引用的天气预报服务网址http://appnews.qq.com/cgi-bin/news_qq_search?city=上海（上海是我自己所在城市，如果想看自己的城市，在浏览器中改成城市名称即可），现在我使用QQ提供的这个服务，将其包装部署为一个Web服务，并编写程序使得我的多普达565智能手机能使用这个Web服务。 &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;　　设备要求：&lt;/P&gt;
&lt;P&gt;　　PC开发环境：Windows XP SP2，Visual Studio 2003.NET,.NET Framework 1.1 SP1&lt;/P&gt;
&lt;P&gt;　　操作系统：Windows Mobile(TM) 2003第二版，版本4.21.1088(Build 14235.2.0.0)&lt;/P&gt;
&lt;P&gt;　　智能手机：多普达565&lt;/P&gt;
&lt;P&gt;　　一、环境安装&lt;/P&gt;
&lt;P&gt;　　首先我们必须安装.NET Mobile所需要的开发环境，必须安装的软件(如下软件都是微软提供免费下载和使用的)&lt;/P&gt;
&lt;P&gt;　　1、Microsoft ActiveSync 3.7.1 &lt;/P&gt;
&lt;P&gt;　　下载网址：http://www.microsoft.com/windowsmobile/downloads/activesync37.mspx，里面有中文版本，或者，在手机附带的微软光盘里面有安装程序；最新版本Microsoft ActiveSync 3.8出来了，可以到摘要的页面中去找链接下载，但这个程序我还是用的老版本。&lt;/P&gt;
&lt;P&gt;　　作用：同步手机和PC机数据的程序&lt;/P&gt;
&lt;P&gt;　　2、Microsoft SMARTPHONE 2003 SDK.msi&lt;/P&gt;
&lt;P&gt;　　下载网址：&lt;/P&gt;
&lt;P&gt;　　http://download.microsoft.com/download/e/3/1/e310bb99-2f33-4d79-bb8a-41d9cb3c79b4/Microsoft SMARTPHONE 2003 SDK.msi&lt;/P&gt;
&lt;P&gt;　　3、MobileAppDevToolkit2004.exe&lt;/P&gt;
&lt;P&gt;　　下载地址：http://download.microsoft.com/download/b/2/5/b25742c0-daa3-4a8c-988d-a947a35e0a68/MobileAppDevToolkit2004.exe&lt;/P&gt;
&lt;P&gt;　　二、设计并部署WebService&lt;/P&gt;
&lt;P&gt;　　1、建立一个名为WeatherService的WebService，并将QQ的天气服务转为XML WebService服务，部署在一台具有固定IP的服务器上。&lt;/P&gt;
&lt;P&gt;　　2、新建一个WeatherDataSet.XSD，存储我们的天气信息&lt;/P&gt;
&lt;P&gt;＜?xml version="1.0" encoding="utf-8" ?＞&lt;BR&gt;＜xs:schema id="WeatherDataSet" targetNamespace="Ezhi.Services.WeatherService" elementFormDefault="qualified"&lt;BR&gt;　　attributeFormDefault="qualified" xmlns="Ezhi.Services.WeatherService" 　　　xmlns:mstns="Ezhi.Services.WeatherService"&lt;BR&gt;　　xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"＞&lt;/P&gt;
&lt;P&gt;＜xs:element name="WeatherDataSet" msdata:IsDataSet="true"＞&lt;BR&gt;＜xs:complexType＞&lt;BR&gt;　＜xs:choice maxOccurs="unbounded"＞&lt;BR&gt;　　＜xs:element name="WeatherDS"＞&lt;BR&gt;　　　＜xs:complexType＞&lt;BR&gt;　　　　＜xs:sequence＞&lt;BR&gt;　　　　　＜xs:element name="CityName" type="xs:string" minOccurs="0" /＞&lt;BR&gt;　　　　　＜xs:element name="Date1" type="xs:string" minOccurs="0" /＞&lt;BR&gt;　　　　　＜xs:element name="Weather1" type="xs:string" minOccurs="0" /＞&lt;BR&gt;　　　　　＜xs:element name="Temp1" type="xs:string" minOccurs="0" /＞&lt;BR&gt;　　　　　＜xs:element name="WindPower1" type="xs:string" minOccurs="0" /＞&lt;BR&gt;　　　　　＜xs:element name="Date2" type="xs:string" minOccurs="0" /＞&lt;BR&gt;　　　　　＜xs:element name="Weather2" type="xs:string" minOccurs="0" /＞&lt;BR&gt;　　　　　＜xs:element name="Temp2" type="xs:string" minOccurs="0" /＞&lt;BR&gt;　　　　　＜xs:element name="WindPower2" type="xs:string" minOccurs="0" /＞&lt;BR&gt;　　　　＜/xs:sequence＞&lt;BR&gt;　　　＜/xs:complexType＞&lt;BR&gt;　　＜/xs:element＞&lt;BR&gt;　＜/xs:choice＞&lt;BR&gt;＜/xs:complexType＞&lt;BR&gt;＜/xs:element＞&lt;BR&gt;＜/xs:schema＞ &lt;/P&gt;
&lt;P&gt;　　3、WeatherService的源代码如下&lt;/P&gt;
&lt;P&gt;#region Using directives&lt;/P&gt;
&lt;P&gt;using System;&lt;BR&gt;using System.Collections;&lt;BR&gt;using System.ComponentModel;&lt;BR&gt;using System.Data;&lt;BR&gt;using System.Diagnostics;&lt;BR&gt;using System.Web;&lt;BR&gt;using System.Web.Services;&lt;BR&gt;using System.IO;&lt;BR&gt;using System.Net;&lt;BR&gt;using System.Text;&lt;/P&gt;
&lt;P&gt;#endregion&lt;/P&gt;
&lt;P&gt;namespace WeatherService&lt;BR&gt;{&lt;BR&gt;　/// ＜summary＞&lt;BR&gt;　/// Service1 的摘要说明。&lt;BR&gt;　/// ＜/summary＞&lt;/P&gt;
&lt;P&gt;　[WebService(Description="WeatherService 天气Service",Namespace="WeatherService")]&lt;/P&gt;
&lt;P&gt;　public class Weather : System.Web.Services.WebService&lt;BR&gt;　{&lt;BR&gt;　　#region Variable&lt;BR&gt;　　private string tommorow;&lt;BR&gt;　　#endregion &lt;/P&gt;
&lt;P&gt;　　#region 构造函数&lt;/P&gt;
&lt;P&gt;public Weather()&lt;BR&gt;{&lt;BR&gt;　InitializeComponent();&lt;/P&gt;
&lt;P&gt;　if(DateTime.Today.AddDays(1).Month.ToString().Length == 1)&lt;BR&gt;　{&lt;BR&gt;　　tommorow= "0"+DateTime.Today.AddDays(1).Month.ToString()+"月" + &lt;BR&gt;　　　　　　DateTime.Today.AddDays(1).Day.ToString()+"日";&lt;BR&gt;　}&lt;BR&gt;　else&lt;BR&gt;　{&lt;BR&gt;　　tommorow= DateTime.Today.AddDays(1).Month.ToString()+"月" + &lt;BR&gt;　　　　　DateTime.Today.AddDays(1).Day.ToString()+"日";&lt;BR&gt;　}&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;#endregion &lt;/P&gt;
&lt;P&gt;　　#region 组件设计器生成的代码&lt;/P&gt;
&lt;P&gt;//Web 服务设计器所必需的&lt;/P&gt;
&lt;P&gt;private IContainer components = null;&lt;/P&gt;
&lt;P&gt;/// ＜summary＞&lt;BR&gt;/// 设计器支持所需的方法 - 不要使用代码编辑器修改&lt;BR&gt;/// 此方法的内容。&lt;BR&gt;/// ＜/summary＞&lt;/P&gt;
&lt;P&gt;private void InitializeComponent()&lt;BR&gt;{}&lt;/P&gt;
&lt;P&gt;/// ＜summary＞&lt;BR&gt;/// 清理所有正在使用的资源。&lt;BR&gt;/// ＜/summary＞&lt;/P&gt;
&lt;P&gt;protected override void Dispose( bool disposing )&lt;BR&gt;{&lt;BR&gt;　if(disposing &amp;amp;&amp;amp; components != null)&lt;BR&gt;　{&lt;BR&gt;　　components.Dispose();&lt;BR&gt;　}&lt;BR&gt;　base.Dispose(disposing); &lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;#endregion&lt;/P&gt;
&lt;P&gt;#region [OK] GetWeatherDataSet 天气预报&lt;/P&gt;
&lt;P&gt;[WebMethod(Description="天气预报")]&lt;/P&gt;
&lt;P&gt;public DataSet GetWeatherDataSet(string cityName)&lt;BR&gt;{&lt;BR&gt;　string url=@"http://appnews.qq.com/cgi-bin/news_qq_search";&lt;BR&gt;　string weatherData="";&lt;/P&gt;
&lt;P&gt;　try&lt;BR&gt;　{&lt;BR&gt;　　weatherData = GetPage(url,cityName).Replace(" ","").Trim();&lt;BR&gt;　}&lt;BR&gt;　catch(Exception)&lt;BR&gt;　{&lt;BR&gt;　　throw new Exception("对不起，没有这个城市的天气信息！");&lt;BR&gt;　}&lt;/P&gt;
&lt;P&gt;　//System.Diagnostics.Trace.WriteLine( tommorow );&lt;BR&gt;　//System.Diagnostics.Trace.WriteLine( weatherData );&lt;/P&gt;
&lt;P&gt;　WeatherDataSet weatherDs = new WeatherDataSet();&lt;BR&gt;　weatherDs.WeatherDS.AddWeatherDSRow(GetWeatherRow(ref weatherDs,weatherData,cityName) );&lt;BR&gt;　return weatherDs;&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;private WeatherDataSet.WeatherDSRow GetWeatherRow(ref WeatherDataSet weatherDs,string weatherData,string cityName)&lt;BR&gt;{&lt;BR&gt;　WeatherDataSet.WeatherDSRow weatherRow = weatherDs.WeatherDS.NewWeatherDSRow();&lt;BR&gt;　weatherRow.CityName = weatherData.Substring(weatherData.IndexOf("●")+1,cityName.Length);&lt;/P&gt;
&lt;P&gt;　weatherRow.Date1 = DateTime.Now.ToLongDateString();&lt;/P&gt;
&lt;P&gt;　weatherRow.Weather1 = weatherData.Substring(weatherData.IndexOf("天气")+"天气".Length,weatherData.IndexOf("气温")-(weatherData.IndexOf("天气")+"天气".Length));&lt;/P&gt;
&lt;P&gt;　weatherRow.Temp1 = weatherData.Substring(weatherData.IndexOf("气温")+"气温".Length,weatherData.IndexOf("风力")-(weatherData.IndexOf("气温")+"气温".Length)).Replace("℃-","℃/");&lt;/P&gt;
&lt;P&gt;　weatherRow.WindPower1 = weatherData.Substring(weatherData.IndexOf("风力")+"风力".Length,weatherData.IndexOf(tommorow)-(weatherData.IndexOf("风力")+"风力".Length));&lt;/P&gt;
&lt;P&gt;　weatherRow.Date2 = DateTime.Today.AddDays(1).ToLongDateString();&lt;/P&gt;
&lt;P&gt;　weatherRow.Weather2 = weatherData.Substring(weatherData.LastIndexOf("天气")+"天气".Length,weatherData.LastIndexOf("气温")-(weatherData.LastIndexOf("天气")+"天气".Length));&lt;/P&gt;
&lt;P&gt;　weatherRow.Temp2 = weatherData.Substring(weatherData.LastIndexOf("气温")+"气温".Length,weatherData.LastIndexOf("风力")-(weatherData.LastIndexOf("气温")+"气温".Length)).Replace("℃-","℃/");&lt;/P&gt;
&lt;P&gt;　weatherRow.WindPower2 = weatherData.Substring(weatherData.LastIndexOf("风力")+"风力".Length);&lt;/P&gt;
&lt;P&gt;　return weatherRow;&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;#endregion&lt;/P&gt;
&lt;P&gt;#region GetPageString 获取QQ的天气服务&lt;/P&gt;
&lt;P&gt;//private string xx="";&lt;/P&gt;
&lt;P&gt;[WebMethod(Description="天气预报")]&lt;/P&gt;
&lt;P&gt;public string GetPageString(string cityName) &lt;BR&gt;{&lt;BR&gt;　string url=@"http://appnews.qq.com/cgi-bin/news_qq_search";&lt;BR&gt;　return GetPage(url,cityName);&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;private static string GetPage(string url,string cityName) &lt;BR&gt;{&lt;BR&gt;　HttpWebResponse res = null;&lt;BR&gt;　string strResult = "";&lt;BR&gt;　try &lt;BR&gt;　{&lt;BR&gt;　　string postData = "city=" + HttpUtility.UrlEncode(cityName,System.Text.Encoding.GetEncoding("GB2312"));&lt;BR&gt;　　HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);&lt;BR&gt;　　req.Method = "POST";&lt;BR&gt;　　req.KeepAlive = true;&lt;BR&gt;　　req.ContentType = "application/x-www-form-urlencoded";&lt;BR&gt;　　StringBuilder UrlEncoded = new StringBuilder();&lt;BR&gt;　　byte[] SomeBytes = Encoding.ASCII.GetBytes(postData);&lt;BR&gt;　　req.ContentLength = SomeBytes.Length;&lt;BR&gt;　　Stream newStream = req.GetRequestStream();&lt;BR&gt;　　newStream.Write(SomeBytes, 0, SomeBytes.Length);&lt;BR&gt;　　newStream.Close();&lt;/P&gt;
&lt;P&gt;　　//获得流内容 &lt;/P&gt;
&lt;P&gt;　　res = (HttpWebResponse)req.GetResponse();&lt;BR&gt;　　System.IO.Stream s=res.GetResponseStream();&lt;BR&gt;　　StreamReader reader = new StreamReader(s,System.Text.Encoding.Default);&lt;BR&gt;　　strResult=reader.ReadToEnd();&lt;BR&gt;　} &lt;BR&gt;　catch(Exception e) &lt;BR&gt;　{&lt;BR&gt;　　strResult = e.ToString();&lt;BR&gt;　} &lt;BR&gt;　finally &lt;BR&gt;　{&lt;BR&gt;　　if ( res != null ) &lt;BR&gt;　　{&lt;BR&gt;　　　res.Close();&lt;BR&gt;　　}&lt;BR&gt;　}&lt;/P&gt;
&lt;P&gt;　strResult=strResult.Remove(0,strResult.IndexOf("●"));&lt;/P&gt;
&lt;P&gt;　if( cityName != "北京" )&lt;BR&gt;　{&lt;BR&gt;　　strResult=strResult.Remove(strResult.IndexOf("北京"),strResult.Length-strResult.IndexOf("北京"));&lt;BR&gt;　}&lt;BR&gt;　else&lt;BR&gt;　{&lt;BR&gt;　　strResult=strResult.Remove(strResult.LastIndexOf("北京"),strResult.Length-strResult.LastIndexOf("北京"));&lt;BR&gt;　}&lt;/P&gt;
&lt;P&gt;　strResult=strResult.Trim();&lt;BR&gt;　while(strResult.IndexOf(@"＜") != -1)&lt;BR&gt;　{&lt;BR&gt;　　strResult=strResult.Remove(strResult.IndexOf(@"＜"),strResult.IndexOf(@"＞")-strResult.IndexOf(@"＜")+1);&lt;BR&gt;　}&lt;/P&gt;
&lt;P&gt;　while(strResult.IndexOf(@" ") != -1)&lt;BR&gt;　{&lt;BR&gt;　　strResult=strResult.Replace(" ","");&lt;BR&gt;　}&lt;/P&gt;
&lt;P&gt;　string x = Encoding.UTF8.GetString(new Byte[]{10});&lt;BR&gt;　string y = Encoding.UTF8.GetString(new Byte[]{9});&lt;/P&gt;
&lt;P&gt;　while(strResult.IndexOf(x) != -1)&lt;BR&gt;　{&lt;BR&gt;　　strResult=strResult.Replace(x,"");&lt;BR&gt;　}&lt;/P&gt;
&lt;P&gt;　while(strResult.IndexOf(y) != -1)&lt;BR&gt;　{&lt;BR&gt;　　strResult=strResult.Replace(y,"");&lt;BR&gt;　}&lt;BR&gt;　return strResult;&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;#endregion&lt;BR&gt;}&lt;BR&gt;} &lt;/P&gt;
&lt;P&gt;　　记得将在Web.Config文件加入以下节点，使得WebService能被外部访问&lt;/P&gt;
&lt;P&gt;＜!-- WebService 获取的途径 --＞&lt;BR&gt;＜webServices＞&lt;BR&gt;＜protocols＞&lt;BR&gt;＜add name="HttpSoap"/＞&lt;BR&gt;＜add name="HttpPost"/＞&lt;BR&gt;＜add name="HttpGet"/＞ &lt;BR&gt;＜add name="HttpPostLocalhost"/?&lt;BR&gt;＜add name="Documentation"/＞&lt;BR&gt;＜/protocols＞&lt;BR&gt;＜/webServices＞ &lt;BR&gt;　&lt;B&gt;三、新建手机应用程序项目&lt;/B&gt;&lt;BR&gt;&lt;BR&gt;　　1、新建一个智能设备应用程序，在主面板上拖放如图2所示的几个控件，其中timer是用来检查是否数据已经下载完毕的。&lt;BR&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;
&lt;TABLE width="90%" align=center border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;A href="http://www.wapzj.com/html/UploadPic/2005-9/200591491127681.jpg" target=_blank&gt;&lt;IMG onmousewheel="return bbimg(this)" style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.wapzj.com/html/UploadPic/2005-9/200591491127681.jpg" onload="javascript:if(this.width&gt;screen.width-600)this.style.width=screen.width-600;" border=0&gt;&lt;/A&gt;&lt;BR&gt;图1－新建智能设备应用程序&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;
&lt;TABLE width="90%" align=center border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;A href="http://www.wapzj.com/html/UploadPic/2005-9/200591491128701.jpg" target=_blank&gt;&lt;IMG onmousewheel="return bbimg(this)" style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.wapzj.com/html/UploadPic/2005-9/200591491128701.jpg" onload="javascript:if(this.width&gt;screen.width-600)this.style.width=screen.width-600;" border=0&gt;&lt;/A&gt;&lt;BR&gt;图2－界面设计&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;BR&gt;　　2、引用建好的WebService&lt;BR&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;
&lt;TABLE width="90%" align=center border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;A href="http://www.wapzj.com/html/UploadPic/2005-9/200591491129692.jpg" target=_blank&gt;&lt;IMG onmousewheel="return bbimg(this)" style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.wapzj.com/html/UploadPic/2005-9/200591491129692.jpg" onload="javascript:if(this.width&gt;screen.width-600)this.style.width=screen.width-600;" border=0&gt;&lt;/A&gt;&lt;BR&gt;图3－引用WebService&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;　　3、WeatherService智能手机上运行的程序源代码&lt;BR&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;
&lt;TABLE borderColor=#ffcc66 width="90%" align=center bgColor=#dadacf border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;using System;&lt;BR&gt;using System.Drawing;&lt;BR&gt;using System.Collections;&lt;BR&gt;using System.Windows.Forms;&lt;BR&gt;using System.Data;&lt;BR&gt;&lt;BR&gt;namespace WeatherService&lt;BR&gt;{&lt;BR&gt;　/// ＜summary＞&lt;BR&gt;　/// Summary description for MainForm.&lt;BR&gt;　/// ＜/summary＞&lt;BR&gt;&lt;BR&gt;　public class MainForm : System.Windows.Forms.Form&lt;BR&gt;　{&lt;BR&gt;　　private System.Windows.Forms.ComboBox comboBox_City;&lt;BR&gt;　　private System.Windows.Forms.MenuItem menuItem1;&lt;BR&gt;　　private System.Windows.Forms.Label txt_Weather1;&lt;BR&gt;　　private System.Windows.Forms.Label txt_Date1;&lt;BR&gt;　　private System.Windows.Forms.Label txt_Temp1;&lt;BR&gt;　　private System.Windows.Forms.Label txt_WindPower1;&lt;BR&gt;　　private System.Windows.Forms.Label txt_Temp2;&lt;BR&gt;　　private System.Windows.Forms.Label txt_WindPower2;&lt;BR&gt;　　private System.Windows.Forms.Label txt_Date2;&lt;BR&gt;　　private System.Windows.Forms.Label txt_Weather2;&lt;BR&gt;　　private System.Windows.Forms.MainMenu mainMenu1;&lt;BR&gt;　　private System.Windows.Forms.MenuItem menuItem_Menu;&lt;BR&gt;　　private System.Windows.Forms.MenuItem menuItem_Exit;&lt;BR&gt;　　private System.Windows.Forms.Label label_City;&lt;BR&gt;　　private System.Windows.Forms.Timer timer1;&lt;BR&gt;　　private System.Windows.Forms.MenuItem menuItem2;&lt;BR&gt;　　private System.Windows.Forms.MenuItem menuItem3;&lt;BR&gt;&lt;BR&gt;　　public string[] cityList = new string[]&lt;BR&gt;　　{&lt;BR&gt;　　　"北京",&lt;BR&gt;　　　"上海",&lt;BR&gt;　　　"天津",&lt;BR&gt;　　　"石家庄",&lt;BR&gt;　　　"哈尔滨",&lt;BR&gt;　　　"沈阳",&lt;BR&gt;　　　"长春",&lt;BR&gt;　　　"太原",&lt;BR&gt;　　　"济南",&lt;BR&gt;　　　"郑州",&lt;BR&gt;　　　"天津",&lt;BR&gt;　　　"呼和浩特",&lt;BR&gt;　　　"西安",&lt;BR&gt;　　　"银川",&lt;BR&gt;　　　"兰州",&lt;BR&gt;　　　"西宁",&lt;BR&gt;　　　"乌鲁木齐",&lt;BR&gt;　　　"合肥",&lt;BR&gt;　　　"南昌",&lt;BR&gt;　　　"南京",&lt;BR&gt;　　　"杭州",&lt;BR&gt;　　　"武汉",&lt;BR&gt;　　　"长沙",&lt;BR&gt;　　　"广州",&lt;BR&gt;　　　"深圳",&lt;BR&gt;　　　"福州",&lt;BR&gt;　　　"厦门",&lt;BR&gt;　　　"南宁",&lt;BR&gt;　　　"桂林",&lt;BR&gt;　　　"海口",&lt;BR&gt;　　　"重庆",&lt;BR&gt;　　　"成都",&lt;BR&gt;　　　"贵阳",&lt;BR&gt;　　　"昆明",&lt;BR&gt;　　　"拉萨",&lt;BR&gt;　　　"香港",&lt;BR&gt;　　　"澳门",&lt;BR&gt;　　　"台北",&lt;BR&gt;　　};&lt;BR&gt;&lt;BR&gt;　　public MainForm()&lt;BR&gt;　　{&lt;BR&gt;　　　InitializeComponent();&lt;BR&gt;　　　foreach( string x in cityList)&lt;BR&gt;　　　{&lt;BR&gt;　　　　this.comboBox_City.Items.Add(x);&lt;BR&gt;　　　}&lt;BR&gt;&lt;BR&gt;　　　this.comboBox_City.SelectedIndex = 0;&lt;BR&gt;　　}&lt;BR&gt;&lt;BR&gt;　　/// ＜summary＞&lt;BR&gt;　　/// Clean up any resources being used.&lt;BR&gt;　　/// ＜/summary＞&lt;BR&gt;&lt;BR&gt;　　protected override void Dispose( bool disposing )&lt;BR&gt;　　{&lt;BR&gt;　　　base.Dispose( disposing );&lt;BR&gt;　　}&lt;BR&gt;&lt;BR&gt;　　#region Windows Form Designer generated code&lt;BR&gt;&lt;BR&gt;　　/// ＜summary＞&lt;BR&gt;　　/// Required method for Designer support - do not modify&lt;BR&gt;　　/// the contents of this method with the code editor.&lt;BR&gt;　　/// ＜/summary＞&lt;BR&gt;&lt;BR&gt;　　private void InitializeComponent()&lt;BR&gt;　　{&lt;BR&gt;　　　this.mainMenu1 = new System.Windows.Forms.MainMenu();&lt;BR&gt;　　　this.menuItem1 = new System.Windows.Forms.MenuItem();&lt;BR&gt;　　　this.menuItem_Menu = new System.Windows.Forms.MenuItem();&lt;BR&gt;　　　this.menuItem_Exit = new System.Windows.Forms.MenuItem();&lt;BR&gt;　　　this.menuItem3 = new System.Windows.Forms.MenuItem();&lt;BR&gt;　　　this.menuItem2 = new System.Windows.Forms.MenuItem();&lt;BR&gt;　　　this.comboBox_City = new System.Windows.Forms.ComboBox();&lt;BR&gt;　　　this.label_City = new System.Windows.Forms.Label();&lt;BR&gt;　　　this.txt_Weather1 = new System.Windows.Forms.Label();&lt;BR&gt;　　　this.txt_Date1 = new System.Windows.Forms.Label();&lt;BR&gt;　　　this.txt_Temp1 = new System.Windows.Forms.Label();&lt;BR&gt;　　　this.txt_WindPower1 = new System.Windows.Forms.Label();&lt;BR&gt;　　　this.txt_Temp2 = new System.Windows.Forms.Label();&lt;BR&gt;　　　this.txt_WindPower2 = new System.Windows.Forms.Label();&lt;BR&gt;　　　this.txt_Date2 = new System.Windows.Forms.Label();&lt;BR&gt;　　　this.txt_Weather2 = new System.Windows.Forms.Label();&lt;BR&gt;　　　this.timer1 = new System.Windows.Forms.Timer();&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// mainMenu1&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.mainMenu1.MenuItems.Add(this.menuItem1);&lt;BR&gt;　　　this.mainMenu1.MenuItems.Add(this.menuItem_Menu);&lt;BR&gt;　　　// &lt;BR&gt;　　　// menuItem1&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.menuItem1.Text = "确定";&lt;BR&gt;　　　this.menuItem1.Click += new System.EventHandler(this.menuItem1_Click);&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// menuItem_Menu&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.menuItem_Menu.MenuItems.Add(this.menuItem_Exit);&lt;BR&gt;　　　this.menuItem_Menu.MenuItems.Add(this.menuItem3);&lt;BR&gt;　　　this.menuItem_Menu.MenuItems.Add(this.menuItem2);&lt;BR&gt;　　　this.menuItem_Menu.Text = "菜单";&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// menuItem_Exit&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.menuItem_Exit.Text = "退出";&lt;BR&gt;　　　this.menuItem_Exit.Click += new System.EventHandler(this.menuItem_Exit_Click);&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// menuItem3&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.menuItem3.Text = "-";&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// menuItem2&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.menuItem2.Text = "关于";&lt;BR&gt;　　　this.menuItem2.Click += new System.EventHandler(this.menuItem2_Click);&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// comboBox_City&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.comboBox_City.Font = new System.Drawing.Font("Nina", 9F, System.Drawing.FontStyle.Regular);&lt;BR&gt;　　　this.comboBox_City.Location = new System.Drawing.Point(52, 8);&lt;BR&gt;　　　this.comboBox_City.Size = new System.Drawing.Size(114, 22);&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// label_City&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.label_City.Font = new System.Drawing.Font("Nina", 9F, System.Drawing.FontStyle.Bold);&lt;BR&gt;　　　this.label_City.Location = new System.Drawing.Point(4, 12);&lt;BR&gt;　　　this.label_City.Size = new System.Drawing.Size(52, 16);&lt;BR&gt;　　　this.label_City.Text = "城市：";&lt;BR&gt;　　　this.label_City.TextAlign = System.Drawing.ContentAlignment.TopCenter;&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// txt_Weather1&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.txt_Weather1.Font = new System.Drawing.Font("Nina", 9F, System.Drawing.FontStyle.Regular);&lt;BR&gt;　　　this.txt_Weather1.Location = new System.Drawing.Point(12, 50);&lt;BR&gt;　　　this.txt_Weather1.Size = new System.Drawing.Size(152, 14);&lt;BR&gt;　　　this.txt_Weather1.Text = "天气:";&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// txt_Date1&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.txt_Date1.Font = new System.Drawing.Font("Nina", 9F, System.Drawing.FontStyle.Regular);&lt;BR&gt;　　　this.txt_Date1.Location = new System.Drawing.Point(12, 34);&lt;BR&gt;　　　this.txt_Date1.Size = new System.Drawing.Size(152, 14);&lt;BR&gt;　　　this.txt_Date1.Text = "日期:";&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// txt_Temp1&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.txt_Temp1.Font = new System.Drawing.Font("Nina", 9F, System.Drawing.FontStyle.Regular);&lt;BR&gt;　　　this.txt_Temp1.Location = new System.Drawing.Point(12, 68);&lt;BR&gt;　　　this.txt_Temp1.Size = new System.Drawing.Size(152, 14);&lt;BR&gt;　　　this.txt_Temp1.Text = "气温:";&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// txt_WindPower1&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.txt_WindPower1.Font = new System.Drawing.Font("Nina", 9F, System.Drawing.FontStyle.Regular);&lt;BR&gt;　　　this.txt_WindPower1.Location = new System.Drawing.Point(12, 84);&lt;BR&gt;　　　this.txt_WindPower1.Size = new System.Drawing.Size(152, 14);&lt;BR&gt;　　　this.txt_WindPower1.Text = "风力:";&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// txt_Temp2&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.txt_Temp2.Font = new System.Drawing.Font("Nina", 9F, System.Drawing.FontStyle.Regular);&lt;BR&gt;　　　this.txt_Temp2.Location = new System.Drawing.Point(12, 140);&lt;BR&gt;　　　this.txt_Temp2.Size = new System.Drawing.Size(152, 14);&lt;BR&gt;　　　this.txt_Temp2.Text = "气温:";&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// txt_WindPower2&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.txt_WindPower2.Font = new System.Drawing.Font("Nina", 9F, System.Drawing.FontStyle.Regular);&lt;BR&gt;　　　this.txt_WindPower2.Location = new System.Drawing.Point(12, 156);&lt;BR&gt;　　　this.txt_WindPower2.Size = new System.Drawing.Size(152, 14);&lt;BR&gt;　　　this.txt_WindPower2.Text = "风力:";&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// txt_Date2&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.txt_Date2.Font = new System.Drawing.Font("Nina", 9F, System.Drawing.FontStyle.Regular);&lt;BR&gt;　　　this.txt_Date2.Location = new System.Drawing.Point(12, 108);&lt;BR&gt;　　　this.txt_Date2.Size = new System.Drawing.Size(152, 14);&lt;BR&gt;　　　this.txt_Date2.Text = "日期:";&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// txt_Weather2&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.txt_Weather2.Font = new System.Drawing.Font("Nina", 9F, System.Drawing.FontStyle.Regular);&lt;BR&gt;　　　this.txt_Weather2.Location = new System.Drawing.Point(12, 124);&lt;BR&gt;　　　this.txt_Weather2.Size = new System.Drawing.Size(152, 14);&lt;BR&gt;　　　this.txt_Weather2.Text = "天气:";&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// timer1&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.timer1.Interval = 200;&lt;BR&gt;　　　this.timer1.Tick += new System.EventHandler(this.timer1_Tick);&lt;BR&gt;&lt;BR&gt;　　　// &lt;BR&gt;　　　// MainForm&lt;BR&gt;　　　// &lt;BR&gt;&lt;BR&gt;　　　this.Controls.Add(this.comboBox_City);&lt;BR&gt;　　　this.Controls.Add(this.txt_Date1);&lt;BR&gt;　　　this.Controls.Add(this.txt_Weather1);&lt;BR&gt;　　　this.Controls.Add(this.label_City);&lt;BR&gt;　　　this.Controls.Add(this.txt_Temp1);&lt;BR&gt;　　　this.Controls.Add(this.txt_WindPower1);&lt;BR&gt;　　　this.Controls.Add(this.txt_Temp2);&lt;BR&gt;　　　this.Controls.Add(this.txt_WindPower2);&lt;BR&gt;　　　this.Controls.Add(this.txt_Date2);&lt;BR&gt;　　　this.Controls.Add(this.txt_Weather2);&lt;BR&gt;　　　this.Menu = this.mainMenu1;&lt;BR&gt;　　　this.Text = "天气预报";&lt;BR&gt;　　}&lt;BR&gt;&lt;BR&gt;　　#endregion&lt;BR&gt;&lt;BR&gt;　　/// ＜summary＞&lt;BR&gt;　　/// The main entry point for the application.&lt;BR&gt;　　/// ＜/summary＞&lt;BR&gt;&lt;BR&gt;　　static void Main() &lt;BR&gt;　　{&lt;BR&gt;　　　Application.Run(new MainForm());&lt;BR&gt;　　}&lt;BR&gt;&lt;BR&gt;　　private void menuItem_Exit_Click(object sender, System.EventArgs e)&lt;BR&gt;　　{&lt;BR&gt;　　　this.Dispose();&lt;BR&gt;　　}&lt;BR&gt;&lt;BR&gt;　　private void menuItem1_Click(object sender, System.EventArgs e)&lt;BR&gt;　　{&lt;BR&gt;　　　SearchWeather(this.comboBox_City.Text);&lt;BR&gt;　　}&lt;BR&gt;&lt;BR&gt;　　private string[] myString = new string[]&lt;BR&gt;　　{&lt;BR&gt;　　　 "日期: ",&lt;BR&gt;　　　 "温度: ",&lt;BR&gt;　　　 "天气: ",&lt;BR&gt;　　　 "风力: ",&lt;BR&gt;　　};&lt;BR&gt;&lt;BR&gt;　　public void SearchWeather(string cityName)&lt;BR&gt;　　{&lt;BR&gt;　　　if( this.txt_Date1.Text != myString[0] )&lt;BR&gt;　　　{&lt;BR&gt;　　　　ReSelect();&lt;BR&gt;　　　}&lt;BR&gt;&lt;BR&gt;　　　this.Text = "正在下载...";&lt;BR&gt;　　　this.timer1.Enabled = true;&lt;BR&gt;&lt;BR&gt;　　　WeatherService.Weather weather = new WeatherService.Weather();&lt;BR&gt;　　　DataSet myDs = weather.GetWeatherDataSet(cityName);&lt;BR&gt;&lt;BR&gt;　　　this.txt_Date1.Text = myString[0] + myDs.Tables[0].Rows[0]["Date1"].ToString();&lt;BR&gt;　　　this.txt_Temp1.Text = myString[1] + myDs.Tables[0].Rows[0]["Temp1"].ToString();&lt;BR&gt;　　　this.txt_Weather1.Text = myString[2] + myDs.Tables[0].Rows[0]["Weather1"].ToString();&lt;BR&gt;　　　this.txt_WindPower1.Text = myString[3] + myDs.Tables[0].Rows[0]["WindPower1"].ToString();&lt;BR&gt;&lt;BR&gt;　　　this.txt_Date2.Text = myString[0] + myDs.Tables[0].Rows[0]["Date2"].ToString();&lt;BR&gt;　　　this.txt_Temp2.Text = myString[1] + myDs.Tables[0].Rows[0]["Temp2"].ToString();&lt;BR&gt;　　　this.txt_Weather2.Text = myString[2] + myDs.Tables[0].Rows[0]["Weather2"].ToString();&lt;BR&gt;　　　this.txt_WindPower2.Text = myString[3] + myDs.Tables[0].Rows[0]["WindPower2"].ToString();&lt;BR&gt;　　}&lt;BR&gt;&lt;BR&gt;　　private void ReSelect()&lt;BR&gt;　　{&lt;BR&gt;　　　this.txt_Date1.Text = myString[0];&lt;BR&gt;　　　this.txt_Temp1.Text = myString[1];&lt;BR&gt;　　　this.txt_Weather1.Text = myString[2];&lt;BR&gt;　　　this.txt_WindPower1.Text = myString[3];&lt;BR&gt;　　　this.txt_Date2.Text = myString[0];&lt;BR&gt;　　　this.txt_Temp2.Text = myString[1];&lt;BR&gt;　　　this.txt_Weather2.Text = myString[2];&lt;BR&gt;　　　this.txt_WindPower2.Text = myString[3];&lt;BR&gt;　　}&lt;BR&gt;&lt;BR&gt;　　private void timer1_Tick(object sender, System.EventArgs e)&lt;BR&gt;　　{&lt;BR&gt;　　　if( this.txt_Date1.Text.IndexOf("月") != -1)&lt;BR&gt;　　　{&lt;BR&gt;　　　　this.timer1.Enabled = false;&lt;BR&gt;　　　　this.Text = "天气预报";&lt;BR&gt;　　　}&lt;BR&gt;　　}&lt;BR&gt;&lt;BR&gt;　　private void menuItem2_Click(object sender, System.EventArgs e)&lt;BR&gt;　　{&lt;BR&gt;　　　this.Text = "作者:贺星河";&lt;BR&gt;　　　System.Threading.Thread.Sleep(3000);&lt;BR&gt;　　　this.Text = "天气预报";&lt;BR&gt;　　}&lt;BR&gt;　}&lt;BR&gt;}&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;　　&lt;STRONG&gt;四、在多普达565手机上部署并运行&lt;BR&gt;&lt;BR&gt;&lt;/STRONG&gt;　　1、在VS.NET2003的&amp;#8220;解决方案WeatherService&amp;#8221;上点击右键，选择&amp;#8221;部署解决方案&amp;#8221;，出现一下对话框&lt;BR&gt;&lt;BR&gt;
&lt;TABLE width="90%" align=center border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;A href="http://www.wapzj.com/html/UploadPic/2005-9/200591491129968.jpg" target=_blank&gt;&lt;IMG onmousewheel="return bbimg(this)" style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.wapzj.com/html/UploadPic/2005-9/200591491129968.jpg" onload="javascript:if(this.width&gt;screen.width-600)this.style.width=screen.width-600;" border=0&gt;&lt;/A&gt;&lt;BR&gt;图4－部署解决方案&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;BR&gt;　　选择&amp;#8220;部署&amp;#8221;，&amp;#8220;部署&amp;#8221;完成后，手机上将显示如下界面&lt;BR&gt;&lt;BR&gt;
&lt;TABLE width="90%" align=center border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;A href="http://www.wapzj.com/html/UploadPic/2005-9/200591491130995.jpg" target=_blank&gt;&lt;IMG onmousewheel="return bbimg(this)" style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.wapzj.com/html/UploadPic/2005-9/200591491130995.jpg" onload="javascript:if(this.width&gt;screen.width-600)this.style.width=screen.width-600;" border=0&gt;&lt;/A&gt;&lt;BR&gt;图5、手机界面之一－部署&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;BR&gt;　　因为我的PC机器上安装了.NET Framework1.1SP1，所以会提示这个界面，选择&amp;#8220;确定&amp;#8221;，继续执行安装部署：&lt;BR&gt;&lt;BR&gt;
&lt;TABLE width="90%" align=center border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;A href="http://www.wapzj.com/html/UploadPic/2005-9/200591491130333.jpg" target=_blank&gt;&lt;IMG onmousewheel="return bbimg(this)" style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.wapzj.com/html/UploadPic/2005-9/200591491130333.jpg" onload="javascript:if(this.width&gt;screen.width-600)this.style.width=screen.width-600;" border=0&gt;&lt;/A&gt;&lt;BR&gt;图6、手机界面之二－选择安装位置&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;BR&gt;　　选择安装位置为&amp;#8221;Sotrage Card&amp;#8221;,选择&amp;#8220;完成&amp;#8221;,这个时候程序就部署完毕了，&lt;BR&gt;&lt;BR&gt;　　使用Resco Explore 2003，找到安装部署后程序所在的目录，在 \Sorage\Program Files\WeatherService\ 目录下面，执行程序WeatherService.exe，将出现如下画面：&lt;BR&gt;&lt;BR&gt;
&lt;TABLE width="90%" align=center border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;A href="http://www.wapzj.com/html/UploadPic/2005-9/200591491130229.jpg" target=_blank&gt;&lt;IMG onmousewheel="return bbimg(this)" style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.wapzj.com/html/UploadPic/2005-9/200591491130229.jpg" onload="javascript:if(this.width&gt;screen.width-600)this.style.width=screen.width-600;" border=0&gt;&lt;/A&gt;&lt;BR&gt;图7、手机界面之三－开始执行程序 选择&amp;#8220;是&amp;#8221;。&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;BR&gt;　　之所以出现这个画面，是因为程序没有经过系统的认证，也是微软安全方面的一个体现，即时这个程序会正常执行，也不会冒然打出电话！&lt;BR&gt;&lt;BR&gt;　　程序执行之后，会出现如下画面，选择需要查询的城市名称，点&amp;#8220;确定&amp;#8221;&lt;BR&gt;&lt;BR&gt;
&lt;TABLE width="90%" align=center border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;A href="http://www.wapzj.com/html/UploadPic/2005-9/200591491130253.jpg" target=_blank&gt;&lt;IMG onmousewheel="return bbimg(this)" style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.wapzj.com/html/UploadPic/2005-9/200591491130253.jpg" onload="javascript:if(this.width&gt;screen.width-600)this.style.width=screen.width-600;" border=0&gt;&lt;/A&gt;&lt;BR&gt;图8、手机界面之四－程序界面&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;BR&gt;　　之后程序标题会变为&amp;#8220;正在下载&amp;#8230;&amp;#8221;，程序通过GPRS上网读取部署在Internet上的WebService&lt;BR&gt;&lt;BR&gt;
&lt;TABLE width="90%" align=center border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;A href="http://www.wapzj.com/html/UploadPic/2005-9/200591491130695.jpg" target=_blank&gt;&lt;IMG onmousewheel="return bbimg(this)" style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.wapzj.com/html/UploadPic/2005-9/200591491130695.jpg" onload="javascript:if(this.width&gt;screen.width-600)this.style.width=screen.width-600;" border=0&gt;&lt;/A&gt;&lt;BR&gt;图9、手机界面之五－运行界面&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;BR&gt;　　稍等几秒钟之后，便会看到所需要的天气信息数据&lt;BR&gt;&lt;BR&gt;
&lt;TABLE width="90%" align=center border=0&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&lt;A href="http://www.wapzj.com/html/UploadPic/2005-9/200591491130150.jpg" target=_blank&gt;&lt;IMG onmousewheel="return bbimg(this)" style="CURSOR: pointer" onclick=javascript:window.open(this.src); src="http://www.wapzj.com/html/UploadPic/2005-9/200591491130150.jpg" onload="javascript:if(this.width&gt;screen.width-600)this.style.width=screen.width-600;" border=0&gt;&lt;/A&gt;&lt;BR&gt;图10、手机界面之六－运行结果&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;&lt;img src ="http://blog.vckbase.com/teky/aggbug/23324.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>teky </dc:creator><title>Windows Mobile中的WebService应用</title><link>http://blog.vckbase.com/teky/articles/23106.html</link><pubDate>Mon, 13 Nov 2006 08:14:00 GMT</pubDate><guid>http://blog.vckbase.com/teky/articles/23106.html</guid><wfw:comment>http://blog.vckbase.com/teky/comments/23106.html</wfw:comment><comments>http://blog.vckbase.com/teky/articles/23106.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://blog.vckbase.com/teky/comments/commentRss/23106.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/teky/services/trackbacks/23106.html</trackback:ping><description>&lt;A class=fwhere&gt;【2006-03-23 16:04】&lt;/A&gt;&lt;A class=fwhere&gt;【】&lt;/A&gt;&lt;A class=fwhere&gt;【CSDN】&lt;/A&gt;&lt;BR&gt;&lt;BR&gt;WebService对于开发者来说已经不再是一个陌生概念了。Web Service允许应用程序通过Internet进行通讯和数据交换。随着微软.NET战略的推行，这种可编程的、通过SOAP协议、基于XML的网络协议已经赢得了开发者的心。
&lt;P&gt;　　现在，随着无线数据网络的发展，移动设备如何访问网络资源的问题显得格外突出。我们目前已经拥有了GPRS和CDMA的广域数据通讯网络，很多地方也覆盖了WI-FI的无线数据局域网。如何让我们的应用程序更好的利用网络资源?&lt;/P&gt;
&lt;P&gt;　　Windows Mobile移动设备为我们提供了.NET Compact Framework，为我们开发移动应用程序带来的了极大的方便。.NET Compact Framework也提供了方便的Web Service访问方式，帮助开发者来编写基于Web Service的移动应用程序。&lt;/P&gt;
&lt;P&gt;　　目前来看，Windows Mobile应用程序访问Web Service的应用主要出现在两个方面:首先是个人应用程序需要获取公共数据服务，比如获取天气预报、地理信息等;其次是，基于Windows Mobile的企业级应用将核心服务发布成Web Service形式，由移动应用程序进行调用。&lt;/P&gt;
&lt;P&gt;　　我们这次主要讨论调用公众数据服务Web Service的情况，以Google和MapPoint Web Service为样本，讲述如何在Windows Mobile应用程序中调用搜索引擎和地图服务。&lt;/P&gt;
&lt;P&gt;　　&lt;STRONG&gt;&lt;FONT color=#ff1493&gt;访问Google Web Service&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;　　Google是目前网络上最流行的搜索引擎之一，关键字搜索完全改变了网络信息的组织形式。Google很早就提供了公共Web Service服务，允许应用程序访问Google提供的搜索、拼写检查和页面缓存的功能。Google Web Service的每个帐号一天最多查询一千次。&lt;/P&gt;
&lt;P&gt;　　在使用Google之前，我们必须去www.google.com/apis，申请一个Google Account。注册成功后，会收到一个Google的关键字，每次调用的时候，都要提供这个关键字。&lt;/P&gt;
&lt;P&gt;　　在申请成功后，我们可以动手开发自己的应用程序了。我们在Visual Studio 2005 Beta 2中创建一个Device Application。然后我们要为Google Web Service添加一个Web引用。在Project菜单中选择Add Web Reference，在URL里输入 http://api.google.com/GoogleSearch.wsdl,选择Add Reference按钮就可以了。这样，我们就把Google Web Service添加到我们的应用程序中来了。&lt;/P&gt;
&lt;P&gt;　　我们先来认识一下Google Web Service中的对象。这些对象设计得和Google的主页一样简单。&lt;/P&gt;
&lt;P&gt;
&lt;TABLE style="WIDTH: 400px; HEIGHT: 72px" borderColor=#000000 cellSpacing=0 cellPadding=0 width=400 bgColor=#ffffff border=1 heihgt=""&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;对象&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;说明&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;DirectoryCategory&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;ODP目录的内容和种类&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;GoogleSearchResult&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;Goolge查询结果&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;GoogleSearchService&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;Google查询服务对象&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;ResultElement&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;查询结果集元素&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;　　我们下面就来用这些对象来编写一个简单的Google查询的程序。我们首先要介绍一个重要的API:GoogleSearchService下的doGoogleSearch。&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;public GoogleSearchResult doGoogleSearch(&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string key, // Google Key&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string q, // 查询内容&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int start, // 从第几条结果开始返回&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; int maxResults, // 最多返回多少条（最多10条）&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; bool filter, // 是否自动过滤相似或来源相同的结果&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string restrict, // 限制查询结果来自Google Web 索引的一个子集&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; bool safeSearch, // 是否过滤成年人内容&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string lr, // 语言限制（&amp;#8221;lang_zh-CN&amp;#8221;为中文）&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string ie, // 输入编码&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; string oe) // 输出编码&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;　　在某些情况下，我们需要设置代理服务器来访问一些网络资源，所以，我们要引入System.Net的命名空间，然后创建一个Web Proxy赋给GlobalProxySelection，才能保证我们调用Web Service的正常。&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;WebProxy proxy = new WebProxy("itgproxy",80);&lt;BR&gt;proxy.BypassProxyOnLocal = true;&lt;BR&gt;GlobalProxySelection.Select = proxy;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;　　在上面的代码里我们首先创建一个WebProxy，地址为&amp;#8221; itgproxy&amp;#8221;，端口为80。然后选择本地地址不使用代理服务器，最后设置到GlobalProxySelection中。&lt;/P&gt;
&lt;P&gt;　　下面我们把完整的代码写出来:&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;try&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; WebProxy proxy = new WebProxy("itgproxy",80);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; proxy.BypassProxyOnLocal = true;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GlobalProxySelection.Select = proxy;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GoogleSearchService service = new GoogleSearchService();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GoogleSearchResult result = service.doGoogleSearch(&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; key, // 查询Key&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; textBox1.Text, // 内容&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0, // 从第几条结果开始返回&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 10, // 最多返回的条数（最大10条）&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; false, // 是否自动过滤相似或来源相同的结果&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "", // 限制查询结果来自Google Web索引的一个子集&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; false, // 是否过滤成年人内容&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "", //"lang_zh-CN", // 语言限制&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "", // 输入编码&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ""); // 输出编码&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for(int i = 0; i &amp;lt;= (result.endIndex - result.startIndex); i++)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ResultElement element = result.resultElements[i];&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; listBox1.Items.Add(element.title);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; listBox1.Items.Add(element.snippet);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; listBox1.Items.Add(element.URL);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; MessageBox.Show(result.estimatedTotalResultsCount.ToString());&lt;BR&gt;}&lt;BR&gt;catch (System.Web.Services.Protocols.SoapException ex)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; MessageBox.Show(ex.Message);&lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;　　在设置好代理服务器后，我们创建一个GoogleSearchService的对象，然后调用该对象的doGoogleSearch方法。我们将得到一个GoogleSearchResult的结果集，通过endIndex和startIndex属性，我们可以获得查询结果的数量。我们从结果集对象的resultElements中获得ResultElement对象，然后把标题、简介和URL显示到listBox中去。最后我们可以用结果集对象的estimatedTotalResultsCount属性，来获取一共找到了多少个结果。我们上边曾经说过，每次查询最多只能返回10个结果，但是estimatedTotalResultsCount返回的是所有符合条件的记录。&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#ff1493&gt;访问MapPoint Web Service&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;　　MapPoint是微软提供的一个地图信息的Web Service，提供全球各地的地理信息和商业网点信息(主要是北美和欧洲地区)。MSN Search推出的地理搜索服务也是基于MapPoint Web Service服务的。目前MapPoint还不包括中国的地理信息。&lt;/P&gt;
&lt;P&gt;　　Windows Mobile设备的存储空间比较小，所以很难保存大量的地图数据。但是随着无线网络的普及，Windows Mobile设备就可以方便地查询保存在服务器上的地图数据和黄页信息。MapPoint Web Service还可以结合Windows Mobile设备上的GPS定位系统或者LBS服务，查询附近的旅游景点和商业场所，这对于移动应用也具有十分现实的意义。&lt;/P&gt;
&lt;P&gt;　　MapPoint是一个收费的Web Service，不过，我们可以申请一个60天的测试帐号。MSDN的订户还可以申请一个为期一年的帐号，用于应用程序的开发。在申请到帐号后，我们不但可以查询公共的地理信息，还可以上传自己的地理信息，用于支持自定义的地理信息查询。&lt;/P&gt;
&lt;P&gt;　　我们创建一个Windows Mobile Device Application，然后添加一个Web Reference，URL为&amp;#8220;http://staging.mappoint.net/standard-30/mappoint.wsdl&amp;#8221;。&lt;/P&gt;
&lt;P&gt;　　在编写程序之前，我们先来看一下MapPoint中需要用到的类和方法。&lt;/P&gt;
&lt;P&gt;
&lt;TABLE style="WIDTH: 499px; HEIGHT: 157px" borderColor=#000000 cellSpacing=0 cellPadding=0 width=499 bgColor=#ffffff border=1 heihgt=""&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;类方法&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;说明&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;FindServiceSoap&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;包括查询服务(find service)的方法和属性&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;RenderServiceSoap&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;包括查询结果表示服务(render service)的方法和属性&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;FindSpecification&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;用于指定FindServiceSoap.Find的查询信息&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;FindResults&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;FindServiceSoap查询操作的单个结果&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;ViewByScale&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;包含地图定义地图比例和基准点&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;MapOptions&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;包含RenderServiceSoap.GetMap方法的地图显示选项&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;Pushpin&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;包括图钉的图标、标签、定位、用户指定数字&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;MapSpecification&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;包含地图显示的详细规范&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;nbsp;MapImage&lt;/TD&gt;
&lt;TD&gt;&amp;nbsp;RenderServiceSoap.GetMap返回的地图&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;　　我们首先来创建MapPoint查询过程中最重要的两个对象:&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;FindServiceSoap fws = new FindServiceSoap();&lt;BR&gt;RenderServiceSoap ws = new RenderServiceSoap();&lt;BR&gt;fws.Credentials = new NetworkCredential(myUserName, myPassword);&lt;BR&gt;ws.Credentials = new NetworkCredential(myUserName, myPassword);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;　　FindServiceSoap是提供地图查询服务的主要对象，RenderServiceSoap是表现查询结果地图的主要对象。在使用之前，我们要先创建一个NetworkCredential对象，将MapPoint的用户名和密码传给FindServiceSoap和RenderServiceSoap的Credentials属性。&lt;/P&gt;
&lt;P&gt;　　然后我们创建一个FindSpecification对象，指定地图数据库、要查询的地点，然后将其作为FindServiceSoap的Find方法的参数执行查询，并返回FindResults对象中。&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;FindSpecification myFindSpec = new FindSpecification();&lt;BR&gt;myFindSpec.DataSourceName = "MapPoint.NA";&lt;BR&gt;myFindSpec.InputPlace = this.textBox1.Text;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;FindResults results = fws.Find(myFindSpec);&lt;BR&gt;if (0 == results.NumberFound)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; MessageBox.Show("你找的是什么鬼地方？");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return;&lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;　　我们选择的地图数据源是北美地区的数据集&amp;#8220;MapPoint.NA&amp;#8221;，而InputPlace是要查询的地点，从界面上的文本框中获得。然后调用FindSpecification的Find方法，返回FindResults对象。如果结果集对象的NumberFound属性为0，则说明没找到合适的结果。&lt;/P&gt;
&lt;P&gt;　　然后我们创建一个ViewByScale对象，为该对象的CenterPoint属性创建LatLong对象。CenterPoint属性的经纬度分别results.Results[0].FoundLocation.LatLong中的经纬度。然后在ViewByScale对象的MapScale属性中设置地图的比例尺。创建MapOptions对象，在MapOptions.Format设置地图的宽度和长度。创建一个图钉对象Pushpin，将图钉对象的经纬度设置为ViewByScale对象的经纬度。&lt;/P&gt;
&lt;P&gt;　　在创建完这些对象后，我们创建一个MapSpecification对象用于指定要显示地图的详细情况。我们要指定MapSpecification对象的地图数据集，并将前边创建的三个对象分别赋给Options、Pushpins、Views属性中。&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;MapSpecification myMapSpec = new MapSpecification();&lt;BR&gt;myMapSpec.DataSourceName = "MapPoint.NA";&lt;BR&gt;myMapSpec.Options = options;&lt;BR&gt;myMapSpec.Pushpins = pushpins;&lt;BR&gt;myMapSpec.Views = views;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;　　在设置完成MapSpecification对象后，我们将其作为参数，调用RenderServiceSoap对象的GetMap方法，获取MapImage对象。然后将MapImage对象中的数据作为MemoryStream内存流，用于创建一个Bitmap对象，最后显示到PictureBox中。&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;MapImage[] images = ws.GetMap(myMapSpec);&lt;BR&gt;this.pictureBox1.Image = new System.Drawing.Bitmap(new System.IO.MemoryStream(images[0].MimeData.Bits));&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;　　完整代码如下:&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;WebProxy proxyObject = new WebProxy(proxy, 80);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;// Disable proxy use when the host is local.&lt;BR&gt;proxyObject.BypassProxyOnLocal = true;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;// All requests this proxy information.&lt;BR&gt;GlobalProxySelection.Select = proxyObject;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;FindServiceSoap fws = new FindServiceSoap();&lt;BR&gt;RenderServiceSoap ws = new RenderServiceSoap();&lt;BR&gt;fws.Credentials = new NetworkCredential(myUserName, myPassword);&lt;BR&gt;ws.Credentials = new NetworkCredential(myUserName, myPassword);&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;FindSpecification myFindSpec = new FindSpecification();&lt;BR&gt;myFindSpec.DataSourceName = "MapPoint.NA";&lt;BR&gt;myFindSpec.InputPlace = this.textBox1.Text;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;FindResults results = fws.Find(myFindSpec);&lt;BR&gt;if (0 == results.NumberFound)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; MessageBox.Show("你找的是什么鬼地方？");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return;&lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;ViewByScale[] views = new ViewByScale[1];&lt;BR&gt;views[0] = new ViewByScale();&lt;BR&gt;views[0].CenterPoint = new LatLong();&lt;BR&gt;views[0].CenterPoint.Latitude = results.Results[0].FoundLocation.LatLong.Latitude;&lt;BR&gt;views[0].CenterPoint.Longitude = results.Results[0].FoundLocation.LatLong.Longitude;&lt;BR&gt;views[0].MapScale = 150000;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;MapOptions options = new MapOptions();&lt;BR&gt;options.Format = new ImageFormat();&lt;BR&gt;options.Format.Height = this.pictureBox1.Height;&lt;BR&gt;options.Format.Width = this.pictureBox1.Width;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;Pushpin[] pushpins = new Pushpin[1];&lt;BR&gt;pushpins[0] = new Pushpin();&lt;BR&gt;pushpins[0].IconDataSource = "MapPoint.Icons";&lt;BR&gt;pushpins[0].IconName = "0";&lt;BR&gt;pushpins[0].Label = results.Results[0].FoundLocation.Entity.Name;&lt;BR&gt;pushpins[0].LatLong = views[0].CenterPoint;&lt;BR&gt;pushpins[0].ReturnsHotArea = true;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;MapSpecification myMapSpec = new MapSpecification();&lt;BR&gt;myMapSpec.DataSourceName = "MapPoint.NA";&lt;BR&gt;myMapSpec.Options = options;&lt;BR&gt;myMapSpec.Pushpins = pushpins;&lt;BR&gt;myMapSpec.Views = views;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT style="BACKGROUND-COLOR: #dddddd" face=Verdana color=#000000&gt;MapImage[] images = ws.GetMap(myMapSpec);&lt;BR&gt;this.pictureBox1.Image = new System.Drawing.Bitmap(new System.IO.MemoryStream(images[0].MimeData.Bits));&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;　　我们上面演示的仅仅是最简单的地图查询功能，我们还可以通过FindAddress, FindByID, FindByProperty, FindNearby 或者 FindNearRoute等方法来查询地址、查询附近的地点等。我们还可以通过MapPoint Web Service来实现智能路标的功能。&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#ff1493&gt;　　&lt;STRONG&gt;写在最后&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;　　上面我们一起了解了如何在Windows Mobile应用程序中加入Google和MapPoint的Web Service。我们还可以通过Web Service来发送短信，获取天气预报。越来越多的服务提供商也开始把自己的服务发布成Web Service，使自己的服务不但可以提供给终端用户，还可以提供给应用程序开发者，从而扩大自己的用户群。&lt;/P&gt;
&lt;P&gt;　　现在Web Service和Windows Mobile应用程序都处在发展期。随着无线网络的成熟，加上其他的智能手机操作系统也开始支持Web Service，我们会看到越来越多应用于移动设备上的Web Service案例。&lt;/P&gt;&lt;img src ="http://blog.vckbase.com/teky/aggbug/23106.html" width = "1" height = "1" /&gt;</description></item><item><dc:creator>teky </dc:creator><title>Creating a P/Invoke Library</title><link>http://blog.vckbase.com/teky/articles/22697.html</link><pubDate>Mon, 09 Oct 2006 06:07:00 GMT</pubDate><guid>http://blog.vckbase.com/teky/articles/22697.html</guid><wfw:comment>http://blog.vckbase.com/teky/comments/22697.html</wfw:comment><comments>http://blog.vckbase.com/teky/articles/22697.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://blog.vckbase.com/teky/comments/commentRss/22697.html</wfw:commentRss><trackback:ping>http://blog.vckbase.com/teky/services/trackbacks/22697.html</trackback:ping><description>&lt;DIV class=postText&gt;
&lt;DIV id=nsbanner&gt;
&lt;DIV id=TitleRow&gt;
&lt;H1 class=dtH1&gt;&lt;A name=pinvokelib&gt;&lt;/A&gt;Creating a P/Invoke Library&lt;/H1&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;!--NONSCROLLING BANNER END--&gt;
&lt;P&gt;Geoff Schwab&lt;BR&gt;Excell Data Corporation&lt;/P&gt;
&lt;P&gt;Contributors:&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Jonathan Wells&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Microsoft Corporation&lt;/P&gt;
&lt;P&gt;Registry Sample:&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Dan Elliott&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Microsoft Corporation&lt;/P&gt;
&lt;P&gt;Wave Samples:&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Seth Demsey&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Microsoft Corporation&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Jonathan Wells&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Microsoft Corporation&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;January 2004&lt;/P&gt;
&lt;P&gt;Applies to: &lt;B&gt;&lt;BR&gt;&lt;/B&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Microsoft&amp;#174; .NET Compact Framework 1.0&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Microsoft Visual Studio&amp;#174; .NET 2003&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Summary:&lt;/B&gt; This sample demonstrates how to P/Invoke numerous useful native functions that are not directly available through the .NET Compact Framework. A test &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Form&lt;/FONT&gt;&lt;/CODE&gt; is provided that enumerates all available test procedures and allows the user to select and run them. (18 printed pages)&lt;/P&gt;
&lt;P&gt;Download &lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyId=B1F5CCAA-ADA2-42D4-8B70-95DC7D8F678C&amp;amp;displaylang=en"&gt;&lt;FONT color=#002c99&gt;Sample&lt;/FONT&gt;&lt;/A&gt;&lt;/P&gt;
&lt;H4 class=dtH1&gt;Contents&lt;/H4&gt;
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_001" target=_self&gt;&lt;FONT color=#002c99&gt;Introduction&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_002" target=_self&gt;&lt;FONT color=#002c99&gt;The Test Application&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_003" target=_self&gt;&lt;FONT color=#002c99&gt;Input&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_004" target=_self&gt;&lt;FONT color=#002c99&gt;Memory&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_005" target=_self&gt;&lt;FONT color=#002c99&gt;Memory Status&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_006" target=_self&gt;&lt;FONT color=#002c99&gt;Performance Counters&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_007" target=_self&gt;&lt;FONT color=#002c99&gt;Power Status&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_008" target=_self&gt;&lt;FONT color=#002c99&gt;SIP&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_009" target=_self&gt;&lt;FONT color=#002c99&gt;System Reset&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_010" target=_self&gt;&lt;FONT color=#002c99&gt;System Time&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_011" target=_self&gt;&lt;FONT color=#002c99&gt;Wave Out&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_012" target=_self&gt;&lt;FONT color=#002c99&gt;Wave In&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_013" target=_self&gt;&lt;FONT color=#002c99&gt;Windows&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_014" target=_self&gt;&lt;FONT color=#002c99&gt;Registry&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_015" target=_self&gt;&lt;FONT color=#002c99&gt;Phone&lt;/FONT&gt;&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/PInvokeLib.asp?frame=true#pinvokelib_topic_016" target=_self&gt;&lt;FONT color=#002c99&gt;Folders&lt;/FONT&gt;&lt;/A&gt;&lt;/P&gt;
&lt;H2 class=dtH1&gt;&lt;A name=pinvokelib_topic_001&gt;&lt;/A&gt;Introduction&lt;/H2&gt;
&lt;P&gt;The intent of this sample is to provide a collection of P/Invokes, as well test procedures that demonstrate their application. This sample provides several of the most commonly requested P/Invoke functions as well as a class that handles the enumeration and invoking of the various test procedures. This class is used by a &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Form&lt;/FONT&gt;&lt;/CODE&gt; to allow the user to select and run the tests from a selection list.&lt;/P&gt;
&lt;BLOCKQUOTE class=dtBlock&gt;&lt;B&gt;Note:&lt;/B&gt; For the sake of brevity and to facilitate searches, all function parameters and class definitions have been omitted from code blocks. Refer to the sample for full implementations of all code.&lt;/BLOCKQUOTE&gt;
&lt;H2 class=dtH1&gt;&lt;A name=pinvokelib_topic_002&gt;&lt;/A&gt;The Test Application&lt;/H2&gt;
&lt;P&gt;The test application is comprised of two components, the test application &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Form&lt;/FONT&gt;&lt;/CODE&gt; and the &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;MainTest&lt;/FONT&gt;&lt;/CODE&gt; class. The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Form&lt;/FONT&gt;&lt;/CODE&gt; provides the user with a list of all available tests and allows the user to select and run one or all of the tests with a press of the "Run Test" button. The results of the tests are displayed on the &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Form&lt;/FONT&gt;&lt;/CODE&gt; and can be cleared by pressing the "Clear Results" button.&lt;/P&gt;
&lt;P&gt;The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;MainTest&lt;/FONT&gt;&lt;/CODE&gt; class provides the &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Form&lt;/FONT&gt;&lt;/CODE&gt; with the number and name of all available tests through &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Reflection&lt;/FONT&gt;&lt;/CODE&gt;. All classes defined in the &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Assembly&lt;/FONT&gt;&lt;/CODE&gt; are enumerated and searched for a &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;static&lt;/FONT&gt;&lt;/CODE&gt; method named "&lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;TestProc&lt;/FONT&gt;&lt;/CODE&gt;." If this method is defined for a class then it is considered to be a P/Invoke test and is therefore added to the list. If the user runs a test then &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Reflection&lt;/FONT&gt;&lt;/CODE&gt; is again used to determine the &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;MethodInfo&lt;/FONT&gt;&lt;/CODE&gt; for the &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;TestProc&lt;/FONT&gt;&lt;/CODE&gt; and it is invoked.&lt;/P&gt;
&lt;P&gt;Results from the tests are displayed via a &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;delegate&lt;/FONT&gt;&lt;/CODE&gt; defined to take a &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;string&lt;/FONT&gt;&lt;/CODE&gt;. This &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;delegate&lt;/FONT&gt;&lt;/CODE&gt; is provided by the &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Form&lt;/FONT&gt;&lt;/CODE&gt; to the &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;MainTest&lt;/FONT&gt;&lt;/CODE&gt; constructor and is, in turn, provided to each &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;TestProc&lt;/FONT&gt;&lt;/CODE&gt; method as its only parameter.&lt;/P&gt;
&lt;P&gt;Figure 1 shows a sample of the &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;MemoryStatus&lt;/FONT&gt;&lt;/CODE&gt; test being run.&lt;/P&gt;
&lt;P class=fig&gt;&lt;IMG alt="" src="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/pinvokelib001.jpg" border=0&gt;&lt;/P&gt;
&lt;P class=label&gt;&lt;B&gt;Figure 1. P/Invoke Library Test Application.&lt;/B&gt;&lt;/P&gt;
&lt;H2 class=dtH1&gt;&lt;A name=pinvokelib_topic_003&gt;&lt;/A&gt;Input&lt;/H2&gt;
&lt;P&gt;The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Input&lt;/FONT&gt;&lt;/CODE&gt; class provides the ability to override hardware hot keys and detect button presses regardless of which &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Control&lt;/FONT&gt;&lt;/CODE&gt; has input focus. Figure 2 shows sample output from this test.&lt;/P&gt;
&lt;BLOCKQUOTE class=dtBlock&gt;&lt;B&gt;Note:&lt;/B&gt; Some hardware keys may not be replicated on some emulators, causing this test to wait indefinitely for the proper key to be pressed.&lt;/BLOCKQUOTE&gt;
&lt;P class=fig&gt;&lt;IMG alt="" src="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/pinvokelib002.jpg" border=0&gt;&lt;/P&gt;
&lt;P class=label&gt;&lt;B&gt;Figure 2. Input Test Results.&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;The following functions are implemented in the &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Input&lt;/FONT&gt;&lt;/CODE&gt; class.&lt;/P&gt;&lt;PRE class=code&gt;&lt;B&gt;&lt;I&gt;// C#
&lt;/I&gt;&lt;/B&gt;[DllImport("coredll.dll")]
protected static extern uint RegisterHotKey

[DllImport("coredll.dll")]
protected static extern uint UnregisterFunc1

[DllImport("coredll.dll")]
protected static extern short GetAsyncKeyState

&lt;B&gt;&lt;I&gt;'VB&lt;/I&gt;&lt;/B&gt;
&amp;lt;DllImport("coredll.dll")&amp;gt; 
Protected Shared Function RegisterHotKey

&amp;lt;DllImport("coredll.dll")&amp;gt; 
Protected Shared Function UnregisterFunc1

&amp;lt;DllImport("coredll.dll")&amp;gt; 
Protected Shared Function GetAsyncKeyState&lt;/PRE&gt;
&lt;H2 class=dtH1&gt;&lt;A name=pinvokelib_topic_004&gt;&lt;/A&gt;Memory&lt;/H2&gt;
&lt;P&gt;The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Memory&lt;/FONT&gt;&lt;/CODE&gt; class provides methods for allocating, reallocating, and freeing memory from the heap. Figure 3 shows output from a sample test.&lt;/P&gt;
&lt;P class=fig&gt;&lt;IMG alt="" src="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/pinvokelib003.jpg" border=0&gt;&lt;/P&gt;
&lt;P class=label&gt;&lt;B&gt;Figure 3. Memory Test Results.&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;The following functions are implemented in the &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Memory&lt;/FONT&gt;&lt;/CODE&gt; class.&lt;/P&gt;&lt;PRE class=code&gt;&lt;B&gt;&lt;I&gt;//c#
&lt;/I&gt;&lt;/B&gt;[DllImport("coredll.dll")]
extern public static IntPtr LocalAlloc

[DllImport("coredll.dll")]
extern public static IntPtr LocalFree

[DllImport("coredll.dll")]
extern public static IntPtr LocalReAlloc

&lt;B&gt;&lt;I&gt;'VB&lt;/I&gt;&lt;/B&gt;
&amp;lt;DllImport("coredll.dll")&amp;gt; 
Public Shared Function LocalAlloc 

&amp;lt;DllImport("coredll.dll")&amp;gt; 
Public Shared Function LocalFree 

&amp;lt;DllImport("coredll.dll")&amp;gt; 
Public Shared Function LocalReAlloc &lt;/PRE&gt;
&lt;H2 class=dtH1&gt;&lt;A name=pinvokelib_topic_005&gt;&lt;/A&gt;Memory Status&lt;/H2&gt;
&lt;P&gt;The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;MemoryStatus&lt;/FONT&gt;&lt;/CODE&gt; class provides methods for determining the status of the device's memory. Figure 4 shows sample output from this test.&lt;/P&gt;
&lt;P class=fig&gt;&lt;IMG alt="" src="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/pinvokelib004.jpg" border=0&gt;&lt;/P&gt;
&lt;P class=label&gt;&lt;B&gt;Figure 4. Memory Status Test Results.&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;MemoryStatus&lt;/FONT&gt;&lt;/CODE&gt; class implements the following classes and functions.&lt;/P&gt;&lt;PRE class=code&gt;&lt;B&gt;&lt;I&gt;//C#
&lt;/I&gt;&lt;/B&gt;public class MEMORYSTATUS

[DllImport("CoreDll.dll")]
public static extern void GlobalMemoryStatus

[DllImport("CoreDll.dll")]
public static extern int GetSystemMemoryDivision

&lt;B&gt;&lt;I&gt;'VB&lt;/I&gt;&lt;/B&gt;
Public Class MEMORYSTATUS

&amp;lt;DllImport("CoreDll.dll")&amp;gt; 
Public Shared Sub GlobalMemoryStatus 

&amp;lt;DllImport("CoreDll.dll")&amp;gt; 
Public Shared Function GetSystemMemoryDivision &lt;/PRE&gt;
&lt;H2 class=dtH1&gt;&lt;A name=pinvokelib_topic_006&gt;&lt;/A&gt;Performance Counters&lt;/H2&gt;
&lt;P&gt;The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;PerfCounter&lt;/FONT&gt;&lt;/CODE&gt; class provides methods for accessing the device's performance counters. For more information on Performance Counters, see &lt;A href="http://msdn.microsoft.com/library/en-us/dncfhowto/html/uperfcoun.asp"&gt;&lt;FONT color=#002c99&gt;"HOWTO: Use a Performance Counter"&lt;/FONT&gt;&lt;/A&gt;. Figure 5 shows sample output from the Performance Counter test.&lt;/P&gt;
&lt;P class=fig&gt;&lt;IMG alt="" src="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/pinvokelib005.jpg" border=0&gt;&lt;/P&gt;
&lt;P class=label&gt;&lt;B&gt;Figure 5. Performance Counter Test Results.&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;The following functions are implemented by the &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;PerfCounter&lt;/FONT&gt;&lt;/CODE&gt; class.&lt;/P&gt;&lt;PRE class=code&gt;&lt;B&gt;&lt;I&gt;C#
&lt;/I&gt;&lt;/B&gt;[DllImport("CoreDll.dll")]
public static extern int QueryPerformanceFrequency

[DllImport("CoreDll.dll")]
public static extern int QueryPerformanceCounter

&lt;B&gt;&lt;I&gt;'VB&lt;/I&gt;&lt;/B&gt;
&amp;lt;DllImport("CoreDll.dll")&amp;gt; 
Public Shared Function QueryPerformanceFrequency 

&amp;lt;DllImport("CoreDll.dll")&amp;gt; 
Public Shared Function QueryPerformanceCounter &lt;/PRE&gt;
&lt;H2 class=dtH1&gt;&lt;A name=pinvokelib_topic_007&gt;&lt;/A&gt;Power Status&lt;/H2&gt;
&lt;P&gt;The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;PowerStatus&lt;/FONT&gt;&lt;/CODE&gt; class provides methods for determining the status of the device's power configuration, e.g., batter life, AC line status. For more information on Power Status, see &lt;A href="http://msdn.microsoft.com/library/en-us/dncfhowto/html/getpowstat.asp"&gt;&lt;FONT color=#002c99&gt;"HOWTO: Get the Device Power Status"&lt;/FONT&gt;&lt;/A&gt;. Figure 6 shows sample output from the Power Status test.&lt;/P&gt;
&lt;P class=fig&gt;&lt;IMG alt="" src="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/pinvokelib006.jpg" border=0&gt;&lt;/P&gt;
&lt;P class=label&gt;&lt;B&gt;Figure 6. Power Status Test Results.&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;PowerStatus&lt;/FONT&gt;&lt;/CODE&gt; class implements the following classes and functions.&lt;/P&gt;&lt;PRE class=code&gt;&lt;B&gt;&lt;I&gt;C#
&lt;/I&gt;&lt;/B&gt;public class SYSTEM_POWER_STATUS_EX2

public class SYSTEM_POWER_STATUS_EX

[DllImport("coredll")]
public static extern uint GetSystemPowerStatusEx

[DllImport("coredll")]
public static extern uint GetSystemPowerStatusEx2

&lt;B&gt;&lt;I&gt;'VB&lt;/I&gt;&lt;/B&gt;
Public Class SYSTEM_POWER_STATUS_EX2

Public Class SYSTEM_POWER_STATUS_EX

&amp;lt;DllImport("coredll")&amp;gt;
Public Shared Function GetSystemPowerStatusEx

&amp;lt;DllImport("coredll")&amp;gt;
Public Shared Function GetSystemPowerStatusEx2&lt;/PRE&gt;
&lt;H2 class=dtH1&gt;&lt;A name=pinvokelib_topic_008&gt;&lt;/A&gt;SIP&lt;/H2&gt;
&lt;P&gt;The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;SIP&lt;/FONT&gt;&lt;/CODE&gt; class provides methods for controlling the state of the Software Input Panel. During execution of the test, the SIP is temporarily displayed and then removed. Figure 7 shows sample output from the SIP test.&lt;/P&gt;
&lt;P class=fig&gt;&lt;IMG alt="" src="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/pinvokelib007.jpg" border=0&gt;&lt;/P&gt;
&lt;P class=label&gt;&lt;B&gt;Figure 7. SIP Test Results.&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;SIP&lt;/FONT&gt;&lt;/CODE&gt; class implements the following classes and functions.&lt;/P&gt;&lt;PRE class=code&gt;&lt;B&gt;&lt;I&gt;C#
&lt;/I&gt;&lt;/B&gt;[DllImport("coredll.dll")]
public extern static void SipShowIM

[DllImport("coredll.dll")]
public extern static uint SipStatus();

public struct RECT

public class SIPINFO

[DllImport("coredll.dll")]
public extern static uint SipGetInfo

[DllImport("coredll.dll")]
public extern static uint SipSetInfo

&lt;B&gt;&lt;I&gt;'VB&lt;/I&gt;&lt;/B&gt;
&amp;lt;DllImport("coredll.dll")&amp;gt;
Public Shared Sub SipShowIM

&amp;lt;DllImport("coredll.dll")&amp;gt;
Public Shared Function SipStatus() As Integer

Public Structure RECT

Public Class SIPINFO

&amp;lt;DllImport("coredll.dll")&amp;gt;
Public Shared Function SipGetInfo

&amp;lt;DllImport("coredll.dll")&amp;gt;
Public Shared Function SipSetInfo&lt;/PRE&gt;
&lt;H2 class=dtH1&gt;&lt;A name=pinvokelib_topic_009&gt;&lt;/A&gt;System Reset&lt;/H2&gt;
&lt;P&gt;The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;SystemReset&lt;/FONT&gt;&lt;/CODE&gt; class provides a mechanism for executing kernel IO controls and specifically demonstrates how to soft reset a device. The user is provided with a warning and the chance to back out, as shown in Figure 8.&lt;/P&gt;
&lt;P class=fig&gt;&lt;IMG alt="" src="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/pinvokelib008.jpg" border=0&gt;&lt;/P&gt;
&lt;P class=label&gt;&lt;B&gt;Figure 8. System Reset Test Warning.&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;SystemReset&lt;/FONT&gt;&lt;/CODE&gt; class implements the following function.&lt;/P&gt;&lt;PRE class=code&gt;&lt;B&gt;&lt;I&gt;C#
&lt;/I&gt;&lt;/B&gt;[DllImport("Coredll.dll")]
public extern static uint KernelIoControl

&lt;B&gt;&lt;I&gt;'VB&lt;/I&gt;&lt;/B&gt;
&amp;lt;DllImport("Coredll.dll")&amp;gt;
Public Shared Function KernelIoControl&lt;/PRE&gt;
&lt;H2 class=dtH1&gt;&lt;A name=pinvokelib_topic_010&gt;&lt;/A&gt;System Time&lt;/H2&gt;
&lt;P&gt;The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;SystemTime&lt;/FONT&gt;&lt;/CODE&gt; class provides methods for accessing and setting the system time of the device. The test accesses the time, increments it by one hour, then sets it back to the original. Figure 9 shows sample output from the System Time test.&lt;/P&gt;
&lt;P class=fig&gt;&lt;IMG alt="" src="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/pinvokelib009.jpg" border=0&gt;&lt;/P&gt;
&lt;P class=label&gt;&lt;B&gt;Figure 9. System Time Test Results.&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;SystemTime&lt;/FONT&gt;&lt;/CODE&gt; class implements the following structures and functions.&lt;/P&gt;&lt;PRE class=code&gt;&lt;B&gt;&lt;I&gt;//C#
&lt;/I&gt;&lt;/B&gt;public struct SYSTEMTIME 

[DllImport("coredll.dll")]
public extern static void GetSystemTime

[DllImport("coredll.dll")]
public extern static uint SetSystemTime

&lt;B&gt;&lt;I&gt;'VB&lt;/I&gt;&lt;/B&gt;
Public Structure SYSTEMTIME

&amp;lt;DllImport("coredll.dll")&amp;gt;
Public Shared Sub GetSystemTime

&amp;lt;DllImport("coredll.dll")&amp;gt;
Public Shared Function SetSystemTime&lt;/PRE&gt;
&lt;H2 class=dtH1&gt;&lt;A name=pinvokelib_topic_011&gt;&lt;/A&gt;Wave Out&lt;/H2&gt;
&lt;P&gt;The &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;WaveOut&lt;/FONT&gt;&lt;/CODE&gt; class provides methods and classes for playing a .wav file. Due to the complexity of the Waveform Audio Interface, a &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;WaveFile&lt;/FONT&gt;&lt;/CODE&gt; class is provided which encapsulates all of the functionality required to use the &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;WaveOut&lt;/FONT&gt;&lt;/CODE&gt; P/Invoke functions. This class provides a mechanism for streaming audio via a specified buffer size. For more information on this sample, see the article &lt;A href="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/WaveInOut.asp"&gt;&lt;FONT color=#002c99&gt;"Recording and Playing Sound with the Waveform Audio Interface"&lt;/FONT&gt;&lt;/A&gt;. Figure 10 shows sample output from the Wave Out test.&lt;/P&gt;
&lt;P class=fig&gt;&lt;IMG alt="" src="http://msdn.microsoft.com/library/en-us/dnnetcomp/html/pinvokelib010.jpg" border=0&gt;&lt;/P&gt;
&lt;P class=label&gt;&lt;B&gt;Figure 10. Wave Out Test Results.&lt;/B&gt;&lt;/P&gt;
&lt;BLOCKQUOTE class=dtBlock&gt;&lt;B&gt;Note: &lt;/B&gt;A helper class named &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;Wave&lt;/FONT&gt;&lt;/CODE&gt; is provided as a common interface to the .wav audio format for both the &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;WaveIn&lt;/FONT&gt;&lt;/CODE&gt; and &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;WaveOut&lt;/FONT&gt;&lt;/CODE&gt; classes.&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The following classes and functions are implemented in the &lt;CODE class=ce&gt;&lt;FONT face=新宋体&gt;WaveOut&lt;/FONT&gt;&lt;/CODE&gt; class.&lt;/P&gt;&lt;PRE class=code&gt;&lt;B&gt;&lt;I&gt;//C#
&lt;/I&gt;&lt;/B&gt;[DllImport ("coredll.dll")]
protected static extern int waveOutGetNumDevs();

[DllImport ("coredll.dll")]
private static extern Wave.MMSYSERR waveOutOpen

[DllImport ("coredll.dll")]
protected static extern Wave.MMSYSERR waveOutGetVolume

[DllImport ("coredll.dll")]
protected static extern Wave.MMSYSERR waveOutSetVolume

[DllImport ("coredll.dll")]
private static extern Wave.MMSYSERR waveOutPrepareHeader

[DllImport ("coredll.dll")]
private static extern Wave.MMSYSERR waveOutWrite

[DllImport ("coredll.dll")]
private static extern Wave.MMSYSERR waveOutUnprepareHeader

[DllImport ("coredll.dll")]
protected static extern Wave.MMSYSERR waveOutClose

[DllImport ("coredll.dll")]
protected static extern Wave.MMSYSERR waveOutReset

[DllImport ("coredll.dll")]
protected static extern Wave.MMSYSERR waveOutPause

[DllImport ("coredll.dll")]
protected static extern Wave.MMSYSERR waveOutRestart

protected class MMTIME

[DllImport ("coredll.dll")]
protected static extern Wave.MMSYSERR waveOutGetPosition

protected class WAVEOUTCAPS

[DllImport ("coredll.dll")]
protected static extern Wave.MMSYSERR waveOutGetDevCaps

&lt;B&gt;&lt;I&gt;'VB&lt;/I&gt;&lt;/B&gt;
&amp;lt;DllImport("coredll.dll")&amp;gt;
Protected Shared Function waveOutGetNumDevs() As Integer

&amp;lt;DllImport("coredll.dll")&amp;gt;
Private Shared Function waveOutOpen

&amp;lt;DllImport("coredll.dll")&amp;gt;
Protected Shared Function waveOutGetVolume

&amp;lt;DllImport("coredll.dll")&amp;gt;
Protected Shared Function waveOutSetVolume

&amp;lt;DllImport("coredll.dll")&amp;gt;
Private Shared Function waveOutPrepareHeader

&amp;lt;DllImport("coredll.dll")&amp;gt;
Private Shared Function waveOutWrite

&amp;lt;DllImport("coredll.dll")&amp;gt;
Private Shared Function waveOutUnprepareHeader

&amp;lt;DllImport("coredll.dll")&amp;gt;
Protected Shared Func