windows驱动开发基础(一)用户层与驱动层通信------ioctl

代码片段来自wdk7,工程路径C:\WinDDK\7600.16385.1\src\general\ioctl\wdm,该工程描述了IOCTLs (METHOD_IN_DIRECT, METHOD_OUT_DIRECT, METHOD_NEITHER, and METHOD_BUFFERED)的使用方法。以下截取关键部分,详情请参考wdk.

4种ioctl  的特点

method_buffered:输入和输出缓冲区一样,并且是由I/O manager 申请的,也就是说不是直接接触用户层传入的缓冲区。

method_neither: 这种类型是直接传入用户层的输入和输出两个缓冲区,在驱动中直接操作用户层内存是比较危险的,为了安全处理,代码增加不少检查。

method_in_direct: 从application 传数据到驱动中。

method_out_direct:从driver传数据到application。

NTSTATUS
SioctlDeviceControl(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    )

/*++

Routine Description:

    This routine is called by the I/O system to perform a device I/O
    control function.

Arguments:

    DeviceObject - a pointer to the object that represents the device
        that I/O is to be done on.

    Irp - a pointer to the I/O Request Packet for this request.

Return Value:

    NT status code

--*/

{
    PIO_STACK_LOCATION  irpSp;// Pointer to current stack location
    NTSTATUS            ntStatus = STATUS_SUCCESS;// Assume success
    ULONG               inBufLength; // Input buffer length
    ULONG               outBufLength; // Output buffer length
    PCHAR               inBuf, outBuf; // pointer to Input and output buffer
    PCHAR               data = "This String is from Device Driver !!!";
    size_t              datalen = strlen(data)+1;//Length of data including null
    PMDL                mdl = NULL;
    PCHAR               buffer = NULL;

    UNREFERENCED_PARAMETER(DeviceObject);

    PAGED_CODE();

    irpSp = IoGetCurrentIrpStackLocation( Irp );
    inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
    outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;

    if (!inBufLength || !outBufLength)
    {
        ntStatus = STATUS_INVALID_PARAMETER;
        goto End;
    }

    //
    // Determine which I/O control code was specified.
    //

    switch ( irpSp->Parameters.DeviceIoControl.IoControlCode )
    {
    case IOCTL_SIOCTL_METHOD_BUFFERED:

        //
        // In this method the I/O manager allocates a buffer large enough to
        // to accommodate larger of the user input buffer and output buffer,
        // assigns the address to Irp->AssociatedIrp.SystemBuffer, and
        // copies the content of the user input buffer into this SystemBuffer
        //

        SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_BUFFERED\n"));
        PrintIrpInfo(Irp);

        //
        // Input buffer and output buffer is same in this case, read the
        // content of the buffer before writing to it
        //

        inBuf = Irp->AssociatedIrp.SystemBuffer;
        outBuf = Irp->AssociatedIrp.SystemBuffer;

        //
        // Read the data from the buffer
        //

        SIOCTL_KDPRINT(("\tData from User :"));
        //
        // We are using the following function to print characters instead
        // DebugPrint with %s format because we string we get may or
        // may not be null terminated.
        //
        PrintChars(inBuf, inBufLength);

        //
        // Write to the buffer over-writes the input buffer content
        //

        RtlCopyBytes(outBuf, data, outBufLength);

        SIOCTL_KDPRINT(("\tData to User : "));
        PrintChars(outBuf, datalen  );

        //
        // Assign the length of the data copied to IoStatus.Information
        // of the Irp and complete the Irp.
        //

        Irp->IoStatus.Information = (outBufLength<datalen?outBufLength:datalen);

        //
        // When the Irp is completed the content of the SystemBuffer
        // is copied to the User output buffer and the SystemBuffer is
        // is freed.
        //

       break;

    case IOCTL_SIOCTL_METHOD_NEITHER:

        //
        // In this type of transfer the I/O manager assigns the user input
        // to Type3InputBuffer and the output buffer to UserBuffer of the Irp.
        // The I/O manager doesn't copy or map the buffers to the kernel
        // buffers. Nor does it perform any validation of user buffer's address
        // range.
        //


        SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_NEITHER\n"));

        PrintIrpInfo(Irp);

        //
        // A driver may access these buffers directly if it is a highest level
        // driver whose Dispatch routine runs in the context
        // of the thread that made this request. The driver should always
        // check the validity of the user buffer's address range and check whether
        // the appropriate read or write access is permitted on the buffer.
        // It must also wrap its accesses to the buffer's address range within
        // an exception handler in case another user thread deallocates the buffer
        // or attempts to change the access rights for the buffer while the driver
        // is accessing memory.
        //

        inBuf = irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
        outBuf =  Irp->UserBuffer;

        //
        // Access the buffers directly if only if you are running in the
        // context of the calling process. Only top level drivers are
        // guaranteed to have the context of process that made the request.
        //

        try {
            //
            // Before accessing user buffer, you must probe for read/write
            // to make sure the buffer is indeed an userbuffer with proper access
            // rights and length. ProbeForRead/Write will raise an exception if it's otherwise.
            //
            ProbeForRead( inBuf, inBufLength, sizeof( UCHAR ) );

            //
            // Since the buffer access rights can be changed or buffer can be freed
            // anytime by another thread of the same process, you must always access
            // it within an exception handler.
            //

            SIOCTL_KDPRINT(("\tData from User :"));
            PrintChars(inBuf, inBufLength);

        }
        except(EXCEPTION_EXECUTE_HANDLER)
        {

            ntStatus = GetExceptionCode();
            SIOCTL_KDPRINT((
                "Exception while accessing inBuf 0X%08X in METHOD_NEITHER\n",
                            ntStatus));
            break;
        }


        //
        // If you are accessing these buffers in an arbitrary thread context,
        // say in your DPC or ISR, if you are using it for DMA, or passing these buffers to the
        // next level driver, you should map them in the system process address space.
        // First allocate an MDL large enough to describe the buffer
        // and initilize it. Please note that on a x86 system, the maximum size of a buffer
        // that an MDL can describe is 65508 KB.
        //

        mdl = IoAllocateMdl(inBuf, inBufLength,  FALSE, TRUE, NULL);
        if (!mdl)
        {
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        try
        {

            //
            // Probe and lock the pages of this buffer in physical memory.
            // You can specify IoReadAccess, IoWriteAccess or IoModifyAccess
            // Always perform this operation in a try except block.
            //  MmProbeAndLockPages will raise an exception if it fails.
            //
            MmProbeAndLockPages(mdl, UserMode, IoReadAccess);
        }
        except(EXCEPTION_EXECUTE_HANDLER)
        {

            ntStatus = GetExceptionCode();
            SIOCTL_KDPRINT((
                "Exception while locking inBuf 0X%08X in METHOD_NEITHER\n",
                    ntStatus));
            IoFreeMdl(mdl);
            break;
        }

        //
        // Map the physical pages described by the MDL into system space.
        // Note: double mapping the buffer this way causes lot of
        // system overhead for large size buffers.
        //

        buffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority );

        if (!buffer) {
                ntStatus = STATUS_INSUFFICIENT_RESOURCES;
                MmUnlockPages(mdl);
                IoFreeMdl(mdl);
                break;
        }

        //
        // Now you can safely read the data from the buffer.
        //
        SIOCTL_KDPRINT(("\tData from User (SystemAddress) : "));
        PrintChars(buffer, inBufLength);

        //
        // Once the read is over unmap and unlock the pages.
        //

        MmUnlockPages(mdl);
        IoFreeMdl(mdl);

        //
        // The same steps can be followed to access the output buffer.
        //

        mdl = IoAllocateMdl(outBuf, outBufLength,  FALSE, TRUE, NULL);
        if (!mdl)
        {
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }


        try {
            //
            // Probe and lock the pages of this buffer in physical memory.
            // You can specify IoReadAccess, IoWriteAccess or IoModifyAccess.
            //

            MmProbeAndLockPages(mdl, UserMode, IoWriteAccess);
        }
        except(EXCEPTION_EXECUTE_HANDLER)
        {

            ntStatus = GetExceptionCode();
            SIOCTL_KDPRINT((
                "Exception while locking outBuf 0X%08X in METHOD_NEITHER\n",
                    ntStatus));
            IoFreeMdl(mdl);
            break;
        }


        buffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority );

        if (!buffer) {
            MmUnlockPages(mdl);
            IoFreeMdl(mdl);
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }
        //
        // Write to the buffer
        //

        RtlCopyBytes(buffer, data, outBufLength);

        SIOCTL_KDPRINT(("\tData to User : %s\n", buffer));
        PrintChars(buffer, datalen);

        MmUnlockPages(mdl);

        //
        // Free the allocated MDL
        //

        IoFreeMdl(mdl);

        //
        // Assign the length of the data copied to IoStatus.Information
        // of the Irp and complete the Irp.
        //

        Irp->IoStatus.Information = (outBufLength<datalen?outBufLength:datalen);

        break;

    case IOCTL_SIOCTL_METHOD_IN_DIRECT:

        //
        // In this type of transfer,  the I/O manager allocates a system buffer
        // large enough to accommodatethe User input buffer, sets the buffer address
        // in Irp->AssociatedIrp.SystemBuffer and copies the content of user input buffer
        // into the SystemBuffer. For the user output buffer, the  I/O manager
        // probes to see whether the virtual address is readable in the callers
        // access mode, locks the pages in memory and passes the pointer to
        // MDL describing the buffer in Irp->MdlAddress.
        //

        SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_IN_DIRECT\n"));

        PrintIrpInfo(Irp);

        inBuf = Irp->AssociatedIrp.SystemBuffer;

        SIOCTL_KDPRINT(("\tData from User in InputBuffer: "));
        PrintChars(inBuf, inBufLength);

        //
        // To access the output buffer, just get the system address
        // for the buffer. For this method, this buffer is intended for transfering data
        // from the application to the driver.
        //

        buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);

        if (!buffer) {
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        SIOCTL_KDPRINT(("\tData from User in OutputBuffer: "));
        PrintChars(buffer, outBufLength);

        //
        // Return total bytes read from the output buffer.
        // Note OutBufLength = MmGetMdlByteCount(Irp->MdlAddress)
        //

        Irp->IoStatus.Information = MmGetMdlByteCount(Irp->MdlAddress);

        //
        // NOTE: Changes made to the  SystemBuffer are not copied
        // to the user input buffer by the I/O manager
        //

      break;

    case IOCTL_SIOCTL_METHOD_OUT_DIRECT:

        //
        // In this type of transfer, the I/O manager allocates a system buffer
        // large enough to accommodate the User input buffer, sets the buffer address
        // in Irp->AssociatedIrp.SystemBuffer and copies the content of user input buffer
        // into the SystemBuffer. For the output buffer, the I/O manager
        // probes to see whether the virtual address is writable in the callers
        // access mode, locks the pages in memory and passes the pointer to MDL
        // describing the buffer in Irp->MdlAddress.
        //


        SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_OUT_DIRECT\n"));

        PrintIrpInfo(Irp);


        inBuf = Irp->AssociatedIrp.SystemBuffer;

        SIOCTL_KDPRINT(("\tData from User : "));
        PrintChars(inBuf, inBufLength);

        //
        // To access the output buffer, just get the system address
        // for the buffer. For this method, this buffer is intended for transfering data
        // from the driver to the application.
        //

        buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);

        if (!buffer) {
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        //
        // Write data to be sent to the user in this buffer
        //

        RtlCopyBytes(buffer, data, outBufLength);

        SIOCTL_KDPRINT(("\tData to User : "));
        PrintChars(buffer, datalen);

        Irp->IoStatus.Information = (outBufLength<datalen?outBufLength:datalen);

        //
        // NOTE: Changes made to the  SystemBuffer are not copied
        // to the user input buffer by the I/O manager
        //

        break;

    default:

        //
        // The specified I/O control code is unrecognized by this driver.
        //

        ntStatus = STATUS_INVALID_DEVICE_REQUEST;
        SIOCTL_KDPRINT(("ERROR: unrecognized IOCTL %x\n",
            irpSp->Parameters.DeviceIoControl.IoControlCode));
        break;
    }

End:
    //
    // Finish the I/O operation by simply completing the packet and returning
    // the same status as in the packet itself.
    //

    Irp->IoStatus.Status = ntStatus;

    IoCompleteRequest( Irp, IO_NO_INCREMENT );

    return ntStatus;
}

用户层请求,可以看到在用户层的请求数据传输都是由DeviceIoControl加不同参数完成

    //
    // Printing Input & Output buffer pointers and size
    //

    printf("InputBuffer Pointer = %p, BufLength = %d\n", InputBuffer,
                        sizeof(InputBuffer));
    printf("OutputBuffer Pointer = %p BufLength = %d\n", OutputBuffer,
                                sizeof(OutputBuffer));
    //
    // Performing METHOD_BUFFERED
    //

    StringCbCopy(InputBuffer, sizeof(InputBuffer),
        "This String is from User Application; using METHOD_BUFFERED");

    printf("\nCalling DeviceIoControl METHOD_BUFFERED:\n");

    memset(OutputBuffer, 0, sizeof(OutputBuffer));

    bRc = DeviceIoControl ( hDevice,
                            (DWORD) IOCTL_SIOCTL_METHOD_BUFFERED,
                            &InputBuffer,
                            (DWORD) strlen ( InputBuffer )+1,
                            &OutputBuffer,
                            sizeof( OutputBuffer),
                            &bytesReturned,
                            NULL
                            );

    if ( !bRc )
    {
        printf ( "Error in DeviceIoControl : %d", GetLastError());
        return;

    }
    printf("    OutBuffer (%d): %s\n", bytesReturned, OutputBuffer);

    //
    // Performing METHOD_NIETHER
    //

    printf("\nCalling DeviceIoControl METHOD_NEITHER\n");

    StringCbCopy(InputBuffer, sizeof(InputBuffer),
               "This String is from User Application; using METHOD_NEITHER");
    memset(OutputBuffer, 0, sizeof(OutputBuffer));

    bRc = DeviceIoControl ( hDevice,
                            (DWORD) IOCTL_SIOCTL_METHOD_NEITHER,
                            &InputBuffer,
                            (DWORD) strlen ( InputBuffer )+1,
                            &OutputBuffer,
                            sizeof( OutputBuffer),
                            &bytesReturned,
                            NULL
                            );

    if ( !bRc )
    {
        printf ( "Error in DeviceIoControl : %d\n", GetLastError());
        return;

    }

    printf("    OutBuffer (%d): %s\n", bytesReturned, OutputBuffer);

    //
    // Performing METHOD_IN_DIRECT
    //

    printf("\nCalling DeviceIoControl METHOD_IN_DIRECT\n");

    StringCbCopy(InputBuffer, sizeof(InputBuffer),
               "This String is from User Application; using METHOD_IN_DIRECT");
    StringCbCopy(OutputBuffer, sizeof(OutputBuffer),
               "This String is from User Application in OutBuffer; using METHOD_IN_DIRECT");

    bRc = DeviceIoControl ( hDevice,
                            (DWORD) IOCTL_SIOCTL_METHOD_IN_DIRECT,
                            &InputBuffer,
                            (DWORD) strlen ( InputBuffer )+1,
                            &OutputBuffer,
                            sizeof( OutputBuffer),
                            &bytesReturned,
                            NULL
                            );

    if ( !bRc )
    {
        printf ( "Error in DeviceIoControl : : %d", GetLastError());
        return;
    }

    printf("    Number of bytes transfered from OutBuffer: %d\n",
                                    bytesReturned);

    //
    // Performing METHOD_OUT_DIRECT
    //

    printf("\nCalling DeviceIoControl METHOD_OUT_DIRECT\n");
    StringCbCopy(InputBuffer, sizeof(InputBuffer),
               "This String is from User Application; using METHOD_OUT_DIRECT");
    memset(OutputBuffer, 0, sizeof(OutputBuffer));
    bRc = DeviceIoControl ( hDevice,
                            (DWORD) IOCTL_SIOCTL_METHOD_OUT_DIRECT,
                            &InputBuffer,
                            (DWORD) strlen ( InputBuffer )+1,
                            &OutputBuffer,
                            sizeof( OutputBuffer),
                            &bytesReturned,
                            NULL
                            );

    if ( !bRc )
    {
        printf ( "Error in DeviceIoControl : : %d", GetLastError());
        return;
    }

    printf("    OutBuffer (%d): %s\n", bytesReturned, OutputBuffer);

    CloseHandle ( hDevice );

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目 录 第1篇 Linux网络开发基础 第1章 Linux操作系统概述 2 1.1 Linux发展历史 2 1.1.1 Linux的诞生和发展 2 1.1.2 Linux名称的由来 1.2 Linux的发展要素 3 1.2.1 UNIX操作系统 4 1.2.2 Minix操作系统 4 1.2.3 POSIX 标准 4 1.3 Linux与UNIX的异同 5 1.4 操作系统类型选择和内核版本的选择 5 1.4.1 常见的不同公司发行的Linux异同 6 1.4.2 内核版本的选择 6 1.5 Linux的系统架构 7 1.5.1 Linux内核的主要模块 7 1.5.2 Linux的文件结构 9 1.6 GNU通用公共许可证 10 1.6.1 GPL许可证的历史 10 1.6.2 GPL的自由理念 10 1.6.3 GPL的基本条款 11 1.6.4 关于GPL许可证的争议 12 1.7 Linux软件开发的可借鉴之处 12 1.8 小结 13 第2章 Linux编程环境 14 2.1 Linux环境下的编辑器 14 2.1.1 vim使用简介 14 2.1.2 使用vim建立文件 15 2.1.3 使用vim编辑文本 16 2.1.4 vim的格式设置 18 2.1.5 vim配置文件.vimrc 19 2.1.6 使用其他编辑器 19 2.2 Linux下的GCC编译器工具集 19 2.2.1 GCC简介 19 2.2.2 编译程序的基本知识 21 2.2.3 单个文件编译成执行文件 22 2.2.4 编译生成目标文件 22 2.2.5 多文件编译 23 2.2.6 预处理 24 2.2.7 编译成汇编语言 24 2.2.8 生成和使用静态链接库 25 2.2.9 生成动态链接库 26 2.2.10 动态加载库 29 2.2.11 GCC常用选项 31 2.2.12 编译环境的搭建 33 2.3 Makefile文件简介 34 2.3.1 一个多文件的工程例子 34 2.3.2 多文件工程的编译 36 2.3.3 Makefile的规则 37 2.3.4 Makefile中使用变量 39 2.3.5 搜索路径 43 2.3.6 自动推导规则 44 2.3.7 递归make 44 2.3.8 Makefile中的函数 46 2.4 用GDB调试程序 47 2.4.1 编译可调试程序 48 2.4.2 使用GDB调试程序 49 2.4.3 GDB常用命令 52 2.4.4 其他的GDB 59 2.5 小结 60 第3章 文件系统简介 61 3.1 Linux下的文件系统 61 3.1.1 Linux下文件的内涵 61 3.1.2 文件系统的创建 62 3.1.3 挂接文件系统 64 3.1.4 索引节点inode 65 3.1.5 普通文件 66 3.1.6 设备文件 66 3.1.7 虚拟文件系统VFS 68 3.2 文件的通用操作方法 72 3.2.1 文件描述符 72 3.2.2 打开创建文件open()、create()函数 72 3.2.3 关闭文件close()函数 76 3.2.4 读取文件read()函数 77 3.2.5 写文件write()函数 79 3.2.6 文件偏移lseek()函数 80 3.2.7 获得文件状态fstat()函数 83 3.2.8 文件空间映射mmap()函数 85 3.2.9 文件属性fcntl()函数 88 3.2.10 文件输入输出控制ioctl()函数 92 3.3 socket文件类型 93 3.4 小结 93 第4章 程序、进程和线程 94 4.1 程序、进程和线程的概念 94 4.1.1 程序和进程的差别 94 4.1.2 Linux环境下的进程 95 4.1.3 进程和线程 96 4.2 进程产生的方式 96 4.2.1 进程号 96 4.2.2 进程复制fork() 97 4.2.3 system()方式 98 4.2.4 进程执行exec()函数系列 99 4.2.5 所有用户态进程的产生进程init 100 4.3 进程间通信和同步 101 4.3.1 半双工管道 101 4.3.2 命名管道 107 4.3.3 消息队列 108 4.3.4 消息队列的一个例子 114 4.3.5 信号量 116 4.3.6 共享内存 121 4.3.7 信号 124 4.4 Linux下的线程 127 4.4.1 多线程编程实例 127 4.4.2 Linux下线程创建函数pthread_create() 129 4.4.3 线程的结束函数pthread_join()和pthread_exit() 129 4.4.4 线程的属性 130 4.4.5 线程间的互斥 132 4.4.6 线程中使用信号量 133 4.5 小结 136 第2篇 Linux用户网络编程 第5章 TCP/IP协议族简介 138 5.1 OSI网络分介绍 138 5.1.1 OSI网络分结构 138 5.1.2 OSI的7网络结构 139 5.1.3 OSI参考模型中的数据传输 140 5.2 TCP/IP协议栈 141 5.2.1 TCP/IP协议栈参考模型 141 5.2.2 主机到网络协议 143 5.2.3 IP协议 144 5.2.4 网际控制报文协议(ICMP) 146 5.2.5 传输控制协议(TCP) 150 5.2.6 用户数据报文协议(UDP) 154 5.2.7 地址解析协议(ARP) 156 5.3 IP地址分类与TCP/UDP端口 158 5.3.1 因特网中IP地址的分类 159 5.3.2 子网掩码(subnet mask address) 161 5.3.3 IP地址的配置 162 5.3.4 端口 163 5.4 主机字节序和网络字节序 163 5.4.1 字节序的含义 164 5.4.2 网络字节序的转换 164 5.5 小结 166 第6章 应用网络服务程序简介 167 6.1 HTTP协议和服务 167 6.1.1 HTTP协议概述 167 6.1.2 HTTP协议的基本过程 168 6.2 FTP协议和服务 170 6.2.1 FTP协议概述 170 6.2.2 FTP协议的工作模式 172 6.2.3 FTP协议的传输方式 172 6.2.4 一个简单的FTP过程 173 6.2.5 常用的FTP工具 173 6.3 TELNET协议和服务 174 6.3.1 远程登录的基本概念 174 6.3.2 使用TELNET协议进行远程登录的工作过程 174 6.3.3 TELNET协议 174 6.4 NFS协议和服务 176 6.4.1 安装NFS服务器和客户端 176 6.4.2 服务器端的设定 176 6.4.3 客户端的操作 177 6.4.4 showmount命令 177 6.5 自定义网络服务 177 6.5.1 xinetd/inetd 178 6.5.2 xinetd服务配置 178 6.5.3 自定义网络服务 179 6.6 小结 180 第7章 TCP网络编程基础 181 7.1 套接字编程基础知识 181 7.1.1 套接字地址结构 181 7.1.2 用户和内核交互过程 183 7.2 TCP网络编程流程 184 7.2.1 TCP网络编程架构 184 7.2.2 创建网络插口函数socket() 186 7.2.3 绑定一个地址端口对bind() 189 7.2.4 监听本地端口listen 192 7.2.5 接受一个网络请求accept() 194 7.2.6 连接目标网络服务器connect() 199 7.2.7 写入数据函数write() 200 7.2.8 读取数据函数read() 201 7.2.9 关闭套接字函数close() 201 7.3 服务器/客户端的简单例子 202 7.3.1 例子功能描述 202 7.3.2 服务器网络程序 203 7.3.3 服务器读取和显示字符串 205 7.3.4 客户端的网络程序 205 7.3.5 客户端读取和显示字符串 206 7.3.6 编译运行程序 206 7.4 截取信号的例子 207 7.4.1 信号处理 207 7.4.2 信号SIGPIPE 208 7.4.3 信号SIGINT 208 7.5 小结 208 第8章 服务器和客户端信息的获取 210 8.1 字节序 210 8.1.1 大端字节序和小端字节序 210 8.1.2 字节序转换函数 212 8.1.3 一个字节序转换的例子 214 8.2 字符串IP地址和二进制IP地址的转换 217 8.2.1 inet_xxx()函数 217 8.2.2 inet_pton()和inet_ntop()函数 219 8.2.3 使用8.2.1节地址转换函数的例子 220 8.2.4 使用函数inet_pton()和函数inet_ntop()的例子 223 8.3 套接字描述符判定函数issockettype() 223 8.3.1 进行文件描述符判定的函数issockettype() 224 8.3.2 main()函数 224 8.4 IP地址与域名之间的相互转换 225 8.4.1 DNS原理 225 8.4.2 获取主机信息的函数 226 8.4.3 使用主机名获取主机信息的例子 228 8.4.4 函数gethostbyname()不可重入的例子 230 8.5 协议名称处理函数 232 8.5.1 xxxprotoxxx()函数 232 8.5.2 使用协议族函数的例子 233 8.6 小结 236 第9章 数据的IO和复用 237 9.1 IO函数 237 9.1.1 使用recv()函数接收数据 237 9.1.2 使用send()函数发送数据 239 9.1.3 使用readv()函数接收数据 240 9.1.4 使用writev()函数发送数据 240 9.1.5 使用recvmsg()函数接收数据 242 9.1.6 使用sendmsg()函数发送数据 244 9.1.7 IO函数的比较 246 9.2 使用IO函数的例子 246 9.2.1 客户端处理框架的例子 246 9.2.2 服务器端程序框架 248 9.2.3 使用recv()和send()函数 249 9.2.4 使用readv()和write()函数 251 9.2.5 使用recvmsg()和sendmsg()函数 253 9.3 IO模型 256 9.3.1 阻塞IO模型 256 9.3.2 非阻塞IO模型 257 9.3.3 IO复用 257 9.3.4 信号驱动IO模型 258 9.3.5 异步IO模型 258 9.4 select()函数和pselect()函数 259 9.4.1 select()函数 259 9.4.2 pselect()函数 261 9.5 poll()函数和ppoll()函数 262 9.5.1 poll()函数 263 9.5.2 ppoll()函数 264 9.6 非阻塞编程 264 9.6.1 非阻塞方式程序设计介绍 264 9.6.2 非阻塞程序设计的例子 264 9.7 小结 266 第10章 基于UDP协议的接收和发送 267 10.1 UDP编程框架 267 10.1.1 UDP编程框图 267
LINUX设备驱动第三版_ 前言 第一章 设备驱动程序简介 设备驱动程序的作用 内核功能划分 设备和模块的分类 安全问题 版本编号 许可证条款 加入内核开发社团 本书概要 第二章 构造和运行模块 设置测试系统 Hello World模块 核心模块与应用程序的对比 编译和装载 内核符号表 预备知识 初始化和关闭 模块参数 在用户空间编写驱动程序 快速参考 第三章 字符设备驱动程序 scull的设计 主设备号和次设备号 一些重要的数据结构 字符设备的注册 open和release scull的内存使用 read和write 试试新设备 快速参考 第四章 调试技术 内核中的调试支持 通过打印调试 通过查询调试 通过监视调试 调试系统故障 调试器和相关工具 第五章 并发和竞态 scull的缺陷 并发及其管理 信号量和互斥体 completion 自旋锁 锁陷阱 除了锁之外的办法 快速参考 第六章 高级字符驱动程序操作 ioctl 阻塞型I/O poll和select 异步通知 定位设备 设备文件的访问控制 快速参考 第七章 时间、延迟及延缓操作 度量时间差 获取当前时间 延迟执行 内核定时器 tasklet 工作队列 快速参考 第八章 分配内存 kmalloc函数的内幕 后备高速缓存 get_free_page和相关函数 vmalloc及其辅助函数 per-CPU变量 获取大的缓冲区 快速参考 第九章 与硬件通信 I/O端口和I/O内存 使用I/O端口 I/O端口示例 使用I/O内存 快速参考 第十章 中断处理 准备并口 安装中断处理例程 实现中断处理例程 顶半部和底半部 中断共享 中断驱动的I/O 快速参考 第十一章 内核的数据类型 使用标准C语言类型 为数据项分配确定的空间大小 接口特定的类型 其他有关移植性的问题 链表 快速参考 第十二章 PCI驱动程序 PCI接口 ISA回顾 PC/104和PC/104+ 其他的PC总线 SBus NuBus 外部总线 快速参考 第十三章 USB驱动程序 USB设备基础 USB和Sysfs USB urb 编写USB驱动程序 不使用urb的USB传输 快速参考 第十四章 Linux设备模型 kobject、kset和子系统 低sysfs操作 热插拔事件的产生 总线、设备和驱动程序 类 各环节的整合 热插拔 处理固件 快速索引 第十五章 内存映射和DMA Linux的内存管理 mmap设备操作 执行直接I/O访问 直接内存访问 快速参考 第十六章 块设备驱动程序 注册 块设备操作 请求处理 其他一些细节 快速参考 第十七章 网络驱动程序 snull设计 连接到内核 net_device结构细节 打开和关闭 数据包传输 数据包的接收 中断处理例程 不使用接收中断 链路状态的改变 套接字缓冲区 MAC 地址解析 定制 ioctl 命令 统计信息 组播 其他知识点详解 快速参考 第十八章 TTY驱动程序 小型TTY驱动程序 tty_driver函数指针 TTY线路设置 ioctls proc和sysfs对TTY设备的处理 tty_driver结构详解 tty_operations结构详解 tty_struct结构详解 快速参考 参考书目 9112405-1_o.jpg (85.53 KB, 下载次数: 50)
目录 第一部分 Windows编程基础 第1章 HelloWindowsCE 1.1 WindowsCE标准Windows的差别 1.1.1 WindowsCE和标准Windows的差别 1.1.2 资源有限的WindowsCE设备 1.1.3 Unicode编码 1.1.4 组件化设计 1.1.5 Win32子集 1.2 仍然是Windows编程 1.3 第一个WindowsCE应用程序 1.3.1 创建第一个WindowsCE应用程序 1.3.2 运行程序 1.3.3 出了什么问题 1.4 Hello2程序 1.5 剖析窗口应用程序 1.5.1 窗口 1.5.2 窗口类 1.5.3 窗口过程 1.5.4 消息的生命期 1.5.5 注册窗口 1.5.6 创建窗口 1.5.7 消息循环 1.5.8 窗口过程 1.6 HelloCE 1.7 运行HelloCE 第2章 在屏幕上绘图 2.1 绘图基础 2.1.1 合法和非法区域 2.1.2 设备上下文 2.2 文本输出 2.2.1 设备上下文属性 2.2.2 TextDemo示例程序 2.2.3 字体 2.2.4 未完成的任务 2.3 位图 2.3.1 设备相关位图 2.3.2 设备无关位图 2.3.3 DIB区域 2.3.4 绘制位图 2.3.5 AlphaBlending 2.4 线和形体 2.4.1 线 2.4.2 形体 2.4.3 填充函数 2.4.4 Shapes示例程序 第3章 输入:键盘、鼠标和触摸屏 3.1 键盘 3.1.1 输入焦点 3.1.2 键盘消息 3.1.3 键盘函数 3.1.4 KeyTrac示例程序 3.2 鼠标和触摸屏 3.2.1 鼠标消息 3.2.2 使用触摸屏 3.2.3 TicTacl示例程序 第4章 窗口、控件和菜单 4.1 子窗口 4.2 窗口管理函数 4.2.1 枚举窗口 4.2.2 寻找窗口 4.2.3 移动窗口 4.2.4 编辑窗口结构的内容 4.3 窗口控件 4.3.1 使用控件工作 4.3.2 按钮控件 4.3.3 编辑控件 4.3.4 列表框控件 4.3.5 组合框控件 4.3.6 静态文本控件 4.3.7 滚动条控件 4.3.8 控件和颜色 4.4 菜单 4.5 资源 4.5.1 资源脚本 4.5.2 图标 4.5.3 加速键 4.5.4 位图 4.5.5 字符串 4.6 DOIView示例程序 第5章 通用控件与WindowsCE 5.1 通用控件编程 5.2 通用控件 5.2.1 命令栏 5.2.2 其他菜单控件 5.2.3 日历控件 5.2.4 时间日期选择器控件 5.2.5 列表视图控件 5.2.6 CapEdit控件 5.3 其他一些通用控件 5.4 不支持的通用控件 第6章 对话框和属性表 6.1 对话框 6.1.1 对话框资源模板 6.1.2 创建对话框 6.1.3 对话框过程 6.1.4 非模态的对话框 6.1.5 属性表 6.1.6 通用对话框 6.2 DlgDemo范例程序 第二部分WindOWSCE编程 第7章 内存管理 7.1 内存基础知识 7.1.1 关于RAM 7.1.2 关于ROM 7.1.3 关于虚拟内存 7.1.4 应用程序的地址空间 7.2 不同类型的内存分配 7.2.1 虚拟内存 7.2.2 堆 7.2.3 本地堆 7.2.4 独立堆 7.2.5 栈 7.2.6 静态数据 7.2.7 字符串资源 7.2.8 选择适当的内存类型 7.2.9 管理低内存状态 第8章 模块、进程和线程 8.1 模块 8.2 进程 8.2.1 创建进程 8.2.2 终止进程 8.2.3 其他进程 8.3 线程 8.3.1 系统调度器 8.3.2 创建线程 8.3.3 设置和查询线程优先级 8.3.4 设置线程时间片 8.3.5 挂起和恢复线程 8.4 纤程 8.5 线程本地存储 8.6 同步 8.6.1 事件 8.6.2 等待 8.6.3 信号量 8.6.4 互斥量 8.6.5 复制同步旬柄 8.6.6 临界区 8.6.7 互锁变量访问 8.7 进程间通信 8.7.1 查找其他进程 8.7.2 WM-COPYDATA 8.7.3 命名内存映射对象 8.7.4 点对点消息队列 8.7.5 使用文件和数据库通信 8.8 XTalk示例程序 8.9 异常处理 8.9.1 C++异常处理 8.9.2 Win32异常处理 第9章 WindLOWSCE文件系统 9.1 WindowsCE文件系统API 9.1.1 标准文件VO 9.1.2 内存映射文件 9.1.3 文件系统浏览 9.2 存储处理 9.2.1 对象存储 9.2.2 使用文件API来访问卷 9.2.3 存储管理器 第10章 注册表 10.1 注册表组织 l0.2 注册表API l0.2.1 打开和创建主键 10.2.2 读取注册表值 10.2.3 写人注册表值 10.2.4 删除注册表主键和值 10.2.5 枚举注册表主键 l0.2.6 刷新注册表主键 10.2.7 注册表改动通知 10.2.8 RegView示例程序 第11章 WindowsCE数据库 11.1 两种数据库 11.2 基本概念 11.3 数据库.API 第12章 通知 12.1 用户通知 12.2 计时器事件通知 12.3 系统事件通知 12.4 NoteDemo示例程序 12.5 查询已设定的通知 12.6 气泡通知 12.6.1 添加气泡通知 12.6.2 修改气泡通知 12.6.3 删除气泡通知 第三部分高级WindOWSCE 第13章 windOWSCE网络 13.1 Windows网络支持 13.1.1 WNet函数 13.1.2 ListNet示例程序 13.2 TCP/IP编程 13.2.1 套接字编程 13.2.2 阻塞套接字与非阻塞套接字 第14章 设备间通信 14.1 红外通信 14.1.1 红外基础 14.1.2 设备发现 14.1.3 发布红外服务 14.1.4 查询和设置红外套接字选项 14.1.5 MySquirt示例程序 14.2 蓝牙 14.2.1 蓝牙协议栈 14.2.2 蓝牙发现 14.2.3 发布一个服务 14.2.4 通过WinSock进行蓝牙通信 14.2.5 通过虚拟COM端口进行蓝牙通信 14.2.6 BtSquirt示例程序 第15章 系统程序设计 15.1 WindowsCE的内存体系结构 15.1.1 应用程序的地址空间 15.1.2 内核态的地址空间 15.2 编写跨平台的WindowsCE应用程序 15.2.1 平台与操作系统版本 15.2.2 编译时的版本确定 15.2.3 显式链接 15.2.4 运行时的版本检测 15.3 电源管理 15.3.1 关机的含义 15.3.2 查询电源状态 15.3.3 电源管理器 15.3.4 不使用电源管理器来管理电源 第16章 串行通信 16.1 基本串行通信 16.1.1 打开和关闭串行端口 16.1.2 读写串行端口 16.1.3 异步串行I/O 16.1.4 配置串行端口 16.1.5 设置端口的超时值 16.1.6 查询串行驱动程序的能力 16.1.7 控制串行端口 16.1.8 清除错误并查询状态 16.1.9 保持活动状态 16.2 CeChat示例程序 第17章 设备驱动程序和服务 17.1 驱动程序基础 17.1.1 驱动程序的名称 17.1.2 设备驱动加载过程 17.1.3 枚举活动的驱动? 17.1.4 读写设备驱动 17.2 编写WindowsCE流式设备驱动 17.2.1 流式驱动的入口函数 17.2.2 缓冲区管理 17.2.3 驱动程序接口类 17.2.4 设备驱动程序的电源管理 17.3 设备驱动程序的构建 17.3.1 DebugZone 17.3.2 Gentle驱动程序示例 17.4 服务 17.4.1 服务的体系结构 17.4.2 服务的生命周期 17.4.3 应用程序对服务的控制 17.4.4 服务DLL的人口函数 17.4.5 服务的IOCTL命令 17.4.6 超级服务 17.4.7 Services.exe的命令行 17.4.8 TickSrv示例服务
目录 第一部分 Windows编程基础 第1章 HelloWindowsCE 1.1 WindowsCE标准Windows的差别 1.1.1 WindowsCE和标准Windows的差别 1.1.2 资源有限的WindowsCE设备 1.1.3 Unicode编码 1.1.4 组件化设计 1.1.5 Win32子集 1.2 仍然是Windows编程 1.3 第一个WindowsCE应用程序 1.3.1 创建第一个WindowsCE应用程序 1.3.2 运行程序 1.3.3 出了什么问题 1.4 Hello2程序 1.5 剖析窗口应用程序 1.5.1 窗口 1.5.2 窗口类 1.5.3 窗口过程 1.5.4 消息的生命期 1.5.5 注册窗口 1.5.6 创建窗口 1.5.7 消息循环 1.5.8 窗口过程 1.6 HelloCE 1.7 运行HelloCE 第2章 在屏幕上绘图 2.1 绘图基础 2.1.1 合法和非法区域 2.1.2 设备上下文 2.2 文本输出 2.2.1 设备上下文属性 2.2.2 TextDemo示例程序 2.2.3 字体 2.2.4 未完成的任务 2.3 位图 2.3.1 设备相关位图 2.3.2 设备无关位图 2.3.3 DIB区域 2.3.4 绘制位图 2.3.5 AlphaBlending 2.4 线和形体 2.4.1 线 2.4.2 形体 2.4.3 填充函数 2.4.4 Shapes示例程序 第3章 输入:键盘、鼠标和触摸屏 3.1 键盘 3.1.1 输入焦点 3.1.2 键盘消息 3.1.3 键盘函数 3.1.4 KeyTrac示例程序 3.2 鼠标和触摸屏 3.2.1 鼠标消息 3.2.2 使用触摸屏 3.2.3 TicTacl示例程序 第4章 窗口、控件和菜单 4.1 子窗口 4.2 窗口管理函数 4.2.1 枚举窗口 4.2.2 寻找窗口 4.2.3 移动窗口 4.2.4 编辑窗口结构的内容 4.3 窗口控件 4.3.1 使用控件工作 4.3.2 按钮控件 4.3.3 编辑控件 4.3.4 列表框控件 4.3.5 组合框控件 4.3.6 静态文本控件 4.3.7 滚动条控件 4.3.8 控件和颜色 4.4 菜单 4.5 资源 4.5.1 资源脚本 4.5.2 图标 4.5.3 加速键 4.5.4 位图 4.5.5 字符串 4.6 DOIView示例程序 第5章 通用控件与WindowsCE 5.1 通用控件编程 5.2 通用控件 5.2.1 命令栏 5.2.2 其他菜单控件 5.2.3 日历控件 5.2.4 时间日期选择器控件 5.2.5 列表视图控件 5.2.6 CapEdit控件 5.3 其他一些通用控件 5.4 不支持的通用控件 第6章 对话框和属性表 6.1 对话框 6.1.1 对话框资源模板 6.1.2 创建对话框 6.1.3 对话框过程 6.1.4 非模态的对话框 6.1.5 属性表 6.1.6 通用对话框 6.2 DlgDemo范例程序 第二部分WindOWSCE编程 第7章 内存管理 7.1 内存基础知识 7.1.1 关于RAM 7.1.2 关于ROM 7.1.3 关于虚拟内存 7.1.4 应用程序的地址空间 7.2 不同类型的内存分配 7.2.1 虚拟内存 7.2.2 堆 7.2.3 本地堆 7.2.4 独立堆 7.2.5 栈 7.2.6 静态数据 7.2.7 字符串资源 7.2.8 选择适当的内存类型 7.2.9 管理低内存状态 第8章 模块、进程和线程 8.1 模块 8.2 进程 8.2.1 创建进程 8.2.2 终止进程 8.2.3 其他进程 8.3 线程 8.3.1 系统调度器 8.3.2 创建线程 8.3.3 设置和查询线程优先级 8.3.4 设置线程时间片 8.3.5 挂起和恢复线程 8.4 纤程 8.5 线程本地存储 8.6 同步 8.6.1 事件 8.6.2 等待 8.6.3 信号量 8.6.4 互斥量 8.6.5 复制同步旬柄 8.6.6 临界区 8.6.7 互锁变量访问 8.7 进程间通信 8.7.1 查找其他进程 8.7.2 WM-COPYDATA 8.7.3 命名内存映射对象 8.7.4 点对点消息队列 8.7.5 使用文件和数据库通信 8.8 XTalk示例程序 8.9 异常处理 8.9.1 C++异常处理 8.9.2 Win32异常处理 第9章 WindLOWSCE文件系统 9.1 WindowsCE文件系统API 9.1.1 标准文件VO 9.1.2 内存映射文件 9.1.3 文件系统浏览 9.2 存储处理 9.2.1 对象存储 9.2.2 使用文件API来访问卷 9.2.3 存储管理器 第10章 注册表 10.1 注册表组织 l0.2 注册表API l0.2.1 打开和创建主键 10.2.2 读取注册表值 10.2.3 写人注册表值 10.2.4 删除注册表主键和值 10.2.5 枚举注册表主键 l0.2.6 刷新注册表主键 10.2.7 注册表改动通知 10.2.8 RegView示例程序 第11章 WindowsCE数据库 11.1 两种数据库 11.2 基本概念 11.3 数据库.API 第12章 通知 12.1 用户通知 12.2 计时器事件通知 12.3 系统事件通知 12.4 NoteDemo示例程序 12.5 查询已设定的通知 12.6 气泡通知 12.6.1 添加气泡通知 12.6.2 修改气泡通知 12.6.3 删除气泡通知 第三部分高级WindOWSCE 第13章 windOWSCE网络 13.1 Windows网络支持 13.1.1 WNet函数 13.1.2 ListNet示例程序 13.2 TCP/IP编程 13.2.1 套接字编程 13.2.2 阻塞套接字与非阻塞套接字 第14章 设备间通信 14.1 红外通信 14.1.1 红外基础 14.1.2 设备发现 14.1.3 发布红外服务 14.1.4 查询和设置红外套接字选项 14.1.5 MySquirt示例程序 14.2 蓝牙 14.2.1 蓝牙协议栈 14.2.2 蓝牙发现 14.2.3 发布一个服务 14.2.4 通过WinSock进行蓝牙通信 14.2.5 通过虚拟COM端口进行蓝牙通信 14.2.6 BtSquirt示例程序 第15章 系统程序设计 15.1 WindowsCE的内存体系结构 15.1.1 应用程序的地址空间 15.1.2 内核态的地址空间 15.2 编写跨平台的WindowsCE应用程序 15.2.1 平台与操作系统版本 15.2.2 编译时的版本确定 15.2.3 显式链接 15.2.4 运行时的版本检测 15.3 电源管理 15.3.1 关机的含义 15.3.2 查询电源状态 15.3.3 电源管理器 15.3.4 不使用电源管理器来管理电源 第16章 串行通信 16.1 基本串行通信 16.1.1 打开和关闭串行端口 16.1.2 读写串行端口 16.1.3 异步串行I/O 16.1.4 配置串行端口 16.1.5 设置端口的超时值 16.1.6 查询串行驱动程序的能力 16.1.7 控制串行端口 16.1.8 清除错误并查询状态 16.1.9 保持活动状态 16.2 CeChat示例程序 第17章 设备驱动程序和服务 17.1 驱动程序基础 17.1.1 驱动程序的名称 17.1.2 设备驱动加载过程 17.1.3 枚举活动的驱动? 17.1.4 读写设备驱动 17.2 编写WindowsCE流式设备驱动 17.2.1 流式驱动的入口函数 17.2.2 缓冲区管理 17.2.3 驱动程序接口类 17.2.4 设备驱动程序的电源管理 17.3 设备驱动程序的构建 17.3.1 DebugZone 17.3.2 Gentle驱动程序示例 17.4 服务 17.4.1 服务的体系结构 17.4.2 服务的生命周期 17.4.3 应用程序对服务的控制 17.4.4 服务DLL的人口函数 17.4.5 服务的IOCTL命令 17.4.6 超级服务 17.4.7 Services.exe的命令行 17.4.8 TickSrv示例服务

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值