走进windows编程的世界-----windows线程

一 线程局部存储 Thread Local Storage

1 由于多个线程使用同一个变量,各个线程
    都对变量进行操作,那么变量的值会被不同
    线程操作覆盖。
         
      通常   变量A   <-- 线程A
                     <-- 线程B
                 
      TLS    变量A   <-- 线程A
             变量A   <-- 线程B
             
   2 TLS的使用
     2.1 使用关键字 __declspec(thread) 
        __declspec(thread) CHAR * g_pszText2 = NULL;
     2.2 TLS相关API
       2.2.1 创建TLS索引
         DWORD TlsAlloc(VOID)
         返回一个TLS索引号
       2.2.2 设置值

         BOOL TlsSetValue(
         DWORD dwTlsIndex, //TLS索引
         LPVOID lpTlsValue //保存的值
         );

2.2.3 获取值

         LPVOID TlsGetValue(
          DWORD dwTlsIndex  //TLS索引
         );

返回存放在索引内的值
       2.2.4 释放

         BOOL TlsFree(
          DWORD dwTlsIndex   //TLS索引
         );
/*File : ThreadTls.cpp
 *Auth : sjin
 *Date :  20140726
 *Mail :  [email protected]
 */

#include "stdafx.h"
#include "stdlib.h"
#include "windows.h"

CHAR * g_pszText   = NULL;
DWORD  g_nTlsIndex = 0;

void Print(CHAR * pszText )
{
	printf("\n===== %s ======\n",pszText);
    printf( "g_pszText: %s\n", g_pszText );
    //从TLS索引中获取值
    CHAR * pszText1 = (CHAR *)TlsGetValue( g_nTlsIndex );
	strcpy( g_pszText, pszText1 );
    printf( "TLS: %s\n", pszText1 );
	printf("=================\n\n");
}

DWORD WINAPI PrintProc( LPVOID pParam )
{
    CHAR * pszText = (CHAR *)pParam;
    g_pszText = (CHAR *)malloc( 100 );
    strcpy( g_pszText, pszText );
    //将值保存到TLS索引当中
    TlsSetValue( g_nTlsIndex, g_pszText );

    while( 1 )
    {
        Print(pszText );
        Sleep( 1000 );
    }
    return 0;
}

void Create( )
{
    HANDLE hThread_1   = NULL;
    DWORD  nThreadID_1 = 0;
	HANDLE hThread_2   = NULL;
    DWORD  nThreadID_2 = 0;

    CHAR szText1[] = "ThreadProc 1----------";
    hThread_1 = CreateThread( NULL, 0,PrintProc, szText1, 0, &nThreadID_1 );

	Sleep(1000); // 让线程1 2 打印错开。
    CHAR szText2[] = "-----ThreadProc 2-----";
    hThread_2 = CreateThread( NULL, 0,PrintProc, szText2, 0, &nThreadID_2 );
	Sleep(5000);
	//退出线程
	TerminateThread(hThread_1,0);
	TerminateThread(hThread_2,0);

    WaitForSingleObject( hThread_1, INFINITE );
	printf("Create exit thread_id : %d \n",nThreadID_1);
	WaitForSingleObject( hThread_2, INFINITE );
	printf("Create exit thread_id : %d \n",nThreadID_2);
}

int _tmain(int argc, _TCHAR* argv[])
{
	//创建TLS索引号
    g_nTlsIndex = TlsAlloc( );
    //创建线程
    Create( );
    //释放索引
    TlsFree( g_nTlsIndex );
	return 0;
}

二 线程同步

1 多线程的问题
    
    A停止 -> B开始 -〉B停止 -> A开始
    
     当线程停止会保存寄存器的状态。
     当线程开始会恢复寄存器的状态。
     
    AB线程都使用printf的问题:
    A线程调用printf时,printf正在输出
    当中,A挂起,B执行,B线程也调用printf输出B的数据,画面会出现A的数据输出1部分,然后是B的数据;
    B挂起,A执行, A继续输出自己的数据.
    所以,由于多线程的切换,产生数据混乱.
     
  2 问题的解决 - 同步机制
    2.1 原子锁
    2.2 临界区
    2.3 事件
    2.4 互斥
    2.5 信号量
    2.6 可等候定时器
    
  3 等候多个内核对象事件

    DWORD WaitForMultipleObjects(
     DWORD nCount,//句柄的数量
     CONST HANDLE *lpHandles,//句柄数组
     BOOL fWaitAll, //等候方式
    DWORD dwMilliseconds );//等候时间

等候方式fWaitAll:
       TRUE - 每个句柄都有事件,解除阻塞
       FALSE - 其中一个句柄有事件,解除阻塞

三 原子锁
  
  1 g_nValue++执行
    线程A通过寄存器完成加法运算,假设g_nValue正在加到10000时,线程切换到B,A的寄存器中保存10000数字,B从10000开始加数据,当B加到15000时,线程切换到A,A恢复寄存器的值,A会继续从10000开始累加,就将B完成5000的加法覆盖.
    
  2 原子锁
    执行单个指令时,锁定操作,不允许其他线程访问.
    
  3 用法
    InterlockedIncrement ++运算
    InterlockedDecrement --运算
    InterlockedCompareExchange ?运算

/* File :InterLock.cpp
 * Auth : sjin
 * Date : 20140727
 * Mail : [email protected]
 */

#include "stdafx.h"
#include "windows.h"

LONG g_nValue1 = 0;
LONG g_nValue2 = 0;

DWORD WINAPI InterProc1( LPVOID pParam )
{
    for( int nIndex=0; nIndex<10000000; nIndex++ ){    //普通++
        g_nValue1++;
    }

    return 0;
}
DWORD WINAPI InterProc2( LPVOID pParam )
{
    for( int nIndex=0; nIndex<10000000; nIndex++ ){    //原子锁++(lock)
        InterlockedIncrement( &g_nValue2 );
    }

    return 0;
}

void Create( )
{
    DWORD  nThreadID  = 0;
    HANDLE hThread[4] = { NULL };

    hThread[0] = CreateThread( NULL, 0, InterProc1, NULL, 0, &nThreadID );

    hThread[1] = CreateThread( NULL, 0, InterProc1, NULL, 0, &nThreadID );

    hThread[2] = CreateThread( NULL, 0, InterProc2, NULL, 0, &nThreadID );

    hThread[3] = CreateThread( NULL, 0, InterProc2, NULL, 0, &nThreadID );

    WaitForMultipleObjects( 4, hThread, TRUE, INFINITE );

    printf( "Value1=%d  Value2=%d\n", g_nValue1, g_nValue2 );
}

int _tmain(int argc, _TCHAR* argv[])
{
	Create( );
	return 0;
}

四 临界区
  
  1 临界区作用
    线程在执行代码时,将代码锁定,不允许其他线程执行,只有该线程离开后,其他线程才能使用这些代码
    
  2 临界区的使用
    2.1 初始化临界区

       VOID InitializeCriticalSection(
       LPCRITICAL_SECTION lpCriticalSection //临界区结构地址
       );

2.2 临界区加锁

       VOID EnterCriticalSection(
              LPCRITICAL_SECTION lpCriticalSection   // pointer to critical
          //临界区
            );

2.3 临界区解锁

       VOID LeaveCriticalSection(
       LPCRITICAL_SECTION lpCriticalSection
          // 临界区
       );

2.4 释放临界区

       VOID DeleteCriticalSection(
       LPCRITICAL_SECTION lpCriticalSection
               //临界区
       );

3 和原子锁相比
    原子锁是一条语句
    临界区可以完成多条语句的锁定.

/* File :CriticalSection.cpp
 * Auth : sjin
 * Date : 20140727
 * Mail : [email protected]
 */

#include "stdafx.h"
#include "conio.h"
#include "windows.h"

CRITICAL_SECTION g_cs = { 0 };
LONG nValue = 0;

void Print( )
{    //进入临界区 - 加锁
    EnterCriticalSection( &g_cs );

    nValue++;
    printf( "Long long long.......%d \n", nValue );

    //离开临界区 - 解锁
    LeaveCriticalSection( &g_cs );
}

DWORD WINAPI PrintProc( LPVOID pParam )
{
    while( 1 ){
        Print( );
        Sleep( 100 );
    }
    return 0;
}

void Create( )
{
    DWORD nThreadID = 0;
    HANDLE hThread[2] = { 0 };

    hThread[0] = CreateThread( NULL, 0, PrintProc, NULL, 0, &nThreadID );
    hThread[1] = CreateThread( NULL, 0, PrintProc, NULL, 0, &nThreadID );

    getch( );
	TerminateThread(hThread[0],1);
	TerminateThread(hThread[1],2);

	//等待线程退出
	WaitForMultipleObjects(2,hThread,TRUE,INFINITE);
	printf("thread exit....");
}

int main(int argc, char* argv[])
{    //初始化临界区
    InitializeCriticalSection( &g_cs );
    Create( );
    //删除临界区
    DeleteCriticalSection( &g_cs );
    return 0;
} 

五 事件

1 事件
    通知的作用,当收到事件时,线程可以执行. 否则,线程将等候事件发生.
    
  2 事件的用法
    2.1 创建事件

            HANDLE CreateEvent(
       LPSECURITY_ATTRIBUTES lpEventAttributes,//安全属性
       BOOL bManualReset,//重置方式
       BOOL bInitialState, //初始化状态
       LPCTSTR lpName //名称
              );

返回创建好的事件句柄
    bManualReset - 事件重置方式, TRUE手动和FALSE自动重置. 如果为FALSE,系统在等候到事件后,会自动将事件重置为无信号状态. 如果为TRUE,我们必须自己使用ResetEvent重置状态.
      bInitialState - 初始化状态, TRUE为有信号,FALSE无信号.
   2.2 等候事件
      WaitForSingleObject/
      WaitForMultipleObjects
    2.3 触发事件

      BOOL SetEvent(
      HANDLE hEvent //事件句柄
      );

2.4 关闭事件
      CloseHandle
    2.5 重置事件

      BOOL ResetEvent(
       HANDLE hEvent //事件句柄
      );

2.6 其他函数
      OpenEvent
      PulseEvent

/* File :Event.cpp
 * Auth : sjin
 * Date : 20140727
 * Mail : [email protected]
 */

#include "stdafx.h"
#include "conio.h"
#include "windows.h"

HANDLE g_hEvent = NULL;
HANDLE g_hEvent2= NULL;

DWORD WINAPI ThreadSend( LPVOID pParam )
{
    while( 1 )
    {    //触发事件
        SetEvent( g_hEvent );
        Sleep( 500 );
        SetEvent( g_hEvent2 );
        Sleep( 500 );
    }
    return 0;
}
DWORD WINAPI ThreadRecv( LPVOID pParam )
{
    while( 1 )
    {    //等候事件通知
        WaitForSingleObject( g_hEvent, INFINITE );
        printf( "Hello Event: %p\n", g_hEvent );
    }
    return 0;
}

DWORD WINAPI ThreadRecv2( LPVOID pParam )
{
    while( 1 )
    {    //等候事件通知
        WaitForSingleObject( g_hEvent2, INFINITE );
        printf( "Hello Event2: %p\n", g_hEvent2 );

		//g_hEvent2 设置为手动重置,如果没有这个函数,将无限制的执行这个操作。
        ResetEvent( g_hEvent2 );
    }
    return 0;
}

void Create( )
{
    DWORD  nThreadID  = 0;
    HANDLE hThread[3] = { NULL };
    hThread[0] = CreateThread( NULL, 0,ThreadSend, NULL, 0, &nThreadID );

    hThread[1] = CreateThread( NULL, 0,ThreadRecv, NULL, 0, &nThreadID );

    hThread[2] = CreateThread( NULL, 0,ThreadRecv2, NULL, 0, &nThreadID );

	getch( );
	TerminateThread(hThread[0],1);
	TerminateThread(hThread[1],2);
	TerminateThread(hThread[2],2);

	//等待线程退出
	WaitForMultipleObjects(3,hThread,TRUE,INFINITE);
	printf("thread exit....");
}

int main(int argc, char* argv[])
{
    //创建自动重置事件
    g_hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
    //创建手动重置事件
    g_hEvent2 = CreateEvent( NULL, TRUE, FALSE, NULL );

    Create( );

    getch( );

    //关闭事件
    CloseHandle( g_hEvent );
	CloseHandle( g_hEvent2 );
    return 0;
}

互斥量

1 互斥量
    多个线程同时只能有一个执行.
    
  2 互斥量使用
    2.1 创建互斥

      HANDLE CreateMutex(
        LPSECURITY_ATTRIBUTES lpMutexAttributes,//安全属性
        BOOL bInitialOwner,  //初始化的拥有线程
              LPCTSTR lpName ); //名称

bInitialOwner - TRUE表示当前创建互斥
    量的线程拥有互斥, FALSE为不拥有.
    2.2 等候互斥
       WaitForSingleObject
       WaitForMultipleObjects
    2.3 重置互斥
       ReleaseMutex 
    2.4 关闭互斥
       CloseHandle
    2.5 使用互斥线程,按照谁先等候谁先拥有互斥量的规则顺序执行.
    2.6 其他函数
      OpenMutex 打开互斥

/* File :Mutex.cpp
 * Auth : sjin
 * DAte : 20140727
 * Mail : [email protected]
 */

#include "stdafx.h"
#include "conio.h"
#include "windows.h"

HANDLE g_hMutex = NULL;

DWORD WINAPI ThreadProc1( LPVOID pParam )
{
    while( 1 )
    {   //等候互斥量
        WaitForSingleObject( g_hMutex, INFINITE );
        printf( "ThreadProc1----------\n");
        Sleep( 500 );
        //释放互斥量
        ReleaseMutex( g_hMutex );
    }
    return 0;
}

DWORD WINAPI ThreadProc2( LPVOID pParam )
{
    while( 1 )
    {    //等候互斥量
        WaitForSingleObject( g_hMutex, INFINITE );
        printf( "------ThreadProc2------\n");
        Sleep( 500 );
        //释放互斥量
        ReleaseMutex( g_hMutex );
    }
    return 0;
}

DWORD WINAPI ThreadProc3( LPVOID pParam )
{
    while( 1 )
    {    //等候互斥量
        WaitForSingleObject( g_hMutex, INFINITE );
        printf( "------------ThreadProc3\n");
        Sleep( 500 );
        //释放互斥量
        ReleaseMutex( g_hMutex );
    }
    return 0;
}

void Create( )
{
    DWORD  nThreadID  = 0;
    HANDLE hThread[3] = { NULL };
    hThread[0] = CreateThread( NULL, 0, ThreadProc1, NULL, 0, &nThreadID );
    hThread[1] = CreateThread( NULL, 0, ThreadProc2, NULL, 0, &nThreadID );
    hThread[2] = CreateThread( NULL, 0,  ThreadProc3, NULL, 0, &nThreadID );

	getch( );
	TerminateThread(hThread[0],1);
	TerminateThread(hThread[1],2);
	TerminateThread(hThread[2],2);

	//等待线程退出
	WaitForMultipleObjects(3,hThread,TRUE,INFINITE);
	printf("thread exit....");
}

int main(int argc, char* argv[])
{    //创建互斥量
    g_hMutex = CreateMutex( NULL,FALSE, NULL ); //FALSE表示当前创建互斥量的线程(main)不拥有互斥量

    Create( );

    getch( );
    //关闭
    CloseHandle( g_hMutex );

    return 0;
}

七 信号量
   
  1 信号量
    通知的作用,和事件类似.但是与事件不同.
    事件只维护一个值0或者1.
    信号量维护一个变量,0时无信号,大于0有信号.
    
  2 信号量的使用
    2.1 创建信号量

        HANDLE CreateSemaphore(
       LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,//安全属性
       LONG lInitialCount,//初始信号量
       LONG lMaximumCount,//最大信号量
       LPCTSTR lpName //命名
        );

返回创建好的信号量句柄.
    2.2 等候信号量
      WaitForSingleObject
      WaitForMultipleObjects
    2.3 释放信号

      BOOL ReleaseSemaphore(
       HANDLE hSemaphore, //信号量句柄
       LONG lReleaseCount,//释放信号的数量
       LPLONG lpPreviousCount //释放前的数量
      );

2.4 关闭信号量
      CloseHandle
    2.5 打开信号量
      OpenSemaphore

/* File :Semaphore.cpp
 * Auth : sjin
 * DAte : 20140727
 * Mail : [email protected]
 */

#include "stdafx.h"
#include "conio.h"
#include "windows.h"

HANDLE g_hSemaphore = NULL;

DWORD WINAPI ThreadSend( LPVOID pParam )
{
    while( 1 ){
        CHAR ch = getch( );
        switch( ch ){
        case ‘1‘:
            //释放信号 其实是增加可用空位
            ReleaseSemaphore( g_hSemaphore, 1, NULL );
            break;
        case ‘5‘:
            ReleaseSemaphore( g_hSemaphore, 5, NULL );
            break;
        }
    }
    return 0;
}

DWORD WINAPI ThreadRecv( LPVOID pParam )
{
    while( 1 ){    //等候信号量的信号
        WaitForSingleObject(  g_hSemaphore, INFINITE );
        printf( "Hello Semaphore\n" );
        Sleep( 100 );
    }
    return 0;
}

void Create( )
{
    DWORD  nThreadID  = 0;
    HANDLE hThread[2] = { NULL };
    hThread[0] = CreateThread( NULL, 0, ThreadSend, NULL, 0, &nThreadID );
    hThread[1] = CreateThread( NULL, 0, ThreadRecv, NULL, 0, &nThreadID );

    WaitForMultipleObjects( 2, hThread, TRUE, INFINITE );
}

int main(int argc, char* argv[])
{    //创建信号量
    g_hSemaphore = CreateSemaphore( NULL, 3, 10, NULL );  //3表示一开始有3个可用空位
    Create();
    //关闭信号量
    CloseHandle( g_hSemaphore );
    return 0;
}

八 可等候定时器

1 可等候定时器
    是一个更加精确系统提供的定时器.能够达到100ns级别. 
    
  2 定时器的使用
    2.1 创建定时器

        HANDLE CreateWaitableTimer(
      LPSECURITY_ATTRIBUTES lpTimerAttributes,//安全属性
      BOOL bManualReset,//重置方式
      LPCTSTR lpTimerName //命名
      );

返回创建好的定时器的句柄
    2.2 设置定时器

      BOOL SetWaitableTimer(
       HANDLE hTimer, //定时器句柄
       const LARGE_INTEGER *pDueTime,//定时器第一次触发的时间,100ns级别
       LONG lPeriod, //后续每次触发的间隔,毫秒级别
       PTIMERAPCROUTINE pfnCompletionRoutine,  //APC处理函数
       LPVOID lpArgToCompletionRoutine,//APC参数
       BOOL fResume ); //休眠标识

pDueTime - 正值,表示绝对时间
          负值,表示相对于现在的时间间隔
       lPeriod  - 0  定时器不再有后续触发
          大于0 按照间隔触发
             
       pDueTime | lPeriod | lPeriod ....
         
    2.3 等候定时器
      WaitForSingleObject
      WaitForMultipleObjects
    2.4 关闭定时器
      CloseHandle
    2.5 APC定时器 (异步调用处理)

/* File :WaitableTimer.cpp
 * Auth : sjin
 * DAte : 20140727
 * Mail : [email protected]
 */

#include "stdafx.h"

#define _WIN32_WINNT 0x0400

#include "windows.h"

HANDLE g_hTimer = NULL;

DWORD WINAPI TimerThread( LPVOID pParam )
{
    while( 1 ){
        WaitForSingleObject( g_hTimer,  INFINITE );
        printf( "Hello Timer\n" );
    }

    return 0;
}

void Create( )
{    //创建定时器
    g_hTimer = CreateWaitableTimer(  NULL, FALSE, NULL );
    //设置定时器
    UINT64 nDueTime = -100000000;
	//nDueTime是第一次触发的时间(纳秒),1000是以后触发间隔(毫秒)
    SetWaitableTimer( g_hTimer,  (PLARGE_INTEGER)&nDueTime, 1000,  NULL, NULL, FALSE );
    //创建等候线程
    DWORD dwThreadID = 0;
    HANDLE hThread = CreateThread( NULL, 0, TimerThread, NULL, 0, &dwThreadID );
    WaitForSingleObject( hThread, INFINITE );
    //关闭定时器
    CloseHandle( g_hTimer );
}

VOID CALLBACK TimerProc( LPVOID lpArgToCompletionRoutine, DWORD  dwTimerLowValue, DWORD  dwTimerHighValue )
{
    printf( "------APC TimerProc--------\n" );
}

void APCTimer( )
{    //创建定时器
    HANDLE hTimer = CreateWaitableTimer(
        NULL, FALSE, NULL );
    //设置定时器
    UINT64 nDueTime = -10000000;
    SetWaitableTimer( hTimer,  (PLARGE_INTEGER)&nDueTime, 1000, TimerProc, NULL, FALSE );
    //
    while( 1 )
    {
        SleepEx( -1, TRUE ); //阻塞main()函数,但是waitabletimer的消息还是能执行。说明这是另外一个消息队列
    }    

    //关闭句柄
    CloseHandle( hTimer );
}

int main(int argc, char* argv[])
{
    Create( );
    APCTimer( );

    return 0;
}
时间: 2024-10-14 14:34:32

走进windows编程的世界-----windows线程的相关文章

走进windows编程的世界-----windows进程

Windows进程  1 Windows进程    进程是一个容器,包含了一个应用程序实例的各种资源.Windows多任务的操作系统,因此可以同时执行多个进程.      2 Windows进程的一些特点    2.1 进程中包含了执行代码等资源.    2.2 进程都具有私有的地址空间.    2.3 每个进程都有一个ID,标识进程.    2.4 每个进程都有自己的安全属性    2.5 至少要包含一个可以执行的线程.    二 进程的环境 1 环境信息的获取    获取:    LPVOI

走进windows编程的世界-----消息处理函数(1)

Win32消息机制 过程驱动:程序是按照我们预先定义好的顺序执行,每执行一步,下一步都已经按照预定的顺序 继续执行,直至程序结束. 事件驱动:程序的执行顺序是无序的.某个时间点所执行的代码,是由外界 通知.由于我们无法决定程序执行顺序.所以代码的执行也是无序的. Win32基本消息 WM_DESTROY:       窗口销毁时的消息,可以做退出或善后处理 WM_CREATE:       窗口创建消息,是在窗口创建后,窗口处理函数收到的第一条消息   可以在这个消息内,做初始化或者穿件子窗口

走进windows编程的世界-----字符编码

1   字符编码 1.1编码的历史 1.1.1ASCII码 0=127 7位表示 1.1.2ASCII扩展码 0-255 8为表示. 代码页:通过代码也来切换对应的字符(数字表示) 1.1.3双字节字符集DBCS 使用一个或两个字节表示字符. 1.1.4Unicode编码 全部使用2个字节表示字符 内存 硬盘等资源占用变大.对编码支持度大. 字符集 1.2C 语言和编码 1.2.1单字节的字符和字符串 Char  cText = 'A'; Char * pszText ="ABCD"

走进windows编程的世界-----消息处理函数(4)

一 右键菜单  1 右键菜单    当在窗口点击鼠标右键时,弹出的菜单.  2 右键菜单的使用    2.1 创建菜单      CreatePopupMenu    2.2 菜单增加     AppendMenu    2.3 菜单的显示. BOOL TrackPopupMenu( HMENU hMenu, //显示的菜单句柄 UINT uFlags, //显示的方式 int x, //菜单的X屏幕坐标 int y, //菜单的Y屏幕坐标 int nReserved, //保留,必须为0 HW

走进windows编程的世界-----消息处理函数(3)

二 定时器消息 1 定时器消息 WM_TIMER   按照定时器设置时间段,自动向窗口发送一个定时器消息WM_TIMER. 优先级比较低.   定时器精度比较低,毫秒级别.消息产生时间也精度比较低.    2 消息和函数   2.1 WM_TIMER  - 消息ID    wParam: 定时器的ID    lParam: 定时器的处理函数 2.2 SetTimer  - 设置一个定时器 UINT SetTimer( HWND hWnd, //窗口的句柄,可以为NULL UINT nIDEven

走进windows编程的世界-----绘图相关

Windows绘图 1 图形绘制      1.1 图形绘制的方式      获取到绘图句柄-设备描述表(DC),使用相应的绘图的API,在设备上绘制图形.          1.2 颜色      R\G\B三色, 每种颜色8位, 共24位颜色.      32位颜色: 颜色数量24位颜色, 多出来的8位表示灰度.      16位: 颜色数量2的16次方.            Win32下,颜色的定义 COLORREF(DWORD), RGB宏定义颜色       COLORREF nCo

走进windows编程的世界-----窗口的注册及创建

1   窗口注册和创建 1.1WIN32 窗口程序创建步骤 1.WinMain入口函数的定义 2.WindowProc函数的定义 3.注册窗口类 RegisterClass.RegisterClassEX 4.创建窗口 CreateWindow.CreateWindowEx HWND CreateWindow( LPCTSTRlpClassName,//指向已注册的窗口类的名称的指针 LPCTSTRlpWindowName,//指向窗口名称的指针 DWORDdwStyle,//窗口的风格 int

走进windows编程的世界-----消息处理函数(2)

一 WM_PAINT消息 1 WM_PAINT的产生   由于窗口的互相覆盖等,产生需要绘制的区域,那么会产生WM_PAINT消息.   一般情况下,不直接发送WM_PAINT消息,通过API声明需要绘制区域,来产生WM_PAINT消息.   例如,可以使用InvalidateRect声明一个需要重新绘制的区域.    2 WM_PAINT的注意点    2.1 如果一个消息队列中,有多个WM_PAINT消息,只有最后一个WM_PAINT消息会被处理.    2.2 WM_PAINT消息处理中,

走进windows编程的世界-----位图及映射模式

1   位图的使用 1.1位图介绍 位图-通过保存在图像上每个点的颜色,生成响应的位图文件. 光栅图:图像点阵的保存 矢量图:绘图命令的保存. 1.2位图的使用 1.             加载位图资源 LoadBitap(); 2.             创建防止位图的DC CreateCompatibleDC 3.             将位图放入创建的DC SlectObject 4.             绘制位图到当前DC中 BitBlt 5.             取出位图