文档库 最新最全的文档下载
当前位置:文档库 › 第9章底层开发

第9章底层开发

第9章底层开发
第9章底层开发

第9章底层开发

很多程序往往需要实现和硬件打交道的功能,这种功能特别是对于那些不能开发驱动程序的语言来说,显得特别重要。这时可以采用C或者汇编语言开发一个驱动程序,通过这些程序和驱动程序通信,实现硬件的驱动。

9.1 基于WindowsNT操作系统的端口直接读写

WindowsNT/2000是一个非常出色的操作系统,凭借其安全性、可靠性、稳定性以及良好的人机交互界面,在商业高端操作系统中占据一席之地,成为工业控制计算机首选的操作系统。然而,Windows NT并不是一个实时的操作系统,出于安全稳定性考虑,它禁止用户态的应用程序直接操纵硬件,所有涉及物理内存、磁盘、中断、端口读写的操作,必须通过一个内核态的WDM驱动程序完成,否则就会出现一个特权指令异常的消息,系统提示用户要么终止、要么调试这个出现异常的应用程序。即便用户在WindowsNT的控制台窗口进行端口读写,IO操作要么被忽略,要么被一个叫做VDD 的虚拟设备驱动程序实现,尽管没有出现任何例外,但是用户并没有获得真正的IO口直接读写。通过编写WDM驱动程序,用户态应用程序可以借助与WDM程序的通信(利用CreateFile、CloseHandle、DeviceIOControl),实现IO读写,直接存取硬件。然而,一个CPUIO指令大约只需要30多个指令周期,然而调用驱动程序再要花费6000到12000个时钟周期,这将使系统的实时性和灵敏度大打折扣。端口指令允许所有的80X86CPU与系统中的其他硬件设备通信,从而实现对硬件设备的直接低层次控制。在C语言中提供了类似于汇编语言的端口操作指令,允许用户实现端口的读写。然而在WindowsNT/2000环境下,直接运行这些操作函数,将导致特权指令异常,并给出终止或者调试出错应用程序的选择。如果在WindowsNT/2000控制台窗口中运行16位的DOS应用程序进行端口操作,这时这些IO操作要么被忽略,要么通过WindowsNT/2000虚拟设备驱动程序仿真实现。尽管没有任何异常,但是用户得不到真正的IO操作。这是因为WindowsNT/2000的安全机制不允许用户态的应用程序直接访问硬件,从而摧毁和搞垮WindowsNT/2000无懈可击的稳定性。WindowsNT/2000规定用户态程序所有的IO操作必须借助于DeviceIOControl函数和内核驱动程序进行通信实现,然而和内核的通信势必会造成大量的时钟周期浪费和开销。

WindowsNT/2000只允许内核态的应用程序存取所有端口,对于用户态的程序,它通过设置IOPL实现了对IO操作的屏蔽。为了实现在用户态的直接IO操作,用户必须通过编写驱动程序去掉对读写端口的屏蔽。我们知道WindowsNT实现IO读写保护是有原因的,一方面它使系统异常的稳定,用户再也不必为Windows9x下的蓝屏和异常而苦恼了。用户可以放心大胆地调试应用程序,即便程序出现死锁,系统也会干脆利落地把它杀死,而不会波及到整个系统。IO读写保护与Windows98保护8253定时器端口是一样道理,它的目的就是防止用户使用简单的in/out指令,从而把系统搞垮。但是,对于大量的信号采集的系统而言,应用程序开发人员会更关心系统的实时性,更习惯于在程序中直接使用in/out指令实现信号采集。因此必须打破WindowsNT环境下的IO瓶颈,使得用户态的应用程序拥有IO读写权限,实现实时控制。

弄清楚如何把IO存取权授权给用户态的应用程序,用户必须了解WindowsNT环境下IO保护是如何实现的。WindowsNT本身并不能实现IO保护,由于CPU能够捕捉尝试的IO存取,WindowsNT利用了80x86这一特征。80x86采用了特权级别系统,它总共定义了0、1、2、3四个级别,即我们所说的Ring环。出于对ALPHA平台的兼容性,80x86仅使用了权限最高的Ring0和最低的ring3,CPU的当前运行权限级(CPL)保存在CS代码段寄存器的两位中。IO权限并不是由CPU静态定义的。CPU在处理器的标志寄存器Eflags的某两位定义了当前的IO权限级别(IOPL),通过比较当前的IO权限级和CPU的当前运行权限级,来决定IO指令能否自由使用。由于当前的IO权限级总是大于等于0,因此运行在Ring0环的内核模式的设备驱动程序,总是可以直接对IO端口进行存取。而运行在用户态的应用程序,工作在Ring3环,WindowsNT 把当前的IO权限级设置为0,因此,用户态的程序尝试端口存取时,必须经过保护机制。判断CPL>IOPL,仅仅是保护机制的第一步,I/O保护要么全有,要么全无。处理器采用了更为灵活的机制,使得操作系统能够根据任务的不同,对端口的任何子集进行授权。CPU是采用了一个位屏蔽矩阵(IOPM)实现这一步的。这个矩阵由0,1组成,每一个二进制位对应一个输入输出端口。这样,65536个端口共需要8192个字节,如果某一二进制位值为0,那么程序对该端口的读写就会不加阻拦。当然用户不能对一个只读端口进行写操作,只能对端口进行读操作。位屏蔽矩阵(IOPM)保存在主存的任务状态段结构中,我们可以通过NTOSKRNL库提供的一些内核模式设备驱动例程,实现对该位屏蔽矩阵进行读写,以便对某些端口进行授权。注意这些服务例程,在DDK帮助文档中并没有说明,并不能保证下个版本是否支持。我们可以通过VisualStudio提供的ViewDependcy工具打开windows/system32/driver/videoprt.sys,发现它调用了ntoskrnl.exe中的几个未见文档的服务例程。尽管没有说明,但顾名思义,我们也可以看出这些函数要干什么。

extern"C"{

void Ke386SetIoAccessMap(int,NTPORT*);//复制位图影像到NTPORT结构指针中

//int:1复制缓冲区,0用0xff填充

voidKe386QueryIoAccessMap(int,NTPORT*);//查询当前IOPM

void Ke386IoSetAccessProcess(PEPROCESS,int);}}//int:1允许I/O,0禁止I/O

PsGetCurrentProcess() //获得当前进程

设备驱动程序的加载是一个非常麻烦的事情。对于一个不是硬件的虚拟设备,用户不得不创建一个安装程序,或者编写一个.inf文件,利用控制面板中的添加新硬件功能,加入一个其它设备,或者直接编辑注册编辑表,把驱动程序复制到WINNT系统目录的Drivers32子目录中,有时还需要用户重新启动计算机。而用户需要的功能仅仅是一次(也许是最后一次)辅助驱动用户的小程序。正因为这个原因,本程序提供了一个设备驱动程序加载工具,实现设备驱动程序的动态加载,用户不用做任何添加新硬件的操作,也不用编辑注册表和重新启动计算机。驱动程序不一定位于系统目录中,但要求和程序提供的NTPORT.dll文件位于同一目录。本程序参考了NumegaDriveStudio提供的loaddrv例子程序。

下面简要介绍一下程序调用的有关API函数。

(1)首先使用OpenSCManager函数与指定服务控制管理器建立联系,打开指定的服务控制管理数据库。

schSCManager=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);

(2)利用CreateService函数创建一个服务对象,并把它加入到指定的服务控制管理数据库中。

SC_HANDLEschService=CreateService(SchSCManager,DriverName,DriverName,SERVICE_ALL_ACCESS,

SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START,SERVICE_ERROR_NORMAL,ServiceExe,NULL,NULL,NULL,NULL,NULL);

具体参数请参考MSDN。

(3)用函数StartService启动一个服务,启动前用OpenService打开服务。

BOOL StartService(SC_HANDLE hService,DWORD dwNumServiceArgs,LPCTSTR *lpServiceArgVectors);

(4)用CreateFile打开设备,设备名为驱动程序中用IoCreateSymbolicLink服务创建的符号连接名。如果执行成功,用户就可以利用DeviceIOControl函数接口与驱动程序进行通信了。

例9-1DirectIO实现。

#include

#define DEVICE_NAME_STRINGL"ZNtPort"

#define IOPM_VERSION 110

#define IOPM_TEST 00123

#define IOPM_TEST 11234

#define IOPM_TEST 22345

#define IOPMD_TYPE 0xF100

#define IOCTL_IOPMD_READ_TESTCTL_CODE (IOPMD_TYPE,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IOCTL_IOPMD_READ_VERSIONCTL_CODE (IOPMD_TYPE,0x901,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IOCTL_IOPMD_CLEAR_LIOPMCTL_CODE (IOPMD_TYPE,0x910,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IOCTL_IOPMD_SET_LIOPMCTL_CODE (IOPMD_TYPE,0x911,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IOCTL_IOPMD_GET_LIOPMBCTL_CODE (IOPMD_TYPE,0x912,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IOCTL_IOPMD_GET_LIOPMACTL_CODE (IOPMD_TYPE,0x913,METHOD_BUFFERED,FILE_ANY_ACCESS) //Interact with kernel

#define IOCTL_IOPMD_ACTIVATE_KIOPMCTL_CODE (IOPMD_TYPE,0x920,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IOCTL_IOPMD_DEACTIVATE_KIOPMCTL_CODE (IOPMD_TYPE,0x921,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IOCTL_IOPMD_QUERY_KIOPMCTL_CODE (IOPMD_TYPE,0x922,METHOD_BUFFERED,FILE_ANY_ACCESS) #define ZNtPort_PARAMCOUNT 3

#define ZNtPort_PARAMCOUNT _BYTESZNtPort_PARAMCOUNT*4

#define IOPM_SIZE0x2000

typedef UCHARIOPM[IOPM_SIZE];

IOPM *IOPM_local=0;

Void Ke386SetIoAccessMap(int,IOPM*);

Void Ke386QueryIoAccessMap(int,IOPM*);

Void Ke386IoSetAccessProcess(PEPROCESS,int);

Void disp_ACTIVATE_KIOPM(void)

{Ke386IoSetAccessProcess(PsGetCurrentProcess(),1); Ke386SetIoAccessMap(1,IOPM_local);}

Void disp_DEACTIVATE_KIOPM(void) { Ke386IoSetAccessProcess(PsGetCurrentProcess(),0);}

Void disp_QUERY_KIOPM(void) { Ke386QueryIoAccessMap(1,IOPM_local);}

Void disp_CLEAR_LIOPM(void)

{int n;

for(n=0;n

NTSTATUSZNt Port_Dispatch(INPDEVICE_OBJECTDeviceObject,INPIRPpIrp)

{int Ix,B;

PIO_STACK_LOCATION pIrpStack;

NTSTATUS Status;

PULONG pIOBuffer;

ULONG InBufferSize;

ULONG OutBufferSize;

ULONG OutByteCount;

ULONG IoControlCode;

pIrpStack=IoGetCurrentIrpStackLocation(pIrp);Status=STATUS_NOT_IMPLEMENTED;OutByteCount=0;

switch(pIrpStack->MajorFunction){

case IRP_MJ_CREATE: Status=STATUS_SUCCESS; break;

case IRP_MJ_CLOSE: Status=STATUS_SUCCESS; break;

case IRP_MJ_DEVICE_CONTROL:

InBufferSize=pIrpStack->Parameters.DeviceIoControl.InputBufferLength;

OutBufferSize=pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;

pIOBuffer=(PULONG)pIrp->AssociatedIrp.SystemBuffer;

IoControlCode=pIrpStack->Parameters.DeviceIoControl.IoControlCode;

switch(IoControlCode){

case IOCTL_IOPMD_READ_TEST: pIOBuffer[0]=IOPM_TEST0;pIOBuffer[1]=IOPM_TEST1;pIOBuffer[2]=IoControlCode;

OutByteCount=ZNtPort_PARAMCOUNT_BYTES;Status=STATUS_SUCCESS;break;

Case IOCTL_IOPMD_READ_VERSION:pIOBuffer[0]=IOPM_VERSION;pIOBuffer[2]=IoControlCode;

OutByteCount=ZNtPort_PARAMCOUNT_BYTES;Status=STATUS_SUCCESS;break;

Case IOCTL_IOPMD_CLEAR_LIOPM: disp_CLEAR_LIOPM();pIOBuffer[2]=IoControlCode;

OutByteCount=ZNtPort_PARAMCOUNT_BYTES; Status=STATUS_SUCCESS; break;

Case IOCTL_IOPMD_SET_LIOPM:Ix=pIOBuffer[0]&0x1FFF;B=pIOBuffer[1]&0xFF;

(*IOPM_local)[Ix]=B;disp_ACTIVATE_KIOPM();pIOBuffer[2]=IoControlCode;OutByteCount=ZNtPort_PARAMCOUNT_BYTES;

Status=STATUS_SUCCESS;break;

Case IOCTL_IOPMD_GET_LIOPMB: disp_QUERY_KIOPM();Ix=pIOBuffer[0]&0x1FFF;B=(*IOPM_local)[Ix];

pIOBuffer[1]=B&0x000000FF;pIOBuffer[2]=IoControlCode;OutByteCount=ZNtPort_PARAMCOUNT_BYTES;

Status=STATUS_SUCCESS;break;

Case IOCTL_IOPMD_GET_LIOPMA:disp_QUERY_KIOPM();

if(OutBufferSize

else{ for(Ix=0;Ix

Status=STATUS_SUCCESS;} break;

Case IOCTL_IOPMD_ACTIVATE_KIOPM: disp_ACTIVATE_KIOPM();pIOBuffer[2]=IoControlCode;

OutByteCount=ZNtPort_PARAMCOUNT_BYTES; Status=STATUS_SUCCESS;break;

Case IOCTL_IOPMD_DEACTIVATE_KIOPM: disp_DEACTIVATE_KIOPM();pIOBuffer[2]=IoControlCode;

OutByteCount=ZNtPort_PARAMCOUNT_BYTES;Status=STATUS_SUCCESS;break;

Case IOCTL_IOPMD_QUERY_KIOPM: disp_QUERY_KIOPM();pIOBuffer[2]=IoControlCode;

OutByteCount=ZNtPort_PARAMCOUNT_BYTES;Status=STATUS_SUCCESS;break;

default:pIOBuffer[2]=IoControlCode;OutByteCount=ZNtPort_PARAMCOUNT_BYTES;

Status=STATUS_INVALID_DEVICE_REQUEST;break;}break;}

pIrp->IoStatus.Status=Status;pIrp->https://www.wendangku.net/doc/4f11213212.html,rmation=OutByteCount; IoCompleteRequest(pIrp,IO_NO_INCREMENT); return Status;}

VOID ZNtPort_Unload(INPDR IVER_OBJECTDriverObject)

{ WCHARD OSNameBuffer[]=L"\\DosDevices\\"DEVICE_NAME_STRING;

UNICODE_STRING uniDOSString;

if(IOPM_local)MmFreeNonCachedMemory(IOPM_local,sizeof(IOPM));

RtlInitUnicodeString(&uniDOSString,DOSNameBuffer);

IoDeleteSymbolicLink(&uniDOSString);IoDeleteDevice(DriverObject->DeviceObject);}

NTSTATUS DriverEntry(INPDRIVER_OBJECT DriverObject,INPUNICODE_STRING RegistryPath)

{PDEVICE_OBJECTdeviceObject;NTSTATUS status;

WCHARNameBuffer[]=L"\\Device\\"DEVICE_NAME_STRING;

WCHARDOSNameBuffer[]=L"\\DosDevices\\"DEVICE_NAME_STRING;

UNICODE_STRING uniNameString,uniDOSString;

Int n; IOPM_local=MmAllocateNonCachedMemory(sizeof(IOPM));

if(IOPM_local==0) return STATUS_INSUFFICIENT_RESOURCES;disp_CLEAR_LIOPM();

RtlInitUnicodeString(&uniNameString,NameBuffer);RtlInitUnicodeString(&uniDOSString,DOSNameBuffer);

status=IoCreateDevice(DriverObject,0,&uniNameString,IOPMD_TYPE,0,FALSE,&deviceObject);

if(!NT_SUCCESS(status)) return status;

status=IoCreateSymbolicLink(&uniDOSString,&uniNameString);

if(!NT_SUCCESS(status)) return status;

DriverObject->MajorFunction[IRP_MJ_CREATE]=ZNtPort_Dispatch;

DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=ZNtPort_Dispatch;

DriverObject->DriverUnload=ZNtPort_Unload; return STATUS_SUCCESS;}

为了方便使用,这里把通信代码封装到一个COM组件中,提供了简单的接口。接口的主要代码如下:

#include"resource.h"//主符号

#include"NTPort.h"

Class ATL_NO_VTABLECDirectIO:

Public CComObjectRootEx,

Public CComCoClass,

Public IDispatchImpl

{public: CDirectIO(){}

DECLARE_REGISTRY_RESOURCEID(IDR_DIRECTIO)

BEGIN_COM_MAP(CDirectIO)

COM_INTERFACE_ENTRY(IDirectIO)

COM_INTERFACE_ENTRY(IDispatch)

END_COM_MAP()

DECLARE_PROTECT_FINAL_CONSTRUCT()

HRESULT FinalConstruct() {sc.init("ZNtPort"); return S_OK;}

Void FinalRelease(){ }

public:

STDMETHOD(GetIDsOfNames)(GUID*riid,OLECHAR**rgszNames,unsigned int cNames,unsigned long lcid,long *rgdispid); STDMETHOD(Invoke)(DISPID dispidMember,REFII Driid,LCID lcid,WORD wFlags,

DISPPARAMS*pdispparams,VARIANT *pvarResult,EXCEPINFO*pexcepinfo,UINT *puArgErr);

public:

STDMETHOD(In)(VARIANT vPort,VARIANT *pVal);

STDMETHOD(Out)(VARIANT vPort,VARIANT vVal);

STDMETHOD(EnablePorts)(VARIANT vPortStart,VARIANT vEnableNum);

STDMETHOD(DisablePorts)(VARIANT vPortStart,VARIANT vDisableNum);

private: Cservice Control sc;};

#include"stdafx.h"

#include"DirectIO.h"

#include".\directio.h"

#defineDEVICE_NAME_STRINGL"ZNtPort"

#define IOPM_VERSION110

#define IOPM_TEST00123

#define IOPM_TEST11234

#define IOPM_TEST22345

#define IOPMD_TYPE0xF100//某些地方使用

#define IOCTL_IOPMD_READ_TESTCTL_CODE (IOPMD_TYPE,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)

//返回IOPM_TEST

#define IOCTL_IOPMD_READ_VERSIONCTL_CODE(IOPMD_TYPE,0x901,METHOD_BUFFERED,FILE_ANY_ACCESS)

//返回IOPM_VERSION

//操作本地IO权限表

#define IOCTL_IOPMD_CLEAR_LIOPMCTL_CODE(IOPMD_TYPE,0x910,METHOD_BUFFERED,FILE_ANY_ACCESS)

#define IOCTL_IOPMD_SET_LIOPMCTL_CODE(IOPMD_TYPE,0x911,METHOD_BUFFERED,FILE_ANY_ACCESS)

#define IOCTL_IOPMD_GET_LIOPMBCTL_CODE(IOPMD_TYPE,0x912,METHOD_BUFFERED,FILE_ANY_ACCESS)

#define IOCTL_IOPMD_GET_LIOPMACTL_CODE(IOPMD_TYPE,0x913,METHOD_BUFFERED,FILE_ANY_ACCESS)

//与内核交互

#define IOCTL_IOPMD_ACTIVATE_KIOPMCTL_CODE(IOPMD_TYPE,0x920,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IOCTL_IOPMD_DEACTIVATE_KIOPMCTL_CODE(IOPMD_TYPE,0x921,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IOCTL_IOPMD_QUERY_KIOPMCTL_CODE(IOPMD_TYPE,0x922,METHOD_BUFFERED,FILE_ANY_ACCESS)

//CDirectIO

const DISPID_IN=1;

const DISPID_OUT=2;

const DISPID_ENABLEPORTS=3;

const DISPID_DISABLEPORTS=4;

//const DISPID_GETERRORSTRING=5;

//const DISPID_GETSCRIPTFUNCTION=6;

//const DISPID_LOADSCRIPTRESOURCE=7;

//const DISPID_LOADSCRIPT=8;

//const DISPID_ADDSCRIPT=9;

//const DISPID_RUNPROCEDURE=10;

//const DISPID_EXECUTESTATEMENT=11;

STDMETHODIMPCDirectIO::GetIDsOfNames(GUID*riid,OLECHAR**rgszNames,

Unsigned int cNames,unsigned long lcid,long *rgdispid)

{ USES_CONVERSION;

char*szAnsi=OLE2A(rgszNames[0]);

if(strnicmp("in",szAnsi,2)==0)

rgdispid[0]=DISPID_IN;

else if(strnicmp("Out",szAnsi,3)==0) rgdispid[0]=DISPID_OUT;

else if(strnicmp("EnablePorts",szAnsi,11)==0)rgdispid[0]=DISPID_ENABLEPORTS;

else if(strnicmp("DisablePorts",szAnsi,12)==0)rgdispid[0]=DISPID_DISABLEPORTS;

else return (DISPID_UNKNOWN); return S_OK;}

STDMETHODIMPCDirectIO::Invoke(DISPID dispidMember,REFII Driid,LCID lcid,

WORD wFlags,DISPPARAMS *pdispparams,VARIANT *pvarResult, EXCEPINFO *pexcepinfo,UINT *puArgErr)

{ int nIndex;

switch(dispidMember)

{case DISPID_IN: In(pdispparams->rgvarg[0],pvarResult);break;

Case DISPID_OUT:Out(pdispparams->rgvarg[1],pdispparams->rgvarg[0]);break;

Case DISPID_ENABLEPORTS:EnablePorts(pdispparams->rgvarg[1],pdispparams->rgvarg[0]);break;

Case DISPID_DISABLEPORTS:DisablePorts(pdispparams->rgvarg[1],pdispparams->rgvarg[0]);break;

Return S_OK;}

STDMETHODIMPCDirectIO::In(VARIANT vPort,VARIANT *pVal)

{ HRESULThr=VariantChangeType(&vPort,&vPort,0,VT_UI2);

if(FAILED(hr))return DISP_E_TYPEMISMATCH;

switch(pVal->vt){

case VT_I1:

case VT_UI1:

{char c;

__asm mov dx,vPort.uiVal

__asm in al,dx

__asm mov c,al

pVal->cVal=c; }break;

case VT_I2:

case VT_UI2:

{ WORD w;

__asm xor ax,ax

__asm mov dx,vPort.uiVal

__asm in al,dx

__asm mov w,ax

pVal->uiVal=w;} break;

case VT_I4:

case VT_UI4:

{ DWORD dw;

__asm xor eax,eax

__asm mov dx,vPort.uiVal

__asm in al,dx

__asm mov dw,eax

pVal->ulVal=dw;}

default: break;}

return S_OK;}

STDMETHODIMPCDirectIO::Out(VARIANT vPort,VARIANT vVal)

{ HRESULThr=VariantChangeType(&vPort,&vPort,0,VT_UI2);

if(FAILED(hr)) return DISP_E_TYPEMISMATCH;

switch(vVal.vt){

case VT_I1:

case VT_UI1:

__asm mov dx,vPort.uiVal

__asm mov al,vVal.cVal

__asm out dx,al

break;

case VT_I2:

case VT_UI2:

__asm mov dx,vPort.uiVal

__asm mov ax,vVal.uiVal

__asm out dx,al

break;

case VT_I4:

case VT_UI4:

__asm mov dx,vPort.uiVal

__asm mov eax,vVal.ulVal

__asm out dx,al

default:break;} return S_OK;}

STDMETHODIMPCDirectIO::EnablePorts(VARIANT vPortStart,VARIANT vEnableNum)

{DWORDdw[3];

HRESULThr=VariantChangeType(&vPortStart,&vPortStart,0,VT_UI4);

if(FAILED(hr)) return DISP_E_TYPEMISMATCH;

hr=VariantChangeType(&vEnableNum,&vEnableNum,0,VT_UI4);

if(FAILED(hr)) return DISP_E_TYPEMISMATCH;

dw[0]=vPortStart.ulVal;dw[1]=0x00000000; sc.WriteIo(IOCTL_IOPMD_QUERY_KIOPM,dw,sizeofdw);

for(inti=0;i

DWORD d;

d=dw[0]; dw[0]=dw[0]>>3; sc.ReadIo(IOCTL_IOPMD_GET_LIOPMB,dw,sizeofdw);

dw[0]=d;dw[0]%=8;int j=1;dw[1]=dw[1]&(0xff-j<>3;sc.WriteIo(IOCTL_IOPMD_SET_LIOPM,dw,sizeofdw);

dw[0]=d+1;} return S_OK;}

STDMETHODIMPCDirectIO::DisablePorts(VARIANT vPortStart,VARIANT vDisableNum)

{DWORD dw[3];

HRESULThr=VariantChangeType(&vPortStart,&vPortStart,0,VT_UI4);

if(FAILED(hr))return DISP_E_TYPEMISMATCH; hr=VariantChangeType(&vDisableNum,&vDisableNum,0,VT_UI4);

if(FAILED(hr))return DISP_E_TYPEMISMATCH;

dw[0]=vPortStart.ulVal; dw[1]=0x00000000;sc.WriteIo(IOCTL_IOPMD_QUERY_KIOPM,dw,sizeofdw);

for(inti=0;i>3;

sc.ReadIo(IOCTL_IOPMD_GET_LIOPMB,dw,sizeof dw);dw[0]=d;dw[0]%=8;int j=1; dw[1]=dw[1]|(j<

dw[0]=d>>3; sc.WriteIo(IOCTL_IOPMD_SET_LIOPM,dw,sizeofdw);dw[0]=d+1;}

sc.WriteIo(IOCTL_IOPMD_CLEAR_LIOPM,dw,sizeofdw);return S_OK;}

9.2 用本机API开发NativeNT应用程序

当用户从WindowsNT环境非正常退出重新启动系统时,会注意到系统会自动运行一个磁盘检查程序AutoCheck。这个程序既不同于Windows9x/Me环境下的ScanDisk.exe16位DOS程序,也不同于Win32环境下的应用程序,它本身不能在Win32环境下加载运行,只能通过注册表由系统启动时自动加载,这种程序我们称之为NativeNT应用程序。

编写Native(本机)NT应用程序有许多好处,因为程序加载时系统尚未完全启动起来,这个环境是一个相对比较干净的

系统,用户可以利用这个机会实现磁盘优化和查杀病毒。另一方面,由于这个程序能够自动加载,所以它可以自动帮我们做许多事情,比如显示一些的提示信息、进行系统初始化等。编写本机NT应用程序,并没有编写Win32应用程序容易,因为系统启动时,Win32尚未启动起来,它无法使用Win32SDK函数,只能使用NTDLL.dll输出的1403个本机API函数,使用的方法类似于我们编写WDM驱动程序使用内核服务。程序调试比较困难,甚至无法实现汉字输出,屏幕的输出不能通过窗口实现,而是写在一个让人反感的蓝色屏幕上。种种缺点使得除了系统提供的磁盘检查程序外,很难觅得它的踪影,当然这与资料奇缺也很有关系。但是由于它本身运行在Ring0层,接近系统内核,拥有没有限制操作的权限,因此它可以读写任何端口,运行用户态无法运行的特权指令。

相对于Win32API函数也有它无法比拟的优点,而且大部分的Win32SDK都是通过调用NTDLL.dll本机API间接实现的。几乎每一个Win32SDK函数在本机API中都有它对应的版本,Kernel32(WindowsNT环境下)的输出函数基本都是NTDLL.dll 过渡产物。它的目的是保持与Windows9x有一样的输出函数,从而使编写的Win32应用程序能够同时在Windows9x和WondowsNT两种环境下运行,而不用作任何修改。

本机NT应用程序的入口为NtProcessStartup,不同于Win32控制台的main函数,也不同于Win32GUI界面的WinMain 函数,程序运行结束后,必须调用NtTerminateProcess结束本进程。本机NT应用程序依靠系统自动加载,为了实现这一步,必须首先把本机NT应用程序复制到WindowsNT系统目录(system32),然后修改注册表实现。修改时既可以利用注册表编辑器对下面的键进行手工编辑,也可以创建一个如下的文件,进行导入。导入后重新启动系统即可生效。如果编写的程序因为错误无法正常运行,可以在启动系统时,选择恢复最后一次正确配置。

下面是一个导入的例子:

WindowsRegistryEditorVersion5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessionManager]

"BootExecute"=hex(7):61,00,75,00,74,00,6f,00,63,00,68,00,65,00,63,00,6b,00,20,\

00,61,00,75,00,74,00,6f,00,63,00,68,00,6b,00,20,00,2a,00,00,00,6e,00,61,00,\

74,00,69,00,76,00,65,00,20,00,57,00,65,00,6c,00,63,00,6f,00,6d,00,65,00,20,\

00,59,00,6f,00,75,00,20,00,54,00,6f,00,20,00,55,00,73,00,65,00,20,00,57,00,\

69,00,6e,00,64,00,6f,00,77,00,73,00,20,00,58,00,50,00,21,00,00,00,00,00

注意这些十六进制的代码分别对应为:

autocheckautochk*

nativeWelcomeYouToUseWindowsXP!

其中native是程序名称,WelcomeYouToUseWindowsXP!为参数信息。

恢复原来设置:

WindowsRegistryEditorVersion5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessionManager]

"BootExecute"=hex(7):61,00,75,00,74,00,6f,00,63,00,68,00,65,00,63,

00,6b,00,20,\

00,61,00,75,00,74,00,6f,00,63,00,68,00,6b,00,20,00,2a,00,00,00,00,00

制作这样一个注册文件是非常麻烦的,可以通过注册表编辑器的导出功能先导出一个样板,然后对样板进行修改。

下面是一个完整的本机NT应用程序的例子,在VisualStudio6环境下用DDK2000编译通过,连接后的程序可以通过WindowsNT/2K/XP测试。

例9-2使用本机API编写应用程序。

这是一个NativeNT演示程序,这个程序只能运行在Win32环境之外,必须依靠由NTDLL.dll提供的原始服务,操作系统提供的AutoChk程序(系统引导时自动运行的磁盘检查工具)就是这样的一个NativeNT应用程序。这样的程序广泛地应用于引导时系统检查,系统初始化,查杀病毒等。

这是一个简单的HelloWorld型的应用程序,它通过注册表进行安装,安装后,在系统引导时,会弹出一个蓝屏背景的提示信息,这个程序不能在Win32环境下运行。

#include"ntddk.h"//包含了所有的Native函数定义

#include"stdio.h"

#include"native.h"

HANDLE Heap;

//NtProcessStartup为NativeNT应用程序的入口点,注意不是main和WinMain

Void NtProcessStartup(PSTARTUP_ARGUMENT Argument)

{PUNICODE_STRING commandLine;

PWCHAR stringBuffer,argPtr;

UNICODE_STRING DisplayMessage;

RTL_HEAP_DEFINITION heapParams;

//初始化一些堆

memset(&heapParams,0,sizeof(RTL_HEAP_DEFINITION));heapParams.Length=sizeof(RTL_HEAP_DEFINITION);

Heap=RtlCreateHeap(2,0,0x100000,0x1000,0,&heapParams);

//获得命令行地址

commandLine=&Argument->Environment->CommandLine;

//参数定位

argPtr=commandLine->Buffer;while(*argPtr!=L'')argPtr++;argPtr++;

//参数打印输出

stringBuffer=RtlAllocateHeap(Heap,0,256);swprintf(stringBuffer,L"\n%s",argPtr);

DisplayMessage.Buffer=stringBuffer;DisplayMessage.Length=wcslen(stringBuffer)*sizeof(WCHAR);

DisplayMessage.MaximumLength=DisplayMessage.Length+sizeof(WCHAR);NtDisplayString(&DisplayMessage);

//堆释放

RtlFreeHeap(Heap,0,stringBuffer);

//进程终止时要调用这个函数服务

NtTerminateProcess(NtCurrentProcess(),0);}

9.3 用户模式应用程序运行Ring0特权指令

用户态的应用程序一般运行在Ring3环,而内核态的驱动程序运行在Ring0环。一般的Ring3环的用户态应用程序是不允许运行Ring0特权指令的。否则就会触发异常,甚至导致系统崩溃。然而,把所有的指令都采用驱动程序实现是繁琐的,能够在用户模式应用程序运行Ring0特权指令是大多数程序员翘首以盼的事情。用户可以想象如果能够在用户态可以像在内核中一样存取所有端口,那么就不必去编写端口存取驱动程序了。

在Windows9x环境下,在用户态应用程序中执行特权指令,并不需要操作系统的支持。WindowsNT系统中提供了一个Beep函数,然而在MSDN文档中明确指出,这个函数不支持Windows9x系统,但用过DOS汇编语言的用户对下面一段的代码肯定不会陌生。

Void __declspec(naked) beepInAsm(void)

{__asm

{push ad

Mov bx,3000h

Mov cx,ax

Mov al,0b6h

Out 43h,al

Mov dx,0012h

Mov ax,34dch

Div cx

Out 42h,al

Mov al,ah

Out 42h,al

In al,61h

Mov ah,al

Or al,03h

Out 61h,al

l1:

mov ecx,4680

l2:

loopl2

dec bx

jnz l1

mov al,ah

out 61h,al

pop ad

iretd

}}

然而,在Windows9x环境下这些端口操作是禁止的,而IretD也是一个特权指令,如果我们能够在Windows9x环境下执行这些特权指令,就能够实现Windows9x环境下的Beep函数。

#define ExceptionUsed 9

DWORD LONGIDT, SaveGate;

WORD OurGate[4]={0,0x28,0x0ee00,0};

BOOL beep(DWORD dwFreq)

{if(IsWindowsNT()){ Beep(dwFreq,500); Return TRUE;}

_asm{

Mov eax,offsetbeepInAsm

Mov [OurGate],ax

Shr eax,16

Mov [OurGate+6],ax

sidtfwordptrIDT;fetchIDTregister

mov ebx,dwordptr[IDT+2];ebx->IDT

add ebx,8*ExceptionUsed;Ebx->IDTentryofExceptionUsed

mov edi,offsetSaveGate

mov esi,ebx

mov sd

mov sd

mov edi,ebx

mov esi,offsetOurGate

mov sd

mov sd

mov eax,dwFreq

int ExceptionUsed;causeexception

mov edi,ebx

mov esi,offsetSaveGate

mov sd

mov sd}

return TRUE;}

上面的这段代码是通过切换调用门实现的。调用门就像一个从Ring0到Ring3的通道,通过这个门槛就可以进入另外一个世界。在上面的代码中通过设置中断向量的地址,触发异常中断,从而执行Ring0代码,而中断的产生刚好处于Ring0环。在WindowsNT内核系统下,也可以切换中断门,只是中断门的切换需要驱动程序支持。

看下面的代码:

#include"callgate.h"

NTSTATUS DriverDispatch(INPDEVICE_OBJECT DeviceObject,INPIRP Irp);

Void DriverUnload(INPDRIVER_OBJECTDriverObject);

NTSYSAPINTS TATUSNTAPIKeI386AllocateGdtSelectors(PUSHORTpSelect orArray,ULONG NumberOfSelectors);

NTSYSAPINTS TATUSNTAPIKeI386ReleaseGdtSelectors(PUSHORTpSelect orArray,ULONG NumberOfSelectors);

NTSYSAPINTS TATUSNTAPIKeI386SetGdtSelector(ULONG Selector,PVOID pDescriptor);

WCHAR deviceNameBuffer[]=L"\\Device\\callgate";

WCHAR deviceLinkBuffer[]=L"\\DosDevices\\callgate";

NTSTATUS CreateCallGate(PcallGateInfo _tCallGateInfo)

{ static CALLGATE_DESCRIPTOR callgate_desc;

Static CODE_SEG_DESCRIPTOR ring0_desc;

Unsigned short SelectorArray[2];

NTSTATUS rc;

#define LOWORD(l)((unsigned short)(unsigned int)(l))

#define HIWORD(l)((unsigned short)((((unsigned int)(l))>>16)&0xFFFF))

rc=KeI386AllocateGdtSelectors(SelectorArray,0x02);

if(rc!=STATUS_SUCCESS){ MYTRACE("UnabletoallocateselectorsfromGDT\n"); return rc;}

MYTRACE("Selectorsallocated=%x%x\n",SelectorArray[0],SelectorArray[1]);

ring0_desc.limit_0_15=0xFFFF;ring0_desc.base_0_15=0;ring0_desc.base_16_23=0;ring0_desc.readable=1;

ring0_desc.conforming=0;ring0_desc.code_data=1;ring0_desc.app_system=1;ring0_desc.dpl=0;ring0_desc.present=1;

ring0_desc.limit_16_19=0xF;ring0_desc.always_0=0;ring0_desc.seg_16_32=1;ring0_desc.granularity=1;

ring0_desc.base_24_31=0;callgate_desc.offset_0_15=LOWORD(CallGateInfo->FunctionLinearAddress);

callgate_desc.selector=SelectorArray[0];callgate_desc.param_count=CallGateInfo->NumberOfParameters;

callgate_desc.some_bits=0;callgate_desc.type=0xC;//386callgate

callgate_desc.app_system=0;//Asystemdescriptor

callgate_desc.dpl=3;//Ring3codecancall

callgate_desc.present=1;

callgate_desc.offset_16_31=HIWORD(CallGateInfo->FunctionLinearAddress);

CallGateInfo->CodeSelector=SelectorArray[0];CallGateInfo->CallGateSelector=SelectorArray[1];

rc=KeI386SetGdtSelector(SelectorArray[0],&ring0_desc);

if(rc!=STATUS_SUCCESS){MYTRACE("SetGdtSelector=%x\n",rc); KeI386ReleaseGdtSelectors(SelectorArray,0x02); Return rc;} rc=KeI386SetGdtSelector(SelectorArray[1],&callgate_desc);

if(rc!=STATUS_SUCCESS){MYTRACE("SetGdtSelector=%x\n",rc); KeI386ReleaseGdtSelectors(SelectorArray,0x02);Return rc;} return STATUS_SUCCESS;}

NTSTATUS ReleaseCallGate(PcallGate Info_tCallGateInfo)

{unsigned short SelectorArray[2];

Int rc;

SelectorArray[0]=CallGateInfo->CodeSelector;SelectorArray[1]=CallGateInfo->CallGateSelector;

rc=KeI386ReleaseGdtSelectors(SelectorArray,0x02);

if(rc!=STATUS_SUCCESS){MYTRACE("ReleaseGDTSelectorsfailed,rc=%x\n",rc);}

return rc;}

NTSTATUS DriverEntry(INPDRIVER_OBJECT DriverObject,INPUNICODE_STRING RegistryPath)

{PDEVICE_OBJECT deviceObject=NULL;

NTSTATUS ntStatus;

UNICODE_STRING deviceNameUnicodeString;

UNICODE_STRING deviceLinkUnicodeString;

RtlInitUnicodeString(&deviceNameUnicodeString,deviceNameBuffer);

ntStatus=IoCreateDevice(DriverObject,0,&deviceNameUnicodeString, FILE_DEVICE_CALLGATE,0,FALSE,&deviceObject);

if(NT_SUCCESS(ntStatus)){ MYTRACE("创建设备成功\n");

RtlInitUnicodeString(&deviceLinkUnicodeString,deviceLinkBuffer);

ntStatus=IoCreateSymbolicLink(&deviceLinkUnicodeString,&deviceNameUnicodeString);

if(!NT_SUCCESS(ntStatus)){ MYTRACE("创建符号失败\n");

IoDeleteDevice(deviceObject);IoDeleteSymbolicLink(&deviceLinkUnicodeString); Return ntStatus;}

MYTRACE("初始化成功\n");

DriverObject->MajorFunction[IRP_MJ_CREATE]=DriverDispatch;

DriverObject->MajorFunction[IRP_MJ_CLOSE]=DriverDispatch;

DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=DriverDispatch;

DriverObject->DriverUnload=DriverUnload; Return STATUS_SUCCESS;}

else{ MYTRACE("创建设备失败\n");IoDeleteSymbolicLink(&deviceLinkUnicodeString);} return ntStatus;}

NTSTATUS DriverDispatch(INPDEVICE_OBJECT DeviceObject,INPIR PIrp)

{ PIO_STACK_LOCATION irpStack;

PVOID ioBuffer;

ULONG inputBufferLength;

ULONG outputBufferLength;

ULONG ioControlCode;

NTSTATU ntStatus;

Irp->IoStatus.Status=STATUS_SUCCESS; Irp->https://www.wendangku.net/doc/4f11213212.html,rmation=0;

irpStack=IoGetCurrentIrpStackLocation(Irp);ioBuffer=Irp->AssociatedIrp.SystemBuffer;

inputBufferLength=irpStack->Parameters.DeviceIoControl.InputBufferLength;

outputBufferLength=irpStack->Parameters.DeviceIoControl.OutputBufferLength;

switch(irpStack->MajorFunction)

{ case IRP_MJ_DEVICE_CONTROL: MYTRACE("CALLGATE.SYS:IRP_MJ_DEVICE_CONTROL\n");

ioControlCode=irpStack->Parameters.DeviceIoControl.IoControlCode;

switch(ioControlCode)

{case IOCTL_CALLGATE_CREATE:{PCallGateInfo_tCallGateInfo;CallGateInfo=(PCallGateInfo_t)ioBuffer;

Irp->IoStatus.Status=CreateCallGate(CallGateInfo);

MYTRACE("CreateCallGaterc=%x\n",Irp->IoStatus.Status);

if(Irp->IoStatus.Status==STATUS_SUCCESS){Irp->https://www.wendangku.net/doc/4f11213212.html,rmation=sizeof(CallGateInfo_t);}break;}

case IOCTL_CALLGATE_RELEASE:

{PCallGateInfo_t CallGateInfo;

CallGateInfo=(PCallGateInfo_t)ioBuffer;ntStatus=ReleaseCallGate(CallGateInfo);

MYTRACE("ReleaseCallGaterc=%x\n",ntStatus);break;}

default:Irp->IoStatus.Status=STATUS_INVALID_PARAMETER;

MYTRACE("CALLGATE.SYS:unknownIRP_MJ_DEVICE_CONTROL\n");break;}break;}

ntStatus=Irp->IoStatus.Status;IoCompleteRequest(Irp,IO_NO_INCREMENT);return ntStatus;}

VOID DriverUnload(INPDRIVER_OBJECT DriverObject)

{ UNICODE_STRING deviceLinkUnicodeString;

RtlInitUnicodeString (&deviceLinkUnicodeString,deviceLinkBuffer);

IoDeleteSymbolicLink(&deviceLinkUnicodeString);IoDeleteDevice(DriverObject->DeviceObject);

MYTRACE("CALLGATE.SYS:unloading\n");}

为了切换到Ring0,用户态应用程序可以通过DeviceIOControl函数和内核驱动程序进行交互。为了简化操作,下面的代码把通信的细节封装到一个动态链接库中。

#include

#include

#include"gatedll.h"

#define SYS_FILETEXT("CallGate.SYS")

#define SYS_NAMETEXT("CallGate")

HANDLE hCallgateDriver=INVALID_HANDLE_VALUE;

WORD CodeSelectorArray[8192];

TCHAR msgbuf[257];

BOOL DriverConnect(void);

BOOL StartDriver(INSC_HANDLE SchSCManager,INLPCTSTR DriverName);

BOOL OpenDevice(INLPCTSTR DriverName,HANDLE*lphDevice);

BOOL RemoveDriver(INSC_HANDLE SchSCManager,INLPCTSTR DriverName);

BOOL DriverDisconnect(void);

BOOL StopDriver(INSC_HANDLE SchSCManager,INLPCTSTR DriverName);

BOOLInstallDriver(INSC_HANDLE SchSCManager,INLPCTSTR DriverName, INLPCTSTR ServiceExe);

Int WINAPICreateCallGate(void*FunctionAddress,int NumberOfParameters,PUSHORTpSelector)

{Call GateInfo_t CallGateInfo;

DWORD BytesReturned;

if(hCallgateDriver==INVALID_HANDLE_VALUE){ return ERROR_DRIVER_NOT_FOUND;}

if(!pSelector)return ERROR_BAD_PARAMETER;

memset(&CallGateInfo,0,sizeof(CallGateInfo));CallGateInfo.FunctionLinearAddress=FunctionAddress;

CallGateInfo.NumberOfParameters=NumberOfParameters;

if(!DeviceIoControl(hCallgateDriver,(DWORD)IOCTL_CALLGATE_CREATE,&CallGateInfo,sizeof(CallGateInfo),&CallGateInfo, sizeof(CallGateInfo),&BytesReturned,NULL)){ return ERROR_IOCONTROL_FAILED;}

*pSelector=CallGateInfo.CallGateSelector;CodeSelectorArray[CallGateInfo.CallGateSelector]=CallGateInfo.CodeSelector;

Return SUCCESS;}

Int WINAPIFreeCallGate(USHORTCall GateSelector)

{CallGateInfo_t CallGateInfo;

DWORD BytesReturned;

if(hCallgateDriver==INVALID_HANDLE_VALUE){ return ERROR_DRIVER_NOT_FOUND;}

if(CallGateSelector>=sizeof(CodeSelectorArray)/sizeof(CodeSelectorArray[0])){ return ERROR_BAD_PARAMETER;} memset(&CallGateInfo,0,sizeof(CallGateInfo));

CallGateInfo.CallGateSelector=CallGateSelector;CallGateInfo.CodeSelector=CodeSelectorArray[CallGateSelector];

if(!DeviceIoControl(hCallgateDriver,(DWORD)IOCTL_CALLGATE_RELEASE,&CallGateInfo,sizeof(CallGateInfo),&CallGateInfo, sizeof(CallGateInfo),&BytesReturned,NULL)){return ERROR_IOCONTROL_FAILED;}

//DriverDisconnect();

Return SUCCESS;}

BOOL APIENTRYDllMain(HANDLE hModule,DWORD Reason,LPVOID lpReserved)

{switch(Reason){

Case DLL_PROCESS_ATTACH: DriverConnect();break;

Case DLL_PROCESS_DETACH:break;

default: break;} return TRUE;}

BOOL LoadDeviceDriver(const TCHAR*Name,const TCHAR*Path,HANDLE *lphDevice)

{SC_HANDLE schSCManager;

BOOL okay;

schSCManager=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);

//Ignore success of installation:it may already be installed.

InstallDriver(schSCManager,Name,Path);

//Ignore success of start:it may already be started.

StartDriver(schSCManager,Name);

//Do make sure we can open it.

okay=OpenDevice(Name,lphDevice); CloseServiceHandle(schSCManager); return okay;}

BOOL InstallDriver(INSC_HANDLE SchSCManager,INLPCTSTR DriverName,INLPCTSTR ServiceExe)

{ SC_HANDLE schService;

schService=CreateService(SchSCManager,//SCManagerdatabase

DriverName,//nameofservice

DriverName,//nametodisplay

SERVICE_ALL_ACCESS,//desiredaccess

SERVICE_KERNEL_DRIVER,//servicetype

SERVICE_DEMAND_START,//starttype

SERVICE_ERROR_NORMAL,//errorcontroltype

ServiceExe,//service'sbinary

NULL,//noloadorderinggroup

NULL,//notagidentifier

NULL,//nodependencies

NULL,//LocalSystemaccount

NULL);//nopassword

if(schService==NULL) return FALSE;

CloseServiceHandle(schService); Return TRUE;}

BOOL StartDriver(INSC_HANDLE SchSCManager,INLPCTSTR DriverName)

{SC_HANDLE schService;

BOOL ret;

schService=OpenService(SchSCManager,DriverName,SERVICE_ALL_ACCESS);

if(schService==NULL) return FALSE;

ret=StartService(schService,0,NULL)||GetLastError()==ERROR_SERVICE_ALREADY_RUNNING;

CloseServiceHandle(schService); return ret;}

BOOL OpenDevice(INLPCTSTR DriverName,HANDLE *lphDevice)

{TCHAR completeDeviceName[64];

HANDLE hDevice;wsprintf(completeDeviceName,TEXT("\\\\.\\%s"),DriverName);

hDevice=CreateFile(completeDeviceName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,

FILE_ATTRIBUTE_NORMAL,NULL);

if(hDevice==((HANDLE)-1)) {TCHARPath[256]; PVOIDlpMsgBuf;

//open the handle to the device

GetCurrentDirectory(sizeofPath,Path);

wsprintf(Path+lstrlen(Path),TEXT("\\%s"),SYS_FILE);wsprintf(msgbuf,TEXT("Erroropening%s(%s):"),SYS_NAME,Path); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR)&lpMsgBuf,0,NULL);

MessageBox(NULL,msgbuf,(LPCTSTR)lpMsgBuf,MB_OK); LocalFree(lpMsgBuf); return FALSE;}

//If user wants handle,give it to them.Otherwise,just close it.

if(lphDevice) *lphDevice=hDevice;

else CloseHandle(hDevice); return TRUE;}

BOOL UnloadDeviceDriver(const TCHAR*Name)

{SC_HANDLE schSCManager; schSCManager=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); StopDriver(schSCManager,Name);RemoveDriver(schSCManager,Name);CloseServiceHandle(schSCManager);Return TRUE;}

BOOL StopDriver(INSC_HANDLE SchSCManager,INLPCTSTR DriverName)

{SC_HANDLE schService; BOOL ret; SERVICE_STATUS serviceStatus;

schService=OpenService(SchSCManager,DriverName,SERVICE_ALL_ACCESS);

if(schService==NULL) return FALSE;

ret=ControlService(schService,SERVICE_CONTROL_STOP,&serviceStatus);CloseServiceHandle(schService);return ret;} BOOL RemoveDriver(INSC_HANDLE SchSCManager,INLPCTSTR DriverName)

{SC_HANDLE schService;BOOL ret;

schService=OpenService(SchSCManager,DriverName,SERVICE_ALL_ACCESS);

if(schService==NULL) return FALSE;

ret=DeleteService(schService);CloseServiceHandle(schService);return ret;}

BOOL DriverConnect(void)

{TCHAR Path[256];PVOID lpMsgBuf;

//open the handle to the device

GetCurrentDirectory(sizeofPath,Path);wsprintf(Path+lstrlen(Path),TEXT("\\%s"),SYS_FILE);

if(!LoadDeviceDriver(SYS_NAME,Path,&hCallgateDriver)){wsprintf(msgbuf,TEXT("Erroropening%s(%s):"),SYS_NAME,Path); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR)&lpMsgBuf,0,NULL);

MessageBox(NULL,msgbuf,(LPCTSTR)lpMsgBuf,MB_OK);LocalFree(lpMsgBuf);DriverDisconnect(); Return FALSE;} Return TRUE; }

BOOL DriverDisconnect(void)

{UnloadDeviceDriver(SYS_NAME);

Return TRUE; }

BOOL CallDriver(intMsg,PBYTEinData,intinDataLen,PBYTEoutData, Int outDataLen)

{ PVOID lpMsgBuf; ULONG nb;Int error;

if(!(error=DeviceIoControl(hCallgateDriver,Msg,inData,inDataLen,outData,outDataLen,&nb,NULL)))

{//if not being called from stats and error isn't device ready,print message

wsprintf(msgbuf,TEXT("PORTIOdrivererror:"));

FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR)&lpMsgBuf,0,NULL);

MessageBox(NULL,msgbuf,(LPCTSTR)lpMsgBuf,MB_OK);LocalFree(lpMsgBuf);return FALSE;}

Return TRUE;}

下面是一段调用的例子:

#include

#include

#include"..\dll\gatedll.h"

/*DeclarethefunctionpresentinRING0.ASM*/

__declspec(naked)voidfunc(int*cr0,int*cr2,int*cr3)

{__asm{

;Setup standard stack frame

Push ebp

Mov ebp,esp

;Issues a beep to show that you can do direct port I/O

;Not a good piece of 32-bit code,but still proves the fact

Push ad

Mov ax,1000

Mov bx,200

Mov cx,ax

Mov al,0b6h

Out 43h,al

Mov dx,0012h

Mov ax,34dch

Div cx

Out 42h,al

Mov al,ah

Out 42h,al

In al,61h

Mov ah,al

Or al,03h

Out 61h,al

l1:

mov ecx,4680

l2:

loopl2

dec bx

jnz l1

mov al,ah

out 61h,al

pop ad

;Save away the registers which we modify

Push esi

Push ebx

;Get the first paramter from EBP+0Ch,since this function is called via a farcall.

Mov esi,[ebp+0Ch]

Test esi,esi

Jz next

Mov ebx,cr0

Mov [esi],ebx

next:

mov esi,[ebp+10h]

test esi,esi

jz next1

mov ebx,cr2

mov [esi],ebx

next1:

mov esi,[ebp+14h]

test esi,esi

jz next2

mov ebx,cr3

mov [esi],ebx

next2:

;Restoretheregisters

Pope si

Pope bx

Pope bp

;Make a far return.Also follow the _stdcall calling convention.

Retf 0Ch };}

main()

{ WORD CallGateSelector;

Int rc;

Short farcall[3];

Int mcr0,mcr2,mcr3;

__try{

__asm hlt

__asm rdtsc }

__except(EXCEPTION_EXECUTE_HANDLER){ printf("Privilegedcoderaisedexception!!\n");}

rc=CreateCallGate(func,3,&CallGateSelector);

if(rc==SUCCESS){printf("Selectorallocated=%x\n",CallGateSelector);

farcall[2]=CallGateSelector;

_asm{

Lea esi,mcr3

Push esi

Lea esi,mcr2

Push esi

Lea esi,mcr0

Push esi

Call fwordptr[farcall] }

printf("cr0=%x,cr2=%x,cr3=%x\n",mcr0,mcr2,mcr3); rc=FreeCallGate(CallGateSelector);

if(rc!=SUCCESS) { printf("FreeCallGatefailed,CallGateSelector=%x,rc=%x\n",CallGateSelector,rc);}} else {printf("CreateCallGatefailed,rc=%x\n",rc);} return 0;}

9.4 小结

本章主要介绍几种典型的驱动程序开发,这些驱动程序主要用于实现端口读写。

9.5 思考题

如何实现Windows9x下的打印机端口读写?

9.6 练习题

使用本章的驱动程序,编写一个程序,实现端口的直接读写。

软件开发网络科技有限公司绩效管理办法与工资体系

XXX网络科技有限公司绩效管理办法 第一部分:二级部绩效思路 根据软件开发部现状,绩效管理的出台可能不能一步到位,要进行分步实施。就目前第一步要解决开发部的对绩效管理的认识。让成员把开发过程中的思路聚焦工作量,开发量的多少决定了他收入的高低。同时对质量、文档的要求也是其中因素。 软件开发部的初步绩效管理办法应制定的简单、易行但又能关注到重点。第二步是在第一步的积累基础上对工作量的评估有的指导和参考依据后进行工作标准化,即每人的工作量会以一个标准工单价进行核算。 第二部门:二级绩效考核办法 1、绩效考核目的 绩效考核是一个正面的激励办法。部门通过一个有效可行的对员工工作各层面进行监督、指导的一个管理制度下帮助员工理解自己的职责和目标,充分调动员工的工作积极性和创造性,在部门、公司建立起一个绩效导向的氛围,促进部门、公司的各项目标的实现。 总结一句话,绩效管理就是要让员工主动的、积极的、高效的、增收的一个管理办法,让个人和团队从中受惠的一个手段。 2、薪酬结构体系 按部门组织结构设置,部门薪酬结构要分成两部门: 行政管理薪酬结构 工资总额=岗位工资+绩效+福利 岗位工资按岗位层级划分;绩效工资按实际绩效考核发放;福利按公司标准发放不参与绩效考核;其中,岗位工资是相对固定不变的,只会随着岗位升降而加减。 岗位工资占工资总额80%;绩效工资占工资总额20%。福利不占工资总额。 技术岗位薪酬结构 工资总额=岗位工资+绩效+项目提成+福利 岗位工资按技术能力考核,考核结果作为岗位层级划分依据;绩效工资按实

际绩效考核发放,绩效不封顶根据员工技术能力和工作效率进行考核发放;福利按公司标准发放不参与绩效考核;其中,岗位工资是相对固定不变的,只会随着岗位升降而加减。 岗位工资占工资总额80%;绩效占工资总额20%。福利不占工资总额。 项目提成在完成项目组业务收入超出部分按比例抽取项目提成发放项目组成员。 项目经理岗位薪酬结构 工资总额=岗位工资+绩效+项目提成+营销提成+福利 项目经理除与上述技术员工同等外加营销提成,因为项目经理在部门要充当营销角色,营销提成部门不做管理办法,以公司营销制度为准;其次项目经理项目提成为季度发放; 岗位工资占工资总额80%;绩效占工资总额20%。福利不占工资总额。(按照公司规定) 项目提成在完成项目组业务收入超出部分按比例抽取项目提成发放项目组成员。 3、基本薪酬与绩效比例 上面所提及的软件开发人员基本薪酬与绩效比例为80:20,这里面有我的主观考虑。主要原因为目前软件开发人员的人均水平在行业中来看处于一个偏下水平,而处于这种水平中的人员思想是不成熟和不安定的,他们是在一个心不稳,低不就的尴尬线上。工资的波动对他们是会造成比较大的不可靠因素,所以我在确定人工成本时候把这点考虑进去。 4、绩效考核内容 部门绩效考核我认为要以目标为导向,考核从两个层面四个维度进行。 第一:项目经理层面 项目计划 项目质量 项目进度 项目成本 项目回款 第二:开发工程师层面

软件开发项目建议书

报告说明《软件开发项目建议书》是中经先略针对软件开发项目编制的项目论证建议书是拟上项目单位向政府项目管理部门申报的项目申请。也是企业和投资者挑选项目的依据。软件开发建议书的审批过程实际就是国家根据有关投资政策、产业政策对软件开发项目进行比较筛选综合评定项目的必要性。软件开发项目是中经先略根据国民经济的发展、国家和地方中长期规划、产业政策、生产力布局、国内外市场、所在地的内外部条件提出的软件开发项目的建议文件是对拟建软件开发项目提出的框架性的总体设想。《软件开发项目建议书》主要包括软件开发项目总论、软件开发项目建设的必要性和条件、软件开发项目建设规模与产品方案、软件开发项目技术方案、软件开发项目设备方案和工程方案、软件开发项目投资估算及资金筹措、软件开发项目效益分析、结论等。报告目录第一章总论一、项目名称二、承办单位概况新建项目指筹建单位情况技术改造项目指原企业情况三、拟建地点四、建设内容与规模五、建设年限六、概算投资七、效益分析第二章软件开发项目建设的必要性和条件一、建设的必要性分析二、建设条件分析包括场址建设条件地质、气候、交通、公用设施、征地拆迁工作、施工等、其它条件分析政策、资源、法律法规等三、资源条件评价第三章软件开发项目建设规模与产品方案一、建设规模达产达标后的规模二、产品方案拟开发产品方案第四章软件开发项目技术方案、设备方案和工程方案一、技术方案1、生产方法包括原料路线2、工艺流程二、主要设备方案1、主要设备选型列出清单表2、主要设备来源三、工程方案1、建、构筑物的建筑特征、结构及面积方案附平面图、规划图2、建筑安装工程量及“三材”用量估算3、主要建、构筑物工程一览表第五章软件开发项目投资估算及资金筹措一、投资估算1、建设投资估算先总述总投资后分述建筑工程费、设备购置安装费等2、流动资金估算3、投资估算表总资金估算表、单项工程投资估算表二、资金筹措1、自筹资金2、其它来源第六章软件开发项目效益分析一、经济效益1、销售收入估算编制销售收入

某大型公司软件开发管理制度

某大型公司公司软件开发管理制度 版本:1.0 SDM审批: QA经理[时间] CTO[时间] 目录 1.目的和作用3 2.适用范围:3 3. 参考文件3 4.适用对象3 5.软件开发流程4 5.1可行性研究与计划4 5.1.1实施4 5.1.2 文档4 5.1.2.1 应交付的文档4 5.1.2.2 提交步骤4 5.2需求分析4 5.2.1实施4 5.2.2要求5 5.2.3交付文档5 5.2.4审批5 5.3概要设计5 5.3.1实施5 5.3.2要求6 5.3.3交付文档6 5.3.4补充说明6 5.3.5审批6 5.4详细设计7 5.4.1实施7 5.4.2要求7 5.4.3文档7 5.4.4审批7 5.5实现7 5.5.1实施与要求7 5.5.2交付文档8 5.5.3审批8 5.6组装测试8 5.6.1实施8 腹有诗书气自华

5.6.2要求8 5.6.3交付文档8 5.6.4审批8 5.7确认测试9 5.7.1实施9 5.7.2要求9 5.7.3交付文档9 5.7.4 补充说明9 5.7.5 审批9 5.8发布10 5.8.1过程10 5.8.2 文档10 5.8.3 审核10 5.9 交接10 6. 附录1:项目文档清单11 1.目的和作用 本流程详细规定软件开发程的各个阶段及每一阶段的任务、要求、交付文件,使整个软件开发过程阶段清晰、要求明确、任务具体,实现软件开发过程的标准化。 2.适用范围: 公司的软件开发产品均适用。 3. 参考文件 各种文档模板 文档命名规则 交接流程 4.适用对象 软件管理人员,软件开发人员,软件维护人员 5.软件开发流程 5.1可行性研究与计划 5.1.1实施 5.1.1.1 软件开发部分析人员进行市场调查与分析,确认软件的市场需求 5.1.1.2 在调查研究的基础上进行可行性研究,写出可行性报告 5.1.1.3 评审和审批,决定项目取消或继续 5.1.1.4 若项目可行,制订初步的软件开发计划,建立项目日志 5.1.1.5 根据市场环境、公司软硬件情况预测十大风险因素 5.1.2 文档 5.1.2.1 应交付的文档 1)可行性研究报告* 2)初步的软件开发计划 3)十大风险列表* 腹有诗书气自华

xx科技-软件系统开发合同

编号:_______________本资料为word版本,可以直接编辑和打印,感谢您的下载 xx科技-软件系统开发合同 甲方:___________________ 乙方:___________________ 日期:___________________

软件系统业务类开发合同 编号:XX- SOFT - N 201110002 甲方:XXXX 乙方:XX科技有限公司 2011年10.月19日 合同正文 经甲、乙双方协商确定,乙方从甲方承接软件模块开发工作,为明确双方责任和权利,保证双 方的利益,双方签订本合同,共同遵守。具体条款如下: 一、项目内容 1. 1.甲方授权乙方进行开发:管理系统 1. 2.乙方在充分了解甲方待开发的模块基本要求并签订好本合同之后,由甲方向乙方提供该模 块的〈〈详细开发说明书》及其他相关文件、资料。具体要求详见合同附件一。(若在开发过程中甲

方的开发需求有改变,则涉及合同的相关文件及费用由双方协商相应改变,合同的执行时间也作相 应改变)。 1. 3.本合同的所有附件是合同的必须附件,与合同主体一起构成整个合同的全部要件。 二、开发费用 甲、乙双方认定本合同开发费用总金额为大写人民币元(大写:);该合同的最终费用总额是指定开发模块经甲方最终验收后再确定的全部费用。 合同执行过程中如开发需求有改变或甲方最终验收后而导致合同的总费用有改变,则以改变后的总 费用作为经甲方最终付给乙方的合同全部费用。 三、项目的承接、开发及验收 3. 1承接 甲乙双方经确定签定此合同之后,即正式承接该项目。具体开发计划: 2011年J—日---2011年—月—日软件项目开发期。 2011年"—日---2011年—月—日软件系统试运行期和系统磨合期,针对期间对甲方提出的软 件系统的修改方案,乙方对系统进行完善。 3. 2开发标准 3.2.1乙方必需以提供模块功能的方式,让甲方进行验收工作。 3.2.2乙方保证合同模块的功能符合甲方〈〈项目功能详细说明书》的要求。 3.2.3乙方保证合同模块的代码编写符合甲方〈〈编码标准》的要求。 3.2.4乙方保证合同模块的相关文档的编写符合甲方〈〈文档编写要求》的要求 3. 3验收方式 乙方必需以提供模块功能和源代码的方式,让甲方进行验收工作。具体步骤为: (1)、乙方提交功能。 (2)、甲方验收功能,同时反馈信息,提供〈〈功能验收报告》。 (3)、乙方根据验收报告修改,提供源代码。 (4)、甲方验收源代码,提供〈〈代码验收报告》。 (5)、乙方修改源代码,全部提交。 (6)、甲方公布最终评分,并提供最终验收报告。 (7)、甲方按本合同的相关约定向乙方支付开发费用。 乙方提交项目的方式:()电子邮件,()光盘邮寄,()其它()。

软件开发工具复习资料(自考)

1)软件开发工具范围:在高级程序设计语言的基础上,为提高软件开发的质量 和效率,从规划分析设计测试成本和管理各方面,对软件开发者提供各种不同程度的帮助的一类广泛的软件。应当为软件人员提供信息管理,信息存储一致性的保证提供帮助支持。 2)SDT 3个发展阶段:通用工具,专用工具,集成工具。 3)软件开发工具的概念:在高级程序设计语言后进一步发展的产物,目的是给 与人们在开发软件过程中不同方面和程度的支持或帮助,支持开发的全过程而不是仅限编码或其他特定工作阶段。 4)软件的意义:硬件是躯体,软件是灵魂;软件是用户和计算机的桥梁;软件 是人类知识与经验的结晶,一种新的载体。 5)通用软件弱点:许多工作无法完成,不能反映逻辑内涵,难于保持一致性。 6)专用软件弱点:对软件开发缺乏全面统一的支撑环境造成冲突和矛盾。 7)软件开发发展阶段:机器语言开发软件,汇编语言开发转换,高级语言开发 编译程序转换,各种软件开发工具完成编译程序转换。(项目管理版本控制软件重用新问题) 8)新的软件开发方法表现在四个方面特点:自动化程度提高,进一步向用户延 伸,延伸到项目版本管理扩展到不断发展生长完善的全过程。 9)4GL:非过程化的程序设计语言,针对以处理过程为中心的第三代语言他希 望通过某些标准处理过程的自动生成使用户可以只说明要求做什么,而把具体的执行步骤安排交给软件自动处理。 10)CASE:计算机辅助软件工程或计算机辅助系统工程,应用计算机自身处理信 息的巨大能力来帮助人们开发复杂的软件或应用系统,。 11)软件开发过程5阶段:初始要求提出需求分析(软件功能说明书),总体设 计,程序文档的编写,测试调试阶段,维护。 12)软件工作的困难体现:复杂性,多样性,可维护性,可重用性。 13)SDT功能(定性):认识与描述客观系统,存储管理开发过程中的信息,代码 的编写生成,文档的编制生成,软件项目的管理。 14)SDT性能(定量):表达能力或描述能力,保持信息一致性的能力,使用的方 便程度,工具的可靠程度,对软硬件环境的要求。 15)SDT划分:A按工作阶段分—设计工具,分析工具,计划工具 B 按集成程度分---单项,集成 C按与硬件软件的关系分—依赖于特定的计算机或软件,独立于 硬件与其他软件。 16)软件开发过程2个转换:用户的理解—程序员的理解---程序的实现。 17)大型软件开发的困难:一致性保持困难,测试的困难大大增加(水波效应), 工作进度难以控制,文档与代码协调困难,版本更新带来的困难。 18)大型软件是现代化生产,单个程序是手工作坊。 19)困难产生的原因:大系统的复杂性,个人组织与协调的困难,各应用领域的 差别,时间和变化的因素。 20)用户任务:提出要求验收使用要求修改。程序员任务:编写程序文档,调试 自己编码的程序想项目负责人提交工作进展。项目负责人任务:分析需求,分配任务,验收联调,向用户交付使用,接受分析用户的修改要求布置修改任务验收修改成果并再提交。 21)结构化程序设计把程序的结构分解成3种基本模块:处理单元,循环机制,

某科技公司软件开发流程

众思达科技软件项目开发流程 1.总纲 目的 主要讲述如何组织开发软件项目,使之更加快速、有效的完成。并分成以下几个阶段进行详细讲述:项目计划阶段、需求分析阶段、软件开发阶段、测试阶段、管理软件开发过程、各参与角色的具体职责描述及对人员的要求。 适用范围 开发周期3周、开发人月2人月的项目,中小型(3-7人)软件项目的开发指南,而大型软件项目使用RUP会更好。 注:周期小于上述范围,使用开发任务需求单进行安排,走任务开发流程。 总体流程 计划阶段-》需求分析阶段-》软件开发阶段-》测试阶段-》完成2.项目计划阶段 项目计划草案和风险管理计划作为第一步,当有一个商业机会后,根据公司高层负责制定的初步商业计划书来完成项目的计划草案,确定、分析项目风险并确定其优先级,还要制定风险解决方案。本阶段的目的是确立产品开发的经济理由。 当确定开发之后则制定软件开发计划、人员组织结构定义及配备、过程控制计划。

(1)项目计划草案 项目计划草案应包括产品简介、产品目标及功能说明、开发所需的资源、开发时间和里程碑。 (2)风险管理计划 也就是把有可能出错或现在还不能确定的东西列出来,并制定出相应的解决方案。风险发现得越早对项目越有利。 (3)软件开发计划 软件开发计划的目的是收集控制项目时所需的所有信息,项目经理根据项目计划来安排资源需求并根据时间表跟踪项目进度。项目团队成员根据项目计划以了解他们的工作任务、工作时间以及他们所依赖的其他活动。 可将计划分成总体计划和详细计划,总体计划中每个任务为一个里程碑,详细计划中必须将任务落实到个人。 软件开发计划还应包括产品的应收标准及应收任务(包括确定需要制订的测试用例)。 (4)人员组织结构定义及资源计划 常见的人员组织结构有垂直方案、水平方案、混合方案。垂直方案中每个成员充当多重角色。水平方案中每个成员充当一到两个角色。混合方案则包括了经验丰富的人员与新手相互融合。具体选择根据人员实际技能情况进行选择。 适用范围:开发人月大于5人月、周期超过2个月、投入人员4人以上的项目必须编写计划,低于范围的则可省略或者简化

通信工程设计辅助软件工具的开发设想

通信工程设计辅助软件工具的开发设想 作者:贾海龙 来源:《电子世界》2012年第17期 【摘要】本文通过利用VBA应用和VB语言编写的设计辅助工具,实现了在设计过程中的数据精确查询、检索、计算、自动报表生成,并延伸到利用软件开发图纸自动化生成功能。阐述了为进一步提高设计基础数据的准确性、缩短设计周期、提高工作效率,进行设计辅助工具软件的开发是可行的和必要的。 【关键词】数据库;VBA;VB;LISP;设计辅助工具软件 1.概述 目前通信行业工程设计从立项到完成设计会审以及后期工程配合,设计周期短则两个月,多则半年。在此过程中,设计人员需要进行大量的手工测量、计算、验证,并完成种类繁多的文本、附表和图纸。由于目前还没有统一的数据库支持、在设计编制过程中,往往出现设计基础数据不一致,容易导致设计质量和效率不高以及设计周期较长的问题。笔者在长期从事设计工作中注意到设计工作中大部分繁琐的工作完全可以通过软件来实现,从而提高设计基础数据的准确性,缩短设计周期,提高工作效率。 对于大多数设计人员来说,如何提高设计质量和效率以及缩短设计周期是一直困扰大家的一个老问题。每个设计人员在多年的设计工作中形成了自己的设计编制方法和风格,而正是这些不同的方法和风格造成了在调用其他设计人员设计时感到不习惯,使得修改的工作量增加,工作效率低下。如果我们大家统一设计方法和风格就可以大大提高工作效率。最好的例子就是模板的使用,大大提高了设计的效率。而正是模板的使用也为实现设计辅助工具软件开发成为可能。笔者提出开发设计辅助工具提高通信工程设计效率的想法,在这里和大家一同分享与探讨。 2.建立数据库方便查询、检索及生成报表 设计辅助工具软件开发需要大量数据库进行支持,目前通信工程设计基础数据比较庞杂,没有建设统一的数据库,设计人员查询、检索极为不便,由于版本的问题,也容易造成数据准确性不高。所以建立统一的数据库是解决问题的做好方法。 笔者在交换数据库建设的课题中体会到,数据库要针对设计基础数据的需求来建立。设计中涉及的数据我们都可以建立数据库,例如:建立所有网元信息数据库;建立所有电源信息数据库;建立所有设备信息数据库。通过网元网元信息数据库我们可以查询、检索到各网元的信息并生成各种网元的信息报表;通过电源信息数据库可以生成电源说明文本,如:XAGS3挂接在枢纽楼六层南第二套直流系统,此电源系统为珠江设备,设备型号为PRS5000,配置了2

大型软件开发过程的质量管理体系

大型软件开发过程的质量管理体系  韩思音 弋陪余    国信朗讯科技网络技术有限公司是中国电信和朗讯科技合资的专业从事通信网络管理软件开发的高科技企业,公司位于上海浦东,注册资金2 980万美元,员工达150人,本科以上学历超过95%。公司在1999年成立后就开展了ISO9001贯标活动,并于2000年8月通过了ISO9001认证。公司以贝尔试验室的大型软件开发管理流程为基础,建立了自己的ISO9001质量管理体系。三年来已经开发了“传输网络集中监控系统NetGuard”、“电信网络资源管理系统NetMaster”两个大型软件系统。通过ISO9001的贯标活动,加强了公司全体员工的质量意识,强化了软件开发过程的规范性,改进了软件开发过程,保证了软件开发的质量,对加强公司实力、提高市场形象起了很好的推动作用。  通过了ISO9001认证后,审核机构每年要进行一次复查,即监督审核。如果公司质量体系运行得不好,就可能被暂停证书;如发生重大事故,证书可能被撤消。除此以外,公司每年还进行一次内审,即公司内部对质量体系运行是否符合ISO9001标准进行的检查,各部门对内审发现的不符合项进行认真整改,由质量管理部验收。各部门对本部门的工作定期提出改进措施,由质量管理部对其进行验证,使质量体系不断改进。所以ISO9001的认证对企业的质量体系是有严格管理的,是有保证的。  1 软件产品质量的特点  按照ISO9126的定义,软件的质量通常可以从以下六个方面去衡量(定义)。  1)功用性(Functionality),即软件是否满足了客户功能要求。  2)可靠性(Reliability),即软件是否能够一直在一个稳定的状态上满足可用性。  3)可用性(Usability),即衡量用户能够使用软件需要多大的努力。  4)效率(Efficiency),即衡量软件正常运行需要耗费多少物理资源。  5)可维护性(Maintainability),即衡量对已经完成的软件进行调整需要多大的努力。  6)可移植性(Portability),即衡量软件是否能够方便地部署到不同的运行环境中。  可见,同其它产品相比,软件产品的质量有其明显的特殊性。

软件开发计划(SDP)

1 引言 本章分为以下几条。 1.1标识 本条应包含本文档适用的系统和软件的完整标识,(若适用)包括标识号、标题、缩略词语、版本号和发行号。 1.2系统概述 本条应简述本文档适用的系统和软件的用途,它应描述系统和软件的一般特性;概述系统开发、运行和维护的历史;标识项目的投资方、需方、用户、开发方和支持机构;标识当前和计划的运行现场;列出其他有关的文档。 1.3文档概述 本条应概述本文档的用途和内容,并描述与其使用有关的保密性和私密性的要求。 1.4与其他计划之间的关系 (若有)本条描述本计划和其他项目管理计划的关系。 1.5基线 给出编写本项目开发计划的输入基线,如软件需求规格说明。 2引用文件 本章应列出本文档引用的所有文档的编号、标题、修订版本和日期,本章也应标识不能通过正常的供货渠道获得的所有文档的来源。 3交付产品 3.1 程序 3.2文档 3.3服务 3.4非移交产品 3.5验收标准 3.6最后交付期限 列出本项目应交付的产品,包括软件产品和文档。其中,软件产品应指明哪些是要开发的,哪些是属于维护性质的;文档是指随软件产品交付给用户的技术文档,例如用户手册、安装手册等。 4所需工作概述 本章根据需要分条对后续章描述的计划作出说明,(若适用)包括以下概述: a.对所要开发系统、软件的需求和约束; b.对项目文档编制的需求和约束; c.该项目在系统生命周期中所处的地位; d.所选用的计划/采购策略或对它们的需求和约束; e.项目进度安排及资源的需求和约柬; f.其他的需求和约束,如:项目的安全性、保密性、私密性、方法、标准、硬件开发和软件开发的相互依赖关系等。 5实施整个软件开发活动的计划 本章分以下几条。不需要的活动的条款用“不适用”注明,如果对项目中不同的开发阶段或不同的软件需要不同的计划,这些不同之处应在此条加以注解。除以下规定的内容外,每条中还应标识可适用的风险和不确定因素,及处理它们的计划。 5.1软件开发过程 本条应描述要采用的软件开发过程。计划应覆盖论及它的所有合同条款,确定已计划的开发阶段(适用的话)、目标和各阶段要执行的软件开发活动。 5.2软件开发总体计划

软件开发环境与工具试题与概念整理

第1章软件开发环境与工具的相关概念 1、什么是软件开发环境? 软件开发环境是指在计算机的基本软件的基础上,为了支持软件的开发而提供的一组工具软件系统。 2、软件开发环境可分为以下4层结构: 宿主层、核心层、基本层、应用层。 3、软件开发环境的分类: 1)按解决的问题分类 2)按软件开发环境的演变趋向分类 3)按集成化程度分类 4、软件开发工具 软件开发工具(Software Development Tool)是用辅助软件生命周期过程的基于计算机的工具。 5、CASE的概念 即计算机辅助软件工程,是一组工具和方法集合,可以辅助软件开发生命周期各阶段进行软件开发。 6、CASE分类 1)CASE技术种类 支持软件开发过程本身的技术(如:支持规约、设计、实现、测试等); 元-CASE技术。 2)CASE工具的分类 功能、支持的过程、支持的范围。 7软件开发环境的折旧问题 1)年限平均法 2)工作量法 3)双倍余额递减法 4)年数总和法 第2章软件开发工具功能与结构 1、软件开发工具的基本功能: (1)提供描述软件状况及其开发过程的概念模式,协助开发人员认识软件工作的环境与要求、管理软件的开发过程; (2)提供存储和管理有关信息的机制与手段; (3)帮助使用者编制、生成和修改各种文档,包括文字材料和各种表格、图像等; (4)生成代码,即帮助使用者编写程序代码,使用户能在较短时间内自动地生成所需要的代码段落,进行测试和修改; (5)对历史信息进行跨生命周期的管理。 2、软件开发工具的一般结构包括哪几个部分?(掌握4个技术要素) 软件开发工具的一般结构如图所示。

包括:总控部分及人机界面、信息库(repository)及其管理、代码生成及文档生成、项目管理及版本管理是构成软件开发工具的四大技术要素。 第3章软件开发环境与工具的选用 1、软件工程过程P24 软件过程的活动工具通常可分为: ①支持软件开发过程的工具:如需求分析工具、需求跟踪工具、设计工具、编码工具、排错工具、测试和集成工具等; ②支持软件维护过程的工具:版本控制工具、文档工具、开发信息库工具、再工程工具(包括逆向工程工具、代码重构与分析工具)等; ③支持软件管理和支持工程的工具:项目计划工具、项目管理工具、配置管理工具、软件评价工具、度量和管理工具等。 2、工具的采用过程 1)准备过程 2)评价和选择过程 3)试验项目过程 4)转换过程 3、CASE工具的选择与评价 1)初始准备过程 2)构造过程 3)评价过程 4)选择过程 第4章需求分析与设计工具 1、需求分析工具概念 2、需求分析工具分类 (1)从自动化程度 以人工方式为主的需求分析工具。 以自动化方式为主的需求分析工具。

常用软件开发模型比较分析

常用软件开发模型比较分析 2007-09-26 20:21 正如任何事物一样,软件也有其孕育、诞生、成长、成熟和衰亡的生存过程,一般称其为“软件生命周期”。软件生命周期一般分为6个阶段,即制定计划、需求分析、设计、编码、测试、运行和维护。软件开发的各个阶段之间的关系不可能是顺序且线性的,而应该是带有反馈的迭代过程。在软件工程中,这个复杂的过程用软件开发模型来描述和表示。 软件开发模型是跨越整个软件生存周期的系统开发、运行和维护所实施的全部工作和任务的结构框架,它给出了软件开发活动各阶段之间的关系。目前,常见的软件开发模型大致可分为如下3种类型。 ① 以软件需求完全确定为前提的瀑布模型(Waterfall Model)。 ② 在软件开发初始阶段只能提供基本需求时采用的渐进式开发模型,如螺旋模型(Spiral Model)。 ③ 以形式化开发方法为基础的变换模型(T ransformational Model)。 本节将简单地比较并分析瀑布模型、螺旋模型和变换模型等软件开发模型。 1.2.1 瀑布模型瀑布模型即生存周期模型,其核心思想是按工序将问题化简,将功能的实现与设计分开,便于分工协作,即采用结构化的分析与设计方法将逻辑实现与物理实现分开。瀑布模型将软件生命周期划分为软件计划、需求分析和定义、软件设计、软件实现、软件测试、软件运行和维护这6个阶段,规定了它们自上而下、相互衔接的固定次序,如同瀑布流水逐级下落。采用瀑布模型的软件过程如图1-3所示。

图1-3 采用瀑布模型的软件过程 瀑布模型是最早出现的软件开发模型,在软件工程中占有重要的地位,它提供了软件开发的基本框架。瀑布模型的本质是一次通过,即每个活动只执行一次,最后得到软件产品,也称为“线性顺序模型”或者“传统生命周期”。其过程是从上一项活动接收该项活动的工作对象作为输入,利用这一输入实施该项活动应完成的内容给出该项活动的工作成果,并作为输出传给下一项活动。同时评审该项活动的实施,若确认,则继续下一项活动;否则返回前面,甚至更前面的活动。瀑布模型有利于大型软件开发过程中人员的组织及管理,有利于软件开发方法和工具的研究与使用,从而提高了大型软件项目开发的质量和效率。然而软件开发的实践表明,上述各项活动之间并非完全是自上而下且呈线性图式的,因此瀑布模型存在严重的缺陷。 ① 由于开发模型呈线性,所以当开发成果尚未经过测试时,用户无法看到软件的效果。这样软件与用户见面的时间间隔较长,也增加了一定的风险。 ② 在软件开发前期末发现的错误传到后面的开发活动中时,可能会扩散,进而可能会造成整个软件项目开发失败。 ③ 在软件需求分析阶段,完全确定用户的所有需求是比较困难的,甚至可以说是不太可能的。 1.2.2 螺旋模型螺旋模型将瀑布和演化模型(Evolution Model)结合起来,它不仅体现了两个模型的优点,而且还强调了其他模型均忽略了的风险分析。这

软件开发部岗位职责(重点哦)

软件部经理岗位职责 职位名称:软件部经理 所属部门:软件部 直属上级:技术总监 职位概要:负责软件工程项目的具体实施、自有产品及基础技术的开发。 工作内容:管理、组建公司开发团队,参与公司相关政策的制定;拟定和执行本部门年度、月度目标、工作计划及总结;设计、开发、维护、管理软件产品。 一、直接职责 1、拟定本部门年度、月度目标、工作计划及总结; 2、负责本部门的成本控制工作以及本部门员工的绩效考评及监督、管理工作; 3、参与技术业务制定流程及与其他部门的协调工作; 4、领导技术团队并组织实施年度工作计划,完成年度任务目标; 5、负责管理公司的整体核心技术,组织制定和实施重大技术决策和技术方案; 6、负责协调项目开发或实施的各个环节,把握项目的整体进度; 7、指导、审核项目总体技术方案,对各项目结果进行最终质量评估; 8、会同项目经理共同审核项目组内部测试计划,并组织项目组负责软件项目的后期维护工作;

9、针对部门的发展计划,向公司提供部门员工的培训要求,抓好部门员工的专业培训工作; 10、本部门的发展规划,组织审定部门各项技术标准,编制、完善软件开发流程; 11、负责与其他部门之间的沟通与协作,满足和协调公司各相关部门提出的系统更新、新产品等技术需求; 12、关注国内外软件市场的发展动向、最新技术及信息,组织内部技术交流。 13、配合市场部门开展工作,向市场部门提供必要的技术支持。 14、需求调研中,配合项目经理进行需求调研工作,并对生成的需求调研报告进行审核评定。 15、明确文档编写种类及格式,对项目组需要生成的文档进行质量、数量和时间控制,并组织召开评审会; 16、制度本部门人员短期和长期需求计划,并配合行政部的人员招聘工作; 二、管理职责 1、抓好本部门项目组总结分析报告工作,定期进行项目分析、总结经验、找出存在的问题,提出改进工作的意见和建议,并组织本部门员工学习,为公司领导决策提供专题分析报告或综合分析资料; 2、开展公司的市场经营和客户服务工作,组织开展市场调查、经营分析,掌握竞争对手动态,及时组织竞争方案的制定和实施,确保公司在市场竞争中的主动;

软件开发与实例分析

软件开发与设计实例分析01026(201204) 一、单项选择题 1.管理信息系统的三项主要功能是:信息处理、辅助事务处理和辅助组织管理以及(C ) A.任务执行 B.临界预警 C.支持决策 D.辅助预测 2. 软件开发分为8个阶段,其中解决的项目的名称、背景、开发该系统的现状,项目的目标等问题的阶段是( A ) A. 问题定义阶段 B. 可行性研究阶段 C. 需求分析阶段 D. 总体设计阶段 3. 下列的陈述中属于软件系统功能需求的是( A ) A. 用户可以浏览公司的图片信息 B. 2000个用户可以同时在线访问系统 C. 系统的Web服务器:Tomcat D. 浏览器支持Internet Explore, Netscape 4. 下面是注册模块的IPO图: 输入:点击”公司简介”超链接按钮. 处理:现实由HTML语言编辑的静态页面 输出:”公司简介”页面 该模块图用于软件开发的阶段是( D ) A. 总体设计阶段 B. 问题定义阶段 C. 需求分析阶段 D. 详细设计阶段 5. 在开发一个企业网站的过程中,为了管理大量的关联数据,所应使用的技术是( B ) A. 文件技术 B. 数据库技术 C. 信息池技术 D. 数据连接池技术 6. 对组织的数据和信息进行收集、储存、传输、加工查询等操作,以实现向管理人员及时提 供所需的可靠、准确信息的功能,属于管理信息系统的( A ) A. 信息处理功能 B. 辅助事务处理功能 C. 支持决策功能 D. 辅助组织管理功能 7. 软件开发分为8个阶段,其中解决系统目标和规模是否能实现,系统方案在经济上、技 术上和操作上是否可以接受等问题的阶段是( B ) A. 问题定义阶段 B. 可行性阶段 C. 需求分析阶段 D. 总体设计阶段 8. 下面的陈述中属于软件系统性能需求的是 ( C ) A. 用户可以浏览公司的图片信息 B. 增加、修改、删除图片信息 C. 系统的Web服务器:Tomcat D. 用户可以随时发表自己的言论 9. 系统详细设计阶段,用于描述模块功能的工具是 (D ) A.系统结构图 B. ER图 C. 功能结构图 D. IPO图 10. 为了从数据库中查询已经存在的数据,首先应当(B ) A. 安装数据库 B. 连接数据库 C. 备份数据库 D. 初始化数据库 11. 下列陈述中属于软件系统性能需求的是(D ) A. 在线进行考试 B. 对在线测试的试题进行管理

大型软件开发人员的组织与分工

大型软件开发人员的组织与分工 大型软件项目需要很多人的能力合作,花费一年或数年的时间才能完成。为了提高工作效率,保证工作质量,软件开发人员的组织、分工与管理是一项十分重要和复杂的工作,它直接影响到软件项目的成功与失败。首先,由于软件开以人员的个人素质与差异很大,因此对软件开发人员的选择、分工十分关键。1970年,Sackman对12名程序员用两个不同的程序进行试验,结论是:程序排错、调试时间差别为18:1;程序编制时间差别为15:1;程序长度庆功别为6:1;程序运行时间差别为13:1。近年来,随着软件开发方法的提高、工具的改善,上述差异可能会减小,但软件人员的合理选择及分工,充分发挥每个人的特长和经验显然是十分重要的。其次,因为软件产品不易理解、不易维护,因此软件人员的组织方式十分关键。一个重要的原则是,软件开发人员的组织结构与软件项目开发 模式和软件产品的结构相对应,这样可以达到软件开发的方法、工具、与人的统一,从而降低管理系统的复杂性,有利于软件开发过程的管理与质量控制。按树形结构组织软件开发人员是一个比较成功的经验。树的根是软件项目经理和项目总的技术负责人。理想的情况是项目经理和技术负责人由一个 人或一个小组担任。树的结点是程序员小组,为了减少系统的复杂性、便于项目管理,树的结点每层不要超过7个,在此基础上尽量降低树的层数。程序员小组的人数应视任务的大小和完成任务的时间机时定,一般是2~5人。为降低系统开发过程的复杂性,程序员小组之间,小组内程序员之间的任务界面必须清楚并尽量简化。 按“主程序员”组织软件开发小组是一条比较成功的经验。“主程序员”应该是“超级程序员”。其他成员,包括程序员、后备工程师等,是主程序员的助手。主程序员负责规划、协调和审查小组的全部技术活动。程序员负责软件的分析和开发。后备工程师是主程序员的助手,必要时能代替主程序员领导小组的工作并保持工作的连续性。软件开发小组还可以根据任务需要配备有关专业人员,如数据库设计人员、远程通信和协调,提高了工作效率。这种形式的成败主要取决于程序员的技术和管理水平。除了按主程序员负责的程序员小组组织开发人员外,还可以按“无我程序设计”建立软件民主开发小组。这各组织形式强调组内成员人人平等,组内问题均由集体讨论决定。这种组织形式有利于集思广益、互相取长补短,但工作效率比较低。 软件项目或软件开以小组可以配置若干个秘书、软件工具员、测试员、编辑和律师等。秘书负责维护和软件配置中的文档、源代码、数据及所依附的各种磁介质;规范并收集软件开发过程中的数据;规范并收集可重用软件,对它们分类并提供检索机制;协助软件开发小组准备文档,对项目中的各种参数,如代码行、成本、工作进度等,进行估算;参与小组的管理、协调和软件配置的评估。大型软件项目需专门配置一个或几个配置管理人员,专门负责软件项目的程

xx科技-软件系统开发合同

XX科技有限公司 软件系统业务类开发合同 编号:XX- SOFT - N 201110002 甲方:XXXX 乙方:XX科技有限公司 2011年10月19日

合同正文 经甲、乙双方协商确定,乙方从甲方承接软件模块开发工作,为明确双方责任和权利,保证双 方的利益,双方签订本合同,共同遵守。具体条款如下: 一、项目内容 1. 1 ?甲方授权乙方进行开发:管理系统 1. 2?乙方在充分了解甲方待开发的模块基本要求并签订好本合同之后,由甲方向乙方提供该模 块的《详细开发说明书》及其他相关文件、资料。具体要求详见合同附件一。(若在开发过程中甲方的开发需求有改变,则涉及合同的相关文件及费用由双方协商相应改变,合同的执行时间也作相应改变)。 1. 3.本合同的所有附件是合同的必须附件,与合同主体一起构成整个合同的全部要件。 二、开发费用 甲、乙双方认定本合同开发费用总金额为大写人民币____________ 元(大写:_______ );该合同的最终费用总额是指定开发模块经甲方最终验收后再确定的全部费用。 合同执行过程中如开发需求有改变或甲方最终验收后而导致合同的总费用有改变,则以改变后的总费用作为经甲方最终付给乙方的合同全部费用。 三、项目的承接、开发及验收 3. 1承接 甲乙双方经确定签定此合同之后,即正式承接该项目。具体开发计划: 2011年—月—日---2011年—月—日软件项目开发期。 2011年—月—日---2011年—月—日软件系统试运行期和系统磨合期,针对期间对甲方提出的软件系统的修改方案,乙方对系统进行完善。 3. 2开发标准 3.2.1乙方必需以提供模块功能的方式,让甲方进行验收工作。 3.2.2乙方保证合同模块的功能符合甲方《项目功能详细说明书》的要求。 3.2.3乙方保证合同模块的代码编写符合甲方《编码标准》的要求。 3.2.4乙方保证合同模块的相关文档的编写符合甲方《文档编写要求》的要求 3. 3验收方式

某大型公司软件开发管理制度.doc

某大型公司软件开发管理制度1 某大型公司公司软件开发管理制度 版本:1.0 SDM审批: QA经理[时间] CTO[时间] 目录 1.目的和作用3 2.适用范围:3 3. 参考文件3 4.适用对象3 5.软件开发流程4 5.1可行性研究与计划4 5.1.1实施4 5.1.2 文档4 5.1.2.1 应交付的文档4 5.1.2.2 提交步骤4 5.2需求分析4

5.2.1实施4 5.2.2要求5 5.2.3交付文档5 5.2.4审批5 5.3概要设计5 5.3.1实施5 5.3.2要求6 5.3.3交付文档6 5.3.4补充说明6 5.3.5审批6 5.4详细设计7 5.4.1实施7 5.4.2要求7 5.4.3文档7 5.4.4审批7 5.5实现7 5.5.1实施与要求7

5.5.2交付文档8 5.5.3审批8 5.6组装测试8 5. 6.1实施8 5.6.2要求8 5.6.3交付文档8 5.6.4审批8 5.7确认测试9 5.7.1实施9 5.7.2要求9 5.7.3交付文档9 5.7.4 补充说明9 5.7.5 审批9 5.8发布10 5.8.1过程10 5.8.2 文档10 5.8.3 审核10

5.9 交接10 6. 附录1:项目文档清单11 1.目的和作用 本流程详细规定软件开发程的各个阶段及每一阶段的任务、要求、交付文件,使整个软件开发过程阶段清晰、要求明确、任务具体,实现软件开发过程的标准化。 2.适用范围: 公司的软件开发产品均适用。 3. 参考文件 各种文档模板 文档命名规则 交接流程 4.适用对象 软件管理人员,软件开发人员,软件维护人员 5.软件开发流程 5.1可行性研究与计划 5.1.1实施 5.1.1.1 软件开发部分析人员进行市场调查与分析,确认软

软件开发公司

广州优伴软件科技有限公司发展历程 广州优伴软件科技有限公司是一家专业从事软件开发高科技技术型公司,公司座落于风景秀丽的天河软件园内,公司拥有三十几名从事软件开发的专家,其中有些获得了国际软件厂商的专业认证(如:Oracle 技术专家认证,微软专家认证等)。 二十年来,优伴软件公司凭借在软件开发行业的实际经验和精湛的软件开发技术,在制造业、零售业、连锁分销等行业传播先进的信息化管理理念。 优伴软件科技有其自有的研发团队、测试团队,可以快速响应用户的需求,优伴软件科技可根据客户的需求进行个性化定制开发。优伴软件科技公司是侧重于技术研发的软件服务提供商,不断创新,积极进取是优伴科技永恒的动力,优伴软件科技之所以能有今天的成就,完全依赖众多优秀的专项人才的鼎力支持,饮水不忘思源,优伴软件科技会继续在技术和服务方面保持高投入,不断充实优伴软件科技的技术队伍,为客户提供更优质的软件产品和技术支持服务。 产品质量保证 优伴软件科技与微软公司是长期合作伙伴关系,优伴软件公司用来开发客户产品的软件开发工具全部是微软正版软件,这从项目开始就保证了开发出来客户产品的稳定性和优质性,“原材料的品质直接影响到成品的品质”这一规则同样适用于软件行业。 一流的技术创造一流的产品 正因优伴用来开发客户产品的软件开发工具全部是最新微软正版

软件,可以在第一时间把最新的技术带给客户使用,让客户享受新技术带来的便捷、愉悦的应用感觉,良好的售后服务保证了一流产品效能的充分发挥。对于客户来讲,优质产品+ 优质售后服务= 物有所值。优伴是一家以技术为载体,沿品牌营销之道持续发展的品牌软件公司,优伴软件科技在为客户提供优质产品的同时也提供后续五星级技术支持服务以解客户后顾之忧,让客户买的放心,用的放心。

几大原型软件开发对比

1、Axure RP(Rapid Prototyping) Axure(读音为Ack-Sure)无疑是目前最受关注的原型开发工具,其能通过组件的方式帮助网站或软件设计师快速建立带有注释的原型(流程图、线框图),并凭借自定义可重用的元件、动态面板以及丰富的script能够建立基本功能或页面逻辑的动态演示文件。 Axure借鉴了office的界面,能够让用户快速上手,并且提供了丰富的组件样式修改,使得通过其能够创建低保真、高保真甚至接近于实际效果的界面。然而最让人称道的是,Axure 的丰富的脚本模式,可以通过点击和选择能够快速完成界面元素的交互,如链接、state切换、动态变化等效果,使得Axure能够生成十分接近于真实产品的原型。另一方面,Axure 能够导入其他人创建的元件库,使得Axure能够满足绝大多数类型产品的设计。 但Axure仍然有一个让人头痛的问题:对于中文的支持不太友好。在小部分元件上输入中午的时候,经常需要像碰运气似的反复切换输入法,破坏了咱们设计师的用户体验。 瑕不掩瑜,Axure仍然是交互设计师的首选原型工具。 2、Microsoft Office Visio Visio在2000年被微软收购,并在2002年成为office2003套件中的一个组件,最新版本是2007。Visio能够获得推荐的原因是因为Visio的适用性非常之广,从网站界面、数据库模型,到平面布置图到工艺流程图,Visio都提供了相应的元件库和模板来进行快速创建。 相较Axure而言,Visio更适合于传统行业的生产或流程设计,或者软件及互联网行业中的信息、数据和流程的说明,而不太适用于web界面。因为其的基于web的元件库还是比较少,并且形式和结构也更类似于word中的图形工具,因此在原型开发效率上都有所不足。 3、Balsamiq Mockups 这个基于Adobe AIR Runtime的工具实在是有让人眼前一亮的感觉,手绘风格的元件样式粗犷淋漓,能创建接近于纸上手绘的原型文件。其提供了丰富的手绘风格的web常用元件,包括常用的html控件、以及一些组合控件,如多媒体控制器、标签页、列表、Iphone界面元件等。 Mockups最值得赞赏之处在于其提供的多数组件都可定制外观,对于中文的支持也不错(选择View > Use System Fonts)。 4、Mockflow Mockflow和以上工具最大的不同在于Mockflow是一项基于Adobe Flex技术开发在线服务,提供了与Balsamiq Mockups基本相似的功能,甚至更丰富的组件,虽然其元件定制化不够强大,但其提供的元件库默认样式却非常适合用来做商业产品原型的搭建。有一个让我爱不释手的功能是模板,可以设置基于任何页面的模板来进行新的页面设计。 与其他模板工具相比,mockflow有一个非常特色的功能,基于web的存储可以在任意电脑上联机打开,同时可以其他人进行快速的分享,并收集在线反馈意见,非常适合虚拟团队的原型设计交流。 虽然在线服务的基本帐号只能创建一个文件,但单个文件却没有限制页数,因此也基本上足够使用。 5、Pencil sketch Pencil 是一款基于Firefox的扩展组件,安装之后即可在Firefox的工具菜单中打开Pencil的绘图面板。功能比较简单,仅能用以日常简单工作的辅助说明。提供的默认元件都是基于软件工程,因此更适合用于windows桌面程序的简易界面搭建,或者是基本的页面功能说明,

相关文档
相关文档 最新文档