zoukankan      html  css  js  c++  java
  • MFC3

    4.15/////////////////////////////////////////////////////////////////////////////15多线程编程

    进程由两个部分:内核对象,地址空间。

    CreateThread

    12.8

    ThreadProc

    sleep暂停当前线程时间间隔

    39.34

    CreateMutex创建互斥对象   取得线程ID

    WaitForSingleObject  独占

    ReleaseMutex 释放

    HANDLE WINAPI CreateMutex(

    _In_opt_  LPSECURITY_ATTRIBUTES lpMutexAttributes, //If this parameter is NULL, the handle cannot be inherited by child processes.

    _In_      BOOL bInitialOwner, //调用线程(主线程)获得初始所有权TURE FALSE

    _In_opt_  LPCTSTR lpName ); //what means  The name of the mutex object ?

    互斥对象 和线程相关 线程ID ,   谁拥有 谁释放 , 请求互斥对象  就要相应去释放。

    命名的互斥对象 ,

    hMutex= CreateMutex(NULL,true,"ticket");
    if(hMutex)
    {
        if(ERROR_ALREADY_EXISTS == GetLastError())
        {
            cout<<"已经有一个程序的实例在运行了"<<endl;
            return;
        }
    }

    case WAIT_FAILED:
         cout<<  "The function has failed. To get extended error information, call GetLastError.\n";

    这个对它不管用。

    一个线程得到运行   关闭后没有释放  系统会将其拥有的ID归为零  系统维护了线程对象引用  引用对象和计数器 置0.

    当得到了互斥对象 , 如何知道是正常请求到, 还是别的进程中止了 WaitForSingleObject返回值

    AfxSocketInit  头文件 Afxsock.h  放到// stdafx.h  , 预编译的头文件,

    所有与窗口有关的类, 都有一个数据成员 m_hWnd保存了窗口句柄。

    cannot convert parameter 3 from 'unsigned long (void *)' to 'unsigned long (__stdcall *)(void *)'

    线程函数要产生时, 对象必须已经存在 , 否则无法创建, 可以声明为static.如果不能用全局变量 , 采用静态的也是一种好办法 ,

    sprintf

    16////////////////////////////////////////////////////线程同步  异步套接字

    CreateEvent

    ResetEvent 设置 事件对象为非事件状态

    事件对象 线程间的同步

    SetEvent 

    HANDLE CreateEvent(

    LPSECURITY_ATTRIBUTES lpEventAttributes,

    BOOL bManualReset, //[in]Boolean that specifies whether a manual-reset or auto-reset event object is created. If TRUE, then you must use theResetEvent function to manually reset the state to nonsignaled. If FALSE, the system automatically resets the state to nonsignaled after a single waiting thread has been released. BUT WE DONOT SUPPOSE YOU WILL USE IT BY MANUAL.

    BOOL bInitialState,

    LPTSTR lpName );

    使用自动重置事件, 设置有信号,等待该事件的进程只有一个可得到该资源,同时 设置为非信号状态供自己使用,用后需要设置setEvent.

    而人工重置的线程对象始终处于有信号状态。

    创建命名的 事件对象。

    关键代码段  临界区   工作在用户方式下。

    EnterCriticalSection

    InitializeCriticalSection(&g_cs);
        Sleep(4000);
    DeleteCriticalSection(&g_cs);

        EnterCriticalSection(&g_cs);
    ………
        LeaveCriticalSection(&g_cs);

    哲学家进餐

    三种互斥操作: 互斥对象、事件对象 与 临界区(关键代码段

    互斥/事件 属于内核对象,速度慢,但可在多进程中各线程间同步。

    临界区速度快,容易死锁。  首选。

    推荐教材

    Windows程序设计(第五版).pdf

    WSAAsyncSelect

    需要一个头文件, 一个库文件

    winsock2.h (放预编译头文件中)    ws2_32.lib

    WSASocket

    定义 , 响应, 映射

    1:19

    WSARecvfrom

    WSABUF 

    SOCKADDR_IN addrTo;  //在网际网路通讯协议家簇,SOCKADDR_IN 结构体用来指定 本机或远程端点位址的连线通讯端windows通讯端。
    addrTo.sin_addr.S_un.S_addr = htonl(dwIP);//IP
    addrTo.sin_family = AF_INET;//位址,必须是AF_INET
    addrTo.sin_port = htons(6000);

    void SetAddress(  BYTE nField0,  BYTE nField1,  BYTE nField2,  BYTE nField3  );

    WSASendTo(m_socket,&wsabuf,1,&dwSend,0,(SOCKADDR*)&addrTo,sizeof(SOCKADDR),NULL,NULL))

    改进点:

    程序接收、发送在同一线程中。 异步选择可提高网络性能。

    如果阻塞套接字,会因接收函数的调用,导致暂停主线程。

    从主机数据库中获取主机名信息,

    pHost = gethostbyname(strHostName);   //字符指针
    addrTo.sin_addr.S_un.S_addr =   //需要ULONG的网络类型

      *((DWORD*)pHost->h_addr_list[0]);  //转换为DWORD* (ULONG类型)只要内在空间一样大就可以转。取值 取个类型4个字节(无符号整形值)。 网络字节序。

    编程写到哪一步,头脑中形成相应的内存模型。则无敌。


     

    Gethostbyaddr.

    //////////////////////////////////////////////////////4.17 进程间的通信                                                                                  

    每个进程分配 4GB私有地址空间, 4种进程间通信方式:剪贴板、匿名管道、命名管道、邮槽?

    一  剪贴板、两个进程间,不能实现跨网络

    OpenClipboard 打开剪贴板

    EmptyClipboard 清空剪贴板,并释放数据 句柄,所有权给当前打开剪贴板的窗口。

    SetClipboardData在剪贴板上放置数据。必须已经调用了OpenClipboard ,   CF_TEXT 。  第二个参数指定格式数据的句柄 可以为NULL, 延迟提交  

     IMEI:868350015222862

    S/N: Q5Q4CC9312227037

    02-5043-126118

    P1NTYN40X3CYXX5

    GlobalAlloc 本地堆 全局堆,  heap Function    GlobalLock 全局内存对象加锁, 返回指针, GlobalUnlock

    IsClipboardFormatAvailable  当前剪贴板是否有指定格式数据,

    if(OpenClipboard())
    {
        CString str;
        HANDLE hClip;
        char *pBuf;
        EmptyClipboard();
        GetDlgItemText(IDC_EDIT_SEND,str);
        hClip = GlobalAlloc(GMEM_MOVEABLE,str.GetLength()+1);//最后一字节会清空。会丢失
    pBuf = (char*)GlobalLock(hClip);//全局内存对象加锁,并返回
        strcpy(pBuf,str);
        GlobalUnlock(hClip);
        SetClipboardData(CF_TEXT,hClip);
        CloseClipboard();
    }

    if(OpenClipboard())
    {
        if(IsClipboardFormatAvailable(CF_TEXT))
        {
            HANDLE hClip;
            char *pBuf;
            hClip = GetClipboardData(CF_TEXT);
            pBuf = (char*)GlobalLock(hClip);
            GlobalUnlock(hClip);
            SetDlgItemText(IDC_EDIT_RECV,pBuf);
            CloseClipboard();
        }

    二 、 匿名管道 父子进程通信  可以跨网络  点对点

    启动一个进程,CreateProcess 参数尼马好烦啊。

        BOOL WINAPI CreateProcess(
      _In_opt_     LPCTSTR lpApplicationName, //可执行文件名
      _Inout_opt_  LPTSTR lpCommandLine,// command line string
      _In_opt_     LPSECURITY_ATTRIBUTES lpProcessAttributes,//SD
      _In_opt_     LPSECURITY_ATTRIBUTES lpThreadAttributes,//SD
      _In_         BOOL bInheritHandles,//句柄继承选择
      _In_         DWORD dwCreationFlags,//创建标记 , 控制优先级类
      _In_opt_     LPVOID lpEnvironment,//环境块指针  NULL新进程使用调用进程的环境 , 如果改新进程环境信息,如此构造环境块
      _In_opt_     LPCTSTR lpCurrentDirectory,//子进程当前驱动器 和目录
      _In_         LPSTARTUPINFO lpStartupInfo,//指定新进程主窗口如何出现
      _Out_        LPPROCESS_INFORMATION lpProcessInformation//
    );

    void CChildView::OnInitialUpdate() 窗口创建完成后 第一个执行的

    hRead = GetStdHandle(STD_INPUT_HANDLE);
    hWrite = GetStdhandle(STD_OUTPUT_HANDLE);

    三 、 命名管道 :可以跨网络  点对点

    命名管道是通过网络来完成进程间的通信,屏蔽(au) 了底层网络协议细节。 实际上建立了一个C/S 通信体系。采用命名管道文件系统接口NPFS ,可以使用WIN32文件系统函数来收发文件,ReadFile WriteFile .

    命名管道和客户机区别, 服务器是唯一 可以有权建立命名管道的进程 , ,, 授权管道客户机的连接请求。 客户机只能同一个现成的命名管道服务器建立连接。

    命名管道提供了两种基本通信方式,字节模式和消息模式。

    1. CreateNamedPipe  返回管道句柄

    HANDLE WINAPI CreateNamedPipe(
      _In_      LPCTSTR lpName,   \\.\\pipe\pipename  点表示本地机器   如果要和远程服务器连接这个点是远程服务器的名字。
    pipe 是硬编码,大小写无所谓。
      _In_      DWORD dwOpenMode,//pipe open mode
      _In_      DWORD dwPipeMode,//pipe-specific modes
      _In_      DWORD nMaxInstances,//maximum number of instance
      _In_      DWORD nOutBufferSize,//为输出 缓冲区保留的字节数目
      _In_      DWORD nInBufferSize,// 是可变的。实际缓冲的大小,或者系统缺省的,
      _In_      DWORD nDefaultTimeOut,//时间间隔
      _In_opt_  LPSECURITY_ATTRIBUTES lpSecurityAttributes//SD
    );

    DWORD dwPipeMode, 

    PIPE_TYPE_BYTE

    Data is written to the pipe as a stream of bytes. This mode cannot be used with PIPE_READMODE_MESSAGE. The pipe does not distinguish bytes written during different write operations.

    PIPE_TYPE_MESSAGE

    Data is written to the pipe as a stream of messages. The pipe treats the bytes written during each write operation as a message unit. The GetLastError function returns ERROR_MORE_DATA when a message is not read completely. This mode can be used with either PIPE_READMODE_MESSAGE or PIPE_READMODE_BYTE.

    2. 命名管道创建成功了,调用函数ConnectNamedPipe 去等待客户端连接请求的实例。允许一个命名管道服务器进程等待客户端进程连接到命名管道的实例上。让命名管道服务器端等待客户端连接请求的到来 。(不是去连接服务器端)

    BOOL WINAPI ConnectNamedPipe(
      _In_         HANDLE hNamedPipe,
      _Inout_opt_  LPOVERLAPPED lpOverlapped
    );

    If hNamedPipe was created with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the OVERLAPPED structure should contain a handle to a manual-reset event object (which the server can create by using the CreateEvent function).要用到CreateEvent创建人工重置的事件对象。

    HANDLE WINAPI CreateEvent(
      _In_opt_  LPSECURITY_ATTRIBUTES lpEventAttributes,
      _In_      BOOL bManualReset,//TRUE 人工
      _In_      BOOL bInitialState,
      _In_opt_  LPCTSTR lpName
    );

    3. 构造 OVERLAPPED 结构体变量 , 5个成员

    ZeroMemory(&ovalp,sizeof(OVERLAPPED));结构体数据成员置零

    人工重置的 有效的事件对象句柄。这时才  调用 ConnectNamedPipe

    4. 调用 WaitForSingleObject 等待事件对象变为有信号状态。

    WaitNamedPipe

        BOOL WINAPI WaitNamedPipe(
      _In_  LPCTSTR lpNamedPipeName,//如果跨网络通信,要设定服务器进程所在机器主机名。
      _In_  DWORD nTimeOut
    );

    Createfile  打开一个命名管道//不仅可以对文件操作,也可以对管道

        HANDLE WINAPI CreateFile(
      _In_      LPCTSTR lpFileName,
      _In_      DWORD dwDesiredAccess,//访问方式
      _In_      DWORD dwShareMode,//共享方式  , 不需要不能够共享 0
      _In_opt_  LPSECURITY_ATTRIBUTES lpSecurityAttributes,//安全属性 NULL
      _In_      DWORD dwCreationDisposition,//创建方式
      _In_      DWORD dwFlagsAndAttributes,
      _In_opt_  HANDLE hTemplateFile
    );

    四、 邮槽  1对多

    基于广播通信,可以利用这个特点 开发会议系统,代码量少。1对多。 每台机器上安装客户端,本机服务器发关后,他们都可以同时接收到通知信息。如果采用socket编码较复杂。

    缺点 ,数据量小。

    无连接的不可靠服务。单身通信机制, 创建邮槽的服务器进程,读取数据,打开邮槽客户机进程,写入数据。 消息长度限制在424字节以下。

    CreateMailslot

    服务器端只能接收数据。客户机只能发送数据。

    要是需要双向通信 , 那么每样 各来一份。

    ///////////////////////////////////////////////18  ACTIVE 控件                                                       

    窗口和服务器程序 word  是容器应用程序  excel 是服务器应用程序。 ACTIVEX 必须嵌入到容器中运行。

    MFC ActiveX Control Wizard.

    DClock 小勺子是接口,函数的集合,抽象基类,所有函数纯虚。实现在CClockCtrl ,

    class CClockApp : public COleControlModule derived from CWnApp

    class CClockCtrl : public COleControl derived form CWnd 主窗口类或view类 ,

    // Dispatch maps高度映射

    // Event maps 事件映射

    class CClockPropPage : public COlePropertyPage derived form CDialog 类似一个对话框,显示控件的属性页,有个对话框的资源相关联,

    // Dialog Data
        //{{AFX_DATA(CClockPropPage)
        enum { IDD = IDD_PROPPAGE_CLOCK };

    COM 知识的书 , 看一下。

    反注册  regsvr32 /u  (同时 拖放ocx组件到命令框。。。可得控件所在路径名)

    DllRegisterServer

    DllUnregisterServer

    ActiveX四种属性

    Stock: 标准属性,字体或颜色

    Ambient:环境属性,不可更改, 但可以使用它们调整

    Extended ,容器处理的属性

    custom:开发者添加的属性

    越发觉得没有意思,一个知识如果不可马上用到,学得就是如我这般鼠目寸光乎?

    又或以为,一个可能过时的知识(现在用不到嘛),就是浪费时间 , 不识时务者为蠢才!

    ///////////////////////////////////////////////////////////////////19 动态链接库            

    基础

    DLL包含能被 其它可执行程序或DLL 调用来完成某项工作的函数。

    API 中所有的函数都包含在DLL 中, 其中有3个最重要的DLL

    • Kernel32.dll  管理内在、进程和纯种的各个函数
    • User32.dll 包含用于执行用户界面任务的各个函数
    • GDI32.dll 包含用于画图和显示文本的各个函数

    静态库:函数被编译进一个二进制文件(通常扩展名为LIB) 。 在使用静态库的情况下在编译链接可执行文件时, 链接器从库中复制这些函数和数据并把它们和应用程序的其它模块组合起来创建最终的可执行文件。

    在使用动态库时,往往提供两个文件, 一个引入库和一个DLL , 引入库包含被DLL导出的函数和变量的符号名, DLL 包含实际的函数和数据,在编译链接可执行文件时, 只需要链接引入库, DLL中的函数代码和数据并不复制到可执行文件中, 在运行的时候,再去加载DLL 访问 DLL 中导出的函数 。

    优点:

    • 可采用多种编程语言来写,例如VB写界面,C++写逻辑。
    • 提供二次开发平台 。
    • 节省空间内存
    • 资源共享
    • 实现应用程序本地化

    动态链接库 显示加载/隐式加载

    新建动态铰接库工程,

    CMD 、路径、 dumpbin(如果找不到,应该在VSTUDIO\VC\VC98\BIN中)

    D:\programs\c6\DLL1\Debug>dumpbin
    Microsoft (R) COFF Binary File Dumper Version 6.00.8168
    Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

    usage: DUMPBIN [options] [files]

       options:

          /ALL
          /ARCH
          /ARCHIVEMEMBERS
          /DEPENDENTS
          /DIRECTIVES
          /DISASM
          /EXPORTS
          /FPO
          /HEADERS
          /IMPORTS
          /LINENUMBERS
          /LINKERMEMBER[:{1|2}]
          /LOADCONFIG
          /OUT:filename
          /PDATA
          /RAWDATA[:{NONE|BYTES|SHORTS|LONGS}[,#]]
          /RELOCATIONS
          /SECTION:name
          /SUMMARY
          /SYMBOLS

    导出函数 _declspec(dllexport) int add(int a, int b)

    查看导出函数: dumpbin -exports dll1.dll

    查看 可执行程序的输入信息,用到哪些动态链接库 dumpbin –imports dlltest.exe

    另一个超有爱的VS工具 Dependency :

    引用的区别

    //extern int add(int a , int b);//lib中定义的
    //extern int subtract(int a , int b);

    _declspec(dllimport) int add(int a , int b);//声明动态链接库中的函数,效率更高
    _declspec(dllimport) int subtract(int a , int b);

    第三种方法,使用头文件包含。

    为调用动态链接库的客户端服务,

    头文件 包含 使用条件编译。即可以自己编译使用,也可以交给调用的客户端使用。

    #ifdef DLL1_API
    #else
    #define DLL1_API _declspec(dllimport)
    #endif
    DLL1_API int add(int a , int b);
    DLL1_API int subtract(int a , int b);

    #define DLL1_API _declspec(dllexport)
    #include "DLL1.h"

    如何导出一个类。

    如何获得调用者的窗口(句柄).GetForegroundWindow  调用者进程当前窗口

    查看导出:dumpbin –exeports name.dll    查看导入 dumpbin –imports name.exe

    58.24

    class /*DLL1_API */Point    ,而是将DLL1_API放到函数前面 。 导出类时,里面所有函数都导出,导出函数时只有函数被导出 。

    为了C语言调用。头文件宏前加  extern "C"   。 编译后的名字,没有发生改编。否则按C++编译改编后的名字,c语言的客户端调用找不到函数。

    采用 extern "C"  后不能用类导出函数,只能导出全局函数。让它的名字不发生改编。

    标准调用 _stdcall  实际上就是winapi ,

    QQ截图20130420093558  函数名字发生了改编,

    解决办法:

    建一个def文件

    LIBRARY Dll2
    EXPORTS
    add
    subtract

    结果不会被改名,详情查看          EXPORTS的文档

    LoadLibrary 用来加载 动态链接库, 可执行模块(为了访问资源), 返回模块的句柄。

    GetProcAddress 得到导出 动态链接库函数的 地址。

    typedef int(*ADDRPROC)(int a, int b);        定义了新的整型的 类型。 也是一个函数,指针类型。 ADDRPROC一个函数指针的类型。而不是变量。

    函数指针变量  可以用来接收函数地址,

    动态加载   在你需要的时候,它就在那里。

    HINSTANCE hInst;
    hInst = LoadLibrary("Dll2.dll");

    typedef int (*ADDPROC)(int a, int b);
    ADDPROC  Add = (ADDPROC)GetProcAddress(hInst,"add");

    命令提示符下面,鼠标右键是复制\粘贴。

    使用序号调用DLL中导出的函数。虽然不推荐

    ADDPROC  Add = (ADDPROC)GetProcAddress(hInst,"GetMAKEINTESOURCE(1));

    DllMain

    ///////////////////////////////////////////////////////////////20   HOOK 和数据库访问  The last lesson … Fireworks, applause , beer!!!        

    钩子过程 SetWindowsHookEx 安装一个应用程序定义的HOOK进程到HOOK链。最后安装的HOOK过程总是排在HOOK链前头。

    如何得到当前线程ID呢, GetCurrentThreadId   、 CallNextHookEx 传递钩子信息给钩子链下一个等待接收的过程。

    钩子过程函数的写法

    鼠标钩子

    LRESULT CALLBACK MouseProc( _In_  int nCode, _In_  WPARAM wParam, _In_  LPARAM lParam );

        SetWindowsHookEx(WH_MOUSE,MouseProc,NULL,GetCurrentThreadId());

    键盘钩子

    LRESULT CALLBACK KeyboardProc( _In_  int nCode, _In_  WPARAM wParam, _In_  LPARAM lParam );

        SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,NULL,GetCurrentThreadId());

    如何屏蔽组合键盘alt + f4 

        if(VK_F4 == wParam  && (1 == (lParam>>29 &1 )))

    移除钩子过程 UnhookWindowsHookEx 从hook链移走一个已经安装的钩子过程

    屏蔽当前正在运行的所有键盘和鼠标消息,安装钩子过程代码必须放DLL实现。

    动态链接库句柄 DllMain 传递一个当前动态链接库的句柄。

    HINSTANCE g_hIst;
    BOOL WINAPI DllMain(
        HINSTANCE hinstDLL,
        DWORD fdwReason,
        LPVOID lpvReserved
        )
    {
        g_hInst = hinstDLL;
    }

    DllMain entry point

    An optional entry point into a dynamic-link library (DLL). When the system starts or terminates a process or thread, it calls the entry-point function for each loaded DLL using the first thread of the process. The system also calls the entry-point function for a DLL when it is loaded or unloaded using the LoadLibrary and FreeLibrary functions.动态链接库可选入口点,,当系统运行或结束一个进程或线程,对每一个加载DLL的使用进程的第一个线程  调用入口点函数 。当加载或卸载LoadLibrary and FreeLibrary 库函数时也会调用入口点函数。

    Warning  There are serious limits on what you can do in a DLL entry point. To provide more complex initialization, create an initialization routine for the DLL. You can require applications to call the initialization routine before calling any other routines in the DLL。警告,对DLL入口点有很多限制,要提供较复杂的初始化,建立DLL初始化路径。可能需要应用程序调用其它路径之前调用初始化路径

    另外一种方法,GetModuleHandle 获取指定模块的模块句柄。返回值 hModule  和 hInstance通用。

    • DLL 文件: 写钩子   模块定义文件 .def
    • 调用文件: _declspec(dllimport) void SetHook();

    如何得到 调用进程主窗口的句柄。  将导出函数 加个参数 , 将它自己句柄通过参数传递进来 。

    设置一个最顶层窗口, 设置屏幕大小  。 使不能看到其它窗口。

    int cxScreen,cyScreen;
    cxScreen = GetSystemMetrics(SM_CXSCREEN);
    cyScreen = GetSystemMetrics(SM_CYSCREEN);
    SetWindowPos(&wndTopMost,0,0,cxScreen,cyScreen,SWP_SHOWWINDOW);

    全局变量在多个进程共享 ,节

    创建一个新的节,变量必须已经初始化。

    设置共享 ,

    #pragma data_seg("MySec")
    HWND g_hWnd = NULL;
    #pragma data_seg()

    #pragma comment(linker,"/section:MySec,RWS")

    pragma 指令的用法,见MSDN

    或者在模块定义文件中,

    SEGMENTS
    MySec READ WRITE SHARED

    请研究不同类型钩子的作用。

    数据库的应用 。

    1. ODBC 开放数据库互联。
    2. DAO 数据访问对象。DAO不像ODBC 是面向C/C++ 程序员的,用于操作ACCESS
    3. RDO 远程数据对象,直接调用ODBC API ,而不像DAO 通过JET引擎。DAO 和RDO 已经不再使用了。

    OLE DB ,对象链接与嵌入数据库。在两方面改进了ODBC , 首先提供了数据库编程的COM接口,提供了可用于关系型 和非关系型 数据源(电子表格、文本)。两个基本结构是 提供程序 和用户程序 。

    ADO , ActiveX数据对象,建立在OLE DB 之上,ADO是OLE DB 用户程序,使得像VBScript脚本语言也能使用ADO 访问数据库。

    QQ截图20130420215532

    ADO 三个核心对象

    1. connection 到数据库连接
    2. command 用来处理重复执行的查询 , 或检查在存储过程中调用的输出或返回参数的值的查询。
    3. Recordset 获取数据

    VC ADO

    导入ADO库

  • 相关阅读:
    python地图投影转换
    python 矢量数据转栅格数据
    读CSV文件并写arcgis shp文件
    python 读取矢量文件
    python 读hdf4文件,再转写成一个tif文件
    python gdal 写GeoTiff文件
    python gdal 读取栅格数据
    linux下在用python向文件写入数据时' '不起作用
    【FFT&NTT 总结】
    -【网络流总结】
  • 原文地址:https://www.cnblogs.com/iamgoodman/p/3022896.html
Copyright © 2011-2022 走看看