﻿<?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++博客-GCC/GNU/Linux Delphi/Window Java/Anywhere</title><link>http://www.cppblog.com/Khan/</link><description>路漫漫，长修远，我们不能没有钱</description><language>zh-cn</language><lastBuildDate>Mon, 08 Sep 2008 10:49:11 GMT</lastBuildDate><pubDate>Mon, 08 Sep 2008 10:49:11 GMT</pubDate><ttl>60</ttl><item><title>sourceforge又被封了...你们想让我说什么呢....</title><link>http://www.cppblog.com/Khan/archive/2008/07/07/55576.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Mon, 07 Jul 2008 15:28:00 GMT</pubDate><guid>http://www.cppblog.com/Khan/archive/2008/07/07/55576.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/55576.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2008/07/07/55576.html#Feedback</comments><slash:comments>17</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/55576.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/55576.html</trackback:ping><description><![CDATA[&nbsp;&nbsp; 此贴是原创, 又不算技术, 关乎开源, 但是又无关软件...矛盾啊....<br>&nbsp;&nbsp; 半夜想down个mingw32... 去sourceforge.发现又上不去了. 凭直觉, 网站出问题的机会几乎没有. 开了个jondo, 果然能上去.<br>&nbsp;&nbsp; 上面的人又封sourceforge了.从06年LUPA事件到现在, 又开始了.<br>&nbsp;&nbsp;&nbsp; 开jondo down东西. 速度不足2k. tor速度更慢, 大家有没有什么好的工具.&nbsp; 这个时势没办法. 不能忍受就要学会享受.<br>&nbsp;&nbsp;&nbsp; 世道真是越来越乱了......<br><br><img src ="http://www.cppblog.com/Khan/aggbug/55576.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2008-07-07 23:28 <a href="http://www.cppblog.com/Khan/archive/2008/07/07/55576.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC6 与GCC-avr交叉环境配置</title><link>http://www.cppblog.com/Khan/archive/2008/06/24/54457.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Tue, 24 Jun 2008 04:05:00 GMT</pubDate><guid>http://www.cppblog.com/Khan/archive/2008/06/24/54457.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/54457.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2008/06/24/54457.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/54457.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/54457.html</trackback:ping><description><![CDATA[01、在C:或其他盘下安装VC6.0<br>02、在C:或其他盘下新建ECC文件夹<br>03、在C:\ECC目录下安装WinAVR-20040720版<br>04、在C:\ECC目录下新建common文件夹<br>05、把lib和inc文件夹copy到C:\ECC\common目录下<br>06、把cl.exe; lhex.exe; link.exe; lview.exe; nmake.exe; rc.exe; sp.exe; ecc.reg; 这8个文件COPY到C:\ECC目录下<br>07、把EccAddin.pdb和EccAddin.dll 文件copy到VC目录下的\common\msdev98\addins 目录下<br>08、把GccWizard.awx 文件copy到 VC目录下的\common\msdev98\template 目录下<br>09、在任何目录下安装port95nt.exe<br>10、把avr5.x 文件copy到C:\ECC\Winavr\avr\lib\ldscripts 目录下<br>11、把usertype&nbsp; 文件copy到 VC目录下的\common\msdev98\bin 目录下<br>12、用记事本打开ecc.reg修改路径并保存，双击此文件添加到注册表中<br>13、打开VC++6.0; 在tools菜单-&gt;options-&gt;directories中将 C:\ECC\common\inc和C:\ECC\winavr\include 两个目录添加到include file选项中。同时将C:\ECC目录添加到executable files 选项中；并将之移到顶部。<br><br>SP.exe 烧录的配置自己google吧<br><br>备注:<br>07 把EccAddin.pdb和EccAddin.dll 文件copy到VC目录下的\common\msdev98\addins 目录下<br>这俩文件是自己写d<br><br> <img src ="http://www.cppblog.com/Khan/aggbug/54457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2008-06-24 12:05 <a href="http://www.cppblog.com/Khan/archive/2008/06/24/54457.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GCC Mingw编译JNI dll要点</title><link>http://www.cppblog.com/Khan/archive/2008/06/23/54364.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Mon, 23 Jun 2008 04:57:00 GMT</pubDate><guid>http://www.cppblog.com/Khan/archive/2008/06/23/54364.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/54364.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2008/06/23/54364.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/54364.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/54364.html</trackback:ping><description><![CDATA[本来想做一个win32平台下, 由于vc没有psapi.dll的库. 所以选择了mingw包和gcc编译器.<br><br>java部分<br>这里主要是申明接口. javah工具会根据你声明的接口自动生成对于的.h头文件<br><br>//SystemInfo.java<br>package com.khan.system;<br><br>public abstract class SystemInfo<br>{<br>&nbsp;&nbsp;&nbsp; // public: ................................................................<br>&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * A simple class to represent data snapshots taken by {@link #makeCPUUsageSnapshot}.<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static final class CPUUsageSnapshot {<br>&nbsp;&nbsp;&nbsp; public final long m_time, m_CPUTime;<br>&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // constructor is private to ensure that makeCPUUsageSnapshot()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // is used as the factory method for this class:<br>&nbsp;&nbsp;&nbsp; private CPUUsageSnapshot (final long time, final long CPUTime) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_time = time;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_CPUTime = CPUTime;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp; &nbsp;<br>&nbsp; } // end of nested class<br><br><br><br>&nbsp;&nbsp;&nbsp; // Custom exception class for throwing<br>&nbsp; public static final class NegativeCPUTime extends Exception {}<br><br><br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * Minimum time difference [in milliseconds] enforced for the inputs into<br>&nbsp;&nbsp;&nbsp; * {@link #getProcessCPUUsage(SystemInfo.CPUUsageSnapshot,SystemInfo.CPUUsageSnapshot)}.<br>&nbsp;&nbsp;&nbsp; * The motivation for this restriction is the fact that &lt;CODE&gt;System.currentTimeMillis()&lt;/CODE&gt;<br>&nbsp;&nbsp;&nbsp; * on some systems has a low resolution (e.g., 10ms on win32). The current value<br>&nbsp;&nbsp;&nbsp; * is 100 ms.<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static final int MIN_ELAPSED_TIME = 100;<br><br><br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * Creates a CPU usage data snapshot by associating CPU time used with system<br>&nbsp;&nbsp;&nbsp; * time. The resulting data can be fed into<br>&nbsp;&nbsp;&nbsp; * {@link #getProcessCPUUsage(SystemInfo.CPUUsageSnapshot,SystemInfo.CPUUsageSnapshot)}.<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static CPUUsageSnapshot makeCPUUsageSnapshot() throws SystemInfo.NegativeCPUTime {<br>&nbsp;&nbsp;&nbsp; long prCPUTime = getProcessCPUTime ();<br>&nbsp;&nbsp;&nbsp; if (prCPUTime&lt;0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new NegativeCPUTime();<br>&nbsp;&nbsp;&nbsp; return new CPUUsageSnapshot (System.currentTimeMillis (), getProcessCPUTime ());<br>&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * Computes CPU usage (fraction of 1.0) between &lt;CODE&gt;start.m_CPUTime&lt;/CODE&gt; and<br>&nbsp;&nbsp;&nbsp; * &lt;CODE&gt;end.m_CPUTime&lt;/CODE&gt; time points [1.0 corresponds to 100% utilization of<br>&nbsp;&nbsp;&nbsp; * all processors].<br>&nbsp;&nbsp;&nbsp; *<br>&nbsp;&nbsp;&nbsp; * @throws IllegalArgumentException if start and end time points are less than<br>&nbsp;&nbsp;&nbsp; * {@link #MIN_ELAPSED_TIME} ms apart.<br>&nbsp;&nbsp;&nbsp; * @throws IllegalArgumentException if either argument is null;<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static double getProcessCPUUsage (final CPUUsageSnapshot start, final CPUUsageSnapshot end) {<br>&nbsp;&nbsp;&nbsp; if (start == null)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new IllegalArgumentException ("null input: start");<br>&nbsp;&nbsp;&nbsp; if (end == null)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new IllegalArgumentException ("null input: end");<br>&nbsp;&nbsp;&nbsp; if (end.m_time &lt; start.m_time + MIN_ELAPSED_TIME)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new IllegalArgumentException ("end time must be at least " + MIN_ELAPSED_TIME + " ms later than start time");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp; return ((double)(end.m_CPUTime - start.m_CPUTime)) / (end.m_time - start.m_time);<br>&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * Returns the PID of the current process. The result is useful when you need<br>&nbsp;&nbsp;&nbsp; * to integrate a Java app with external tools.<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static native int getProcessID ();<br><br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * Returns the number of processors on machine<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static native int getCPUs ();<br><br><br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * Returns CPU (kernel + user) time used by the current process [in milliseconds].<br>&nbsp;&nbsp;&nbsp; * The returned value is adjusted for the number of processors in the system.<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static native long getProcessCPUTime ();<br><br><br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * Returns CPU (kernel + user) time used by the current process [in perecents].<br>&nbsp;&nbsp;&nbsp; * The returned value is either CPU percentage, or zero if this is not supported by OS.<br>&nbsp;&nbsp;&nbsp; * Currently it is supported by Solaris8, and not supported by Windows XP<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static native double getProcessCPUPercentage();<br><br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * Returns maximum memory available in the system.<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static native long getMaxMem ();<br><br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * Returns current free memory in the system.<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static native long getFreeMem ();<br><br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * Returns system name info like "uname" command output<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static native String getSysInfo ();<br><br><br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * Returns CPU usage (fraction of 1.0) so far by the current process. This is a total<br>&nbsp;&nbsp;&nbsp; * for all processors since the process creation time.<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static native double getProcessCPUUsage ();<br><br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * Returns current space allocated for the process, in Kbytes. Those pages may or may not be in memory.<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static native long getMemoryUsage();<br><br><br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * Returns current process space being resident in memory, in Kbytes.<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static native long getMemoryResident();<br><br><br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * Sets the system native process PID for which all measurements will be done.<br>&nbsp;&nbsp;&nbsp; * If this method is not called then the current JVM pid will act as a default.<br>&nbsp;&nbsp;&nbsp; * Returns the native-dependent error code, or 0 in case of success.<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static native int setPid(int pid);<br><br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp; * Closes native-dependent process handle, if necessary.<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; public static native int detachProcess();<br><br>&nbsp;&nbsp;&nbsp; // protected: .............................................................<br><br>&nbsp;&nbsp;&nbsp; // package: ...............................................................<br><br>&nbsp;&nbsp;&nbsp; // private: ...............................................................<br><br><br>&nbsp; private SystemInfo() {} // prevent subclassing<br><br>&nbsp; private static final String SILIB = "SystemInfo";<br><br>&nbsp; static {<br>&nbsp;&nbsp;&nbsp; // loading a native lib in a static initializer ensures that it is<br>&nbsp;&nbsp;&nbsp; // available done before any method in this class is called:<br>&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.loadLibrary (SILIB);<br>&nbsp;&nbsp;&nbsp; }catch (UnsatisfiedLinkError e){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("native lib '" + SILIB<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + "' not found in 'java.library.path': "<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; + System.getProperty ("java.library.path"));<br>&nbsp;&nbsp;&nbsp; }catch (Exception e){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(e.getMessage());<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp; }<br><br>} // end of class<br><br><br>//AppMain.java 测试文件<br>package com.khan.system;<br><br>public class AppMain {<br>&nbsp;&nbsp;&nbsp; /**<br>&nbsp;&nbsp;&nbsp;&nbsp; * Default constructor<br>&nbsp;&nbsp;&nbsp;&nbsp; */<br>&nbsp;&nbsp;&nbsp; public AppMain() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // TODO: Add constructor code here<br>&nbsp;&nbsp;&nbsp; }<br><br><br>&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.sleep(1000);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("getMaxMem:" + SystemInfo.getMaxMem());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("getCPUs:" + SystemInfo.getCPUs());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("getSysInfo:" + SystemInfo.getSysInfo());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }catch (Exception e){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(e.getMessage());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br><br>}<br><br>java部分工程文件. 等同与makefile<br>ant build.xml<br><br>&lt;project name="IpNet" default="build" basedir="."&gt;<br>&nbsp; &lt;description&gt;<br>&nbsp;&nbsp;&nbsp; simple example build file<br>&nbsp; &lt;/description&gt;<br>&nbsp; &lt;!-- set global properties for this build --&gt;<br>&nbsp; &lt;property name="name" value="IpNet"/&gt;<br>&nbsp; &lt;property name="src" location="src"/&gt;<br>&nbsp; &lt;property name="build" location="build"/&gt;<br>&nbsp; &lt;property name="dist"&nbsp; location="dist"/&gt;<br>&nbsp; &lt;property name="web"&nbsp; location="web/WEB-INF/lib"/&gt;<br><br>&nbsp; &lt;path id="master-classpath"&gt;<br>&nbsp;&nbsp;&nbsp; &lt;fileset dir="./lib"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;include name="*.jar"/&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/fileset&gt;<br>&nbsp; &lt;/path&gt;<br><br>&nbsp; &lt;target name="init"&gt;<br>&nbsp;&nbsp;&nbsp; &lt;tstamp/&gt;<br>&nbsp;&nbsp;&nbsp; &lt;mkdir dir="${build}"/&gt;<br>&nbsp;&nbsp;&nbsp; &lt;mkdir dir="${dist}"/&gt;<br>&nbsp; &lt;/target&gt;<br><br>&nbsp; &lt;target name="build" depends="init" description="compile the source " &gt;<br>&nbsp;&nbsp;&nbsp; &lt;javac srcdir="${src}" destdir="${build}"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;compilerarg value="-Xlint:unchecked"/&gt; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;compilerarg value="-deprecation"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;classpath refid="master-classpath"/&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/javac&gt;<br>&nbsp; <br>&nbsp;&nbsp;&nbsp; &lt;copy todir="${build}" preservelastmodified="true"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;fileset dir="${src}"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;include name="*.class"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/fileset&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/copy&gt;<br>&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp; &lt;jar jarfile="${dist}/${name}.jar" compress="true"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;fileset dir="${build}"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;include name="**"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/fileset&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/jar&gt;<br><br>&nbsp;&nbsp;&nbsp; &lt;copy todir="${web}" &gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;fileset dir="${dist}"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;include name="${name}.jar"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/fileset&gt;<br>&nbsp;&nbsp;&nbsp; &lt;/copy&gt;<br>&nbsp; &lt;/target&gt;<br>&nbsp;<br>&nbsp; &lt;target name="clean" description="clean up" &gt;<br>&nbsp;&nbsp;&nbsp; &lt;delete dir="${build}"/&gt;<br>&nbsp;&nbsp;&nbsp; &lt;delete dir="${dist}"/&gt;<br>&nbsp;&nbsp;&nbsp; &lt;delete file="${web}/${name}.jar"/&gt;<br>&nbsp; &lt;/target&gt;<br>&lt;/project&gt;<br><br>在工程目录下ant 编译工程<br>build目录为本工程目标二进制文件目录. 编译后的class在此目录下<br>然后到build目录下<br>javah javah -jni com.khan.system.SystemInfo //注意, 一定要使用包全路径. 如果不是default包的话.<br>会在此目录下生成3个.h文件<br>com_khan_system_SystemInfo.h<br>com_khan_system_SystemInfo_CPUUsageSnapshot.h<br>com_khan_system_SystemInfo_NegativeCPUTime.h<br><br><br>java这边的准备工作完成<br><br>接下来处理c部分<br>新建一个c工程. 我用gcc的. 所以这些部分我手工完成的<br>将刚刚的.h文件实现<br><br>/* ------------------------------------------------------------------------- */<br>/*<br>&nbsp;* An implementation of JNI methods in com.vladium.utils.SystemInformation<br>&nbsp;* class. The author compiled it using Microsoft Visual C++ and GCC for Win32 but the code<br>&nbsp;* should be easy to use with any compiler for win32 platform.<br>&nbsp;*<br>&nbsp;* For simplicity, this implementaion assumes JNI 1.2+ and omits error handling.<br>&nbsp;*<br>&nbsp;* Enhanced by Peter V. Mikhalenko (C) 2004, Deutsche Bank [peter@mikhalenko.com]<br>&nbsp;* Original source (C) 2002, Vladimir Roubtsov [vlad@trilogy.com]<br>&nbsp;*/<br>/* ------------------------------------------------------------------------- */<br><br><br>#include &lt;windows.h&gt;<br>#include &lt;stdio.h&gt;<br>#include &lt;process.h&gt;<br>#include &lt;winbase.h&gt;<br>#include &lt;psapi.h&gt;<br>#include &lt;string.h&gt;<br><br><br>#include "include/com_khan_system_SystemInfo.h"<br><br><br><br>static jint s_PID;<br>static HANDLE s_currentProcess;<br>static int alreadyDetached;<br>static int s_numberOfProcessors;<br>static SYSTEM_INFO systemInfo;<br>static WORD processorArchitecture;<br>static DWORD pageSize;<br>static DWORD processorType;<br>static WORD processorLevel;<br>static WORD processorRevision;<br><br>#define INFO_BUFFER_SIZE 32768<br>#define BUFSIZE 2048<br><br>//BOOL flll = TRUE;<br>/* ------------------------------------------------------------------------- */<br><br>/*<br>&nbsp;* A helper function for converting FILETIME to a LONGLONG [safe from memory<br>&nbsp;* alignment point of view].<br>&nbsp;*/<br>static LONGLONG fileTimeToInt64 (const FILETIME * time)<br>{<br>&nbsp;&nbsp;&nbsp; ULARGE_INTEGER _time;<br><br>&nbsp;&nbsp;&nbsp; _time.LowPart = time-&gt;dwLowDateTime;<br>&nbsp;&nbsp;&nbsp; _time.HighPart = time-&gt;dwHighDateTime;<br><br>&nbsp;&nbsp;&nbsp; return _time.QuadPart;<br>}<br>/* ......................................................................... */<br><br>/*<br>&nbsp;* This method was added in JNI 1.2. It is executed once before any other<br>&nbsp;* methods are called and is ostensibly for negotiating JNI spec versions, but<br>&nbsp;* can also be conveniently used for initializing variables that will not<br>&nbsp;* change throughout the lifetime of this process.<br>&nbsp;*/<br>JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM * vm, void * reserved)<br>{<br>&nbsp; s_PID = _getpid ();<br>&nbsp; s_currentProcess = GetCurrentProcess ();<br>&nbsp; //externalCPUmon = 0;<br>&nbsp; alreadyDetached = 0;<br><br>&nbsp; GetSystemInfo (&amp;systemInfo);<br>&nbsp; s_numberOfProcessors = systemInfo.dwNumberOfProcessors;<br>&nbsp; processorArchitecture = systemInfo.wProcessorArchitecture;<br>&nbsp; pageSize = systemInfo.dwPageSize;<br>&nbsp; processorType = systemInfo.dwProcessorType;<br>&nbsp; processorLevel = systemInfo.wProcessorLevel;<br>&nbsp; processorRevision = systemInfo.wProcessorRevision;<br>&nbsp; printf("SystemInfo.dll is Loaded");<br>&nbsp; return JNI_VERSION_1_2;<br>}<br>/* ......................................................................... */<br><br>JNIEXPORT void JNICALL<br>JNI_OnUnload (JavaVM * vm, void * reserved)<br>{<br>&nbsp; if (!alreadyDetached &amp;&amp; s_currentProcess!=NULL) {<br>&nbsp;&nbsp;&nbsp; CloseHandle(s_currentProcess);<br>&nbsp;&nbsp;&nbsp; printf("[JNI Unload] Detached from native process.");<br>&nbsp;&nbsp;&nbsp; fflush(stdout);<br>&nbsp; }<br>&nbsp; printf("SystemInfo.dll is UnLoaded");<br>}<br>/* ......................................................................... */<br><br>/*<br>&nbsp;* Class:&nbsp;&nbsp;&nbsp;&nbsp; com_vladium_utils_SystemInformation<br>&nbsp;* Method:&nbsp;&nbsp;&nbsp; getCPUs<br>&nbsp;* Signature: ()I<br>&nbsp;*/<br>JNIEXPORT jint JNICALL Java_com_khan_system_SystemInfo_getCPUs(JNIEnv * env, jclass cls)<br>{<br>&nbsp;&nbsp;&nbsp; return (jint)s_numberOfProcessors;<br>}<br>/* ......................................................................... */<br><br><br><br>/*<br>&nbsp;* Class:&nbsp;&nbsp;&nbsp;&nbsp; com_vladium_utils_SystemInformation<br>&nbsp;* Method:&nbsp;&nbsp;&nbsp; getProcessID<br>&nbsp;* Signature: ()I<br>&nbsp;*/<br>JNIEXPORT jint JNICALL<br>Java_com_khan_system_SystemInfo_getProcessID(JNIEnv * env, jclass cls)<br>{<br>&nbsp;&nbsp;&nbsp; return s_PID;<br>}<br>/* ......................................................................... */<br><br>/*<br>&nbsp;* Class:&nbsp;&nbsp;&nbsp;&nbsp; com_vladium_utils_SystemInformation<br>&nbsp;* Method:&nbsp;&nbsp;&nbsp; setPid<br>&nbsp;* Signature: ()I<br>&nbsp;*/<br>JNIEXPORT jint JNICALL<br>Java_com_khan_system_SystemInfo_setPid(JNIEnv * env, jclass cls, jint pid)<br>{<br>&nbsp;&nbsp;&nbsp; DWORD errCode;<br>&nbsp;&nbsp;&nbsp; LPVOID lpMsgBuf;<br>&nbsp;&nbsp;&nbsp; s_PID = pid;<br>&nbsp;&nbsp;&nbsp; s_currentProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);<br>&nbsp;&nbsp;&nbsp; if (s_currentProcess==NULL) {<br>&nbsp;&nbsp;&nbsp;&nbsp; errCode = GetLastError();<br>&nbsp;&nbsp;&nbsp;&nbsp; FormatMessage(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FORMAT_MESSAGE_ALLOCATE_BUFFER |<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FORMAT_MESSAGE_FROM_SYSTEM,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; errCode,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (LPTSTR) &amp;lpMsgBuf,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0, NULL );<br>&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp; printf("[CPUmon] Could not attach to native process. Error code: %ld Error description: %s", errCode, (char *)lpMsgBuf);<br>&nbsp;&nbsp;&nbsp;&nbsp; fflush(stdout);<br>&nbsp;&nbsp;&nbsp;&nbsp; LocalFree(lpMsgBuf);<br>&nbsp;&nbsp;&nbsp;&nbsp; return errCode;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; printf("[CPUmon] Attached to native process.");<br>&nbsp;&nbsp;&nbsp; fflush(stdout);<br>&nbsp;&nbsp;&nbsp; return 0;<br>}<br>/* ......................................................................... */<br><br>/*<br>&nbsp;* Class:&nbsp;&nbsp;&nbsp;&nbsp; com_vladium_utils_SystemInformation<br>&nbsp;* Method:&nbsp;&nbsp;&nbsp; detachProcess<br>&nbsp;* Signature: ()I<br>&nbsp;*/<br>JNIEXPORT jint JNICALL<br>Java_com_khan_system_SystemInfo_detachProcess(JNIEnv * env, jclass cls)<br>{<br>&nbsp;&nbsp;&nbsp; if (!alreadyDetached &amp;&amp; s_currentProcess!=NULL) {<br>&nbsp;&nbsp;&nbsp;&nbsp; CloseHandle(s_currentProcess);<br>&nbsp;&nbsp;&nbsp;&nbsp; alreadyDetached = 1;<br>&nbsp;&nbsp;&nbsp;&nbsp; printf("[CPUmon] Detached from native process.");<br>&nbsp;&nbsp;&nbsp;&nbsp; fflush(stdout);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; return 0;<br>}<br>/* ......................................................................... */<br><br>/*<br>&nbsp;* Class:&nbsp;&nbsp;&nbsp;&nbsp; com_vladium_utils_SystemInformation<br>&nbsp;* Method:&nbsp;&nbsp;&nbsp; getProcessCPUTime<br>&nbsp;* Signature: ()J<br>&nbsp;*/<br>JNIEXPORT jlong JNICALL<br>Java_com_khan_system_SystemInfo_getProcessCPUTime (JNIEnv * env, jclass cls)<br>{<br>&nbsp;&nbsp;&nbsp; FILETIME creationTime, exitTime, kernelTime, userTime;<br>&nbsp;&nbsp;&nbsp; DWORD errCode;<br>&nbsp;&nbsp;&nbsp; LPVOID lpMsgBuf;<br>&nbsp; <br>&nbsp;&nbsp;&nbsp; BOOL resultSuccessful = GetProcessTimes (s_currentProcess, &amp; creationTime, &amp; exitTime, &amp; kernelTime, &amp; userTime);<br>&nbsp;&nbsp;&nbsp; if (!resultSuccessful) {<br>&nbsp;&nbsp;&nbsp;&nbsp; errCode = GetLastError();<br>&nbsp;&nbsp;&nbsp;&nbsp; FormatMessage(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FORMAT_MESSAGE_ALLOCATE_BUFFER |<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FORMAT_MESSAGE_FROM_SYSTEM,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; errCode,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (LPTSTR) &amp;lpMsgBuf,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0, NULL );<br>&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp; printf("[CPUmon] An error occured while trying to get CPU time. Error code: %ld Error description: %s", errCode, (char *)lpMsgBuf);<br><br>&nbsp;&nbsp;&nbsp;&nbsp; fflush(stdout);<br>&nbsp;&nbsp;&nbsp;&nbsp; LocalFree(lpMsgBuf);<br>&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; return (jlong) ((fileTimeToInt64 (&amp; kernelTime) + fileTimeToInt64 (&amp; userTime)) /<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (s_numberOfProcessors * 10000));<br>}<br>/* ......................................................................... */<br><br>/*<br>&nbsp;* Class:&nbsp;&nbsp;&nbsp;&nbsp; com_vladium_utils_SystemInformation<br>&nbsp;* Method:&nbsp;&nbsp;&nbsp; getMaxMem<br>&nbsp;* Signature: ()J<br>&nbsp;*/<br>JNIEXPORT jlong JNICALL<br>Java_com_khan_system_SystemInfo_getMaxMem(JNIEnv * env, jclass cls)<br>{<br>&nbsp;MEMORYSTATUS stat;<br>&nbsp;GlobalMemoryStatus (&amp;stat);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (jlong)(stat.dwTotalPhys/1024);<br>}<br>/* ......................................................................... */<br><br>/*<br>&nbsp;* Class:&nbsp;&nbsp;&nbsp;&nbsp; com_vladium_utils_SystemInformation<br>&nbsp;* Method:&nbsp;&nbsp;&nbsp; getFreeMem<br>&nbsp;* Signature: ()J<br>&nbsp;*/<br>JNIEXPORT jlong JNICALL<br>Java_com_khan_system_SystemInfo_getFreeMem (JNIEnv * env, jclass cls)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MEMORYSTATUS stat;<br>&nbsp;GlobalMemoryStatus (&amp;stat);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (jlong)(stat.dwAvailPhys/1024);<br>}<br>/* ......................................................................... */<br><br><br>/* define min elapsed time (in units of 10E-7 sec): */<br>#define MIN_ELAPSED_TIME (10000)<br><br>/*<br>&nbsp;* Class:&nbsp;&nbsp;&nbsp;&nbsp; com_vladium_utils_SystemInformation<br>&nbsp;* Method:&nbsp;&nbsp;&nbsp; getProcessCPUUsage<br>&nbsp;* Signature: ()D<br>&nbsp;*/<br>JNIEXPORT jdouble JNICALL<br>Java_com_khan_system_SystemInfo_getProcessCPUUsage(JNIEnv * env, jclass cls)<br>{<br>&nbsp;&nbsp;&nbsp; FILETIME creationTime, exitTime, kernelTime, userTime, nowTime; <br>&nbsp;&nbsp;&nbsp; LONGLONG elapsedTime;<br>&nbsp;&nbsp;&nbsp; DWORD errCode;<br>&nbsp;&nbsp;&nbsp; LPVOID lpMsgBuf;<br>&nbsp; <br>&nbsp;&nbsp;&nbsp; BOOL resultSuccessful = GetProcessTimes (s_currentProcess, &amp; creationTime, &amp; exitTime, &amp; kernelTime, &amp; userTime);<br>&nbsp;&nbsp;&nbsp; if (!resultSuccessful) {<br>&nbsp;&nbsp;&nbsp;&nbsp; errCode = GetLastError();<br>&nbsp;&nbsp;&nbsp;&nbsp; FormatMessage(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; errCode,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (LPTSTR) &amp;lpMsgBuf,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0, NULL );<br>&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp; printf("[CPUmon] An error occured while trying to get CPU time. Error code: %ld Error description: %s", errCode, (char *)lpMsgBuf);<br>&nbsp;&nbsp;&nbsp;&nbsp; fflush(stdout);<br>&nbsp;&nbsp;&nbsp;&nbsp; LocalFree(lpMsgBuf);<br>&nbsp;&nbsp;&nbsp;&nbsp; return -1.0;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; GetSystemTimeAsFileTime (&amp; nowTime);<br><br>&nbsp;&nbsp;&nbsp; /*<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NOTE: win32 system time is not very precise [~10ms resolution], use<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sufficiently long sampling intervals if you make use of this method.<br>&nbsp;&nbsp;&nbsp; */<br>&nbsp; <br>&nbsp;&nbsp;&nbsp; elapsedTime = fileTimeToInt64 (&amp; nowTime) - fileTimeToInt64 (&amp; creationTime);<br>&nbsp; <br>&nbsp;&nbsp;&nbsp; if (elapsedTime &lt; MIN_ELAPSED_TIME)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0.0;<br>&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ((jdouble) (fileTimeToInt64 (&amp; kernelTime) + fileTimeToInt64 (&amp; userTime))) /<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (s_numberOfProcessors * elapsedTime);<br>}<br>/* ......................................................................... */<br><br>/*<br>&nbsp;* Class:&nbsp;&nbsp;&nbsp;&nbsp; com_vladium_utils_SystemInformation<br>&nbsp;* Method:&nbsp;&nbsp;&nbsp; getProcessCPUPercentage<br>&nbsp;* Signature: ()D<br>&nbsp;*/<br>JNIEXPORT jdouble JNICALL<br>Java_com_khan_system_SystemInfo_getProcessCPUPercentage (JNIEnv * env, jclass cls)<br>{<br>&nbsp;// Not implemented on Windows<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (jdouble)(-1.0);<br>}<br>/* ......................................................................... */<br><br>/*<br>&nbsp;* Class:&nbsp;&nbsp;&nbsp;&nbsp; com_vladium_utils_SystemInformation<br>&nbsp;* Method:&nbsp;&nbsp;&nbsp; getMemoryUsage<br>&nbsp;* Signature: ()J<br>&nbsp;*/<br>JNIEXPORT jlong JNICALL<br>Java_com_khan_system_SystemInfo_getMemoryUsage (JNIEnv * env, jclass cls)<br>{<br>&nbsp;&nbsp;&nbsp; PROCESS_MEMORY_COUNTERS pmc;<br>&nbsp; <br>&nbsp;&nbsp;&nbsp; if ( GetProcessMemoryInfo( s_currentProcess, &amp;pmc, sizeof(pmc)) )<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;return (jlong)(pmc.PagefileUsage/1024);<br>&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;return (jlong)(0);<br>&nbsp;&nbsp;&nbsp; }<br>}<br>/* ......................................................................... */<br><br>/*<br>&nbsp;* Class:&nbsp;&nbsp;&nbsp;&nbsp; com_vladium_utils_SystemInformation<br>&nbsp;* Method: getMemoryResident * Signature: ()J<br>*/<br>JNIEXPORT jlong JNICALL<br>Java_com_khan_system_SystemInfo_getMemoryResident(JNIEnv * env, jclass cls)<br>{<br>&nbsp;&nbsp;&nbsp; PROCESS_MEMORY_COUNTERS pmc;<br>&nbsp; <br>&nbsp;&nbsp;&nbsp; if ( GetProcessMemoryInfo( s_currentProcess, &amp;pmc, sizeof(pmc)) )<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (jlong)(pmc.WorkingSetSize/1024);<br>&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (jlong)(0);<br>&nbsp;&nbsp;&nbsp; }<br>}<br><br><br>/*<br>&nbsp;* Class:&nbsp;&nbsp;&nbsp;&nbsp; com_vladium_utils_SystemInformation<br>&nbsp;* Method:&nbsp;&nbsp;&nbsp; getSysInfo<br>&nbsp;* Signature: ()S<br>&nbsp;*/<br>JNIEXPORT jstring JNICALL<br>Java_com_khan_system_SystemInfo_getSysInfo(JNIEnv * env, jclass cls)<br>{<br>&nbsp; char buf[2048];<br>&nbsp; char buf2[512];<br>&nbsp; jstring retval;<br>&nbsp; OSVERSIONINFOEX osvi;<br>&nbsp; BOOL bOsVersionInfoEx;<br>&nbsp; TCHAR infoBuf[INFO_BUFFER_SIZE];<br><br>&nbsp; DWORD bufCharCount = INFO_BUFFER_SIZE;<br>&nbsp; *buf = 0; //c语言. 变量定义所有代码在前<br>&nbsp; *buf2 = 0;<br>&nbsp; ZeroMemory(&amp;osvi, sizeof(OSVERSIONINFOEX));<br>&nbsp; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);<br>&nbsp; if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &amp;osvi)) )<br>&nbsp; {<br>&nbsp;&nbsp;&nbsp; osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);<br>&nbsp;&nbsp;&nbsp; if (! GetVersionEx ( (OSVERSIONINFO *) &amp;osvi) ) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Return empty string in case of problems<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto next_label;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp; }<br>&nbsp; &nbsp;<br>&nbsp; switch (osvi.dwPlatformId)<br>&nbsp; {<br>&nbsp;&nbsp;&nbsp; // Test for the Windows NT product family.<br>&nbsp;&nbsp;&nbsp; case VER_PLATFORM_WIN32_NT:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Test for the specific product.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( osvi.dwMajorVersion == 5 &amp;&amp; osvi.dwMinorVersion == 2 )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"WinServer2003, ");<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( osvi.dwMajorVersion == 5 &amp;&amp; osvi.dwMinorVersion == 1 )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"WinXP ");<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( osvi.dwMajorVersion == 5 &amp;&amp; osvi.dwMinorVersion == 0 )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"Win2K ");<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( osvi.dwMajorVersion &lt;= 4 )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"WinNT ");<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Display service pack (if any) and build number.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( osvi.dwMajorVersion == 4 &amp;&amp; lstrcmpi( osvi.szCSDVersion, "Service Pack 6" ) == 0 )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HKEY hKey;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LONG lRet;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Test for SP6 versus SP6a.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, "SOFTWAREMicrosoftWindows NTCurrentVersionHotfixQ246009", 0, KEY_QUERY_VALUE, &amp;hKey );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( lRet == ERROR_SUCCESS ) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(buf2, "SP 6a (Build %d), ", (int)(osvi.dwBuildNumber &amp; 0xFFFF) );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,buf2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else // Windows NT 4.0 prior to SP6a<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(buf2, "%s (Build %d), ",<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; osvi.szCSDVersion,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (int)(osvi.dwBuildNumber &amp; 0xFFFF));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,buf2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RegCloseKey( hKey );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else // not Windows NT 4.0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(buf2, "%s (Build %d), ", osvi.szCSDVersion, (int)(osvi.dwBuildNumber &amp; 0xFFFF));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,buf2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Test for the Windows Me/98/95.<br>&nbsp;&nbsp;&nbsp; case VER_PLATFORM_WIN32_WINDOWS:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (osvi.dwMajorVersion == 4 &amp;&amp; osvi.dwMinorVersion == 0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"Win95 ");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"OSR2 " );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (osvi.dwMajorVersion == 4 &amp;&amp; osvi.dwMinorVersion == 10)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"Win98 ");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( osvi.szCSDVersion[1] == 'A' )<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"SE " );<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (osvi.dwMajorVersion == 4 &amp;&amp; osvi.dwMinorVersion == 90)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"WinME ");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br><br>&nbsp;&nbsp;&nbsp; case VER_PLATFORM_WIN32s:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"Win32s ");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br>&nbsp; }<br>&nbsp; &nbsp;<br>next_label:<br><br>&nbsp; strcat(buf,"on ");<br>&nbsp; // Get and display the name of the computer.<br>&nbsp; bufCharCount = INFO_BUFFER_SIZE;<br>&nbsp; if( !GetComputerName( infoBuf, &amp;bufCharCount ) )<br>&nbsp;&nbsp;&nbsp; goto next_label_2;<br>&nbsp; strcat(buf, infoBuf );<br>&nbsp; <br>next_label_2:<br>&nbsp; strcat(buf," (");<br>&nbsp; if (!(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS &amp;&amp; osvi.dwMajorVersion == 4 &amp;&amp; osvi.dwMinorVersion == 0)) {<br>&nbsp;&nbsp;&nbsp; // Win95 does not keep CPU info in registry<br>&nbsp;&nbsp;&nbsp; LONG lRet;<br>&nbsp;&nbsp;&nbsp; HKEY hKey;<br>&nbsp;&nbsp;&nbsp; char szOrigCPUType[BUFSIZE];<br>&nbsp;&nbsp;&nbsp; int i=0;<br>&nbsp;&nbsp;&nbsp; DWORD dwBufLen=BUFSIZE;<br>&nbsp;&nbsp;&nbsp; lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, "HARDWAREDESCRIPTIONSystemCentralProcessor", 0, KEY_QUERY_VALUE, &amp;hKey );<br>&nbsp;&nbsp;&nbsp; if( lRet != ERROR_SUCCESS ) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto next_label_3;<br>&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp; lRet = RegQueryValueEx( hKey, "ProcessorNameString", NULL, NULL, (LPBYTE) szOrigCPUType, &amp;dwBufLen);<br>&nbsp;&nbsp;&nbsp; if( (lRet != ERROR_SUCCESS) || (dwBufLen &gt; BUFSIZE) ) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto next_label_3;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; RegCloseKey( hKey );<br><br>&nbsp;&nbsp;&nbsp; if (strlen(szOrigCPUType)&gt;0) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(szOrigCPUType[i]==' ' &amp;&amp; szOrigCPUType[i]!=0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i++;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,szOrigCPUType+i);<br>&nbsp;&nbsp;&nbsp; } else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto next_label_3;<br>&nbsp; } else {<br>next_label_3:<br>&nbsp;&nbsp; if (processorArchitecture==PROCESSOR_ARCHITECTURE_UNKNOWN)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"unknown_arch");<br>&nbsp;&nbsp; else if (processorArchitecture==PROCESSOR_ARCHITECTURE_INTEL) {<br>&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"Intel ");<br>&nbsp;&nbsp;&nbsp;&nbsp; sprintf(buf2,"level %d ",processorLevel);<br>&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,buf2);<br>&nbsp;&nbsp; } else if (processorArchitecture==PROCESSOR_ARCHITECTURE_IA64)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"IA64 ");<br>&nbsp;&nbsp; else if (processorArchitecture==PROCESSOR_ARCHITECTURE_MIPS)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"MIPS ");<br>&nbsp;&nbsp; else if (processorArchitecture==PROCESSOR_ARCHITECTURE_ALPHA)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"Alpha ");<br>&nbsp;&nbsp; else if (processorArchitecture==PROCESSOR_ARCHITECTURE_PPC)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"PowerPC ");<br>&nbsp;&nbsp; else if (processorArchitecture==PROCESSOR_ARCHITECTURE_SHX)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"SHX ");<br>&nbsp;&nbsp; else if (processorArchitecture==PROCESSOR_ARCHITECTURE_ALPHA64)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"Alpha64 ");<br>&nbsp;&nbsp; else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcat(buf,"unknown_arch ");<br>&nbsp; }<br>&nbsp; <br>&nbsp; strcat(buf,")");<br><br>&nbsp; retval = (*env)-&gt;NewStringUTF(env,buf);<br>&nbsp; return retval;<br>}<br>/* ......................................................................... */<br><br><br><br><br><br><br>#undef MIN_ELAPSED_TIME<br><br>/* ------------------------------------------------------------------------- */<br>/* end of file */<br><br><br><br><br><br>编写makefile<br>#&nbsp;&nbsp;&nbsp; Project: SystemInfo<br>#&nbsp;&nbsp;&nbsp; Makefile created by Khan.Lau<br>#&nbsp;&nbsp;&nbsp; Write&nbsp;&nbsp;&nbsp; by 2007-05-16<br><br><br>#&nbsp;&nbsp;&nbsp; 应用程序名<br>#LIB = SystemInfo.a<br>DLL =&nbsp;&nbsp;&nbsp; SystemInfo.dll<br>#BIN = SystemInfo.exe<br><br><br>#&nbsp;&nbsp;&nbsp; 输出目录<br>#&nbsp;&nbsp;&nbsp; CONFIGURATION = debug<br>CONFIGURATION&nbsp;&nbsp;&nbsp; =&nbsp;&nbsp;&nbsp; release<br><br>#&nbsp;&nbsp;&nbsp; 取得项目的当前工作路径<br>PROJECT_PATH = "D:/Project/Cplus/SystemInfo/src"<br><br>CPP = g++<br>CC = gcc<br>COMPILER = $(CC)<br><br>#&nbsp;&nbsp;&nbsp; c/c++库路径<br>LIBPATH = "D:/Develop/CPlus/MinGW/lib"<br><br>WINDRES = windres.exe<br>RES =<br><br>#&nbsp;&nbsp;&nbsp; 包路径<br>LIBS = -L$(LIBPATH) \<br>&nbsp;&nbsp;&nbsp; -lpsapi<br><br>INCS = -I$(LIBPATH)/include \<br>&nbsp;&nbsp;&nbsp; -ID:/Develop/Java/jdk1.5.0_02/include \<br>&nbsp;&nbsp;&nbsp; -ID:/Develop/Java/jdk1.5.0_02/include/win32 \<br>&nbsp;&nbsp;&nbsp; -I$(PROJECT_PATH)<br><br>CXXINCS = -I$(LIBPATH)/include \<br>&nbsp;&nbsp;&nbsp; -I$(LIBPATH)/include/c++/3.2.3 \<br>&nbsp;&nbsp;&nbsp; -I$(LIBPATH)/include/c++/3.2.3/backward \<br>&nbsp;&nbsp;&nbsp; -I$(LIBPATH)/include/c++/3.2.3/mingw32 \<br>&nbsp;&nbsp;&nbsp; -I$(PROJECT_PATH)<br><br>DLLFLAGS = -DBUILD_DLL<br>CXXFLAGS = $(DLLFLAGS) -g -Wall $(CXXINCS)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>CFLAGS = $(DLLFLAGS) -Wall $(INCS)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br><br>COMPILER_FLAG = $(CFLAGS)<br><br>RM = rm -f<br><br>LINKOBJ = $(CONFIGURATION)/SystemInfo.o&nbsp;&nbsp;&nbsp; \<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $(RES)<br><br><br>.PHONY:&nbsp;&nbsp;&nbsp; all all-before all-after clean clean-custom rebuild&nbsp; &nbsp;<br><br>all: all-before $(DLL) all-after<br><br>clean: clean-custom<br>&nbsp;&nbsp;&nbsp; ${RM} $(LINKOBJ) $(CONFIGURATION)/$(DLL)&nbsp; &nbsp;<br><br>$(LIB): $(LINKOBJ)<br>&nbsp;&nbsp;&nbsp; ar -r $(CONFIGURATION)/$(LIB) $(LINKOBJ)&nbsp; &nbsp;<br><br>$(DLL): $(LINKOBJ)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $(COMPILER)&nbsp; -shared -Wl,--add-stdcall-alias&nbsp; -o $(CONFIGURATION)/$(DLL) $(LINKOBJ) $(LIBS)<br><br>$(BIN):&nbsp;&nbsp;&nbsp; $(LINKOBJ)<br>&nbsp;&nbsp;&nbsp; $(COMPILER) -o $(CONFIGURATION)/$(BIN) $(LINKOBJ) $(LIBS)<br><br>#缩减可执行文件大小<br>strip:&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp; strip&nbsp;&nbsp;&nbsp; $(CONFIGURATION)/$(LIB)<br>&nbsp; &nbsp;<br><br>################################################################################<br><br>$(CONFIGURATION)/SystemInfo.o: src/dll/SystemInfo.c<br>&nbsp;&nbsp;&nbsp; $(COMPILER) -c src/dll/SystemInfo.c -o $(CONFIGURATION)/SystemInfo.o $(COMPILER_FLAG)<br><br><br>################################################################################<br><br>rebuild: clean&nbsp;&nbsp;&nbsp; all<br><br><br><br>makefile中注意<br>$(DLL): $(LINKOBJ)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $(COMPILER)&nbsp; -shared -Wl,--add-stdcall-alias&nbsp; -o $(CONFIGURATION)/$(DLL) $(LINKOBJ) $(LIBS)<br><br>-shared -Wl,--add-stdcall-alias 这3个参数是一定要的. 具体含义请参阅gcc帮助..<br>否则会出现如下异常:java.lang.UnsatisfiedLinkError<br>如果你确认自己的dll名没有错. loadlibrary的名字也没有填错. 那应该就要检查如上部分了<br><br>实际发布的时候. 不要使用调试版本. 也就是编译参数不能有-g<br><br>ok, 现在make出dll使用吧....<br><br><br>我本地测试的输出结果为 :<br><br>getMaxMem:506604<br>getCPUs:1<br>getSysInfo:WinXP Service Pack 2 (Build 2600), on A7648944D08843B (Intel level 15 )<br>SystemInfo.dll is Loaded<img src ="http://www.cppblog.com/Khan/aggbug/54364.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2008-06-23 12:57 <a href="http://www.cppblog.com/Khan/archive/2008/06/23/54364.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ubuntu 下安装wine</title><link>http://www.cppblog.com/Khan/archive/2008/05/23/50909.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Fri, 23 May 2008 15:18:00 GMT</pubDate><guid>http://www.cppblog.com/Khan/archive/2008/05/23/50909.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/50909.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2008/05/23/50909.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/50909.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/50909.html</trackback:ping><description><![CDATA[编译源码的方式就不写了， 无非就是解决依赖关系， down一堆的包， 然后make<br>简单粗暴的来......<br><br>1.安装<br>sudo apt-get install <span class="hilite1">wine<br><br>2.初始化<br>winecfg&nbsp; //不要用root模式, 也就是不要用sudo<br><br>如果出现以下警告或者错误:<br></span><span class="postbody">preloader: Warning: failed to reserve range 00000000-60000000
<br>
err:dosmem:setup_dos_mem Cannot use first megabyte for DOS address space, please report
</span><br><br>解决方法: 其实我不清楚为什么要这么做....唉.....<br><span class="postbody">sudo sysctl -w vm.mmap_min_addr=0
<br>
<br>
然后打开sysctl.conf
<br>
sudo gedit /etc/sysctl.conf
<br>
<br>
#vm.mmap_min_addr = 65536&nbsp;
//注释掉这行<br>
vm.mmap_min_addr = 0&nbsp;
//改为这行</span><br><span class="hilite1"><br><br></span>
<p>3、设置中文问题</p>
<p>&nbsp;&nbsp; 先把字体simsun.ttc（在你的windows的<span class="hilite2">安装</span>目录里的font文件夹里找，找不到可以从网上下到） 复制到 /home/你的用户名/.<span class="hilite1">wine</span>/drive_c/windows/fonts 文件夹中，<span style="color: #ff0000; font-size: small;">要显示隐藏文件夹按Ctrl+H</span>
</p>
<br>
<p>&nbsp; 修改注册表，在命令行输入 gedit&nbsp; ~/.<span class="hilite1">wine</span>/system.reg</p>
<p>&nbsp; 找到&#8220;[System\\CurrentControlSet\\Hardware
Profiles\\Current\\Software\\Fonts]&#8221;，将其中的&#8220;&#8220;LogPixels&#8221;=dword:00000060&#8221;改成
&#8220;&#8220;LogPixels&#8221;=dword:00000070&#8220;。<br>
<br>
再找到&#8221;[Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes] xxxx&#8220;项，将其中的&#8221;MS Shell Dlg&#8220;相关的两项修改成如下内容（即更换字体为宋体）：<br>
<br>
&#8220;MS Shell Dlg&#8221;=&#8221;SimSun&#8221;<br>
&#8220;MS Shell Dlg 2&#8243;=&#8221;SimSun&#8221;<br>
<br>
然后：gedit ~/.<span class="hilite1">wine</span>/drive_c/windows/win.ini</p>
<p>在其中加上（如果没有），有的话修改成如下</p>
<p> [Desktop]<br>
menufontsize=13<br>
messagefontsize=13<br>
statusfontsize=13<br>
IconTitleSize=13</p>
<p>现在中文显示应该正常了</p>
<br><span class="hilite1"><br></span><img src ="http://www.cppblog.com/Khan/aggbug/50909.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2008-05-23 23:18 <a href="http://www.cppblog.com/Khan/archive/2008/05/23/50909.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>linux下执行java的脚本</title><link>http://www.cppblog.com/Khan/archive/2008/05/06/49008.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Tue, 06 May 2008 07:26:00 GMT</pubDate><guid>http://www.cppblog.com/Khan/archive/2008/05/06/49008.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/49008.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2008/05/06/49008.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/49008.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/49008.html</trackback:ping><description><![CDATA[<br><font face="monospace"><font color="#0000ff">#!/bin/sh</font><br><font color="#0000ff"># Filename : StockDispatch</font><br><font color="#0000ff"># &amp; nohub</font><br># 思路: 遍历当前目录和$JAVA_HOME/lib下所有的jar文件, 加入-cp的环境变量 然后执行入口类<br><font color="#008080">SETCOLOR_BOLD</font>=<font color="#804040"><strong>"</strong></font><font color="#ff00ff">echo -en </font><font color="#6a5acd">\\</font><font color="#ff00ff">033[1;32m</font><font color="#804040"><strong>"</strong></font><br><font color="#008080">SETCOLOR_NORMAL</font>=<font color="#804040"><strong>"</strong></font><font color="#ff00ff">echo -en </font><font color="#6a5acd">\\</font><font color="#ff00ff">033[0;39m</font><font color="#804040"><strong>"</strong></font><br><br><font color="#008080"><br>CLASSPATH</font>=<font color="#804040"><strong>""</strong></font><br><font color="#008080">CURRDIR</font>=<font color="#804040"><strong>"</strong></font><span style="background-color: #ff0000;"><font color="#ffffff">$(</font></span><font color="#804040"><strong>pwd</strong></font><span style="background-color: #ff0000;"><font color="#ffffff">)</font></span><font color="#804040"><strong>"</strong></font><br><font color="#008080">LIBDIR</font>=<font color="#804040"><strong>"</strong></font><font color="#a020f0">$CURRDIR</font><font color="#ff00ff">&nbsp;/usr/local/jdk1.5.0_02/lib</font><font color="#804040"><strong>"</strong></font><br><font color="#008080">tmpFile</font>=./<font color="#ff00ff">11</font><br><font color="#008080">pidFile</font>=./<font color="#a020f0">${</font><font color="#a020f0">0</font><font color="#a020f0">}</font>pid<br><br><font color="#0000ff"># find all jar library from current dir and CLASSPATH</font><br>find <font color="#a020f0">$LIBDIR</font>&nbsp;<font color="#6a5acd">-name</font>&nbsp;<font color="#804040"><strong>"</strong></font><font color="#ff00ff">*.jar</font><font color="#804040"><strong>"</strong></font><font color="#804040"><strong>&gt;</strong></font><font color="#a020f0">$tmpFile</font><br><br><br><font color="#0000ff"># add jar library to CLASSPATH</font><br><font color="#008080">I</font>=<font color="#ff00ff">0</font><br><font color="#804040"><strong>while</strong></font><font color="#804040"><strong>&nbsp;</strong></font><font color="#804040"><strong>read</strong></font><font color="#804040"><strong>&nbsp;line </strong></font><br><font color="#804040"><strong>do</strong></font>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#008080">I</font>=<font color="#6a5acd">`expr </font><font color="#a020f0">$I</font><font color="#6a5acd">&nbsp;+ </font><font color="#ff00ff">1</font><font color="#6a5acd">&nbsp;`</font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#804040"><strong>if</strong></font>&nbsp;<font color="#804040"><strong>[</strong></font>&nbsp;<font color="#a020f0">$I</font>&nbsp;<font color="#804040"><strong>-eq</strong></font>&nbsp;<font color="#ff00ff">1</font>&nbsp;<font color="#804040"><strong>]</strong></font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#804040"><strong>then</strong></font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#008080">CLASSPATH</font>=<font color="#804040"><strong>"</strong></font><font color="#a020f0">${</font><font color="#a020f0">line</font><font color="#a020f0">}</font><font color="#804040"><strong>"</strong></font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#804040"><strong>else</strong></font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#008080">CLASSPATH</font>=<font color="#804040"><strong>"</strong></font><font color="#a020f0">${</font><font color="#a020f0">CLASSPATH</font><font color="#a020f0">}</font><font color="#ff00ff">:</font><font color="#a020f0">${</font><font color="#a020f0">line</font><font color="#a020f0">}</font><font color="#804040"><strong>"</strong></font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#804040"><strong>fi</strong></font><br><font color="#804040"><strong>done</strong></font><font color="#804040"><strong>&lt;</strong></font>&nbsp;<font color="#a020f0">$tmpFile</font><br><br>rm <font color="#a020f0">$tmpFile</font><br><br><br><font color="#0000ff"># run program</font><br><font color="#804040"><strong>if</strong></font>&nbsp;<font color="#804040"><strong>[</strong></font>&nbsp;<font color="#804040"><strong>"</strong></font><font color="#ff00ff">-</font><font color="#a020f0">$1</font><font color="#804040"><strong>"</strong></font>&nbsp;<font color="#804040"><strong>!=</strong></font>&nbsp;<font color="#804040"><strong>"</strong></font><font color="#ff00ff">-</font><font color="#804040"><strong>"</strong></font>&nbsp;<font color="#804040"><strong>]</strong></font><font color="#804040"><strong>;</strong></font>&nbsp;<font color="#804040"><strong>then</strong></font>&nbsp;&nbsp; <font color="#0000ff"># if parameter 1 is not null</font><br>&nbsp;&nbsp;<font color="#804040"><strong>echo</strong></font><font color="#ff00ff">&nbsp;</font><font color="#804040"><strong>"</strong></font><font color="#ff00ff">java -cp .:</font><font color="#a020f0">${</font><font color="#a020f0">CLASSPATH</font><font color="#a020f0">}</font><font color="#ff00ff">&nbsp;&nbsp;com.khan.AppMain.UpdateCell2CBC </font><font color="#a020f0">$1</font><font color="#ff00ff">&nbsp;&gt; updatecell2cbc.log</font><font color="#804040"><strong>"</strong></font><br><font color="#0000ff">#&nbsp;&nbsp;java -cp .:${CLASSPATH} com.khan.AppMain.UpdateCell2CBC $1&gt; updatecell2cbc.log</font><br><font color="#804040"><strong>else</strong></font><br>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#804040"><strong>echo</strong></font><font color="#ff00ff">&nbsp;</font><font color="#804040"><strong>"</strong></font><font color="#ff00ff">&nbsp;&nbsp;usage: </font><font color="#a020f0">$0</font><font color="#ff00ff">&nbsp;&nbsp;CellListFile</font><font color="#804040"><strong>"</strong></font><br><font color="#804040"><strong>fi</strong></font><br><br><br></font><img src ="http://www.cppblog.com/Khan/aggbug/49008.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2008-05-06 15:26 <a href="http://www.cppblog.com/Khan/archive/2008/05/06/49008.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>epoll简介(转载)</title><link>http://www.cppblog.com/Khan/archive/2008/04/02/46015.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Wed, 02 Apr 2008 03:58:00 GMT</pubDate><guid>http://www.cppblog.com/Khan/archive/2008/04/02/46015.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/46015.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2008/04/02/46015.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/46015.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/46015.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Epoll  epoll_event epoll_wait epoll_ctl epoll_create&nbsp;&nbsp;<a href='http://www.cppblog.com/Khan/archive/2008/04/02/46015.html'>阅读全文</a><img src ="http://www.cppblog.com/Khan/aggbug/46015.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2008-04-02 11:58 <a href="http://www.cppblog.com/Khan/archive/2008/04/02/46015.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Epoll模型</title><link>http://www.cppblog.com/Khan/archive/2008/04/02/46013.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Wed, 02 Apr 2008 03:37:00 GMT</pubDate><guid>http://www.cppblog.com/Khan/archive/2008/04/02/46013.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/46013.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2008/04/02/46013.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/46013.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/46013.html</trackback:ping><description><![CDATA[&nbsp;Linux 2.6内核中提高网络I/O性能的新方法-epoll I/O多路复用技术在比较多的TCP网络服务器中有使用，即比较多的用到select函数。<br><br>1、为什么select落后<br>&nbsp;&nbsp;&nbsp; 首先，在Linux内核中，select所用到的FD_SET是有限的，即内核中有个参数__FD_SETSIZE定义了每个FD_SET的句柄个数，在我用的2.6.15-25-386内核中，该值是1024，搜索内核源代码得到：<br>include/linux/posix_types.h:<br>#define __FD_SETSIZE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1024<br>也就是说，如果想要同时检测1025个句柄的可读状态是不可能用select实现的。或者同时检测1025个句柄的可写状态也是不可能的。其次，内核中实现 select是用轮询方法，即每次检测都会遍历所有FD_SET中的句柄，显然，select函数执行时间与FD_SET中的句柄个数有一个比例关系，即 select要检测的句柄数越多就会越费时。当然，在前文中我并没有提及poll方法，事实上用select的朋友一定也试过poll，我个人觉得 select和poll大同小异，个人偏好于用select而已。<br><br>2、内核中提高I/O性能的新方法epoll<br>&nbsp;&nbsp;&nbsp; epoll是什么？按照man手册的说法：是为处理大批量句柄而作了改进的poll。要使用epoll只需要这三个系统调用：epoll_create(2)， epoll_ctl(2)， epoll_wait(2)。<br>当然，这不是2.6内核才有的，它是在2.5.44内核中被引进的(epoll(4) is a new API introduced in Linux kernel 2.5.44)<br><br>Linux2.6内核epoll介绍<br>&nbsp;&nbsp;&nbsp; 先介绍2本书《The Linux Networking Architecture--Design and Implementation of Network Protocols in the Linux Kernel》，以2.4内核讲解Linux TCP/IP实现，相当不错.作为一个现实世界中的实现，很多时候你必须作很多权衡，这时候参考一个久经考验的系统更有实际意义。举个例子,linux内核中sk_buff结构为了追求速度和安全，牺牲了部分内存，所以在发送TCP包的时候，无论应用层数据多大,sk_buff最小也有272的字节.其实对于socket应用层程序来说，另外一本书《UNIX Network Programming Volume 1》意义更大一点.2003年的时候，这本书出了最新的第3版本，不过主要还是修订第2版本。其中第6章《I/O Multiplexing》是最重要的。Stevens给出了网络IO的基本模型。在这里最重要的莫过于select模型和Asynchronous I/O模型.从理论上说，AIO似乎是最高效的，你的IO操作可以立即返回，然后等待os告诉你IO操作完成。但是一直以来，如何实现就没有一个完美的方案。最著名的windows完成端口实现的AIO,实际上也是内部用线程池实现的罢了，最后的结果是IO有个线程池，你应用也需要一个线程池...... 很多文档其实已经指出了这带来的线程context-switch带来的代价。在linux 平台上，关于网络AIO一直是改动最多的地方，2.4的年代就有很多AIO内核patch,最著名的应该算是SGI那个。但是一直到2.6内核发布，网络模块的AIO一直没有进入稳定内核版本(大部分都是使用用户线程模拟方法，在使用了NPTL的linux上面其实和windows的完成端口基本上差不多了)。2.6内核所支持的AIO特指磁盘的AIO---支持io_submit(),io_getevents()以及对Direct IO的支持(就是绕过VFS系统buffer直接写硬盘，对于流服务器在内存平稳性上有相当帮助)。<br>&nbsp;&nbsp;&nbsp; 所以，剩下的select模型基本上就是我们在linux上面的唯一选择，其实，如果加上no-block socket的配置，可以完成一个"伪"AIO的实现，只不过推动力在于你而不是os而已。不过传统的select/poll函数有着一些无法忍受的缺点，所以改进一直是2.4-2.5开发版本内核的任务，包括/dev/poll，realtime signal等等。最终，Davide Libenzi开发的epoll进入2.6内核成为正式的解决方案<br><br>3、epoll的优点<br>&lt;1&gt;支持一个进程打开大数目的socket描述符(FD)<br>&nbsp;&nbsp;&nbsp; select 最不能忍受的是一个进程所打开的FD是有一定限制的，由FD_SETSIZE设置，默认值是2048。对于那些需要支持的上万连接数目的IM服务器来说显然太少了。这时候你一是可以选择修改这个宏然后重新编译内核，不过资料也同时指出这样会带来网络效率的下降，二是可以选择多进程的解决方案(传统的 Apache方案)，不过虽然linux上面创建进程的代价比较小，但仍旧是不可忽视的，加上进程间数据同步远比不上线程间同步的高效，所以也不是一种完美的方案。不过 epoll则没有这个限制，它所支持的FD上限是最大可以打开文件的数目，这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右，具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。<br><br>&lt;2&gt;IO效率不随FD数目增加而线性下降<br>&nbsp;&nbsp;&nbsp; 传统的select/poll另一个致命弱点就是当你拥有一个很大的socket集合，不过由于网络延时，任一时间只有部分的socket是"活跃"的，但是select/poll每次调用都会线性扫描全部的集合，导致效率呈现线性下降。但是epoll不存在这个问题，它只会对"活跃"的socket进行操作---这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。那么，只有"活跃"的socket才会主动的去调用 callback函数，其他idle状态socket则不会，在这点上，epoll实现了一个"伪"AIO，因为这时候推动力在os内核。在一些 benchmark中，如果所有的socket基本上都是活跃的---比如一个高速LAN环境，epoll并不比select/poll有什么效率，相反，如果过多使用epoll_ctl,效率相比还有稍微的下降。但是一旦使用idle connections模拟WAN环境,epoll的效率就远在select/poll之上了。<br><br>&lt;3&gt;使用mmap加速内核与用户空间的消息传递。<br>&nbsp;&nbsp;&nbsp; 这点实际上涉及到epoll的具体实现了。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间，如何避免不必要的内存拷贝就很重要，在这点上，epoll是通过内核于用户空间mmap同一块内存实现的。而如果你想我一样从2.5内核就关注epoll的话，一定不会忘记手工 mmap这一步的。<br><br>&lt;4&gt;内核微调<br>&nbsp;&nbsp;&nbsp; 这一点其实不算epoll的优点了，而是整个linux平台的优点。也许你可以怀疑 linux平台，但是你无法回避linux平台赋予你微调内核的能力。比如，内核TCP/IP协议栈使用内存池管理sk_buff结构，那么可以在运行时期动态调整这个内存pool(skb_head_pool)的大小--- 通过echo XXXX&gt;/proc/sys/net/core/hot_list_length完成。再比如listen函数的第2个参数(TCP完成3次握手的数据包队列长度)，也可以根据你平台内存大小动态调整。更甚至在一个数据包面数目巨大但同时每个数据包本身大小却很小的特殊系统上尝试最新的NAPI网卡驱动架构。<br><br>4、epoll的工作模式<br>&nbsp;&nbsp;&nbsp; 令人高兴的是，2.6内核的epoll比其2.5开发版本的/dev/epoll简洁了许多，所以，大部分情况下，强大的东西往往是简单的。唯一有点麻烦是epoll有2种工作方式:LT和ET。<br>LT(level triggered)是缺省的工作方式，并且同时支持block和no-block socket.在这种做法中，内核告诉你一个文件描述符是否就绪了，然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作，内核还是会继续通知你的，所以，这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表．<br>&nbsp;&nbsp;&nbsp; ET (edge-triggered)是高速工作方式，只支持no-block socket。在这种模式下，当描述符从未就绪变为就绪时，内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪，并且不会再为那个文件描述符发送更多的就绪通知，直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如，你在发送，接收或者接收请求，或者发送接收的数据少于一定量时导致了一个EWOULDBLOCK 错误）。但是请注意，如果一直不对这个fd作IO操作(从而导致它再次变成未就绪)，内核不会发送更多的通知(only once),不过在TCP协议中，ET模式的加速效用仍需要更多的benchmark确认。<br>&nbsp;&nbsp;&nbsp; epoll只有epoll_create,epoll_ctl,epoll_wait 3个系统调用，具体用法请参考http://www.xmailserver.org/linux-patches/nio-improve.html ，在http://www.kegel.com/rn/也有一个完整的例子，大家一看就知道如何使用了<br>Leader/follower模式线程pool实现，以及和epoll的配合。<br><br>5、 epoll的使用方法<br>&nbsp;&nbsp;&nbsp; 首先通过create_epoll(int maxfds)来创建一个epoll的句柄，其中maxfds为你epoll所支持的最大句柄数。这个函数会返回一个新的epoll句柄，之后的所有操作将通过这个句柄来进行操作。在用完之后，记得用close()来关闭这个创建出来的epoll句柄。之后在你的网络主循环里面，每一帧的调用epoll_wait(int epfd, epoll_event events, int max events, int timeout)来查询所有的网络接口，看哪一个可以读，哪一个可以写了。基本的语法为：<br>nfds = epoll_wait(kdpfd, events, maxevents, -1);<br>其中kdpfd为用epoll_create创建之后的句柄，events是一个epoll_event*的指针，当epoll_wait这个函数操作成功之后，epoll_events里面将储存所有的读写事件。max_events是当前需要监听的所有socket句柄数。最后一个timeout是 epoll_wait的超时，为0的时候表示马上返回，为-1的时候表示一直等下去，直到有事件范围，为任意正整数的时候表示等这么长的时间，如果一直没有事件，则范围。一般如果网络主循环是单独的线程的话，可以用-1来等，这样可以保证一些效率，如果是和主逻辑在同一个线程的话，则可以用0来保证主循环的效率。<br><br>epoll_wait范围之后应该是一个循环，遍利所有的事件：<br>for(n = 0; n &lt; nfds; ++n) {<br>&nbsp; if(events[n].data.fd == listener) { //如果是主socket的事件的话，则表示有新连接进入了，进行新连接的处理。<br>&nbsp;&nbsp;&nbsp; client = accept(listener, (struct sockaddr *) &amp;local,&nbsp; &amp;addrlen);<br>&nbsp;&nbsp;&nbsp; if(client &lt; 0){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; perror("accept");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; setnonblocking(client); // 将新连接置于非阻塞模式<br>&nbsp;&nbsp;&nbsp; ev.events = EPOLLIN | EPOLLET; // 并且将新连接也加入EPOLL的监听队列。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //注意，这里的参数EPOLLIN | EPOLLET并没有设置对写socket的监听，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //如果有写操作的话，这个时候epoll是不会返回事件的，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //如果要对写操作也监听的话，应该是EPOLLIN | EPOLLOUT | EPOLLET<br>&nbsp;&nbsp;&nbsp; ev.data.fd = client;<br>&nbsp;&nbsp;&nbsp; if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &amp;ev) &lt; 0) {&nbsp; // 设置好event之后，将这个新的event通过epoll_ctl<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //加入到epoll的监听队列里面，这里用EPOLL_CTL_ADD<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //来加一个新的 epoll事件，通过EPOLL_CTL_DEL来减少<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //一个epoll事件，通过EPOLL_CTL_MOD来改变一个事件的<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //监听方式。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fprintf(stderr, "epoll set insertion error: fd=%d0, client);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp; }&nbsp; else // 如果不是主socket的事件的话，则代表是一个用户socket的事件，<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //则来处理这个用户socket的事情，比如说read(fd,xxx)之类的，或者一些其他的处理。<br>&nbsp;&nbsp;&nbsp; do_use_fd(events[n].data.fd);<br>}<br><br>对，epoll的操作就这么简单，总共不过4个API：epoll_create, epoll_ctl, epoll_wait和close。<br>如果您对epoll的效率还不太了解，请参考我之前关于网络游戏的网络编程等相关的文章。<br><br><br>&nbsp;&nbsp;&nbsp; 以前公司的服务器都是使用HTTP连接，但是这样的话，在手机目前的网络情况下不但显得速度较慢，而且不稳定。因此大家一致同意用 SOCKET来进行连接。虽然使用SOCKET之后，对于用户的费用可能会增加(由于是用了CMNET而非CMWAP)，但是，秉着用户体验至上的原则，相信大家还是能够接受的(希望那些玩家月末收到帐单不后能够保持克制...)。<br>这次的服务器设计中，最重要的一个突破，是使用了EPOLL模型，虽然对之也是一知半解，但是既然在各大PC网游中已经经过了如此严酷的考验，相信他不会让我们失望，使用后的结果，确实也是表现相当不错。在这里，我还是主要大致介绍一下这个模型的结构。<br>6、Linux下EPOll编程实例<br>EPOLL模型似乎只有一种格式，所以大家只要参考我下面的代码，就能够对EPOLL有所了解了，代码的解释都已经在注释中：<br><br>while (TRUE) {<br>&nbsp; int nfds = epoll_wait (m_epoll_fd, m_events, MAX_EVENTS, EPOLL_TIME_OUT);//等待EPOLL时间的发生，相当于监听，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //至于相关的端口，需要在初始化EPOLL的时候绑定。<br>&nbsp; if (nfds &lt;= 0)<br>&nbsp;&nbsp;&nbsp; continue;<br>&nbsp; m_bOnTimeChecking = FALSE;<br>&nbsp; G_CurTime = time(NULL);<br>&nbsp; for (int i=0; i&lt;nfds; i++) {<br>&nbsp;&nbsp;&nbsp; try {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (m_events[i].data.fd == m_listen_http_fd)//如果新监测到一个HTTP用户连接到绑定的HTTP端口，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //建立新的连接。由于我们新采用了SOCKET连接，所以基本没用。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OnAcceptHttpEpoll ();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (m_events[i].data.fd == m_listen_sock_fd)//如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //建立新的连接。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OnAcceptSockEpoll ();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (m_events[i].events &amp; EPOLLIN)//如果是已经连接的用户，并且收到数据，那么进行读入。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OnReadEpoll (i);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OnWriteEpoll (i);//查看当前的活动连接是否有需要写出的数据。<br>&nbsp;&nbsp;&nbsp; } catch (int) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PRINTF ("CATCH捕获错误\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp; }<br>&nbsp; m_bOnTimeChecking = TRUE;<br>&nbsp; OnTimer ();//进行一些定时的操作，主要就是删除一些短线用户等。<br>}<br>　其实EPOLL的精华，也就是上述的几段短短的代码，看来时代真的不同了，以前如何接受大量用户连接的问题，现在却被如此轻松的搞定，真是让人不得不感叹，对哪。<br><br><br><br><img alt=""  src="http://www.cppblog.com/images/cppblog_com/khan/6584/r_epoll.jpg"><br><br>Epoll模型主要负责对大量并发用户的请求进行及时处理，完成服务器与客户端的数据交互。其具体的实现步骤如下：<br>(a) 使用epoll_create()函数创建文件描述，设定将可管理的最大socket描述符数目。<br>(b) 创建与epoll关联的接收线程，应用程序可以创建多个接收线程来处理epoll上的读通知事件，线程的数量依赖于程序的具体需要。<br>(c) 创建一个侦听socket描述符ListenSock；将该描述符设定为非阻塞模式，调用Listen（）函数在套接字上侦听有无新的连接请求，在epoll_event结构中设置要处理的事件类型EPOLLIN，工作方式为 epoll_ET，以提高工作效率，同时使用epoll_ctl()注册事件，最后启动网络监视线程。<br>(d) 网络监视线程启动循环，epoll_wait()等待epoll事件发生。<br>(e) 如果epoll事件表明有新的连接请求，则调用accept（）函数，将用户socket描述符添加到epoll_data联合体，同时设定该描述符为非阻塞，并在epoll_event结构中设置要处理的事件类型为读和写，工作方式为epoll_ET.<br>(f) 如果epoll事件表明socket描述符上有数据可读，则将该socket描述符加入可读队列，通知接收线程读入数据，并将接收到的数据放入到接收数据的链表中，经逻辑处理后，将反馈的数据包放入到发送数据链表中，等待由发送线程发送。<br><br>
<br><img src ="http://www.cppblog.com/Khan/aggbug/46013.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2008-04-02 11:37 <a href="http://www.cppblog.com/Khan/archive/2008/04/02/46013.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内存越界和泄露调试工具(转载自赛迪网)</title><link>http://www.cppblog.com/Khan/archive/2008/03/20/44933.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Thu, 20 Mar 2008 04:23:00 GMT</pubDate><guid>http://www.cppblog.com/Khan/archive/2008/03/20/44933.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/44933.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2008/03/20/44933.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/44933.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/44933.html</trackback:ping><description><![CDATA[<span id="zoom" class="a14c">
<p style="text-indent: 2em;"><span class="b">作者：sixth</span></p>
<p style="text-indent: 2em;">用C/C++开发其中最令人头疼的一个问题就是内存管理，有时候为了查找一个内存泄漏或者一个内存访问越界，需要要花上好几天时间，如果有一款工具能够帮助我们做这件事情就好了，valgrind正好就是这样的一款工具。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">Valgrind是一款基于模拟linux下的程序调试器和剖析器的软件套件，可以
运行于x86,
amd64和ppc32架构上。valgrind包含一个核心，它提供一个虚拟的CPU运行程序，还有一系列的工具，它们完成调试，剖析和一些类似的任
务。valgrind是高度模块化的，所以开发人员或者用户可以给它添加新的工具而不会损坏己有的结构。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">valgrind的官方网址是：http://valgrind.org
</p>
<p style="text-indent: 2em;">你可以在它的网站上下载到最新的valgrind，它是开放源码和免费的。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;"><strong>一、介绍</strong>
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">valgrind包含几个标准的工具，它们是：
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">1、memcheck
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">memcheck探测程序中内存管理存在的问题。它检查所有对内存的读/写操作，并截取所有的malloc/new/free/delete调用。因此memcheck工具能够探测到以下问题：
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">1）使用未初始化的内存
</p>
<p style="text-indent: 2em;">2）读/写已经被释放的内存
</p>
<p style="text-indent: 2em;">3）读/写内存越界
</p>
<p style="text-indent: 2em;">4）读/写不恰当的内存栈空间
</p>
<p style="text-indent: 2em;">5）内存泄漏
</p>
<p style="text-indent: 2em;">6）使用malloc/new/new[]和free/delete/delete[]不匹配。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">2、cachegrind
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">cachegrind是一个cache剖析器。它模拟执行CPU中的L1,
D1和L2
cache，因此它能很精确的指出代码中的cache未命中。如果你需要，它可以打印出cache未命中的次数，内存引用和发生cache未命中的每一行
代码，每一个函数，每一个模块和整个程序的摘要。如果你要求更细致的信息，它可以打印出每一行机器码的未命中次数。在x86和amd64上，
cachegrind通过CPUID自动探测机器的cache配置，所以在多数情况下它不再需要更多的配置信息了。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">3、helgrind
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">helgrind查找多线程程序中的竞争数据。helgrind查找内存地址，那些被多于一条线程访问的内存地址，但是没有使用一致的锁就会被查出。这表示这些地址在多线程间访问的时候没有进行同步，很可能会引起很难查找的时序问题。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;"><strong>二、valgrind对你的程序都做了些什么</strong>
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">valgrind被设计成非侵入式的，它直接工作于可执行文件上，因此在检查前不需要重新编译、连接和修改你的程序。要检查一个程序很简单，只需要执行下面的命令就可以了
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">valgrind --tool=tool_name  program_name
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">比如我们要对ls -l命令做内存检查，只需要执行下面的命令就可以了
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">valgrind --tool=memcheck ls -l
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">不管是使用哪个工具，valgrind在开始之前总会先取得对你的程序的控制权，从
可执行关联库里读取调试信息。然后在valgrind核心提供的虚拟CPU上运行程序，valgrind会根据选择的工具来处理代码，该工具会向代码中加
入检测代码，并把这些代码作为最终代码返回给valgrind核心，最后valgrind核心运行这些代码。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">如果要检查内存泄漏，只需要增加--leak-check=yes就可以了，命令如下
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">valgrind --tool=memcheck --leak-check=yes ls -l
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">不同工具间加入的代码变化非常的大。在每个作用域的末尾，memcheck加入代码检查每一片内存的访问和进行值计算，代码大小至少增加12倍，运行速度要比平时慢25到50倍。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">valgrind模拟程序中的每一条指令执行，因此，检查工具和剖析工具不仅仅是对你的应用程序，还有对共享库，GNU C库，X的客户端库都起作用。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;"><strong>三、现在开始</strong>
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">首先，在编译程序的时候打开调试模式（gcc编译器的-g选项）。如果没有调试信
息，即使最好的valgrind工具也将中能够猜测特定的代码是属于哪一个函数。打开调试选项进行编译后再用valgrind检查，valgrind将会
给你的个详细的报告，比如哪一行代码出现了内存泄漏。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">当检查的是C++程序的时候，还应该考虑另一个选项
-fno-inline。它使得函数调用链很清晰，这样可以减少你在浏览大型C++程序时的混乱。比如在使用这个选项的时候，用memcheck检查
openoffice就很容易。当然，你可能不会做这项工作，但是使用这一选项使得valgrind生成更精确的错误报告和减少混乱。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">一些编译优化选项(比如-O2或者更高的优化选项)，可能会使得memcheck提交错误的未初始化报告，因此，为了使得valgrind的报告更精确，在编译的时候最好不要使用优化选项。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">如果程序是通过脚本启动的，可以修改脚本里启动程序的代码，或者使用--trace-children=yes选项来运行脚本。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">下面是用memcheck检查ls -l命令的输出报告，在终端下执行下面的命令
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">valgrind --tool=memcheck ls -l
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">程序会打印出ls -l命令的结果，最后是valgrind的检查报告如下：
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">==4187==
</p>
<p style="text-indent: 2em;">==4187== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 19 from 2)
</p>
<p style="text-indent: 2em;">==4187== malloc/free: in use at exit: 15,154 bytes in 105 blocks.
</p>
<p style="text-indent: 2em;">==4187== malloc/free: 310 allocs, 205 frees, 60,093 bytes allocated.
</p>
<p style="text-indent: 2em;">==4187== For counts of detected errors, rerun with: -v
</p>
<p style="text-indent: 2em;">==4187== searching for pointers to 105 not-freed blocks.
</p>
<p style="text-indent: 2em;">==4187== checked 145,292 bytes.
</p>
<p style="text-indent: 2em;">==4187==
</p>
<p style="text-indent: 2em;">==4187== LEAK SUMMARY:
</p>
<p style="text-indent: 2em;">==4187==    definitely lost: 0 bytes in 0 blocks.
</p>
<p style="text-indent: 2em;">==4187==      possibly lost: 0 bytes in 0 blocks.
</p>
<p style="text-indent: 2em;">==4187==    still reachable: 15,154 bytes in 105 blocks.
</p>
<p style="text-indent: 2em;">==4187==         suppressed: 0 bytes in 0 blocks.
</p>
<p style="text-indent: 2em;">==4187== Reachable blocks (those to which a pointer was found) are not shown.
</p>
<p style="text-indent: 2em;">==4187== To see them, rerun with: --show-reachable=yes
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">这里的&#8220;4187&#8221;指的是执行ls -l的进程ID，这有利于区别不同进程的报告。memcheck会给出报告，分配置和释放了多少内存，有多少内存泄漏了，还有多少内存的访问是可达的，检查了多少字节的内存。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">下面举两个用valgrind做内存检查的例子
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">例子一 (test.c)：
</p>
<p style="text-indent: 2em;">
</p>
<center><ccid_nobr>
</ccid_nobr>
<table bordercolorlight="black" bordercolordark="#FFFFFF" align="center" border="1" cellpadding="2" cellspacing="0" width="400">
    <tbody>
        <tr>
            <td class="code" style="font-size: 9pt;" bgcolor="#e6e6e6">
            <pre><ccid_code>#include &lt;string.h&gt;<br><br>int main(int argc, char *argv[])<br>{<br>    char *ptr;<br><br>    ptr = (char*) malloc(10);<br>    strcpy(ptr, "01234567890");<br><br>    return 0;<br>}</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</center>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">编译程序
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">gcc -g -o test test.c
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">用valgrind执行命令
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">valgrind --tool=memcheck --leak-check=yes ./test
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">报告如下
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">==4270== Memcheck, a memory error detector.
</p>
<p style="text-indent: 2em;">==4270== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
</p>
<p style="text-indent: 2em;">==4270== Using LibVEX rev 1606, a library for dynamic binary translation.
</p>
<p style="text-indent: 2em;">==4270== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
</p>
<p style="text-indent: 2em;">==4270== Using valgrind-3.2.0, a dynamic binary instrumentation framework.
</p>
<p style="text-indent: 2em;">==4270== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
</p>
<p style="text-indent: 2em;">==4270== For more details, rerun with: -v
</p>
<p style="text-indent: 2em;">==4270==
</p>
<p style="text-indent: 2em;">==4270== Invalid write of size 1
</p>
<p style="text-indent: 2em;">==4270==    at 0x4006190: strcpy (mc_replace_strmem.c:271)
</p>
<p style="text-indent: 2em;">==4270==    by 0x80483DB: main (test.c:8)
</p>
<p style="text-indent: 2em;">==4270==  Address 0x4023032 is 0 bytes after a block of size 10 alloc'd
</p>
<p style="text-indent: 2em;">==4270==    at 0x40044F6: malloc (vg_replace_malloc.c:149)
</p>
<p style="text-indent: 2em;">==4270==    by 0x80483C5: main (test.c:7)
</p>
<p style="text-indent: 2em;">==4270==
</p>
<p style="text-indent: 2em;">==4270== Invalid write of size 1
</p>
<p style="text-indent: 2em;">==4270==    at 0x400619C: strcpy (mc_replace_strmem.c:271)
</p>
<p style="text-indent: 2em;">==4270==    by 0x80483DB: main (test.c:8)
</p>
<p style="text-indent: 2em;">==4270==  Address 0x4023033 is 1 bytes after a block of size 10 alloc'd
</p>
<p style="text-indent: 2em;">==4270==    at 0x40044F6: malloc (vg_replace_malloc.c:149)
</p>
<p style="text-indent: 2em;">==4270==    by 0x80483C5: main (test.c:7)
</p>
<p style="text-indent: 2em;">==4270==
</p>
<p style="text-indent: 2em;">==4270== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 12 from 1)
</p>
<p style="text-indent: 2em;">==4270== malloc/free: in use at exit: 10 bytes in 1 blocks.
</p>
<p style="text-indent: 2em;">==4270== malloc/free: 1 allocs, 0 frees, 10 bytes allocated.
</p>
<p style="text-indent: 2em;">==4270== For counts of detected errors, rerun with: -v
</p>
<p style="text-indent: 2em;">==4270== searching for pointers to 1 not-freed blocks.
</p>
<p style="text-indent: 2em;">==4270== checked 51,496 bytes.
</p>
<p style="text-indent: 2em;">==4270==
</p>
<p style="text-indent: 2em;">==4270==
</p>
<p style="text-indent: 2em;">==4270== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1
</p>
<p style="text-indent: 2em;">==4270==    at 0x40044F6: malloc (vg_replace_malloc.c:149)
</p>
<p style="text-indent: 2em;">==4270==    by 0x80483C5: main (test.c:7)
</p>
<p style="text-indent: 2em;">==4270==
</p>
<p style="text-indent: 2em;">==4270== LEAK SUMMARY:
</p>
<p style="text-indent: 2em;">==4270==    definitely lost: 10 bytes in 1 blocks.
</p>
<p style="text-indent: 2em;">==4270==      possibly lost: 0 bytes in 0 blocks.
</p>
<p style="text-indent: 2em;">==4270==    still reachable: 0 bytes in 0 blocks.
</p>
<p style="text-indent: 2em;">==4270==         suppressed: 0 bytes in 0 blocks.
</p>
<p style="text-indent: 2em;">==4270== Reachable blocks (those to which a pointer was found) are not shown.
</p>
<p style="text-indent: 2em;">==4270== To see them, rerun with: --show-reachable=yes
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">从这份报告可以看出，进程号是4270，test.c的第8行写内存越界了，引起写内存越界的是strcpy函数，
</p>
<p style="text-indent: 2em;">第7行泄漏了10个字节的内存，引起内存泄漏的是malloc函数。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">例子二（test2.c)
</p>
<p style="text-indent: 2em;">
</p>
<center><ccid_nobr>
</ccid_nobr>
<table bordercolorlight="black" bordercolordark="#FFFFFF" align="center" border="1" cellpadding="2" cellspacing="0" width="400">
    <tbody>
        <tr>
            <td class="code" style="font-size: 9pt;" bgcolor="#e6e6e6">
            <pre><ccid_code>#include &lt;stdio.h&gt;<br><br>int foo(int x)<br>{<br>    if (x &lt; 0) {<br>        printf("%d ", x);<br>    }<br><br>    return 0;<br>}<br><br>int main(int argc, char *argv[])<br>{<br>    int x;<br>   <br>    foo(x);<br><br>    return 0;<br>}</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</center>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">编译程序
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">gcc -g -o test2 test2.c
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">用valgrind做内存检查
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">valgrind --tool=memcheck ./test2
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">输出报告如下
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">==4285== Memcheck, a memory error detector.
</p>
<p style="text-indent: 2em;">==4285== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
</p>
<p style="text-indent: 2em;">==4285== Using LibVEX rev 1606, a library for dynamic binary translation.
</p>
<p style="text-indent: 2em;">==4285== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
</p>
<p style="text-indent: 2em;">==4285== Using valgrind-3.2.0, a dynamic binary instrumentation framework.
</p>
<p style="text-indent: 2em;">==4285== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
</p>
<p style="text-indent: 2em;">==4285== For more details, rerun with: -v
</p>
<p style="text-indent: 2em;">==4285==
</p>
<p style="text-indent: 2em;">==4285== Conditional jump or move depends on uninitialised value(s)
</p>
<p style="text-indent: 2em;">==4285==    at 0x8048372: foo (test2.c:5)
</p>
<p style="text-indent: 2em;">==4285==    by 0x80483B4: main (test2.c:16)
</p>
<p style="text-indent: 2em;">==4285==p p
</p>
<p style="text-indent: 2em;">==4285== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 12 from 1)
</p>
<p style="text-indent: 2em;">==4285== malloc/free: in use at exit: 0 bytes in 0 blocks.
</p>
<p style="text-indent: 2em;">==4285== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.
</p>
<p style="text-indent: 2em;">==4285== For counts of detected errors, rerun with: -v
</p>
<p style="text-indent: 2em;">==4285== All heap blocks were freed -- no leaks are possible.
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">从这份报告可以看出进程PID是4285，test2.c文件的第16行调用了foo函数，在test2.c文件的第5行foo函数使用了一个未初始化的变量。
</p>
<p style="text-indent: 2em;">
</p>
<p style="text-indent: 2em;">valgrind还有很多使用选项，具体可以查看valgrind的man手册页和valgrind官方网站的在线文档。</p>
<br>
<p style="text-indent: 2em;"><br></p>
<br>
<p style="text-indent: 2em;"><br></p>
<p style="text-indent: 2em;">Windows用户不必沮丧，虽然在Windows上没有Valgrind可用，但是你可以试一试IBM的<a  href="http://www-306.ibm.com/software/awdtools/purify/">Purify</a>，它在功能上和Valgrind相似。<br>
</p>
</span><img src ="http://www.cppblog.com/Khan/aggbug/44933.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2008-03-20 12:23 <a href="http://www.cppblog.com/Khan/archive/2008/03/20/44933.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>通过两个点的经纬度计算距离</title><link>http://www.cppblog.com/Khan/archive/2008/02/28/43390.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Thu, 28 Feb 2008 07:18:00 GMT</pubDate><guid>http://www.cppblog.com/Khan/archive/2008/02/28/43390.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/43390.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2008/02/28/43390.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/43390.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/43390.html</trackback:ping><description><![CDATA[最近开始做一个类似gis的东西. 需要求一些经纬度相关的值..<br><br>看了<a href="http://panyee.cnblogs.com/archive/2006/07/04/442771.html" target="_blank">通过两个点的经纬度计算距离</a>这篇，据说是Google里扒来的算法，于是决定验证一下。<br>通过计算发现非常正确。<br>用30,120和31,121两个坐标点进行验证，同Mapinfo中计算的结果非常的相近。<br>后来又把坐标系直接当成直角坐标系来计算，发现误差很大。<br>于是仍然用直角坐标系方法来计算，给纬度加上了个0.86的参数，这样计算下来和结果相近。<br><br><br><br><br>c#代码<br>private const double EARTH_RADIUS = 6378.137; //地球半径<br>private static double rad(double d)<br>{<br>&nbsp;&nbsp;&nbsp;return d * Math.PI / 180.0;<br>}
<p>public static double GetDistance(double lat1, double lng1, double lat2, double lng2)<br>{<br>&nbsp;&nbsp;&nbsp;double radLat1 = rad(lat1);<br>&nbsp;&nbsp;&nbsp;double radLat2 = rad(lat2);<br>&nbsp;&nbsp;&nbsp;double a = radLat1 - radLat2;<br>&nbsp;&nbsp;&nbsp;double b = rad(lng1) - rad(lng2);<br>&nbsp;&nbsp;&nbsp;double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a/2),2) + <br>&nbsp;&nbsp;&nbsp;&nbsp;Math.Cos(radLat1)*Math.Cos(radLat2)*Math.Pow(Math.Sin(b/2),2)));<br>&nbsp;&nbsp;&nbsp;s = s * EARTH_RADIUS;<br>&nbsp;&nbsp;&nbsp;s = Math.Round(s * 10000) / 10000;<br>&nbsp;&nbsp;&nbsp;return s;<br>}</p>
<br>
<p>vb代码</p>
<img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">Const&nbsp;EARTH_RADIUS&nbsp;=&nbsp;6378.137<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">Const&nbsp;Pi&nbsp;=&nbsp;3.1415926535898<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">Function&nbsp;rad(ByVal&nbsp;d&nbsp;As&nbsp;Double)&nbsp;As&nbsp;Double<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">rad&nbsp;=&nbsp;d&nbsp;*&nbsp;Pi&nbsp;/&nbsp;180<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">End&nbsp;Function<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">Function&nbsp;GetDistance(lat1&nbsp;As&nbsp;Double,&nbsp;lng1&nbsp;As&nbsp;Double,&nbsp;lat2&nbsp;As&nbsp;Double,&nbsp;lng2&nbsp;As&nbsp;Double)&nbsp;As&nbsp;Double<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">Dim&nbsp;radlat1&nbsp;As&nbsp;Double,&nbsp;radlat2&nbsp;As&nbsp;Double<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">Dim&nbsp;a&nbsp;As&nbsp;Double,&nbsp;b&nbsp;As&nbsp;Double,&nbsp;s&nbsp;As&nbsp;Double,&nbsp;Temp&nbsp;As&nbsp;Double<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">radlat1&nbsp;=&nbsp;rad(lat1)<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">radlat2&nbsp;=&nbsp;rad(lat2)<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">a&nbsp;=&nbsp;radlat1&nbsp;-&nbsp;radlat2<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">b&nbsp;=&nbsp;rad(lng1)&nbsp;-&nbsp;rad(lng2)<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">Temp&nbsp;=&nbsp;Sqr(Sin(a&nbsp;/&nbsp;2)&nbsp;^&nbsp;2&nbsp;+&nbsp;Cos(radlat1)&nbsp;*&nbsp;Cos(radlat2)&nbsp;*&nbsp;Sin(b&nbsp;/&nbsp;2)&nbsp;^&nbsp;2)<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">s&nbsp;=&nbsp;2&nbsp;*&nbsp;Atn(Temp&nbsp;/&nbsp;Sqr(-Temp&nbsp;*&nbsp;Temp&nbsp;+&nbsp;1))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'没有反正弦函数，网上找了个<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">s&nbsp;=&nbsp;s&nbsp;*&nbsp;EARTH_RADIUS<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">GetDistance&nbsp;=&nbsp;s<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">End&nbsp;Function<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">Private&nbsp;Sub&nbsp;Command1_Click()<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">Text5.Text&nbsp;=&nbsp;Str(GetDistance(Val(Text1.Text),&nbsp;Val(Text2.Text),&nbsp;Val(Text3.Text),&nbsp;Val(Text4.Text)))<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">End&nbsp;Sub<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">Private&nbsp;Sub&nbsp;Command2_Click()<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">Text5.Text&nbsp;=&nbsp;Str((Sqr((Val(Text3.Text)&nbsp;-&nbsp;Val(Text1.Text))&nbsp;^&nbsp;2&nbsp;+&nbsp;(Val(Text4.Text)&nbsp;-&nbsp;Val(Text2.Text))&nbsp;^&nbsp;2))&nbsp;*&nbsp;111.3199338)<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">End&nbsp;Sub<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">Private&nbsp;Sub&nbsp;Command3_Click()<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">Text5.Text&nbsp;=&nbsp;Str((Sqr((Val(Text3.Text)&nbsp;*&nbsp;0.86&nbsp;-&nbsp;Val(Text1.Text)&nbsp;*&nbsp;0.86)&nbsp;^&nbsp;2&nbsp;+&nbsp;(Val(Text4.Text)&nbsp;-&nbsp;Val(Text2.Text))&nbsp;^&nbsp;2))&nbsp;*&nbsp;111.3199338)<br><img src="http://tangf.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">End&nbsp;Sub
<p><br></p>
<p><br></p>
同纬度计算比较简单<br>
<p>A（60，30），B（60，90）两点之间，此段代码和我用余弦定理算出来的结果很一致。
<br>余弦定理的步骤是：1、算A、B弦长：地球半径R*cos（经度差60）=R/2；
<br>2、算角AOB,O为地球圆心，利用余弦定理，
<br>cosAOB=(2R*R-(R/2)^2) /2*R*R=7/8;
<br>3、弧AB的长为：R*arc cos(7/8);求毕 <br></p>
<br>
<p><br></p>
<p>原理:<br></p>
<p>
地球赤道上环绕地球一周走一圈共40075.04公里,而@一圈分成360&#176;,而每1&#176;(度)有60,每一度一秒在赤道上的长度计算如下：
<br>
<br>　　40075.04km/360&#176;=111.31955km
<br>
<br>　　111.31955km/60=1.8553258km=1855.3m
<br>
<br>　　而每一分又有60秒,每一秒就代表1855.3m/60=30.92m
<br>
<br>　　任意两点距离计算公式为
<br>
<br>　　d＝111.12cos{1/[sin&#934;Asin&#934;B十cos&#934;Acos&#934;Bcos(&#955;B—&#955;A)]}
<br>
<br>　　其中A点经度，纬度分别为&#955;A和&#934;A，B点的经度、纬度分别为&#955;B和&#934;B，d为距离。</p>
<br>  <img src ="http://www.cppblog.com/Khan/aggbug/43390.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2008-02-28 15:18 <a href="http://www.cppblog.com/Khan/archive/2008/02/28/43390.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Symbian 的Gif显示.(暂且记录关键信息. 完善后再认真介绍)</title><link>http://www.cppblog.com/Khan/archive/2007/12/19/39027.html</link><dc:creator>Khan's Notebook</dc:creator><author>Khan's Notebook</author><pubDate>Wed, 19 Dec 2007 06:22:00 GMT</pubDate><guid>http://www.cppblog.com/Khan/archive/2007/12/19/39027.html</guid><wfw:comment>http://www.cppblog.com/Khan/comments/39027.html</wfw:comment><comments>http://www.cppblog.com/Khan/archive/2007/12/19/39027.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/Khan/comments/commentRss/39027.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Khan/services/trackbacks/39027.html</trackback:ping><description><![CDATA[我的gif播放这样设置,为什么只播放一次呢??<br><br>&nbsp;&nbsp;&nbsp; if(iImageViewer)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; delete iImageViewer;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; TRect r(TPoint(0,0), TSize(50, 50));<br>&nbsp;&nbsp;&nbsp; iImageViewer = CPAlbImageViewerBasic::NewL(NULL, r);<br><br><br>&nbsp;&nbsp;&nbsp; TRAPD(err, iImageViewer-&gt;LoadImageL(tFullFileName, EColor4K));<br>&nbsp;&nbsp;&nbsp; if (err == KErrNone)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; iImageViewer-&gt;SetAnimationObserver(NULL,ETrue);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; iImageViewer-&gt;ScaleOptimumL();<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; iImageViewer-&gt;PlayAnimationL();<br>&nbsp;&nbsp;&nbsp; }<br><br><br><br>愣愣(65087426) 13:06:35<br>iViewer=CPAlbImageViewerBasic::NewL(this,aRect);<br>&nbsp;&nbsp;&nbsp; iViewer-&gt;SetAnimationObserver(this,ETrue);//for looping <br>&nbsp;&nbsp;&nbsp; iViewer-&gt;LoadImageL(_L("c:\\nokia\\images\\anim.gif"),EColor4K);&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; iViewer-&gt;PlayAnimationL(); // support image and animation<br><br>循环播放<br><br>无牙老虎(276877017) 13:07:26<br>iViewer-&gt;SetAnimationObserver(this,ETrue);<br><br>如果我这里不想设置为this呢??<br>愣愣(65087426) 13:07:52<br>不行吧，要一个observer的<br>无牙老虎(276877017) 13:08:14<br>我上面的代码就运行了一次<br>植物兽兽(39827140) 13:08:16<br>这个地方传入的是MPAlbAnimationObserver *aObserver,<br><br>愣愣(65087426) 13:08:18<br>Notify 实现这个就循环了<br><br>  <img src ="http://www.cppblog.com/Khan/aggbug/39027.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Khan/" target="_blank">Khan's Notebook</a> 2007-12-19 14:22 <a href="http://www.cppblog.com/Khan/archive/2007/12/19/39027.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>