• Win32编程day14 学习笔记


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

      1 环境信息的获取
        获取:
        LPVOID GetEnvironmentStrings(VOID)
        返回值是获取到的所有环境信息
        释放:

        BOOL FreeEnvironmentStrings(  
         LPTSTR lpszEnvironmentBlock )

      2 环境变量的获取和设置
        获取:

         DWORD GetEnvironmentVariable(
         LPCTSTR lpName,  //变量名称
         LPTSTR lpBuffer, //数据BUFF
         DWORD nSize      //BUFF的长度
        );

        返回值是获取到的字符串的长度
        设置:

        BOOL SetEnvironmentVariable(
         LPCTSTR lpName, //变量名称
         LPCTSTR lpValue  //变量的值
        );
    View Code
    // ProcInfo.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include "windows.h"
    
    void EnvVariable( LPSTR pszVar )
    {    //设置指定变量的值
        SetEnvironmentVariable( pszVar,    "C:\\" );
        //获取指定的变量的值
        CHAR szValue[1024] = { 0 };
        GetEnvironmentVariable( pszVar,
            szValue, 1024 );
        printf( "%s: %s\n", pszVar,  szValue );
    }
    
    void EnvString( )
    {    //获取所有环境信息
        LPSTR pszEnv = ( LPSTR )
            GetEnvironmentStrings( );
        LPSTR pszTmp = pszEnv;
        while( 0 != pszTmp[0] )
        {
            printf( "%s\n", pszTmp );
            pszTmp = strlen(pszTmp) + 1 + pszTmp;
        }
        //释放环境信息字符串
        FreeEnvironmentStrings( pszEnv );
    }
    
    int main(int argc, char* argv[])
    {
        EnvString( );
        EnvVariable( "MYPATH" );
        return 0;
    }  

    三 进程的信息
       1 进程ID和句柄
         GetCurrentProcessID 获取进程的ID
         GetCurrentProcess 获取进程的句柄,
             返回值为-1,是当前进程的伪句柄,永远是-1.如果想获取当前进程的实际句柄需要使用OpenProcess函数.
       2 打开进程

         HANDLE OpenProcess(
           DWORD dwDesiredAccess, //访问模式
           BOOL bInheritHandle, //继承标识
           DWORD dwProcessId //进程ID
         );

       返回进程的句柄
       3 获取进程的所使用的所有模块(EXE或DLL)
         使用PSAPI函数.

          BOOL EnumProcessModules(
           HANDLE hProcess,//进程句柄
           HMODULE * lphModule,//模块的数组
           DWORD cb, //数组的长度
           LPDWORD lpcbNeeded //获取到数据的字节数
          );
    View Code
    // ProcBase.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include "windows.h"
    
    #include "../psapi/psapi.h"
    #pragma comment( lib, "../psapi/psapi.lib" )
    
    void ProcModule( )
    {
        printf( "All Modules\n" ); 
        //当前进程句柄
        HANDLE  hProc = GetCurrentProcess( ); 
        //获取模块句柄
        HMODULE hModules[256] = { 0 };
        DWORD   nNeed = 0;
        EnumProcessModules( hProc, hModules,
            256, &nNeed );
        //计算获取到句柄数量
        DWORD   nCount = nNeed / sizeof(HMODULE);
        for( DWORD nIndex=0; nIndex<nCount; nIndex++ )
        {    //获取模块的文件名及路径
            CHAR szPath[MAX_PATH] = { 0 };
            GetModuleFileNameEx( hProc, 
                hModules[nIndex], szPath, MAX_PATH );
            //打印
            printf( "\t%d: %p, %s\n", nIndex+1, 
                hModules[nIndex], szPath );
        }
    }
    
    void ProcInfo( )
    {    //获取进程ID
        DWORD  nID   = GetCurrentProcessId( );
        //获取进程句柄(-1,伪句柄)
        HANDLE hProc = GetCurrentProcess( ); 
        printf( "Process ID: %d\n",     nID );
        printf( "Process Handle: %p\n", hProc );
        //根据进程ID获取进程实际句柄
        hProc = OpenProcess( PROCESS_ALL_ACCESS, 
                   FALSE, nID );
        printf( "Process Handle: %p\n", hProc );
    }
    
    int main(int argc, char* argv[])
    {
        ProcInfo( );
        ProcModule( );
        return 0;
    }

    四 进程的使用
      1 创建进程
         WinExec 16位,现在不使用
         ShellExecute 执行打开文件等操作.
         CreateProcess 执行一个EXE可执行文件.创建一个进程以及它的主线程.

         BOOL CreateProcess(
              LPCTSTR lpApplicationName,//应用程序路径名
          LPTSTR lpCommandLine, //命令行
          LPSECURITY_ATTRIBUTES lpProcessAttributes, //进程安全属性
          LPSECURITY_ATTRIBUTES lpThreadAttributes, //线程安全属性
          BOOL bInheritHandles, //句柄继承标识
          DWORD dwCreationFlags, //创建标识
          LPVOID lpEnvironment, //环境块
          LPCTSTR lpCurrentDirectory,//当前目录
          LPSTARTUPINFO lpStartupInfo,//启动参数
          LPPROCESS_INFORMATION lpProcessInformation //进程信息
          );

          当进程创建成功,可以从进程信息中获取创建好的进程句柄\ID等.
          如果执行程序是16的程序,那么只能使用lpCommandLine设置执行程序路径.
      2 打开进程
         OpenProcess
      3 结束进程
         VOID ExitProcess( UINT uExitCode ); (用得较少)

         BOOL TerminateProcess(
          HANDLE hProcess, //进程句柄
          UINT uExitCode );  //结束代码

      4 等候进程结束

         DWORD WaitForSingleObject(
          HANDLE hHandle, //等候的句柄
          DWORD dwMilliseconds );//等候的时间,毫秒

        阻塞函数,当运行时,会在等候的时间的时间内,
        等待句柄的信号.

    View Code
    // ProcUse.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include "conio.h"
    #include "windows.h"
    
    void Create( )
    {
        STARTUPINFO         si = { 0 };
        PROCESS_INFORMATION pi = { 0 };
        si.cb = sizeof( si );
        si.dwFlags = STARTF_USESIZE;
        si.dwXSize = 100;
        si.dwYSize = 200;
        //创建进程
        CreateProcess( "ChildProc.exe",  //新建一个项目childproc。 把exe的生成目录设为和当前程序的生成目录相同
            "\"Hello Child\"",  
            NULL, NULL, FALSE,
            CREATE_NEW_CONSOLE, 
            NULL, NULL, &si, &pi );
        //输出信息
        printf( "Process Handle: %p\n", pi.hProcess );
        printf( "Process ID: %d\n", pi.dwProcessId );
        printf( "Thread Handle: %p\n", pi.hThread );
        printf( "Thread ID: %d\n", pi.dwThreadId );
    }
    
    void Terminate( DWORD dwProcID )
    {    //打开进程获取句柄
        HANDLE hProc = OpenProcess( 
            PROCESS_ALL_ACCESS, FALSE,
            dwProcID );
        //结束进程
        TerminateProcess( hProc, 0 );
    }
    
    void Wait( )
    {
        //创建进程
        STARTUPINFO si = { 0 };
        PROCESS_INFORMATION pi = { 0 };
        si.cb = sizeof( si );
        CreateProcess( 
            "C:\\Windows\\System32\\Winmine.exe",
            NULL, NULL, NULL, FALSE, 0,
            NULL, NULL, &si, &pi );
        printf( "Winmine is running\n" );
        //等候进程结束
        WaitForSingleObject( pi.hProcess,
            INFINITE );
        printf( "Winmine is stop\n" );
    }
    
    int main(int argc, char* argv[])
    {
        //Create( );
        //Terminate( 244 );
        Wait( );
        getch( );
        return 0;
    }

    五 Windows作业(Job)

      1 Windows作业
        实际是一个进程组. 可以对作业设置权限,一旦进程加入到作业之内,进程的权限将被作业限制.
       
      2 作业的使用
        需要NT5.0以上支持,所有在Windows.h前定义
          #define _WIN32_WINNT 0x0500
        2.1 创建一个作业

         HANDLE CreateJobObject(
           LPSECURITY_ATTRIBUTES lpJobAttributes,// 安全属性
           LPCTSTR lpName ); //名称

         返回创建的Job句柄
        2.2 设置作业权限

         BOOL SetInformationJobObject(
          HANDLE hJob,//Job句柄
                JOBOBJECTINFOCLASS JobObjectInformationClass,//Job权限的类型
                LPVOID lpJobObjectInformation,//类型所对应的数据结构的地址
                DWORD cbJobObjectInformationLength //类型所对应的数据结构的长度
                );

        2.3 将进程加入作业

           BOOL AssignProcessToJobObject(
            HANDLE hJob, //作业句柄
            HANDLE hProcess );//进程句柄

        2.4 关闭作业
           CloseHandle
        2.5 结束作业
           使用TerminateJobObject结束作业.但是并不是所有情况下,作业内的进程都能被结束.

    View Code
    // WinJob.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include "conio.h"
    
    #define _WIN32_WINNT 0x0500
    
    #include "windows.h"
    
    HANDLE Create( LPSTR pszPath )
    {
        STARTUPINFO si = { 0 };
        PROCESS_INFORMATION pi = { 0 };
        si.cb = sizeof( si );
        CreateProcess( pszPath,
            NULL, NULL, NULL, FALSE, 0,
            NULL, NULL, &si, &pi );
        return pi.hProcess;
    }
    
    void Job( )
    {    //创建Job对象
        HANDLE hJob = 
            CreateJobObject( NULL, "MyJob" );
        //设置权限
        JOBOBJECT_BASIC_UI_RESTRICTIONS ui = {0};
        ui.UIRestrictionsClass = 
            JOB_OBJECT_UILIMIT_READCLIPBOARD|
            JOB_OBJECT_UILIMIT_WRITECLIPBOARD;  //限制操作剪贴板
        SetInformationJobObject( hJob,
          JobObjectBasicUIRestrictions,   //ui的类型与这个参数有关
          &ui, sizeof(ui) );
        //创建进程
        HANDLE hProc = Create( 
            "c:\\windows\\system32\\mspaint.exe" );
        //将进程加入作业
        AssignProcessToJobObject( 
            hJob, hProc );
    
        getch( );
        //结束作业
        TerminateJobObject( hJob, 0 );
        //关闭Job
        CloseHandle( hJob );
    }
    
    int main(int argc, char* argv[])
    {
        Job( );
        return 0;
    }

    六 Windows线程

      1 Windows线程
        Windows进程中可以执行代码的实体,Windows系统可以调度的执行代码.一个进程中至少有一个或多个线程. 每个线程是进程的一个任务分支.
       
      2 线程的特点
        2.1 每个线程有一个ID.
        2.2 每个线程有自己的安全属性
        2.3 每个线程有自己的内存栈.
       
      3 进程和线程多任务
        多进程实现的多任务: 由于进程地址空间是属于各自私有, 内存和资源不能共享.
        多线程实现的多任务: 由于线程都是位于同一个进程的地址空间,内存和资源可以共享.
         
      4 线程的执行
        线程的执行方式采用轮询方式执行.
           A -> B -> A -> B.....
          
    七 线程的使用

      1 定义线程处理函数

        DWORD WINAPI ThreadProc(
         LPVOID lpParameter );  //线程参数

      2 创建线程

        HANDLE CreateThread(
        LPSECURITY_ATTRIBUTES lpThreadAttributes,  //安全属性
        DWORD dwStackSize, //初始化栈的大小,缺省为0
        LPTHREAD_START_ROUTINE lpStartAddress, //线程的函数指针
        LPVOID lpParameter, //线程参数
        DWORD dwCreationFlags,  //创建方式
        LPDWORD lpThreadId //返回线程ID
        );

        返回值是创建好的线程的句柄.
      3 结束线程
        ExitThread
        TerminateThread
      4 线程挂起和执行
        挂起线程
          DWORD SuspendThread( HANDLE hThread  );
        执行线程
         DWORD ResumeThread( HANDLE hThread  );
      5 等候线程的结束
        可以使用 WaitForSingleObject 等候线程的
        结束。
      6 关闭线程句柄
        CloseHandle  句柄关掉不代表结束线程,只是释放线程句柄资源

    View Code
    // ThreadBase.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include "conio.h"
    #include "windows.h"
    
    DWORD WINAPI ThreadProc1( LPVOID pParam )
    {
        DWORD nValue = (DWORD)pParam;
        for( int nIndex=0; nIndex<10; nIndex++ )
        {
            printf( "Thread Proc1-------%d\n", 
                nValue );
            Sleep( 1000 );
        }
        return 0;
    }
    
    DWORD WINAPI ThreadProc2( LPVOID pParam )
    {
        while( 1 )
        {
            printf( "-------Thread Proc2\n" );
            Sleep( 1000 );
        }
        return 0;
    }
    
    void Create( )
    {    DWORD nValue = 100;
        //创建一个挂起的线程
        DWORD nThreadID = 0;
        HANDLE hThread = CreateThread( NULL, 0,
            ThreadProc1, (LPVOID)nValue, 
            CREATE_SUSPENDED, &nThreadID );
        printf( "Thread 1 ID: %d\n", nThreadID );
        printf( "Thread 1 Handle: %p\n", hThread );
        //执行线程
        ResumeThread( hThread );
        
        //等候线程1结束
        WaitForSingleObject( hThread, INFINITE );
        CloseHandle( hThread );
    
        //创建一个立刻执行的线程
        hThread = CreateThread( NULL, 0, 
            ThreadProc2, NULL, 0, &nThreadID );
        printf( "Thread 2 ID: %d\n", nThreadID );
        printf( "Thread 2 Handle: %p\n", hThread );
        //挂起线程
        //SuspendThread( hThread );
        CloseHandle( hThread );
    }
    
    int main(int argc, char* argv[])
    {
        Create( );
        getch( );
        return 0;
    }

    八 线程局部存储 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
             TlsAlloc
             TlsSetValue
             TlsGetValue
             TlsFree

    View Code
    // ThreadTls.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include "conio.h"
    #include "stdlib.h"
    #include "windows.h"
    
    CHAR * g_pszText1 = NULL;  //所有子线程共享一个全局变量
    //使用关键字定义TLS变量
    __declspec(thread) CHAR * g_pszText2 = NULL;
    
    void Print( )
    {
        printf( "Text1: %s\n", g_pszText1 );
        printf( "Text2: %s\n", g_pszText2 );
    }
    
    DWORD WINAPI PrintProc( LPVOID pParam )
    {
        CHAR * pszText = (CHAR *)pParam;
        
        g_pszText1 = (CHAR *)malloc( 100 );
        memset( g_pszText1, 0, 100 );
        strcpy( g_pszText1, pszText );
    
        g_pszText2 = (CHAR *)malloc( 100 );
        memset( g_pszText2, 0, 100 );
        strcpy( g_pszText2, pszText );
    
        while( 1 )
        {
            Print( );
            Sleep( 1000 );
        }
        return 0;
    }
    
    void Create( )
    {
        DWORD dwThread = 0;
        CHAR  szText1[] = "Thread 1----------";
        HANDLE hThread = CreateThread( NULL, 
            0, PrintProc, szText1, 0, &dwThread );
    
        CHAR  szText2[] = "-----Thread 2-----";
        hThread = CreateThread( NULL, 
            0, PrintProc, szText2, 0, &dwThread );
    
        CHAR  szText3[] = "----------Thread 3";
        hThread = CreateThread( NULL, 
            0, PrintProc, szText3, 0, &dwThread );
    
        getch( );
    }
    
    int main(int argc, char* argv[])
    {
        Create( );
        return 0;
    }  
  • 相关阅读:
    Pentaho Data Integration (二) Spoon
    Pentaho Data Integration笔记 (一):安装
    透视纹理引发的对于插值的思考
    读取位图(bitmap)实现及其要点
    关于渲染流水线的几何变化
    关于C++中不同类之间的赋值问题——存疑
    uva 12284 直接判断
    uva 12549 最大流
    uva 12544 无向图最小环
    uva 12587 二分枚举
  • 原文地址:https://www.cnblogs.com/tangzhengyue/p/2647664.html
Copyright © 2020-2023  润新知