﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><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>C++博客-井泉</title><link>http://www.cppblog.com/zjj2816/</link><description /><language>zh-cn</language><lastBuildDate>Wed, 08 Apr 2026 15:34:39 GMT</lastBuildDate><pubDate>Wed, 08 Apr 2026 15:34:39 GMT</pubDate><ttl>60</ttl><item><title>Write HBITMAP Object in to BMP File 转</title><link>http://www.cppblog.com/zjj2816/archive/2009/02/16/73921.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Mon, 16 Feb 2009 03:32:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2009/02/16/73921.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/73921.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2009/02/16/73921.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/73921.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/73921.html</trackback:ping><description><![CDATA[<font face=Arial size=2>void WriteBMPFile(HBITMAP bitmap, LPTSTR filename, HDC hDC)<br>{<br>BITMAP bmp; <br>PBITMAPINFO pbmi; <br>WORD cClrBits; <br>HANDLE hf; // file handle <br>BITMAPFILEHEADER hdr; // bitmap file-header <br>PBITMAPINFOHEADER pbih; // bitmap info-header <br>LPBYTE lpBits; // memory pointer <br>DWORD dwTotal; // total count of bytes <br>DWORD cb; // incremental count of bytes <br>BYTE *hp; // byte pointer <br>DWORD dwTmp; <br><br>// create the bitmapinfo header information<br><br>if (!GetObject( (bitmap, sizeof(BITMAP), (LPSTR)&amp;bmp)){<br>AfxMessageBox("Could not retrieve bitmap info");<br>return;<br>}<br><br>// Convert the color format to a count of bits. <br>cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); <br>if (cClrBits == 1) <br>cClrBits = 1; <br>else if (cClrBits &lt;= 4) <br>cClrBits = 4; <br>else if (cClrBits &lt;= 8) <br>cClrBits = 8; <br>else if (cClrBits &lt;= 16) <br>cClrBits = 16; <br>else if (cClrBits &lt;= 24) <br>cClrBits = 24; <br>else cClrBits = 32; </font><br><font face=Arial size=2>// Allocate memory for the BITMAPINFO structure.<br>if (cClrBits != 24) <br>pbmi = (PBITMAPINFO) LocalAlloc(LPTR, <br>sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1&lt;&lt; cClrBits)); <br>else <br>pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER)); <br><br>// Initialize the fields in the BITMAPINFO structure. <br><br>pbmi-&gt;bmiHeader.biSize = sizeof(BITMAPINFOHEADER); <br>pbmi-&gt;bmiHeader.biWidth = bmp.bmWidth; <br>pbmi-&gt;bmiHeader.biHeight = bmp.bmHeight; <br>pbmi-&gt;bmiHeader.biPlanes = bmp.bmPlanes; <br>pbmi-&gt;bmiHeader.biBitCount = bmp.bmBitsPixel; <br>if (cClrBits &lt; 24) <br>pbmi-&gt;bmiHeader.biClrUsed = (1&lt;&lt;cClrBits); <br><br>// If the bitmap is not compressed, set the BI_RGB flag. <br>pbmi-&gt;bmiHeader.biCompression = BI_RGB; <br><br>// Compute the number of bytes in the array of color <br>// indices and store the result in biSizeImage. <br>pbmi-&gt;bmiHeader.biSizeImage = (pbmi-&gt;bmiHeader.biWidth + 7) /8 * pbmi-&gt;bmiHeader.biHeight * cClrBits; <br>// Set biClrImportant to 0, indicating that all of the <br>// device colors are important. <br>pbmi-&gt;bmiHeader.biClrImportant = 0; <br><br>// now open file and save the data<br>pbih = (PBITMAPINFOHEADER) pbmi; <br>lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih-&gt;biSizeImage);<br><br>if (!lpBits) {<br>AfxMessageBox("writeBMP::Could not allocate memory");<br>return;<br>}<br><br>// Retrieve the color table (RGBQUAD array) and the bits <br>if (!GetDIBits(hDC, HBITMAP(bitmap), 0, (WORD) pbih-&gt;biHeight, lpBits, pbmi, <br>DIB_RGB_COLORS)) {<br>AfxMessageBox("writeBMP::GetDIB error");<br>return;<br>}<br><br>// Create the .BMP file. <br>hf = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, (DWORD) 0, <br>NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, <br>(HANDLE) NULL); <br>if (hf == INVALID_HANDLE_VALUE){<br>AfxMessageBox("Could not create file for writing");<br>return;<br>}<br>hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M" <br>// Compute the size of the entire file. <br>hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + <br>pbih-&gt;biSize + pbih-&gt;biClrUsed <br>* sizeof(RGBQUAD) + pbih-&gt;biSizeImage); <br>hdr.bfReserved1 = 0; <br>hdr.bfReserved2 = 0; <br><br>// Compute the offset to the array of color indices. <br>hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + <br>pbih-&gt;biSize + pbih-&gt;biClrUsed <br>* sizeof (RGBQUAD); <br><br>// Copy the BITMAPFILEHEADER into the .BMP file. <br>if (!WriteFile(hf, (LPVOID) &amp;hdr, sizeof(BITMAPFILEHEADER), <br>(LPDWORD) &amp;dwTmp, NULL)) {<br>AfxMessageBox("Could not write in to file");<br>return;<br>}<br><br>// Copy the BITMAPINFOHEADER and RGBQUAD array into the file. <br>if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER) <br>+ pbih-&gt;biClrUsed * sizeof (RGBQUAD), <br>(LPDWORD) &amp;dwTmp, ( NULL))){<br>AfxMessageBox("Could not write in to file");<br>return;<br>}<br><br><br>// Copy the array of color indices into the .BMP file. <br>dwTotal = cb = pbih-&gt;biSizeImage; <br>hp = lpBits; <br>if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &amp;dwTmp,NULL)){<br>AfxMessageBox("Could not write in to file");<br>return;<br>}<br><br>// Close the .BMP file. <br>if (!CloseHandle(hf)){<br>AfxMessageBox("Could not close file");<br>return;<br>}<br><br>// Free memory. <br>GlobalFree((HGLOBAL)lpBits);<br>}</font>
<img src ="http://www.cppblog.com/zjj2816/aggbug/73921.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2009-02-16 11:32 <a href="http://www.cppblog.com/zjj2816/archive/2009/02/16/73921.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用VS2008 Feature Pack 修改您现有的Visual C++的程序界面 转</title><link>http://www.cppblog.com/zjj2816/archive/2009/01/09/71593.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Fri, 09 Jan 2009 05:51:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2009/01/09/71593.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/71593.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2009/01/09/71593.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/71593.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/71593.html</trackback:ping><description><![CDATA[上次给大家介绍了Visual C++ 2008 的Feature Pack的界面库新特性。今天给大家介绍一下，怎样用Feature Pack把您现有的Visual C++ 程序界面修改得漂亮些。<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;所需的修改环境：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Visual&nbsp;C++ 2008&nbsp; (Team Suite版Express版都可以，但必须是英文版，否则Feature Pack不支持)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 正确的安装了Visual C++ 2008 Feature Pack beta<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 您要修改的Visual C++ 的程序源代码工程<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;具备了以上三点就可以开始进行修改操作了。但是有一点提请注意，那就是您程序中是否用到了MS C++ 9.0
编译器不再支持的语法特性？如果有，那很不幸，我个人不推荐您升级您的程序界面，毕竟程序运行的稳定性才是最重要的。为了漂亮的界面修改已经测试过并稳定
运行的代码，可不是一个明智的选择。<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面我就用一个Visual C++的入门Demo&nbsp;<a  href="http://msdn2.microsoft.com/zh-cn/library/f35t8fts.aspx" target="_blank">Scribble</a> 来修改。这个Scribble您可以在MSDN网站上下载到，但请您注意，我给出的这个下载工程是VS2005 for x64的。下载后，您需要进行以下改动：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1) 将Scribble工程属性中，C/C++编译器的Treat Warnings as error 关闭，否则您的工程将会因为一个Warning没有解决，导致整个程序编译失败。如图：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <img  src="http://images.cnblogs.com/cnblogs_com/michaellee/disable_WX.jpg" alt="" border="0" height="530" width="762"><br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2) 编译时，将Target 改为Win32;<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;罗嗦了这么多，开始修改吧！<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第一步: 请确定CScribbleApp::InitialInstance() 方法中已经调用了AfxOleInit();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第二步: 在stdafx.h文件中加入 #include"afxcontrolbars.h" ,这头文件包含了Feature Pack新增的界面类声明;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第三步：修改CScribbleApp类继承的父类，由CWinApp改为CWinAppEx;这个CWinAppEx类比CWinApp添
加了很多的功能，说个简单的，CWinAppEx提供了一个SetRegistryBase方法，这个方法可以用来设定当前App所使用的注册表的根。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
第四步：修改主框架类，将CMainFrame的父类由CMDIFrameWnd改为CMDIFrameWndEx;这个修改设计到类声明、
IMPLEMENT_DYNAMIC宏、MESSAGE_MAP宏、OnCreate函数等调用到静态方法的地方、以及其它等等。最好是直接用
Replace all文本替换掉;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第五步：将CMDIChildWnd类替换为CMDIChildWndEx,主框架换了，子窗体也要换;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第六步：替换CTooBar为CMFCTooBar，替换CStatusBar为CMFCStatusBar;就是修改一下m_wndStatusBar和m_wndToolBar两个变量的声明处;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第七步：替换CMainFrame::OnCreate()函数中m_wndToolBar
和m_wndStatusBar停靠的相关代码;将Set/Get BarStyle改为Set/Get PaneStyle
也是文本替换一下，很简单。将DockControlBar(&amp;m_wndStatusBar);改为
DockPane(&amp;m_wndStatusBar);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 完成以上七步,基本改造就算完成了。但是如果您现在编译您的程序，您会发现Scribble界面基本上没有任何改变。下面的才是更重要的，我们要添加RibbonBar了：<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第一步：在CMainFrame类中声明一个CMFCRibbonBar类型的变量m_wndRibbonBar。这个变量就代表Office2007界面里面那个替代了菜单的东东;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第二步：在CMainFrame类中声明一个CMFCRibbonApplicationButton的变量m_MainButton。这个变量代表了Office2007界面左上角那个Home按钮;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第三步：在CMainFrame::OnCreate函数中添加代码。首先是创建RibbonBar对象，老规矩：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!m_wndRibbonBar.Create(this))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return -1;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第四步：设定m_MainButton对象：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_MainButton.SetImage(&#8230;&#8230;);&nbsp;&nbsp; //设定图标<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_MainButton.SetToolTipText(&#8230;&#8230;); //设定提示文本<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_MainButton.SetText(&#8230;&#8230;);&nbsp;&nbsp;&nbsp;//设定按钮文本<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第五步：在CMainFrame::OnCreate函数中添加代码，通过RibbonBar对象添加一个Category:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CMFCRibbonMainPanel *pMainPanel = m_wndRibbonBar.AddMainCategory(_T("File"));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这实际上就类似于创建了一个名为File的主菜单项;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第六步：给这个Panel添加按钮(其实就是子菜单项)：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pMainPanel-&gt;Add(new CMFCRibbonButton(ID_FILE_OPEN,_T("打开")));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8230;&#8230;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第七步：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在CMainFrame::OnCreate()函数的最后部分,添加代码设定当前界面的风格：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007Luna_Blue);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 代码的第一行用来设定可视化管理器为Office2007类型，可供选择的还有OfficXP、Office2003、VS2005
三种,换句话说，我们可以将我们的程序界面修改为Office2007、Office2003、OfficeXP、VS2005四种风格;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 代码的第二行用来设定Office2007界面的色调;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 完成以上步骤后，就可以编译运行啦，看看界面是不是改变了呢？<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 修改前：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <img  src="http://images.cnblogs.com/cnblogs_com/michaellee/Scribble1.jpg" alt="" border="0" height="484" width="702"><br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 修改后：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img  src="http://images.cnblogs.com/cnblogs_com/michaellee/Scribble2.jpg" alt="" border="0" height="486" width="705"><br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我没有找到比较好看的图标，也没有把菜单都实现出来，仅仅是作为一个演示。相信在美工的帮助下，我们的MFC程序界面一定会漂亮起来的。<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说到最后，我要提醒大家一下，发布程序前，已经要静态链接MFC的库。在现在VC8.0
的RTM尚不普及的情况下，就别指望您的用户安装部署了支持Feature
Packe的FTM库了。粗粗看了一下，一个用向导生成的支持Feature Pack的Application(是的，安装了Feature
Pack在用AppWizard生新程序的时候,就可以指定Feature
Pack支持了)，什么代码都不加，静态编译一般在6M-8M之间(还算可以接受的说)。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img  src="http://images.cnblogs.com/cnblogs_com/michaellee/Scribble_3.jpg" alt="" border="0" height="530" width="761"><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src ="http://www.cppblog.com/zjj2816/aggbug/71593.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2009-01-09 13:51 <a href="http://www.cppblog.com/zjj2816/archive/2009/01/09/71593.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>.net制作的wap网站在手机中的测试 转</title><link>http://www.cppblog.com/zjj2816/archive/2008/12/31/70830.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Wed, 31 Dec 2008 02:46:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2008/12/31/70830.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/70830.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2008/12/31/70830.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/70830.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/70830.html</trackback:ping><description><![CDATA[<p style="text-align: left;">访问asp站点的时候会根据访问的设备,输出不同的内容,如果用IE访问就输出的是html,手机访问,输出就是WML。是什么让他这么智能化呢？关键之处就在配置文件的<span style="color: #0000ff;">&lt;</span><span style="color: #800000;">browserCaps</span><span style="color: #0000ff;">&gt;节！</span></p>
<p style="text-align: left;"><span style="color: #0000ff;">在webconfig中加上这个，他可以强制输出wml，还有其他的移动设置属性都在这。</span></p>
<p style="text-align: left;"><span style="color: #0000ff;"><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">browserCaps</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">result&nbsp;</span><span style="color: #ff0000;">type</span><span style="color: #0000ff;">="System.Web.Mobile.MobileCapabilities,&nbsp;System.Web.Mobile,&nbsp;Version=1.0.5000.0,&nbsp;Culture=neutral,&nbsp;PublicKeyToken=b03f5f7f11d50a3a"</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">use&nbsp;</span><span style="color: #ff0000;">var</span><span style="color: #0000ff;">="HTTP_USER_AGENT"</span><span style="color: #0000ff;">/&gt;</span><span style="color: #000000;"><br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11"><br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;browser=Unknown<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;version=0.0<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;majorversion=0<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;minorversion=0<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;frames=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tables=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cookies=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;backgroundsounds=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vbscript=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;javascript=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;javaapplets=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;activexcontrols=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;win16=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;win32=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;beta=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ak=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sk=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;aol=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;crawler=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cdf=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gold=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;authenticodeupdate=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tagwriter=System.Web.UI.Html32TextWriter<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ecmascriptversion=0.0<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;msdomversion=0.0<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;w3cdomversion=0.0<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;platform=Unknown<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;css1=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;css2=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xml=false<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11"><br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mobileDeviceManufacturer&nbsp;=&nbsp;"Unknown"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mobileDeviceModel&nbsp;=&nbsp;"Unknown"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11"><br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gatewayVersion&nbsp;=&nbsp;"None"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gatewayMajorVersion&nbsp;=&nbsp;"0"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gatewayMinorVersion&nbsp;=&nbsp;"0"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11"><br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;preferredRenderingType&nbsp;=&nbsp;"wml11"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;preferredRenderingMime&nbsp;=&nbsp;"text/vnd.wap.wml"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;preferredImageMime&nbsp;=&nbsp;"image/vnd.wap.wbmp"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11"><br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;defaultScreenCharactersWidth&nbsp;=&nbsp;"12"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;defaultScreenCharactersHeight&nbsp;=&nbsp;"6"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;defaultScreenPixelsWidth&nbsp;=&nbsp;"96"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;defaultScreenPixelsHeight&nbsp;=&nbsp;"72"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;defaultCharacterWidth&nbsp;=&nbsp;"8"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;defaultCharacterHeight&nbsp;=&nbsp;"12"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;screenBitDepth&nbsp;=&nbsp;"1"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isColor&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inputType&nbsp;=&nbsp;"telephoneKeypad"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11"><br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;numberOfSoftkeys&nbsp;=&nbsp;"0"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maximumSoftkeyLabelLength&nbsp;=&nbsp;"5"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11"><br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;canInitiateVoiceCall&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11"><br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;canSendMail&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hasBackButton&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rendersWmlDoAcceptsInline&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rendersWmlSelectsAsMenuCards&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rendersBreaksAfterWmlAnchor&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rendersBreaksAfterWmlInput&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rendersBreakBeforeWmlSelectAndInput&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiresAttributeColonSubstitution&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiresPhoneNumbersAsPlainText&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiresUrlEncodedPostfieldValues&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiredMetaTagNameValue&nbsp;=&nbsp;""<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rendersBreaksAfterHtmlLists&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiresUniqueHtmlCheckboxNames&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiresUniqueHtmlInputNames&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiresUniqueFilePathSuffix&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsCss&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hidesRightAlignedMultiselectScrollbars&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;canRenderAfterInputOrSelectElement&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;canRenderInputAndSelectElementsTogether&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;canRenderOneventAndPrevElementsTogether&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;canCombineFormsInDeck&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;canRenderMixedSelects&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;canRenderPostBackCards&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;canRenderSetvarZeroWithMultiSelectionList&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsImageSubmit&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsSelectMultiple&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiresHtmlAdaptiveErrorReporting&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiresContentTypeMetaTag&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiresDBCSCharacter&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiresOutputOptimization&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsAccesskeyAttribute&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsInputIStyle&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsInputMode&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsIModeSymbols&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsJPhoneSymbols&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsJPhoneMultiMediaAttributes&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maximumRenderedPageSize&nbsp;=&nbsp;"2000"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiresSpecialViewStateEncoding&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiresNoBreakInFormatting&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiresLeadingPageBreak&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsQueryStringInFormAction&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsCacheControlMetaTag&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsUncheck&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;canRenderEmptySelects&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsRedirectWithCookie&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsEmptyStringInCookieValue&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cachesAllResponsesWithExpires&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;requiresNoSoftkeyLabels&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;defaultSubmitButtonLimit&nbsp;=&nbsp;"1"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsBold&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsItalic&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsFontSize&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsFontName&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsFontColor&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsBodyColor&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsDivAlign&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsDivNoWrap&nbsp;=&nbsp;"false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;supportsCharacterEntityEncoding&nbsp;=&nbsp;"true"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11"><br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isMobileDevice="false"<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11"></span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">browserCaps</span><span style="color: #0000ff;">&gt;</span>&nbsp;</span><span style="color: #000000;"><br>
</span>另外通过设置<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Page.Response.Expires&nbsp;<span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br>
<img  src="http://www.aspxclub.com/UploadFile/Material/1/3974.gif" alt="" align="top" height="16" width="11">&nbsp;&nbsp;&nbsp;Response.CacheControl&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Public</span><span style="color: #000000;">"</span><span style="color: #000000;">;</span> <br>
可以<strong>取消移动设备缓存，并通过</strong>RedirectToMobilePage函数进行重定向。</p><img src ="http://www.cppblog.com/zjj2816/aggbug/70830.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2008-12-31 10:46 <a href="http://www.cppblog.com/zjj2816/archive/2008/12/31/70830.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WINCE Driver and BSP Develop Blog 转</title><link>http://www.cppblog.com/zjj2816/archive/2008/12/24/70243.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Wed, 24 Dec 2008 07:12:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2008/12/24/70243.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/70243.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2008/12/24/70243.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/70243.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/70243.html</trackback:ping><description><![CDATA[<h3 class="post-title">
开发优秀的驱动程序
</h3>
<div class="post-body">
<div>
<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">作为驱动开发工程师</span><span lang="EN-US">,</span><span style="font-family: 宋体;">我们需要在每一行代码上下功夫</span><span lang="EN-US">,</span><span style="font-family: 宋体;">因为驱动程序的效率直接影响着系统的性能</span><span lang="EN-US">.</span><span style="font-family: 宋体;">而新手往往不会注意到这些细节。以为功能实现以后就万事大吉了，其实不然，好的驱动程序不只是能实现预期的功能。它同样需要高的效率与规范的风格。用户花钱买我们系统是给他</span><span lang="EN-US">/</span><span style="font-family: 宋体;">她做事的，而不是给我们做测试的，所以我们要尽可能提高效率。同时好的代码风格能大大降低我们自己的维护成本。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>       </span></span><span style="font-family: 宋体;">高效率看似容易，但要注意到每个细节还是挺难的，我们可以从以下几点去注意这个问题：</span></p>
<p class="MsoNormal" style="margin-left: 18pt; text-indent: -18pt;"><!--[if !supportLists]--><span lang="EN-US"><span>1，<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">  </span></span></span><!--[endif]--><span style="font-family: 宋体;">不要使用无关的代码，这点容易理解，尤其是调试代码，</span><span lang="EN-US">RELEASE</span><span style="font-family: 宋体;">时一定要去除这些代码。</span></p>
<p class="MsoNormal" style="margin-left: 18pt; text-indent: -18pt;"><!--[if !supportLists]--><span lang="EN-US"><span>2，<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">  </span></span></span><!--[endif]--><span style="font-family: 宋体;">去掉多余的函数调用，尽可能的保存一些数据。即使是最快的函数，调用它时也会引发压栈与出栈，所以要尽量少做函数调用。当然如果一个函数返回的数据比较大，保存那些数据将占用比较多的内在空间，保存返回值就得不偿失了。比如，看到有的人每次在使用一个地址时就调用</span><span lang="EN-US">MmmapIoSpace</span><span style="font-family: 宋体;">将这个地址映射到程序地址空间，用完以后又立即</span><span lang="EN-US">Unmap</span><span style="font-family: 宋体;">这个地址，下次使用时又做</span><span lang="EN-US">MAP</span><span style="font-family: 宋体;">，这就是一种及不好的方法，每次需要多调用两个系统函数。</span></p>
<p class="MsoNormal"><span lang="EN-US">3</span><span style="font-family: 宋体;">．如果可行，不要在循环中使用条件判断，尤其在一个次数很多的循环中更应该如此。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>   </span></span><span style="font-family: 宋体;">比如：</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US">For( i=0; i&lt;1000;&gt;</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US"><span>       </span>If( m==1)<span>  </span>..</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US"><span>    </span>Else if (m==2 )&#8230;.</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US"><span>    </span>Else &#8230;..</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US">}</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>       </span></span><span style="font-family: 宋体;">这种代码，我们可以把</span><span lang="EN-US">If </span><span style="font-family: 宋体;">写在</span><span lang="EN-US">for </span><span style="font-family: 宋体;">之外，即，每一种不同的条件写一个循环体。</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US"><span>       </span>If( m==1)<span>  </span>for ...</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US"><span>    </span>Else if (m==2 )<span>  </span>for &#8230;.</span></p>
<p class="MsoNormal" style="text-indent: 21.75pt;"><span lang="EN-US"><span>    </span>Else<span>  </span>for &#8230;..</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="blogger-labels">标签： <a  href="http://winceblog.blogspot.com/search/label/%E7%A8%8B%E5%BA%8F%E6%8A%80%E5%B7%A7" rel="tag">程序技巧</a></p>
</div>
</div>
<p class="post-footer">
<em>张贴者：Blog by Braden @ <a  href="http://winceblog.blogspot.com/2007/05/blog-post.html" title="permanent link">5/07/2007 07:56:00 上午</a></em> &nbsp;
<a  href="https://www.blogger.com/comment.g?blogID=37724268&amp;postID=1038057089695710244" class="comment-link" location.href="https://www.blogger.com/comment.g?blogID=37724268&amp;postID=1038057089695710244;"><span style="text-transform: lowercase;">0 条评论</span></a>
<a  href="http://winceblog.blogspot.com/2007/05/blog-post.html#links" class="comment-link"><span style="text-transform: lowercase;">指向此帖子的链接</span></a>
<span class="item-action"><a  href="http://www.blogger.com/email-post.g?blogID=37724268&amp;postID=1038057089695710244" title="以电子邮件发送帖子"><img  src="http://www.blogger.com/img/icon18_email.gif" class="icon-action" alt="" height="13" width="18"></a></span><span class="item-control blog-admin pid-2106978906"><a  href="http://www.blogger.com/post-edit.g?blogID=37724268&amp;postID=1038057089695710244" style="border: medium none ;" title="修改帖子"><img  src="http://www.blogger.com/img/icon18_edit_allbkg.gif" class="icon-action" alt="" height="18" width="18"></a></span>
</p>
<!-- End .post -->
<!-- Begin #comments -->
<!-- End #comments -->
<h2 class="date-header">2007-03-10</h2>
<!-- Begin .post -->
<div class="post"><a name="216214469836542308"></a>
<h3 class="post-title">
开发DMA驱动
</h3>
<div class="post-body">
<div>
<span lang="EN-US"><span>       </span></span><span style="font-family: 宋体;">使用</span><span lang="EN-US">DMA</span><span style="font-family: 宋体;">的好处就是它不需要</span><span lang="EN-US">CPU</span><span style="font-family: 宋体;">的干预而直接服务外设，这样</span><span lang="EN-US">CPU</span><span style="font-family: 宋体;">就可以去处理别的事务，从而提高系统的效率，对于慢速设备，如</span><span lang="EN-US">UART</span><span style="font-family: 宋体;">，其作用只是降低</span><span lang="EN-US">CPU</span><span style="font-family: 宋体;">的使用率，但对于高速设备，如硬盘，它不只是降低</span><span lang="EN-US">CPU</span><span style="font-family: 宋体;">的使用率，而且能大大提高硬件设备的吞吐量。因为对于这种设备，</span><span lang="EN-US">CPU</span><span style="font-family: 宋体;">直接供应数据的速度太低。</span>
<p class="MsoNormal"><span lang="EN-US"><span>       </span></span><span style="font-family: 宋体;">因</span><span lang="EN-US">CPU</span><span style="font-family: 宋体;">只能一个总线周期最多存取一次总线，而且对于</span><span lang="EN-US">ARM</span><span style="font-family: 宋体;">，它不能把内存中</span><span lang="EN-US">A</span><span style="font-family: 宋体;">地址的值直接搬到</span><span lang="EN-US">B</span><span style="font-family: 宋体;">地址。它只能先把</span><span lang="EN-US">A</span><span style="font-family: 宋体;">地址的值搬到一个寄存器，然后再从这个寄存器搬到</span><span lang="EN-US">B</span><span style="font-family: 宋体;">地址。也就是说，对于</span><span lang="EN-US">ARM</span><span style="font-family: 宋体;">，要花费两个总线周期才能将</span><span lang="EN-US">A</span><span style="font-family: 宋体;">地址的值送到</span><span lang="EN-US">B</span><span style="font-family: 宋体;">地址。而</span><span lang="EN-US">DMA</span><span style="font-family: 宋体;">就不同了，一般系统中的</span><span lang="EN-US">DMA</span><span style="font-family: 宋体;">都有突发（</span><span lang="EN-US">Burst</span><span style="font-family: 宋体;">）传输的能力，在这种模式下，</span><span lang="EN-US">DMA</span><span style="font-family: 宋体;">能一次传输几个甚至几十个字节的数据，所以使用</span><span lang="EN-US">DMA</span><span style="font-family: 宋体;">能使设备的吞吐能力大为增强。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>       </span></span><span style="font-family: 宋体;">使用</span><span lang="EN-US">DMA</span><span style="font-family: 宋体;">时我们必须要注意如下事实：</span></p>
<p class="MsoNormal" style="margin-left: 18pt; text-indent: -18pt;"><!--[if !supportLists]--><span lang="EN-US"><span>1．<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">  </span></span></span><!--[endif]--><span lang="EN-US">DMA</span><span style="font-family: 宋体;">使用物理地址，程序是使用虚拟地址的，所以配置</span><span lang="EN-US">DMA</span><span style="font-family: 宋体;">时必须将虚拟地址转化成物理地址。</span></p>
<p class="MsoNormal" style="margin-left: 18pt; text-indent: -18pt;"><!--[if !supportLists]--><span lang="EN-US"><span>2．<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">  </span></span></span><!--[endif]--><span style="font-family: 宋体;">因为程序使用虚拟地址，而且一般使用</span><span lang="EN-US">CACHED</span><span style="font-family: 宋体;">地址，所以虚拟地址中的内容与其物理地址上的内容不一定一致辞，所以在启动</span><span lang="EN-US">DMA</span><span style="font-family: 宋体;">传输之前一定要将该地址的</span><span lang="EN-US">CACHE</span><span style="font-family: 宋体;">刷新，即写入内存。</span></p>
<p class="MsoNormal" style="margin-left: 18pt; text-indent: -18pt;"><!--[if !supportLists]--><span lang="EN-US"><span>3．<span style="font-family: &quot;Times New Roman&quot;; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">  </span></span></span><!--[endif]--><span lang="EN-US">OS</span><span style="font-family: 宋体;">并不能保证每次分配到的内在空间在物理上是连续的。尤其是在系统使用过一段时间而又分配了一块比较大的内存时。</span></p>
<p class="MsoNormal" style="margin-left: 18pt;"><span style="font-family: 宋体;">所以每次都需要判断地址是不是连续的，如果不连续就需要把这段内存分成几段让</span><span lang="EN-US">DMA</span><span style="font-family: 宋体;">完成传输。</span></p>
<p class="MsoNormal" style="margin-left: 18pt;"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="blogger-labels">标签： <a  href="http://winceblog.blogspot.com/search/label/BaseKnowledge" rel="tag">BaseKnowledge</a></p>
</div>
</div>
<p class="post-footer">
<em>张贴者：Blog by Braden @ <a  href="http://winceblog.blogspot.com/2007/03/dma.html" title="permanent link">3/10/2007 09:44:00 下午</a></em> &nbsp;
<a  href="https://www.blogger.com/comment.g?blogID=37724268&amp;postID=216214469836542308" class="comment-link" location.href="https://www.blogger.com/comment.g?blogID=37724268&amp;postID=216214469836542308;"><span style="text-transform: lowercase;">0 条评论</span></a>
<a  href="http://winceblog.blogspot.com/2007/03/dma.html#links" class="comment-link"><span style="text-transform: lowercase;">指向此帖子的链接</span></a>
<span class="item-action"><a  href="http://www.blogger.com/email-post.g?blogID=37724268&amp;postID=216214469836542308" title="以电子邮件发送帖子"><img  src="http://www.blogger.com/img/icon18_email.gif" class="icon-action" alt="" height="13" width="18"></a></span><span class="item-control blog-admin pid-2106978906"><a  href="http://www.blogger.com/post-edit.g?blogID=37724268&amp;postID=216214469836542308" style="border: medium none ;" title="修改帖子"><img  src="http://www.blogger.com/img/icon18_edit_allbkg.gif" class="icon-action" alt="" height="18" width="18"></a></span>
</p>
</div>
<!-- End .post -->
<!-- Begin #comments -->
<!-- End #comments -->
<h2 class="date-header">2007-03-03</h2>
<!-- Begin .post -->
<div class="post"><a name="5156944094587713279"></a>
<h3 class="post-title">
WINCE下USBFN驱动程序的一些概念
</h3>
<div class="post-body">
<div>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">USBFN</span><span style="font-family: 宋体;">，即</span><span lang="EN-US">USB</span><span style="font-family: 宋体;">客户端驱动，用来将一个</span><span lang="EN-US">WINCE</span><span style="font-family: 宋体;">设备模拟成一定的</span><span lang="EN-US">USB</span><span style="font-family: 宋体;">设备，让主机端（如</span><span lang="EN-US">PC</span><span style="font-family: 宋体;">）访问。目前</span><span lang="EN-US">WINCE</span><span style="font-family: 宋体;">提供的</span><span lang="EN-US">USB</span><span style="font-family: 宋体;">客户端有存储设备，串口设备，及</span><span lang="EN-US">RNDIS</span><span style="font-family: 宋体;">网络接口设备。</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal" style="text-indent: 21pt;"><span style="font-family: 宋体;">存储设备用来将</span><span lang="EN-US">WINCE</span><span style="font-family: 宋体;">设备上的存储空间，例如</span><span lang="EN-US">FLASH</span><span style="font-family: 宋体;">，当作一块存储介质给主机访问，即将</span><span lang="EN-US">WINCE</span><span style="font-family: 宋体;">设备模拟成一个</span><span lang="EN-US">U</span><span style="font-family: 宋体;">盘。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>       </span></span><span style="font-family: 宋体;">串口设备将设备与主机的</span><span lang="EN-US">USB</span><span style="font-family: 宋体;">连线模拟成串口，</span><span lang="EN-US">WINCE</span><span style="font-family: 宋体;">和主机端都认为它们之前连接上了一根串口线，它们之间可以做串口通信，典型的应用是用来实现</span><span lang="EN-US">WINCE</span><span style="font-family: 宋体;">与</span><span lang="EN-US">PC</span><span style="font-family: 宋体;">机的同步连接。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>       </span>RNDIS</span><span style="font-family: 宋体;">设备使两端认为它们之间建立了网络连接，通过注册表设置可以让主机通过</span><span lang="EN-US">WINCE</span><span style="font-family: 宋体;">设备上网或者使</span><span lang="EN-US">WINCE</span><span style="font-family: 宋体;">设备通过主机上网。</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><span>       </span>WINCE</span><span style="font-family: 宋体;">已经提供了以上三种设备的驱动程序，在同一时刻只能使用一个设备。而我们需要做的只是提供</span><span lang="EN-US">USBFN</span><span style="font-family: 宋体;">总线控制器的驱动程序。</span><span lang="EN-US">USBFN</span><span style="font-family: 宋体;">系统各个模块的关系如下：</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>       </span>USBFN</span><span style="font-family: 宋体;">总路线控制器作为一个总线驱动程序，被设备管理器加载，根据注册表设置加载相应的客户驱动程序，即存储设备，串口设备或者</span><span lang="EN-US">RNDIS</span><span style="font-family: 宋体;">设备。客户驱动程序即启动</span><span lang="EN-US">USBFN</span><span style="font-family: 宋体;">，引发主机配置设备，配置完成以后即可开始工作。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>       </span></span><span style="font-family: 宋体;">而</span><span lang="EN-US">USBFN</span><span style="font-family: 宋体;">总路线控制器驱动的</span><span lang="EN-US">MDD</span><span style="font-family: 宋体;">部分</span><span lang="EN-US">WINCE</span><span style="font-family: 宋体;">本身已经提供，</span><span lang="EN-US">PDD</span><span style="font-family: 宋体;">只需初始化硬件设备，提供传输即可。</span><span lang="EN-US">MDD</span><span style="font-family: 宋体;">在初始化时调用</span><span lang="EN-US">UfnPdd_Init</span><span style="font-family: 宋体;">函数得到</span><span lang="EN-US">PDD</span><span style="font-family: 宋体;">层的函数表，之后会根据需要调用各个函数。</span><span lang="EN-US">PDD</span><span style="font-family: 宋体;">还需要提供</span><span lang="EN-US">IST</span><span style="font-family: 宋体;">，用以处理各个中断。需要注意的是</span><span lang="EN-US">USBFN</span><span style="font-family: 宋体;">有一个与其它设备不同之处，它的注册表需要这样一个设置：</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>   </span>"BusIoctl"=dword:<st1:chmetcnv unitname="a" sourcevalue="2" hasspace="False" negative="False" numbertype="1" tcsc="0" st="on">2a</st1:chmetcnv>0048</span><span style="font-family: 宋体;">，用以让系统加载完设备之后调用值为</span><span lang="EN-US">0x<st1:chmetcnv unitname="a" sourcevalue="2" hasspace="False" negative="False" numbertype="1" tcsc="0" st="on">2a</st1:chmetcnv>0048</span><span style="font-family: 宋体;">的</span><span lang="EN-US">IOCTL</span><span style="font-family: 宋体;">代码去完成初始化，其定义为</span><span style="font-size: 12pt; font-family: 宋体;" lang="EN-US">IOCTL_BUS_POSTINIT</span><span style="font-size: 12pt; font-family: 宋体;">。<span lang="EN-US"><o:p></o:p></span></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="blogger-labels">标签： <a  href="http://winceblog.blogspot.com/search/label/BaseKnowledge" rel="tag">BaseKnowledge</a></p>
</div>
</div>
<p class="post-footer">
<em>张贴者：Blog by Braden @ <a  href="http://winceblog.blogspot.com/2007/03/winceusbfn.html" title="permanent link">3/03/2007 06:56:00 下午</a></em> &nbsp;
<a  href="https://www.blogger.com/comment.g?blogID=37724268&amp;postID=5156944094587713279" class="comment-link" location.href="https://www.blogger.com/comment.g?blogID=37724268&amp;postID=5156944094587713279;"><span style="text-transform: lowercase;">2 条评论</span></a>
<a  href="http://winceblog.blogspot.com/2007/03/winceusbfn.html#links" class="comment-link"><span style="text-transform: lowercase;">指向此帖子的链接</span></a>
<span class="item-action"><a  href="http://www.blogger.com/email-post.g?blogID=37724268&amp;postID=5156944094587713279" title="以电子邮件发送帖子"><img  src="http://www.blogger.com/img/icon18_email.gif" class="icon-action" alt="" height="13" width="18"></a></span><span class="item-control blog-admin pid-2106978906"><a  href="http://www.blogger.com/post-edit.g?blogID=37724268&amp;postID=5156944094587713279" style="border: medium none ;" title="修改帖子"><img  src="http://www.blogger.com/img/icon18_edit_allbkg.gif" class="icon-action" alt="" height="18" width="18"></a></span>
</p>
</div>
<!-- End .post -->
<!-- Begin #comments -->
<!-- End #comments -->
<h2 class="date-header">2007-02-28</h2>
<!-- Begin .post -->
<div class="post"><a name="990238142699354822"></a>
<h3 class="post-title">
SOURCES文件详解
</h3>
<div class="post-body">
<div>
<p class="MsoNormal"><span lang="EN-US">SOURCES</span><span style="font-family: 宋体;">文件是</span><span lang="EN-US">WINCE</span><span style="font-family: 宋体;">底层开发中最重要的文件之一</span><span lang="EN-US">,</span><span style="font-family: 宋体;">主要的配置项如下</span><span lang="EN-US">:</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p></o:p>TARGETNAME,</span><span style="font-family: 宋体;">定义模块名称</span><span lang="EN-US">.<br>TARGETTYPE,</span><span style="font-family: 宋体;">模块的种类</span><span lang="EN-US">,</span><span style="font-family: 宋体;">可以是</span><span lang="EN-US">DYNLINK, LIBRARY,EXE.<br></span><span style="font-family: 宋体;">如果</span><span lang="EN-US">TARGETTYPE</span><span style="font-family: 宋体;">是</span><span lang="EN-US">DLL,</span><span style="font-family: 宋体;">则可以定义</span><span lang="EN-US">DLLENTRY,</span><span style="font-family: 宋体;">将</span><span lang="EN-US">Dll</span><span style="font-family: 宋体;">入口定义成别的不是</span><span lang="EN-US">DLLMain</span><span style="font-family: 宋体;">的函数</span><span lang="EN-US">,</span><span style="font-family: 宋体;">如果</span><span lang="EN-US">DLL</span><span style="font-family: 宋体;">的入口是</span><span lang="EN-US">DllMain</span><span style="font-family: 宋体;">，则不需要别的定义。</span><span lang="EN-US"><br></span><span style="font-family: 宋体;">如果</span><span lang="EN-US">TARGETTYPE</span><span style="font-family: 宋体;">是</span><span lang="EN-US">EXE,</span><span style="font-family: 宋体;">则可以定义</span><span lang="EN-US">EXEENTRY,</span><span style="font-family: 宋体;">用于指定</span><span lang="EN-US">EXE</span><span style="font-family: 宋体;">的入口函数</span><span lang="EN-US">. </span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">如果</span><span lang="EN-US">TARGETTYPE</span><span style="font-family: 宋体;">是</span><span lang="EN-US">LIBRARY,</span><span style="font-family: 宋体;">则不需要定义入口函数。</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p><br>INCLUDES</span><span style="font-family: 宋体;">，如果一个模块需要使用非标准路径下的头文件时</span><span lang="EN-US">,</span><span style="font-family: 宋体;">需要定义</span><span lang="EN-US">INCLUDES,</span><span style="font-family: 宋体;">用于包含更多的头文件路径</span><span lang="EN-US">,</span><span style="font-family: 宋体;">用法如下</span><span lang="EN-US">:<br><br>INCLUDES=$(INCLUDES);\new directory\...,</span><span style="font-family: 宋体;">注意定义新的</span><span lang="EN-US">INCLUDES</span><span style="font-family: 宋体;">时</span><span lang="EN-US">,</span><span style="font-family: 宋体;">需要包含</span><span lang="EN-US">INCLUDES</span><span style="font-family: 宋体;">原来的值，否则就需要包含所有可能的目录。</span><span lang="EN-US"><br><br>TARGETLIBS,SOURCELIBS</span><span style="font-family: 宋体;">用于定义该模块需要链接哪些库文件</span><span lang="EN-US">.</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p><br>TARGETLIBS</span><span style="font-family: 宋体;">，如果一个库以</span><span lang="EN-US">DLL</span><span style="font-family: 宋体;">的形式提供给调用者，就需要用</span><span lang="EN-US">TARGETLIBS</span><span style="font-family: 宋体;">，它只链接一个函数地址，系统执行时会将被链接的库加载。比如</span><span lang="EN-US">coredll.lib</span><span style="font-family: 宋体;">就是这样的库文件。即动态链接。</span></p>
<p class="MsoNormal"><span lang="EN-US">SOURCELIBS</span><span style="font-family: 宋体;">，将库中的函数实体链接进来。即静态链接，用到的函数会在我们的文件中形成一份拷贝。</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span><br><span style="font-family: 宋体;">注意，内核这个执行文件是没有</span><span lang="EN-US">TARGETLIBS</span><span style="font-family: 宋体;">的，</span><span lang="EN-US">GIISR.DLL</span><span style="font-family: 宋体;">也不能有</span><span lang="EN-US">TARGETLIBS</span><span style="font-family: 宋体;">。</span></p>
<p class="MsoNormal"><span lang="EN-US"><br>WINCECOD,</span><span style="font-family: 宋体;">如果将其定义为</span><span lang="EN-US">1,</span><span style="font-family: 宋体;">则编译器会为每一个文件生成</span><span lang="EN-US">.cod</span><span style="font-family: 宋体;">文件</span><span lang="EN-US">,</span><span style="font-family: 宋体;">它是一个汇编文件，调试时查看汇编代码也是一种很好的办法。</span><span lang="EN-US"><br><br>SOURCES,</span><span style="font-family: 宋体;">定义该模块需要哪些源文件</span><span lang="EN-US">.</span></p>
<p class="blogger-labels">标签： <a  href="http://winceblog.blogspot.com/search/label/BaseKnowledge" rel="tag">BaseKnowledge</a></p>
</div>
</div>
<p class="post-footer">
<em>张贴者：Blog by Braden @ <a  href="http://winceblog.blogspot.com/2007/02/sources.html" title="permanent link">2/28/2007 09:09:00 下午</a></em> &nbsp;
<a  href="https://www.blogger.com/comment.g?blogID=37724268&amp;postID=990238142699354822" class="comment-link" location.href="https://www.blogger.com/comment.g?blogID=37724268&amp;postID=990238142699354822;"><span style="text-transform: lowercase;">1 条评论</span></a>
<a  href="http://winceblog.blogspot.com/2007/02/sources.html#links" class="comment-link"><span style="text-transform: lowercase;">指向此帖子的链接</span></a>
<span class="item-action"><a  href="http://www.blogger.com/email-post.g?blogID=37724268&amp;postID=990238142699354822" title="以电子邮件发送帖子"><img  src="http://www.blogger.com/img/icon18_email.gif" class="icon-action" alt="" height="13" width="18"></a></span><span class="item-control blog-admin pid-2106978906"><a  href="http://www.blogger.com/post-edit.g?blogID=37724268&amp;postID=990238142699354822" style="border: medium none ;" title="修改帖子"><img  src="http://www.blogger.com/img/icon18_edit_allbkg.gif" class="icon-action" alt="" height="18" width="18"></a></span>
</p>
</div>
<!-- End .post -->
<!-- Begin #comments -->
<!-- End #comments -->
<h2 class="date-header">2007-02-17</h2>
<!-- Begin .post -->
<a name="8604944099509790452"></a>
<h3 class="post-title">
多个设备共享同一个硬件中断
</h3>
<span lang="EN-US"><o:p></o:p></span><span style="font-family: 宋体;">硬件中断线总是有限的，我们可能需要在已有的系统上做一些扩展，比如将串口扩展成好几个，有些硬件本身就设计成多个设备共享一条中断线，比如我的系统中两个串口就共享同一个</span><span lang="EN-US">CPU</span><span style="font-family: 宋体;">中断，任何一个串口发生中断以后都会触发</span><span lang="EN-US">CPU</span><span style="font-family: 宋体;">的同一条中断线，需要判断别的寄存器来确定是哪个串口发生了什么中断。</span>
<p class="MsoNormal"><span style="font-family: 宋体;">我们可以在</span><span lang="EN-US">OAL</span><span style="font-family: 宋体;">中分析各个中断源，然后返回不同的</span><span lang="EN-US">SYSINTR</span><span style="font-family: 宋体;">值，但这种做法扩展性不好。例如，</span><span lang="EN-US">OAL</span><span style="font-family: 宋体;">中设值某个中断源最多会产生三个</span><span lang="EN-US">SYSINTR</span><span style="font-family: 宋体;">，但以后扩展成了四个设备，有一个设备就无法正常工作了。</span></p>
<p class="MsoNormal"><span lang="EN-US">WINCE</span><span style="font-family: 宋体;">引入了可装载中断处理例程的概念。即在需要与别的设备共享中断的驱动程序中加载一个</span><span lang="EN-US">ISR</span><span style="font-family: 宋体;">，一般使用</span><span lang="EN-US">WINCE</span><span style="font-family: 宋体;">提供的</span><span lang="EN-US">GIISR</span><span style="font-family: 宋体;">即成满足需求。将其安装到内核。</span><span lang="EN-US">OAL</span><span style="font-family: 宋体;">中发生中断时调用</span><strong><span style="font-size: 8.5pt; color: black; letter-spacing: 1.2pt;" lang="EN-US">NKCallIntChain</span></strong><span style="font-family: 宋体;">来得到</span><span lang="EN-US">SYSINTR</span><span style="font-family: 宋体;">，这个函数会引起系统逐个调用在该</span><span lang="EN-US">IRQ</span><span style="font-family: 宋体;">上加载的所有可装载的</span><span lang="EN-US">ISR</span><span style="font-family: 宋体;">，当某个</span><span lang="EN-US">ISR</span><span style="font-family: 宋体;">认为这个中断是由它引发的时就返回其</span><span lang="EN-US">SYSINTR</span><span style="font-family: 宋体;">，否则就返回</span><span style="font-size: 8.5pt; font-family: verdana; color: black;" lang="EN-US">SYSINTR_CHAIN</span><span style="font-size: 8.5pt; font-family: 宋体; color: black;">，</span><span style="font-family: 宋体;">系统就会接着调用其它的</span><span lang="EN-US">ISR</span><span style="font-family: 宋体;">，甚至所有的</span><span lang="EN-US">ISR</span><span style="font-family: 宋体;">都被调用或者有一个</span><span lang="EN-US">ISR</span><span style="font-family: 宋体;">返回了正确的</span><span lang="EN-US">SYSINTR</span><span style="font-family: 宋体;">。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">驱动程序中的调用办法如下（</span><span lang="EN-US">CE</span><span style="font-family: 宋体;">帮助文档）：</span></p>
<p class="MsoNormal"><span lang="EN-US"><span> </span>if (InstallIsr) {</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>        </span>// Install ISR handler</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>        </span>g_IsrHandle = LoadIntChainHandler(IsrDll, IsrHandler, (BYTE)Irq);</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>        </span>if (!g_IsrHandle) {</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>DEBUGMSG(ZONE_ERROR, (L"WAVEDEV: Couldn't install ISR handler\r\n"));</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>        </span>} else {</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>GIISR_INFO Info;</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>PVOID PhysAddr;</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>DWORD inIoSpace = 1;<span>    </span>// io space</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>           </span><span> </span>PHYSICAL_ADDRESS PortAddress = {ulIoBase, 0}; </span></p>
<p class="MsoNormal"><span lang="EN-US"><span>                </span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>if (!TransBusAddrToStatic(PCIBus, 0, PortAddress, ulIoLen, &amp;inIoSpace, &amp;PhysAddr)) {</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>                </span>DEBUGMSG(ZONE_ERROR, (L"WAVEDEV: Failed TransBusAddrToStatic\r\n"));</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>                </span>return FALSE;</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>}</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>                </span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>DEBUGMSG(ZONE_PDD,
(L"WAVEDEV: Installed ISR handler, Dll = '%s', Handler = '%s', Irq =
%d, PhysAddr = 0x%x\r\n", IsrDll, IsrHandler, Irq, PhysAddr));</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>                </span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>// Set up ISR handler</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>Info.SysIntr = ulSysIntr;</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>Info.CheckPort = TRUE;</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>Info.PortIsIO = TRUE;</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>Info.UseMaskReg = FALSE;</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>Info.PortAddr = (DWORD)PhysAddr + ES1371_dSTATUS_OFF;</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>Info.PortSize = sizeof(DWORD);</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>Info.Mask = ES1371_INTSTAT_PENDING;</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>                </span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>if (!KernelLibIoControl(g_IsrHandle, IOCTL_GIISR_INFO, &amp;Info, sizeof(Info), NULL, 0, NULL)) {</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>                </span>DEBUGMSG(ZONE_ERROR, (L"WAVEDEV: KernelLibIoControl call failed.\r\n"));</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>            </span>}</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>        </span>}</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>    </span>}</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">这里需要注意一下，因为</span><span lang="EN-US">ISR</span><span style="font-family: 宋体;">在内核态运行，</span><span lang="EN-US">Info.PortAddr</span><span style="font-family: 宋体;">必须是系统最原始的虚拟地址，即没有用</span><span lang="EN-US">VirtualCopy</span><span style="font-family: 宋体;">映射过的，从</span><span lang="EN-US">OEMAddressTable</span><span style="font-family: 宋体;">中计算出来的虚拟地址。在这个例子中用</span><span lang="EN-US">TransBusAddrToStatic</span><span style="font-family: 宋体;">函数可以直接把物理地址转换成这种地址。而</span><strong><span style="font-size: 8.5pt; color: black; letter-spacing: 1.2pt;" lang="EN-US">MmMapIoSpace</span></strong><span style="font-family: 宋体;">得到是在当前程序空间中的地址</span><span lang="EN-US">,</span><span style="font-family: 宋体;">不能使用。而且</span><span lang="EN-US">GIIR</span><span style="font-family: 宋体;">要被加载到内核空间，所以在加入到</span><span lang="EN-US">OS</span><span style="font-family: 宋体;">包中时需要加上</span><span lang="EN-US">K</span><span style="font-family: 宋体;">标志，否则</span><span lang="EN-US">LoadIntChainHandler</span><span style="font-family: 宋体;">函数会失败。</span></p><img src ="http://www.cppblog.com/zjj2816/aggbug/70243.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2008-12-24 15:12 <a href="http://www.cppblog.com/zjj2816/archive/2008/12/24/70243.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 如何使用CeLog调试Windows mobile设备驱动 转</title><link>http://www.cppblog.com/zjj2816/archive/2008/12/19/69830.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Fri, 19 Dec 2008 06:07:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2008/12/19/69830.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/69830.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2008/12/19/69830.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/69830.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/69830.html</trackback:ping><description><![CDATA[<div style="margin-left: 21pt; text-indent: -21pt;"><span>一.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp; </span></span>介绍</div>
<div>本文主要介绍在不进入KITL模式, 使用CeLog工具来调试Windows mobile设备的方法，该方法可以抓到使用DEBUGMSG打出的log信息，注意：本方法只在RETAIL版本上实验通过。</div>
<div style="margin-left: 21pt; text-indent: -21pt;"><span>二.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp; </span></span>工具</div>
<div style="margin-left: 21pt; text-indent: -21pt;">Platform Builder</div>
<div style="margin-left: 21pt; text-indent: -21pt;"><span><span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;</span></span>Readlog.exe</div>
<div style="margin-left: 21pt; text-indent: -21pt;">CeLogStopFlush.exe</div>
<div>Readlog.exe可以在路径：_WINCEROOT\SDK\BIN\I386下面找到，CeLogStopFlush.exe</div>
<div>的源代码可以在_WINCEROOT\Public\Common\SDK\Samples\CeLog\Flush\Stopflush找到,使用build &#8211;c可以生成CeLogStopFlush.exe。</div>
<div style="margin-left: 21pt; text-indent: -21pt;"><span>三.<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">&nbsp;&nbsp;&nbsp;&nbsp; </span></span>步骤</div>
<div>1．建立一个Start Log的快捷方式，具体新建一个文件，复制下面的语句：</div>
<pre style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"><span style="font-size: 10.5pt;">83#\Windows\<span style="color: red;">celogflush</span>.exe -buf 0x100000 -time 60000 -n \celog.clg -z 0x00800000 -ui 1</span></pre>
<pre style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"><span style="font-size: 10.5pt;">将其重命名为Start Log.lnk</span></pre>
<pre style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"><span style="font-size: 10.5pt;">2</span><span style="font-size: 10.5pt;">．检查手机的\Windows目录是否有以下两个文件</span><span style="font-size: 10.5pt;">CeLog.dll and CeLogFlush.exe</span><span style="font-size: 10.5pt;">，如果没有的话，将它们拷贝到</span><span style="font-size: 10.5pt;">\Windows</span><span style="font-size: 10.5pt;">目录（</span><span style="font-size: 10.5pt;">release</span><span style="font-size: 10.5pt;">目录可以找到）</span></pre>
<pre style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"><span style="font-size: 10.5pt;">3</span><span style="font-size: 10.5pt;">．拷贝Start Log.lnk和CeLogStopFlush.exe到开始菜单中，修改注册表，增加或修改下面的键值。（注意</span>ZoneCE是16进制的）</pre>
<pre>[HKEY_LOCAL_MACHINE\System\CeLog]</pre>
<pre><span>&nbsp;&nbsp;&nbsp; "Transport"="LocalFile"</span></pre>
<pre><span>&nbsp;&nbsp;&nbsp; "FileName"="celog.clg"</span></pre>
<pre><span>&nbsp;&nbsp;&nbsp; "ZoneCE"=dword:800000</span></pre>
<pre style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"><span style="font-size: 10.5pt;">4</span><span style="font-size: 10.5pt;">．点击Start Log开始抓log</span></pre>
<div>5．点击CeLogStopFlush.exe停止抓log</div>
<div>6．将根目录下生成的<strong><span style="font-weight: normal;">celog.clg</span></strong><strong><span style="font-weight: normal;">文件拷贝到</span></strong><strong><span style="font-weight: normal;">PC</span></strong><strong><span style="font-weight: normal;">机与</span></strong>Readlog同一级目录<strong><span style="font-weight: normal;">上</span></strong></div>
<div><strong><span style="font-weight: normal;">7</span></strong><strong><span style="font-weight: normal;">．打开</span></strong><strong><span style="font-weight: normal;">DOS</span></strong><strong><span style="font-weight: normal;">命令行，转到</span></strong><strong><span style="font-weight: normal;">Readlog.exe</span></strong><strong><span style="font-weight: normal;">目录中，输入下面的命令：</span></strong></div>
<pre><span style="font-size: 10.5pt;">Readlog.exe celog.clg celog.log</span></pre>
<div>8．使用文本工具查看<strong><span style="font-weight: normal;">celog.log</span></strong><strong><span style="font-weight: normal;">中的</span></strong><strong><span style="font-weight: normal;">log</span></strong><strong><span style="font-weight: normal;">信息，下面是一个</span></strong><strong><span style="font-weight: normal;">log</span></strong><strong><span style="font-weight: normal;">的实例。</span></strong></div><img src ="http://www.cppblog.com/zjj2816/aggbug/69830.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2008-12-19 14:07 <a href="http://www.cppblog.com/zjj2816/archive/2008/12/19/69830.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux应用程序安装与管理-转</title><link>http://www.cppblog.com/zjj2816/archive/2008/12/16/69559.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Tue, 16 Dec 2008 03:34:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2008/12/16/69559.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/69559.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2008/12/16/69559.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/69559.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/69559.html</trackback:ping><description><![CDATA[<strong>Linux应用程序安装与管理</strong>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<br>
目标：<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;了解linux应用程序的组成部分<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;掌握使用RPM工具管理软件包的方法<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;掌握应用程序源代码包的编译安装方法<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;掌握图形界面下应用程序管理工具的使用<br>
1、Linux应用程序基础<br>
2、RPM包管理<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;包管理系统初步：<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;RPM:RPM Package Manager&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<br>
<a  href="http://www.rpm.org/" target="_blank"><font color="#0000ff">http://www.rpm.org</font></a><br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;RPM包管理系统：<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ rpm<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;RPPM包的文件名称：<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;bash-3.0-19.2.i386.rpm<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; bash:软件名称。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 3.0-19.2:软件的版本号。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; i386:软件所运行的最低硬件平台。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; rpm:文件的扩展名,用来标识当前文件是rpm格式的软件包。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;RPM包管理功能：<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;rpm命令配合不同的参数可以实现以下的rpm包的管理功能:<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 查询已安装在linux系统中的RPM软件包的信息。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 查询RPM软件包安装文件的信息。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 安装RPM软件包到当前linux系统。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 从当前linux系统中卸载已安装的RPM软件包。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 从当前linux系统中升级已安装的RPM软件包。<br>
使用rpm命令查询软件包：<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;1、查询系统中安装的所有RPM包<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ rpm&nbsp;&nbsp;-qa&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;查询当前linux系统中已经安装的软件包。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 例：$ rpm -qa | grep -i x11 | head -3&nbsp;&nbsp;察看系统中包含x11字符串的前3行软件包。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2、查询软件包是否安装<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ rpm &#8211;q rpm包名称&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;察看系统中指定软件包是否安。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 例: $ rpm -q bash&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 察看系统中bash软件包是否安装。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;"rpm -q"命令中指定的软件包名称需要准确的拼写，该命令不会在软件包的名称中进行局部匹配的查询。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;3、查询已安装软件包详细信息<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ rpm &#8211;qi RPM包名称&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;查询linux系统中指定名称软件包的详细信息。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 例：$ rpm -qi bash&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;察看bash软件包的详细信息。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;"rpm -qi"命令的执行结果中包含较详细的信息，包括：软件名称，版本信息，包大小，描述，等。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;4、查询已安装软件包中的文件列表<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ rpm &#8211;ql RPM包名称&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;查询已安装软件包在当前系统中安装了哪些文件。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 例：$ rpm -ql bash | head -3&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;查看bash软件在系统中已安装文件的前3行文件列表。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;$ rpm -ql bash | grep bin&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 用过滤方式察看bash中包含bin字符串的文件列表。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;5、查询系统中文件所属的软件包<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ rpm &#8211;qf 文件名称&nbsp; &nbsp; 查询linux系统中指定文件所属的软件包。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 例：$ rpm -qf /bin/bash&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 察看bash文件所属的软件包。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;bash-3.0-19.2&nbsp; &nbsp;&nbsp; &nbsp;显示结果。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;6、查询RPM安装包文件中的信息 <br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ rpm &#8211;qpi RPM包文件名&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;察看RPM包未安装前的详细信息。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ rpm &#8211;qpl RPM包文件名&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;察看RPM包未安装前的文件列表。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;"rpm -qpi和rpm -qpl 这两条命令可作为在安装软件包之前对其的了解。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;7、rpm命令查询实例<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ which mount&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 获得mount命令的可执行文件路径。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ rpm &#8211;qf&nbsp;&nbsp;/bin/mount&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;查询/bin/mount所属的软件包。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ rpm &#8211;qi util-linux&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;查询/bin/mount所属软件包的详细信息。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ rpm &#8211;qf util-linux | grep mount&nbsp; &nbsp;&nbsp; &nbsp; 查询/bin/mount所属软件包中包括mount相关所有文件。<br>
使用rpm命令安装软件包<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;1、rpm软件包地基本安装<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ rpm &#8211;i&nbsp;&nbsp;rpm安装包文件名&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 安装该软件包中的文件到当前系统，安装过程不提示任何信息。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2、在安装软件包的同时显示详细信息<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ rpm &#8211;ivh rpm安装包文件&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;安装该软件包中的文件到当前系统，安装过程会以百分比的形式<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;显示安装的进度和一些其他信息。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;3、RPM软件包安装的依赖关系<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 强制安装：$ rpm&nbsp;&nbsp;--force&nbsp;&nbsp;&#8211;i&nbsp;&nbsp;rpm包文件名<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;注：要先满足软件包的依赖关系后再进行软件包的安装，使用强制安装命令安装不能保证软件安装到系统后一定能<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;正常运行，因此建议慎重使用。<br>
使用rpm命令卸载软件包：<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;1、RPM软件包的卸载<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ rpm&nbsp;&nbsp;-e&nbsp;&nbsp;软件包名称&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;软件包的卸载，在卸载时不显示任何信息。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;注：RPM软件包的卸载同样存在依赖关系，只有在没有依赖关系存在时才能对其进行卸载。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2、rpm软件包卸载的依赖关系<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;在使用RPM命令进行卸载时，RPM命令会分析要卸载的软件包的依赖关系，当存在依赖关系时会自动停止，并显由&nbsp; &nbsp; <br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;哪个软件造成的卸载失败。根据RPM提示的错误信息，确定先卸载的软件包，再卸载被依赖的软件包。<br>
使用rpm命令升级软件包：<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;$ rpm&nbsp;&nbsp;- U&nbsp;&nbsp;rpm安装包文件名<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;注："rpm -u"命令中使用的升级软件包文件最好使用RED HAT公司针对当前的linux版本官方推出的升级文件，建议不要&nbsp;&nbsp;<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;使用第三方提供的升级包。<br>
&nbsp; &nbsp;<br>
应用程序编译<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;开放源代码应用程序的编译安装<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;（下面以多线程下载软件"prozilla"的源代码编译安装为例来说明源代码编译安装的整个过程）<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;编译应用程序前的准备工作：<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;1、确认系统中已经安装了编译环境<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ rpm&nbsp;&nbsp;-qa&nbsp;&nbsp;| grep gcc&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;确定当前系统中安装了gcc编译器环境。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2、下载prozilla程序的源代码安装包文件<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;略<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;3、释放已下载的源代码软件包文件<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ tar jxf prozilla-2.0.4.tar.bz2&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;释放以下载的源代码软件包文件到当前目录。解压后的文件<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;名：prozilla-2.0.4<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;扩展：tar的xzvf参数用于释放以tar.gz格式的压缩包。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;4、进入源代码目录<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ cd prozilla-2.0.4&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;进入目录。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ pwd&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;显示当前目录路径。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; /home/teacher/download/prozilla-2.0.4&nbsp; &nbsp;&nbsp; &nbsp;显示结果。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;编译软件安装的路径：<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ ./configure --prefix=/home/teacher/proz&nbsp;&nbsp;<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 在prozilla程序的配置中，使用"--prdfix"选项可以指定应用程序编译后的安装路径，如果不使用"--prefix"<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 选项指定安装路径，configure程序将配置prozilla的默认安装路径为"/usr/local/bin"目录。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;5、程序编译过程<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ make&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; 使用make命令进行程序的二进制编译。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;6、程序安装过程<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ make install<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; "make install"命令将按照configuer命令的"--prefix"选项中设定的安装路径将已编译完成的应用程序安装<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;到目标目录。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;7、验证编译安装的程序<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ ls /home/teacher/proz&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;察看proz文件夹中的文件。<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; bin&nbsp;&nbsp;include lib man share<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;编译前的配置<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ ./configure&nbsp;&nbsp;- - help&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;编译与安装：<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;1、程序编译过程<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ make <br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;2、程序安装过程<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; $ make install<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;3、验证编译安装的程序<br>
使用图形界面系统工具完成RPM保的安装<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;略<img src ="http://www.cppblog.com/zjj2816/aggbug/69559.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2008-12-16 11:34 <a href="http://www.cppblog.com/zjj2816/archive/2008/12/16/69559.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows CE usb驱动程序</title><link>http://www.cppblog.com/zjj2816/archive/2008/12/03/68441.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Wed, 03 Dec 2008 02:35:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2008/12/03/68441.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/68441.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2008/12/03/68441.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/68441.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/68441.html</trackback:ping><description><![CDATA[<font class="htd" id="font_word" style="font-size: 14px; font-family: 宋体,Verdana,Arial,Helvetica,sans-serif;">上述讲了堆理论，可能读者脑袋都已经大了，为此，我们举个简单的例子来详细说明一下驱动程序的开发过程。 <br><br>例如我们有个USB Mouse设备，设备信息描述如下： <br>Device Descriptor: <br>bcdUSB: 0x0100 <br>bDeviceClass: 0x00 <br>bDeviceSubClass: 0x00 <br>bDeviceProtocol: 0x00 <br>bMaxPacketSize0: 0x08 (8) <br>idVendor: 0x05E3 (Genesys Logic Inc.) <br>idProduct: 0x0001 <br>bcdDevice: 0x0101 <br>iManufacturer: 0x00 <br>iProduct: 0x01 <br>iSerialNumber: 0x00 <br>bNumConfigurations: 0x01 <br><br>ConnectionStatus: DeviceConnected <br>Current Config <em>value</em>: 0x01 <br>Device Bus Speed: Low <br>Device Address: 0x02 <br>Open Pipes: 1 <br><br>Endpoint Descriptor: <br>bEndpointAddress: 0x81 <br>Transfer Type: Interrupt <br>wMaxPacketSize: 0x0003 (3) <br>bInterval: 0x0A <br><br>可以看出上述设备有一个中断PIPE，包的最大值为3。可能有人问上述的值怎么得到的，win2k 的DDK中有个usbview的例程，编译一下，将你的USB设备插到PC机的USB口中，运行usbview.exe即可看得相应的设备信息。 <br><br>有了这些基本信息，就可以编写USB设备了，首先声明一下，下面的代码取自微软的USB鼠标样本程序，版权归微软所有，此处仅仅借用来描述一下USB鼠标驱动的开发过程，读者如需要引用此代码，需要得到微软的同意。 <br><br>首先，必须输出USBD要求调用的三个函数，首先到设备插入到USB端口时，USBD会调用USBDeviceAttach()函数，相应的代码如下： <br>extern "C" BOOL <br>USBDeviceAttach( <br>USB_HANDLE hDevice, // USB设备句柄 <br>LPCUSB_FUNCS lpUsbFuncs, // USBDI的函数集合 <br>LPCUSB_INTERFACE lpInterface, // 设备接口描述信息 <br>LPCWSTR szUniqueDriverId, // 设备ID描述字符串。 <br>LPBOOL fAcceptControl, // 返回TRUE，标识我们可以控制此设备， 反之表示不能控制 <br>DWORD dwUnused) <br>{ <br>*fAcceptControl = FALSE; <br>// 我们的鼠标设备有特定的描述信息，要检测是否是我们的设备。 <br>if (lpInterface == NULL) <br>return FALSE; <br>// 打印相关的USB设备接口描述信息。 <br>DEBUGMSG(ZONE_INIT,(TEXT("USBMouse:
DeviceAttach, IF %u, #EP:%u, Class:%u, Sub:%u,Prot:%u\r\n"),
lpInterface-&gt;Descriptor.bInterfaceNumber,lpInterface-&gt;Descriptor.bNumEndpoints,
lpInterface-&gt;Descriptor.bInterfaceClass,lpInterface-&gt;Descriptor.bInterfaceSubClass,lpInterface-&gt;Descriptor.bInterfaceProtocol));
<br>// 初试数据USB鼠标类，产生一个接受USB鼠标数据的线程 <br>CMouse * pMouse = new CMouse(hDevice, lpUsbFuncs, lpInterface); <br>if (pMouse == NULL) <br>return FALSE; <br><br>if (!pMouse-&gt;Initialize()) <br>{ <br>delete pMouse; <br>return FALSE; <br>} <br><br>// 注册一个监控USB设备事件的回调函数，用于监控USB设备是否已经拔掉。 <br>(*lpUsbFuncs-&gt;lpRegisterNotificationRoutine)(hDevice, <br>USBDeviceNotifications, pMouse); <br><br>*fAcceptControl = TRUE; <br>return TRUE; <br>} <br><br>第二个函数是 USBInstallDriver（）函数， <br>一些基本定义如下： <br>const WCHAR gcszRegisterClientDriverId[] = L"RegisterClientDriverID"; <br>const WCHAR gcszRegisterClientSettings[] = L"RegisterClientSettings"; <br>const WCHAR gcszUnRegisterClientDriverId[] = L"UnRegisterClientDriverID"; <br>const WCHAR gcszUnRegisterClientSettings[] = L"UnRegisterClientSettings"; <br>const WCHAR gcszMouseDriverId[] = L"Generic_Sample_Mouse_Driver"; <br><br>函数接口如下： <br>extern "C" BOOL <br>USBInstallDriver( <br>LPCWSTR szDriverLibFile) // @parm [IN] - Contains client driver DLL name <br>{ <br>BOOL fRet = FALSE; <br>HINSTANCE hInst = LoadLibrary(L"USBD.DLL"); <br><br>// 注册USB设备信息 <br>if(hInst) <br>{ <br>LPREGISTER_CLIENT_DRIVER_ID pRegisterId = (LPREGISTER_CLIENT_DRIVER_ID) <br>GetProcAddress(hInst, gcszRegisterClientDriverId); <br><br>LPREGISTER_CLIENT_SETTINGS pRegisterSettings = <br>(LPREGISTER_CLIENT_SETTINGS) GetProcAddress(hInst, <br>gcszRegisterClientSettings); <br><br>if(pRegisterId &amp;&amp; pRegisterSettings) <br>{ <br>USB_DRIVER_SETTINGS DriverSettings; <br><br>DriverSettings.dwCount = sizeof(DriverSettings); <br><br>// 设置我们的特定的信息。 <br>DriverSettings.dwVendorId = USB_NO_INFO; <br>DriverSettings.dwProductId = USB_NO_INFO; <br>DriverSettings.dwReleaseNumber = USB_NO_INFO; <br><br>DriverSettings.dwDeviceClass = USB_NO_INFO; <br>DriverSettings.dwDeviceSubClass = USB_NO_INFO; <br>DriverSettings.dwDeviceProtocol = USB_NO_INFO; <br><br>DriverSettings.dwInterfaceClass = 0x03; // HID <br>DriverSettings.dwInterfaceSubClass = 0x01; // boot device <br>DriverSettings.dwInterfaceProtocol = 0x02; // mouse <br><br>fRet = (*pRegisterId)(gcszMouseDriverId); <br><br>if(fRet) <br>{ <br>fRet = (*pRegisterSettings)(szDriverLibFile, <br>gcszMouseDriverId, NULL, &amp;DriverSettings); <br><br>if(!fRet) <br>{ <br>//BUGBUG unregister the Client Driver&#8217;s ID <br>} <br>} <br>} <br>else <br>{ <br>RETAILMSG(1,(TEXT("!USBMouse: Error getting USBD function pointers\r\n"))); <br>} <br>FreeLibrary(hInst); <br>} <br>return fRet; <br>} <br>上述代码主要用于产生USB设备驱动程序需要的注册表信息，需要注意的是：USB设备驱动程序不使用标准的注册表函数，而是使用RegisterClientDriverID（）和RegisterClientSettings来注册相应的设备信息。 <br><br>另外一个函数是USBUninstallDriver()函数，具体代码如下： <br>extern "C" BOOL <br>USBUnInstallDriver() <br>{ <br>BOOL fRet = FALSE; <br>HINSTANCE hInst = LoadLibrary(L"USBD.DLL"); <br><br>if(hInst) <br>{ <br>LPUN_REGISTER_CLIENT_DRIVER_ID pUnRegisterId = <br>(LPUN_REGISTER_CLIENT_DRIVER_ID) <br>GetProcAddress(hInst, gcszUnRegisterClientDriverId); <br><br>LPUN_REGISTER_CLIENT_SETTINGS pUnRegisterSettings = <br>(LPUN_REGISTER_CLIENT_SETTINGS) GetProcAddress(hInst, <br>gcszUnRegisterClientSettings); <br><br>if(pUnRegisterSettings) <br>{ <br>USB_DRIVER_SETTINGS DriverSettings; <br><br>DriverSettings.dwCount = sizeof(DriverSettings); <br>// 必须填入与注册时相同的信息。 <br>DriverSettings.dwVendorId = USB_NO_INFO; <br>DriverSettings.dwProductId = USB_NO_INFO; <br>DriverSettings.dwReleaseNumber = USB_NO_INFO; <br><br>DriverSettings.dwDeviceClass = USB_NO_INFO; <br>DriverSettings.dwDeviceSubClass = USB_NO_INFO; <br>DriverSettings.dwDeviceProtocol = USB_NO_INFO; <br><br>DriverSettings.dwInterfaceClass = 0x03; // HID <br>DriverSettings.dwInterfaceSubClass = 0x01; // boot device <br>DriverSettings.dwInterfaceProtocol = 0x02; // mouse <br><br>fRet = (*pUnRegisterSettings)(gcszMouseDriverId, NULL, <br>&amp;DriverSettings); <br>} <br><br>if(pUnRegisterId) <br>{ <br>BOOL fRetTemp = (*pUnRegisterId)(gcszMouseDriverId); <br>fRet = fRet ? fRetTemp : fRet; <br>} <br>FreeLibrary(hInst); <br>} <br>return fRet; <br>} <br>此函数主要用于删除USBInstallDriver()时创建的注册表信息，同样的它使用自己的函数接口UnRegisterClientDriverID（）和UnRegisterClientSettings（）来做相应的处理。 <br><br>另外一个需要处理的注册的监控通知函数USBDeviceNotifications（）： <br>extern "C" BOOL USBDeviceNotifications(LPVOID lpvNotifyParameter, DWORD dwCode, <br>LPDWORD * dwInfo1, LPDWORD * dwInfo2, LPDWORD * dwInfo3, <br>LPDWORD * dwInfo4) <br>{ <br>CMouse * pMouse = (CMouse *)lpvNotifyParameter; <br><br>switch(dwCode) <br>{ <br>case USB_CLOSE_DEVICE: <br>//删除相关的资源。 <br>delete pMouse; <br>return TRUE; <br>} <br>return FALSE; <br>} <br><br><br>USB鼠标的类的定义如下： <br>class CMouse <br>{ <br>public: <br>CMouse::CMouse(USB_HANDLE hDevice, LPCUSB_FUNCS lpUsbFuncs, <br>LPCUSB_INTERFACE lpInterface); <br>~CMouse(); <br><br>BOOL Initialize(); <br>private: <br>// 传输完毕调用的回调函数 <br>static DWORD CALLBACK MouseTransferCompleteStub(LPVOID lpvNotifyParameter); <br>// 中断处理函数 <br>static ULONG CALLBACK CMouse::MouseThreadStub(PVOID context); <br>DWORD MouseTransferComplete(); <br>DWORD MouseThread(); <br><br>BOOL SubmitInterrupt(); <br>BOOL HandleInterrupt(); <br><br>BOOL m_fClosing; <br>BOOL m_fReadyForMouseEvents; <br><br>HANDLE m_hEvent; <br>HANDLE m_hThread; <br><br>USB_HANDLE m_hDevice; <br>USB_PIPE m_hInterruptPipe; <br>USB_TRANSFER m_hInterruptTransfer; <br><br>LPCUSB_FUNCS m_lpUsbFuncs; <br>LPCUSB_INTERFACE m_pInterface; <br><br>BOOL m_fPrevButton1; <br>BOOL m_fPrevButton2; <br>BOOL m_fPrevButton3; <br><br>// 数据接受缓冲区。 <br>BYTE m_pbDataBuffer[8]; <br>}; <br><br>具体实现如下： <br><br>// 构造函数，初始化时调用 <br>CMouse::CMouse(USB_HANDLE hDevice, LPCUSB_FUNCS lpUsbFuncs, <br>LPCUSB_INTERFACE lpInterface) <br>{ <br>m_fClosing = FALSE; <br>m_fReadyForMouseEvents = FALSE; <br>m_hEvent = NULL; <br>m_hThread = NULL; <br><br>m_hDevice = hDevice; <br>m_hInterruptPipe = NULL; <br>m_hInterruptTransfer = NULL; <br><br>m_lpUsbFuncs = lpUsbFuncs; <br>m_pInterface = lpInterface; <br><br>m_fPrevButton1 = FALSE; <br>m_fPrevButton2 = FALSE; <br>m_fPrevButton3 = FALSE; <br><br>memset(m_pbDataBuffer, 0, sizeof(m_pbDataBuffer)); <br>} <br><br>// 析构函数，用于清除申请的资源。 <br>CMouse::~CMouse() <br>{ <br>// 通知系统去关闭相关的函数接口。 <br>m_fClosing = TRUE; <br><br>// Wake up the connection thread again and give it time to die. <br>if (m_hEvent != NULL) <br>{ <br>// 通知关闭数据接受线程。 <br>SetEvent(m_hEvent); <br><br>if (m_hThread != NULL) <br>{ <br>DWORD dwWaitReturn; <br><br>dwWaitReturn = WaitForSingleObject(m_hThread, 1000); <br>if (dwWaitReturn != WAIT_OBJECT_0) <br>{ <br>TerminateThread(m_hThread, DWORD(-1)); <br>} <br>CloseHandle(m_hThread); <br>m_hThread = NULL; <br>} <br>CloseHandle(m_hEvent); <br>m_hEvent = NULL; <br>} <br><br>if(m_hInterruptTransfer) <br>(*m_lpUsbFuncs-&gt;lpCloseTransfer)(m_hInterruptTransfer); <br><br>if(m_hInterruptPipe) <br>(*m_lpUsbFuncs-&gt;lpClosePipe)(m_hInterruptPipe); <br>} <br><br><br>// 初始化USB鼠标驱动程序 <br>BOOL CMouse::Initialize() <br>{ <br>LPCUSB_DEVICE lpDeviceInfo = (*m_lpUsbFuncs-&gt;lpGetDeviceInfo)(m_hDevice); <br><br>// 检测配置：USB鼠标应该只有一个中断管道 <br>if ((m_pInterface-&gt;lpEndpoints[0].Descriptor.bmAttributes &amp; USB_ENDPOINT_TYPE_MASK) != USB_ENDPOINT_TYPE_INTERRUPT) <br>{ <br>RETAILMSG(1,(TEXT("!USBMouse: EP 0 wrong type (%u)!\r\n"), <br>m_pInterface-&gt;lpEndpoints[0].Descriptor.bmAttributes)); <br>return FALSE; <br>} <br>DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: EP 0:MaxPacket: %u, Interval: %u\r\n"), <br>m_pInterface-&gt;lpEndpoints[0].Descriptor.wMaxPacketSize, <br>m_pInterface-&gt;lpEndpoints[0].Descriptor.bInterval)); <br><br>m_hInterruptPipe = (*m_lpUsbFuncs-&gt;lpOpenPipe)(m_hDevice, <br>&amp;m_pInterface-&gt;lpEndpoints[0].Descriptor); <br><br>if (m_hInterruptPipe == NULL) { <br>RETAILMSG(1,(TEXT("Mouse: Error opening interrupt pipe\r\n"))); <br>return (FALSE); <br>} <br>m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); <br>if (m_hEvent == NULL) <br>{ <br>RETAILMSG(1,(TEXT("USBMouse: Error on CreateEvent for connect event\r\n"))); <br>return(FALSE); <br>} <br>// 创建数据接受线程 <br>m_hThread = CreateThread(0, 0, MouseThreadStub, this, 0, NULL); <br>if (m_hThread == NULL) <br>{ <br>RETAILMSG(1,(TEXT("USBMouse: Error on CreateThread\r\n"))); <br>return(FALSE); <br>} <br><br>return(TRUE); <br>} <br><br>// 从USB鼠标设备中读出数据，产生相应的鼠标事件。 <br>BOOL CMouse::SubmitInterrupt() <br>{ <br>if(m_hInterruptTransfer) <br>(*m_lpUsbFuncs-&gt;lpCloseTransfer)(m_hInterruptTransfer); <br><br>// 从USB鼠标PIPE中读数据 <br>m_hInterruptTransfer = (*m_lpUsbFuncs-&gt;lpIssueInterruptTransfer) <br>(m_hInterruptPipe, MouseTransferCompleteStub, this, <br>USB_IN_TRANSFER | USB_SHORT_TRANSFER_OK, // 表示读数据 <br>min(m_pInterface-&gt;lpEndpoints[0].Descriptor.wMaxPacketSize, <br>sizeof(m_pbDataBuffer)), <br>m_pbDataBuffer, <br>NULL); <br><br>if (m_hInterruptTransfer == NULL) <br>{ <br>DEBUGMSG(ZONE_ERROR，（L "!USBMouse: Error in IssueInterruptTransfer\r\n")); <br>return FALSE; <br>} <br>else <br>{ <br>DEBUGMSG(ZONE_TRANSFER,(L"USBMouse::SubmitInterrupt,Transfer:0x%X\r\n", <br>m_hInterruptTransfer)); <br>} <br>return TRUE; <br>} <br><br>// 处理鼠标中断传输的数据 <br>BOOL CMouse::HandleInterrupt() <br>{ <br>DWORD dwError; <br>DWORD dwBytes; <br><br>DWORD dwFlags = 0; <br>INT dx = (signed char)m_pbDataBuffer[1]; <br>INT dy = (signed char)m_pbDataBuffer[2]; <br><br>BOOL fButton1 = m_pbDataBuffer[0] &amp; 0x01 ? TRUE : FALSE; <br>BOOL fButton2 = m_pbDataBuffer[0] &amp; 0x02 ? TRUE : FALSE; <br>BOOL fButton3 = m_pbDataBuffer[0] &amp; 0x04 ? TRUE : FALSE; <br><br>if (!(*m_lpUsbFuncs-&gt;lpGetTransferStatus)(m_hInterruptTransfer, &amp;dwBytes,&amp;dwError)) <br>{ <br>DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Error in GetTransferStatus(0x%X)\r\n"), <br>m_hInterruptTransfer)); <br>return FALSE; <br>} <br>else <br>{ <br>DEBUGMSG(ZONE_TRANSFER,(TEXT("USBMouse::HandleInterrupt, hTransfer 0x%X complete (%u bytes, Error:%X)\r\n"), <br>m_hInterruptTransfer,dwBytes,dwError)); <br>} <br><br>if (!SubmitInterrupt()) <br>return FALSE; <br><br>if(dwError != USB_NO_ERROR) <br>{ <br>DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Error 0x%X in interrupt transfer\r\n"),dwError)); <br>return TRUE; <br>} <br><br>if(dwBytes &lt; 3) <br>{ <br>DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Invalid byte cnt %u from interrupt transfer\r\n"),dwBytes)); <br>return TRUE; <br>} <br><br>if(dx || dy) <br>dwFlags |= MOUSEEVENTF_MOVE; <br><br>if(fButton1 != m_fPrevButton1) <br>{ <br>if(fButton1) <br>dwFlags |= MOUSEEVENTF_LEFTDOWN; <br>else <br>dwFlags |= MOUSEEVENTF_LEFTUP; <br>} <br><br>if(fButton2 != m_fPrevButton2) <br>{ <br>if(fButton2) <br>dwFlags |= MOUSEEVENTF_RIGHTDOWN; <br>else <br>dwFlags |= MOUSEEVENTF_RIGHTUP; <br>} <br><br>if(fButton3 != m_fPrevButton3) <br>{ <br>if(fButton3) <br>dwFlags |= MOUSEEVENTF_MIDDLEDOWN; <br>else <br>dwFlags |= MOUSEEVENTF_MIDDLEUP; <br>} <br><br>m_fPrevButton1 = fButton1; <br>m_fPrevButton2 = fButton2; <br>m_fPrevButton3 = fButton3; <br><br>DEBUGMSG(ZONE_EVENTS, <br>(TEXT("USBMouse event: dx:%d, dy:%d, dwFlags:0x%X (B1:%u, B2:%u, B3:%u)\r\n"), <br>dx,dy,dwFlags,fButton1,fButton2,fButton3)); <br><br>// 通知系统产生鼠标事件 <br>if (m_fReadyForMouseEvents) <br>mouse_event(dwFlags, dx, dy, 0, 0); <br>else <br>m_fReadyForMouseEvents = IsAPIReady(SH_WMGR); <br><br>return TRUE; <br>} <br><br><br>DWORD CALLBACK CMouse::MouseTransferCompleteStub(LPVOID lpvNotifyParameter) <br>{ <br>CMouse * pMouse = (CMouse *)lpvNotifyParameter; <br>return(pMouse-&gt;MouseTransferComplete()); <br>} <br><br>// 数据传输完毕回调函数 <br>DWORD CMouse::MouseTransferComplete() <br>{ <br>if (m_hEvent) <br>SetEvent(m_hEvent); <br>return 0; <br>} <br><br><br>ULONG CALLBACK CMouse::MouseThreadStub(PVOID context) <br>{ <br>CMouse * pMouse = (CMouse *)context; <br>return(pMouse-&gt;MouseThread()); <br>} <br><br>// USB鼠标线程 <br>DWORD CMouse::MouseThread() <br>{ <br>DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: Worker thread started\r\n"))); <br>SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); <br><br>if (SubmitInterrupt()) <br>{ <br>while (!m_fClosing) <br>{ <br>WaitForSingleObject(m_hEvent, INFINITE); <br><br>if (m_fClosing) <br>break; <br><br>if ((*m_lpUsbFuncs-&gt;lpIsTransferComplete)(m_hInterruptTransfer)) <br>{ <br>if (!HandleInterrupt()) <br>break; <br>} <br>else <br>{ <br>RETAILMSG(1,(TEXT("!USBMouse: Event signalled, but transfer not complete\r\n"))); <br>// The only time this should happen is if we get an error on the transfer <br>ASSERT(m_fClosing || (m_hInterruptTransfer == NULL)); <br>break; <br>} <br>} <br>} <br>RETAILMSG(1,(TEXT("USBMouse: Worker thread exiting\r\n"))); <br>return(0); <br>} <br><br>看
到了没有，其实USB的驱动程序编写就这么简单，类似的其他设备，例如打印机设备，就有Bulk OUT
PIPE，需要Bulk传输，那就需要了解一下IssueBulkTransfer（）的应用。当然如果是开发USB Mass Storage
Disk的驱动，那就需要了解更多的协议，例如Bulk-Only Transport协议等。 <br><br>微软的Windows CE.NET的Platform Build中已经带有USB Printer和USB Mass Storage Disk的驱动的源代码了，好好研究一下，你一定回受益非浅的。 <br><br><br><br>参考资料： <br>1． 微软出版社 &lt;&lt;Windows Ce Device Driver Kit&gt;&gt; <br>2． &lt;&lt;Universal Serial Bus Specification 1.1&gt;&gt; 来自http:://www.usb.org
</font><img src ="http://www.cppblog.com/zjj2816/aggbug/68441.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2008-12-03 10:35 <a href="http://www.cppblog.com/zjj2816/archive/2008/12/03/68441.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows CE 6.0中断处理过程 by ningling</title><link>http://www.cppblog.com/zjj2816/archive/2008/12/02/68406.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Tue, 02 Dec 2008 09:00:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2008/12/02/68406.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/68406.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2008/12/02/68406.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/68406.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/68406.html</trackback:ping><description><![CDATA[<div class="BlogPostContent">
<p>这里我们主要讨论的是CE的中断建立和中断相应的大概流程以及所涉及的代码位置。这里所讲述的，是针对ARM平台的。在CE的中断处理里面，有一部分工作是CE Kernel完成的，有一部分工作是要由OEM完成的。</p>
<p style="margin: 0in; font-size: 10pt;"><span style="font-family: calibri;" lang="en-US">Kernel</span><span style="font-family: simsun;" lang="zh-CN">代码工作</span></p>
<p style="margin: 0in; font-size: 10pt;"><span style="font-family: calibri;" lang="en-US">ExVector.s</span><span style="font-family: simsun;" lang="zh-CN">：中断向量定义，里面定义的是</span><span style="font-family: calibri;" lang="en-US">armtrap.s</span><span style="font-family: simsun;" lang="zh-CN">的函数地址</span></p>
<p style="margin: 0in; font-size: 10pt;"><span style="font-family: calibri;" lang="en-US">Armtrap.s</span><span style="font-family: simsun;" lang="zh-CN">：中断处理定义，最重要是里面的</span><span style="font-family: calibri;" lang="en-US">IRQHandler</span><span style="font-family: simsun;" lang="zh-CN">函数，而其中最重要的是</span><span style="font-family: calibri;" lang="en-US">CALL OEMInterruptHandler</span></p>
<p style="margin: 0in; font-size: 10pt;"><span style="font-family: calibri;" lang="en-US">Mdarm.c</span><span style="font-family: simsun;" lang="zh-CN">：中断向量加载</span></p>
<p style="margin: 0in; font-size: 10pt;"><span style="font-family: calibri;" lang="en-US">Kdriver.c</span><span style="font-family: simsun;" lang="zh-CN">：</span><span style="font-family: calibri;" lang="en-US">NKCallIntChain</span><span style="font-family: simsun;" lang="zh-CN">函数：把</span><span style="font-family: calibri;" lang="en-US">IRQ</span><span style="font-family: simsun;" lang="zh-CN">转换为</span><span style="font-family: calibri;" lang="en-US">SysIntr</span><span style="font-family: simsun;" lang="zh-CN">，值得留意的是</span><span style="font-family: calibri;" lang="en-US">pIntChainTable[]</span><span style="font-family: simsun;" lang="zh-CN">，是</span><span style="font-family: calibri;" lang="en-US">IRQ</span><span style="font-family: simsun;" lang="zh-CN">所对应的</span><span style="font-family: calibri;" lang="en-US">ISR</span><span style="font-family: simsun;" lang="zh-CN">处理程序的入口，其中最主要的是其成员函数</span><span style="font-family: calibri;" lang="en-US">pfnHandler</span><span style="font-family: simsun;" lang="zh-CN">。</span><span style="font-family: calibri;" lang="en-US">pfnHandler</span><span style="font-family: simsun;" lang="zh-CN">的填充，是在</span><span style="font-family: calibri;" lang="en-US">HookIntChain</span><span style="font-family: simsun;" lang="zh-CN">里面，这个函数是</span><span style="font-family: calibri;" lang="en-US">ISR</span><span style="font-family: simsun;" lang="zh-CN">在初始化的时候调用的。在这个函数里面，如果</span><span style="font-family: calibri;" lang="en-US">pIntChainTable</span><span style="font-family: simsun;" lang="zh-CN">为空，则返回</span><span style="font-family: calibri;" lang="en-US">SYSINTR_CHAIN</span><span style="font-family: simsun;" lang="zh-CN">，如果</span><span style="font-family: calibri;" lang="en-US">pIntChainTable[]</span><span style="font-family: simsun;" lang="zh-CN">不为空，则调用</span><span style="font-family: calibri;" lang="en-US">pfnHandler</span><span style="font-family: simsun;" lang="zh-CN">得到一个</span><span style="font-family: calibri;" lang="en-US">sysintr</span><span style="font-family: simsun;" lang="zh-CN">值，然后返回之。</span></p>
<p style="margin: 0in; font-size: 10pt; font-family: simsun;" mce_keep="true">&nbsp;</p>
<p style="margin: 0in; font-size: 10pt;"><span style="font-family: calibri;" lang="en-US">OEM</span><span style="font-family: simsun;" lang="zh-CN">定义工作：</span><span style="font-family: calibri;" lang="en-US">Oalintr.c</span><span style="font-family: simsun;" lang="zh-CN">：</span><span style="font-family: calibri;" lang="en-US">OEMInterruptHandler</span><span style="font-family: simsun;" lang="zh-CN">函数，通过查询硬件的中断寄存器，得到硬件</span><span style="font-family: calibri;" lang="en-US">IRQ</span><span style="font-family: simsun;" lang="zh-CN">号。对于</span><span style="font-family: calibri;" lang="en-US">EINT04-23</span><span style="font-family: simsun;" lang="zh-CN">的中断，通过</span><span style="font-family: calibri;" lang="en-US">EINTMASK</span><span style="font-family: simsun;" lang="zh-CN">寄存器，得到相对应的系统</span><span style="font-family: calibri;" lang="en-US">IRQ</span><span style="font-family: simsun;" lang="zh-CN">。注意，这里的</span><span style="font-family: calibri;" lang="en-US">IRQ</span><span style="font-family: simsun;" lang="zh-CN">是</span><span style="font-family: calibri;" lang="en-US">CE</span><span style="font-family: simsun;" lang="zh-CN">定义的</span><span style="font-family: calibri;" lang="en-US">IRQ</span><span style="font-family: simsun;" lang="zh-CN">，是系统硬件</span><span style="font-family: calibri;" lang="en-US">IRQ</span><span style="font-family: simsun;" lang="zh-CN">的扩展。然后调用</span><span style="font-family: calibri;" lang="en-US">NKCallIntChain</span><span style="font-family: simsun;" lang="zh-CN">看看这个</span><span style="font-family: calibri;" lang="en-US">IRQ</span><span style="font-family: simsun;" lang="zh-CN">是否是一个</span><span style="font-family: calibri;" lang="en-US">Chain</span><span style="font-family: simsun;" lang="zh-CN">的</span><span style="font-family: calibri;" lang="en-US">Interrupt</span><span style="font-family: simsun;" lang="zh-CN">。如果函数返回</span><span style="font-family: calibri;" lang="en-US">SYSINTR_CHAIN</span><span style="font-family: simsun;" lang="zh-CN">或者返回一个不合法的</span><span style="font-family: calibri;" lang="en-US">sysintr</span><span style="font-family: simsun;" lang="zh-CN">，则通过</span><span style="font-family: calibri;" lang="en-US">OALIntrTranslateIrq</span><span style="font-family: simsun;" lang="zh-CN">把</span><span style="font-family: calibri;" lang="en-US">IRQ</span><span style="font-family: simsun;" lang="zh-CN">转化为</span><span style="font-family: calibri;" lang="en-US">sysintr</span><span style="font-family: simsun;" lang="zh-CN">。如果是一个合法的</span><span style="font-family: calibri;" lang="en-US">sysintr</span><span style="font-family: simsun;" lang="zh-CN">，则返回该值。</span></p>
<p style="margin: 0in; font-size: 10pt; font-family: simsun;" mce_keep="true">&nbsp;</p>
<p style="margin: 0in; font-size: 10pt;"><span style="font-family: simsun;" lang="zh-CN">单一</span><span style="font-family: calibri;" lang="en-US">ISR</span><span style="font-family: simsun;" lang="zh-CN">的</span><span style="font-family: calibri;" lang="en-US">Device</span><span style="font-family: simsun;" lang="zh-CN">，主要通过</span><span style="font-family: calibri;" lang="en-US">OEMInterruptHandler</span><span style="font-family: simsun;" lang="zh-CN">处理，在</span><span style="font-family: calibri;" lang="en-US">OEMInterruptHandler</span><span style="font-family: simsun;" lang="zh-CN">没有定义的</span><span style="font-family: calibri;" lang="en-US">IRQ</span><span style="font-family: simsun;" lang="zh-CN">，可以在</span><span style="font-family: calibri;" lang="en-US">OAL</span><span style="font-family: simsun;" lang="zh-CN">里面或者驱动的加载里面，通过</span><span style="font-family: calibri;" lang="en-US">HookInterrupt</span><span style="font-family: simsun;" lang="zh-CN">函数进行关联。</span></p>
<p style="margin: 0in; font-size: 10pt;"><span style="font-family: simsun;" lang="zh-CN">多个</span><span style="font-family: calibri;" lang="en-US">ISR</span><span style="font-family: simsun;" lang="zh-CN">的</span><span style="font-family: calibri;" lang="en-US">Device</span><span style="font-family: simsun;" lang="zh-CN">，通常这是总线设备的需求，因为总线设备上面通常串有几个设备。这些总线上的设备，需要有一个</span><span style="font-family: calibri;" lang="en-US">ISR</span><span style="font-family: simsun;" lang="zh-CN">判断究竟是哪个设备发出的中断。这个</span><span style="font-family: calibri;" lang="en-US">ISR</span><span style="font-family: simsun;" lang="zh-CN">，是一个</span><span style="font-family: calibri;" lang="en-US">DLL</span><span style="font-family: simsun;" lang="zh-CN">的程序，设备驱动必须在初始化的时候通过</span><span style="font-family: calibri;" lang="en-US">LoadIntChainHandler</span><span style="font-family: simsun;" lang="zh-CN">（文件名，函数名，</span><span style="font-family: calibri;" lang="en-US">irq</span><span style="font-family: simsun;" lang="zh-CN">）加载这个</span><span style="font-family: calibri;" lang="en-US">DLL</span><span style="font-family: simsun;" lang="zh-CN">程序。</span><span style="font-family: calibri;" lang="en-US">LoadIntChainHandler</span><span style="font-family: simsun;" lang="zh-CN">的定义在</span><span style="font-family: calibri;" lang="en-US">kdriver.c</span><span style="font-family: simsun;" lang="zh-CN">的</span><span style="font-family: calibri;" lang="en-US">NKLoadIntChainHandler</span><span style="font-family: simsun;" lang="zh-CN">里面。对于大多数的总线设备，可以利用微软已经写好的</span><span style="font-family: calibri;" lang="en-US">giisr.dll</span><span style="font-family: simsun;" lang="zh-CN">来实现。</span><span style="font-family: calibri;" lang="en-US">giisr</span><span style="font-family: simsun;" lang="zh-CN">的实现代码在</span><span style="font-family: calibri;" lang="en-US">Public\common\oak\drivers</span><span style="font-family: simsun;" lang="zh-CN">下面。</span></p>
<p style="margin: 0in; font-size: 10pt; font-family: simsun;" mce_keep="true">&nbsp;</p>
<p style="margin: 0in; font-size: 10pt;"><span style="font-family: simsun;" lang="zh-CN">对于总线设备，如果利用</span><span style="font-family: calibri;" lang="en-US">GIISR</span><span style="font-family: simsun;" lang="zh-CN">的话，原理如下：</span></p>
<p style="margin: 0in; font-size: 10pt;"><span style="font-family: simsun;" lang="zh-CN">总线设备驱动在初始化的时候，通过</span><span style="font-family: calibri;" lang="en-US">LoadIntChainHandler</span><span style="font-family: simsun;" lang="zh-CN">加载</span><span style="font-family: calibri;" lang="en-US">GIISR</span><span style="font-family: simsun;" lang="zh-CN">，而加载的时候，</span><span style="font-family: calibri;" lang="en-US">LoadIntChainHandler</span><span style="font-family: simsun;" lang="zh-CN">会调用</span><span style="font-family: calibri;" lang="en-US">GIISR</span><span style="font-family: simsun;" lang="zh-CN">的</span><span style="font-family: calibri;" lang="en-US">CreateInstance</span><span style="font-family: simsun;" lang="zh-CN">创建一个实例，</span><span style="font-family: calibri;" lang="en-US">GIISR</span><span style="font-family: simsun;" lang="zh-CN">会返回一个</span><span style="font-family: calibri;" lang="en-US">index</span><span style="font-family: simsun;" lang="zh-CN">值给</span><span style="font-family: calibri;" lang="en-US">LoadIntChainHandler</span><span style="font-family: simsun;" lang="zh-CN">，以标示实例，</span><span style="font-family: calibri;" lang="en-US">LoadIntChainHandler</span><span style="font-family: simsun;" lang="zh-CN">则会返回一个</span><span style="font-family: calibri;" lang="en-US">Handle</span><span style="font-family: simsun;" lang="zh-CN">给驱动，驱动则根据这个</span><span style="font-family: calibri;" lang="en-US">Handle</span><span style="font-family: simsun;" lang="zh-CN">存取</span><span style="font-family: calibri;" lang="en-US">GIISR</span><span style="font-family: simsun;" lang="zh-CN">。得到这个</span><span style="font-family: calibri;" lang="en-US">handle</span><span style="font-family: simsun;" lang="zh-CN">之后，初始化还需要包括从</span><span style="font-family: calibri;" lang="en-US">reg</span><span style="font-family: simsun;" lang="zh-CN">表里面读出相关的初始化参数，对</span><span style="font-family: calibri;" lang="en-US">GIISR</span><span style="font-family: simsun;" lang="zh-CN">进行赋值，譬如</span><span style="font-family: calibri;" lang="en-US">Port Address</span><span style="font-family: simsun;" lang="zh-CN">，</span><span style="font-family: calibri;" lang="en-US">Mask Address</span><span style="font-family: simsun;" lang="zh-CN">，</span><span style="font-family: calibri;" lang="en-US">SysIntr</span><span style="font-family: simsun;" lang="zh-CN">等。</span></p>
<p style="margin: 0in; font-size: 10pt; font-family: simsun;" mce_keep="true">&nbsp;</p>
<p style="margin: 0in; font-size: 10pt; font-family: SimSun;">驱动程序在初始化的时候：</p>
<p style="margin: 0in; font-size: 10pt;"><span style="font-family: calibri;" lang="en-US">1</span><span style="font-family: simsun;" lang="zh-CN">、创建一个</span><span style="font-family: calibri;" lang="en-US">Event</span><span style="font-family: simsun;" lang="zh-CN">（</span><span style="font-family: calibri;" lang="en-US">CreateEvent</span><span style="font-family: simsun;" lang="zh-CN">）</span></p>
<p style="margin: 0in; font-size: 10pt;"><span style="font-family: calibri;" lang="en-US">2</span><span style="font-family: simsun;" lang="zh-CN">、然后用</span><span style="font-family: calibri;" lang="en-US">InterruptInitialize</span><span style="font-family: simsun;" lang="zh-CN">函数把</span><span style="font-family: calibri;" lang="en-US">sysintr</span><span style="font-family: simsun;" lang="zh-CN">和这个</span><span style="font-family: calibri;" lang="en-US">Event</span><span style="font-family: simsun;" lang="zh-CN">相关联</span></p>
<p style="margin: 0in; font-size: 10pt;"><span style="font-family: calibri;" lang="en-US">3</span><span style="font-family: simsun;" lang="zh-CN">、</span><span style="font-family: calibri;" lang="en-US">Kick-off</span><span style="font-family: simsun;" lang="zh-CN">一个</span><span style="font-family: calibri;" lang="en-US">Thread</span><span style="font-family: simsun;" lang="zh-CN">（</span><span style="font-family: calibri;" lang="en-US">IST</span><span style="font-family: simsun;" lang="zh-CN">）</span></p>
<p style="margin: 0in; font-size: 10pt;"><span style="font-family: calibri;" lang="en-US">4</span><span style="font-family: simsun;" lang="zh-CN">、这个</span><span style="font-family: calibri;" lang="en-US">Thread</span><span style="font-family: simsun;" lang="zh-CN">最终是</span><span style="font-family: calibri;" lang="en-US">WaitForSingleObject</span><span style="font-family: simsun;" lang="zh-CN">（</span><span style="font-family: calibri;" lang="en-US">EventID</span><span style="font-family: simsun;" lang="zh-CN">）</span></p>
<p style="margin: 0in; font-size: 10pt;"><span style="font-family: simsun;" lang="zh-CN">具体的例子，可以参阅</span><span style="font-family: calibri;" lang="en-US">USBFN</span><span style="font-family: simsun;" lang="zh-CN">的例子：</span><span style="font-family: calibri;" lang="en-US">sc2410pdd.cpp</span><span style="font-family: simsun;" lang="zh-CN">里面，</span><span style="font-family: calibri;" lang="en-US">UfnPdd_Start</span><span style="font-family: simsun;" lang="zh-CN">函数；</span></p>
</div>
Published Sunday, June 10, 2007 7:13 PM
by
<a  href="http://blogs.msdn.com/user/Profile.aspx?UserID=25770" id="ctl00___ctl00___ctl00_ctl00_bcr_ctl00___Entry___AuthorLink">ningling</a><img src ="http://www.cppblog.com/zjj2816/aggbug/68406.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2008-12-02 17:00 <a href="http://www.cppblog.com/zjj2816/archive/2008/12/02/68406.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows CE下驱动开发基础 付林林</title><link>http://www.cppblog.com/zjj2816/archive/2008/11/28/68088.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Fri, 28 Nov 2008 08:59:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2008/11/28/68088.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/68088.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2008/11/28/68088.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/68088.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/68088.html</trackback:ping><description><![CDATA[<span lang="zh-cn"></span>这是我从1月6日开始主持天极网论坛嵌入式开发版以来第一次发表文章，加上以前琐碎的文章共
计30篇。研究的越多就越感觉自己懂的太少，其实在驱动开发方面我还是个菜鸟，我是想再次抛砖引玉，让做驱动有N年经验的人奉献一点出来，让大家减少一些
研究驱动源码而又缺少注释所带来的痛苦。<br>
<span lang="zh-cn">　　</span>我想即使读者看过微软的关于驱动开发的培训教材和CE帮助文档中的驱动部分，头脑中仍然一片茫然。要想真正了解驱动程序必须结合一些驱动程序源码，在此我以串口驱动程序（COM16550）中初始化过程为线索简单讲一讲驱动开发的基础知识。<br>
<span lang="zh-cn">　　</span>Windows
CE下的串口驱动程序能够处理所有I/O行为类似串口的设备，包括基于16450、16550
UART（通用异步收发芯片）的设备和一些采用DMA的设备，常见的有9针串口、红外I/O口、Modem等。在%_WINCEROOT%\Public
\Common\OAK\Drivers\Serial目录下，COM_MDD2子目录包含新的串口驱动MDD层函数代码。COM16550子目录包含串
口驱动PDD层代码。SER16550子目录包含的一系列函数专用于控制与16550兼容的UART，这样PDD层的主要工作就是调用SER16550中
的函数。还有一个ISR16550子目录包含的是串口驱动程序专用的可安装ISR（中断服务例程），而很多硬件设备驱动程序采用CE默认的可安装ISR
giisr.dll。一般串口设备相应的注册表设置例子及意义如下：
<table style="border-collapse: collapse;" id="AutoNumber1" border="1" bordercolor="#111111" cellpadding="0" cellspacing="0" width="90%">
    <tbody>
        <tr>
            <td align="center" width="40%"><strong>键</strong></td>
            <td align="center" width="60%"><strong>意义</strong></td>
        </tr>
        <tr>
            <td width="40%">"SysIntr"=dword:13</td>
            <td width="60%">串口1的中断ID为十进制13</td>
        </tr>
        <tr>
            <td width="40%">"IoBase"=dword:02F8</td>
            <td width="60%">串口1的IO空间首地址为十六进制2F8</td>
        </tr>
        <tr>
            <td width="40%">"IoLen"=dword:8</td>
            <td width="60%">串口1的IO空间长度为8个字节</td>
        </tr>
        <tr>
            <td width="40%">"DeviceArrayIndex"=dword:0</td>
            <td width="60%">串口1的索引，是1的由来</td>
        </tr>
        <tr>
            <td width="40%">"Order"=dword:0</td>
            <td width="60%">串口1驱动的加载顺序</td>
        </tr>
        <tr>
            <td width="40%">"DeviceType"=dword:0</td>
            <td width="60%">串口1的设备类型</td>
        </tr>
        <tr>
            <td width="40%">"DevConfig"=hex: 10,00 ....</td>
            <td width="60%">串口1在与Modem设备通讯时的配置，如波特率、奇偶校检等</td>
        </tr>
        <tr>
            <td width="40%">"FriendlyName"="COM1:"</td>
            <td width="60%">串口1在拨号程序中显示的名字</td>
        </tr>
        <tr>
            <td width="40%">"Tsp"="Unimodem.dll"</td>
            <td width="60%">串口1 被用于与Modem设备通讯的时候要加载的TSP（TAPI Service provider）DLL</td>
        </tr>
        <tr>
            <td width="40%">"Prefix"="COM"</td>
            <td width="60%">串口1的流接口的前缀</td>
        </tr>
        <tr>
            <td width="40%">"Dll"="com16550.Dll"</td>
            <td width="60%">串口1的驱动程序DLL</td>
        </tr>
    </tbody>
</table>
<p><span lang="zh-cn">　　</span>SysIntr
由CE在文件Nkintr.h中预定义，用于唯一标识中断设备。OEM可以在文件Oalintr.h中定义自己的SysIntr。常见的预定义
SysIntr有SYSINTR_NOP（中断只由ISR处理，IST不再处理），SYSINTR_RESCHED（重新调度线
程），SYSINTR_DEVICES（由CE预定义的设备中断ID的基值），SYSINTR_PROFILE、SYSINTR_TIMING、
SYSINTR_FIRMWARE等都是基于SYSINTR_DEVICES定义的。IoBase是串口1的IO地址空间的首地址，IoLen是IO空间
的大小。IO地址空间只存在于x86平台，如果在其它平台硬件寄存器必须映射到物理地址空间，那子键的名称为MemBase和MemLen。在x86平台
更多硬件的寄存器由于IO空间的局限也映射到物理地址空间。DeviceArrayIndex是设备的索引，用于区分同类型的设备。Prefix是流驱动
程序的前缀，当应用程序调用CreateFile函数传递COM1:参数时，文件系统负责与串口驱动程序通信，串口驱动程序是在CE启动时由
device.exe加载的。<br>
<br>
<span lang="zh-cn">　　</span>下面从MDD
层函数COM_Init开始探索串口驱动的初始化过程。COM_Init是在串口设备被检测后由设备管理器device.exe调用的，主要的作用是初始
化设备，它的唯一参数Identifier是由device.exe传递的，其类型是一个字符串指针，字符串的内容是HLM\Drivers
\Active\xx，xx是一个十进制数（device.exe会跟踪系统中每个驱动程序，把加载的驱动程序记录在Active键下）。
COM_Init先分配一个HW_INDEP_INFO结构体，这个结构体是独立于串口硬件的头信息（MDD、PDD、SER16550都包含自己独特的
结构体，具体的结构体定义请参见串口驱动源码），分配之后再初始化结构体中每个成员，初始化结构体后调用
OpenDeviceKey((LPCTSTR)Identifier)打开HLM\Drivers\Active\xx\Key包含的注册表路径，在这
里路径一般为HLM\Drivers\BuiltIn\Serial，即串口的驱动程序信息在注册表中所处的位置。COM_Init接着在HLM
\Drivers\BuiltIn\Serial下查询DeviceArrayIndex、Priority256的值，Priority256指定了驱
动程序的优先级，如果没有就用默认的优先级。接下来调用GetSerialObject(DeviceArrayIndex)，这个函数由PDD层定义，
返回HWOBJ结构体，这个结构体主要包含PDD层和SER16550定义的函数的指针。也就是说MDD通过调用这个函数才能调用底层实现的函数。接下来
的大多数工作都是调用底层函数实现初始化。第一个调用的底层函数SerInit主要设置由用户设置的硬件配置，例如线路控制、波特率。它调用
Ser_GetRegistryData函数得到保存在注册表中的硬件信息，Ser_GetRegistryData在内部调用系统提供的
DDKReg_GetIsrInfoDDK和DDKReg_GetWindowInfo函数得到在HLM\Drivers\BuiltIn\Serial
下保存的IRQ、SysIntr、IsrDll、IsrHandler、IoBase、IoLen。IRQ是逻辑中断号，IsrDll表示当前驱动程序的
可安装ISR所在的DLL名称，IsrHandler
表示可安装ISR的函数名称。在这里顺便提一下可安装ISR，读者在我以前发表的关于OAL的文章中可以了解到OEM在OEMInit函数中关联IRQ和
SysIntr，当硬件设备发生中断时，ISR会禁止同级和低级中断，然后根据IRQ返回关联的SysIntr，内核根据ISR返回的SysIntr唤醒
相应的IST（SysIntr与IST创建的Event关联），IST处理中断之后调用InterruptDone解除中断禁止。在OEMInit中关联
的缺点是一旦编译了CE内核后就无法添加这种关联了，而一些硬件设备会随时插拔或者共享中断，要关联这样的硬件设备解决方法就是可安装ISR，可安装
ISR专用于处理指定的硬件设备发出的中断，所以如果硬件设备需要可安装ISR必须在注册表中添加IsrDll、IsrHandler。多数硬件设备采用
CE默认的可安装ISR giisr.dll，格式如下：</p>
<pre> "IsrDll"="giisr.dll"<br>"IsrHandler"="ISRHandler"</pre>
<p><span lang="zh-cn">　　</span>如果一个硬件驱动程序需要可安装ISR而开发者又不想自己写一个，那么可以利用giisr.dll来实现。除了在注册表中添加如上所示外，还要在驱动程序中调用相关函数注册可安装ISR。伪代码如下：</p>
<pre>g_IsrHandle = LoadIntChainHandler(IsrDll, IsrHandler, (BYTE)Irq);<br>GIISR_INFO Info;<br>PHYSICAL_ADDRESS PortAddress = {PhysAddr, 0};<br>TransBusAddrToStatic(BusType, dwBusNumber, PortAddress, dwAddrLen, &amp;dwIOSpace, &amp;(PVOID)PhysAddr)<br>Info.SysIntr = dwSysIntr;<br>Info.CheckPort = TRUE;<br>Info.PortIsIO = (dwIOSpace) ? TRUE : FALSE;<br>Info.UseMaskReg = TRUE;<br>Info.PortAddr = PhysAddr + 0x0C;<br>Info.PortSize = sizeof(DWORD);<br>Info.MaskAddr = PhysAddr + 0x10;<br>KernelLibIoControl(g_IsrHandle, IOCTL_GIISR_INFO, &amp;Info, sizeof(Info), NULL, 0, NULL);</pre>
<p><span lang="zh-cn">　　</span>LoadIntChainHandler
函数负责注册可安装ISR，参数1为DLL名称，参数2为ISR函数名称，参数3为IRQ。TransBusAddrToStatic函数在后面讲。如果
要利用giisr.dll作为可安装ISR，必须先填充GIISR_INFO结构体，CheckPort=TRUE表示giisr要检测指定的寄存器来确
定当前发出中断的是否是这个设备。PortIsIO表示寄存器地址属于哪个地址空间，FALSE表示是内定空间，TRUE表示IO空间。
UseMaskReg=TRUE表示设备有一个掩码寄存器，专用于指定当前设备是否是中断源，也就是发出中断，而MaskAddr表示掩码寄存器的地址。
如果对Info.Mask赋值，那么PortAddr表示一个特殊的寄存器地址，这个寄存器的值与Mask的值&amp;运算的结果如果为真，则证明当前
设备是中断源，否则返回SYSINTR_CHAIN（表示当前ISR没有处理中断，内核将调用ISR链中下一个ISR），如果
UseMaskReg=TRUE，那么MaskReg寄存器的值与PortAddr指定的寄存器的值&amp;运算的结果如果为真，则证明当前设备是中断
源。<br>
<span lang="zh-cn">　　</span>函数SerInit接着调用函数
Ser_InternalMapRegisterAddresses转换IO地址并且映射地
址，Ser_InternalMapRegisterAddresses在内部调用系统提供的HalTranslateBusAddress(Isa,
0, ioPhysicalBase, &amp;inIoSpace,
&amp;ioPhysicalBase)函数将与总线相关的地址转换为系统地址，参数1为总线类型，参数2为总线号，参数3为要转换的地址
（PHYSICAL_ADDRESS类型，实际是LARGE_INTEGER型），参数4指定寄存器地址属于IO地址空间还是物理地址空间，参数5返回转
换后的物理地址。观察HalTranslateBusAddress的源码得知如果是在x86平台，这个函数除了把参数3赋给了参数5其余什么都没有做，
而非x86平台将inIoSpace的值置为0，表示一定是物理地址。在调用HalTranslateBusAddress前要确定从注册表中得到的寄存
器地址到底是属于哪个地址空间的，例如：</p>
<pre>ULONG inIoSpace = 1; ///1表示是IO空间<br>PHYSICAL_ADDRESS ioPhysicalBase = {iobase, 0}; ///相当于ioPhysicalBase.LowPart = iobase</pre>
<p><span lang="zh-cn">　　</span>在地址转换后就要将转换后的地址映射到驱动程序（一般IST和应用程序一样运行在用户模式）能够访问的虚拟地址空间（0x80000000以下）和ISR能够访问的静态虚拟地址空间中（0x80000000以上）。例如：</p>
<pre>////如果地址属于物理地址空间<br>ioPortBase = (PUCHAR)MmMapIoSpace(ioPhysicalBase, Size, FALSE);<br>TransBusAddrToStatic(Isa, 0, ioPhysicalBase, Size, &amp;inIoSpace, ppStaticAddress);</pre>
<p><span lang="zh-cn">　　</span>MmMapIoSpace函数负责将物理地址映射到驱动程序能够访问的虚拟地址空间中，通过源码分析MmMapIoSpace在内部分别调用：</p>
<pre>pVirtualAddress =VirtualAlloc(0, SourceSize, MEM_RESERVE, PAGE_NOACCESS);<br>VirtualCopy(pVirtualAddress, (PVOID)(SourcePhys &gt;&gt; 8), SourceSize, PAGE_PHYSICAL | <br>PAGE_READWRITE | (CacheEnable ? 0 : PAGE_NOCACHE));</pre>
<p><span lang="zh-cn">　　</span>VirtualAlloc
分配一块和MemLen一样大小的虚拟地址空间，因为参数1为0，所以内核自动分配。一般MemLen小于2MB，所以会在应用程序的地址空间中分配。
VirtualCopy负责将硬件设备寄存器的物理地址与VirtualAlloc分配的虚拟地址做一个映射关系，这样驱动程序访问
PvirtualAddress实际上就是访问第一个寄存器。因为硬件设备寄存器的物理地址一定是在512MB（CE支持RAM的最大值）以上，所以除了
最后的参数要加PAGE_PHYSICAL外，第二个参数物理地址也要右移8位（或者除以256）。映射硬件寄存器当然PAGE_NOCACHE是必须加
的。TransBusAddrToStatic函数负责将物理地址映射到ISR能够访问的静态虚拟地址空间中，当出现中断共享时，ISR要负责访问硬件设
备的某一个寄存器来判断中断源，所以将寄存器的物理地址映射到静态虚拟地址空间中是必要的（ISR只能访问静态的虚拟地址空间）。所谓静态虚拟地址空间是
指在OEMAddressTable中定义的虚拟地址空间（当然是0x80000000以上）。在x86平台一般这个表只定义RAM的物理地址与虚拟地址
对应关系，而硬件设备的寄存器地址并不在该表中定义，所以如果要创建一块静态的虚拟地址空间供ISR访问，必须在此之前调用
CreateStaticMapping函数在0xC4000000到0xE0000000虚拟地址空间中分配。
TransBusAddrToStatic函数在内部就是调用了CreateStaticMapping函数。注：硬件设备的寄存器地址也可以在
OEMAddressTable中定义。</p>
<pre>////如果地址属于IO空间<br>ioPortBase = (PUCHAR)ioPhysicalBase.LowPart;<br>*ppStaticAddress=ioPortBase</pre>
<p>这种情况只属于x86平台，是IO空间就可以直接访问，即使是用户模式。<br>
<span lang="zh-cn">　　</span>SerInit
函数接着初始化SER_INFO结构体成员，之后调用SL_Init函数，这个函数在ser16550中定义，负责初始化SER16550_INFO结构
体，在这个结构体中保存串口8个寄存器的地址。SerInit函数执行完毕后COM_Init函数创建接收缓冲区，然后调用
StartDispatchThread函数初始化中断并且创建IST。StartDispatchThread函数在内部调用
InterruptInitialize函数关联SysIntr和Event，然后调用InterruptDone函数告诉内核当前串口可以中断处理，接
着调用CreateThread函数创建IST线程。（over吧，再往下说就和串口硬件有关了，看多了没注释的代码我也烦！！）</p><img src ="http://www.cppblog.com/zjj2816/aggbug/68088.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2008-11-28 16:59 <a href="http://www.cppblog.com/zjj2816/archive/2008/11/28/68088.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Enumhandle</title><link>http://www.cppblog.com/zjj2816/archive/2008/11/28/68083.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Fri, 28 Nov 2008 08:30:00 GMT</pubDate><guid>http://www.cppblog.com/zjj2816/archive/2008/11/28/68083.html</guid><wfw:comment>http://www.cppblog.com/zjj2816/comments/68083.html</wfw:comment><comments>http://www.cppblog.com/zjj2816/archive/2008/11/28/68083.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/zjj2816/comments/commentRss/68083.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/zjj2816/services/trackbacks/68083.html</trackback:ping><description><![CDATA[here it is .. you need the DDK for that , Gary Nebbett is the author:<br>
<br>
#include "ntdll.h"<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;stdio.h&gt;<br>
#include "ntddk.h"<br>
<br>
#define DUPLICATE_SAME_ATTRIBUTES   0x00000004<br>
<br>
#pragma comment(lib,"ntdll.lib")<br>
<br>
BOOL EnablePrivilege(PCSTR name)<br>
{<br>
TOKEN_PRIVILEGES priv = {1, {0, 0, SE_PRIVILEGE_ENABLED}};<br>
LookupPrivilegeValue(0, name, &amp;priv.Privileges[0].Luid);<br>
<br>
HANDLE hToken;<br>
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &amp;hToken);<br>
<br>
AdjustTokenPrivileges(hToken, FALSE, &amp;priv, sizeof priv, 0, 0);<br>
BOOL rv = GetLastError() == ERROR_SUCCESS;<br>
<br>
CloseHandle(hToken);<br>
return rv;<br>
}<br>
<br>
int main(int argc, char *argv[])<br>
{<br>
if (argc == 1) return 0;<br>
<br>
ULONG pid = strtoul(argv[1], 0, 0);<br>
<br>
EnablePrivilege(SE_DEBUG_NAME);<br>
<br>
HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);<br>
<br>
ULONG n = 0x1000;<br>
PULONG p = new ULONG[n];<br>
<br>
while (NT::ZwQuerySystemInformation(NT::SystemHandleInformation, p, n * sizeof *p, 0)<br>
== STATUS_INFO_LENGTH_MISMATCH)<br>
<br>
delete [] p, p = new ULONG[n *= 2];<br>
<br>
NT::PSYSTEM_HANDLE_INFORMATION h = NT::PSYSTEM_HANDLE_INFORMATION(p + 1);<br>
<br>
for (ULONG i = 0; i &lt; *p; i++) {<br>
<br>
if (h[i].ProcessId == pid) {<br>
HANDLE hObject;<br>
<br>
if (NT::ZwDuplicateObject(hProcess, HANDLE(h[i].Handle), NtCurrentProcess(), &amp;hObject,<br>
0, 0, DUPLICATE_SAME_ATTRIBUTES)<br>
!= STATUS_SUCCESS) continue;<br>
<br>
NT::OBJECT_BASIC_INFORMATION obi;<br>
<br>
NT::ZwQueryObject(hObject, NT::ObjectBasicInformation, &amp;obi, sizeof obi, &amp;n);<br>
<br>
printf("%p %04hx %6lx %2x %3lx %3ld %4ld ", <br>
h[i].Object, h[i].Handle, h[i].GrantedAccess,<br>
int(h[i].Flags), obi.Attributes,<br>
obi.HandleCount - 1, obi.PointerCount - 2);<br>
<br>
n = obi.TypeInformationLength + 2;<br>
<br>
NT::POBJECT_TYPE_INFORMATION oti = NT::POBJECT_TYPE_INFORMATION(new CHAR[n]);<br>
<br>
NT::ZwQueryObject(hObject, NT::ObjectTypeInformation, oti, n, &amp;n);<br>
<br>
printf("%-14.*ws ", oti[0].Name.Length / 2, oti[0].Name.Buffer);<br>
<br>
n = obi.NameInformationLength == 0 <br>
? MAX_PATH * sizeof (WCHAR) : obi.NameInformationLength;<br>
<br>
NT::POBJECT_NAME_INFORMATION oni = NT::POBJECT_NAME_INFORMATION(new CHAR[n]);<br>
<br>
NTSTATUS rv = NT::ZwQueryObject(hObject, NT::ObjectNameInformation, oni, n, &amp;n);<br>
if (NT_SUCCESS(rv))<br>
printf("%.*ws", oni[0].Name.Length / 2, oni[0].Name.Buffer);<br>
<br>
printf("\n");<br>
<br>
CloseHandle(hObject);<br>
}<br>
}<br>
delete [] p;<br>
<br>
CloseHandle(hProcess);<br>
<br>
return 0;<br>
}<img src ="http://www.cppblog.com/zjj2816/aggbug/68083.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/zjj2816/" target="_blank">井泉</a> 2008-11-28 16:30 <a href="http://www.cppblog.com/zjj2816/archive/2008/11/28/68083.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>