驱动程序简单开发

我们学习程序设计,都是从“Hello World”开始的,驱动程序也不例外,今天我就写一个驱动版的“Hello World”来热热身,目的希望大家能对驱动程序的基本框架有所了解。

驱动程序分为2类,一个是Kernel模式驱动,另一个是Windows模式驱动,2种模式本质是相同,但细节不同,本文介绍的是内核模式驱动和驱动程序的安装、使用。

驱动程序同普通的EXE,DLL一样,都属于PE文件,而且都有一个入口函数。但EXE中,入口函数是main()/WinMain()和Unicode的wmain()/wWinmain(),DLL的入口函数 
则可有可无,它是DllMain()。驱动程序也有入口函数,而且是必须的,它是DriverEntry(),再次提示,它是必须的,因为I/O管理器会首先调用驱动程序的DriverEntry() 
,它的作用就像DllMain()--完成一些初始化工作。DriverEntry()一共有2个参数:1)PDRIVER_OBJECT DriverObject,指向驱动程序对象的指针,我们操作驱动程序, 
全靠它,它是由I/O管理器传递进来的;2)PUNICODE_STRING RegistryPath,驱动程序的服务主键,这个参数的使用并不多,但要注意,在DriverEntry()返回后,它可能 
会消失,所以如果需要使用,记住先要保存下来。DriverEntry()的返回一个NTSTATUS值,它是一个ULONG值,具体的定义,请参见DDK中的NTSTATUS.H头文件,里边有详细 
的定义。

既然要写驱动版的“Hello World”,就需要确定如何来与驱动程序通信,常用的共享内存,共享事件,IOCTL宏,或者直接用ReadFile()或WriteFile()进行读写,在本文

里我就采用一种简单的、但又很常用的IOCTL宏,它依赖的IRP派遣例程是IRP_MJ_DEVICE_CONTROL,Win32程序使用DeviceIoControl()与驱动进行通信,根据不同的IOCTL宏,

输出不同的调试信息。为了简便,我并没有使用ReadFile()将信息读出来,而是直接用DbgPrint()输出,所以需要使用DbgView查看,其他调试工具也可以。PS:偷懒!

驱动程序与I/O管理器通信,使用的是IRP,即I/O请求包。IRP分为2部分:1)IRP首部;2)IRP堆栈。IRP首部信息如下:

IRP首部:

IO_STATUS_BLOCK IoStatus                 包含I/O请求的状态  
  
PVOID AssociatedIrp.SystemBuffer         如果执行缓冲区I/O,这个指针指向系统缓冲区  
  
PMDL MdlAddress                          如果直接I/O,这个指针指向用户缓冲区的存储器描述符表  
  
PVOID UserBuffer                         I/O缓冲区的用户空间地址

IRP堆栈:

UCHAR MajorFunction               指示IRP_MJ_XXX派遣例程  
  
UCHAR MinorFunction               同上,一般文件系统和SCSI驱动程序使用它  
  
union Parameters                  MajorFunction的联合类型  
{  
struct Read                       IRP_MJ_READ的参数  
ULONG Length  
ULONG Key  
LARGE_INTEGER ByteOffset  
  
struct Write                      IRP_MJ_WRITE的参数  
ULONG Length  
ULONG Key  
LARGE_INTEGER ByteOffset  
  
struct DeviceIoControl            IRP_MJ_DEVICE_CONTROL和IRP_MJ_INTERNAL_DEVICE_CONTROL的参数  
ULONG OutputBufferLength  
ULONG InputBufferLength  
ULONG IoControlCode  
PVOID Type3InputBuffer  
}   
PDEVICE_OBJECT DeviceObject       请求的目标设备对象的指针  
  
PFILE_OBJECT FileObject           请求的目标文件对象的指针,如果有的话

操作IRP。对于不同的IRP函数,操作也是不同的:有的只操作IRP首部;有的只操作IRP堆栈;还有操作IRP整体,

下面是一些常用的函数:

IRP整体:

名称                     描述                         调用者 
IoStartPacket           发送IRP到Start I/O例程           Dispatch  
  
IoCompleteRequest       表示所有的处理完成               DpcForIsr  
  
IoStartNextPacket       发送下一个IRP到Start I/O例程     DpcForIsr  
  
IoCallDriver            发送IRP请求                      Dispatch  
  
IoAllocateIrp           请求另外的IRP                    Dispatch  
  
IoFreeIrp               释放驱动程序分配的IRP            I/O Completion

IRP堆栈:

名称                            描述                         调用者 
IoGetCurrentIrpStackLocation   得到调用者堆栈的指针             Dispatch  
    
IoMarkIrpPending               为进一步的处理标记调用者I/O堆栈  Dispatch  
  
IoGetNextIrpStackLocation      得到下一个驱动程序的I/O堆栈的指针   Dispatch  
  
IoSetNextIrpStackLocation      将I/O堆栈指针压入堆栈            Dispatc

在驱动程序,IRP派遣例程起着很重要的作用,每个IRP派遣例程,几乎都有对应的Win32函数,下面是几个常用的:

IRP派遣例程:

名称                            描述                         调用者 
IRP_MJ_CREATE                   请求一个句柄                   CreateFile  
  
IRP_MJ_CLEANUP                  在关闭句柄时取消悬挂的IRP      CloseHandle  
  
IRP_MJ_CLOSE                    关闭句柄                       CloseHandle  
  
IRP_MJ_READ                     从设备得到数据                 ReadFile  
  
IRP_MJ_WRITE                    传送数据到设备                 WriteFile  
  
IRP_MJ_DEVICE_CONTROL           控制操作(利用IOCTL宏)        DeviceIoControl  
  
IRP_MJ_INTERNAL_DEVICE_CONTROL  控制操作(只能被内核调用)       N/A  
  
IRP_MJ_QUERY_INFORMATION        得到文件的长度                 GetFileSize  
  
IRP_MJ_SET_INFORMATION          设置文件的长度                 SetFileSize  
  
IRP_MJ_FLUSH_BUFFERS            写输出缓冲区或者丢弃输入缓冲区 FlushFileBuffers FlushConsoleInputBuffer PurgeComm  
  
IRP_MJ_SHUTDOWN                 系统关闭                       InitiateSystemShutdown

=================================================================================================================================

下面开始写我们的驱动版的“Hello World”,程序很简单,先介绍一下流程:

1,调用IoCreateDevice()创建一个设备,并返回一个设备对象。 
2,调用IoCreateSynbolicLink()创建一个符号连接,使Win32程序可以使用驱动程序 
3,设置IRP_MJ_DEVICE_CONTROL派遣例程HelloWorldDispatch()和卸载例程HelloWorldUnLoad()。

如果Win32程序使用DeviceIoControl(),则执行HelloWorldDispatch()函数 
4,调用IoGetCurrentIrpStackLocation()得到当前调用者的IRP指针 
5,取得IO控制代码,完成后使用IoCompleteRequest()完成IRP操作

如果使用ControlService()停止驱动程序,则执行HelloWorldUnLoad()函数 
4,调用IoDeleteSymbolicLink()删除符号连接 
5,调用IoDeleteDevice()删除已建立的设备

驱动入口DriverEntry()

//创建设备 
IoCreateDevice(DriverObject,        //驱动程序对象 
               0,                   //扩展设备的大小,由于不需要,所以置0 
               &DeviceNameString,   //设备名称 
               FILE_DEVICE_UNKNOWN, //设备类型 
               0,                   //指示设备允许的操作 
               FALSE,               //如果为TRUE,表示只能有一个线程使用该设备,为FALSE,则没有限制 
               &lpDeviceObject);    //返回的设备对象

//创建符号连接 
IoCreateSymbolicLink(&DeviceLinkString,   //存放符号连接的UNICODE_STRING 
                     &DeviceNameString);  //设备名称

//派遣例程和卸载例程 
DriverObject->MajorFunction[IRP_MJ_CREATE]= 
    DriverObject->MajorFunction[IRP_MJ_CLOSE]= 
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=HelloWorldDispatch; 
DriverObject->DriverUnload=HelloWorldUnLoad;

IRP派遣例程HelloWorldDispatch()

IrpStack=IoGetCurrentIrpStackLocation(pIrp);   //得到当前调用者的IRP堆栈

//获取IO控制代码,并执行指定操作,这里只是DbgPrint() 
IoControlCodes=IrpStack->Parameters.DeviceIoControl.IoControlCode; 
switch (IoControlCodes)  { 
......

IoCompleteRequest(pIrp,IO_NO_INCREMENT);   //完成IRP操作

卸载例程HelloWorldUnLoad()

//删除符号连接和设备 
IoDeleteSymbolicLink(&DeviceLinkString); 
IoDeleteDevice(DriverObject->DeviceObject);

=================================================================================================================================

完整代码:

=================================================================================================================================

驱动程序的编译需要使用DDK中的build实用程序,它是一个命令行程序,使用不是很方便。VC知识库有一篇在VC++ 6.0中编译驱动的文章,有兴趣可以去看看。

1,makefile 
编译驱动程序,首先应该准备一个makefile,这个文件很简单,只有一句代码: 

# DO NOT EDIT THIS FILE!!!  Edit ./sources. if you want to add a new source 
# file to this component.  This file merely indirects to the real make file 
# that is shared by all the driver components of the Windows NT DDK 
#

!INCLUDE $(NTMAKEENV)/makefile.def

正如描述的那样,不要修改这个文件---它是通用的!

2,sources 
准备的第二个文件就是sources,它描述了一些编译的细节。针对本文的程序,sources文件的内容是这样的: 
TARGETNAME=HelloWorld   //驱动名称 
TARGETPATH=.            //编译后SYS的路径 
TARGETTYPE=DRIVER       //类型为驱动程序

SOURCES= HelloWorld.c   //只有一个源文件

有了这2个文件后,就可以使用build进行编译了。进入「开始」菜单/程序/Development Kits/Windows 2000 DDK,
分别有3个CMD程序:1)Checked 64 Bit Build Environment,“Debug”的64位版本;2)Checked Build Environment 
“Debug”的32位版本;3)Free Build Environment,“Release”的32位版本。不用说,肯定是使用Free Build Environment。

New or updated MSVC detected.  Updating DDK environment....

Setting environment for using Microsoft Visual C++ tools. 
Starting dirs creation...Completed.

C:/NTDDK>cd/

C:/>cd HelloWorld

C:/HelloWorld>build 
BUILD: Object root set to: ==> objfre 
BUILD: /i switch ignored 
BUILD: Compile and Link for i386 
BUILD: Loading c:/NTDDK/build.dat... 
BUILD: Computing Include file dependencies: 
BUILD: Examining c:/helloworld directory for files to compile. 
    c:/helloworld - 1 source files (127 lines) 
BUILD: Saving c:/NTDDK/build.dat... 
BUILD: Compiling c:/helloworld directory 
Compiling - helloworld.c for i386 
BUILD: Linking c:/helloworld directory 
Linking Executable - i386/helloworld.sys for i386 
BUILD: Done

1 file compiled 
    1 executable built

C:/HelloWorld>

现在C:/HelloWorld/i386目录下,就有了HelloWorld.sys。

=================================================================================================================================

驱动程序的安装如同安装服务一样,唯一不同的是,创建服务时,类型是内核驱动,其他跟操作服务没什么区别。

安装驱动程序流程: 
1,调用OpenSCManager()打开服务控制管理器 
2,调用CreateService()创建一个服务,服务类型为内核驱动 
3,调用OpenService()取得服务句柄 
启动服务 
4,调用StartService()启动服务 
停止服务 
4,调用ControlService()停止服务 
删除服务 
4,调用DeleteService()删除服务 
5,调用CloseServiceHandle()关闭服务句柄

操作驱动程序流程:  
1,调用CreateFile()取得设备句柄 
2,调用DeviceIoControl()传递I/O控制代码 
3,调用CloseHandle()关闭设备句柄

http://www.xfocus.net/tools/200411/882.html 
这里有一个完整的驱动安装程序,所以我就不写了,只给出操作驱动程序的代码

完整代码:

=================================================================================================================================

参考资料

《Windows 2000 DDK》

《Windows 2000 驱动程序设计》

附录代码:

#ifndef __HELLOWORLD_C__  
#define __HELLOWORLD_C__

#define DEBUGMSG

#include <ntddk.h>

#define DEVICE_HELLO_INDEX 0x860

//2个IOCTL宏  
#define START_HELLPWORLD CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_HELLO_INDEX,METHOD_BUFFERED,FILE_ANY_ACCESS) 
#define STOP_HELLPWORLD  CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_HELLO_INDEX+1,METHOD_BUFFERED,FILE_ANY_ACCESS)

#define NT_DEVICE_NAME L"//Device//HelloWorld"        //设备名称  
#define DOS_DEVICE_NAME L"//DosDevices//HelloWorld"   //符号连接

NTSTATUS HelloWorldDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp);

VOID HelloWorldUnLoad (IN PDRIVER_OBJECT DriverObject);

//驱动入口  
NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)  
{  
    NTSTATUS ntStatus=STATUS_SUCCESS;  
    PDEVICE_OBJECT lpDeviceObject=NULL;       //指向设备对象的指针  
    UNICODE_STRING DeviceNameString={0};      //设备名称  
    UNICODE_STRING DeviceLinkString={0};      //符号连接

//调试信息  
    #ifdef DEBUGMSG  
           DbgPrint("Starting DriverEntry()/n");  
    #endif

RtlInitUnicodeString(&DeviceNameString,NT_DEVICE_NAME);  //初始化Unicode字符串  
    //创建设备  
    ntStatus=IoCreateDevice(DriverObject,0,&DeviceNameString,FILE_DEVICE_UNKNOWN,0,FALSE,&lpDeviceObject);

//使用NT_SUCCESS宏检测函数调用是否成功  
    if (!NT_SUCCESS(ntStatus))  
    {  
        #ifdef DEBUGMSG  
               DbgPrint("IoCreateDevice() error reports 0x%08X/n",ntStatus);  
        #endif  
        return ntStatus;  
    }

RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);  
    //创建符号连接  
    ntStatus=IoCreateSymbolicLink(&DeviceLinkString,&DeviceNameString);

if (!NT_SUCCESS(ntStatus))  
    {  
        #ifdef DEBUGMSG  
               DbgPrint("IoCreateSymbolicLink() error reports 0x%08X/n",ntStatus);  
        #endif  
        if (lpDeviceObject)  
            IoDeleteDevice(lpDeviceObject);  
        return ntStatus;  
    }

//设置IRP派遣例程和卸载例程  
    DriverObject->MajorFunction[IRP_MJ_CREATE]=  
    DriverObject->MajorFunction[IRP_MJ_CLOSE]=  
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=HelloWorldDispatch;  
    DriverObject->DriverUnload=HelloWorldUnLoad;

return ntStatus;  
}

NTSTATUS HelloWorldDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp)  
{  
    NTSTATUS ntStatus=STATUS_SUCCESS;  
    PIO_STACK_LOCATION IrpStack=NULL;   //IRP堆栈  
    ULONG IoControlCodes=0;             //I/O控制代码

//设置IRP状态  
    pIrp->IoStatus.Status=STATUS_SUCCESS;  
    pIrp->IoStatus.Information=0;

#ifdef DEBUGMSG  
           DbgPrint("Starting HelloWorldDispatch()/n");  
    #endif

IrpStack=IoGetCurrentIrpStackLocation(pIrp);    //得到当前调用者的IRP

switch (IrpStack->MajorFunction)  
    {  
            case IRP_MJ_CREATE:  
                 #ifdef DEBUGMSG  
                        DbgPrint("IRP_MJ_CREATE/n");  
                 #endif  
                 break;

case IRP_MJ_CLOSE:  
                 #ifdef DEBUGMSG  
                        DbgPrint("IRP_MJ_CLOSE/n");  
                 #endif  
                 break;

case IRP_MJ_DEVICE_CONTROL:

#ifdef DEBUGMSG  
                        DbgPrint("IRP_MJ_DEVICE_CONTROL/n");  
                 #endif

//取得I/O控制代码  
                 IoControlCodes=IrpStack->Parameters.DeviceIoControl.IoControlCode;

switch (IoControlCodes)  
                 {  
                         //启动  
                         case START_HELLPWORLD:  
                              DbgPrint("Starting /"Hello World/"/n");  
                              break;

//停止  
                         case STOP_HELLPWORLD:  
                              DbgPrint("Stoping /"Hello World/"/n");  
                              break;

default:  
                              pIrp->IoStatus.Status=STATUS_INVALID_PARAMETER;  
                              break;  
                 }

break;

default:  
                 break;  
    }

ntStatus=pIrp->IoStatus.Status;  
    IoCompleteRequest(pIrp,IO_NO_INCREMENT);

return ntStatus;  
}

VOID HelloWorldUnLoad (IN PDRIVER_OBJECT DriverObject)  
{  
     UNICODE_STRING DeviceLinkString={0};  
     PDEVICE_OBJECT DeviceObjectTemp1=NULL;  
     PDEVICE_OBJECT DeviceObjectTemp2=NULL;

#ifdef DEBUGMSG  
            DbgPrint("Starting HelloWorldUnLoad()/n");  
     #endif

RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);

if (DeviceLinkString.Buffer)  
         IoDeleteSymbolicLink(&DeviceLinkString);

if (DriverObject)  
     {  
         DeviceObjectTemp1=DriverObject->DeviceObject;

while (DeviceObjectTemp1)  
         {  
                DeviceObjectTemp2=DeviceObjectTemp1;  
                DeviceObjectTemp1=DeviceObjectTemp1->NextDevice;  
                IoDeleteDevice(DeviceObjectTemp2);  
         }  
     }  
}

#endif

用户态程序:

#define DEBUGMSG

#include <windows.h>  
#include <winioctl.h>  
#include <stdio.h>

#define DEVICE_FILTER_INDEX 0x860

#define START_HELLPWORLD CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_FILTER_INDEX,METHOD_BUFFERED,FILE_ANY_ACCESS) 
#define STOP_HELLPWORLD CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_FILTER_INDEX+1,METHOD_BUFFERED,FILE_ANY_ACCESS)

#define erron GetLastError()

#define MY_DEVICE_NAME "////.//HelloWorld"

#define MY_DEVICE_START "-start"  
#define MY_DEVICE_STOP "-stop"

BOOL DriverControl (TCHAR *Maik);

void Usage (TCHAR *Paramerter);

int main (int argc,TCHAR *argv[])  
{  
    if (argc!=2)  
    {  
        Usage(argv[0]);  
        return 0;  
    }

if (strcmpi(argv[1],MY_DEVICE_START)==0 || strcmpi(argv[1],MY_DEVICE_STOP)==0)  
        DriverControl(argv[1]);  
    else  
    {  
        Usage(argv[0]);  
        return 0;  
    }

return 0;  
}

BOOL DriverControl (TCHAR *Maik)  
{  
     HANDLE hDevice=NULL;  //设备句柄

//获得设备句柄  
     hDevice=CreateFile(MY_DEVICE_NAME,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

if (hDevice==INVALID_HANDLE_VALUE)  
     {  
         #ifdef DEBUGMSG  
                printf("CreateFile() GetLastError reports %d/n",erron);  
         #endif  
         return FALSE;  
     }

//启动  
     if (strcmpi(Maik,MY_DEVICE_START)==0)  
     {  
         //传递启动的I/O控制代码  
         if (!(DeviceIoControl(hDevice,START_HELLPWORLD,NULL,0,NULL,0,NULL,NULL)))  
         {  
             #ifdef DEBUGMSG  
                    printf("DeviceIoControl() GetLastError reports %d/n",erron);  
             #endif  
             CloseHandle(hDevice);  
             return FALSE;  
         }  
     }

//停止  
     if (strcmpi(Maik,MY_DEVICE_STOP)==0)  
     {  
         //传递停止的I/O控制代码  
         if (!(DeviceIoControl(hDevice,STOP_HELLPWORLD,NULL,0,NULL,0,NULL,NULL)))  
         {  
             #ifdef DEBUGMSG  
                    printf("DeviceIoControl() GetLastError reports %d/n",erron);  
             #endif  
             CloseHandle(hDevice);  
             return FALSE;  
         }  
     }

if (hDevice)  
         CloseHandle(hDevice);  //关闭句柄

return TRUE;  
}

void Usage (TCHAR *Paramerter)  
{  
     fprintf(stderr,"============================================================================/n" 
             "      驱动版Hello World/n"  
             "作者:dahubaobao[E.S.T]/n"  
             "主页:www.eviloctal.com/n"  
             "OICQ:382690/n/n"  
             "%s -start/t启动/n"  
             "%s -stop /t停止/n/n"  
             "本程序只是用做代码交流,如有错误,还请多多包含!/n"  
             "============================================================================/n"  
             ,Paramerter,Paramerter);  
}

文章来自: dahubaobao.eviloctal.org
引用通告地址: http://www.wesoho.com/trackback.asp?tbID=1456

时间: 2024-11-08 11:06:52

驱动程序简单开发的相关文章

Notepad++搭建Python简单开发环境(nppexec插件版)

Notepad++搭建Python简单开发环境(nppexec插件版)  原地址:http://blog.sina.com.cn/s/blog_55eb21950101daty.html 1.打开Notepad++,选择菜单Plugin(插件)->Plugin Manager->Show Plugin Manager,打开插件管理器,在”Available”选项卡中找到NppExec2.勾选NppExec,然后Install,下载完成后,一切Yes,OK3.重新启动Notepad++,NppE

IOS游戏源码下载之简易版雷电(2.2.3版本)源码完整下载和简单开发教程

 头回写教程这玩意,真不知道要写些什么,所以主要就是共享下我的代码,和一些重要功能的讲解吧,各位如果有啥不懂的可以回帖提问哟. 其实这个demo(为何叫demo呢,因为我真不敢称这个为游戏呀)是我初学cocos2d-x两周的时候写的,所以可能写的不是很好(好吧,其实现在写的东西也不好),当初主要还是靠着度娘和TestCpp学的,所以在此还是要强调一下TestCpp的重要性,要好好把它看一遍哟,以后你想实现什么功能就可以去翻看了. 好了,言归正传,还是介绍下我写的这个demo了,在此先华丽丽的

用Quick3.3简单开发微信打飞机 (三)----------------------------- 添加爆炸动画和子弹与敌机的碰撞

用Quick3.3简单开发微信打飞机03 添加爆炸动画和子弹与敌机的碰撞 这个就作为最后一篇吧,当然,可以扩展的方面还有很多,比如分数的记录,结算界面还有一些小道具等,就不添加了.这只是当作一个简单的入门,而在这个入门中确实学到了不少东西.而那些没添加的东西呢,其实,就没那么重要了.没有太难的知识点.所以,就没必要纠结太长时间了. 碰撞检测: 碰撞检测重新写了一个计时器,这个计时器是每帧调用的,也就是每秒调用60次.但是,没有用updata. 检测碰撞的函数如下: [plain] view pl

Struts2的&quot;两个蝴蝶飞,你好&quot;简单开发(一)

我把你的头像,设置成我的名字,此刻你便与我同在. 我把你的名字,写进我的代码里面,以后,我的世界便存在着你. “两个蝴蝶飞”特别喜欢"java1234知识分享网"小峰的实用主义,所以本文及其系列文章均是采用实用主义,从项目和代码的角度去分析.由于本人经验有限,嘴皮子不溜,所以学术性,概念性,底层性的知识点暂时不做介绍.文章中有错误之处,欢迎拍砖和指点.特别感谢"java1234知识分享网"和"黑马程序员官网",所有的资料大部分是两者提供,为了方便

Symfony2.5简单开发实例(未连接数据库)

1.创建bundle:(很多人在刚开发的时候不知道什么是bundle,它是Symfony的核心模块,说白了Symfony就是各个bundle配合系统组件组成的,大家可以简单的理解为是在创建php的项目文件夹,不要想得太深奥) 先在E:\wamp\www\Symfony\src文件夹下创建文件夹Site, 在命令行cmd,进入到项目文件夹,比如cd E:\wamp\www\Symfony,输入如下命令: php app/console generate:bundle --namespace=Sit

C语言 动态库简单开发

动态库项目 //简单的动态库开发----报文发送 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<string.h> //定义上下文结构体 typedef struct _SCK_HANDLE{ //定义报文IP char ipaddress[30]; //定义报文端口 char port[10]; //定义报文接受数组 unsigned char * buf;

小知识积累-linux下一些简单开发配置

系统环境为 redhat enterprise 6.x,主要是针对初学者在linux下用gcc和vi简单测试开发的一些配置 1.vi 自动换行 在终端下敲入vi命令打开文件 : vi ~/.vimrc 如果不存在这个文件会自动新建一个文件,输入i进入插入模式,将下面一行数据敲入文件中,然后依次按 esc:wq! 这些键保存文件 set cindent 也可以上面的cindent改为autoindent ,不过我个人感觉cindent更符合编程习惯. 因为~表示当前用户的主文件夹,所以进行如上操作

mac pro安装双系统及简单开发环境搭建

前段时间换电脑,在搭建开发环境时,遇到了些小问题,下面简单说说这些小坑. 因为开发场景比较特殊,我多数时间会在windows下做开发,但有时还会切换到mac os下做些开发,刚开始时,尝试在mac os下安装虚拟机,然后在安装windows,但是实际体验不是很好,有时会有点卡的感觉,纠结过后,还是选择安装双系统,虽然系统切换比较繁琐,但是独立安装的windows,使用上操作更流畅.显示效果也更佳.mac os上使用bootcamp安装windows非常方便.省事,大体流程是:准备系统镜像文件(我

微信公众号PHP简单开发流程

微信公众号开发分傻瓜模式和开发者模式两种,前者不要考虑调用某些接口,只要根据后台提示傻瓜式操作即可,适用于非专业开发人员. 开发模式当然就是懂程序开发的人员使用的. 下面简单说一下微信公众号开发的简易流程,新手看看会有帮助,高手请一笑而过. 1.配置服务器: A.首先在本机建立如下结构的文件夹(这里是我自己的习惯,仅供参考) MMPN:总目录mro message public number 微信公众号 backup:备份目录,主要用于备份php文件,每次修改时将原稿备份到里面去. images