﻿<?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/hugai/</link><description /><language>zh-cn</language><lastBuildDate>Thu, 23 Apr 2026 10:14:13 GMT</lastBuildDate><pubDate>Thu, 23 Apr 2026 10:14:13 GMT</pubDate><ttl>60</ttl><item><title>*控制流图(II)</title><link>http://www.cppblog.com/hugai/archive/2010/09/15/126646.html</link><dc:creator>悟山</dc:creator><author>悟山</author><pubDate>Wed, 15 Sep 2010 04:14:00 GMT</pubDate><guid>http://www.cppblog.com/hugai/archive/2010/09/15/126646.html</guid><wfw:comment>http://www.cppblog.com/hugai/comments/126646.html</wfw:comment><comments>http://www.cppblog.com/hugai/archive/2010/09/15/126646.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/hugai/comments/commentRss/126646.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/hugai/services/trackbacks/126646.html</trackback:ping><description><![CDATA[<p>控制流图对编译优化和程序静态分析很有用处。编译优化根据待编译程序的控制流减少其中不必要的跳转，使得代码结构更加紧凑。静态分析工具根据程序的控制流来分析得到程序的复杂度等等一系列统计信息，Visual Studio自带的代码度量(Code Metrics)就是静态分析中控制流图应用的一个例子。<br></p>
<img src ="http://www.cppblog.com/hugai/aggbug/126646.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/hugai/" target="_blank">悟山</a> 2010-09-15 12:14 <a href="http://www.cppblog.com/hugai/archive/2010/09/15/126646.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>*控制流图</title><link>http://www.cppblog.com/hugai/archive/2010/09/15/126645.html</link><dc:creator>悟山</dc:creator><author>悟山</author><pubDate>Wed, 15 Sep 2010 04:00:00 GMT</pubDate><guid>http://www.cppblog.com/hugai/archive/2010/09/15/126645.html</guid><wfw:comment>http://www.cppblog.com/hugai/comments/126645.html</wfw:comment><comments>http://www.cppblog.com/hugai/archive/2010/09/15/126645.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/hugai/comments/commentRss/126645.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/hugai/services/trackbacks/126645.html</trackback:ping><description><![CDATA[控制流图（Control Flow Graph)是在计算机科学中用图的方式来表现程序执行过程中所有的可能执行路径的一种方式。在控制流图中，每一个节点表示表示一个基本的代码块，这些基本的代码块用箭头连接起来用以描述这些代码块之间的执行顺序。<br>在控制流图中，有两类特殊的代码块，入口代码块和出口代码块；所有的执行路径都从入口块开始，并且结束于一个出口块。<br>一个控制流图本身是一个图(Graph)，可以用计算机图论中的术语来加以描述，诸如edge，vertex，back edge等等。<br>下面的图片可以作为一个基本的控制流图的样本：<br><img border=0 src="http://www.cppblog.com/images/cppblog_com/hugai/Simplified_Control_Flowgraphs.jpg"> 
<img src ="http://www.cppblog.com/hugai/aggbug/126645.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/hugai/" target="_blank">悟山</a> 2010-09-15 12:00 <a href="http://www.cppblog.com/hugai/archive/2010/09/15/126645.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个小型CRM系统的设计（未完成版本）</title><link>http://www.cppblog.com/hugai/archive/2009/11/06/100292.html</link><dc:creator>悟山</dc:creator><author>悟山</author><pubDate>Fri, 06 Nov 2009 05:26:00 GMT</pubDate><guid>http://www.cppblog.com/hugai/archive/2009/11/06/100292.html</guid><wfw:comment>http://www.cppblog.com/hugai/comments/100292.html</wfw:comment><comments>http://www.cppblog.com/hugai/archive/2009/11/06/100292.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/hugai/comments/commentRss/100292.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/hugai/services/trackbacks/100292.html</trackback:ping><description><![CDATA[
Core-Man System Design Document
Version 1.0


9/29/2009


 

Contents
简介	4
系统总体架构介绍	4
系统具体设计	6
后记	6
 

简介
本文档用来描述Core-Man这个用来为汽配行业做货物、订单、客户关系管理的系统功能和设计。本文档基于该系统的需求分析和前期市场调研，关于需求分析和市场调研的结果，可以查看文档XXXX.
1.	系统设计目标
为了使得系统能最大程度的满足用户的需求，尽可能的减少以后再定制维护过程中的代价，Core-Man系统应该达到以下几个目标：
	可定制性：虽然本系统是为了汽配行业的客户管理而设计的，但是本系统需要达到在特定的需求下经过适当的配置（数据库配置，配置文件更改）而达到满足其他行业需求的目的。
	可维护性：本系统的设计应该达到可维护的目的，因为用户的需求可能会变化（企业规模扩大，经营业务增多）。在用户变化需求的时候，我们的系统就需要升级，那么在升级的过程，至少需要满足两方面的可重用，一是数据上的可重用。客户在一定的经营过程中积累了一定数目的用户资源和经营经验数据，这部分数据对于客户以后继续经营，扩大业务规模都是有重要作用的。在我们的系统升级的过程，应该使得客户可以重用这部分数据，即使得升级后的系统能够识别维护旧的数据。另一方面的可重用性是指代码上的可重用性，系统的升级不能使推到系统重来。新系统应该基于旧系统已有的代码，这样可以最大程度上的节省成本。
	安全性：虽然在系统初期，客户对于安全性上的要求不会很高，但是随着企业业务规模的扩大，必然涉及到很多的商业保密信息。企业的客户数据，订单数据，管理模式都有很重要的商业价值，此时对于我们系统的安全性就提出了要求。Core-Man系统的安全性主要体现在一下几个方面：
	用户认证：系统应该区分登录的会话中用户的身份，以此来判断用户可访问哪些数据，可更改哪些数据，这个对于一个中大型企业里面，各个管理层面（老板，总经理，经理，员工）应用同一个系统式很重要的。
	权限管理：验证用户后，需要判断已验证用户是否被允许访问其所请求的数据，在判断通过的情况下，系统返回正确的响应；否则，系统告知客户端无权访问。

	数据加密：企业的客户数据，员工数据，订单数据都涉及到商业秘密。这些数据都需要经过加密后存储在系统的文件系统或者数据库中。

系统总体架构介绍
很明显的Core-Man系统是一个以数据库为中心，以多终端进行数据处理维护的分布式系统，一个Core-Man系统的典型的应用场景可以用下图来描述：
 
在上面的应用场景中，各个角色的分工如下：
	中心数据库：负责提供整个系统的数据的存贮，这里包含两部分内容
	由数据库管理系统托管的数据库表，视图，存储过程，数据等信息。
	由文件系统托管的图片，文件等信息。
	请求监听/代理服务器：负责作为终端用户和数据库之间通信的一个代理人的角色。所有客户端的操作如果涉及到数据库查询/更改请求，由请求监听/代理服务器将其转换为对相应数据库项目的查询/更新操作。这样的设计能使得终端用户和数据库的耦合性降到最低，使得在需要更换数据库的时候，我们只需要更新请求监听/代理服务器里面与数据库交互的那部分代码。同时，加进一层请求监听/代理服务器，可以让我们的系统在这一层进行安全性上的检查更改等操作，比如，在这一层做终端用户身份的鉴别，只有终端用户是授权用户的时候，我们才允许客户端进行后续操作。
	超级管理终端：这个终端有最大的管理权限，用于进行数据的备份，紧急模式下的更改等操作。
	分布式终端1：本系统众多分布式终端的其中一个，用户为普通用户（经理，员工，客户）提供访问我们系统的功能。每一个分布式终端在发起连接请求监听/代理服务器的时候，都需要提供用户身份的信息，请求监听/代理服务器用这些信息来判断发起连接的用户是否是一个经过授权的用户。

下图描述了我们的数据库设计的基本轮廓：
下图描述了我们的请求监听/代理服务器的设计模块以及模块之间的联系：
 

自上至下，三个大的模块分别是：
	请求监听层：负责监听客户端的操作请求，检查客户端的身份，以及客户端的权限。如果客户端是经授权的用户并且其请求操作被策略允许，请求监听层会将该请求放进该层维护的请求队列中。放进请求队列中的请求包含请求的客户端信息，请求的优先级，请求所要进行的具体操作等等。请求监听层会有一个请求分发线程，从请求队列中按照一定的策略找出一个请求，将该请求送往逻辑处理层。
	逻辑处理层：逻辑处理层的主要功能是维护抽象的数据模型，使得请求层不必与具体的数据库访问器接口方法做交互。逻辑处理层将请求监听层分发过来的请求转换为对特定抽象数据的操作，这就使得在这一层能尽最大可能地应用面向对象设计的好处，为以后的升级，定制提供方便。逻辑处理层由请求监听模块，逻辑处理模块和逻辑对象管理器组成。请求监听模块将请求监听层分发过来的请求转换为对特定逻辑对象的操作。逻辑处理模块是一个特定的线程，负责调用逻辑对象管理器的方法来进行逻辑多项生命周期的维护。逻辑对象管理器负责提供逻辑对象的管理接口，比如逻辑对象的创建，删除等操作。
	数据库访问层：数据库访问层主要由数据库访问器接口和数据库访问器实现来组成。这一层提供具体的数据访问操作给逻辑处理层使用。数据库访问器接口和数据库访问器实现分属于不同的程序集，这样就使得数据库访问器实现能很方便的被替换，使系统能迁移到使用新的数据库系统，只要我们提供新数据库系统的数据库访问器实现，并且更改数据库访问层的程序配置文件指向新的数据库访问器实现。
系统具体设计
本章节按照“系统总体架构介绍”里面描述的模块顺序逐个介绍这些模块的具体实现策略。
请求监听层：
请求监听模块：
设计请求监听模块涉及到设计我们所使用的具体的网络协议的格式，在初步的设计里面，我们使用 .Net对于 WinSocket的封装来实现网络数据的传输，使用TCP/IP协议。在TCP的payload里面传输我们的请求消息和响应消息。消息格式如下：
 
其中各个字段的含义如下：
Command Value: 用于指示操作码，如果系统最高位是0，表明这是系统定义的操作码；如果最高位是1，则表明是用户定义的操作码。对于每一个特定的操作码，系统应该提供一个该操作码下的Request Data的解析函数；所以，如果用户需要定义自己的操作码，那么他也应该提供该操作码下的Request Data的解析函数实现。解析函数有特定的格式如下：
public Dictionary<System.Type, object> RequestDataParser(ushort commandValue, ushort flags, Guid sessionId, byte[] requestData);
其输入为一个完整的包结构，输出为解析出来的Request Data中包含的有意义的字段对应C#中的数据类型，以及这些数据的值。这样子就是得我们能在我们的请求监听层初始化的时候根据配置文件中的解析函数配置注册合适的解析函数，在运行中能够调用注册好的配置函数解析对应的网络数据将其转换为有意义的逻辑数据。
在这种设计之下，用户如果需要定义自己的Command Value，假设其值为0xF000，那么用户提供一个叫做CustomeRequestDataParser.dll的程序集，其中包含了对于Command Value0xF0000下的Request Data的解析函数实现，其实现如下：
public class CustomeRequestDataParser
    {
        public Dictionary<System.Type, object> RequestDataParser(ushort commandValue, ushort flags, Guid sessionId, byte[] requestData)
        {
            Dictionary<System.Type, object> result = new Dictionary<Type, object>();
            if (requestData.Length != 8)
            {
                throw new ArgumentException("Invalid network data received.");
            }
            byte[] field1 = new byte[4];
            byte[] field2 = new byte[4];
            Array.Copy(requestData, field1, 4);
            Array.Copy(requestData, field2, 4, 4);
            result.Add(
                typeof(uint),
                BitConverter.ToUInt32(field1, 0));
            result.Add(typeof(uint), BitConverter.ToUInt32(field2, 0));
            return result;
        }
}
在我们的请求监听层的程序配置文件中存在这么一项：
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="0xF000ProcessingModule" value="CustomeRequestDataParser.dll.CustomeRequestDataParser"/>
      </appSettings>  
</configuration>

在我们的请求监听层的初始化代码中存在这么几行代码：
public void RegisterRequestDataParsers()
        {
            System.Collections.Specialized.NameObjectCollectionBase.KeysCollection keysCOllection = ConfigurationSettings.AppSettings.Keys;
            List<string> requestDataParserKeys = new List<string>();
            foreach (string keyValue in keysCOllection)
            {
                if (keyValue.Contains("CommandValueParser"))
                {
                    requestDataParserKeys.Add(keyValue);
                }
            }

            foreach (string keyValue in requestDataParserKeys)
            {
                string assemblyPath = GetAssemblyPath(ConfigurationSettings.AppSettings[keyValue]);

                if (!IsAssemblyLoaded(assemblyPath))
                {
                    AppDomain.CurrentDomain.Load(assemblyPath);
                }
                string typeName = GetTypeName(ConfigurationSettings.AppSettings[keyValue]);
                ushort commandValue=GetCommandValue(ConfigurationSettings.AppSettings[keyValue]);
                if (!registeredRequestDataParsers.ContainsKey(commandValue))
                {
                    registeredRequestDataParsers.Add(commandValue, Type.GetType(GetTypeFullName(typeName)));
                }
            }
        }
当请求监听模块收到一个请求之后，它会将其转换为一个事件，将其放进事件队列中，一个事件应该包含以下信息：
public class Event
    {
        private DateTime timeStamp;
        private ushort commandValue;
        private ushort flags;
        private Guid sessionId;
        Dictionary<System.Type, object> requestData;
    }

一个时间队列的可能定义如下：
public class EventQueue
    {
        private List<Event> eventPool;
        private uint eventCount;
        private Event mostPrioritizedEvent;
}

请求调度模块不断的查询事件队列中的时间，按照特定的调度策略找出一个合适的事件交给逻辑层处理：
public abstract class EventSelectionPolicy
    {
    }
public class EventQueueProcessor
    {
        private EventQueue eventQueue;
        private EventSelectionPolicy eventSelectionPolicy;

        public void RegisterEventQueue(EventQueue queue)
        {
            if (this.eventQueue != null)
            {
                throw new ArgumentException("Unable to register another event queue when a queue is still in processing.");
            }
            this.eventQueue = queue;
        }

        public EventQueue UnregisterEventQueue()
        {
            if (this.eventQueue == null)
            {
                throw new InvalidOperationException("Unable to unregister an event queue when the queue is not intialized.");
            }
            EventQueue queue = this.eventQueue;
            this.eventQueue = null;
            return queue;
        }

        public void RegisterEventSelectionPolicy(EventSelectionPolicy policy)
        {
            this.eventSelectionPolicy = policy;
        }

        public Event SelectEvent()
        {
            //
            //return ...;
        }
}
EventQueueProcessor调用SelectEvent方法按照注册过的调度策略选择一个event交给逻辑处理层处理。

后记
<img src ="http://www.cppblog.com/hugai/aggbug/100292.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/hugai/" target="_blank">悟山</a> 2009-11-06 13:26 <a href="http://www.cppblog.com/hugai/archive/2009/11/06/100292.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在.Net Framework中动态创建类型---System.Reflection.Emit命名空间小试</title><link>http://www.cppblog.com/hugai/archive/2009/07/24/91075.html</link><dc:creator>悟山</dc:creator><author>悟山</author><pubDate>Fri, 24 Jul 2009 13:51:00 GMT</pubDate><guid>http://www.cppblog.com/hugai/archive/2009/07/24/91075.html</guid><wfw:comment>http://www.cppblog.com/hugai/comments/91075.html</wfw:comment><comments>http://www.cppblog.com/hugai/archive/2009/07/24/91075.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/hugai/comments/commentRss/91075.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/hugai/services/trackbacks/91075.html</trackback:ping><description><![CDATA[<div style="background-color: rgb(238, 238, 238); font-size: 13px; border-left-color: rgb(204, 204, 204); padding-right: 5px; padding-bottom: 4px; padding-left: 4px; padding-top: 4px; width: 98%; word-break: break-all; "><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">string</span><span style="color: #000000; ">&nbsp;assemblyName&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">.txtAssemblyName.Text;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">string</span><span style="color: #000000; ">&nbsp;className&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">this</span><span style="color: #000000; ">.txtClassName.Text;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.Diagnostics.Debug.Assert(assemblyName&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">&amp;&amp;</span><span style="color: #000000; ">&nbsp;assemblyName&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">string</span><span style="color: #000000; ">.Empty);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.Diagnostics.Debug.Assert(className&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">&amp;&amp;</span><span style="color: #000000; ">&nbsp;className&nbsp;</span><span style="color: #000000; ">!=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">string</span><span style="color: #000000; ">.Empty);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.Reflection.AssemblyName&nbsp;asmName&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;System.Reflection.AssemblyName(assemblyName);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AssemblyBuilder&nbsp;asmBuilder&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;AppDomain.CurrentDomain.DefineDynamicAssembly(asmName,&nbsp;AssemblyBuilderAccess.Run);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ModuleBuilder&nbsp;modBuilder&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;asmBuilder.DefineDynamicModule(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">MyModule</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #0000FF; ">true</span><span style="color: #000000; ">);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TypeBuilder&nbsp;typeBuilder&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;modBuilder.DefineType(className);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typeBuilder.DefineField(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">myfield</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,</span><span style="color: #0000FF; ">typeof</span><span style="color: #000000; ">(</span><span style="color: #0000FF; ">string</span><span style="color: #000000; ">),&nbsp;System.Reflection.FieldAttributes.Public);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MethodBuilder&nbsp;methodBuilder&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;typeBuilder.DefineMethod(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">CallMethod</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,&nbsp;System.Reflection.MethodAttributes.Public</span><span style="color: #000000; ">|</span><span style="color: #000000; ">&nbsp;System.Reflection.MethodAttributes.SpecialName&nbsp;</span><span style="color: #000000; ">|</span><span style="color: #000000; ">&nbsp;System.Reflection.MethodAttributes.HideBySig<br>&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">,&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Type[]&nbsp;{&nbsp;</span><span style="color: #0000FF; ">typeof</span><span style="color: #000000; ">(</span><span style="color: #0000FF; ">string</span><span style="color: #000000; ">)&nbsp;});<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;methodBuilder.DefineParameter(</span><span style="color: #000000; ">0</span><span style="color: #000000; ">,&nbsp;System.Reflection.ParameterAttributes.Retval,&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;methodBuilder.DefineParameter(</span><span style="color: #000000; ">1</span><span style="color: #000000; ">,&nbsp;System.Reflection.ParameterAttributes.In,&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">name</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ILGenerator&nbsp;ilGenerator&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;methodBuilder.GetILGenerator();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ilGenerator.Emit(OpCodes.Ldarg_1);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">System.Reflection.Assembly&nbsp;asmSystem&nbsp;=&nbsp;System.Reflection.Assembly.GetAssembly(typeof(MessageBox));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">Type&nbsp;typeMessageBox&nbsp;=&nbsp;asmSystem.GetType("MessageBox");</span><span style="color: #008000; "><br></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Type&nbsp;typeMessageBox&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">typeof</span><span style="color: #000000; ">(MessageBox);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.Reflection.MethodInfo&nbsp;mInfoShow&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;typeMessageBox.GetMethod(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Show</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;Type[]{</span><span style="color: #0000FF; ">typeof</span><span style="color: #000000; ">(</span><span style="color: #0000FF; ">string</span><span style="color: #000000; ">)}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">System.Reflection.BindingFlags.Public|&nbsp;System.Reflection.BindingFlags.Static,</span><span style="color: #008000; "><br></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ilGenerator.EmitCall(OpCodes.Call,&nbsp;mInfoShow,&nbsp;</span><span style="color: #0000FF; ">null</span><span style="color: #000000; ">);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ilGenerator.Emit(OpCodes.Ret);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Type&nbsp;customType&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;typeBuilder.CreateType();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">object</span><span style="color: #000000; ">&nbsp;customeObj&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;Activator.CreateInstance(customType);&nbsp;;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.Reflection.MethodInfo&nbsp;methodInfo&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;customType.GetMethod(</span><span style="color: #000000; ">"</span><span style="color: #000000; ">CallMethod</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">customType.InvokeMember("CallMethod",&nbsp;System.Reflection.BindingFlags.Public,&nbsp;null,&nbsp;customeObj,&nbsp;new&nbsp;object[]&nbsp;{&nbsp;"123"&nbsp;});<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">methodBuilder.Invoke(customeObj,&nbsp;new&nbsp;object[]&nbsp;{&nbsp;"123"&nbsp;});</span><span style="color: #008000; "><br></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;methodInfo.Invoke(customeObj,&nbsp;</span><span style="color: #0000FF; ">new</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">object</span><span style="color: #000000; ">[]&nbsp;{&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">11</span><span style="color: #000000; ">"</span><span style="color: #000000; ">&nbsp;});<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.ReadLine();</span></div><img src ="http://www.cppblog.com/hugai/aggbug/91075.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/hugai/" target="_blank">悟山</a> 2009-07-24 21:51 <a href="http://www.cppblog.com/hugai/archive/2009/07/24/91075.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]滤波和卷积的资料汇总</title><link>http://www.cppblog.com/hugai/archive/2009/06/22/88290.html</link><dc:creator>悟山</dc:creator><author>悟山</author><pubDate>Mon, 22 Jun 2009 07:28:00 GMT</pubDate><guid>http://www.cppblog.com/hugai/archive/2009/06/22/88290.html</guid><wfw:comment>http://www.cppblog.com/hugai/comments/88290.html</wfw:comment><comments>http://www.cppblog.com/hugai/archive/2009/06/22/88290.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/hugai/comments/commentRss/88290.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/hugai/services/trackbacks/88290.html</trackback:ping><description><![CDATA[<p>原文地址：<a href="http://hi.baidu.com/niiuniu1127/blog/item/ba6e07fb28248e126d22eb8c.html">http://hi.baidu.com/niiuniu1127/blog/item/ba6e07fb28248e126d22eb8c.html</a><br><br>什么叫滤波：用白话讲就是，一个电信号中有若干种成分，把其中一部分交流信号过滤掉就叫滤波。</p>
<p>卷积和滤波的区别：在数字信号处理的理论中，卷给可以说是一种数学运算，而滤波是一种信号处理的方法。卷积就像加权乘法一样，你能说滤波和加权乘法是一样的吗，显然不行；但是滤波最终是有乘法来实现的。</p>
<p>自适应滤波就是滤波所用的模板系数会根据图像不同位置自动调整。<br>中值滤波(median filter)简单的说就是：一个窗(window)中心的象素值就是这个窗包含的象素中处于中间位置的象素值。<br>均值滤波(mean filter)就是一个窗中心的象素值就是这个窗包含的象素的平均值。<br>空间频率主要是指图像的平滑或粗糙程度。一般可认为，高空间频率区域称&#8220;粗糙&#8221;，即图像的亮度值在小范围内变化很大，而&#8220;平滑&#8221;区，图像的亮度值变化相对较小，如平滑的水体表面等。低通滤波主要用于加强图像中的低频成分，减弱高频成分，而高通滤波则正好相反，加强高频细节，减弱低频细节，简单地讲：高通滤波处理过的图像更加&#8220;粗糙&#8221;。高通滤波顾名思义就是让频率高的通过，使图像具有锐化效果；低通滤波则恰好相反了，它是使低频通过，使图像具有平滑的效果。</p>
<p><br>&#8226;模板的定义 &#8211;所谓模板就是一个系数矩阵 &#8211;模板大小：经常是奇数，如： 3x3&nbsp;&nbsp; 5x5&nbsp;&nbsp; 7x7 &#8211;模板系数: 矩阵的元素 w1 w2 w3 w4 w5 w6 w7 w8 w9<br>空域过滤及过滤器的定义：使用空域模板进行的图像处理，被称为空域过滤。<br></p>
<div><span style="FONT-SIZE: 28pt; COLOR: red">w</span><span style="FONT-SIZE: 18pt; COLOR: red; POSITION: relative; TOP: 0.37em">1</span><span style="FONT-SIZE: 28pt; COLOR: red"><span> </span>w</span><span style="FONT-SIZE: 18pt; COLOR: red; POSITION: relative; TOP: 0.37em">2</span><span style="FONT-SIZE: 28pt; COLOR: red"><span> </span>w</span><span style="FONT-SIZE: 18pt; COLOR: red; POSITION: relative; TOP: 0.37em">3</span><span style="FONT-SIZE: 28pt; COLOR: red"> </span></div>
<div><span style="FONT-SIZE: 28pt; COLOR: red">w</span><span style="FONT-SIZE: 18pt; COLOR: red; POSITION: relative; TOP: 0.37em">4</span><span style="FONT-SIZE: 28pt; COLOR: red"><span> </span>w</span><span style="FONT-SIZE: 18pt; COLOR: red; POSITION: relative; TOP: 0.37em">5</span><span style="FONT-SIZE: 28pt; COLOR: red"><span> </span>w</span><span style="FONT-SIZE: 18pt; COLOR: red; POSITION: relative; TOP: 0.37em">6</span><span style="FONT-SIZE: 28pt; COLOR: red"> </span></div>
<div><span style="FONT-SIZE: 28pt; COLOR: red">w</span><span style="FONT-SIZE: 18pt; COLOR: red; POSITION: relative; TOP: 0.37em">7</span><span style="FONT-SIZE: 28pt; COLOR: red"><span> </span>w</span><span style="FONT-SIZE: 18pt; COLOR: red; POSITION: relative; TOP: 0.37em">8</span><span style="FONT-SIZE: 28pt; COLOR: red"><span> </span>w</span><span style="FONT-SIZE: 18pt; COLOR: red; POSITION: relative; TOP: 0.37em">9</span><br><br>模板本身被称为空域过滤器<br>空域过滤器的分类<br>按效果分：钝化过滤器，锐化过滤器<br>按数学形态分类<br>1，线性过滤器：使用乘积和的计算，例如：R = w1z1 + w2z2 + &#8230; + wnzn<br>高通：边缘增强、边缘提取<br>低通：钝化图像、去除噪音<br>带通：删除特定频率、增强中很少用<br>2，非线性过滤器：结果值直接取决于像素邻域的值<br>最大值：寻找最亮点，亮化图片<br>最小值：寻找最暗点，暗化图片<br>中值：钝化图像、去除噪音</div>
<p><br>钝化过滤器的主要用途<br>1，对大图像处理前，删去无用的细小细节<br>2，连接中断的线段和曲线<br>3，降低噪音<br>4，钝化处理，恢复过分锐化的图像<br>5，图像创艺（阴影、软边、朦胧效果）<br>缺点：<br>如果图像处理的目的是去除噪音，那么，低通滤波在去除噪音的同时也钝化了边和尖锐的细节，但是中值滤波算法的特点：在去除噪音的同时，可以比较好地保留边的锐度和图像的细节锐化过滤器的主要用途<br>1，印刷中的细微层次强调。弥补扫描、挂网对图像的钝化<br>2，超声探测成象，分辨率低，边缘模糊，通过锐化来改善<br>3，图像识别中，分割前的边缘提取<br>4，锐化处理恢复过度钝化、暴光不足的图像<br>5，图像创艺（只剩下边界的特殊图像）<br>6，尖端武器的目标识别、定位</p>
<p>过滤器效果的分析<br>1，常数或变化平缓的区域，结果为0或很小，图像很暗，亮度被降低了<br>2，在暗的背景上边缘被增强了<br>3，图像的整体对比度降低了<br>4，计算时会出现负值，归0处理为常见</p>
<p>基本高通空域滤波的缺点和问题<br>高通滤波在增强了边的同时，丢失了图像的层次和亮度<br></p>
<img src ="http://www.cppblog.com/hugai/aggbug/88290.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/hugai/" target="_blank">悟山</a> 2009-06-22 15:28 <a href="http://www.cppblog.com/hugai/archive/2009/06/22/88290.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]WM_PAINT消息小结</title><link>http://www.cppblog.com/hugai/archive/2009/06/04/86764.html</link><dc:creator>悟山</dc:creator><author>悟山</author><pubDate>Thu, 04 Jun 2009 09:21:00 GMT</pubDate><guid>http://www.cppblog.com/hugai/archive/2009/06/04/86764.html</guid><wfw:comment>http://www.cppblog.com/hugai/comments/86764.html</wfw:comment><comments>http://www.cppblog.com/hugai/archive/2009/06/04/86764.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/hugai/comments/commentRss/86764.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/hugai/services/trackbacks/86764.html</trackback:ping><description><![CDATA[<p>原文地址：<a href="http://dev.csdn.net/article/74/74935.shtm"><u><font color=#0066cc>http://dev.csdn.net/article/74/74935.shtm</font></u></a><br><br><br>WM_PAINT是Windows窗口系统中一条重要的消息，应用程序通过处理该消息实现在窗口上的绘制工作。</p>
<p>1. 系统何时发送WM_PAINT消息？</p>
<p>系统会在多个不同的时机发送WM_PAINT消息：当第一次创建一个窗口时，当改变窗口的大小时，当把窗口从另一个窗口背后移出时，当最大化或最小化窗口时，等等，这些动作都是由 系统管理的，应用只是被动地接收该消息，在消息处理函数中进行绘制操作；大多数的时候应用也需要能够主动引发窗口中的绘制操作，比如当窗口显示的数据改变的时候，这一般是通过InvalidateRect和 InvalidateRgn函数来完成的。InvalidateRect和InvalidateRgn把指定的区域加到窗口的Update Region中，当应用的消息队列没有其他消息时，如果窗口的Update Region不为空时，系统就会自动产生WM_PAINT消息。</p>
<p>系统为什么不在调用Invalidate时发送WM_PAINT消息呢？又为什么非要等应用消息队列为空时才发送WM_PAINT消息呢？这是因为系统把在窗口中的绘制操作当作一种低优先级的操作，于是尽 可能地推后做。不过这样也有利于提高绘制的效率：两个WM_PAINT消息之间通过InvalidateRect和InvaliateRgn使之失效的区域就会被累加起来，然后在一个WM_PAINT消息中一次得到 更新，不仅能避免多次重复地更新同一区域，也优化了应用的更新操作。像这种通过InvalidateRect和InvalidateRgn来使窗口区域无效，依赖于系统在合适的时机发送WM_PAINT消息的机 制实际上是一种异步工作方式，也就是说，在无效化窗口区域和发送WM_PAINT消息之间是有延迟的；有时候这种延迟并不是我们希望的，这时我们当然可以在无效化窗口区域后利用<br>SendMessage 发送一条WM_PAINT消息来强制立即重画<br>【注解：SendMessage会block到被发送的消息被处理完才返回，但是WM_PAINT消息的处理时间又是用户不可控制的：&#8220;<strong>GetMessage</strong> returns the <strong>WM_PAINT</strong> message when there are no other messages in the application's message queue, and <strong>DispatchMessage</strong> sends the message to the appropriate window procedure. &#8221;(MSDN原文)，那么也就是说，你调用SendMessage之后，这个方法需要等待多长时间才能返回是不可控制的。所以MSDN不推荐用户直接发送WM_PAINT消息：&#8220;The <strong>WM_PAINT</strong> message is generated by the system and should not be sent by an application&#8221;】<br>，但不如使用Windows GDI为我们提供的更方便和强大的函数：UpdateWindow和RedrawWindow。UpdateWindow会检查窗口的Update Region，当其不为空时才发送WM_PAINT消息；RedrawWindow则给我们更多的控制：是否重画非客户区和背景，是否总是发送WM_PAINT消息而不管Update Region是否为空等。</p>
<p>2. BeginPaint</p>
<p>BeginPaint和WM_PAINT消息紧密相关。试一试在WM_PAINT处理函数中不写BeginPaint会怎样？程序会像进入了一个死循环一样达到惊人的CPU占用率，你会发现程序总在处理一个接 一个的WM_PAINT消息。这是因为在通常情况下，当应用收到WM_PAINT消息时，窗口的Update Region都是非空的（如果为空就不需要发送WM_PAINT消息了），BeginPaint的一个作用就是把该Update Region置为空，这样如果不调用BeginPaint，窗口的Update Region就一直不为空，如前所述，系统就会一直发送WM_PAINT消息。</p>
<p>BeginPaint和WM_ERASEBKGND消息也有关系。当窗口的Update Region被标志为需要擦除背景时，BeginPaint会发送WM_ERASEBKGND消息来重画背景，同时在其返回信息里有一个标志表明窗口背景是否被重画过。当我们用InvalidateRect和InvalidateRgn来把指定区域加到Update Region中时，可以设置该区域是否需要被擦除背景，这样下一个BeginPaint就知道是否需要发送WM_ERASEBKGND消息了。</p>
<p>另外要注意的一点是，BeginPaint只能在WM_PAINT处理函数中使用。</p>
<img src ="http://www.cppblog.com/hugai/aggbug/86764.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/hugai/" target="_blank">悟山</a> 2009-06-04 17:21 <a href="http://www.cppblog.com/hugai/archive/2009/06/04/86764.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[图像处理]自适应局部图像阈值处理（Adaptive Local Thresholding）</title><link>http://www.cppblog.com/hugai/archive/2009/05/28/86018.html</link><dc:creator>悟山</dc:creator><author>悟山</author><pubDate>Thu, 28 May 2009 09:04:00 GMT</pubDate><guid>http://www.cppblog.com/hugai/archive/2009/05/28/86018.html</guid><wfw:comment>http://www.cppblog.com/hugai/comments/86018.html</wfw:comment><comments>http://www.cppblog.com/hugai/archive/2009/05/28/86018.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/hugai/comments/commentRss/86018.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/hugai/services/trackbacks/86018.html</trackback:ping><description><![CDATA[将一副灰度图像转换为只包含为黑白两色的二值图像称之为图像的阈值处理；这种处理有多种方式，最简单的就是设定一个静态的阈值，色素值大于该阈值的为白，否则该值的为黑色。但是在很多时候，这种简单的方法并不能得到很好的效果。在这篇文章里面我们介绍一种很简单的局部自适应性图像阈值化处理方法，该方法根据图像局部特点动态的调整其阈值，能够得到比较理想的阈值化处理效果。<br><br>该方法的思想是首先将图像分为一定大小的区块，这个可以根据情况选用，比如你可以选择3*3的矩阵，或者5*5的矩阵。选定好这些小块之后，我们计算这个小块中包围了中心像素点的其他像素点（或者用户也可以加其他的限定条件选择像素点）的灰度值的某种统计信息，比如灰度均值，或者灰度中间值，或者最大灰度与最小灰度之间的均值作为中间像素点的阈值。如果中间像素点的灰度大于该阈值，则中间像素被转换为白色点；反之，则转换为黑色点。<br>以ROUND(x)代表像素点x周围的所有像素点，以函数Statistic(ROUND(x))表示对上述的这些像素点的灰度值做统计运算，那么我们的算法思想可以描述为：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1（x&gt;Statistic(ROUND(x)))<br>x={<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0(x&lt;=Statistic(ROUND(x)))<br><br>在实际情况中，选用3*3的包围矩阵和取均值的统计算法可以得到比较理想的处理效果（处理效果的图片对比如下：<br>原图：<br><img height=432 alt="" src="http://www.cppblog.com/images/cppblog_com/hugai/1.jpg" width=576 border=0><br><br>处理后图片：<br><br><img height=432 alt="" src="http://www.cppblog.com/images/cppblog_com/hugai/2.jpg" width=576 border=0><br><br><br>）。 
<img src ="http://www.cppblog.com/hugai/aggbug/86018.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/hugai/" target="_blank">悟山</a> 2009-05-28 17:04 <a href="http://www.cppblog.com/hugai/archive/2009/05/28/86018.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]浅析本机API</title><link>http://www.cppblog.com/hugai/archive/2009/05/22/85450.html</link><dc:creator>悟山</dc:creator><author>悟山</author><pubDate>Fri, 22 May 2009 10:43:00 GMT</pubDate><guid>http://www.cppblog.com/hugai/archive/2009/05/22/85450.html</guid><wfw:comment>http://www.cppblog.com/hugai/comments/85450.html</wfw:comment><comments>http://www.cppblog.com/hugai/archive/2009/05/22/85450.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/hugai/comments/commentRss/85450.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/hugai/services/trackbacks/85450.html</trackback:ping><description><![CDATA[原文地址：<a href="http://www.xfocus.net/articles/200503/782.html">http://www.xfocus.net/articles/200503/782.html</a><br><br><br>创建时间：2005-03-09<br>文章属性：转载<br>文章提交：<a href="https://www.xfocus.net/bbs/index.php?lang=cn&amp;act=Profile&amp;do=03&amp;MID=82515"><u><font color=#0066cc>cisocker</font></u></a> (cisocker_at_163.com)<br><br>by sunwear [E.S.T]&nbsp;&nbsp;<br>2004/10/02&nbsp;&nbsp; <br>shellcoder@163.com<br><br>此文只能说是一篇笔记，是关于本机API的.本机API是除了Win32 API，NT平台开放了另一个基本接口。本机API也被很多人所熟悉，因为内核模式模块位于更低的系统级别，在那个级别上环境子系统是不可见的。尽管如此，并不需要驱动级别去访问这个接口，普通的Win32程序可以在任何时候向下调用本机API。并没有任何技术上的限制，只不过微软不支持这种应用开发方法。&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;User32.dll,kernel32.dll,shell32.dll,gdi32.dll,rpcrt4.dll,comctl32.dll,advapi32.dll,version.dll等dll代表了Win32 API的基本提供者。Win32 API中的所有调用最终都转向了ntdll.dll，再由它转发至ntoskrnl.exe。ntdll.dll是本机 API用户模式的终端。真正的接口在ntoskrnl.exe里完成。事实上，内核模式的驱动大部分时间调用这个模块，如果它们请求系统服务。Ntdll.dll的主要作用就是让内核函数的特定子集可以被用户模式下运行的程序调用。Ntdll.dll通过软件中断int 2Eh进入ntoskrnl.exe，就是通过中断门切换CPU特权级。比如kernel32.dll导出的函数DeviceIoControl()实际上调用ntdll.dll中导出的NtDeviceIoControlFile()，反汇编一下这个函数可以看到，EAX载入magic数0x38，实际上是系统调用号，然后EDX指向堆栈。目标地址是当前堆栈指针ESP+4，所以EDX指向返回地址后面一个，也就是指向在进入NtDeviceIoControlFile()之前存入堆栈的东西。事实上就是函数的参数。下一个指令是int 2Eh，转到中断描述符表IDT位置0x2E处的中断处理程序。<br><br>反编汇这个函数得到：<br><br>mov eax, 38h<br><br>lea edx, [esp+4]<br><br>int 2Eh<br><br>ret 28h<br><br>当然int 2E接口不仅仅是简单的API调用调度员，他是从用户模式进入内核模式的main gate。<br><br>W2k Native API由248个这么处理的函数组成，比NT 4.0多了37个。可以从ntdll.dll的导出列表中很容易认出来：前缀Nt。Ntdll.dll中导出了249个，原因在于NtCurrentTeb()为一个纯用户模式函数，所以不需要传给内核。令人惊奇的是，仅仅Native API的一个子集能够从内核模式调用。而另一方面，ntoskrnl.exe导出了两个Nt*符号，它们不存在于ntdll.dll中: NtBuildNumber, NtGlobalFlag。它们不指向函数，事实上，是指向ntoskrnl.exe的变量，可以被使用C编译器extern关键字的驱动模块导入。Ntdll.dll和ntoskrnl.exe中都有两种前缀Nt*,Zw*。事实上ntdll.dll中反汇编结果两者是一样的。而在ntoskrnl.exe中，nt前缀指向真正的代码，而zw还是一个int 2Eh的stub。也就是说zw*函数集通过用户模式到内核模式门传递的，而Nt*符号直接指向模式切换以后的代码。Ntdll.dll中的NtCurrentTeb()没有相对应的zw函数。Ntoskrnl并不导出配对的Nt/zw函数。有些函数只以一种方式出现。<br><br>2Eh中断处理程序把EAX里的值作为查找表中的索引，去找到最终的目标函数。这个表就是系统服务表SST，C的结构SYSTEM_SERVICE_TABLE的定义如下:清单也包含了结构SERVICE_DESCRIPTOR_TABLE中的定义，为SST数组第四个成员，前两个有着特别的用途。<br><br>typedef NTSTATUS (NTAPI *NTPROC) ( ) ；<br><br>typedef NTPROC *PNTPROC；<br><br>#define NTPROC_ sizeof (NTPROC)<br><br>typedef struct _SYSTEM_SERVICE_TABLE<br><br>{ PNTPROC ServiceTable; // 这里是入口指针数组<br><br>PDWORD CounterTable; // 此处是调用次数计数数组<br><br>DWORD ServiceLimit ; // 服务入口的个数<br><br>PBYTE ArgumentTable; // 服务参数字节数的数组<br><br>) SYSTEM_SERVICE_TABLE ,<br><br>* PSYSTEM_SERVICE_TABLE ,<br><br>* * PPSYSTEM_SERVICE_TABLE ;<br><br>/ / _ _ _ _ _ _ _ _ _ _ _ _<br><br>typedef struct _SERVICE_DESCRIPTOR_TABLE<br><br>{ SYSTEM_SERVICE_TABLE ntoskrnl ; // ntoskrnl所实现的系统服务，本机的API}<br><br>SYSTEM_SERVICE_TABLE win32k; // win32k所实现的系统服务<br><br>SYSTEM_SERVICE_TABLE Table3; // 未使用<br><br>SYSTEM_SERVICE_TABLE Table4; // 未使用<br><br>} SERVICE_DESCRIPTOR_TABLE ,<br><br>* PSERVICE_DESCRIPTOR_TABLE,<br><br>* PPSERVICE_DESCRIPTOR_TABLE ；<br><br>ntoskrnl通过KeServiceDescriptorTable符号,导出了主要SDT的一个指针。内核维护另外的一个SDT，就是KeServiceDescriptorTableShadow。但这个符号没有导出。要想在内核模式组件中存取主要SDT很简单，只需两行C语言的代码:<br><br>extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;<br><br>PSERVICE_DESCRIPTOR_TABLE psdt= KeServiceDescriptorTable;<br><br>NTPROC为本机 API的方便的占位符，他类似于Win32编程中的PROC。Native API正常的返回应该是一个NTSTATUS代码，他使用NTAPI调用约定，它和_stdcall一样。ServiceLimit成员有在ServiceTable数组里找到的入口数目。在2000下，默认值是248。ArgumentTable为BYTEs的数组，每一个对应于ServiceTable的位置并显示了在调用者堆栈里的参数比特数。这个信息与EDX结合，这是内核从调用者堆栈copy参数到自己的堆栈所需的。CounterTable成员在free buid的2000中并没有使用到，在debug build中，这个成员指向代表所有函数使用计数的DWORDS数组，这个信息能用于性能分析。<br>&nbsp;&nbsp;&nbsp;&nbsp;可以使用这个命令来显示:dd KeServiceDescriptorTable，调试器把此符号解析为0x8046e0c0。只有前四行是最重要的，对应那四个SDT成员。<br>&nbsp;&nbsp;&nbsp;&nbsp;运行这个命令:ln 8046e100，显示符号是KeServiceDescriptorTableShadow，说明第五个开始确实为内核维护的第二个SDT。主要的区别在于后一个包含了win32k.sys的入口，前一个却没有。在这两个表中，Table3与Table4都是空的。Ntoskrnl.exe提供了一个方便的API函数。这个函数的名字为：<br><br>&nbsp;&nbsp;&nbsp;&nbsp;KeAddSystemServiceTable<br>此函数去填充这些位置。<br><br>2Eh的中断处理标记是KisystemService()。这也是ntoskrnl.exe没有导出的内部的符号，但包含在2k符号文件中。关于KisystemService的操作如下：<br><br>1 从当前的线程控制块检索SDT指针<br><br>2 决定使用SDT中4个SST的其中一个。通过测试EAX中递送ID的第12和13位来决定。ID在0x0000-0x0fff的映射至ntoskrnl表格，ID在<br><br>0x1000与0x1ffff的分配给win32k表格。剩下的0x2000-0x2ffff与<br><br>0x3000-0x3ffff则是Table3和Table4保留。<br><br>3 通过选定SST中的ServiceLimit成员检查EAX的0－11位。如果ID超过了范围，返回错误代码为STATUS_INVALID_SYSTEM_SERVICE。<br><br>4 检查EAX中的参数堆栈指针与MmUserProbeAddress。这是一个ntoskrnl导出的全局变量。通常等于0x7FFF0000，如果参数指针不在这个地址之下，返回STATUS_ACCESS_VIOLATION。<br><br>5 查找ArgumentTable中的参数堆栈的字节数，从调用者的堆栈copy所有的参数至当前内核模式堆栈。<br><br>6 搜索serviceTable中的服务函数指针，并调用这个函数。<br><br>7 控制转到内部的函数KiserviceExit，在此次服务调用返回之后。<br><br>从对SDT的讨论可以看到与本机API一起还有第二个内核模式接口。这个接口把Win32子系统的图形设备接口和窗口管理器和内核模式组件Win32k连接起来。Win32k接口一样是基于int 2eh。本机API的服务号是从0x0000到0x0fff，win32k的服务号是从0x1000到0x1fff。(ddW32pServiceTable认定win32k.sys的符号可用。)win32k总共包含639个系统服务。<br><br><br>2Eh的处理过程没有使用全局SDT KeServiceDescriptorTable。<br><br>而是一个与线程相关的指针。显然，线程可以有不同得SDT相关到自身。线程初试化的时候,KeInitializeThread()把KeServiceDescriptorTable写到线程的控制块。尽管这样，这个默认设置之后可能被改变为其它值，例如KeServiceDescriptorTableShadow。<br><br><br>Windows 2000运行时库<br><br>Ntdll.dll至少导出了不少于1179个符号。其中的249/248是属于Nt*/zw*集合。所以还有682个函数不是通过int 2eh门中转。很显然，这么多的函数不依靠2k的内核。<br><br>其中一些是和c运行时库几乎一样的函数。其实ntoskrnl也实现了一些类似Ｃ运行时库的一些函数。可以通过ddk里的ntdll.lib来链接和使用这些函数。反汇编ntdll.dll与ntoskrnl.exe的Ｃ运行时函数能发现，ntdll.dll并不是依赖ntoskrnl.exe。这两个模块各自实现了这些函数。<br><br>除了Ｃ运行时库外，2000还提供了一个扩展的运行时函数集合。再一次，ntdll.dll与ntoskrnl.exe各自实现了它们。同样，实现集合有重复，但是并不完全匹配。这个集合的函数都是以Rtl开头的。2000运行时库包括一些辅助函数用于Ｃ运行时候无法完成的任务。例如有些处理安全事务，另外的操纵2000专用的数据结构，还有些支持内存管理。微软仅仅在DDK中记录了很有用的406个函数中的115个函数。<br><br>Ntdll.dll还提供了另外一个函数集合，以__e前缀开头。实际上它们用于浮点数模拟器。<br><br>还有很多的函数集合，所有这些函数的前缀如下：<br><br>__e(浮点模拟),Cc(Cache管理),Csr(c/s运行时库),Dbg(调试支持)，Ex(执行支持),FsRtl(文件系统运行时)，Hal(硬件抽象层),Inbv(系统初试化/vga启动驱动程序bootvid.dll),Init(系统初试化),Interlocked(线程安全变量操作),Io(IO管理器),Kd(内核调试器支持),Ke(内核例程),Ki(内核中断处理),Ldr(映象装载器),Lpc(本地过程调用),Lsa(本地安全授权),Mm(内存管理),Nls(国际化语言支持),Nt(NT本机API)，Ob(对象管理器),Pfx(前缀处理)，Po(电源管理),Ps(进程支持),READ_REGISTER_(从寄存器地址读)，Rtl(2k运行时库),Se(安全处理),WRITE_REGISTER_（写寄存器地址）,Zw(本机API的替换叫法)，&lt;其它&gt;(辅助函数和Ｃ运行时库)。<br><br>当编写从用户模式通过ntdll.dll或内核模式通过ntoskrnl.exe和2000内核交互的软件的时候，需要处理很多基本的数据结构，这些结构在Win32世界中很少见到。<br><br>常用数据结构<br><br>l&nbsp;&nbsp;&nbsp;&nbsp; 整数<br><br>ANSI字符是有符号的，而Unicode WCHAR是无符号的<br><br>MASM的TBYTE是80位的浮点数，用于高精度浮点运算单元操作，注意它与Win32的TBYTE（text byte）完全不同。<br><br>TABLE 2-3. Equivalent Integral Data Types<br><br>BITS&nbsp;&nbsp;&nbsp;&nbsp;MASM&nbsp;&nbsp; FUNDAMENTAL&nbsp;&nbsp;&nbsp;&nbsp;ALIAS #1&nbsp;&nbsp;&nbsp;&nbsp;ALIAS #2&nbsp;&nbsp;SIGNED<br><br>8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BYTE&nbsp;&nbsp;&nbsp;&nbsp;unsigned char&nbsp;&nbsp;UCHAR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CHAR<br>16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WORD&nbsp;&nbsp;&nbsp;&nbsp;unsigned short USHORT&nbsp;&nbsp;&nbsp;&nbsp; WCHAR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SHORT<br><br>32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp; unsigned long&nbsp;&nbsp;ULONG&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LONG<br><br>32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;&nbsp; unsigned int&nbsp;&nbsp;&nbsp;&nbsp;UINT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INT<br><br>64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;QWORD&nbsp;&nbsp; unsigned _int64 ULONGLONG DWORDLONG LONGLONG<br><br>80&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TBYTE&nbsp;&nbsp;&nbsp;&nbsp;N/A<br><br>typedef union _LARGE_INTEGER<br><br>{&nbsp;&nbsp;struct{<br><br>ULONG LowPart;<br><br>LONG HighPart；};<br><br>LONGLONG QuadPart;<br><br>}<br><br>LARGE_INTEGER , * PULARGE_INTEGER ;<br><br>typedef union _ULARGE_INTEGER{<br><br>struct{<br><br>ULONG LowPart;<br><br>ULONG HighPart;｝<br><br>ULONGLONG QuadPart;<br><br>}ULARGE_INTEGER, *PULARGE_INTEGER;<br><br>l&nbsp;&nbsp;&nbsp;&nbsp; 字符<br><br>&nbsp;&nbsp;&nbsp;&nbsp;Win32编程中PSTR用户CHAR*，PWSTR用于WCHAR*。取决于是否定义了UNICODE，PTSTR解释为PSTR或者PWSTR。在2k内核模式下，常用的数据类型是UNICODE_STRING，而STRING用来表示ANSI字符串:<br><br>typedef struct _UNICODE_STRING{<br><br>USHORT Length; //当前字节长度，不是字符！！！<br><br>USHORT MaximumLength; //Buffer的最大字节长度<br><br>PWSTR Buffer;}UNICODE_STRING , * PUNICODE_STRING ;<br><br>typedef struct _STRING{<br><br>USHORT Length;<br><br>USHORT MaximumLength;<br><br>PCHAR Buffer;}STRING, *PSTRING;<br><br>typedef STRING ANSI_STRING, *PANSI_STRING;<br><br>typedef STRING OEM_STRING, *POEM_STRING;<br><br>&nbsp;&nbsp;操纵函数:RtlCreatUnicodeString(),RtlInitUnicodeString(),<br><br>RtlCopyUnicodeString()等等<br><br>l&nbsp;&nbsp;&nbsp;&nbsp; 结构<br><br>许多内核API函数需要一个固定大小的OBJECT_ATTRIBUTES结构，比如NtOpenFile()。对象的属性是OBJ_*值的组合，可以从ntdef.h中查到。<br><br>IO_STATUS_BLOCK结构提供了所请求操作结果的信息，很简单，status成员包含一个NTSTATUS代码, 如果操作成功 information成员提供特定请求的信息。<br><br>还有一个结构是LIST_ENTRY，这是一个双向环链表。<br><br>typedef struct _OBJECT_ATTRIBUTES<br><br>{<br><br>ULONG Length;<br><br>HANDLE RootDirectory;<br><br>PUNICODE_STRING ObjectName;<br><br>ULONG Attributes;<br><br>PVOID SecurityDescriptor;<br><br>PVOID SecurityQualityOfService;<br><br>} OBJECT_ATTRIBDTES, *POBJECT_ ATTRIBUTES;<br><br>typedef struct _IO_STATUS_BLOCK<br><br>{<br><br>NTSTATDS Status;<br><br>ULONG Information;<br><br>}IO_STATUS_BLOCK , * PIO_STATUS_BLOCK ;<br><br>typedef struct _LIST_ENTRY<br><br>{<br><br>Struct _LIST_ENTRY *Flink;<br><br>Struct _LIST_ENTRY *Blink;<br><br>}LIST_ENTRY, *PLIST_ENTRY;<br><br>双向链表的典型例子就是进程和线程链。内部变量PsActiveProcessHead是一个LIST_ENTRY结构，在ntoskrnl.exe的数据段中，指定了系统进程列表的第一个成员。<br><br>CLIENT_ID结构由进程和线程ID组成。<br><br>typedef struct _CLIENT_ID<br><br>{ HANDLE UniqueProcess;<br><br>HANDLE UniqueThread;<br><br>)CLIENT_ID, *PCLIENT_ID;<br><br>想要从用户模式调用ntdll.dll中的API函数，必须考虑到以下四点:<br><br>1 SDK头文件没有包括这些函数的原型<br><br>2 这些函数使用的若干基本数据类型没有包括在SDK文件中<br><br>3 SDK和DDK头文件不兼容，不能在win32的c源文件包含ntddk.h中<br><br>4 ntdll.lib没有包括在VC的默认导入库列表中。<br><br>第4个很容易解决：#progma comment(linker,&#8220;/defaultlib:ntdll.lib&#8221;)<br><br>缺失的定义比较难解决，最简单的方法是写一个自定义的头文件，刚刚包含需要调用ntdll.dll中函数的定义。幸运的是，已经在光盘的w2k_def.h文件中做了这个工作。因为这个头文件将用于用户模式和内核模式程序，所以必须在用户模式代码中，#include&lt;w2k_def.h&gt;之前#define _USER_MODE_，使得DDK中出现而SDK中没有的定义可用。<br><br><br>本文部分翻译于一篇电子书&lt;win api about&gt;.也感谢朋友GameHunter这位英语极好的朋友帮忙.与Free的指导 
<img src ="http://www.cppblog.com/hugai/aggbug/85450.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/hugai/" target="_blank">悟山</a> 2009-05-22 18:43 <a href="http://www.cppblog.com/hugai/archive/2009/05/22/85450.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[C#学习笔记]在Vista或者Server2008下以Admin模式启动程序</title><link>http://www.cppblog.com/hugai/archive/2009/05/22/85447.html</link><dc:creator>悟山</dc:creator><author>悟山</author><pubDate>Fri, 22 May 2009 10:36:00 GMT</pubDate><guid>http://www.cppblog.com/hugai/archive/2009/05/22/85447.html</guid><wfw:comment>http://www.cppblog.com/hugai/comments/85447.html</wfw:comment><comments>http://www.cppblog.com/hugai/archive/2009/05/22/85447.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/hugai/comments/commentRss/85447.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/hugai/services/trackbacks/85447.html</trackback:ping><description><![CDATA[原文（参考文章）链接：<a href="http://www.codeproject.com/KB/vista-security/UAC_Shield_for_Elevation.aspx">http://www.codeproject.com/KB/vista-security/UAC_Shield_for_Elevation.aspx</a><br><br>Vista和Windows Server 2008上面系统的UAC（User&nbsp;Account Control）默认是开启的，用户在一般情况下并通过双击启动程序都不是以管理员模式运行。但是，在很多情况下，为了在程序里面访问系统的某些特定资源，需要当前程序的identity具有admin的权限。那么这就需要涉及到检测当前程序的执行用户是否处于管理员模式，在当前程序不处于admin模式的情况以admin模式下重启程序。<br><br>参考了<a href="http://www.codeproject.com/KB/vista-security/UAC_Shield_for_Elevation.aspx">http://www.codeproject.com/KB/vista-security/UAC_Shield_for_Elevation.aspx</a>这篇文章，做如下学习笔记。<br><br>为了检测当前进程的之行用户是否是管理员，需要用到CLR种System.Security.Principal名称空间种的WindowsIdentity类和WindowsPrincipal类。下面是代码，很好理解：<br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;IsAdmin()<br><img id=Codehighlighter1_30_255_Open_Image onclick="this.style.display='none'; Codehighlighter1_30_255_Open_Text.style.display='none'; Codehighlighter1_30_255_Closed_Image.style.display='inline'; Codehighlighter1_30_255_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_30_255_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_30_255_Closed_Text.style.display='none'; Codehighlighter1_30_255_Open_Image.style.display='inline'; Codehighlighter1_30_255_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_30_255_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_30_255_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WindowsIdentity&nbsp;identity&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;WindowsIdentity.GetCurrent();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WindowsPrincipal&nbsp;principle&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;WindowsPrincipal(identity);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;principle.IsInRole(WindowsBuiltInRole.Administrator);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div>
<br>如果当前进程不是处于管理员模式，那么我们可以重启这个程序。为了重启程序使用了System.Diagnostics名称空间下的Process类，Process类调用命令行下的"runas"命令，以管理员模式重新启动当前程序。代码如下，也很好理解：<br><br>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;RestartProcessElevated()<br><img id=Codehighlighter1_46_644_Open_Image onclick="this.style.display='none'; Codehighlighter1_46_644_Open_Text.style.display='none'; Codehighlighter1_46_644_Closed_Image.style.display='inline'; Codehighlighter1_46_644_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_46_644_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_46_644_Closed_Text.style.display='none'; Codehighlighter1_46_644_Open_Image.style.display='inline'; Codehighlighter1_46_644_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_46_644_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_46_644_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ProcessStartInfo&nbsp;info&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;ProcessStartInfo();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;info.UseShellExecute&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;info.WorkingDirectory&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;Environment.CurrentDirectory;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;info.FileName&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;System.Windows.Forms.Application.ExecutablePath;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;info.Verb&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">runas</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_353_404_Open_Image onclick="this.style.display='none'; Codehighlighter1_353_404_Open_Text.style.display='none'; Codehighlighter1_353_404_Closed_Image.style.display='inline'; Codehighlighter1_353_404_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_353_404_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_353_404_Closed_Text.style.display='none'; Codehighlighter1_353_404_Open_Image.style.display='inline'; Codehighlighter1_353_404_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_353_404_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_353_404_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Process.Start(info);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000">&nbsp;(System.ComponentModel.Win32Exception&nbsp;ex)<br><img id=Codehighlighter1_478_580_Open_Image onclick="this.style.display='none'; Codehighlighter1_478_580_Open_Text.style.display='none'; Codehighlighter1_478_580_Closed_Image.style.display='inline'; Codehighlighter1_478_580_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_478_580_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_478_580_Closed_Text.style.display='none'; Codehighlighter1_478_580_Open_Image.style.display='inline'; Codehighlighter1_478_580_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_478_580_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_478_580_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Exception:{0}</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;ex.Message);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.Windows.Forms.Application.Exit();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div>
<img src ="http://www.cppblog.com/hugai/aggbug/85447.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/hugai/" target="_blank">悟山</a> 2009-05-22 18:36 <a href="http://www.cppblog.com/hugai/archive/2009/05/22/85447.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转载]解剖XP最核心的dll——NTDLL.dll </title><link>http://www.cppblog.com/hugai/archive/2009/05/21/83573.html</link><dc:creator>悟山</dc:creator><author>悟山</author><pubDate>Thu, 21 May 2009 07:23:00 GMT</pubDate><guid>http://www.cppblog.com/hugai/archive/2009/05/21/83573.html</guid><wfw:comment>http://www.cppblog.com/hugai/comments/83573.html</wfw:comment><comments>http://www.cppblog.com/hugai/archive/2009/05/21/83573.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/hugai/comments/commentRss/83573.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/hugai/services/trackbacks/83573.html</trackback:ping><description><![CDATA[原文地址：<a href="http://club.it.sohu.com/read_art_sub.new.php?b=os&amp;a=114021&amp;NoCache=1">http://club.it.sohu.com/read_art_sub.new.php?b=os&amp;a=114021&amp;NoCache=1</a><br><br>打开NTDLL.dll,惊奇的发现原来CRT的许多基本函数居然都是在这里实现的！甚至包括qsort,ceil这样的函数，还有臭名昭著的strcpy（严格来讲，这只能怪使用者不当心）。堆的释放，进城管理，似乎都是在这。于是，我决定，仔细察看以下它，这1410个函数是做什么的<br><br><br>用户模式的代码在调用系统内核函数的时候，首先把一个叫做system&nbsp;call&nbsp;number的数放在EAX中，把参数放在其它的寄存器中了。然后调用INT&nbsp;2E中断。但是大部分应用程序并不需要直接这么做。通常都是在调用kernel32.dll等时由他们来调用INT&nbsp;2E.<br><br>内核模式的代码，做法稍微有点不同。他们通常调用由NTOSKRNL.EXE导出的NTDLL.dll中Zw开头的那一系列函数，比如ZwWaitForSingleObject，　反之，如果是用户级代码需要调用内核，就会利用INT&nbsp;2E调用WaitForSingleObject.对于许多函数的批量调用，你会明显发现&nbsp;Zw族要比Rtl族效率高很多。<br><br><br>可惜ntdll.dll中的大部分函数都是undocumented.<br>对于一部分得知其定义形式的函数，可以这样调用：<br>1.先将NTDLL.DLL读入&nbsp;LoadLibrary(TEXT("NTDLL.dll"))&nbsp;<br>2.利用GetProcAddress&nbsp;获取其函数入口地址<br>3.利用得到的函数指针调用<br><br>但是可以大致的分为几类吧<br>1&nbsp;PropertyLengthAsVariant&nbsp;&nbsp;它被排在了第一号，但是我就是不明白它是做什么的<br>2&nbsp;&nbsp;Csr（configuration&nbsp;status&nbsp;register？&nbsp;Command&nbsp;and&nbsp;Status&nbsp;Register？）系列&nbsp;&nbsp;<br>CsrAllocateCaptureBuffer&nbsp;CsrAllocateMessagePointer&nbsp;CsrCaptureMessageBuffer&nbsp;CsrCaptureMessageMultiUnicodeStringsInPlace&nbsp;<br>CsrCaptureMessageString&nbsp;CsrCaptureTimeout&nbsp;CsrClientCallServer&nbsp;CsrClientConnectToServer&nbsp;CsrFreeCaptureBuffer&nbsp;<br>CsrGetProcessId&nbsp;CsrIdentifyAlertableThread&nbsp;CsrNewThread&nbsp;CsrProbeForRead&nbsp;CsrProbeForWrite&nbsp;CsrSetPriorityClass<br><br>3&nbsp;Dbg系列&nbsp;调试函数<br>DbgBreakPoint&nbsp;DbgPrint&nbsp;DbgPrintEx&nbsp;DbgPrintReturnControlC&nbsp;DbgPrompt&nbsp;DbgQueryDebugFilterState&nbsp;DbgSetDebugFilterState&nbsp;<br>DbgUiConnectToDbg&nbsp;DbgUiContinue&nbsp;DbgUiConvertStateChangeStructure&nbsp;DbgUiDebugActiveProcess&nbsp;DbgUiGetThreadDebugObject&nbsp;<br>DbgUiIssueRemoteBreakin&nbsp;DbgUiRemoteBreakin&nbsp;DbgUiSetThreadDebugObject&nbsp;DbgUiStopDebugging&nbsp;DbgUiWaitStateChange&nbsp;DbgUserBreakPoint<br><br>4&nbsp;ki系列<br>KiRaiseUserExceptionDispatcher<br>KiUserApcDispatcher<br>KiUserCallbackDispatcher<br>KiUserExceptionDispatcher<br><br>5&nbsp;Ldr系列&nbsp;&nbsp;Loader&nbsp;APIs，共34个<br><br>API<br>NTDLL&nbsp;APIs<br>LoadResource<br>LdrAccessResource<br>LdrAlternateResourcesEnabled<br>DisableThreadLibraryCalls<br>LdrDisableThreadCalloutsForDll<br>LdrEnumResources<br>LdrFindAppCompatVariableInfo<br>LdrFindEntryForAddress<br>EnumResourceTypesW<br>LdrFindResourceDirectory_U<br>FindResourceExA<br>LdrFindResource_U<br>LdrFlushAlternateResourceModules<br>LdrGetAlternateResourceModuleHandle<br>GetModuleHandleForUnicodeString<br>LdrGetDllHandle<br>GetProcAddress<br>LdrGetProcedureAddress<br>LdrInitializeThunk<br>LoadLibraryEx&nbsp;(LOAD_LIBRARY_AS_DATAFILE)<br>LdrLoadAlternateResourceModule<br>LoadLibrary<br>LdrLoadDll<br>LdrProcessRelocationBlock<br>LdrQueryApplicationCompatibilityGoo<br>LdrQueryImageFileExecutionOptions<br>LdrQueryProcessModuleInformation<br>LdrRelocateImage<br>ExitProcess<br>LdrShutdownProcess<br>ExitThread<br>LdrShutdownThread<br>LdrUnloadAlternateResourceModule<br>FreeLibrary<br>LdrUnloadDll<br>LdrVerifyImageMatchesChecksum<br>LdrVerifyMappedImageMatchesChecksum<br><br><br>6&nbsp;Nls（National&nbsp;Language&nbsp;Support）系列&nbsp;&nbsp;代码页管理&nbsp;<br>NlsAnsiCodePage<br>NlsMbCodePageTag<br>NlsMbOemCodePageTag<br><br>7&nbsp;Nt系列&nbsp;共285个，大部分都是kernel32.dll,user32.dll等的核心实现<br><br>NtCreateFile,&nbsp;NtOpenFile,&nbsp;NtClose,&nbsp;NtWaitForSingleObject&nbsp;是kernel32.dll中许多用户级代码的核心实现。<br><br>NTSTATUS&nbsp;NtClose(&nbsp;HANDLE&nbsp;&nbsp;Handle);<br>竟然是CloseHandle&nbsp;的原身！唯一的缺点是该函数并没有导出库，如果要调用，就必须使用GetProcAddress&nbsp;来获得其函数指针然后调用。<br><br>NtCreateFile&nbsp;&nbsp;可以说是DDK的核心<br><br>RtlUnwind&nbsp;initiates&nbsp;an&nbsp;unwind&nbsp;of&nbsp;procedure&nbsp;call&nbsp;frames&nbsp;<br>结构化异常（Structured&nbsp;Exception&nbsp;Handling,&nbsp;SEH&nbsp;）的&nbsp;核心。<br><br>NTSTATUS&nbsp;NtWaitForSingleObject(&nbsp;&nbsp;HANDLE&nbsp;Handle,&nbsp;BOOLEAN&nbsp;Alertable,&nbsp;PLARGE_INTEGER&nbsp;Timeout);<br>Waits&nbsp;until&nbsp;the&nbsp;specified&nbsp;object&nbsp;attains&nbsp;a&nbsp;state&nbsp;of&nbsp;signaled<br>我想，信号同步等，应该与之有莫大的联系吧<br><br>8&nbsp;pfx&nbsp;不明白<br>PfxFindPrefix<br>PfxInitialize<br>PfxInsertPrefix<br>PfxRemovePrefix<br><br>9&nbsp;RestoreEm87Context&nbsp;SaveEm87Context<br><br>10&nbsp;rtl系列&nbsp;共506个。我想，rtl应该是runtime&nbsp;library的缩写吧。一个很庞大的函数族，<br>里面包含像&nbsp;RtlCreateUserProcess&nbsp;这样的一些很基本的函数，通常供内核模式的driver等调用<br>下面是一部分示例<br>APIs&nbsp;Forwarded&nbsp;to&nbsp;NTDLL<br><br>API<br>Destination<br>DeleteCriticalSection<br>Forwarded&nbsp;to&nbsp;NTDLL.RtlDeleteCriticalSection<br>EnterCriticalSection<br>Forwarded&nbsp;to&nbsp;NTDLL.RtlEnterCriticalSection<br>HeapAlloc<br>Forwarded&nbsp;to&nbsp;NTDLL.RtlAllocateHeap<br>HeapFree<br>Forwarded&nbsp;to&nbsp;NTDLL.RtlFreeHeap<br>HeapReAlloc<br>Forwarded&nbsp;to&nbsp;NTDLL.RtlReAllocateHeap<br>HeapSize<br>Forwarded&nbsp;to&nbsp;NTDLL.RtlSizeHeap<br>LeaveCriticalSection<br>Forwarded&nbsp;to&nbsp;NTDLL.RtlLeaveCriticalSection<br>RtlFillMemory<br>Forwarded&nbsp;to&nbsp;NTDLL.RtlFillMemory<br>RtlMoveMemory<br>Forwarded&nbsp;to&nbsp;NTDLL.RtlMoveMemory<br>RtlUnwind<br>Forwarded&nbsp;to&nbsp;NTDLL.RtlUnwind<br>RtlZeroMemory<br>Forwarded&nbsp;to&nbsp;NTDLL.RtlZeroMemory<br>SetCriticalSectionSpinCount<br>Forwarded&nbsp;to&nbsp;NTDLL.RtlSetCriticalSection-&nbsp;SpinCount<br>TryEnterCriticalSection<br>Forwarded&nbsp;to&nbsp;NTDLL.RtlTryEnterCriticalSection<br>VerSetConditionMask<br>Forwarded&nbsp;to&nbsp;NTDLL.VerSetConditionMask<br><br>11&nbsp;VerSetConditionMask&nbsp;用于确认系统信息<br>The&nbsp;VerSetConditionMask&nbsp;function&nbsp;sets&nbsp;the&nbsp;bits&nbsp;of&nbsp;a&nbsp;64-bit&nbsp;value&nbsp;to&nbsp;indicate&nbsp;the&nbsp;comparison&nbsp;operator&nbsp;to&nbsp;use&nbsp;for&nbsp;a&nbsp;specified&nbsp;operating&nbsp;system&nbsp;version&nbsp;attribute.&nbsp;<br>This&nbsp;function&nbsp;is&nbsp;used&nbsp;to&nbsp;build&nbsp;the&nbsp;dwlConditionMask&nbsp;parameter&nbsp;of&nbsp;the&nbsp;VerifyVersionInfo&nbsp;function.<br><br>12&nbsp;Zw系列&nbsp;共284个。前面已经说过，为可执行性系统服务提供内核模式的入口，&nbsp;为NTOSKRNL.EXE&nbsp;提供实现。由于是内核模式，所以在执行的时候并不检查用户是否有执行权限<br>13&nbsp;内部函数&nbsp;共116个。具体作用不明，很底层的东西。无法查到任何相关资料。无法得知与其相关的任何信息。<br>_CIcos&nbsp;<br>_CIlog&nbsp;<br>_CIpow&nbsp;<br>_CIsin&nbsp;<br>_CIsqrt&nbsp;<br>__eCommonExceptions&nbsp;<br>__eEmulatorInit&nbsp;<br>__eF2XM1&nbsp;<br>__eFABS&nbsp;<br>__eFADD32&nbsp;<br>__eFADD64&nbsp;<br>__eFADDPreg&nbsp;<br>__eFADDreg&nbsp;<br>__eFADDtop&nbsp;<br>__eFCHS&nbsp;<br>__eFCOM&nbsp;<br>__eFCOM32&nbsp;<br>__eFCOM64&nbsp;<br>__eFCOMP&nbsp;<br>__eFCOMP32&nbsp;<br>__eFCOMP64&nbsp;<br>__eFCOMPP&nbsp;<br>__eFCOS&nbsp;<br>__eFDECSTP&nbsp;<br>__eFDIV32&nbsp;<br>__eFDIV64&nbsp;<br>__eFDIVPreg&nbsp;<br>__eFDIVR32&nbsp;<br>__eFDIVR64&nbsp;<br>__eFDIVRPreg&nbsp;<br>__eFDIVRreg&nbsp;<br>__eFDIVRtop&nbsp;<br>__eFDIVreg&nbsp;<br>__eFDIVtop&nbsp;<br>__eFFREE&nbsp;<br>__eFIADD16&nbsp;<br>__eFIADD32&nbsp;<br>__eFICOM16&nbsp;<br>__eFICOM32&nbsp;<br>__eFICOMP16&nbsp;<br>__eFICOMP32&nbsp;<br>__eFIDIV16&nbsp;<br>__eFIDIV32&nbsp;<br>__eFIDIVR16&nbsp;<br>__eFIDIVR32&nbsp;<br>__eFILD16&nbsp;<br>__eFILD32&nbsp;<br>__eFILD64&nbsp;<br>__eFIMUL16&nbsp;<br>__eFIMUL32&nbsp;<br>__eFINCSTP&nbsp;<br>__eFINIT&nbsp;<br>__eFIST16&nbsp;<br>__eFIST32&nbsp;<br>__eFISTP16&nbsp;<br>__eFISTP32&nbsp;<br>__eFISTP64&nbsp;<br>__eFISUB16&nbsp;<br>__eFISUB32&nbsp;<br>__eFISUBR16&nbsp;<br>__eFISUBR32&nbsp;<br>__eFLD1&nbsp;<br>__eFLD32&nbsp;<br>__eFLD64&nbsp;<br>__eFLD80&nbsp;<br>__eFLDCW&nbsp;<br>__eFLDENV&nbsp;<br>__eFLDL2E&nbsp;<br>__eFLDLN2&nbsp;<br>__eFLDPI&nbsp;<br>__eFLDZ&nbsp;<br>__eFMUL32&nbsp;<br>__eFMUL64&nbsp;<br>__eFMULPreg&nbsp;<br>__eFMULreg&nbsp;<br>__eFMULtop&nbsp;<br>__eFPATAN&nbsp;<br>__eFPREM&nbsp;<br>__eFPREM1&nbsp;<br>__eFPTAN&nbsp;<br>__eFRNDINT&nbsp;<br>__eFRSTOR&nbsp;<br>__eFSAVE&nbsp;__eFSCALE&nbsp;__eFSIN&nbsp;__eFSQRT&nbsp;__eFST&nbsp;__eFST32&nbsp;__eFST64&nbsp;__eFSTCW&nbsp;__eFSTENV&nbsp;__eFSTP&nbsp;__eFSTP32&nbsp;__eFSTP64&nbsp;__eFSTP80<br>&nbsp;__eFSTSW&nbsp;__eFSUB32&nbsp;__eFSUB64&nbsp;__eFSUBPreg&nbsp;__eFSUBR32&nbsp;__eFSUBR64&nbsp;__eFSUBRPreg&nbsp;__eFSUBRreg&nbsp;__eFSUBRtop&nbsp;__eFSUBreg&nbsp;__eFSUBtop<br>&nbsp;__eFTST&nbsp;__eFUCOM&nbsp;__eFUCOMP&nbsp;__eFUCOMPP&nbsp;__eFXAM&nbsp;__eFXCH&nbsp;__eFXTRACT&nbsp;__eFYL2X&nbsp;__eFYL2XP1&nbsp;__eGetStatusWord&nbsp;<br><br>14&nbsp;一些CRT的基本函数&nbsp;共131个&nbsp;主要是字符串管理，还有些基本的数学函数<br>__isascii&nbsp;__iscsym&nbsp;__iscsymf&nbsp;__toascii&nbsp;_alldiv&nbsp;_alldvrm&nbsp;_allmul&nbsp;_alloca_probe&nbsp;_allrem&nbsp;_allshl&nbsp;_allshr&nbsp;_atoi64&nbsp;_aulldiv&nbsp;_aulldvrm&nbsp;_aullrem&nbsp;_aullshr&nbsp;_chkstk&nbsp;_fltused&nbsp;<br>_ftol&nbsp;_i64toa&nbsp;_i64tow&nbsp;_itoa&nbsp;_itow&nbsp;_lfind&nbsp;_ltoa&nbsp;_ltow&nbsp;_memccpy&nbsp;_memicmp&nbsp;_snprintf&nbsp;_snwprintf&nbsp;_splitpath&nbsp;_strcmpi&nbsp;_stricmp&nbsp;_strlwr&nbsp;_strnicmp&nbsp;_strupr&nbsp;_tolower&nbsp;<br>_toupper&nbsp;_ui64toa&nbsp;_ui64tow&nbsp;_ultoa&nbsp;_ultow&nbsp;_vsnprintf&nbsp;_vsnwprintf&nbsp;_wcsicmp&nbsp;_wcslwr&nbsp;_wcsnicmp&nbsp;_wcsupr&nbsp;_wtoi&nbsp;_wtoi64&nbsp;_wtol&nbsp;abs&nbsp;atan&nbsp;atoi&nbsp;atol&nbsp;bsearch&nbsp;ceil&nbsp;<br>cos&nbsp;fabs&nbsp;floor&nbsp;isalnum&nbsp;isalpha&nbsp;iscntrl&nbsp;isdigit&nbsp;isgraph&nbsp;islower&nbsp;isprint&nbsp;ispunct&nbsp;isspace&nbsp;isupper&nbsp;iswalpha&nbsp;iswctype&nbsp;iswdigit&nbsp;iswlower&nbsp;iswspace&nbsp;iswxdigit&nbsp;isxdigit&nbsp;labs&nbsp;log&nbsp;<br>mbstowcs&nbsp;memchr&nbsp;memcmp&nbsp;memcpy&nbsp;memmove&nbsp;memset&nbsp;pow&nbsp;qsort&nbsp;sin&nbsp;sprintf&nbsp;sqrt&nbsp;sscanf&nbsp;strcat&nbsp;strchr&nbsp;strcmp&nbsp;strcpy&nbsp;strcspn&nbsp;strlen&nbsp;strncat&nbsp;strncmp&nbsp;strncpy&nbsp;strpbrk&nbsp;<br>strrchr&nbsp;strspn&nbsp;strstr&nbsp;strtol&nbsp;strtoul&nbsp;swprintf&nbsp;tan&nbsp;tolower&nbsp;toupper&nbsp;towlower&nbsp;towupper&nbsp;vDbgPrintEx&nbsp;vDbgPrintExWithPrefix&nbsp;vsprintf&nbsp;wcscat&nbsp;wcschr&nbsp;wcscmp&nbsp;wcscpy&nbsp;<br>wcscspn&nbsp;wcslen&nbsp;wcsncat&nbsp;wcsncmp&nbsp;wcsncpy&nbsp;wcspbrk&nbsp;wcsrchr&nbsp;wcsspn&nbsp;wcsstr&nbsp;wcstol&nbsp;wcstombs&nbsp;wcstoul
<img src ="http://www.cppblog.com/hugai/aggbug/83573.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/hugai/" target="_blank">悟山</a> 2009-05-21 15:23 <a href="http://www.cppblog.com/hugai/archive/2009/05/21/83573.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>