﻿<?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++博客-牵着老婆满街逛-文章分类-Windows编程</title><link>http://www.cppblog.com/tx7do/category/1514.html</link><description>危机感是一种强大前进的动力！&lt;/br&gt;
GMail/GTalk: yanglinbo#google.com;&lt;/br&gt;
MSN/Email: tx7do#yahoo.com.cn;&lt;/br&gt;
QQ: 3 0 3 3 9 6 9 2 0 .</description><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 12:20:12 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 12:20:12 GMT</pubDate><ttl>60</ttl><item><title>开源日志系统log4cplus(七)</title><link>http://www.cppblog.com/tx7do/articles/11721.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 25 Aug 2006 20:51:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/11721.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/11721.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/11721.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/11721.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/11721.html</trackback:ping><description><![CDATA[
		<p>经过短暂的熟悉过程，log4cplus已经被成功应用到了我的项目中去了，效果还不错，：）除了上文提及的<br />功能之外，下面将介绍log4cplus提供的线程和套接字的使用情况。<br /></p>
		<pre>### NDC ###</pre>
		<pre>首先我们先了解一下log4cplus中嵌入诊断上下文（Nested Diagnostic Context），即NDC。对log系统而言，<br />当输入源可能不止一个，而只有一个输出时，往往需要分辩所要输出消息的来源，比如服务器处理来自不同<br />客户端的消息时就需要作此判断，NDC可以为交错显示的信息打上一个标记(stamp)， 使得辨认工作看起来<br />比较容易些，呵呵。这个标记是线程特有的，利用了线程局部存储机制，称为线程私有数据（Thread-specific<br /> Data，或TSD）。 看了一下源代码，相关定义如下，包括定义、初始化、获取、设置和清除操作：</pre>
		<pre>linux pthread</pre>
		<pre>
				<br />#   define LOG4CPLUS_THREAD_LOCAL_TYPE pthread_key_t*<br />#   define LOG4CPLUS_THREAD_LOCAL_INIT ::log4cplus::thread::createPthreadKey()<br />#   define LOG4CPLUS_GET_THREAD_LOCAL_VALUE( key ) pthread_getspecific(*key)<br />#   define LOG4CPLUS_SET_THREAD_LOCAL_VALUE( key, value ) pthread_setspecific(*key, value)<br />#   define LOG4CPLUS_THREAD_LOCAL_CLEANUP( key ) pthread_key_delete(*key)</pre>
		<pre>win32</pre>
		<pre>#   define LOG4CPLUS_THREAD_LOCAL_TYPE DWORD<br />#   define LOG4CPLUS_THREAD_LOCAL_INIT TlsAlloc()<br />#   define LOG4CPLUS_GET_THREAD_LOCAL_VALUE( key ) TlsGetValue(key)<br />#   define LOG4CPLUS_SET_THREAD_LOCAL_VALUE( key, value ) \<br />       TlsSetValue(key, static_cast<lpvoid />(value))<br />#   define LOG4CPLUS_THREAD_LOCAL_CLEANUP( key ) TlsFree(key)</pre>
		<pre>
				<br />使用起来比较简单，在某个线程中：</pre>
		<pre>    NDC&amp; ndc = log4cplus::getNDC();<br />    ndc.push("ur ndc string");<br />    LOG4CPLUS_DEBUG(logger, "this is a NDC test");</pre>
		<pre>    ... ...<br />    <br />    ndc.pop();<br />    <br />    ... ...<br />    <br />    LOG4CPLUS_DEBUG(logger, "There should be no NDC...");<br />    ndc.remove();<br />    <br />当设定输出格式(Layout)为TTCCLayout时，输出如下：</pre>
		<pre>10-21-04 21:32:58, [3392] DEBUG test <ur string="" ndc="" /> - this is a NDC test<br />10-21-04 21:32:58, [3392] DEBUG test &lt;&gt; - There should be no NDC...</pre>
		<pre>也可以在自定义的输出格式中使用NDC(用%x) ，比如：</pre>
		<pre>    ... ...<br />    <br />    std::string pattern = "NDC:[%x]  - %m %n";<br />    std::auto_ptr<layout /> _layout(new PatternLayout(pattern));</pre>
		<pre>    ... ...<br />    <br />    LOG4CPLUS_DEBUG(_logger, "This is the FIRST log message...")<br />    NDC&amp; ndc = log4cplus::getNDC();<br />    ndc.push("ur ndc string");<br />    LOG4CPLUS_WARN(_logger, "This is the SECOND log message...")<br />    ndc.pop();<br />    ndc.remove();<br />    <br />    ... ...<br />    <br />输出如下：</pre>
		<pre>NDC:[]  - This is the FIRST log message...<br />NDC:[ur ndc string]  - This is the SECOND log message...</pre>
		<pre>
				<br />另外一种更简单的使用方法是在线程中直接用NDCContextCreator：</pre>
		<pre>    NDCContextCreator _first_ndc("ur ndc string");<br />    LOG4CPLUS_DEBUG(logger, "this is a NDC test")<br />    <br />不必显式地调用push/pop了，而且当出现异常时，能够确保push与pop的调用是匹配的。</pre>
		<pre>    <br />### 线程 ###</pre>
		<pre>线程是log4cplus中的副产品， 而且仅作了最基本的实现，使用起来也异常简单，只要且必须要<br />在派生类中重载run函数即可：</pre>
		<pre>class TestThread : public AbstractThread<br />{<br />public:</pre>
		<pre>    virtual void run();</pre>
		<pre>};</pre>
		<pre>
				<br />void TestThread::run()<br />{<br />    /* do sth. */<br />    ... ...</pre>
		<pre>}</pre>
		<pre>log4cplus的线程没有考虑同步、死锁，有互斥，实现线程切换的小函数挺别致的：</pre>
		<pre>void log4cplus::thread::yield()<br />{<br />#if defined(LOG4CPLUS_USE_PTHREADS)<br />    ::sched_yield();<br />#elif defined(LOG4CPLUS_USE_WIN32_THREADS)<br />    ::Sleep(0);<br />#endif<br />}</pre>
		<pre>
				<br />### 套接字 ###</pre>
		<pre>套接字也是log4cplus中的副产品，在namespace log4cplus::helpers中，实现了C/S方式的日志记录。</pre>
		<pre>1. 客户端程序需要做的工作：</pre>
		<pre>/* 定义一个SocketAppender类型的挂接器 */<br />SharedAppenderPtr _append(new SocketAppender(host, 8888, "ServerName"));</pre>
		<pre>/* 把_append加入到logger中 */<br />Logger::getRoot().addAppender(_append);</pre>
		<pre>/*  SocketAppender类型不需要Layout, 直接调用宏就可以将信息发往loggerServer了 */<br />LOG4CPLUS_INFO(Logger::getRoot(), "This is a test: ")</pre>
		<pre>
				<br />【注】 这里对宏的调用其实是调用了SocketAppender::append，里面有一个数据传输约定，即先发送<br />一个后续数据的总长度，然后再发送实际的数据：</pre>
		<pre>    ... ...</pre>
		<pre>    SocketBuffer buffer = convertToBuffer(event, serverName);<br />    SocketBuffer msgBuffer(LOG4CPLUS_MAX_MESSAGE_SIZE);</pre>
		<pre>    msgBuffer.appendSize_t(buffer.getSize());<br />    msgBuffer.appendBuffer(buffer);<br />   <br />    ... ...</pre>
		<pre>
				<br />2. 服务器端程序需要做的工作：</pre>
		<pre>/* 定义一个ServerSocket */<br />ServerSocket serverSocket(port);</pre>
		<pre> </pre>
		<pre>/* 调用accept函数创建一个新的socket与客户端连接 */<br />Socket sock = serverSocket.accept();</pre>
		<pre>
				<br />此后即可用该sock进行数据read/write了,形如：</pre>
		<pre>SocketBuffer msgSizeBuffer(sizeof(unsigned int));</pre>
		<pre>if(!clientsock.read(msgSizeBuffer))<br />{<br />    return;<br />}</pre>
		<pre>unsigned int msgSize = msgSizeBuffer.readInt();</pre>
		<pre>SocketBuffer buffer(msgSize);</pre>
		<pre>if(!clientsock.read(buffer))<br />{<br />    return;<br />}</pre>
		<pre>为了将读到的数据正常显示出来，需要将SocketBuffer存放的内容转换成InternalLoggingEvent格式：</pre>
		<pre>spi::InternalLoggingEvent event = readFromBuffer(buffer);</pre>
		<pre>然后输出：<br />Logger logger = Logger::getInstance(event.getLoggerName());<br />logger.callAppenders(event);</pre>
		<pre>
				<br />【注】 read/write是按照阻塞方式实现的，意味着对其调用直到满足了所接收或发送的个数才返回。</pre>
<img src ="http://www.cppblog.com/tx7do/aggbug/11721.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-08-26 04:51 <a href="http://www.cppblog.com/tx7do/articles/11721.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源日志系统log4cplus(四)</title><link>http://www.cppblog.com/tx7do/articles/11718.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 25 Aug 2006 20:50:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/11718.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/11718.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/11718.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/11718.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/11718.html</trackback:ping><description><![CDATA[
		<p>将log信息记录到文件应该说是日志系统的一个基本功能，log4cplus在此基础上，提供了更多的功能，可以按照你预先设定的大小来决定是否转储，当超过该大小，后续log信息会另存到新文件中，依次类推；或者按照日期来决定是否转储。本文将详细介绍这些用法。</p>
		<br />
		<pre>
				<br />### 如何将log记录到文件 ###</pre>
		<pre>我们在例5中给出了一个将log记录到文件的例子，用的是FileAppender类实现的，log4cplus提供了三个类用于<br />文件操作，它们是FileAppender类、RollingFileAppender类、DailyRollingFileAppender类。</pre>
		<pre>1. FileAppender类</pre>
		<pre>实现了基本的文件操作功能，构造函数如下：</pre>
		<pre>FileAppender(const log4cplus::tstring&amp; filename,<br />                     LOG4CPLUS_OPEN_MODE_TYPE mode = LOG4CPLUS_FSTREAM_NAMESPACE::ios::trunc,<br />                     bool immediateFlush = true);<br />                     <br />filename       : 文件名<br />mode           : 文件类型，可选择的文件类型包括app、ate、binary、in、out、trunc，因为实际上只是对<br />                 stl的一个简单包装，呵呵，这里就不多讲了。缺省是trunc，表示将先前文件删除。<br />immediateFlush ：缓冲刷新标志，如果为true表示每向文件写一条记录就刷新一次缓存，否则直到FileAppender<br />                 被关闭或文件缓存已满才更新文件，一般是要设置true的，比如你往文件写的过程中出现<br />                 了错误（如程序非正常退出），即使文件没有正常关闭也可以保证程序终止时刻之前的所有<br />                 记录都会被正常保存。</pre>
		<pre>FileAppender类的使用情况请参考例5，这里不再赘述。</pre>
		<pre>
				<br />2. RollingFileAppender类</pre>
		<pre>构造函数如下：<br />log4cplus::RollingFileAppender::RollingFileAppender(const log4cplus::tstring&amp; filename,<br />                                                    long maxFileSize,<br />                                                    int maxBackupIndex,<br />                                                    bool immediateFlush)</pre>
		<pre>filename       : 文件名<br />maxFileSize    : 文件的最大尺寸<br />maxBackupIndex : 最大记录文件数<br />immediateFlush : 缓冲刷新标志<br />                                                    <br />RollingFileAppender类可以根据你预先设定的大小来决定是否转储，当超过该大小，后续log信息会另存到新<br />文件中，除了定义每个记录文件的大小之外，你还要确定在RollingFileAppender类对象构造时最多需要多少个<br />这样的记录文件(maxBackupIndex+1)，当存储的文件数目超过maxBackupIndex+1时，会删除最早生成的文件，<br />保证整个文件数目等于maxBackupIndex+1。然后继续记录，比如以下代码片段：</pre>
		<pre>    ... ...<br />    <br />    #define LOOP_COUNT 200000<br />    <br />    SharedAppenderPtr _append(new RollingFileAppender("Test.log", 5*1024, 5));<br />    _append-&gt;setName("file test");<br />    _append-&gt;setLayout( std::auto_ptr<layout />(new TTCCLayout()) );<br />    Logger::getRoot().addAppender(_append);</pre>
		<pre>    Logger root = Logger::getRoot();<br />    Logger test = Logger::getInstance("test");<br />    Logger subTest = Logger::getInstance("test.subtest");</pre>
		<pre>    for(int i=0; i<loop_count; />    {<br />        NDCContextCreator _context("loop");<br />        LOG4CPLUS_DEBUG(subTest, "Entering loop #" &lt;&lt; i)<br />    }<br />    <br />    ... ...<br />    </pre>
		<pre>运行结果：</pre>
		<pre>运行后会产生6个输出文件，Test.log、Test.log.1、Test.log.2、Test.log.3、Test.log.4、Test.log.5<br />其中Test.log存放着最新写入的信息，而最后一个文件中并不包含第一个写入信息，说明已经被不断更新了。<br />需要指出的是，这里除了Test.log之外，每个文件的大小都是200K,而不是我们想像中的5K，这是因为<br />log4cplus中隐含定义了文件的最小尺寸是200K，只有大于200K的设置才生效，&lt;= 200k的设置都会被认为是<br />200K.</pre>
		<pre>
				<br />3. DailyRollingFileAppender类</pre>
		<pre>构造函数如下：<br />DailyRollingFileAppender::DailyRollingFileAppender(const log4cplus::tstring&amp; filename,<br />                                                   DailyRollingFileSchedule schedule,<br />                                                   bool immediateFlush,<br />                                                   int maxBackupIndex)<br />                                                   <br />filename       : 文件名<br />schedule       : 存储频度<br />immediateFlush : 缓冲刷新标志<br />maxBackupIndex : 最大记录文件数</pre>
		<pre>DailyRollingFileAppender类可以根据你预先设定的频度来决定是否转储，当超过该频度，后续log信息会另存<br />到新文件中，这里的频度包括：MONTHLY（每月）、WEEKLY（每周）、DAILY（每日）、TWICE_DAILY（每两天）、<br />HOURLY（每时）、MINUTELY（每分）。maxBackupIndex的含义同上所述，比如以下代码片段：</pre>
		<pre>    ... ...<br />    <br />    SharedAppenderPtr _append(new DailyRollingFileAppender("Test.log", MINUTELY, true, 5));<br />    _append-&gt;setName("file test");<br />    _append-&gt;setLayout( std::auto_ptr<layout />(new TTCCLayout()) );<br />    Logger::getRoot().addAppender(_append);</pre>
		<pre>    Logger root = Logger::getRoot();<br />    Logger test = Logger::getInstance("test");<br />    Logger subTest = Logger::getInstance("test.subtest");</pre>
		<pre>    for(int i=0; i<loop_count; />    {<br />        NDCContextCreator _context("loop");<br />        LOG4CPLUS_DEBUG(subTest, "Entering loop #" &lt;&lt; i)<br />    }<br />    <br />    ... ...</pre>
		<pre>
				<br />运行结果：</pre>
		<pre>运行后会以分钟为单位，分别生成名为Test.log.2004-10-17-03-03、Test.log.2004-10-17-03-04和<br />Test.log.2004-10-17-03-05这样的文件。</pre>
		<pre>需要指出的是，刚看到按照频度（如HOURLY、MINUTELY）转储这样的概念，以为log4cplus提供了内部定时器，<br />感觉很奇怪，因为日志系统不应该主动记录，而loging事件总是应该被动触发的啊。仔细看了源代码后才知道<br />这里的"频度"并不是你写入文件的速度，其实是否转储的标准并不依赖你写入文件的速度，而是依赖于写入<br />的那一时刻是否满足了频度条件，即是否超过了以分钟、小时、周、月为单位的时间刻度，如果超过了就另存。</pre>
		<pre>本部分详细介绍log信息的几种文件操作方式，下面将重点介绍一下如何有选择地控制log信息的输出。</pre>
<img src ="http://www.cppblog.com/tx7do/aggbug/11718.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-08-26 04:50 <a href="http://www.cppblog.com/tx7do/articles/11718.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源日志系统log4cplus(五)</title><link>http://www.cppblog.com/tx7do/articles/11719.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 25 Aug 2006 20:50:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/11719.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/11719.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/11719.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/11719.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/11719.html</trackback:ping><description><![CDATA[
		<pre>日志系统的另一个基本功能就是能够让使用者按照自己的意愿来控制什么时候，哪些log信息可以输出。<br />如果能够让用户在任意时刻设置允许输出的LogLevel的信息就好了，log4cplus通过LogLevelManager、<br />LogLog、Filter三种方式实现了上述功能。</pre>
		<br />
		<pre>
				<br />### 优先级控制 ###</pre>
		<pre>在研究LogLevelManager之前，首先介绍一下log4cplus中logger的存储机制，在log4cplus中，所有<br />logger都通过一个层次化的结构（其实内部是hash表）来组织的，有一个Root级别的logger,可以通<br />过以下方法获取：</pre>
		<pre>    Logger root = Logger::getRoot();<br />    <br />用户定义的logger都有一个名字与之对应，比如：</pre>
		<pre>    Logger test = Logger::getInstance("test");<br />    <br />可以定义该logger的子logger:</pre>
		<pre>    Logger subTest = Logger::getInstance("test.subtest");<br />    <br />注意Root级别的logger只有通过getRoot方法获取，Logger::getInstance("root")获得的是它的<br />子对象而已。有了这些具有父子关系的logger之后可分别设置其LogLevel,比如：</pre>
		<pre>root.setLogLevel( ... );<br />Test.setLogLevel( ... );<br />subTest.setLogLevel( ... );</pre>
		<pre>
				<br />logger的这种父子关联性会体现在优先级控制方面，log4cplus将输出的log信息按照LogLevel<br />（从低到高）分为：</pre>
		<pre>NOT_SET_LOG_LEVEL (   -1) ：接受缺省的LogLevel，如果有父logger则继承它的LogLevel<br />ALL_LOG_LEVEL     (    0) ：开放所有log信息输出<br />TRACE_LOG_LEVEL   (    0) ：开放trace信息输出(即ALL_LOG_LEVEL)<br />DEBUG_LOG_LEVEL   (10000) ：开放debug信息输出<br />INFO_LOG_LEVEL    (20000) ：开放info信息输出<br />WARN_LOG_LEVEL    (30000) ：开放warning信息输出<br />ERROR_LOG_LEVEL   (40000) ：开放error信息输出<br />FATAL_LOG_LEVEL   (50000) ：开放fatal信息输出<br />OFF_LOG_LEVEL     (60000) ：关闭所有log信息输出</pre>
		<pre>LogLevelManager负责设置logger的优先级，各个logger可以通过setLogLevel设置自己的优先级，<br />当某个logger的LogLevel设置成NOT_SET_LOG_LEVEL时，该logger会继承父logger的优先级，另外，<br />如果定义了重名的多个logger, 对其中任何一个的修改都会同时改变其它logger,我们举例说明：</pre>
		<pre>〖例6〗</pre>
		<pre>#include "log4cplus/logger.h"<br />#include "log4cplus/consoleappender.h"<br />#include "log4cplus/loglevel.h"<br />#include &lt;iostream&gt;<iostream /></pre>
		<pre>using namespace std;<br />using namespace log4cplus;</pre>
		<pre>int main()<br />{<br />    SharedAppenderPtr _append(new ConsoleAppender());<br />    _append-&gt;setName("test");<br />    Logger::getRoot().addAppender(_append);<br />    Logger root = Logger::getRoot();</pre>
		<pre>    Logger test = Logger::getInstance("test");<br />    Logger subTest = Logger::getInstance("test.subtest");<br />    LogLevelManager&amp; llm = getLogLevelManager();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "Before Setting, Default LogLevel" &lt;&lt; endl;<br />    LOG4CPLUS_FATAL(root, "root: " &lt;&lt; llm.toString(root.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test: " &lt;&lt; llm.toString(test.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test.subtest: " &lt;&lt; llm.toString(subTest.getChainedLogLevel()))</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "Setting test.subtest to WARN" &lt;&lt; endl;<br />    subTest.setLogLevel(WARN_LOG_LEVEL);<br />    LOG4CPLUS_FATAL(root, "root: " &lt;&lt; llm.toString(root.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test: " &lt;&lt; llm.toString(test.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test.subtest: " &lt;&lt; llm.toString(subTest.getChainedLogLevel()))</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "Setting test.subtest to TRACE" &lt;&lt; endl;<br />    test.setLogLevel(TRACE_LOG_LEVEL);<br />    LOG4CPLUS_FATAL(root, "root: " &lt;&lt; llm.toString(root.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test: " &lt;&lt; llm.toString(test.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test.subtest: " &lt;&lt; llm.toString(subTest.getChainedLogLevel()))</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "Setting test.subtest to NO_LEVEL" &lt;&lt; endl;<br />    subTest.setLogLevel(NOT_SET_LOG_LEVEL);<br />    LOG4CPLUS_FATAL(root, "root: " &lt;&lt; llm.toString(root.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test: " &lt;&lt; llm.toString(test.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test.subtest: " &lt;&lt; llm.toString(subTest.getChainedLogLevel()) &lt;&lt; '\n')</pre>
		<pre>    cout &lt;&lt; "create a logger test_bak, named \"test_\", too. " &lt;&lt; endl;<br />    Logger test_bak = Logger::getInstance("test");<br />    cout &lt;&lt; "Setting test to INFO, so test_bak also be set to INFO" &lt;&lt; endl;<br />    test.setLogLevel(INFO_LOG_LEVEL);<br />    LOG4CPLUS_FATAL(root, "test: " &lt;&lt; llm.toString(test.getChainedLogLevel()))<br />    LOG4CPLUS_FATAL(root, "test_bak: " &lt;&lt; llm.toString(test_bak.getChainedLogLevel()))</pre>
		<pre>    return 0;<br />}</pre>
		<pre>输出结果：</pre>
		<pre>Before Setting, Default LogLevel<br />FATAL - root: DEBUG<br />FATAL - test: DEBUG<br />FATAL - test.subtest: DEBUG</pre>
		<pre>Setting test.subtest to WARN<br />FATAL - root: DEBUG<br />FATAL - test: DEBUG<br />FATAL - test.subtest: WARN</pre>
		<pre>Setting test.subtest to TRACE<br />FATAL - root: DEBUG<br />FATAL - test: TRACE<br />FATAL - test.subtest: WARN</pre>
		<pre>Setting test.subtest to NO_LEVEL<br />FATAL - root: DEBUG<br />FATAL - test: TRACE<br />FATAL - test.subtest: TRACE</pre>
		<pre>create a logger test_bak, named "test_", too.<br />Setting test to INFO, so test_bak also be set to INFO<br />FATAL - test: INFO<br />FATAL - test_bak: INFO</pre>
		<pre>
				<br />下面的例子演示了如何通过设置LogLevel来控制用户的log信息输出：</pre>
		<pre>〖例7〗</pre>
		<pre>#include "log4cplus/logger.h"<br />#include "log4cplus/consoleappender.h"<br />#include "log4cplus/loglevel.h"<br />#include &lt;iostream&gt;<iostream /></pre>
		<pre>using namespace std;<br />using namespace log4cplus;</pre>
		<pre>void ShowMsg(void)<br />{<br />    LOG4CPLUS_TRACE(Logger::getRoot(),"info")<br />    LOG4CPLUS_DEBUG(Logger::getRoot(),"info")<br />    LOG4CPLUS_INFO(Logger::getRoot(),"info")<br />    LOG4CPLUS_WARN(Logger::getRoot(),"info")<br />    LOG4CPLUS_ERROR(Logger::getRoot(),"info")<br />    LOG4CPLUS_FATAL(Logger::getRoot(),"info")<br />}</pre>
		<pre>int main()<br />{<br />    SharedAppenderPtr _append(new ConsoleAppender());<br />    _append-&gt;setName("test");<br />    _append-&gt;setLayout(std::auto_ptr<layout />(new TTCCLayout()));<br />    Logger root = Logger::getRoot();<br />    root.addAppender(_append);</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "all-log allowed" &lt;&lt; endl;<br />    root.setLogLevel(ALL_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "trace-log and above allowed" &lt;&lt; endl;<br />    root.setLogLevel(TRACE_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "debug-log and above allowed" &lt;&lt; endl;<br />    root.setLogLevel(DEBUG_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "info-log and above allowed" &lt;&lt; endl;<br />    root.setLogLevel(INFO_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "warn-log and above allowed" &lt;&lt; endl;<br />    root.setLogLevel(WARN_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "error-log and above allowed" &lt;&lt; endl;<br />    root.setLogLevel(ERROR_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "fatal-log and above allowed" &lt;&lt; endl;<br />    root.setLogLevel(FATAL_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    cout &lt;&lt; endl &lt;&lt; "log disabled" &lt;&lt; endl;<br />    root.setLogLevel(OFF_LOG_LEVEL);<br />    ShowMsg();</pre>
		<pre>    return 0;<br />}</pre>
		<pre>输出结果：</pre>
		<pre>all-log allowed<br />10-17-04 10:11:40,587 [1075298944] TRACE root &lt;&gt; - info<br />10-17-04 10:11:40,590 [1075298944] DEBUG root &lt;&gt; - info<br />10-17-04 10:11:40,591 [1075298944] INFO root &lt;&gt; - info<br />10-17-04 10:11:40,591 [1075298944] WARN root &lt;&gt; - info<br />10-17-04 10:11:40,592 [1075298944] ERROR root &lt;&gt; - info<br />10-17-04 10:11:40,592 [1075298944] FATAL root &lt;&gt; - info</pre>
		<pre>trace-log and above allowed<br />10-17-04 10:11:40,593 [1075298944] TRACE root &lt;&gt; - info<br />10-17-04 10:11:40,593 [1075298944] DEBUG root &lt;&gt; - info<br />10-17-04 10:11:40,594 [1075298944] INFO root &lt;&gt; - info<br />10-17-04 10:11:40,594 [1075298944] WARN root &lt;&gt; - info<br />10-17-04 10:11:40,594 [1075298944] ERROR root &lt;&gt; - info<br />10-17-04 10:11:40,594 [1075298944] FATAL root &lt;&gt; - info</pre>
		<pre>debug-log and above allowed<br />10-17-04 10:11:40,595 [1075298944] DEBUG root &lt;&gt; - info<br />10-17-04 10:11:40,595 [1075298944] INFO root &lt;&gt; - info<br />10-17-04 10:11:40,596 [1075298944] WARN root &lt;&gt; - info<br />10-17-04 10:11:40,596 [1075298944] ERROR root &lt;&gt; - info<br />10-17-04 10:11:40,596 [1075298944] FATAL root &lt;&gt; - info</pre>
		<pre>info-log and above allowed<br />10-17-04 10:11:40,597 [1075298944] INFO root &lt;&gt; - info<br />10-17-04 10:11:40,597 [1075298944] WARN root &lt;&gt; - info<br />10-17-04 10:11:40,597 [1075298944] ERROR root &lt;&gt; - info<br />10-17-04 10:11:40,598 [1075298944] FATAL root &lt;&gt; - info</pre>
		<pre>warn-log and above allowed<br />10-17-04 10:11:40,598 [1075298944] WARN root &lt;&gt; - info<br />10-17-04 10:11:40,598 [1075298944] ERROR root &lt;&gt; - info<br />10-17-04 10:11:40,599 [1075298944] FATAL root &lt;&gt; - info</pre>
		<pre>error-log and above allowed<br />10-17-04 10:11:40,599 [1075298944] ERROR root &lt;&gt; - info<br />10-17-04 10:11:40,600 [1075298944] FATAL root &lt;&gt; - info</pre>
		<pre>fatal-log and above allowed<br />10-17-04 10:11:40,600 [1075298944] FATAL root &lt;&gt; - info</pre>
		<pre>log disabled</pre>
		<pre> </pre>
		<pre>用户也可以自行定义LogLevel，操作比较简单，首先要定义LEVEL值，比如HELLO_LOG_LEVEL定义如下：</pre>
		<pre>/* DEBUG_LOG_LEVEL  &lt; HELLO_LOG_LEVEL &lt; INFO_LOG_LEVEL */<br />const LogLevel HELLO_LOG_LEVEL = 15000;</pre>
		<pre>然后定义以下宏即可：</pre>
		<pre>/* define MACRO LOG4CPLUS_HELLO */<br />#define LOG4CPLUS_HELLO(logger, logEvent) \<br />    if(logger.isEnabledFor(HELLO_LOG_LEVEL)) { \<br />        log4cplus::tostringstream _log4cplus_buf; \<br />        _log4cplus_buf &lt;&lt; logEvent; \<br /> logger.forcedLog(HELLO_LOG_LEVEL, _log4cplus_buf.str(), __FILE__, __LINE__); \<br />    }</pre>
		<pre>不过log4cplus没有提供给用户一个接口来实现LEVEL值与字符串的转换，所以当带格式输出LogLevel字符<br />串时候会显示"UNKNOWN"， 不够理想。比如用TTCCLayout控制输出的结果可能会如下所示：</pre>
		<pre>10-17-04 11:17:51,124 [1075298944] UNKNOWN root &lt;&gt; - info</pre>
		<pre>而不是期望的以下结果：<br />10-17-04 11:17:51,124 [1075298944] HELLO root &lt;&gt; - info</pre>
		<pre>要想实现第二种结果，按照log4cplus现有的接口机制，只能改其源代码后重新编译，方法是在loglevel.cxx<br />中加入：</pre>
		<pre>#define _HELLO_STRING LOG4CPLUS_TEXT("HELLO")</pre>
		<pre>然后修改log4cplus::tstring  defaultLogLevelToStringMethod(LogLevel ll)函数，增加一个判断：</pre>
		<pre>case HELLO_LOG_LEVEL:    return _HELLO_STRING;</pre>
		<pre>重新编译log4cplus源代码后生成库文件，再使用时即可实现满意效果。</pre>
		<pre>
				<br />### 调试模式 ###</pre>
		<pre>即通过loglog来控制输出调试、警告或错误信息，见例4，这里不再赘述。</pre>
		<pre> </pre>
		<pre>### 基于脚本配置来过滤log信息 ###</pre>
		<pre>除了通过程序实现对log环境的配置之外，log4cplus通过PropertyConfigurator类实现了基于脚本配置的功能。<br />通过脚本可以完成对logger、appender和layout的配置，因此可以解决怎样输出，输出到哪里的问题，我将在<br />全文的最后一部分中提到多线程环境中如何利用脚本配置来配合实现性能测试，本节将重点介绍基脚本实现过<br />滤log信息的功能。</pre>
		<pre>首先简单介绍一下脚本的语法规则：</pre>
		<pre>包括Appender的配置语法和logger的配置语法，其中：</pre>
		<pre>1.Appender的配置语法:</pre>
		<pre>（1）设置名称：</pre>
		<pre>/*设置方法*/<br />log4cplus.appender.appenderName=fully.qualified.name.of.appender.class</pre>
		<pre>例如（列举了所有可能的Appender，其中SocketAppender后面会讲到）：<br />log4cplus.appender.append_1=log4cplus::ConsoleAppender<br />log4cplus.appender.append_2=log4cplus::FileAppender<br />log4cplus.appender.append_3=log4cplus::RollingFileAppender<br />log4cplus.appender.append_4=log4cplus::DailyRollingFileAppender<br />log4cplus.appender.append_4=log4cplus::SocketAppender</pre>
		<pre>（2）设置Filter：</pre>
		<pre>包括选择过滤器和设置过滤条件，可选择的过滤器包括：LogLevelMatchFilter、LogLevelRangeFilter、<br />和StringMatchFilter：</pre>
		<pre>对LogLevelMatchFilter来说，过滤条件包括LogLevelToMatch和AcceptOnMatch（true|false）， 只有<br />当log信息的LogLevel值与LogLevelToMatch相同，且AcceptOnMatch为true时才会匹配。</pre>
		<pre>LogLevelRangeFilter来说，过滤条件包括LogLevelMin、LogLevelMax和AcceptOnMatch，只有当log信息<br />的LogLevel在LogLevelMin、LogLevelMax之间同时AcceptOnMatch为true时才会匹配。</pre>
		<pre>对StringMatchFilter来说，过滤条件包括StringToMatch和AcceptOnMatch，只有当log信息的LogLevel值<br />与StringToMatch对应的LogLevel值与相同， 且AcceptOnMatch为true时会匹配。</pre>
		<pre>
				<br />过滤条件处理机制类似于IPTABLE的Responsibility chain，（即先deny、再allow）不过执行顺序刚好相反，<br />后写的条件会被先执行，比如：</pre>
		<pre>log4cplus.appender.append_1.filters.1=log4cplus::spi::LogLevelMatchFilter<br />log4cplus.appender.append_1.filters.1.LogLevelToMatch=TRACE<br />log4cplus.appender.append_1.filters.1.AcceptOnMatch=true<br />#log4cplus.appender.append_1.filters.2=log4cplus::spi::DenyAllFilter</pre>
		<pre>会首先执行filters.2的过滤条件，关闭所有过滤器，然后执行filters.1，仅匹配TRACE信息。</pre>
		<pre>（3）设置Layout</pre>
		<pre>可以选择不设置、TTCCLayout、或PatternLayout</pre>
		<pre>如果不设置，会输出简单格式的log信息。</pre>
		<pre>设置TTCCLayout如下所示：<br />log4cplus.appender.ALL_MSGS.layout=log4cplus::TTCCLayout</pre>
		<pre>设置PatternLayout如下所示：<br />log4cplus.appender.append_1.layout=log4cplus::PatternLayout<br />log4cplus.appender.append_1.layout.ConversionPattern=%d{%m/%d/%y %H:%M:%S,%Q} [%t] %-5p - %m%n</pre>
		<pre>
				<br />2.logger的配置语法</pre>
		<pre>包括rootLogger和non-root logger。</pre>
		<pre>对于rootLogger来说：<br />log4cplus.rootLogger=[LogLevel], appenderName, appenderName, ...</pre>
		<pre>对于non-root logger来说：<br />log4cplus.logger.logger_name=[LogLevel|INHERITED], appenderName, appenderName, ...</pre>
		<pre>
				<br />脚本方式使用起来非常简单，只要首先加载配置即可（urconfig.properties是自行定义的配置文件）：</pre>
		<pre>PropertyConfigurator::doConfigure("urconfig.properties");</pre>
		<pre>
				<br />下面我们通过例子体会一下log4cplus强大的基于脚本过滤log信息的功能。</pre>
		<pre>
				<br />〖例8〗</pre>
		<pre>/*<br /> *    urconfig.properties<br /> */<br />log4cplus.rootLogger=TRACE, ALL_MSGS, TRACE_MSGS, DEBUG_INFO_MSGS, FATAL_MSGS</pre>
		<pre>log4cplus.appender.ALL_MSGS=log4cplus::RollingFileAppender<br />log4cplus.appender.ALL_MSGS.File=all_msgs.log<br />log4cplus.appender.ALL_MSGS.layout=log4cplus::TTCCLayout</pre>
		<pre>log4cplus.appender.TRACE_MSGS=log4cplus::RollingFileAppender<br />log4cplus.appender.TRACE_MSGS.File=trace_msgs.log<br />log4cplus.appender.TRACE_MSGS.layout=log4cplus::TTCCLayout<br />log4cplus.appender.TRACE_MSGS.filters.1=log4cplus::spi::LogLevelMatchFilter<br />log4cplus.appender.TRACE_MSGS.filters.1.LogLevelToMatch=TRACE<br />log4cplus.appender.TRACE_MSGS.filters.1.AcceptOnMatch=true<br />log4cplus.appender.TRACE_MSGS.filters.2=log4cplus::spi::DenyAllFilter</pre>
		<pre>log4cplus.appender.DEBUG_INFO_MSGS=log4cplus::RollingFileAppender<br />log4cplus.appender.DEBUG_INFO_MSGS.File=debug_info_msgs.log<br />log4cplus.appender.DEBUG_INFO_MSGS.layout=log4cplus::TTCCLayout<br />log4cplus.appender.DEBUG_INFO_MSGS.filters.1=log4cplus::spi::LogLevelRangeFilter<br />log4cplus.appender.DEBUG_INFO_MSGS.filters.1.LogLevelMin=DEBUG<br />log4cplus.appender.DEBUG_INFO_MSGS.filters.1.LogLevelMax=INFO<br />log4cplus.appender.DEBUG_INFO_MSGS.filters.1.AcceptOnMatch=true<br />log4cplus.appender.DEBUG_INFO_MSGS.filters.2=log4cplus::spi::DenyAllFilter</pre>
		<pre>log4cplus.appender.FATAL_MSGS=log4cplus::RollingFileAppender<br />log4cplus.appender.FATAL_MSGS.File=fatal_msgs.log<br />log4cplus.appender.FATAL_MSGS.layout=log4cplus::TTCCLayout<br />log4cplus.appender.FATAL_MSGS.filters.1=log4cplus::spi::StringMatchFilter<br />log4cplus.appender.FATAL_MSGS.filters.1.StringToMatch=FATAL<br />log4cplus.appender.FATAL_MSGS.filters.1.AcceptOnMatch=true<br />log4cplus.appender.FATAL_MSGS.filters.2=log4cplus::spi::DenyAllFilter</pre>
		<pre>
				<br />/*<br /> *    main.cpp<br /> */<br />#include &lt;log4cplus/logger.h&gt;<br />#include &lt;log4cplus/configurator.h&gt;<br />#include &lt;log4cplus/helpers/stringhelper.h&gt;<log4cplus /></pre>
		<pre>using namespace log4cplus;</pre>
		<pre>static Logger logger = Logger::getInstance("log");</pre>
		<pre>void printDebug()<br />{<br />    LOG4CPLUS_TRACE_METHOD(logger, "::printDebug()");<br />    LOG4CPLUS_DEBUG(logger, "This is a DEBUG message");<br />    LOG4CPLUS_INFO(logger, "This is a INFO message");<br />    LOG4CPLUS_WARN(logger, "This is a WARN message");<br />    LOG4CPLUS_ERROR(logger, "This is a ERROR message");<br />    LOG4CPLUS_FATAL(logger, "This is a FATAL message");<br />}<br />int main()<br />{<br />    Logger root = Logger::getRoot();<br />    PropertyConfigurator::doConfigure("urconfig.properties");<br />    printDebug();</pre>
		<pre>    return 0;<br />}</pre>
		<pre>运行结果：</pre>
		<pre>1. all_msgs.log<br />10-17-04 14:55:25,858 [1075298944] TRACE log &lt;&gt; - ENTER: ::printDebug()<br />10-17-04 14:55:25,871 [1075298944] DEBUG log &lt;&gt; - This is a DEBUG message<br />10-17-04 14:55:25,873 [1075298944] INFO log &lt;&gt; - This is a INFO message<br />10-17-04 14:55:25,873 [1075298944] WARN log &lt;&gt; - This is a WARN message<br />10-17-04 14:55:25,874 [1075298944] ERROR log &lt;&gt; - This is a ERROR message<br />10-17-04 14:55:25,874 [1075298944] FATAL log &lt;&gt; - This is a FATAL message<br />10-17-04 14:55:25,875 [1075298944] TRACE log &lt;&gt; - EXIT:  ::printDebug()</pre>
		<pre>2. trace_msgs.log<br />10-17-04 14:55:25,858 [1075298944] TRACE log &lt;&gt; - ENTER: ::printDebug()<br />10-17-04 14:55:25,875 [1075298944] TRACE log &lt;&gt; - EXIT:  ::printDebug()</pre>
		<pre>3. debug_info_msgs.log<br />10-17-04 14:55:25,871 [1075298944] DEBUG log &lt;&gt; - This is a DEBUG message<br />10-17-04 14:55:25,873 [1075298944] INFO log &lt;&gt; - This is a INFO message</pre>
		<pre>4. fatal_msgs.log<br />10-17-04 14:55:25,874 [1075298944] FATAL log &lt;&gt; - This is a FATAL message</pre>
		<pre> </pre>
		<pre>本部分详细介绍了如何有选择地控制log信息的输出，最后一部分我们将介绍一下多线程、<br />和C/S模式下该如何操作，顺便提一下NDC的概念。</pre>
<img src ="http://www.cppblog.com/tx7do/aggbug/11719.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-08-26 04:50 <a href="http://www.cppblog.com/tx7do/articles/11719.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源日志系统log4cplus(六)</title><link>http://www.cppblog.com/tx7do/articles/11720.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 25 Aug 2006 20:50:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/11720.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/11720.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/11720.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/11720.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/11720.html</trackback:ping><description><![CDATA[
		<p>log4cplus在很多方面做的都很出色，但是使用过程有些地方感觉不爽。在继续吹捧之前我先把不爽之处<br />稍微提一提，然后继续介绍关于线程和套接字的知识。<br /></p>
		<pre>### 一些可以改进之处 ###</pre>
		<pre>1. 用户自定义LogLevel的实现机制不够开放</pre>
		<pre>在第五篇中曾经介绍过如何实现用户自行定义LogLevel，为了实现比较理想的效果，甚至还需要改log4cplus<br />的源代码。：（</pre>
		<pre>2. 生成Logger对象的机制可以改进</pre>
		<pre>我在使用时候，经常需要在不同的文件、函数中操作同一个logger，虽然log4cplus实现了树状存储以及根据<br />名称生成Logger，却没有充分利用这样的特点确保同一个名称对应的logger对象的唯一性，比如以下代码：</pre>
		<pre>    ... ...<br />    <br />    Logger logger1 = Logger::getInstance("test");<br />    Logger logger2 = Logger::getInstance("test");</pre>
		<pre>    Logger * plogger1 = &amp;logger1;<br />    Logger * plogger2 = &amp;logger2;</pre>
		<pre>    std::cout &lt;&lt; "plogger1: " &lt;&lt; plogger1 &lt;&lt; std::endl &lt;&lt; "plogger2: " &lt;&lt; plogger2 &lt;&lt; std::endl;<br />    <br />    ... ...<br />    <br />    <br />运行结果：</pre>
		<pre>plogger1: 0xbfffe5a0<br />plogger2: 0xbfffe580</pre>
		<pre>
				<br />从结果可以看出，明明是同一个Logger，但每次调用都会产生一个Logger副本，虽然结果是正确的（因为将存<br />储和操作分开了），但是资源有些浪费，我看了一下log4cplus的代码，其实可以按照如下方式实现（示意性<br />的）：</pre>
		<pre>#include &lt;iostream&gt;<br />#include &lt;string&gt;<br />#include &lt;map&gt;<map></map></pre>
		<pre>/* forward declaration */<br />class Logger;</pre>
		<pre>class LoggerContainer<br />{<br />public:</pre>
		<pre>    ~LoggerContainer();</pre>
		<pre>    Logger * getinstance(const std::string &amp; strLogger);</pre>
		<pre>private:</pre>
		<pre>    typedef std::map&lt;:string,&gt; LoggerMap;<br />    LoggerMap loggerPtrs;<br />};</pre>
		<pre>class Logger<br />{<br />public:<br />     Logger() {std::cout &lt;&lt; "ctor of Logger " &lt;&lt; std::endl; }<br />    ~Logger() {std::cout &lt;&lt; "dtor of Logger " &lt;&lt; std::endl; }</pre>
		<pre>    static Logger * getInstance( const std::string &amp; strLogger)<br />    {<br />        static LoggerContainer defaultLoggerContainer;<br />        return defaultLoggerContainer.getinstance(strLogger);<br />    }<br />};</pre>
		<pre>LoggerContainer::~LoggerContainer()<br />{<br />    /* release all ptr in LoggerMap */<br />    LoggerMap::iterator itr = loggerPtrs.begin();</pre>
		<pre>    for( ; itr != loggerPtrs.end(); ++itr )<br /> {<br />     delete (*itr).second;<br /> }</pre>
		<pre>}</pre>
		<pre>Logger * LoggerContainer::getinstance(const std::string &amp; strLogger)<br />{<br />   LoggerMap::iterator itr = loggerPtrs.find(strLogger);</pre>
		<pre>   if(itr != loggerPtrs.end())<br />   {<br />       /* logger exist, just return it */<br />       return (*itr).second;<br />   }<br />   else<br />   {<br />       /* return a new logger */<br />       Logger * plogger = new Logger();<br />       loggerPtrs.insert(std::make_pair(strLogger, plogger));</pre>
		<pre>       return plogger;<br />   }<br />}</pre>
		<pre>int main()<br />{<br />    Logger * plogger1 = Logger::getInstance("test");<br />    Logger * plogger2 = Logger::getInstance("test");</pre>
		<pre>    std::cout &lt;&lt; "plogger1: " &lt;&lt; plogger1 &lt;&lt; std::endl &lt;&lt; "plogger2: " &lt;&lt; plogger2 &lt;&lt; std::endl;</pre>
		<pre>    return 0;<br />}</pre>
		<pre>
				<br />运行结果：</pre>
		<pre>ctor of Logger<br />plogger1: 0x804fc30<br />plogger2: 0x804fc30<br />dtor of Logger</pre>
		<pre>这里的LoggerContainer相当于log4cplus中的Hierarchy类，结果可以看出，通过同一个名称可以获取相同的<br />Logger实例。</pre>
		<pre>
				<br />还有一些小毛病比如RollingFileAppender和DailyRollingFileAppender的参数输入顺序可以调整成统一方式<br />等等，就不细说了。</pre>
		<pre>本部分提到了使用log4cplus时候感觉不爽的地方，最后一部分将介绍一下log4cplus中线程和套接字实现情况<br /></pre>
<img src ="http://www.cppblog.com/tx7do/aggbug/11720.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-08-26 04:50 <a href="http://www.cppblog.com/tx7do/articles/11720.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源日志系统log4cplus(二)</title><link>http://www.cppblog.com/tx7do/articles/11716.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 25 Aug 2006 20:49:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/11716.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/11716.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/11716.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/11716.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/11716.html</trackback:ping><description><![CDATA[
		<pre>本文介绍了使用log4cplus有六个步骤，并提供了一些例子引导你了解log4cplus的基本使用。</pre>
		<br />
		<pre>
				<br />### 基本使用 ###</pre>
		<pre>使用log4cplus有六个基本步骤：</pre>
		<pre>1. 实例化一个appender对象<br />2. 实例化一个layout对象<br />3. 将layout对象绑定(attach)到appender对象<br />4. 实例化一个logger对象,调用静态函数：log4cplus::Logger::getInstance("logger_name")<br />5. 将appender对象绑定(attach)到logger对象，如省略此步骤，标准输出（屏幕）appender对象会绑定到logger<br />6. 设置logger的优先级，如省略此步骤，各种有限级的消息都将被记录</pre>
		<pre>下面通过一些例子来了解log4cplus的基本使用。</pre>
		<pre>〖例1〗<br />/*<br />    严格实现步骤1-6，appender输出到屏幕, 其中的布局格式和LogLevel后面会详细解释。<br />*/<br />#include &lt;log4cplus/logger.h&gt;<br />#include &lt;log4cplus/consoleappender.h&gt;<br />#include &lt;log4cplus/layout.h&gt;<log4cplus /></pre>
		<pre>using namespace log4cplus;<br />using namespace log4cplus::helpers;</pre>
		<pre>int main()<br />{<br />    /* step 1: Instantiate an appender object */<br />    SharedObjectPtr<appender /> _append (new ConsoleAppender());<br />    _append-&gt;setName("append for test");</pre>
		<pre>    /* step 2: Instantiate a layout object */<br />    std::string pattern = "%d{%m/%d/%y %H:%M:%S}  - %m [%l]%n";<br />    std::auto_ptr<layout /> _layout(new PatternLayout(pattern));</pre>
		<pre>    /* step 3: Attach the layout object to the appender */<br />    _append-&gt;setLayout( _layout );</pre>
		<pre>    /* step 4: Instantiate a logger object */<br />    Logger _logger = Logger::getInstance("test");</pre>
		<pre>    /* step 5: Attach the appender object to the logger  */<br />    _logger.addAppender(_append);</pre>
		<pre>    /* step 6: Set a priority for the logger  */<br />    _logger.setLogLevel(ALL_LOG_LEVEL);</pre>
		<pre>     /* log activity */<br />    LOG4CPLUS_DEBUG(_logger, "This is the FIRST log message...")<br />    sleep(1);<br />    LOG4CPLUS_WARN(_logger, "This is the SECOND log message...")</pre>
		<pre>    return 0;<br />}</pre>
		<pre>输出结果：<br />10/14/04 09:06:24  - This is the FIRST log message... [main.cpp:31]<br />10/14/04 09:06:25  - This is the SECOND log message... [main.cpp:33]</pre>
		<pre>
				<br />〖例2〗<br />/*<br />    简洁使用模式，appender输出到屏幕。<br />*/<br />#include &lt;log4cplus/logger.h&gt;<br />#include &lt;log4cplus/consoleappender.h&gt;<log4cplus /></pre>
		<pre>using namespace log4cplus;<br />using namespace log4cplus::helpers;</pre>
		<pre>int main()<br />{<br />    /* step 1: Instantiate an appender object */<br />    SharedAppenderPtr _append(new ConsoleAppender());<br />    _append-&gt;setName("append test");</pre>
		<pre>    /* step 4: Instantiate a logger object */<br />    Logger _logger = Logger::getInstance("test");</pre>
		<pre>    /* step 5: Attach the appender object to the logger  */<br />    _logger.addAppender(_append);</pre>
		<pre>    /* log activity */<br />    LOG4CPLUS_DEBUG(_logger, "This is the FIRST log message...")<br />    sleep(1);<br />    LOG4CPLUS_WARN(_logger, "This is the SECOND log message...")</pre>
		<pre>    return 0;<br />}</pre>
		<pre>输出结果：<br />DEBUG - This is the FIRST log message...<br />WARN - This is the SECOND log message...</pre>
		<pre>
				<br />〖例3〗<br />/*<br />    iostream模式，appender输出到屏幕。<br />*/<br />#include &lt;log4cplus/logger.h&gt;<br />#include &lt;log4cplus/consoleappender.h&gt;<br />#include &lt;iomanip&gt; /* 其实这个东东还是放到log4cplus头文件中比较合适些，个人意见：） */using namespace log4cplus;</pre>
		<pre>int main()<br />{<br />    /* step 1: Instantiate an appender object */<br />    SharedAppenderPtr _append(new ConsoleAppender());<br />    _append-&gt;setName("append test");</pre>
		<pre>    /* step 4: Instantiate a logger object */<br />    Logger _logger = Logger::getInstance("test");</pre>
		<pre>    /* step 5: Attach the appender object to the logger  */<br />    _logger.addAppender(_append);</pre>
		<pre>    /* log activity */<br />    LOG4CPLUS_TRACE(_logger, "This is"  &lt;&lt; " just a t" &lt;&lt; "est." &lt;&lt; std::endl)<br />    LOG4CPLUS_DEBUG(_logger, "This is a bool: " &lt;&lt; true)<br />    LOG4CPLUS_INFO(_logger, "This is a char: " &lt;&lt; 'x')<br />    LOG4CPLUS_WARN(_logger, "This is a int: " &lt;&lt; 1000)<br />    LOG4CPLUS_ERROR(_logger, "This is a long(hex): " &lt;&lt; std::hex &lt;&lt; 100000000)<br />    LOG4CPLUS_FATAL(_logger, "This is a double: "  &lt;&lt; std::setprecision(15)  &lt;&lt; 1.2345234234)</pre>
		<pre>    return 0;<br />}</pre>
		<pre>输出结果：<br />DEBUG - This is a bool: 1<br />INFO - This is a char: x<br />WARN - This is a int: 1000<br />ERROR - This is a long(hex): 5f5e100<br />FATAL - This is a double: 1.2345234234</pre>
		<pre>
				<br />〖例4〗<br />/*<br />    调试模式，通过loglog来控制输出调试、警告或错误信息，appender输出到屏幕。<br />*/<br />#include &lt;iostream&gt;<br />#include &lt;log4cplus/helpers/loglog.h&gt;</pre>
		<pre>using namespace log4cplus::helpers;</pre>
		<pre>void printMsgs(void)<br />{<br />    std::cout &lt;&lt; "Entering printMsgs()..." &lt;&lt; std::endl;<br />    LogLog::getLogLog()-&gt;debug("This is a Debug statement...");<br />    LogLog::getLogLog()-&gt;warn("This is a Warning...");<br />    LogLog::getLogLog()-&gt;error("This is a Error...");<br />    std::cout &lt;&lt; "Exiting printMsgs()..." &lt;&lt; std::endl &lt;&lt; std::endl;<br />}</pre>
		<pre>int main()<br />{<br />    /*<br />       LogLog类实现了debug, warn, error 函数用于输出调试、警告或错误信息，<br />       同时提供了两个方法来进一步控制所输出的信息，其中：</pre>
		<pre>       setInternalDebugging方法用来控制是否屏蔽输出信息中的调试信息，当输入<br />       参数为false则屏蔽，缺省设置为false。</pre>
		<pre>       setQuietMode方法用来控制是否屏蔽所有输出信息，当输入参数为true则屏蔽，<br />       缺省设置为false。</pre>
		<pre>       LogLog::getLogLog()-&gt;setInternalDebugging(false);<br />    */</pre>
		<pre>    printMsgs();</pre>
		<pre>    std::cout &lt;&lt; "Turning on debug..." &lt;&lt; std::endl;<br />    LogLog::getLogLog()-&gt;setInternalDebugging(true);<br />    printMsgs();</pre>
		<pre>    std::cout &lt;&lt; "Turning on quiet mode..." &lt;&lt; std::endl;<br />    LogLog::getLogLog()-&gt;setQuietMode(true);<br />    printMsgs();</pre>
		<pre>    return 0;<br />}</pre>
		<pre>输出结果：<br />Entering printMsgs()...<br />log4cplus:WARN This is a Warning...<br />log4cplus:ERROR This is a Error...<br />Exiting printMsgs()...</pre>
		<pre>Turning on debug...<br />Entering printMsgs()...<br />log4cplus: This is a Debug statement...<br />log4cplus:WARN This is a Warning...<br />log4cplus:ERROR This is a Error...<br />Exiting printMsgs()...</pre>
		<pre>Turning on quiet mode...<br />Entering printMsgs()...<br />Exiting printMsgs()...</pre>
		<pre>需要指出的是，输出信息中总是包含"log4cplus:"前缀，有时候会感觉不爽，这是因为LogLog在实现时候死定了要这么写：</pre>
		<pre>LogLog::LogLog()<br /> : mutex(LOG4CPLUS_MUTEX_CREATE),<br />   debugEnabled(false),<br />   quietMode(false),<br />   PREFIX( LOG4CPLUS_TEXT("log4cplus: ") ),<br />   WARN_PREFIX( LOG4CPLUS_TEXT("log4cplus:WARN ") ),<br />   ERR_PREFIX( LOG4CPLUS_TEXT("log4cplus:ERROR ") )<br />{<br />}</pre>
		<pre>你可以把这些前缀换成自己看着爽的提示符号，然后重新编译，hihi。除非万不得已或者实在郁闷的不行，否则还是不要这样干。</pre>
		<pre>
				<br />〖例5〗<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"><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">    文件模式，appender输出到文件。</span><span style="COLOR: #008000">*/<br /></span><span style="COLOR: #000000">#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">log4cplus</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">logger.h</span><span style="COLOR: #000000">&gt;<br /></span><span style="COLOR: #000000">#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">log4cplus</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">fileappender.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br /></span><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000"> log4cplus;<br /></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> main()<br />{    <br /></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000"> step 1: Instantiate an appender object </span><span style="COLOR: #008000">*/<br /></span><span style="COLOR: #000000">    SharedAppenderPtr _append(</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> FileAppender(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Test.log</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">));<br />    _append</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">setName(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">file log test</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br />    </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000"> step 4: Instantiate a logger object </span><span style="COLOR: #008000">*/<br /></span><span style="COLOR: #000000">    Logger _logger </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> Logger::getInstance(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">test.subtestof_filelog</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br />    </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000"> step 5: Attach the appender object to the logger  </span><span style="COLOR: #008000">*/<br /></span><span style="COLOR: #000000">    _logger.addAppender(_append);<br />    </span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000"> log activity </span><span style="COLOR: #008000">*/<br /></span><span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i;<br />    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">( i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; i </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">; </span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">i )<br />    {<br />        LOG4CPLUS_DEBUG(_logger, </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Entering loop #</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000"> i </span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">End line #</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">)<br />    }<br />    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br />}<br /></span></div></pre>
		<pre>输出结果（Test.log文件）：</pre>
		<pre>DEBUG - Entering loop #0End line #<br />DEBUG - Entering loop #1End line #<br />DEBUG - Entering loop #2End line #<br />DEBUG - Entering loop #3End line #<br />DEBUG - Entering loop #4End line #</pre>
<img src ="http://www.cppblog.com/tx7do/aggbug/11716.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-08-26 04:49 <a href="http://www.cppblog.com/tx7do/articles/11716.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源日志系统log4cplus(三)</title><link>http://www.cppblog.com/tx7do/articles/11717.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 25 Aug 2006 20:49:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/11717.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/11717.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/11717.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/11717.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/11717.html</trackback:ping><description><![CDATA[
		<p>本文介绍了三种控制输出格式的布局管理器的概念和使用情况，通过掌握这些知识，可以更有效地控制log系统输出尽可能贴近你需求的信息来。<br /></p>
		<pre>
				<br />### 如何控制输出消息的格式 ###</pre>
		<pre>前面已经讲过，log4cplus通过布局器（Layouts）来控制输出的格式，log4cplus提供了三种类型的Layouts，<br />分别是SimpleLayout、PatternLayout、和TTCCLayout。其中：</pre>
		<pre>1. SimpleLayout<br />是一种简单格式的布局器，在输出的原始信息之前加上LogLevel和一个"-"。</pre>
		<pre>比如以下代码片段：</pre>
		<pre>    ... ...</pre>
		<pre>    /* step 1: Instantiate an appender object */<br />    SharedObjectPtr _append (new ConsoleAppender());<br />    _append-&gt;setName("append for test");</pre>
		<pre>    /* step 2: Instantiate a layout object */<br />    std::auto_ptr  _layout(new log4cplus::SimpleLayout());</pre>
		<pre>    /* step 3: Attach the layout object to the appender */<br />    _append-&gt;setLayout( _layout );</pre>
		<pre>    /* step 4: Instantiate a logger object */<br />    Logger _logger = Logger::getInstance("test");</pre>
		<pre>    /* step 5: Attach the appender object to the logger  */<br />    _logger.addAppender(_append);</pre>
		<pre>     /* log activity */<br />    LOG4CPLUS_DEBUG(_logger, "This is the simple formatted log message...")<br />    <br />    ... ...<br />    <br />    <br />将打印结果：<br />DEBUG - This is the simple formatted log message...</pre>
		<pre>2. PatternLayout<br />是一种有词法分析功能的模式布局器，一提起模式就会想起正则表达式，这里的模式和正则表达式类似，但是<br />远比后者简单，能够对预定义的标识符（称为conversion specifiers）进行解析，转换成特定格式输出。以下<br />代码片段演示了如何使用PatternLayout：</pre>
		<pre>    ... ...</pre>
		<pre>    /* step 1: Instantiate an appender object */<br />    SharedObjectPtr _append (new ConsoleAppender());<br />    _append-&gt;setName("append for test");<br />   <br />    /* step 2: Instantiate a layout object */<br />    std::string pattern = "%d{%m/%d/%y %H:%M:%S}  - %m [%l]%n";<br />    std::auto_ptr _layout(new PatternLayout(pattern));<br />    <br />    /* step 3: Attach the layout object to the appender */<br />    _append-&gt;setLayout( _layout );</pre>
		<pre>    /* step 4: Instantiate a logger object */<br />    Logger _logger = Logger::getInstance("test_logger.subtest");</pre>
		<pre>    /* step 5: Attach the appender object to the logger  */<br />    _logger.addAppender(_append);</pre>
		<pre>     /* log activity */<br />    LOG4CPLUS_DEBUG(_logger, "teststr")<br />    <br />    ... ...<br />    <br />输出结果：<br />10/16/04 18:51:25  - teststr [main.cpp:51]</pre>
		<pre>可以看出通过填写特定格式的模式字符串"pattern"，原始信息被包含到一堆有格式的信息当中了，这就使得<br />用户可以根据自身需要来定制显示内容。"pattern"可以包含普通字符串和预定义的标识符，其中：</pre>
		<pre>（1）普通字符串，能够被直接显示的信息。<br />（2）预定义标识符，通过"%"与一个或多个字符共同构成预定义的标识符，能够产生出特定格式信息。</pre>
		<pre>关于预定义标识符，log4cplus文档中提供了详细的格式说明，我每种都试了一下，以上述代码为例，根据不同<br />的pattern，各种消息格式使用情况列举如下：</pre>
		<pre>（1）"%%"，转义为%, 即，std::string pattern = "%%" 时输出: "%"<br />（2）"%c"，输出logger名称，比如std::string pattern ="%c" 时输出: "test_logger.subtest"，<br />     也可以控制logger名称的显示层次，比如"%c{1}"时输出"test_logger"，其中数字表示层次。<br />（3）"%D"，显示本地时间，当std::string pattern ="%D" 时输出:"2004-10-16 18:55:45"，%d显示标准时间，<br />     所以当std::string pattern ="%d" 时输出 "2004-10-16 10:55:45" （因为我们是东8区，差8个小时啊）。<br />     可以通过%d{...}定义更详细的显示格式，比如%d{%H:%M:%s}表示要显示小时:分钟：秒。大括号中可显示的<br />     预定义标识符如下：<br />     <br />%a -- 表示礼拜几，英文缩写形式，比如"Fri"<br />%A -- 表示礼拜几，比如"Friday"<br />%b -- 表示几月份，英文缩写形式，比如"Oct"<br />%B -- 表示几月份，"October"<br />%c -- 标准的日期＋时间格式，如 "Sat Oct 16 18:56:19 2004"<br />%d -- 表示今天是这个月的几号(1-31)"16"<br />%H -- 表示当前时刻是几时(0-23)，如 "18"<br />%I -- 表示当前时刻是几时(1-12)，如 "6"<br />%j -- 表示今天是哪一天(1-366)，如 "290"<br />%m -- 表示本月是哪一月(1-12)，如 "10"<br />%M -- 表示当前时刻是哪一分钟(0-59)，如 "59"<br />%p -- 表示现在是上午还是下午， AM or PM<br />%q -- 表示当前时刻中毫秒部分(0-999)，如 "237"<br />%Q -- 表示当前时刻中带小数的毫秒部分(0-999.999)，如 "430.732"<br />%S -- 表示当前时刻的多少秒(0-59)，如 "32"<br />%U -- 表示本周是今年的第几个礼拜，以周日为第一天开始计算(0-53)，如 "41"<br />%w -- 表示礼拜几，(0-6, 礼拜天为0)，如 "6"<br />%W -- 表示本周是今年的第几个礼拜，以周一为第一天开始计算(0-53)，如 "41"<br />%x -- 标准的日期格式，如 "10/16/04"<br />%X -- 标准的时间格式，如 "19:02:34"<br />%y -- 两位数的年份(0-99)，如 "04"<br />%Y -- 四位数的年份，如 "2004"<br />%Z -- 时区名，比如 "GMT"</pre>
		<pre>（4）"%F"，输出当前记录器所在的文件名称，比如std::string pattern ="%F" 时输出: "main.cpp"<br />（5）"%L"，输出当前记录器所在的文件行号，比如std::string pattern ="%L" 时输出: "51"<br />（6）"%l"，输出当前记录器所在的文件名称和行号，比如std::string pattern ="%L" 时输出:<br />     "main.cpp:51"<br />（7）"%m"，输出原始信息，比如std::string pattern ="%m" 时输出: "teststr"，即上述代码中<br />     LOG4CPLUS_DEBUG的第二个参数，这种实现机制可以确保原始信息被嵌入到带格式的信息中。<br />（8）"%n"，换行符，没什么好解释的<br />（9）"%p"，输出LogLevel，比如std::string pattern ="%p" 时输出: "DEBUG"<br />（10）"%t"，输出记录器所在的线程ID，比如std::string pattern ="%t" 时输出: "1075298944"<br />（11）"%x"，嵌套诊断上下文NDC (nested diagnostic context) 输出，从堆栈中弹出上下文信息，NDC可以用对<br />      不同源的log信息（同时地）交叉输出进行区分，关于NDC方面的详细介绍会在下文中提到。<br />（12）格式对齐，比如std::string pattern ="%-10m"时表示左对齐，宽度是10，此时会输出"teststr   "，当<br />      然其它的控制字符也可以相同的方式来使用，比如"%-12d"，"%-5p"等等（刚接触log4cplus文档时还以为<br />      "%-5p"整个字符串代表LogLevel呢，呵呵）。</pre>
		<pre>      <br />3. TTCCLayout<br />是在PatternLayout基础上发展的一种缺省的带格式输出的布局器， 其格式由时间，线程ID，Logger和NDC 组<br />成（consists of time, thread, Logger and nested diagnostic context information, hence the name），<br />因而得名（怎么得名的？Logger里哪里有那个"C"的缩写啊！名字起得真够烂的，想扁人）。提供给那些想显示<br />典型的信息（一般情况下够用了）又懒得配置pattern的同志们。</pre>
		<pre>TTCCLayout在构造时有机会选择显示本地时间或GMT时间，缺省是按照本地时间显示：<br />TTCCLayout::TTCCLayout(bool use_gmtime  = false)</pre>
		<pre>以下代码片段演示了如何使用TTCCLayout：</pre>
		<pre>    ... ...</pre>
		<pre>    /* step 1: Instantiate an appender object */<br />    SharedObjectPtr _append (new ConsoleAppender());<br />    _append-&gt;setName("append for test");</pre>
		<pre>    /* step 2: Instantiate a layout object */<br />    std::auto_ptr _layout(new TTCCLayout());</pre>
		<pre>    /* step 3: Attach the layout object to the appender */<br />    _append-&gt;setLayout( _layout );</pre>
		<pre>    /* step 4: Instantiate a logger object */<br />    Logger _logger = Logger::getInstance("test_logger");</pre>
		<pre>    /* step 5: Attach the appender object to the logger  */<br />    _logger.addAppender(_append);</pre>
		<pre>     /* log activity */<br />    LOG4CPLUS_DEBUG(_logger, "teststr")<br />    <br />    ... ...<br />    <br />输出结果：<br />10-16-04 19:08:27,501 [1075298944] DEBUG test_logger &lt;&gt; - teststr</pre>
		<pre>
				<br />当构造TTCCLayout对象时选择GMT时间格式时：</pre>
		<pre>    ... ...<br />    <br />    /* step 2: Instantiate a layout object */<br />    std::auto_ptr _layout(new TTCCLayout(true));<br />    <br />    ... ...<br />    <br />输出结果：<br />10-16-04 11:12:47,678 [1075298944] DEBUG test_logger &lt;&gt; - teststr</pre>
		<pre>
				<br />本文介绍了控制log信息格式的相关知识，下一部分将详细介绍log信息的几种文件操作方式。</pre>
<img src ="http://www.cppblog.com/tx7do/aggbug/11717.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-08-26 04:49 <a href="http://www.cppblog.com/tx7do/articles/11717.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源日志系统log4cplus(一)</title><link>http://www.cppblog.com/tx7do/articles/11715.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 25 Aug 2006 20:45:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/11715.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/11715.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/11715.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/11715.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/11715.html</trackback:ping><description><![CDATA[
		<p>log4cplus是C++编写的开源的日志系统，功能非常全面，用到自己开发的工程中会比较专业的，：），本文介绍了log4cplus基本概念，以及如何安装，配置。 <br /></p>
		<pre>
				<br />### 简介 ###</pre>
		<pre>log4cplus是C++编写的开源的日志系统，前身是java编写的log4j系统.受Apache Software License<br />保护。作者是Tad E. Smith。log4cplus具有线程安全、灵活、以及多粒度控制的特点，通过将信息划分<br />优先级使其可以面向程序调试、运行、测试、和维护等全生命周期； 你可以选择将信息输出到屏幕、文件、<br />NT event log、甚至是远程服务器；通过指定策略对日志进行定期备份等等。</pre>
		<pre> </pre>
		<pre>### 下载 ###</pre>
		<pre>最新的log4cplus可以从以下网址下载 <a href="http://log4cplus.sourceforge.net/"><font color="#002c99">http://log4cplus.sourceforge.net</font></a><br />本文使用的版本为：1.0.2</pre>
		<pre> </pre>
		<pre>### 安装 ###</pre>
		<pre> </pre>
		<pre>1. linux下安装</pre>
		<pre>tar xvzf log4cplus-x.x.x.tar.gz<br />cd log4cplus-x.x.x<br />./configure --prefix=/where/to/install<br />make<br />make install</pre>
		<pre>这里我采用缺省安装路径：/usr/local，下文如无特别说明，均以此路径为准。</pre>
		<pre> </pre>
		<pre>2. windows下安装</pre>
		<pre>不需要安装，有一个msvc6存放包括源代码和用例在内的开发工程（for VC6 only），使用之前请先编译<br />"log4cplus_dll class"工程生成dll，或者编译"log4cplus_static class"工程生成lib.</pre>
		<pre> </pre>
		<pre>### 使用前的配置 ###</pre>
		<pre>1. linux下的配置</pre>
		<pre>确保你的Makefile中包含 /usr/local/lib/liblog4cplus.a（静态库）或  -llog4cplus（动态库）即可，<br />头文件在/usr/local/include/log4cplus目录下。对于动态库，要想正常使用，还得将库安装路径加入到<br />LD_LIBRARY_PATH 中，我一般是这样做的：以管理员身份登录，在/etc/ld.so.conf中加入安装路径，这里<br />是/usr/local/lib，然后执行ldconfig使设置生效即可。</pre>
		<pre>2. windows下的配置</pre>
		<pre>将"log4cplus_dll class"工程或"log4cplus_static class"工程的dsp 文件插入到你的工程中，或者直接<br />把两个工程编译生成的库以及头文件所在目录放到你的工程的搜索路径中，如果你使用静态库，请在你的工程中<br />"project/setting/C++"的preprocessor definitions中加入LOG4CPLUS_STATIC。</pre>
		<pre> </pre>
		<pre>### 构成要素介绍 ###</pre>
		<pre>虽然功能强大，应该说log4cplus用起来还是比较复杂的，为了更好地使用它，先介绍一下它的基本要素。</pre>
		<pre>Layouts      ：布局器，控制输出消息的格式.<br />Appenders    ：挂接器，与布局器紧密配合，将特定格式的消息输出到所挂接的设备终端<br />               （如屏幕，文件等等)。<br />Logger       ：记录器，保存并跟踪对象日志信息变更的实体，当你需要对一个对象进行<br />               记录时，就需要生成一个logger。<br />Categories   ：分类器，层次化（hierarchy）的结构，用于对被记录信息的分类，层次中<br />               每一个节点维护一个logger的所有信息。<br />Priorities   ：优先权，包括TRACE, DEBUG, INFO, WARNING, ERROR, FATAL。</pre>
		<pre>
				<br />本文介绍了log4cplus基本概念，以及如何安装，配置，下一篇将通过例子介绍如何使用log4cplus。</pre>
<img src ="http://www.cppblog.com/tx7do/aggbug/11715.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-08-26 04:45 <a href="http://www.cppblog.com/tx7do/articles/11715.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>INF文件格式说明</title><link>http://www.cppblog.com/tx7do/articles/8922.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 23 Jun 2006 13:48:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/8922.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/8922.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/8922.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/8922.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/8922.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: INF				文件必须包含以下规则：														       								节（				Sections				）开始于由中括号				([])				扩起来的节名								必须包含版本信息节以表明自己属于				win95				还是				winnt4				格式。								值...&nbsp;&nbsp;<a href='http://www.cppblog.com/tx7do/articles/8922.html'>阅读全文</a><img src ="http://www.cppblog.com/tx7do/aggbug/8922.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-06-23 21:48 <a href="http://www.cppblog.com/tx7do/articles/8922.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC中加入定时机制的几种方法</title><link>http://www.cppblog.com/tx7do/articles/8923.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 23 Jun 2006 13:48:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/8923.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/8923.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/8923.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/8923.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/8923.html</trackback:ping><description><![CDATA[
		<p>
				<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>机制是指在程序运行当中间隔特定的时间引发指定的事件。在DOS下编程时，主要依靠时钟中断Int 8及其调用中断 Int 1cH来实现，应用程序通过修改这些系统中断来达到实现<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>触发。而在Windows下，若想象在DOS下肆无忌惮的修改系统是不现实的，那么应当如何实现<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>机制呢？下面在下就在学习当中的几点体会谈谈这个问题，提出几种方案供大家参考。</p>
		<p>第一种方案是大家熟悉的截获<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>消息的途径。在Windows提供给我们使用的系统资源当中，有一种称为“<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>器（Timer）”的特殊资源，在申请了这类资源的程序当中每间隔一段时间会接收到值为WM_TIMER的消息。需要<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>执行的代码可以放在该消息的处理部分。如果在VC中，我们可以具体按照以下步骤实现这一目的：</p>
		<ol>
				<p>
				</p>
				<li>利用MFC AppWizard创建一个标准的工程，接受所有缺省选项。名为s1 
<p></p><p></p></li>
				<li>在Classview中选中“CMainFrame”类，然后按Ctrl+W激活ClassWizard，在“Message Map”选项卡中Class Name选“CMainFrame”，接着在“Message”中选“WM_TIMER”，最后按下“Add Funcation”。以上步骤加入了对WM_TIMER消息的映射处理。 
<p></p><p></p></li>
				<li>回到Classview中，双击“OnCreate”成员函数，在函数的末尾添加申请Timer的语句：<br />SetTimer(100,1000,NULL);//申请一个标识值为100的Timer，<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>间隔为1000毫秒（1秒）。 
<p></p><p></p></li>
				<li>在“Classview”中双击OnTimer函数，输入要<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>实现的代码。本例子中为：<br />MessageBeep(1000);;//每隔一秒发出通告声 
<p></p><p></p></li>
				<li>编译并执行之，我们可以每隔一秒就听到声音。这正是我们在OnTimer函数内要求执行的。 
<p></p></li>
		</ol>
		<p>实际当中，我们可以将“MessageBeep(1000);”换成任何我们想完成的任务，譬如<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>存盘等。</p>
		<p>第二种方案也利用Timer资源，但却是采用已经编写好的代码&amp;#0;&amp;#0;我们可以加入一个具有<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>功能的组件至当前工程当中。这种方法特别适用于基于对话框的工程。具体步骤如下：</p>
		<ol>
				<p>
				</p>
				<li>利用MFC AppWizard创建一个基于对话框的工程，其余接受所有缺省选项。名为s2。 
<p></p><p></p></li>
				<li>在ResourceView中，双击IDD_S2_DIALOG，显示对话框，将其中的“To do:”改为“<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>触发演示的例子”，表明工程的作用。 
<p></p><p></p></li>
				<li>右击对话框编辑区，在弹出的右键菜单中选择“Insert ActiveX Control”，从弹出的列表框中选择“Timer Object”，确定后会在对话框内出现一个Timer对象。 
<p></p><p></p></li>
				<li>我们右击Timer对象，从弹出的菜单中选择“Properties”，接着选“All”选项卡，将其中的Interval值设为5000，即每隔5秒发生一次Timer事件。 
<p></p><p></p></li>
				<li>回到对话框编辑界面，双击Timer，产生一个CS2Dlg::OnTimerTimer1成员函数，接受缺省值，并在函数实现部分输入：<br />MessageBox("<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>触发消息框","<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>演示" ,MB_OK); 
<p></p><p></p></li>
				<li>编译并运行此工程，将会在产生的对话框运行期间，每隔5秒弹出一个消息框。 
<p></p></li>
		</ol>
		<p>同样，我们可以以任何自己的代码来替换5中的消息框语句。详细见附例s2。</p>
		<p>第三种方法是采用线程技术。众所周知，Windows 9X是一个基于多线程的多任务操作系统，在内核中以线程作为调度的基本单位，由系统分时间片进行调度。利用这一点，我们可以在程序当中创建一个“司职”计时的线程，通过线程间的同步来<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>触发我们要完成的任务的代码。不象前两种方法需要至少有一个窗口作为接受消息的主窗口，采用线程技术实现<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>触发将免去创建窗口的麻烦以及带来的系统各种资源的消耗。下面我们来举一个例子来说明这个问题：我们在CmyApp类的Initstance成员中不建立主窗口而是创建一个工作线程，该线程休眠一定的时间后，自动调用主线程的SomeThing函数。为了支持线程的运行，我们需要给CmyApp类增加相应的线程函数。下面，我们还是一步一步的实现：</p>
		<ol>
				<p>
				</p>
				<li>利用MFC AppWizard创建一个标准工程，其中为不产生多余的代码，不选文档/视图支持，并选择单文档。工程名为S3。 
<p></p><p></p></li>
				<li>在CS3App:: InitInstance()中用“/* … */”注释掉“return TRUE;”之前的所有代码。这是为了不建立窗口。并添加以下代码：<br />ExitFlag=TRUE;//是否结束主线程的循环的标志变量。因为子线程严重依赖主线程，所以在本例子中为了避免没有主窗口而提前结束应用程序，从而使子线程无法存在，所以给主线程一个循环，知道全局变量ExitFlag在子线程退出前被设置成FALSE为止.<br />StartThread();//启动线程<br />do{}while(ExitFlag);//直到结束子线程<br />::MessageBox(NULL,"主线程结束！","<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>触发演示",MB_OK);<br />return TRUE; 
<p></p><p></p></li>
				<li>在Globals中增加一标志变量“ExitFlag”，类型为BOOL。它被主线程用来判断是否结束自身运行。 
<p></p><p></p></li>
				<li>通过ClassView在CS3App的Public部分声明以下函数:<br />void StartThread(void); //启动线程<br />static UINT ThreadFunction(void); //主要执行代码的函数<br />static UINT StaticThreadFunc(LPVOID lpparam);//设置线程时用到的函数<br />需要特别指出的是，用AfxBeginThread进行线程设置时，第一参数必须象本例所指出的那样声明为Static ，不然参数转换的错误会扰得你不得安宁。 
<p></p><p></p></li>
				<li>在StartThread中输入如下代码：<br />AfxBeginThread(StaticThreadFunc,this);//建立并启动线程 
<p></p><p></p></li>
				<li>在StaticThreadFunc中输入如下代码：<br />return ThreadFunc();//调用完成主要线程代码的函数，注意一定要是Static. 
<p></p><p></p></li>
				<li>实现ThreadFunction：<br />int i;<br />i=5;//触发5次<br />while(i--)<br />{<br />Sleep(5000);//间隔5秒<br />::MessageBox (NULL,"我被<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>触发了！","<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>触发演示",MB_OK);<br />}<br />ExitFlag=FALSE;//ExitFlag是一全局变量，通知主线程结束运行。<br />return 0; <br />} 
<p></p><p></p></li>
				<li>编译并运行工程，将看不到应用程序窗口，但可以看到每隔5秒，桌面上出现一个消息框，5次后弹出主线程结束的消息框。 
<p></p></li>
		</ol>
		<p>以上即本人在学习当中解决 Windows下实现<font style="BACKGROUND-COLOR: yellow" color="red">定时</font>触发而采取的一些办法，各自方法的特点也在介绍当中指出。希望所述能给大家一点帮助，更希望能得到大家的指正。如果您有什么意见和设想，欢迎发E-Mail给我（<a href="mailto:yangshanhe@21cn.com"><font color="#000080">yangshanhe@21cn.com</font></a>）。</p>
		<p> </p>
		<p>==</p>
		<p>很早之前2000年的拙作，集在一起，免得自己都不清楚干过什么。</p>
<img src ="http://www.cppblog.com/tx7do/aggbug/8923.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-06-23 21:48 <a href="http://www.cppblog.com/tx7do/articles/8923.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何对webbrowser和IE编程（十）</title><link>http://www.cppblog.com/tx7do/articles/8920.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 23 Jun 2006 13:46:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/8920.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/8920.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/8920.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/8920.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/8920.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 由Internet Explorer 5激发事件														如你所知， Internet Explorer像其他COM对象一样激发事件—通过连接点.但实际上Internet Explorer如何激发事件呢?每次 Internet Explorer需要向客户提供关于当前活动状态的信息, Internet Explorer 激发通过DWebBrowserEvents2 ...&nbsp;&nbsp;<a href='http://www.cppblog.com/tx7do/articles/8920.html'>阅读全文</a><img src ="http://www.cppblog.com/tx7do/aggbug/8920.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-06-23 21:46 <a href="http://www.cppblog.com/tx7do/articles/8920.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何对webbrowser和IE编程（十一）</title><link>http://www.cppblog.com/tx7do/articles/8921.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 23 Jun 2006 13:46:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/8921.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/8921.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/8921.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/8921.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/8921.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 仅仅用于Internet Explorer的事件														有些是仅仅可用于自动化 Internet Explorer,:												·         																												OnQuit																																					...&nbsp;&nbsp;<a href='http://www.cppblog.com/tx7do/articles/8921.html'>阅读全文</a><img src ="http://www.cppblog.com/tx7do/aggbug/8921.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-06-23 21:46 <a href="http://www.cppblog.com/tx7do/articles/8921.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何对webbrowser和IE编程（九） </title><link>http://www.cppblog.com/tx7do/articles/8919.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 23 Jun 2006 13:45:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/8919.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/8919.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/8919.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/8919.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/8919.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 接收事件的途径														依靠开发工具你创建客户应用程序,你可以接收事件通过不同的途径. 显然, 在Vb中接收事件同在VC中接收事件相比是如此不同和容易.在 C++ 应用中,你可以用不同的技术，通过使用 ATL, MFC, 或者标准C++.																		Visual Basic 中接收事件 									...&nbsp;&nbsp;<a href='http://www.cppblog.com/tx7do/articles/8919.html'>阅读全文</a><img src ="http://www.cppblog.com/tx7do/aggbug/8919.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tx7do/" target="_blank">杨粼波</a> 2006-06-23 21:45 <a href="http://www.cppblog.com/tx7do/articles/8919.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 如何对webbrowser和IE编程（八）</title><link>http://www.cppblog.com/tx7do/articles/8918.html</link><dc:creator>杨粼波</dc:creator><author>杨粼波</author><pubDate>Fri, 23 Jun 2006 13:44:00 GMT</pubDate><guid>http://www.cppblog.com/tx7do/articles/8918.html</guid><wfw:comment>http://www.cppblog.com/tx7do/comments/8918.html</wfw:comment><comments>http://www.cppblog.com/tx7do/articles/8918.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tx7do/comments/commentRss/8918.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tx7do/services/trackbacks/8918.html</trackback:ping><description><![CDATA[
		<h1 style="MARGIN: auto 0cm">
				<span lang="EN-US">
						<font face="宋体">Internet Explorer 事件</font>
				</span>
		</h1>
		<p>
				<span lang="EN-US">
						<font face="宋体">
								<font size="3">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p>
				<font face="宋体">
						<font size="3">
								<i>
										<span lang="EN-US">IWebBrowser2 </span>
								</i>的属性和方法给了你确切的控制导航和用户接口的途径，但是如果你不能够检测到浏览器正在处理什么以及何时处理什么，你还是没有全面的控制它<span lang="EN-US">.因此，WebBrowser控件和Internet Explorer暴露出事件，通过此你可以必要时监视活动以及处理某些活动. 举例来说，假设你建立一个intranet应用程序, 你想限制用户用户访问某些web页.利用Internet Explorer的时间处理句柄,你可以指令应用程序在用户试图访问受限的URL时候取消导航完成。</span></font>
				</font>
		</p>
		<p>
				<span lang="EN-US">
						<font face="宋体">
								<font size="3">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<h1 style="MARGIN: auto 0cm">
				<font face="宋体">事件 和 引出的接口</font>
		</h1>
		<p>
				<font size="3">
						<font face="宋体">无论何时一个<span lang="EN-US">COM 对象需要客户应用程序一个事件发生了, COM 对象发送一个叫做事件的消息. 发送消息的处理过程会激发一个事件. 但如果事件没有任何监听者会如何？ 事件每次都发生吗? 显然, 客户应用程序监听这些事件并控制COM对象.如果一个客户应用想接收来自COM 对象的事件,它"advises" 实际的COM 对象的.</span></font>
				</font>
		</p>
		<p>
				<font size="3">
						<font face="宋体">一个<span lang="EN-US">COM 对象为了通客户通信, 对象自身必须支持一个或者多个外引接口.一个 COM 对象支持的外引接口是作为可连接对象引用. 要成为一个可连接对象，COM对象必须实现<i>IConnectionPointContainer </i>接口。通过此接口，客户可认识到那些外引接口被服务器支持. 外引接口实际通过连接点由客户挂接入COM实现。实现外引接口的客户部分众所周知是通过事件接收槽（event sink）实现的.</span></font>
				</font>
		</p>
		<p>
				<font size="3">
						<font face="宋体">单一的连接点由服务器支持每一个外引接口<span lang="EN-US">.每一个连接点能够操纵一种类型的外引接口且至少支持<i>IConnectionPoint</i> 接口. 图7-1 描述了可连接的对象和它的客户之间的关系.</span></font>
				</font>
		</p>
		<p>
				<span lang="EN-US">
						<font size="3">
								<font face="宋体">
										<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600">
												<stroke joinstyle="miter">
												</stroke>
												<formulas>
														<f eqn="if lineDrawn pixelLineWidth 0">
														</f>
														<f eqn="sum @0 1 0">
														</f>
														<f eqn="sum 0 0 @1">
														</f>
														<f eqn="prod @2 1 2">
														</f>
														<f eqn="prod @3 21600 pixelWidth">
														</f>
														<f eqn="prod @3 21600 pixelHeight">
														</f>
														<f eqn="sum @0 0 1">
														</f>
														<f eqn="prod @6 1 2">
														</f>
														<f eqn="prod @7 21600 pixelWidth">
														</f>
														<f eqn="sum @8 21600 0">
														</f>
														<f eqn="prod @7 21600 pixelHeight">
														</f>
														<f eqn="sum @10 21600 0">
														</f>
												</formulas>
												<path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f">
												</path>
												<lock aspectratio="t" v:ext="edit">
												</lock>
										</shapetype>
										<shape id="_x0000_i1025" style="WIDTH: 297pt; HEIGHT: 143.25pt" type="#_x0000_t75">
												<imagedata o:title="CH7-1_Events" src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msoclip1/01/clip_image001.jpg">
												</imagedata>
										</shape>
								</font>
						</font>
				</span>
		</p>
		<p>
				<font size="3">
						<font face="宋体">
								<b>
										<span lang="EN-US">Figure 7-1.</span>
								</b>
								<span lang="EN-US">
										<i>Connectable object and its client.</i>
								</span>
						</font>
				</font>
		</p>
		<p>
				<font size="3">
						<font face="宋体">每一个服务器必须实现<span lang="EN-US">2个接口以便实现客户可以接收事件—<i>IConnectionPointContainer</i> 和 <i>IConnectionPoint</i>. 我们将先看看这些接口之后将检视实现事件的不同途径.</span></font>
				</font>
		</p>
		<h2 style="MARGIN: auto 0cm">
				<i>
						<span lang="EN-US">
								<font face="宋体">IConnectionPointContainer</font>
						</span>
				</i>
		</h2>
		<p>
				<font face="宋体">
						<font size="3">每一个可连接对象实现了<i><span lang="EN-US">IConnectionPointContainer</span></i><span lang="EN-US">. 通过此接口, 试图接收事件的客户可找出关于可连接对象支持的不同的连接点. 通过调用<i>QueryInterface </i>using 客户可以获得服务器支持的任何接口的指针. (你可以使用任何接口指针调用<i>QueryInterface</i>, 因为全部 COM 接口继承自<i>IUnknown</i>.) 之后客户可以使用<i>IConnectionPointContainer</i> 接口的2个方法中的之一获取可连接点。 如表7-1, 获得可连接点</span></font>
				</font>
		</p>
		<p>
				<font face="宋体">
						<font size="3">
								<b>
										<span lang="EN-US">Table 7-1</span>
								</b>
								<span lang="EN-US">
										<i>Methods of the</i> IConnectionPointContainer<i> Interface</i></span>
						</font>
				</font>
		</p>
		<table style="WIDTH: 95%; mso-cellspacing: 1.5pt; mso-padding-alt: 3.75pt 3.75pt 3.75pt 3.75pt" cellpadding="0" width="95%" border="0">
				<tbody>
						<tr>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align="center">
												<font size="3">
														<b>
																<i>
																		<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法</span>
																</i>
														</b>
														<b>
																<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																		<p>
																		</p>
																</span>
														</b>
												</font>
										</p>
										<p>
										</p>
								</td>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align="center">
												<font size="3">
														<b>
																<i>
																		<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">描述</span>
																</i>
														</b>
														<b>
																<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																		<p>
																		</p>
																</span>
														</b>
												</font>
										</p>
										<p>
										</p>
								</td>
						</tr>
						<tr>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent" valign="top">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
												<font face="Times New Roman">
														<font size="3">
																<i>
																		<span lang="EN-US">EnumConnectionPoints</span>
																</i>
																<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																		<p>
																		</p>
																</span>
														</font>
												</font>
										</p>
										<p>
										</p>
								</td>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent" valign="top">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
												<font size="3">
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">列举可连接对象支持的全部可连接对象</span>
														<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																<p>
																</p>
														</span>
												</font>
										</p>
										<p>
										</p>
								</td>
						</tr>
						<tr>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent" valign="top">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
												<font face="Times New Roman">
														<font size="3">
																<i>
																		<span lang="EN-US">FindConnectionPoint</span>
																</i>
																<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																		<p>
																		</p>
																</span>
														</font>
												</font>
										</p>
										<p>
										</p>
								</td>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent" valign="top">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
												<font size="3">
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">让客户查询可连接对象关于它是否支持一个特殊接口。客户指定特殊的接口（可连接点）的接口标示</span>
														<span lang="EN-US">
																<font face="Times New Roman"> (IID) </font>
														</span>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。如果可连接对象支持此接口，返回</span>
														<font face="Times New Roman">
																<i>
																		<span lang="EN-US">IConnectionPoint</span>
																</i>
																<span lang="EN-US">
																</span>
														</font>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口的指针。</span>
														<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																<p>
																</p>
														</span>
												</font>
										</p>
										<p>
										</p>
								</td>
						</tr>
				</tbody>
		</table>
		<h2 style="MARGIN: auto 0cm">
				<i>
						<span lang="EN-US">
								<font face="宋体">IConnectionPoint</font>
						</span>
				</i>
		</h2>
		<p>
				<font face="宋体">
						<font size="3">一旦客户知道哪个连接点可被连接对象服务器支持<span lang="EN-US">, 客户就可建立同可连接对象的连接。客户通知可连接对象将要在全部事件中接收那些事件.当客户不再需要接收来自可连接对象的事件,客户解除对对象的通知. 表7-2 展示了 <i>IConnectionPoint</i> 接口可被客户连接的. (大多数时候,你将连接到仅仅表中头两个)</span></font>
				</font>
		</p>
		<p>
				<font face="宋体">
						<font size="3">
								<b>
										<span lang="EN-US">Table 7-2</span>
								</b>
								<span lang="EN-US">
										<i>Methods of the </i>IConnectionPoint<i> Interface</i></span>
						</font>
				</font>
		</p>
		<table style="WIDTH: 95%; mso-cellspacing: 1.5pt; mso-padding-alt: 3.75pt 3.75pt 3.75pt 3.75pt" cellpadding="0" width="95%" border="0">
				<tbody>
						<tr>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align="center">
												<font size="3">
														<b>
																<i>
																		<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法</span>
																</i>
														</b>
														<b>
																<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																		<p>
																		</p>
																</span>
														</b>
												</font>
										</p>
										<p>
										</p>
								</td>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align="center">
												<font size="3">
														<b>
																<i>
																		<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">描述</span>
																</i>
														</b>
														<b>
																<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																		<p>
																		</p>
																</span>
														</b>
												</font>
										</p>
										<p>
										</p>
								</td>
						</tr>
						<tr>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent" valign="top">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
												<font face="Times New Roman">
														<font size="3">
																<i>
																		<span lang="EN-US">Advise </span>
																</i>
																<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																		<p>
																		</p>
																</span>
														</font>
												</font>
										</p>
										<p>
										</p>
								</td>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent" valign="top">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
												<font size="3">
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">在客户和可连接对象的某一个可连接点间建立连接。</span>
														<font face="Times New Roman">
														</font>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">客户必须传递它的事件接收槽的</span>
														<font face="Times New Roman">
																<i>
																		<span lang="EN-US">IUnknown</span>
																</i>
																<span lang="EN-US">
																</span>
														</font>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口。</span>
														<font face="Times New Roman">
														</font>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">事件接收槽必须实现</span>
														<font face="Times New Roman">
																<i>
																		<span lang="EN-US">IDispatch</span>
																</i>
																<span lang="EN-US">
																</span>
														</font>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口以接收事件。</span>
														<font face="Times New Roman">
														</font>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">典型地</span>
														<span lang="EN-US">
																<font face="Times New Roman">,</font>
														</span>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">党课连接对象激发事件，可连接对象将调用</span>
														<font face="Times New Roman">
																<i>
																		<span lang="EN-US">IDispatch</span>
																</i>
																<span lang="EN-US">
																</span>
														</font>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口的</span>
														<i>
																<span lang="EN-US">
																		<font face="Times New Roman">Invoke </font>
																</span>
														</i>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法。</span>
														<font face="Times New Roman">
																<i>
																		<span lang="EN-US">Advise</span>
																</i>
																<span lang="EN-US">
																</span>
														</font>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法返回一个</span>
														<span lang="EN-US">
																<font face="Times New Roman"> cookie </font>
														</span>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，当客户中断连接时候，调用</span>
														<i>
																<span lang="EN-US">
																		<font face="Times New Roman">Unadvise</font>
																</span>
														</i>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法时候需要携带此</span>
														<font face="Times New Roman">
																<span lang="EN-US">cookie</span>
																<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																		<p>
																		</p>
																</span>
														</font>
												</font>
										</p>
										<p>
										</p>
								</td>
						</tr>
						<tr>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent" valign="top">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
												<font face="Times New Roman">
														<font size="3">
																<i>
																		<span lang="EN-US">Unadvise </span>
																</i>
																<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																		<p>
																		</p>
																</span>
														</font>
												</font>
										</p>
										<p>
										</p>
								</td>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent" valign="top">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
												<font size="3">
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中断连接</span>
														<font face="Times New Roman">
																<span lang="EN-US">.</span>
																<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																		<p>
																		</p>
																</span>
														</font>
												</font>
										</p>
										<p>
										</p>
								</td>
						</tr>
						<tr>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent" valign="top">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
												<font face="Times New Roman">
														<font size="3">
																<i>
																		<span lang="EN-US">GetConnectionInterface</span>
																</i>
																<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																		<p>
																		</p>
																</span>
														</font>
												</font>
										</p>
										<p>
										</p>
								</td>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent" valign="top">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
												<font size="3">
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">返回由连接点管理的外发接口的</span>
														<span lang="EN-US">
																<font face="Times New Roman">IID . <i>GetConnectionInterface </i></font>
														</span>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法让客户将</span>
														<i>
																<span lang="EN-US">
																		<font face="Times New Roman">IConnectionPoint</font>
																</span>
														</i>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">翻译为一个</span>
														<font face="Times New Roman">
																<span lang="EN-US">IID.</span>
																<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																		<p>
																		</p>
																</span>
														</font>
												</font>
										</p>
										<p>
										</p>
								</td>
						</tr>
						<tr>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent" valign="top">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
												<font face="Times New Roman">
														<font size="3">
																<i>
																		<span lang="EN-US">GetConnectionPointContainer </span>
																</i>
																<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																		<p>
																		</p>
																</span>
														</font>
												</font>
										</p>
										<p>
										</p>
								</td>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent" valign="top">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
												<font size="3">
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">得到刻连接对象的</span>
														<font face="Times New Roman">
																<i>
																		<span lang="EN-US">IConnectionPointContainer</span>
																</i>
																<span lang="EN-US">
																</span>
														</font>
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">接口</span>
														<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																<p>
																</p>
														</span>
												</font>
										</p>
										<p>
										</p>
								</td>
						</tr>
						<tr>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent" valign="top">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
												<font face="Times New Roman">
														<font size="3">
																<i>
																		<span lang="EN-US">EnumConnections </span>
																</i>
																<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																		<p>
																		</p>
																</span>
														</font>
												</font>
										</p>
										<p>
										</p>
								</td>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent" valign="top">
										<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
												<font size="3">
														<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">枚举刻连接对象的当前可连接点</span>
														<font face="Times New Roman">
																<span lang="EN-US">.</span>
																<span lang="EN-US" style="FONT-SIZE: 12pt; COLOR: black; FONT-FAMILY: 宋体">
																		<p>
																		</p>
																</span>
														</font>
												</font>
										</p>
										<p>
										</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 10.5pt; TEXT-INDENT: -10.5pt; mso-char-indent-count: -1.0; mso-char-indent-size: 10.5pt">
				<span lang="EN-US">
						<font size="3">
								<font face="Times New Roman">
										<p>
										</p>
								</font>
						</font>
				</span>
		</p>
		<p>
		</p>
		<h1 style="MARGIN: auto 0cm">
				<font face="宋体">接收事件的途径</font>
		</h1>
		<p>
				<font size="3">
						<font face="宋体">依靠开发工具你创建客户应用程序<span lang="EN-US">,你可以接收事件通过不同的途径. 显然, 在Vb中接收事件同在VC中接收事件相比是如此不同和容易.在 C++ 应用中,你可以用不同的技术，通过使用 ATL, MFC, 或者标准C++.</span></font>
				</font>
		</p>
		<h2 style="MARGIN: auto 0cm">
				<span lang="EN-US">
						<font face="宋体">Visual Basic 中接收事件 </font>
				</span>
		</h2>
		<p>
				<span lang="EN-US">
						<font face="宋体" size="3">Visual Basic是创建大多数类型应用的最轻松的工具, 所以我告诉你VB是处理事件最溶的工具时也不要惊奇. ATL 和 Visual Basic 示例我们同样的工作,但是ATL花费了我4个小时, 而 Visual Basic 例子仅仅只花20 分钟.别说我错了—我是ATL, 和 MFC， C++的忠实信徒,<span style="mso-spacerun: yes">  </span>尤其是你建立一个接口的时候.但是 Visual Basic当建立客户应用程序从类似IE这样的服务器接收事件时是伟大的工具.</font>
				</span>
		</p>
		<p>
				<span lang="EN-US">
						<font face="宋体" size="3">OK,如何从Visual Basic 应用程序中接收事件？当宿主WebBrowser 控件,你不必做任何特别的事. Visual Basic 在form上为WebBrowser 控件接收事件.你所需要做的全部事情就是未你要接收的任何事件创建一个事件处理句柄.</font>
				</span>
		</p>
		<p>
				<font size="3">
						<font face="宋体">你象创建其他事件句柄一样创建句柄<span lang="EN-US"> (例如<i>Form_Load</i> event). 从Procedure下拉列表框中选择你象控制的句柄, 在事件句柄中,加入任何你型在事件激发时执行的任何代码.</span></font>
				</font>
		</p>
		<p>
				<font size="3">
						<font face="宋体">当自动化服务器时候接收事件<span lang="EN-US">, 例如在VB应用中的Internet Explorer,过程直截了当.首先设置对服务器的类型库的引用, 你可以访问Project/References 菜单.之后，采用<i>WithEvents</i> 关键字声明服务器对象的变量.举例, 如果你自动化Internet Explorer, 你将声明变量如下:</span></font>
				</font>
		</p>
		<table style="WIDTH: 95%; mso-cellspacing: 1.5pt; mso-padding-alt: 3.75pt 3.75pt 3.75pt 3.75pt" cellpadding="0" width="95%" border="0">
				<tbody>
						<tr>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent">
										<pre>
												<span lang="EN-US">
														<font face="黑体" size="2">Dim WithEvents InternetExplorer1 As InternetExplorer</font>
												</span>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<font size="3">
						<font face="宋体">下一步，采用<span lang="EN-US">new或者其他 关键字创建实例变量 ，如下：:</span></font>
				</font>
		</p>
		<table style="WIDTH: 95%; mso-cellspacing: 1.5pt; mso-padding-alt: 3.75pt 3.75pt 3.75pt 3.75pt" cellpadding="0" width="95%" border="0">
				<tbody>
						<tr>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent">
										<pre>
												<span lang="EN-US">
														<font face="黑体" size="2">Set InternetExplorer1 = CreateObject("InternetExplorer.Application.1")</font>
												</span>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<font size="3">
						<font face="宋体">或者<span lang="EN-US">:</span></font>
				</font>
		</p>
		<table style="WIDTH: 95%; mso-cellspacing: 1.5pt; mso-padding-alt: 3.75pt 3.75pt 3.75pt 3.75pt" cellpadding="0" width="95%" border="0">
				<tbody>
						<tr>
								<td style="BORDER-RIGHT: #d4d0c8; PADDING-RIGHT: 3.75pt; BORDER-TOP: #d4d0c8; PADDING-LEFT: 3.75pt; PADDING-BOTTOM: 3.75pt; BORDER-LEFT: #d4d0c8; PADDING-TOP: 3.75pt; BORDER-BOTTOM: #d4d0c8; BACKGROUND-COLOR: transparent">
										<pre>
												<span lang="EN-US">
														<font face="黑体" size="2">Set InternetExplorer1 = New InternetExplorer</font>
												</span>
										</pre>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<font size="3">
						<font face="宋体">当你采用以上途径生成实例接收事件<span lang="EN-US">, Visual Basic 自动为你初