﻿<?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++博客-geforceX的编程小苑-随笔分类-VC/MFC</title><link>http://www.cppblog.com/geforcex/category/421.html</link><description /><language>zh-cn</language><lastBuildDate>Sun, 27 Jul 2008 20:29:30 GMT</lastBuildDate><pubDate>Sun, 27 Jul 2008 20:29:30 GMT</pubDate><ttl>60</ttl><item><title>讲讲volatile的作用(转)</title><link>http://www.cppblog.com/geforcex/archive/2008/07/27/57316.html</link><dc:creator>geforceX</dc:creator><author>geforceX</author><pubDate>Sun, 27 Jul 2008 13:56:00 GMT</pubDate><guid>http://www.cppblog.com/geforcex/archive/2008/07/27/57316.html</guid><wfw:comment>http://www.cppblog.com/geforcex/comments/57316.html</wfw:comment><comments>http://www.cppblog.com/geforcex/archive/2008/07/27/57316.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/geforcex/comments/commentRss/57316.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/geforcex/services/trackbacks/57316.html</trackback:ping><description><![CDATA[一个定义为volatile的变量是说这变量可能会被意想不到地改变，这样，编译器就不会去假设这个变量的值了。精确地说就是，优化器在用到这个变量时必须每次都小心地重新读取这个变量的值，而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子： <br>&nbsp;&nbsp;&nbsp;&nbsp;1). 并行设备的硬件寄存器（如：状态寄存器） <br>&nbsp;&nbsp;&nbsp;&nbsp;2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) <br>&nbsp;&nbsp;&nbsp;&nbsp;3). 多线程应用中被几个任务共享的变量 <br>&nbsp;&nbsp;&nbsp;&nbsp;回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道，所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。 <br>&nbsp;&nbsp;&nbsp;&nbsp;假设被面试者正确地回答了这是问题（嗯，怀疑这否会是这样），我将稍微深究一下，看一下这家伙是不是直正懂得volatile完全的重要性。 <br>&nbsp;&nbsp;&nbsp;&nbsp;1). 一个参数既可以是const还可以是volatile吗？解释为什么。 <br>&nbsp;&nbsp;&nbsp;&nbsp;2). 一个指针可以是volatile 吗？解释为什么。 <br>&nbsp;&nbsp;&nbsp;&nbsp;3). 下面的函数有什么错误： <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int square(volatile int *ptr) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return *ptr * *ptr; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br>&nbsp;&nbsp;&nbsp;&nbsp;下面是答案： <br>&nbsp;&nbsp;&nbsp;&nbsp;1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。 <br>&nbsp;&nbsp;&nbsp;&nbsp;2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。 <br>&nbsp;&nbsp;&nbsp;&nbsp;3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方，但是，由于*ptr指向一个volatile型参数，编译器将产生类似下面的代码： <br>&nbsp;&nbsp;&nbsp;&nbsp;int square(volatile int *ptr)&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int a,b; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a = *ptr; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b = *ptr; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return a * b; <br>&nbsp;&nbsp;&nbsp;&nbsp; } <br>&nbsp;&nbsp;&nbsp;&nbsp;由于*ptr的值可能被意想不到地该变，因此a和b可能是不同的。结果，这段代码可能返不是你所期望的平方值！正确的代码如下： <br>&nbsp;&nbsp;&nbsp;&nbsp; long square(volatile int *ptr)&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp; { <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int a; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a = *ptr; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return a * a; <br>&nbsp;&nbsp;&nbsp;&nbsp; } <br><br>讲讲我的理解： （欢迎打板子...~~！） <br><br>关键在于两个地方：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;<br>1. 编译器的优化&nbsp;&nbsp;(请高手帮我看看下面的理解) <br><br>在本次线程内, 当读取一个变量时，为提高存取速度，编译器优化时有时会先把变量读取到一个寄存器中；以后，再取变量值时，就直接从寄存器中取值； <br><br>当变量值在本线程里改变时，会同时把变量的新值copy到该寄存器中，以便保持一致 <br><br>当变量在因别的线程等而改变了值，该寄存器的值不会相应改变，从而造成应用程序读取的值和实际的变量值不一致 <br><br>当该寄存器在因别的线程等而改变了值，原变量的值不会改变，从而造成应用程序读取的值和实际的变量值不一致&nbsp;&nbsp;<br><br><br>举一个不太准确的例子：&nbsp;&nbsp;<br><br>发薪资时，会计每次都把员工叫来登记他们的银行卡号；一次会计为了省事，没有即时登记，用了以前登记的银行卡号；刚好一个员工的银行卡丢了，已挂失该银行卡号；从而造成该员工领不到工资&nbsp;&nbsp;<br><br>员工 －－ 原始变量地址&nbsp;&nbsp;<br>银行卡号 －－ 原始变量在寄存器的备份&nbsp;&nbsp;<br><br><br>2. 在什么情况下会出现(如1楼所说) <br><br>&nbsp;&nbsp;&nbsp;&nbsp;1). 并行设备的硬件寄存器（如：状态寄存器）&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;3). 多线程应用中被几个任务共享的变量&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp; <br><br>补充： volatile应该解释为&#8220;直接存取原始内存地址&#8221;比较合适，&#8220;易变的&#8221;这种解释简直有点误导人；&nbsp;&nbsp;<br><br>&#8220;易变&#8221;是因为外在因素引起的，象多线程，中断等，并不是因为用volatile修饰了的变量就是&#8220;易变&#8221;了，假如没有外因，即使用volatile定义，它也不会变化； <br><br>而用volatile定义之后，其实这个变量就不会因外因而变化了，可以放心使用了； 大家看看前面那种解释（易变的）是不是在误导人 <br><br><br>－－－－－－－－－－－－简明示例如下：－－－－－－－－－－－－－－－－－<wbr>－ <br><br>volatile关键字是一种类型修饰符，用它声明的类型变量表示可以被某些编译器未知的因素更改，比如：操作系统、硬件或者其它线程等。遇到这个关键字声明的变量，编译器对访问该变量的代码就不再进行优化，从而可以提供对特殊地址的稳定访问。 <br>使用该关键字的例子如下： <br>int volatile nVint; <br>&gt;&gt;&gt;&gt;当要求使用volatile 声明的变量的值的时候，系统总是重新从它所在的内存读取数据，即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。 <br>例如： <br>volatile int i=10; <br>int a = i; <br>... <br>//其他代码，并未明确告诉编译器，对i进行过操作 <br>int b = i; <br>&gt;&gt;&gt;&gt;volatile 指出 i是随时可能发生变化的，每次使用它的时候必须从i的地址中读取，因而编译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是，由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作，它会自动把上次读的数据放在b中。而不是重新从i里面读。这样以来，如果i是一个寄存器变量或者表示一个端口数据就容易出错，所以说volatile可以保证对特殊地址的稳定访问。 <br>&gt;&gt;&gt;&gt;注意，在vc6中，一般调试模式没有进行代码优化，所以这个关键字的作用看不出来。下面通过插入汇编代码，测试有无volatile关键字，对程序最终代码的影响： <br>&gt;&gt;&gt;&gt;首先，用classwizard建一个win32 console工程，插入一个voltest.cpp文件，输入下面的代码： <br>&gt;&gt; <br>＃i nclude &lt;stdio.h&gt; <br>void main() <br>{ <br>int i=10; <br>int a = i; <br>printf("i= %d",a); <br>//下面汇编语句的作用就是改变内存中i的值，但是又不让编译器知道 <br>__asm { <br>mov dword ptr [ebp-4], 20h <br>} <br>int b = i; <br>printf("i= %d",b); <br>}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>然后，在调试版本模式运行程序，输出结果如下： <br>i = 10 <br>i = 32 <br>然后，在release版本模式运行程序，输出结果如下： <br>i = 10 <br>i = 10 <br>输出的结果明显表明，release模式下，编译器对代码进行了优化，第二次没有输出正确的i值。下面，我们把 i的声明加上volatile关键字，看看有什么变化： <br>＃i nclude &lt;stdio.h&gt; <br>void main() <br>{ <br>volatile int i=10; <br>int a = i; <br>printf("i= %d",a); <br>__asm { <br>mov dword ptr [ebp-4], 20h <br>} <br>int b = i; <br>printf("i= %d",b); <br>}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>分别在调试版本和release版本运行程序，输出都是： <br>i = 10 <br>i = 32 <br>这说明这个关键字发挥了它的作用！ <br><br>－－－－－－－－－－－－－－－－－<wbr>－－－－－－－－－－－－－－－－－－<wbr>－ <br><br><br>volatile对应的变量可能在你的程序本身不知道的情况下发生改变 <br>比如多线程的程序，共同访问的内存当中，多个程序都可以操纵这个变量 <br>你自己的程序，是无法判定合适这个变量会发生变化 <br>还比如，他和一个外部设备的某个状态对应，当外部设备发生操作的时候，通过驱动程序和中断事件，系统改变了这个变量的数值，而你的程序并不知道。 <br>对于volatile类型的变量，系统每次用到他的时候都是直接从对应的内存当中提取，而不会利用cache当中的原有数值，以适应它的未知何时会发生的变化，系统对这种变量的处理不会做优化——显然也是因为它的数值随时都可能变化的情况。 <br><br>-------------------------------------------------------------------------------- <br><br>典型的例子 <br>for ( int i=0; i&lt;100000; i++); <br>这个语句用来测试空循环的速度的 <br>但是编译器肯定要把它优化掉，根本就不执行 <br>如果你写成&nbsp;&nbsp;<br>for ( volatile int i=0; i&lt;100000; i++); <br>它就会执行了 <br><br>volatile的本意是&#8220;易变的&#8221;&nbsp;&nbsp;<br>由于访问寄存器的速度要快过RAM，所以编译器一般都会作减少存取外部RAM的优化。比如： <br><br>static int i=0; <br><br>int main(void) <br>{ <br>... <br>while (1) <br>{ <br>if (i) dosomething(); <br>} <br>} <br><br>/* Interrupt service routine. */ <br>void ISR_2(void) <br>{ <br>i=1; <br>} <br><br>程序的本意是希望ISR_2中断产生时，在main当中调用dosomething函数，但是，由于编译器判断在main函数里面没有修改过i，因此 <br>可能只执行一次对从i到某寄存器的读操作，然后每次if判断都只使用这个寄存器里面的&#8220;i副本&#8221;，导致dosomething永远也不会被 <br>调用。如果将将变量加上volatile修饰，则编译器保证对此变量的读写操作都不会被优化（肯定执行）。此例中i也应该如此说明。 <br><br>一般说来，volatile用在如下的几个地方： <br><br>1、中断服务程序中修改的供其它程序检测的变量需要加volatile； <br><br>2、多任务环境下各任务间共享的标志应该加volatile； <br><br>3、存储器映射的硬件寄存器通常也要加volatile说明，因为每次对它的读写都可能由不同意义； <br><br>另外，以上这几种情况经常还要同时考虑数据的完整性（相互关联的几个标志读了一半被打断了重写），在1中可以通过关中断来实 <br>现，2中可以禁止任务调度，3中则只能依靠硬件的良好设计了。
<img src ="http://www.cppblog.com/geforcex/aggbug/57316.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/geforcex/" target="_blank">geforceX</a> 2008-07-27 21:56 <a href="http://www.cppblog.com/geforcex/archive/2008/07/27/57316.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SetWindowPos</title><link>http://www.cppblog.com/geforcex/archive/2006/03/01/3605.html</link><dc:creator>geforceX</dc:creator><author>geforceX</author><pubDate>Wed, 01 Mar 2006 09:30:00 GMT</pubDate><guid>http://www.cppblog.com/geforcex/archive/2006/03/01/3605.html</guid><wfw:comment>http://www.cppblog.com/geforcex/comments/3605.html</wfw:comment><comments>http://www.cppblog.com/geforcex/archive/2006/03/01/3605.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/geforcex/comments/commentRss/3605.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/geforcex/services/trackbacks/3605.html</trackback:ping><description><![CDATA[昨天写了MoveWindow函数，今天又要写SetWindowPos函数，因为MoveWindow确实不好，浪费了差不多一天时间。。。对于主窗口，选择了Center属性就可以移动位置，不选就不行；窗口资源过大也不能移动；改变后窗口的尺寸大于等于屏幕尺寸的话，在它上面DoModal出来的新窗口不能移动。。原来，使用MoveWindow移动对话框位置似乎有很苛刻的条件，一不小心就原地不动了，而且我也实在琢磨不透这样的条件，网上也没有查处来。今天用了SetWindowPos后，才发现，果然好用！<BR><BR>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">BOOL&nbsp;SetWindowPos(<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">const</SPAN><SPAN style="COLOR: #000000">&nbsp;CWnd</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">&nbsp;pWndInsertAfter,<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;x,<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;y,<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;cx,<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;cy,<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;UINT&nbsp;nFlags&nbsp;<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top>);</SPAN></DIV>
<H4 class=dtH4>Parameters</H4>
<DL>
<DT><I>pWndInsertAfter</I> 
<DD>Identifies the <B>CWnd</B> object that will precede this <B>CWnd</B> object in the Z-order. This parameter can be a pointer to a <B>CWnd</B> or a <B>Pointer</B> to one of the following values: 
<UL type=disc>
<LI><B>wndBottom</B>&nbsp;&nbsp;&nbsp;Places the window at the bottom of the Z-order. If this <B>CWnd</B> is a topmost window, the window loses its topmost status; the system places the window at the bottom of all other windows. 
<LI><B>wndTop</B>&nbsp;&nbsp;&nbsp;Places the window at the top of the Z-order. 
<LI><B>wndTopMost</B>&nbsp;&nbsp;&nbsp;Places the window above all nontopmost windows. The window maintains its topmost position even when it is deactivated. 
<LI><B>wndNoTopMost</B>&nbsp;&nbsp;&nbsp;Repositions the window to the top of all nontopmost windows (that is, behind all topmost windows). This flag has no effect if the window is already a nontopmost window. </LI></UL></DD></DL>
<DT><I>nFlags</I> 
<DD>Specifies sizing and positioning options. This parameter can be a combination of the following: 常用的是<STRONG>SWP_SHOWWINDOW<BR><BR></STRONG>注意：<BR>&nbsp;&nbsp;&nbsp; 这里的坐标参数用的是Client坐标，对于子窗口用的是其父窗口的坐标系。然而对于用DoModal()弹出的窗口，如果在资源属性里没有选择Child属性的话，它的父窗口是DeskTop，而不是调用DoModal()的窗口。<BR><BR></DD><img src ="http://www.cppblog.com/geforcex/aggbug/3605.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/geforcex/" target="_blank">geforceX</a> 2006-03-01 17:30 <a href="http://www.cppblog.com/geforcex/archive/2006/03/01/3605.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MoveWindow</title><link>http://www.cppblog.com/geforcex/archive/2006/02/28/3574.html</link><dc:creator>geforceX</dc:creator><author>geforceX</author><pubDate>Tue, 28 Feb 2006 07:44:00 GMT</pubDate><guid>http://www.cppblog.com/geforcex/archive/2006/02/28/3574.html</guid><wfw:comment>http://www.cppblog.com/geforcex/comments/3574.html</wfw:comment><comments>http://www.cppblog.com/geforcex/archive/2006/02/28/3574.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/geforcex/comments/commentRss/3574.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/geforcex/services/trackbacks/3574.html</trackback:ping><description><![CDATA[<P>刚做的那个软件界面很重要，就象是把自己做的一个个控件网上画一样，还要按照实际运行效果来不断调整位置，很麻烦。当时使用MoveWindow()这个函数来控制对话框的大小和位置，不了解参数情况，在网上查了，记得好象放在这里备忘，那时还觉得blog真是方便。结果现在又要用起这个函数却又找不到了！不知道是不是放在这个blog里了。看来blog多了还不方便了。不过不要误会，那些都是以前找到这个blog之前暂时用的，都不太满意。最后觉得还是这里好，hoho，方便。晕，我来写这篇日志是干吗的？这么扯到这么远了。。。不说了，还是把MoveWindow()再贴一下吧。。</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">BOOL&nbsp;MoveWindow<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top>(&nbsp;&nbsp;&nbsp;HWND&nbsp;hWnd,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">Handle&nbsp;to&nbsp;the&nbsp;window</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;X,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">Specifies&nbsp;the&nbsp;new&nbsp;position&nbsp;of&nbsp;the&nbsp;left&nbsp;side&nbsp;of&nbsp;the&nbsp;window.</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;Y,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">Specifies&nbsp;the&nbsp;new&nbsp;position&nbsp;of&nbsp;the&nbsp;top&nbsp;of&nbsp;the&nbsp;window.</SPAN><SPAN style="COLOR: #008000"><BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;nWidth,<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;nHeight,<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;BOOL&nbsp;bRepaint<BR><IMG src="http://www.cppblog.com/images/OutliningIndicators/None.gif" align=top>);</SPAN></DIV><BR>这个是 API函数，如果在MFC中使用CWnd::MoveWindow则不需要第一个参数句柄hWnd，其他相同。<img src ="http://www.cppblog.com/geforcex/aggbug/3574.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/geforcex/" target="_blank">geforceX</a> 2006-02-28 15:44 <a href="http://www.cppblog.com/geforcex/archive/2006/02/28/3574.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对《Visual C++中为普通程序添加ODBC应用》的学习和认识</title><link>http://www.cppblog.com/geforcex/archive/2005/11/24/1292.html</link><dc:creator>geforceX</dc:creator><author>geforceX</author><pubDate>Thu, 24 Nov 2005 08:47:00 GMT</pubDate><guid>http://www.cppblog.com/geforcex/archive/2005/11/24/1292.html</guid><wfw:comment>http://www.cppblog.com/geforcex/comments/1292.html</wfw:comment><comments>http://www.cppblog.com/geforcex/archive/2005/11/24/1292.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/geforcex/comments/commentRss/1292.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/geforcex/services/trackbacks/1292.html</trackback:ping><description><![CDATA[从来没有独立做过ODBC数据库的程序，今天才发现原来自己动起手来是那么得蹒跚，呵呵。看了《<A id=CategoryEntryList1_EntryStoryList_Entries__ctl0_TitleUrl href="/geforcex/articles/1288.html"><FONT color=#223355>Visual C++中为普通程序添加ODBC应用</FONT></A>》后收获不小，现把这些记录下来，以便日后再忘记的话可以查阅^_^#<BR><BR>1。给程序加入ODBC数据库的支持需要用到两个类：CDatabase和CRecordset，主要是后面一个；<BR>2。一般步骤为：<BR>（1）&nbsp;创建一个继承于CRecordset的类CMyRS，系统会自动提示你选择数据源，并会自动关联数据表中各项属性<BR>（2）在需要查询数据库的地方先construct一个CMyRS类的实例myRS，然后调用myRS.Open()打开记录集<BR>（3）移动数据集指针到需要的地方，从CMyRS中系统自动关联好的数据表各项属性的变量中读取相应的值<BR>3。需要注意的是：<BR>（1）调用myRS.Open()前<FONT color=#ff0000>一定要先construct CMyRS类的对象</FONT>，构造的时候可以事先创建一个CDatabase类的对象，然后将该对象的指针传给构CMyRS的造函数，如：CMyRs myRS(&amp;db); 如果为空的话，当调用myRS.Open()时，系统会自动为myRS构造一个CDatabase的对象，并且调用CMyRS类的Default SQL 和CONNECT字符串来连接数据源。所以不用担心没有连接数据库数据源。<BR>（2）如果事先创建了一个CDatabase的对象db，则可以先用自己的conn连接字和sql连接字Open它，然后传给CMyRS的构造函数，构造的myRS再不用任何参数Open()就可以了<BR><BR>可能有些地方理解的还是不对，希望随着以后多接触再来修改！<img src ="http://www.cppblog.com/geforcex/aggbug/1292.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/geforcex/" target="_blank">geforceX</a> 2005-11-24 16:47 <a href="http://www.cppblog.com/geforcex/archive/2005/11/24/1292.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>