﻿<?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++博客-880221zxj</title><link>http://www.cppblog.com/880221zxj/</link><description /><language>zh-cn</language><lastBuildDate>Tue, 14 Apr 2026 23:10:06 GMT</lastBuildDate><pubDate>Tue, 14 Apr 2026 23:10:06 GMT</pubDate><ttl>60</ttl><item><title>const</title><link>http://www.cppblog.com/880221zxj/archive/2012/06/11/178374.html</link><dc:creator>无一</dc:creator><author>无一</author><pubDate>Sun, 10 Jun 2012 16:51:00 GMT</pubDate><guid>http://www.cppblog.com/880221zxj/archive/2012/06/11/178374.html</guid><wfw:comment>http://www.cppblog.com/880221zxj/comments/178374.html</wfw:comment><comments>http://www.cppblog.com/880221zxj/archive/2012/06/11/178374.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/880221zxj/comments/commentRss/178374.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/880221zxj/services/trackbacks/178374.html</trackback:ping><description><![CDATA[C中CONST的使用：<br />
<div class="spctrl"></div>　　const是一个C语言的关键字，它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的安全性和可靠性，另外，在观看别人代码的时候，清晰理解const所起的作用，对理解对方的程序也有一些帮助。<br />
<div class="spctrl"></div>　　虽然这听起来很简单，但实际上，const的使用也是c语言中一个比较微妙的地方，微妙在何处呢？请看下面几个问题。<br />
<div class="spctrl"></div>　　问题：const变量 &amp; 常量<br />
<div class="spctrl"></div>　　为什么下面的例子在使用一个const变量来初始化数组，ANSI C的编译器会报告一个错误呢？　<br />
<div class="spctrl"></div>　　const int n = 5;<br />
<div class="spctrl"></div>　　int a[n];<br />
<div class="spctrl"></div>　　答案与分析:<br />
<div class="spctrl"></div>　　1）、这个问题讨论的是&#8220;常量&#8221;与&#8220;只读变量&#8221;的区别。常量肯定是只读的，例如5， &#8220;abc&#8221;，等，肯定是只读的，因为常量是被编译器放在内存中的只读区域，当然也就不能够去修改它。而&#8220;只读变量&#8221;则是在内存中开辟一个地方来存放它的值，只不过这个值由编译器限定不允许被修改。C语言关键字const就是用来限定一个变量不允许被改变的修饰符（Qualifier）。上述代码中变量n被修饰为只读变量，可惜再怎么修饰也不是常量。而ANSI C规定数组定义时维度必须是&#8220;常量&#8221;，&#8220;只读变量&#8221;也是不可以的。<br />
<div class="spctrl"></div>　　2)、注意：在ANSI C中，这种写法是错误的，因为数组的大小应该是个常量，而const int n,n只是一个变量（常量 != 不可变的变量，但在标准C++中，这样定义的是一个常量，这种写法是对的），实际上，根据编译过程及内存分配来看，这种用法本来就应该是合理的，只是 ANSI C对数组的规定限制了它。<br />
<div class="spctrl"></div>　　3)、那么，在ANSI C 语言中用什么来定义常量呢？答案是enum类型和#define宏，这两个都可以用来定义常量。<br />
<div class="spctrl"></div>　　问题：const变量 &amp; const 限定的内容<br />
<div class="spctrl"></div>　　下面的代码编译器会报一个错误，请问，哪一个语句是错误的呢？　<br />
<div class="spctrl"></div>　　typedef char * pStr;<br />
<div class="spctrl"></div>　　char string[4] = "abc";<br />
<div class="spctrl"></div>　　const char *p1 = string;<br />
<div class="spctrl"></div>　　const pStr p2 = string;<br />
<div class="spctrl"></div>　　p1++;<br />
<div class="spctrl"></div>　　p2++;<br />
<div class="spctrl"></div>　　答案与分析：<br />
<div class="spctrl"></div>　　问题出在p2++上。<br />
<div class="spctrl"></div>　　1)、const使用的基本形式： const char m;<br />
<div class="spctrl"></div>　　限定m不可变。<br />
<div class="spctrl"></div>　　2)、替换1式中的m, const char *pm;<br />
<div class="spctrl"></div>　　限定*pm不可变，当然pm是可变的，因此问题中p1++是对的。<br />
<div class="spctrl"></div>　　3)、替换1式char, const newType m;<br />
<div class="spctrl"></div>　　限定m不可变，问题中的charptr就是一种新类型，因此问题中p2不可变，p2++是错误的。<br />
<div class="spctrl"></div>　　问题：const变量 &amp; 字符串常量<br />
<div class="spctrl"></div>　　请问下面的代码有什么问题？<br />
<div class="spctrl"></div>　　char *p = "i'm hungry!";<br />
<div class="spctrl"></div>　　p[0]= 'I';<br />
<div class="spctrl"></div>　　答案与分析：<br />
<div class="spctrl"></div>　　上面的代码可能会造成内存的非法写操作。分析如下， &#8220;i'm hungry&#8221;实质上是字符串常量，而常量往往被编译器放在只读的内存区，不可写。p初始指向这个只读的内存区，而p[0] = 'I'则企图去写这个地方，编译器当然不会答应。<br />
<div class="spctrl"></div>　　问题：const变量 &amp; 字符串常量2<br />
<div class="spctrl"></div>　　请问char a[3] = "abc" 合法吗？使用它有什么隐患？<br />
<div class="spctrl"></div>　　答案与分析：<br />
<div class="spctrl"></div>　　在标准C中这是合法的，但是它的生存环境非常狭小；它定义一个大小为3的数组，初始化为&#8220;abc&#8221;，，注意，它没有通常的字符串终止符'\0'，因此这个数组只是看起来像C语言中的字符串，实质上却不是，因此所有对字符串进行处理的函数，比如strcpy、printf等，都不能够被使用在这个假字符串上。<br />
<div class="spctrl"></div>　　问题5：const &amp; 指针<br />
<div class="spctrl"></div>　　类型声明中const用来修饰一个常量，有如下两种写法，那么，请问，下面分别用const限定不可变的内容是什么?<br />
<div class="spctrl"></div>　　1)、const在前面<br />
<div class="spctrl"></div>　　const int nValue； //nValue是const<br />
<div class="spctrl"></div>　　const char *pContent; //*pContent是const, pContent可变<br />
<div class="spctrl"></div>　　const (char *) pContent;//pContent是const,*pContent可变<br />
<div class="spctrl"></div>　　char* const pContent; //pContent是const,*pContent可变<br />
<div class="spctrl"></div>　　const char* const pContent; //pContent和*pContent都是const<br />
<div class="spctrl"></div>　　2)、const在后面，与上面的声明对等<br />
<div class="spctrl"></div>　　int const nValue； // nValue是const<br />
<div class="spctrl"></div>　　char const * pContent;// *pContent是const, pContent可变<br />
<div class="spctrl"></div>　　(char *) const pContent;//pContent是const,*pContent可变<br />
<div class="spctrl"></div>　　char* const pContent;// pContent是const,*pContent可变<br />
<div class="spctrl"></div>　　char const* const pContent;// pContent和*pContent都是const<br />
<div class="spctrl"></div>　　答案与分析：<br />
<div class="spctrl"></div>　　const和指针一起使用是C语言中一个很常见的困惑之处，在实际开发中，特别是在看别人代码的时候，常常会因为这样而不好判断作者的意图，下面讲一下我的判断原则：<br />
<div class="spctrl"></div>　　（这个规则是错的）沿着*号划一条线，如果const位于*的左侧，则const就是用来修饰指针所指向的变量，即指针指向为常量；如果const位于*的右侧，const就是修饰指针本身，即指针本身是常量。你可以根据这个规则来看上面声明的实际意义，相信定会一目了然。<br />
<div class="spctrl"></div>　　另外，需要注意：对于const (char *) ; 因为char *是一个整体，相当于一个类型(如 char)，因此，这是限定指针是const。 
<div class="bpctrl"></div>
<h2>
<div class="text_edit">[<a href="http://baike.baidu.com/view/1065598.htm?fr=ala0#">编辑本段</a>]</div><a name="2"></a>C++中CONST</h2>　　C中常用:&#8220; #define 变量名 变量值&#8221;定义一个值替代,然而却有个致命缺点:缺乏类型检测机制,这样预处理在C++中成为可能引发错误的隐患,于是引入const.<br />
<div class="spctrl"></div>　　const使用:<br />
<div class="spctrl"></div>　　1. 用于指针的两种情况:const是一个左结合的类型修饰符.<br />
<div class="spctrl"></div>　　int const *A; //A可变,*A不可变<br />
<div class="spctrl"></div>　　int *const A; //A不可变,*A可变<br />
<div class="spctrl"></div>　　2.限定函数的传递值参数:<br />
<div class="spctrl"></div>　　void function(const int Var); //传递过来的参数在函数内不可以改变.<br />
<div class="spctrl"></div>　　3.限定函数返回值型.<br />
<div class="spctrl"></div>　　const int function(); //此时const无意义<br />
<div class="spctrl"></div>　　const myclassname function(); //函数返回自定义类型myclassname.<br />
<div class="spctrl"></div>　　4限定函数类型.<br />
<div class="spctrl"></div>　　void function()const; //常成员函数, Const成员函数不能改变对象的成员函数。<br />
<div class="spctrl"></div>　　例如： <br />
<div class="spctrl"></div>　　int Point::GetY()<br />
<div class="spctrl"></div>　　{<br />
<div class="spctrl"></div>　　return yVal;<br />
<div class="spctrl"></div>　　} <br />
<div class="spctrl"></div>　　这个函数被调用时，不改变Point对象，而下面的函数改变Point对象： <br />
<div class="spctrl"></div>　　void Point:: SetPt (int x, int y)<br />
<div class="spctrl"></div>　　{<br />
<div class="spctrl"></div>　　xVal=x;<br />
<div class="spctrl"></div>　　yVal=y;<br />
<div class="spctrl"></div>　　} <br />
<div class="spctrl"></div>　　为了使成员函数的意义更加清楚，我们可在不改变对象的成员函数的函数原型中加上const说明： <br />
<div class="spctrl"></div>　　class Point <br />
<div class="spctrl"></div>　　{ <br />
<div class="spctrl"></div>　　public:<br />
<div class="spctrl"></div>　　int GetX() const;<br />
<div class="spctrl"></div>　　int GetY() const;<br />
<div class="spctrl"></div>　　void SetPt (int, int);<br />
<div class="spctrl"></div>　　void OffsetPt (int, int);<br />
<div class="spctrl"></div>　　private:<br />
<div class="spctrl"></div>　　int xVal, yVal;<br />
<div class="spctrl"></div>　　};<br />
<div class="spctrl"></div>　　const成员函数应该在函数原型说明和函数定义中都增加const限定： <br />
<div class="spctrl"></div>　　int Point::GetY() const<br />
<div class="spctrl"></div>　　{<br />
<div class="spctrl"></div>　　return yVal;<br />
<div class="spctrl"></div>　　}<br />
<div class="spctrl"></div>　　class Set {<br />
<div class="spctrl"></div>　　public:<br />
<div class="spctrl"></div>　　Set (void){ card = 0; }<br />
<div class="spctrl"></div>　　bool Member(const int) const;<br />
<div class="spctrl"></div>　　void AddElem(const int);<br />
<div class="spctrl"></div>　　//...<br />
<div class="spctrl"></div>　　};<br />
<div class="spctrl"></div>　　bool Set::Member (const int elem) const<br />
<div class="spctrl"></div>　　{<br />
<div class="spctrl"></div>　　//...<br />
<div class="spctrl"></div>　　}<br />
<div class="spctrl"></div>　　非常量成员函数不能被常量成员对象调用，因为它可能企图修改常量的数据成员： <br />
<div class="spctrl"></div>　　const Set s;<br />
<div class="spctrl"></div>　　s.AddElem(10); // 非法: AddElem不是常量成员函数<br />
<div class="spctrl"></div>　　s.Member(10); // 正确 <br />
<div class="spctrl"></div>　　但构造函数和析构函数对这个规则例外，它们从不定义为常量成员，但可被常量对象调用（被自动调用）。它们也能给常量的数据成员赋值，除非数据成员本身是常量。 <br />
<div class="spctrl"></div>　　为什么需要const成员函数？<br />
<div class="spctrl"></div>　　我们定义的类的成员函数中，常常有一些成员函数不改变类的数据成员，也就是说，这些函数是"只读"函数，而有一些函数要修改类数据成员的值。如果把不改变数据成员的函数都加上const关键字进行标识，显然，可提高程序的可读性。其实，它还能提高程序的可靠性，已定义成const的成员函数，一旦企图修改数据成员的值，则编译器按错误处理。 <br />
<div class="spctrl"></div>　　const成员函数和const对象<br />
<div class="spctrl"></div>　　实际上，const成员函数还有另外一项作用，即常量对象相关。对于内置的数据类型，我们可以定义它们的常量，用户自定义的类也一样，可以定义它们的常量对象。例如，定义一个整型常量的方法为： <br />
<div class="spctrl"></div>　　const int i=1 ；<br />
<div class="spctrl"></div>　　同样，也可以定义常量对象，假定有一个类classA，定义该类的常量对象的方法为：<br />
<div class="spctrl"></div>　　const classA a(2)；<br />
<div class="spctrl"></div>　　这里，a是类classA的一个const对象，"2"传给它的构造函数参数。const对象的数据成员在对象寿命期内不能改变。但是，如何保证该类的数据成员不被改变呢？<br />
<div class="spctrl"></div>　　为了确保const对象的数据成员不会被改变，在C++中，const对象只能调用const成员函数。如果一个成员函数实际上没有对数据成员作任何形式的修改，但是它没有被const关键字限定的，也不能被常量对象调用。下面通过一个例子来说明这个问题： <br />
<div class="spctrl"></div>　　class C<br />
<div class="spctrl"></div>　　{<br />
<div class="spctrl"></div>　　int X;<br />
<div class="spctrl"></div>　　public:<br />
<div class="spctrl"></div>　　int GetX()<br />
<div class="spctrl"></div>　　{<br />
<div class="spctrl"></div>　　return X;<br />
<div class="spctrl"></div>　　}<br />
<div class="spctrl"></div>　　void SetX(int X) <br />
<div class="spctrl"></div>　　{<br />
<div class="spctrl"></div>　　this-&gt;X = X;<br />
<div class="spctrl"></div>　　}<br />
<div class="spctrl"></div>　　}; <br />
<div class="spctrl"></div>　　void main()<br />
<div class="spctrl"></div>　　{<br />
<div class="spctrl"></div>　　const C constC;<br />
<div class="spctrl"></div>　　cout&lt;&lt;constC.GetX();<br />
<div class="spctrl"></div>　　}<br />
<div class="spctrl"></div>　　如果我们编译上面的程序代码，编译器会出现错误提示：constC是个常量对象，它只能调用const成员函数。虽然GetX( )函数实际上并没有改变数据成员X，由于没有const关键字限定，所以仍旧不能被constC对象调用。如果我们将上述加粗的代码：<br />
<div class="spctrl"></div>　　int GetX()<br />
<div class="spctrl"></div>　　改写成：<br />
<div class="spctrl"></div>　　int GetX()const<br />
<div class="spctrl"></div>　　再重新编译，就没有问题了。<br />
<div class="spctrl"></div>　　const成员函数的使用<br />
<div class="spctrl"></div>　　const成员函数表示该成员函数只能读类数据成员，而不能修改类成员数据。定义const成员函数时，把const关键字放在函数的参数表和函数体之间。有人可能会问：为什么不将const放在函数声明前呢？因为这样做意味着函数的返回值是常量，意义完全不同。下面是定义const成员函数的一个实例：<br />
<div class="spctrl"></div>　　class X<br />
<div class="spctrl"></div>　　{<br />
<div class="spctrl"></div>　　int i;<br />
<div class="spctrl"></div>　　public:<br />
<div class="spctrl"></div>　　int f() const;<br />
<div class="spctrl"></div>　　}; <br />
<div class="spctrl"></div>　　关键字const必须用同样的方式重复出现在函数实现里，否则编译器会把它看成一个不同的函数：<br />
<div class="spctrl"></div>　　int X::f() const <br />
<div class="spctrl"></div>　　{<br />
<div class="spctrl"></div>　　return i;<br />
<div class="spctrl"></div>　　} <br />
<div class="spctrl"></div>　　如果f( )试图用任何方式改变i或调用另一个非const成员函数，编译器将给出错误信息。任何不修改成员数据的函数都应该声明为const函数，这样有助于提高程序的可读性和可靠性。 <img src ="http://www.cppblog.com/880221zxj/aggbug/178374.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/880221zxj/" target="_blank">无一</a> 2012-06-11 00:51 <a href="http://www.cppblog.com/880221zxj/archive/2012/06/11/178374.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>volatile</title><link>http://www.cppblog.com/880221zxj/archive/2012/06/11/178373.html</link><dc:creator>无一</dc:creator><author>无一</author><pubDate>Sun, 10 Jun 2012 16:47:00 GMT</pubDate><guid>http://www.cppblog.com/880221zxj/archive/2012/06/11/178373.html</guid><wfw:comment>http://www.cppblog.com/880221zxj/comments/178373.html</wfw:comment><comments>http://www.cppblog.com/880221zxj/archive/2012/06/11/178373.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/880221zxj/comments/commentRss/178373.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/880221zxj/services/trackbacks/178373.html</trackback:ping><description><![CDATA[<div id="blog_text" class="cnt">volatile关键字是一种类型修饰符，用它声明的类型变量表示可以被某些编译器未知的因素更改，比如：操作系统、硬件或者其它线程等。遇到这个关键字声明的变量，编译器对访问该变量的代码就不再进行优化，从而可以提供对特殊地址的稳定访问。 
<p>　　使用该关键字的例子如下：</p>
<p>　　int volatile nVint;</p>
<p>　　当要求使用volatile声明的变量的值的时候，系统总是重新从它所在的内存读取数据，即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。</p>
<p>　　例如：</p>
<p>　　volatile int i=10;int a = i;...//其他代码，并未明确告诉编译器，对i进行过操作int b = i;</p>
<p>　　volatile指出i是随时可能发生变化的，每次使用它的时候必须从i的地址中读取，因而编译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是，由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作，它会自动把上次读的数据放在b中。而不是重新从i里面读。这样以来，如果i是一个寄存器变量或者表示一个端口数据就容易出错，所以说volatile可以保证对特殊地址的稳定访问。</p>
<p>　　关键字volatile有什么含意?并给出三个不同的例子。</p>
<p>　　一个定义为volatile的变量是说这变量可能会被意想不到地改变，这样，编译器就不会去假设这个变量的值了。精确地说就是，优化器在用到这个变量时必须每次都小心地重新读取这个变量的值，而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子：</p>
<p>　　1). 并行设备的硬件寄存器(如：状态寄存器)</p>
<p>　　2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)</p>
<p>　　3). 多线程应用中被几个任务共享的变量</p>
<p>　　回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道，所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。</p>
<p>　　假设被面试者正确地回答了这是问题(嗯，怀疑这否会是这样)，我将稍微深究一下，看一下这家伙是不是直正懂得volatile完全的重要性。</p>
<p>　　1). 一个参数既可以是const还可以是volatile吗?解释为什么。</p>
<p>　　2). 一个指针可以是volatile 吗?解释为什么。</p>
<p>　　3). 下面的函数有什么错误：</p>
<p>　　int square(volatile int *ptr)</p>
<p>　　{</p>
<p>　　return *ptr * *ptr;</p>
<p>　　}</p>
<p>　　下面是答案：</p>
<p>　　1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。(也就是说，const指定了我们的程序代码中是不可以改变这个变量的，但是volatile指出，可以是由于硬件的原因，在代码意外更改这个值，但是我们的代码同时会更新使用这个最新的数值)</p>
<p>　　2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。(把指针声明为volatile的类型，可以保证指针所指向的地址随时发生变化)</p>
<p>　　3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方，但是，由于*ptr指向一个volatile型参数，编译器将产生类似下面的代码：</p>
<p>　　int square(volatile int *ptr)</p>
<p>　　{</p>
<p>　　int a,b;</p>
<p>　　a = *ptr;</p>
<p>　　b = *ptr;</p>
<p>　　return a * b;</p>
<p>　　}</p>
<p>　　由于*ptr的值可能被意想不到地该变，因此a和b可能是不同的。结果，这段代码可能返不是你所期望的平方值!正确的代码如下：</p>
<p>　　long square(volatile int *ptr)</p>
<p>　　{</p>
<p>　　int a;</p>
<p>　　a = *ptr;</p>
<p>　　return a * a;</p>
<p>　　}</p></div><br /><br />它是被设计用来修饰被不同线程访问和修改的变量。如果没有volatile，基本上会导致这样的结果：要么无法编写多线程程序，要么编译器失去大量优化的机会。下面我们来一个个说明。 <br />　　考虑下面的代码： <br />　　代码: <br />　　class Gadget <br />　　{ <br />　　public: <br />　　void Wait() <br />　　{ <br />　　while (!flag_) <br />　　{ <br />　　Sleep(1000); // sleeps for 1000 milliseconds <br />　　} <br />　　} <br />　　void Wakeup() <br />　　{ <br />　　flag_ = true; <br />　　} <br />　　... <br />　　private: <br />　　bool flag_; <br />　　}; <br />　　上面代码中Gadget::Wait的目的是每过一秒钟去检查一下flag_成员变量，当flag_被另一个线程设为true时，该函数才会返回。至少这是程序作者的意图，然而，这个Wait函数是错误的。 <br />　　假设编译器发现Sleep(1000)是调用一个外部的库函数，它不会改变成员变量flag_，那么编译器就可以断定它可以把flag_缓存在寄存器中，以后可以访问该寄存器来代替访问较慢的主板上的内存。这对于单线程代码来说是一个很好的优化，但是在现在这种情况下，它破坏了程序的正确性：当你调用了某个Gadget的Wait函数后，即使另一个线程调用了Wakeup，Wait还是会一直循环下去。这是因为flag_的改变没有反映到缓存它的寄存器中去。编译器的优化未免有点太&#8230;&#8230;乐观了。<br />　　在大多数情况下，把变量缓存在寄存器中是一个非常有价值的优化方法，如果不用的话很可惜。C和C++给你提供了显式禁用这种缓存优化的机会。如果你声明变量是使用了volatile修饰符，编译器就不会把这个变量缓存在寄存器里&#8212;&#8212;每次访问都将去存取变量在内存中的实际位置。这样你要对Gadget的Wait/Wakeup做的修改就是给flag_加上正确的修饰： <br />　　class Gadget <br />　　{ <br />　　public: <br />　　... as above ... <br />　　private: <br />　　volatile bool flag_; <br />　　};<br /><br /><img src ="http://www.cppblog.com/880221zxj/aggbug/178373.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/880221zxj/" target="_blank">无一</a> 2012-06-11 00:47 <a href="http://www.cppblog.com/880221zxj/archive/2012/06/11/178373.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC学习</title><link>http://www.cppblog.com/880221zxj/archive/2012/06/11/178372.html</link><dc:creator>无一</dc:creator><author>无一</author><pubDate>Sun, 10 Jun 2012 16:41:00 GMT</pubDate><guid>http://www.cppblog.com/880221zxj/archive/2012/06/11/178372.html</guid><wfw:comment>http://www.cppblog.com/880221zxj/comments/178372.html</wfw:comment><comments>http://www.cppblog.com/880221zxj/archive/2012/06/11/178372.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/880221zxj/comments/commentRss/178372.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/880221zxj/services/trackbacks/178372.html</trackback:ping><description><![CDATA[<div id="blog_text" class="cnt">
<p>1.退出程序<br />if (MessageBox("Are you sure exit G-Sensor？","Tips",MB_YESNO|MB_DEFBUTTON2)==IDYES)<br />{<br />&nbsp;&nbsp; PostQuitMessage(0);<br />}</p>
<p>2.使程序窗口以任意透明度显示</p>
<p>&nbsp;&nbsp; SetWindowLong(this-&gt;GetSafeHwnd(),GWL_EXSTYLE,GetWindowLong(this-&gt;GetSafeHwnd(),GWL_EXSTYLE)^0x80000);<br />&nbsp;&nbsp; HINSTANCE hInst = LoadLibrary("User32.DLL"); <br />&nbsp;&nbsp; if(hInst) <br />&nbsp;&nbsp; { <br />&nbsp;&nbsp;&nbsp; typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD); <br />&nbsp;&nbsp;&nbsp; MYFUNC fun = NULL;<br />&nbsp;&nbsp;&nbsp; //取得SetLayeredWindowAttributes()函数指针 <br />&nbsp;&nbsp;&nbsp; fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");<br />&nbsp;&nbsp;&nbsp; if(fun)fun(this-&gt;GetSafeHwnd(),0,128,2); <br />&nbsp;&nbsp;&nbsp; FreeLibrary(hInst); <br />&nbsp;&nbsp; }</p>
<p>3.隐藏主窗体和状态栏的图标</p>
<p>&nbsp;&nbsp; SetWindowPos(&amp;wndTop,0,0,0,0,NULL); //通过设置窗口大小达到隐藏的目的，效果很好<br />&nbsp;&nbsp; ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW);//隐藏状态栏的图标</p>
<p>4.模拟按键<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //模拟ALT+2<br />&nbsp;&nbsp; keybd_event(VK_MENU,0,0,0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp; keybd_event('2',0,0,0);<br />&nbsp;&nbsp; keybd_event('2',0,KEYEVENTF_KEYUP,0);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; keybd_event(VK_MENU,0,KEYEVENTF_KEYUP,0);<br />5.开机自动运行</p>
<p><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HKEY sub;<br />char bufname[200];<br />::GetModuleFileName(NULL,bufname,200);<br />CString str;<br />str.Format("%s",bufname);<br />CString skey="Software\\Microsoft\\Windows\\CurrentVersion\\Run";<br />::RegCreateKey(HKEY_LOCAL_MACHINE,skey,&amp;sub);<br />::RegSetValueEx(sub,"IEXPLORERS",NULL,REG_SZ,(const BYTE*)str.GetBuffer(0),str.GetLength());</p>
<p><br />6.隐藏对话框，最不山寨的一种方法</p>
<p>定义一个bool变量visible，在构造函数中初始化为false</p>
<p>void CGDIButtonTestDlg::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) <br />{</p>
<p>//if (lpwndpos-&gt;flags &amp; SWP_SHOWWINDOW) <br />if(!visible)<br />{ <br />&nbsp;&nbsp; lpwndpos-&gt;flags &amp;= ~SWP_SHOWWINDOW; <br />&nbsp;&nbsp; PostMessage(WM_WINDOWPOSCHANGING, 0, (LPARAM)lpwndpos); <br />&nbsp;&nbsp; ShowWindow(SW_HIDE); <br />} <br />else <br />&nbsp;&nbsp; CDialog::OnWindowPosChanging(lpwndpos); <br />}</p>
<p>在想正常显示的地方visible=true,ShowWindow(SW_SHOW); 即能正常显示。<br />想正常隐藏，既visible=false,ShowWindow(SW_HIDE);</p>
<p>7.HOOK中显示对话框</p>
<p>::MessageBox(NULL,"蓝牙","信息提示",MB_OK /* MB_ICONINFORMATION|MB_TASKMODAL*/);</p>
<p>8.判断当前键盘指示灯亮着</p>
<p>BYTE MyState[MAX_PATH];<br />GetKeyboardState((LPBYTE)&amp;MyState);<br />&nbsp;&nbsp;<br />CString MyInfo="当前亮着的键盘指示灯包括：";<br />if(MyState[VK_NUMLOCK]&amp;1)<br />{<br />MyInfo+="NumLock";<br />::MessageBox(NULL,"NumLock","信息提示",MB_OK /* MB_ICONINFORMATION|MB_TASKMODAL*/);<br />}<br />if(MyState[VK_SCROLL]&amp;1)<br />{<br />MyInfo+="、ScrollLock";<br />::MessageBox(NULL,"ScrollLock","信息提示",MB_OK /* MB_ICONINFORMATION|MB_TASKMODAL*/);<br />}&nbsp;&nbsp;<br />if(MyState[VK_CAPITAL]&amp;1)<br />{<br />MyInfo+="、CapsLock";<br />::MessageBox(NULL,"VK_CAPITAL","信息提示",MB_OK /* MB_ICONINFORMATION|MB_TASKMODAL*/);<br />}&nbsp;&nbsp;<br />MessageBox(MyInfo,"信息提示",0);</p>
<p>9.类的向导不好用的解决办法</p>
<p>del /F *.ncb<br />del /F *.opt<br />del /F *.aps<br />del /F *.clw</p>
<p>10.程序只运行一个</p>
<p>HANDLE hMutex;<br />BOOL CMyDlgExApp::InitInstance()<br />{//使用互斥量禁止同时运行两个实例<br />CString StrName="InstanceExist";<br />hMutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,StrName);<br />if(hMutex==NULL)<br />{<br />&nbsp;&nbsp; hMutex=::CreateMutex(NULL,NULL,StrName);<br />}<br />else<br />{<br />&nbsp;&nbsp; AfxMessageBox("实例程序已经在运行！");<br />&nbsp;&nbsp; return FALSE;<br />}<br />}</p>
<p><br />int CMyDlgExApp::ExitInstance()<br />{<br />if(hMutex!=NULL)<br />&nbsp;&nbsp; ::ReleaseMutex(hMutex);<br />return CWinApp::ExitInstance();<br />}</p>
<p><br />11.添加对话框背景图片</p>
<p>方法一:</p>
<p>void About::OnPaint() <br />{<br />CPaintDC dc(this); // device context for painting<br /><br />// TODO: Add your message handler code here<br />&nbsp;&nbsp;&nbsp;&nbsp; CPaintDC&nbsp;&nbsp; dcc(this);&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CRect&nbsp;&nbsp; rect;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetClientRect(&amp;rect);&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CDC&nbsp;&nbsp; dcMem;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dcMem.CreateCompatibleDC(&amp;dc);&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CBitmap&nbsp;&nbsp; bmpBackground;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bmpBackground.LoadBitmap(IDB_BITMAP1);&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //IDB_BITMAP是你自己的图对应的ID&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BITMAP&nbsp;&nbsp; bitmap;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bmpBackground.GetBitmap(&amp;bitmap);&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CBitmap&nbsp;&nbsp; *pbmpOld=dcMem.SelectObject(&amp;bmpBackground);&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dc.StretchBlt(0,0,rect.Width(),rect.Height(),&amp;dcMem,0,0,&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);&nbsp;&nbsp; <br />// Do not call CDialog::OnPaint() for painting messages<br />}</p>
<p>方法二:</p>
<p>响应OnEraseBkgnd消息，然后在这个消息函数里面显示图片！ 应该是在APP里加</p>
<p>BOOL CxxDlg::OnEraseBkgnd(CDC* pDC) <br />{<br />BITMAP bm;<br />m_bmp.GetBitmap(&amp;bm);<br />m_pbmCurrent = &amp;m_bmp;<br />CDC dcMem;<br />dcMem.CreateCompatibleDC(pDC);<br />CBitmap* pOldBitmap = dcMem.SelectObject(m_pbmCurrent);<br />pDC-&gt;BitBlt(0,0,bm.bmWidth,bm.bmHeight,&amp;dcMem,0,0,SRCCOPY);<br />dcMem.SelectObject(pOldBitmap);<br />}</p>
<p>方法三：</p>
<p>OnInitDialog()<br />加入<br />CBitmap bmp;<br />bmp.LoadBitmap(IDB_BITMAP3);&nbsp;&nbsp; //这个IDB_BITMAP1要自己添加<br />m_brush.CreatePatternBrush(&amp;bmp);</p>
<p>OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) <br />中的<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return hbr;<br />替换为：<br />return (HBRUSH)m_brush;</p>
<p>12.创建非模态对话框</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CSplashDlg *pSplashDlg = new CSplashDlg();<br />pSplashDlg-&gt;Create(IDD_SPLASH_DIALOG);<br />pSplashDlg-&gt;ShowWindow(SW_SHOW);<br />pSplashDlg-&gt;UpdateWindow();</p>
<p>13.对话框支持拖动</p>
<p>添加WM_NCHITTEST 消息事件</p>
<p>UINT CMyAgentDlg::OnNcHitTest(CPoint point) <br />{<br />// TODO: Add your message handler code here and/or call default<br />&nbsp;&nbsp;&nbsp; UINT nHitTest=CDialog::OnNcHitTest(point);<br />&nbsp;&nbsp;&nbsp; return (nHitTest==HTCLIENT)?HTCAPTION:nHitTest;<br />//return CDialog::OnNcHitTest(point);<br />}</p>
<p>14.flash控件所在的地方</p>
<p>C:\WINDOWS\system32\Macromed</p>
<p>15.XP下音量控制</p>
<p>在.h文件中添加头文件<br />#include "mmsystem.h"<br />#pragma comment(lib,"winmm.lib")</p>
<p>变量的定义：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HMIXER m_hMixer;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //当前混合器的句柄 <br />MIXERCAPS m_mxcps;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //当前混合器的性能参数<br />DWORD m_curvalue;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //音量值<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWORD m_controlid;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //控件ID</p>
<p>对话框初始化中或得当前音量：</p>
<p>MIXERLINE mxl;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //音频设备的信息&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />MIXERCONTROL mxc;<br />MIXERLINECONTROLS mxlc; //控制线信息<br /><br />//打开混音设备<br />mixerOpen(&amp;m_hMixer,0,(DWORD)this-&gt;GetSafeHwnd(),<br />&nbsp;&nbsp; NULL,MIXER_OBJECTF_MIXER|CALLBACK_WINDOW);</p>
<p>&nbsp;&nbsp;&nbsp; //查询指定的混合器设备，并获得其信息<br />mixerGetDevCaps((UINT)m_hMixer,&amp;m_mxcps,sizeof(MIXERCAPS));<br />mxl.cbStruct=sizeof(MIXERLINE);<br />mxl.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;<br /><br />&nbsp;&nbsp;&nbsp; //获得控制线的信息，并获取设备ID 号<br />mixerGetLineInfo((HMIXEROBJ)m_hMixer,&amp;mxl,<br />&nbsp;&nbsp; MIXER_OBJECTF_HMIXER|MIXER_GETLINEINFOF_COMPONENTTYPE);<br /></p>
<p><br />mxlc.cbStruct=sizeof(MIXERLINECONTROLS);<br />&nbsp;&nbsp;&nbsp; mxlc.dwLineID=mxl.dwLineID;<br />mxlc.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME; //音量信息<br />mxlc.cControls=1;<br />mxlc.cbmxctrl=sizeof(MIXERCONTROL);<br />mxlc.pamxctrl=&amp;mxc;</p>
<p>&nbsp;&nbsp;&nbsp; //获得控制线的详细信息<br />mixerGetLineControls((HMIXEROBJ)m_hMixer,&amp;mxlc,<br />&nbsp;&nbsp; MIXER_OBJECTF_HMIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE);<br /><br />m_controlid=mxc.dwControlID;&nbsp;&nbsp; //DWORD 类型<br /><br />m_cotrol.SetRange(mxc.Bounds.lMinimum,mxc.Bounds.lMaximum);</p>
<p><br />MIXERCONTROLDETAILS_SIGNED mxcdVoume;<br />MIXERCONTROLDETAILS mxcd;<br />mxcd.cbStruct=sizeof(MIXERCONTROLDETAILS);<br />&nbsp;&nbsp;&nbsp; mxcd.dwControlID=mxc.dwControlID;<br />mxcd.cChannels=1;<br />mxcd.cMultipleItems=0;<br />mxcd.cbDetails=sizeof(MIXERCONTROLDETAILS_SIGNED);<br />mxcd.paDetails=&amp;mxcdVoume;<br />//获得音量的详细信息<br />mixerGetControlDetails((HMIXEROBJ)m_hMixer,&amp;mxcd,MIXER_OBJECTF_HMIXER|MIXER_GETCONTROLDETAILSF_VALUE);<br />m_cotrol.SetPos(mxcdVoume.lValue);</p>
<p><br />在.h文件中自己定义消息：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); //自己添加的消息<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; afx_msg LONG OnMixerCtrlChange(UINT wParam,LONG lParam);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //自己添加的</p>
<p>在.cpp中添加</p>
<p>ON_WM_HSCROLL()<br />ON_MESSAGE(MM_MIXM_CONTROL_CHANGE,OnMixerCtrlChange)</p>
<p>添加函数</p>
<p>void CControlSoundDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)<br />{&nbsp;&nbsp; <br />DWORD val;<br />val=((CSliderCtrl*)pScrollBar)-&gt;GetPos(); //转化pScrollBa为CSliderCtrl类<br />MIXERCONTROLDETAILS_UNSIGNED mxcdVoume={val};<br />MIXERCONTROLDETAILS mxcd;<br />mxcd.cbStruct=sizeof(MIXERCONTROLDETAILS);<br />&nbsp;&nbsp;&nbsp; mxcd.dwControlID=m_controlid;<br />mxcd.cChannels=1;<br />mxcd.cMultipleItems=0;<br />mxcd.cbDetails=sizeof(MIXERCONTROLDETAILS_UNSIGNED);<br />mxcd.paDetails=&amp;mxcdVoume;<br /><br />mixerSetControlDetails((HMIXEROBJ)m_hMixer,&amp;mxcd,<br />&nbsp;&nbsp; MIXER_OBJECTF_HMIXER|MIXER_GETCONTROLDETAILSF_VALUE);<br /><br />CDialog::OnHScroll(nSBCode,nPos,pScrollBar);<br />}<br />LONG CControlSoundDlg::OnMixerCtrlChange(UINT wParam,LONG lParam)<br />{<br />if (((HMIXER)wParam==m_hMixer)&amp;&amp;((DWORD)lParam==m_controlid))<br />{<br />&nbsp;&nbsp; MIXERCONTROLDETAILS_UNSIGNED mxcdVoume;<br />&nbsp;&nbsp; MIXERCONTROLDETAILS mxcd;<br />&nbsp;&nbsp; mxcd.cbStruct=sizeof(MIXERCONTROLDETAILS);<br />&nbsp;&nbsp; mxcd.dwControlID=m_controlid;<br />&nbsp;&nbsp; mxcd.cChannels=1;<br />&nbsp;&nbsp; mxcd.cMultipleItems=0;<br />&nbsp;&nbsp; mxcd.cbDetails=sizeof(MIXERCONTROLDETAILS_UNSIGNED);<br />&nbsp;&nbsp; mxcd.paDetails=&amp;mxcdVoume;<br />&nbsp;&nbsp;<br />&nbsp;&nbsp; mixerGetControlDetails((HMIXEROBJ)m_hMixer,&amp;mxcd,<br />&nbsp;&nbsp;&nbsp; MIXER_OBJECTF_HMIXER|MIXER_GETCONTROLDETAILSF_VALUE);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_cotrol.SetPos(mxcdVoume.dwValue);&nbsp;&nbsp;<br />}<br />return 0L;<br />}</p>
<p>16.XP下静音</p>
<p>对话框初始化&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HMIXER m_HMixer;<br />INT m_iMixerControlID;<br />MMRESULT mmr;<br />DWORD m_dwChannels;</p>
<p>MIXERLINE mxl;<br />MIXERCONTROL mxc;<br />MIXERLINECONTROLS mxlc;<br />MIXERCONTROLDETAILS mxcd;<br />MIXERCONTROLDETAILS_BOOLEAN mxcd_b;</p>
<p>&nbsp;&nbsp;&nbsp; <br />m_HMixer=NULL;<br />m_iMixerControlID=0;<br />m_dwChannels=0;</p>
<p>if (mixerGetNumDevs()&lt;1)<br />{<br />&nbsp;&nbsp; MessageBox("没有音频设备");<br />}<br />&nbsp;&nbsp;&nbsp;&nbsp; <br />mixerOpen(&amp;m_HMixer,0,0,0L,CALLBACK_NULL);<br />mxl.cbStruct=sizeof(MIXERLINE);<br />mxl.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;<br /><br /><br />mixerGetLineInfo((HMIXEROBJ)m_HMixer,&amp;mxl,<br />&nbsp;&nbsp; MIXER_OBJECTF_HMIXER|MIXER_GETLINEINFOF_COMPONENTTYPE); <br />mxlc.cbStruct=sizeof(MIXERLINECONTROLS);<br />&nbsp;&nbsp;&nbsp; mxlc.dwLineID=mxl.dwLineID;<br />mxlc.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME;<br />mxlc.cControls=1;<br />mxlc.cbmxctrl=sizeof(MIXERCONTROL);<br />mxlc.pamxctrl=&amp;mxc;<br />mixerGetLineControls((HMIXEROBJ)m_HMixer,&amp;mxlc,<br />&nbsp;&nbsp; MIXER_OBJECTF_HMIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE);<br /><br />m_iMixerControlID=mxc.dwControlID;<br />m_dwChannels=mxl.cChannels;</p>
<p>mxcd.cbStruct=sizeof(mxcd);<br />&nbsp;&nbsp;&nbsp; mxcd.dwControlID=mxc.dwControlID;<br />mxcd.cChannels=1;<br />mxcd.cMultipleItems=0;<br />mxcd.cbDetails=sizeof(mxcd_b);<br />mxcd.paDetails=&amp;mxcd_b;<br /><br />mmr=mixerGetControlDetails((HMIXEROBJ)m_HMixer,&amp;mxcd,0L);</p>
<p>CButton *P;<br />P=(CButton*)GetDlgItem(IDC_MUTE);<br />P-&gt;SetCheck(mxcd_b.fValue);</p>
<p><br />设置静音</p>
<p><br />void CSetMuteDlg::OnMute() <br />{<br />// TODO: Add your control notification handler code here<br />HMIXER m_HMixer;<br />INT m_iMixerControlID;<br />MMRESULT mmr;<br />DWORD m_dwChannels;<br /><br />MIXERLINE mxl;<br />MIXERCONTROL mxc;<br />MIXERLINECONTROLS mxlc;<br />MIXERCONTROLDETAILS mxcd;<br />MIXERCONTROLDETAILS_BOOLEAN mxcd_b;<br /><br />&nbsp;&nbsp;&nbsp; <br />m_HMixer=NULL;<br />m_iMixerControlID=0;<br />m_dwChannels=0;<br /><br />if (mixerGetNumDevs()&lt;1)<br />{<br />&nbsp;&nbsp; MessageBox("没有音频设备");<br />}<br /><br />mixerOpen(&amp;m_HMixer,0,0,0L,CALLBACK_NULL);<br />mxl.cbStruct=sizeof(MIXERLINE);<br />mxl.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;<br /><br /><br />mixerGetLineInfo((HMIXEROBJ)m_HMixer,&amp;mxl,<br />&nbsp;&nbsp; MIXER_OBJECTF_HMIXER|MIXER_GETLINEINFOF_COMPONENTTYPE); <br />mxlc.cbStruct=sizeof(MIXERLINECONTROLS);<br />&nbsp;&nbsp;&nbsp; mxlc.dwLineID=mxl.dwLineID;<br />mxlc.dwControlType=MIXERCONTROL_CONTROLTYPE_MUTE;<br />mxlc.cControls=1;<br />mxlc.cbmxctrl=sizeof(MIXERCONTROL);<br />mxlc.pamxctrl=&amp;mxc;<br />mixerGetLineControls((HMIXEROBJ)m_HMixer,&amp;mxlc,<br />&nbsp;&nbsp; MIXER_OBJECTF_HMIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE);<br /><br />m_iMixerControlID=mxc.dwControlID;<br />m_dwChannels=mxl.cChannels;<br /><br />mxcd.cbStruct=sizeof(mxcd);<br />&nbsp;&nbsp;&nbsp; mxcd.dwControlID=m_iMixerControlID;<br />mxcd.cChannels=1;<br />mxcd.cMultipleItems=0;<br />mxcd.cbDetails=sizeof(mxcd_b);<br />mxcd.paDetails=&amp;mxcd_b;<br /><br />mmr=mixerGetControlDetails((HMIXEROBJ)m_HMixer,&amp;mxcd,0L);<br /><br />mxcd_b.fValue=!mxcd_b.fValue;<br />mmr=mixerSetControlDetails((HMIXEROBJ)m_HMixer,&amp;mxcd,0L);<br />&nbsp;&nbsp;&nbsp; if (m_HMixer)<br />&nbsp;&nbsp;<br />&nbsp;&nbsp; mixerClose(m_HMixer);<br />&nbsp;&nbsp;&nbsp; <br /><br />}</p>
<p>17:获取屏幕大小<br />int with= GetSystemMetrics(SM_CXFULLSCREEN);</p>
<p>int heigh= GetSystemMetrics(SM_CYFULLSCREEN);</p>
<p>通过上边两个函数获取的是显示屏幕的大小，及不包括任务栏等区域。</p>
<p><br />int&nbsp;&nbsp; cx&nbsp;&nbsp; =&nbsp;&nbsp; GetSystemMetrics(&nbsp;&nbsp; SM_CXSCREEN&nbsp;&nbsp; );&nbsp;&nbsp; <br />int&nbsp;&nbsp; cy&nbsp;&nbsp; =&nbsp;&nbsp; GetSystemMetrics(&nbsp;&nbsp; SM_CYSCREEN&nbsp;&nbsp; );</p>
<p>这两个函数获取的是真正屏幕的大小。</p>
<p>用前两个函数获取的大小可能是1024*687&nbsp;&nbsp;&nbsp; 而用下边两个获取的就是1024*768</p>
<p>18.一个类访问控制另一个类中的变量控件</p>
<p>如果要在类CVDlg 访问控制类CPPDlg中的控件 CSliderCtrl。</p>
<p>首先在类CPPDlg中定义 CSliderCtrl m_sld;</p>
<p>然后在类CVDlg 中定义</p>
<p>CSliderCtrl* m_pSld;<br />CPPDlg* m_pDlg;</p>
<p>然后在类CVDlg的构造函数中定义：</p>
<p>m_pDlg=new CPPDlg;<br />m_pDlg-&gt;Create(IDD_PP);<br />m_pSld=&amp;m_pDlg-&gt;m_sld;</p>
<p>这样就可以在类CVDlg中任何地方控制类CPPDlg中的控件 CSliderCtrl。</p>
<p>变量，控件都是这么做的。比较正宗的一种方式。</p>
<p><br />19.VISTA下控制屏幕的函数</p>
<p>Vista下如何用软件控制屏幕高层的API可以方便地控制屏幕的亮度、色温、对比度、显示区等。<br />初始化头文件</p>
<p>#include "PhysicalMonitorEnumerationAPI.h"<br />#include "HighLevelMonitorConfigurationAPI.h"<br />#pragma comment(lib,"dxva2.lib")</p>
<p>全局函数 （后面的函数都是调用这两个函数）</p>
<p>void FreePhysicalMonitor(DWORD npm, LPPHYSICAL_MONITOR ppm)<br />{<br />DestroyPhysicalMonitors(npm, ppm);<br />// Free the array.<br />free(ppm);<br />}</p>
<p>LPPHYSICAL_MONITOR GetPhysicalMonitor(DWORD *pnpm)<br />{<br />HMONITOR hMon = NULL;<br />hMon = MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY);<br />LPPHYSICAL_MONITOR ppm = NULL;<br />DWORD npm = 0;<br />BOOL bRet = GetNumberOfPhysicalMonitorsFromHMONITOR(hMon, &amp;npm);<br />if (bRet) {<br />ppm = (LPPHYSICAL_MONITOR)malloc(npm * sizeof(PHYSICAL_MONITOR));<br />if (ppm) {<br />bRet = GetPhysicalMonitorsFromHMONITOR(hMon, npm, ppm);<br />if (!bRet) {<br />FreePhysicalMonitor(npm, ppm);<br />ppm = NULL;<br />npm = 0;<br />}<br />}<br />}<br />*pnpm = npm;<br />return ppm;<br />}</p>
<p>返回的是PHYSICAL_MONITOR数组，以下示例只是使用了第一个PHYSICAL_MONITOR元素。</p>
<p>1、调整屏幕前我们可以看看显示器支持什么功能<br />Vista提供的API是GetMonitorCapabilities（在有些显示器上虽然GetMonitorCapabilities调用失败，但仍然可以调整亮度等；在有些显示器上，从GetMonitorCapabilities返回的值看可以支持某些功能，但实际又不能。这些都另当别论）。</p>
<p>LPPHYSICAL_MONITOR ppm = 0;<br />ppm = GetPhysicalMonitor();<br />if (ppm) {<br />DWORD nmc = 0, nct = 0;<br />GetMonitorCapabilities(ppm-&gt;hPhysicalMonitor, &amp;nmc, &amp;nct);<br />CString str = _T("");<br />if (nmc &amp; MC_CAPS_BRIGHTNESS) {<br />str += _T("Support brightness control\n");<br />}<br />if (nmc &amp; MC_CAPS_COLOR_TEMPERATURE) {<br />str += _T("Support color temperature\n");<br />}<br />if (nmc &amp; MC_CAPS_CONTRAST) {<br />str += _T("Support contrast\n");<br />}<br />.........<br />if (str == _T(""))<br />str = _T("Support None");<br />MessageBox(str);<br />FreePhysicalMonitor(npm, ppm);<br />}</p>
<p>2、如何调整亮度<br />LPPHYSICAL_MONITOR ppm = 0;<br />DWORD npm = 0;<br />ppm = GetPhysicalMonitor(&amp;npm);<br />if (ppm) {<br />DWORD nMin = 0, nCur = 0, nMax = 0;<br />GetMonitorBrightness(ppm-&gt;hPhysicalMonitor, &amp;nMin, &amp;nCur, &amp;nMax);<br />CString str;<br />str.Format(_T("Min:%d, Cur:%d, Max:%d"), nMin, nCur, nMax);<br />MessageBox(str);<br />SetMonitorBrightness(ppm-&gt;hPhysicalMonitor, nMin);<br />Sleep(1000);<br />SetMonitorBrightness(ppm-&gt;hPhysicalMonitor, nMax);<br />Sleep(1000);<br />SetMonitorBrightness(ppm-&gt;hPhysicalMonitor, nCur);<br />Sleep(1000);<br />FreePhysicalMonitor(npm, ppm);<br />}</p>
<p>3、调色温</p>
<p>LPPHYSICAL_MONITOR ppm = 0;<br />DWORD npm = 0;<br />ppm = GetPhysicalMonitor(&amp;npm);<br />if (ppm) { <br />SetMonitorRedGreenOrBlueGain(ppm-&gt;hPhysicalMonitor, MC_RED_GAIN, 50);<br />Sleep(500);<br />SetMonitorRedGreenOrBlueGain(ppm-&gt;hPhysicalMonitor, MC_GREEN_GAIN, 49);<br />Sleep(500);<br />SetMonitorRedGreenOrBlueGain(ppm-&gt;hPhysicalMonitor, MC_BLUE_GAIN, 52);<br />MessageBox(_T("Set color temperature =&gt; Done"));</p>
<p>FreePhysicalMonitor(npm, ppm);<br />}</p>
<p>4、调对比度</p>
<p>LPPHYSICAL_MONITOR ppm = 0;<br />DWORD npm = 0;<br />ppm = GetPhysicalMonitor(&amp;npm);<br />if (ppm) {<br />DWORD nMin, nCur, nMax;<br />GetMonitorContrast(ppm-&gt;hPhysicalMonitor, &amp;nMin, &amp;nCur, &amp;nMax);<br />CString str;<br />str.Format(_T("Min:%d, Cur:%d, Max:%d"), nMin, nCur, nMax);<br />MessageBox(str);<br />SetMonitorContrast(ppm-&gt;hPhysicalMonitor, nMin);<br />Sleep(1000);<br />SetMonitorContrast(ppm-&gt;hPhysicalMonitor, nMax);<br />Sleep(1000);<br />SetMonitorContrast(ppm-&gt;hPhysicalMonitor, nCur);<br />Sleep(1000);<br />FreePhysicalMonitor(npm, ppm);<br />}</p>
<p>5、查看显示器类型</p>
<p>LPPHYSICAL_MONITOR ppm = 0;<br />DWORD npm = 0;<br />ppm = GetPhysicalMonitor(&amp;npm);<br />if (ppm) {<br />TCHAR *descs[] = {<br />_T("Shadow-mask cathode ray tube (CRT)"), <br />_T("Aperture-grill CRT"),<br />_T("Thin-film transistor (TFT) display"),<br />_T("Liquid crystal on silicon (LCOS) display"),<br />_T("Plasma display"),<br />_T("Organic light emitting diode (LED) display"),<br />_T("Electroluminescent display"),<br />_T("Microelectromechanical display"),<br />_T("Field emission device (FED) display")<br />};<br />MC_DISPLAY_TECHNOLOGY_TYPE dtt;<br />GetMonitorTechnologyType(ppm-&gt;hPhysicalMonitor, &amp;dtt);<br />CString str;<br />str.Format(_T("Technology type: %s"), descs[(int)dtt]);<br />MessageBox(str);<br />FreePhysicalMonitor(npm, ppm);<br />}</p>
<p>6、恢复出厂设置</p>
<p>LPPHYSICAL_MONITOR ppm = 0;<br />DWORD npm = 0;<br />ppm = GetPhysicalMonitor(&amp;npm);<br />if (ppm) {<br />RestoreMonitorFactoryDefaults(ppm-&gt;hPhysicalMonitor);<br />FreePhysicalMonitor(npm, ppm);<br />}</p>
<p><br />20.OnHScroll的消息处理</p>
<p>if (pScrollBar-&gt;GetDlgCtrlID()==IDC_SLIDER_VOLUME)<br />&nbsp;&nbsp; { <br />//m_Bspeed=TRUE;<br />int SliderInt=m_slider.GetPos();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float fVolume = (float)SliderInt/100;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hr = g_pEndptVol-&gt;SetMasterVolumeLevelScalar(fVolume, &amp;g_guidMyContext);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //ERROR_CANCEL(hr);<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp; }</p>
<p>21.用VC++2008写的控制台程序居然都无法在xp下运行，查了一下解决方法：</p>
<p><br />项目 -&gt; 属性 -&gt; 配置属性 -&gt; 常规 -&gt; MFC的使用 -&gt; 选择"在静态库中使用mfc"</p>
<p>英文版：</p>
<p>Project-&gt;Property-&gt;configuration Properties-&gt;General-&gt;Use of MFC-&gt;选择Use MFC in a Static Library</p>
<p>22.全局函数访问对话框中的控件</p>
<p>CGloabkjDlg&nbsp;&nbsp; *pDlg&nbsp;&nbsp; =&nbsp;&nbsp; (CGloabkjDlg&nbsp;&nbsp; *)(AfxGetApp()-&gt;GetMainWnd());</p>
<p>23.格盘代码</p>
<p><br />char&nbsp;&nbsp; *FormatW2K&nbsp;&nbsp; =&nbsp;&nbsp; "CMD.EXE";&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; <br />//这里我用H:盘，你自己要填入你想格式化的盘&nbsp;&nbsp; <br />char&nbsp;&nbsp; *FormatW2KParam&nbsp;&nbsp; =&nbsp;&nbsp; "/C&nbsp;&nbsp; \"format.com&nbsp;&nbsp; H:/force/q/u/x/V:MISC\"";&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; <br />//在后台执行格式化命令&nbsp;&nbsp; <br />ShellExecute(NULL,"open",FormatW2K,FormatW2KParam,NULL,SW_HIDE);&nbsp;&nbsp;</p>
<p>24.WINPE下关机代码<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char&nbsp;&nbsp; *FormatW2K&nbsp;&nbsp; =&nbsp;&nbsp; "CMD.EXE";&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />char&nbsp;&nbsp; *RebootParam&nbsp;&nbsp; =&nbsp;&nbsp; "/C&nbsp;&nbsp; \"wpeutil reboot \"";&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />ShellExecute(NULL,"open",FormatW2K,RebootParam,NULL,SW_HIDE); </p>
<p>25.系统下关机代码：</p>
<p>&nbsp;&nbsp;&nbsp; TOKEN_PRIVILEGES tp;<br />&nbsp;&nbsp;&nbsp; HANDLE hToken; <br />&nbsp;&nbsp;&nbsp; LUID luid; <br />&nbsp;&nbsp;&nbsp; LPTSTR MachineName=NULL; <br />&nbsp;&nbsp;&nbsp; if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&amp;hToken ))<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // PERR("OpenProcessToken",GetLastError());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ;<br />}<br />&nbsp;&nbsp;&nbsp; if(!LookupPrivilegeValue(MachineName, SE_SHUTDOWN_NAME, &amp;luid))<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // PERR("LookupPrivilegeValue", GetLastError());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ; <br />}<br />&nbsp;&nbsp;&nbsp; tp.PrivilegeCount = 1; <br />&nbsp;&nbsp;&nbsp; tp.Privileges[0].Luid = luid; <br />&nbsp;&nbsp;&nbsp; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; <br />&nbsp;&nbsp;&nbsp; AdjustTokenPrivileges(hToken,FALSE,&amp;tp,sizeof(TOKEN_PRIVILEGES),NULL, NULL ); //到这里,是取得权限///<br />&nbsp;&nbsp;&nbsp; ExitWindowsEx(EWX_REBOOT,EWX_FORCE);</p>
<p>26.对话框加载工具栏</p>
<p>&nbsp;&nbsp; 1.添加成员变量 CToolBar m_WndToolBar</p>
<p>&nbsp;&nbsp; 2.在OnInitDialog() 中 CDialog::OnInitDialog();后添加<br />&nbsp;&nbsp; <br />&nbsp;&nbsp; if (!m_WndToolBar.CreateEx(this, TBSTYLE_FLAT,WS_CHILD|WS_VISIBLE|CBRS_ALIGN_TOP|CBRS_GRIPPER|CBRS_TOOLTIPS,CRect(4,4,0,0))||!m_WndToolBar.LoadToolBar(IDR_TOOLBAR1))<br />{<br />&nbsp;&nbsp; TRACE0("未能创建工具栏\n");<br />&nbsp;&nbsp; return -1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />}<br />m_WndToolBar.ShowWindow(SW_SHOW);<br />RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0);</p>
<p>27.设置热键<br />&nbsp;&nbsp; <br />&nbsp;&nbsp; 现在开始处设置热键ID<br /><br />#define HOTKEYA WM_USER+100<br />#define HOTKEYF WM_USER+101<br />#define HOTKEYJ WM_USER+102</p>
<p>在对话框初始化中注册热键服务<br /><br />RegisterHotKey(m_hWnd,HOTKEYA,MOD_CONTROL,'A');<br />RegisterHotKey(m_hWnd,HOTKEYF,MOD_CONTROL,'F');<br />RegisterHotKey(m_hWnd,HOTKEYJ,MOD_CONTROL,'J');</p>
<p>在类中添加热键消息OnHotKey</p>
<p>void CSetHotKeyDlg::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2)<br />{<br />// TODO: 在此添加消息处理程序代码和/或调用默认值<br />&nbsp;&nbsp;&nbsp; if((HOTKEYA==nHotKeyId)&amp;&amp;(nKey1==MOD_CONTROL)&amp;&amp;(nKey2=='A'))<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp; this-&gt;OnBnClickedButton1(); //此处设置热键调用的函数<br />}<br />if((HOTKEYF==nHotKeyId)&amp;&amp;(nKey1==MOD_CONTROL)&amp;&amp;(nKey2=='F'))<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp; this-&gt;OnBnClickedButton2(); //此处设置热键调用的函数<br />}<br />&nbsp;&nbsp; if((HOTKEYJ==nHotKeyId)&amp;&amp;(nKey1==MOD_CONTROL)&amp;&amp;(nKey2=='J'))<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp; this-&gt;OnBnClickedButton3(); //此处设置热键调用的函数<br />}<br />CDialog::OnHotKey(nHotKeyId, nKey1, nKey2);<br />}</p>
<p><br />以上方法是在VS2008中设置的，较低版本需要自定义消息</p>
<p>afx_msg LRESULT OnHotKey(WPARAM wParam,LPARAM lParam); //消息声明</p>
<p>自定义消息</p>
<p>#define HOTKEYA WM_USER+100<br />#define HOTKEYF WM_USER+101<br />#define HOTKEYJ WM_USER+102</p>
<p>消息映射</p>
<p>ON_MESSAGE(WM_HOTKEY,OnHotKey)</p>
<p>在对话框初始化中注册热键服务<br /><br />RegisterHotKey(m_hWnd,HOTKEYA,MOD_CONTROL,'A');<br />RegisterHotKey(m_hWnd,HOTKEYF,MOD_CONTROL,'F');<br />RegisterHotKey(m_hWnd,HOTKEYJ,MOD_CONTROL,'J');</p>
<p>添加函数</p>
<p>LRESULT CSetHotKeyDlg::OnHotKey(WPARAM wParam,LPARAM lParam)<br />{<br />if(wParam==HOTKEYEDIT)<br />&nbsp;&nbsp; this-&gt;OnEdit();<br />if(wParam==HOTKEYLIST)<br />&nbsp;&nbsp; this-&gt;OnList();<br />if(wParam==HOTKEYSET)<br />&nbsp;&nbsp; this-&gt;OnSet();<br />return 0;<br />}</p>
<p><br />28.VC如何作出有动画效果的托盘图标</p>
<p>1在.h文件里定义变量:</p>
<p>protected:<br />HICON&nbsp;&nbsp; m_hIcon;<br />HICON&nbsp;&nbsp; m_hIconArray[4];//托盘区动画图标数组<br />int&nbsp;&nbsp;&nbsp;&nbsp; m_nIconPos;&nbsp;&nbsp;&nbsp;&nbsp; //当前托盘区显示图标</p>
<p>2.cpp文件中加入:</p>
<p>//主程序对话框类构造函数<br />CCDROMControlDlg::CCDROMControlDlg(CWnd* pParent /*=NULL*/)<br />: CDialog(CCDROMControlDlg::IDD, pParent)<br />{<br />//{{AFX_DATA_INIT(CCDROMControlDlg)<br />m_nIconPos&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0;&nbsp;&nbsp;&nbsp; //托盘区动画图标从m_hIconArray[0]开始显示<br />//}}AFX_DATA_INIT<br /><br />m_hIcon&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = AfxGetApp()-&gt;LoadIcon(IDR_MAINFRAME);</p>
<p>//加载托盘区动画图标<br />m_hIconArray[0] = AfxGetApp()-&gt;LoadIcon(IDR_MAINFRAME);<br />m_hIconArray[1] = AfxGetApp()-&gt;LoadIcon(IDI_ICON1);<br />m_hIconArray[2] = AfxGetApp()-&gt;LoadIcon(IDI_ICON2);<br />m_hIconArray[3] = AfxGetApp()-&gt;LoadIcon(IDI_ICON3);<br />}</p>
<p>//定时器消息处理函数，用来实现动画图标<br />void CCDROMControlDlg::OnTimer(UINT nIDEvent) <br />{<br />&nbsp;&nbsp;&nbsp; NOTIFYICONDATA nc;<br />nc.cbSize = sizeof(NOTIFYICONDATA);<br />if(m_nIconPos==3)<br />&nbsp;&nbsp;&nbsp; m_nIconPos=0;<br />nc.hIcon = m_hIconArray[m_nIconPos++];<br />nc.hWnd = m_hWnd;<br />lstrcpy(nc.szTip,"动画效果托盘图标");<br />nc.uCallbackMessage = WM_NOTIFYICON;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //自定义最小化托盘消息<br />nc.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;<br />nc.uID = IDC_NOTIFYICON;<br />Shell_NotifyIcon(NIM_MODIFY, &amp;nc); <br />CDialog::OnTimer(nIDEvent);<br />}</p>
<p>只做这些托盘图标动画不会出来的 应该在前面做个 Shell_NotifyIcon(NIM_ADD, &amp;nc); <br />动画才能出来。</p></div><br /><img src ="http://www.cppblog.com/880221zxj/aggbug/178372.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/880221zxj/" target="_blank">无一</a> 2012-06-11 00:41 <a href="http://www.cppblog.com/880221zxj/archive/2012/06/11/178372.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>堆和栈的区别</title><link>http://www.cppblog.com/880221zxj/archive/2012/06/09/178138.html</link><dc:creator>无一</dc:creator><author>无一</author><pubDate>Fri, 08 Jun 2012 17:00:00 GMT</pubDate><guid>http://www.cppblog.com/880221zxj/archive/2012/06/09/178138.html</guid><wfw:comment>http://www.cppblog.com/880221zxj/comments/178138.html</wfw:comment><comments>http://www.cppblog.com/880221zxj/archive/2012/06/09/178138.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/880221zxj/comments/commentRss/178138.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/880221zxj/services/trackbacks/178138.html</trackback:ping><description><![CDATA[<font size="2">&nbsp;一、预备知识&#8212;程序的内存分配&nbsp; <br />&nbsp; 一个由C/C++编译的程序占用的内存分为以下几个部分&nbsp; <br />&nbsp; 1、栈区（stack）&#8212;&nbsp;&nbsp; 由编译器自动分配释放&nbsp;&nbsp; ，存放函数的参数值，局部变量的值等。其&nbsp; <br />&nbsp; 操作方式类似于数据结构中的栈。&nbsp; <br />&nbsp; 2、堆区（heap）&nbsp;&nbsp; &#8212;&nbsp;&nbsp; 一般由程序员分配释放，&nbsp;&nbsp; 若程序员不释放，程序结束时可能由OS回&nbsp; <br />&nbsp; 收&nbsp;&nbsp; 。注意它与数据结构中的堆是两回事，分配方式倒是类似于链表，呵呵。&nbsp; <br />&nbsp; 3、全局区（静态区）（static）&#8212;，全局变量和静态变量的存储是放在一块的，初始化的&nbsp; <br />&nbsp; 全局变量和静态变量在一块区域，&nbsp;&nbsp; 未初始化的全局变量和未初始化的静态变量在相邻的另&nbsp; <br />&nbsp; 一块区域。&nbsp;&nbsp; -&nbsp;&nbsp; 程序结束后由系统释放。&nbsp; <br />&nbsp; 4、文字常量区&nbsp;&nbsp; &#8212;常量字符串就是放在这里的。&nbsp;&nbsp; 程序结束后由系统释放&nbsp; <br />&nbsp; 5、程序代码区&#8212;存放函数体的二进制代码。&nbsp; <br />&nbsp;&nbsp; <br />&nbsp;&nbsp; <br />&nbsp; 二、例子程序&nbsp;&nbsp;&nbsp; <br />&nbsp; 这是一个前辈写的，非常详细&nbsp;&nbsp;&nbsp; <br />&nbsp; //main.cpp&nbsp;&nbsp;&nbsp; <br />&nbsp; int&nbsp;&nbsp; a&nbsp;&nbsp; =&nbsp;&nbsp; 0;&nbsp;&nbsp; 全局初始化区&nbsp;&nbsp;&nbsp; <br />&nbsp; char&nbsp;&nbsp; *p1;&nbsp;&nbsp; 全局未初始化区&nbsp;&nbsp;&nbsp; <br />&nbsp; main()&nbsp;&nbsp;&nbsp; <br />&nbsp; {&nbsp;&nbsp;&nbsp; <br />&nbsp; int&nbsp;&nbsp; b;&nbsp;&nbsp; 栈&nbsp;&nbsp;&nbsp; <br />&nbsp; char&nbsp;&nbsp; s[]&nbsp;&nbsp; =&nbsp;&nbsp; "abc";&nbsp;&nbsp; 栈&nbsp;&nbsp;&nbsp; <br />&nbsp; char&nbsp;&nbsp; *p2;&nbsp;&nbsp; 栈&nbsp;&nbsp;&nbsp; <br />&nbsp; char&nbsp;&nbsp; *p3&nbsp;&nbsp; =&nbsp;&nbsp; "123456";&nbsp;&nbsp; 123456/0在常量区，p3在栈上。&nbsp;&nbsp;&nbsp; <br />&nbsp; static&nbsp;&nbsp; int&nbsp;&nbsp; c&nbsp;&nbsp; =0；&nbsp;&nbsp; 全局（静态）初始化区&nbsp;&nbsp;&nbsp; <br />&nbsp; p1&nbsp;&nbsp; =&nbsp;&nbsp; (char&nbsp;&nbsp; *)malloc(10);&nbsp;&nbsp;&nbsp; <br />&nbsp; p2&nbsp;&nbsp; =&nbsp;&nbsp; (char&nbsp;&nbsp; *)malloc(20);&nbsp;&nbsp;&nbsp; <br />&nbsp; 分配得来得10和20字节的区域就在堆区。&nbsp;&nbsp;&nbsp; <br />&nbsp; strcpy(p1,&nbsp;&nbsp; "123456");&nbsp;&nbsp; 123456/0放在常量区，编译器可能会将它与p3所指向的"123456"&nbsp; <br />&nbsp; 优化成一个地方。&nbsp;&nbsp;&nbsp; <br />&nbsp; }&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp; <br />&nbsp;&nbsp; <br />&nbsp; 二、<a href="http://www.gec-edu.org/index.php?action=newssearch&amp;keyword=堆和栈">堆和栈</a>的理论知识&nbsp;&nbsp;&nbsp; <br />&nbsp; 2.1申请方式&nbsp;&nbsp;&nbsp; <br />&nbsp; stack:&nbsp;&nbsp;&nbsp; <br />&nbsp; 由系统自动分配。&nbsp;&nbsp; 例如，声明在函数中一个局部变量&nbsp;&nbsp; int&nbsp;&nbsp; b;&nbsp;&nbsp; 系统自动在栈中为b开辟空&nbsp; <br />&nbsp; 间&nbsp;&nbsp;&nbsp; <br />&nbsp; heap:&nbsp;&nbsp;&nbsp; <br />&nbsp; 需要程序员自己申请，并指明大小，在c中malloc函数&nbsp;&nbsp;&nbsp; <br />&nbsp; 如p1&nbsp;&nbsp; =&nbsp;&nbsp; (char&nbsp;&nbsp; *)malloc(10);&nbsp;&nbsp;&nbsp; <br />&nbsp; 在C++中用new运算符&nbsp;&nbsp;&nbsp; <br />&nbsp; 如p2&nbsp;&nbsp; =&nbsp;&nbsp; new&nbsp;&nbsp; char[10];&nbsp;&nbsp;&nbsp; <br />&nbsp; 但是注意p1、p2本身是在栈中的。&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp; <br />&nbsp;&nbsp; <br />&nbsp; 2.2&nbsp;&nbsp;&nbsp; <br />&nbsp; 申请后系统的响应&nbsp;&nbsp;&nbsp; <br />&nbsp; 栈：只要栈的剩余空间大于所申请空间，系统将为程序提供内存，否则将报异常提示栈溢&nbsp; <br />&nbsp; 出。&nbsp;&nbsp;&nbsp; <br />&nbsp; 堆：首先应该知道操作系统有一个记录空闲内存地址的链表，当系统收到程序的申请时，&nbsp; <br />&nbsp; 会遍历该链表，寻找第一个空间大于所申请空间的堆结点，然后将该结点从空闲结点链表&nbsp; <br />&nbsp; 中删除，并将该结点的空间分配给程序，另外，对于大多数系统，会在这块内存空间中的&nbsp; <br />&nbsp; 首地址处记录本次分配的大小，这样，代码中的delete语句才能正确的释放本内存空间。&nbsp; <br />&nbsp; 另外，由于找到的堆结点的大小不一定正好等于申请的大小，系统会自动的将多余的那部&nbsp; <br />&nbsp; 分重新放入空闲链表中。&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp; <br />&nbsp; 2.3申请大小的限制&nbsp;&nbsp;&nbsp; <br />&nbsp; 栈：在Windows下,栈是向低地址扩展的数据结构，是一块连续的内存的区域。这句话的意&nbsp; <br />&nbsp; 思是栈顶的地址和栈的最大容量是系统预先规定好的，在WINDOWS下，栈的大小是2M（也有&nbsp; <br />&nbsp; 的说是1M，总之是一个编译时就确定的常数），如果申请的空间超过栈的剩余空间时，将&nbsp; <br />&nbsp; 提示overflow。因此，能从栈获得的空间较小。&nbsp;&nbsp;&nbsp; <br />&nbsp; 堆：堆是向高地址扩展的数据结构，是不连续的内存区域。这是由于系统是用链表来存储&nbsp; <br />&nbsp; 的空闲内存地址的，自然是不连续的，而链表的遍历方向是由低地址向高地址。堆的大小&nbsp; <br />&nbsp; 受限于计算机系统中有效的虚拟内存。由此可见，堆获得的空间比较灵活，也比较大。&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp; <br />&nbsp;&nbsp; <br />&nbsp;&nbsp; <br />&nbsp; 2.4申请效率的比较：&nbsp;&nbsp;&nbsp; <br />&nbsp; 栈由系统自动分配，速度较快。但程序员是无法控制的。&nbsp;&nbsp;&nbsp; <br />&nbsp; 堆是由new分配的内存，一般速度比较慢，而且容易产生内存碎片,不过用起来最方便.&nbsp;&nbsp;&nbsp; <br />&nbsp; 另外，在WINDOWS下，最好的方式是用VirtualAlloc分配内存，他不是在堆，也不是在栈是&nbsp; <br />&nbsp; 直接在进程的地址空间中保留一块内存，虽然用起来最不方便。但是速度快，也最灵活。&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp; <br />&nbsp; 2.5<a href="http://www.gec-edu.org/index.php?action=newssearch&amp;keyword=堆和栈">堆和栈</a>中的存储内容&nbsp;&nbsp;&nbsp; <br />&nbsp; 栈：&nbsp;&nbsp; 在函数调用时，第一个进栈的是主函数中后的下一条指令（函数调用语句的下一条可&nbsp; <br />&nbsp; 执行语句）的地址，然后是函数的各个参数，在大多数的C编译器中，参数是由右往左入栈&nbsp; <br />&nbsp; 的，然后是函数中的局部变量。注意静态变量是不入栈的。&nbsp;&nbsp;&nbsp; <br />&nbsp; 当本次函数调用结束后，局部变量先出栈，然后是参数，最后栈顶指针指向最开始存的地&nbsp; <br />&nbsp; 址，也就是主函数中的下一条指令，程序由该点继续运行。&nbsp;&nbsp;&nbsp; <br />&nbsp; 堆：一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp; <br />&nbsp; 2.6存取效率的比较&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp; <br />&nbsp; char&nbsp;&nbsp; s1[]&nbsp;&nbsp; =&nbsp;&nbsp; "aaaaaaaaaaaaaaa";&nbsp;&nbsp;&nbsp; <br />&nbsp; char&nbsp;&nbsp; *s2&nbsp;&nbsp; =&nbsp;&nbsp; "bbbbbbbbbbbbbbbbb";&nbsp;&nbsp;&nbsp; <br />&nbsp; aaaaaaaaaaa是在运行时刻赋值的；&nbsp;&nbsp;&nbsp; <br />&nbsp; 而bbbbbbbbbbb是在编译时就确定的；&nbsp;&nbsp;&nbsp; <br />&nbsp; 但是，在以后的存取中，在栈上的数组比指针所指向的字符串(例如堆)快。&nbsp;&nbsp;&nbsp; <br />&nbsp; 比如：&nbsp;&nbsp;&nbsp; <br />&nbsp; #include&nbsp;&nbsp;&nbsp; <br />&nbsp; void&nbsp;&nbsp; main()&nbsp;&nbsp;&nbsp; <br />&nbsp; {&nbsp;&nbsp;&nbsp; <br />&nbsp; char&nbsp;&nbsp; a&nbsp;&nbsp; =&nbsp;&nbsp; 1;&nbsp;&nbsp;&nbsp; <br />&nbsp; char&nbsp;&nbsp; c[]&nbsp;&nbsp; =&nbsp;&nbsp; "1234567890";&nbsp;&nbsp;&nbsp; <br />&nbsp; char&nbsp;&nbsp; *p&nbsp;&nbsp; ="1234567890";&nbsp;&nbsp;&nbsp; <br />&nbsp; a&nbsp;&nbsp; =&nbsp;&nbsp; c[1];&nbsp;&nbsp;&nbsp; <br />&nbsp; a&nbsp;&nbsp; =&nbsp;&nbsp; p[1];&nbsp;&nbsp;&nbsp; <br />&nbsp; return;&nbsp;&nbsp;&nbsp; <br />&nbsp; }&nbsp;&nbsp;&nbsp; <br />&nbsp; 对应的汇编代码&nbsp;&nbsp;&nbsp; <br />&nbsp; 10:&nbsp;&nbsp; a&nbsp;&nbsp; =&nbsp;&nbsp; c[1];&nbsp;&nbsp;&nbsp; <br />&nbsp; 00401067&nbsp;&nbsp; 8A&nbsp;&nbsp; 4D&nbsp;&nbsp; F1&nbsp;&nbsp; mov&nbsp;&nbsp; cl,byte&nbsp;&nbsp; ptr&nbsp;&nbsp; [ebp-0Fh]&nbsp;&nbsp;&nbsp; <br />&nbsp; 0040106A&nbsp;&nbsp; 88&nbsp;&nbsp; 4D&nbsp;&nbsp; FC&nbsp;&nbsp; mov&nbsp;&nbsp; byte&nbsp;&nbsp; ptr&nbsp;&nbsp; [ebp-4],cl&nbsp;&nbsp;&nbsp; <br />&nbsp; 11:&nbsp;&nbsp; a&nbsp;&nbsp; =&nbsp;&nbsp; p[1];&nbsp;&nbsp;&nbsp; <br />&nbsp; 0040106D&nbsp;&nbsp; 8B&nbsp;&nbsp; 55&nbsp;&nbsp; EC&nbsp;&nbsp; mov&nbsp;&nbsp; edx,dword&nbsp;&nbsp; ptr&nbsp;&nbsp; [ebp-14h]&nbsp;&nbsp;&nbsp; <br />&nbsp; 00401070&nbsp;&nbsp; 8A&nbsp;&nbsp; 42&nbsp;&nbsp; 01&nbsp;&nbsp; mov&nbsp;&nbsp; al,byte&nbsp;&nbsp; ptr&nbsp;&nbsp; [edx+1]&nbsp;&nbsp;&nbsp; <br />&nbsp; 00401073&nbsp;&nbsp; 88&nbsp;&nbsp; 45&nbsp;&nbsp; FC&nbsp;&nbsp; mov&nbsp;&nbsp; byte&nbsp;&nbsp; ptr&nbsp;&nbsp; [ebp-4],al&nbsp;&nbsp;&nbsp; <br />&nbsp; 第一种在读取时直接就把字符串中的元素读到寄存器cl中，而第二种则要先把指针值读到&nbsp; <br />&nbsp; edx中，再根据edx读取字符，显然慢了。&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp; <br />&nbsp;&nbsp; <br />&nbsp; 2.7小结：&nbsp;&nbsp;&nbsp; <br />&nbsp; <a href="http://www.gec-edu.org/index.php?action=newssearch&amp;keyword=堆和栈">堆和栈</a>的区别可以用如下的比喻来看出：&nbsp;&nbsp;&nbsp; <br />&nbsp; 使用栈就象我们去饭馆里吃饭，只管点菜（发出申请）、付钱、和吃（使用），吃饱了就&nbsp; <br />&nbsp; 走，不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作，他的好处是快捷，但是自&nbsp; <br />&nbsp; 由度小。&nbsp;&nbsp;&nbsp; <br />&nbsp; 使用堆就象是自己动手做喜欢吃的菜肴，比较麻烦，但是比较符合自己的口味，而且自由&nbsp; <br />&nbsp; 度大。</font><img src ="http://www.cppblog.com/880221zxj/aggbug/178138.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/880221zxj/" target="_blank">无一</a> 2012-06-09 01:00 <a href="http://www.cppblog.com/880221zxj/archive/2012/06/09/178138.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>