caridle caridle
关注数: 18 粉丝数: 285 发帖数: 1,425 关注贴吧数: 7
用Delphi编写一个Svchost.exe调用的DLL模块 这个模块的代码在网上流传的是用C写的,这里我花了一个早上用Delphi写了一个DLL,可以自己扩充各种功能.{ 文件名: ServiceDll.dpr 概述: 替换由svchost.exe启动的某个系统服务,具体服务由全局变量 ServiceName 决定. 经测试,生成的DLL文件运行完全正常. 测试环境: Windows 2003 Server + Delphi 7.0 代码只实现了一个框架,没有任何实际动作,仅作为学习用.如果你使用本代码 进行了任何扩充和修改,希望您能将代码寄一份给我. 日期: 2005-04-01 作者: yanxizhen yanxizhen#163.com}library ServiceDll;uses SysUtils, Classes, winsvc, System, Windows;{ 定义全局变量 }var // 服务控制信息句柄 SvcStatsHandle : SERVICE_STATUS_HANDLE; // 存储服务状态 dwCurrState : DWORD; // 服务名称 ServiceName : PChar = 'BITS';{ 调试函数,用于输出调试文本 }procedure OutPutText(CH:PChar);var FileHandle: TextFile; F : Integer;Begin try if not FileExists('zztestdll.txt') then F := FileCreate('zztestdll.txt'); finally if F > 0 Then FileClose(F); end; AssignFile(FileHandle,'zztestdll.txt'); Append(FileHandle); Writeln(FileHandle,CH); Flush(FileHandle); CloseFile(FileHandle);END;{ dll入口和出口处理函数 }procedure DLLEntryPoint(dwReason : DWord);begin case dwReason of DLL_PROCESS_ATTACH: ; DLL_PROCESS_DETACH: ; DLL_THREAD_ATTACH: ; DLL_THREAD_DETACH: ; end;end;{ 与SCM管理器通话 }function TellSCM(dwState : DWORD ; dwExitCode : DWORD; dwProgress : DWORD ): LongBool;var srvStatus : service_status;BEGIN srvStatus.dwServiceType := SERVICE_WIN32_SHARE_PROCESS; dwCurrState := dwState; srvStatus.dwCurrentState := dwState; srvStatus.dwControlsAccepted := SERVICE_ACCEPT_STOP or SERVICE_ACCEPT_PAUSE_CONTINUE or SERVICE_ACCEPT_SHUTDOWN; srvStatus.dwWin32ExitCode := dwExitCode; srvStatus.dwServiceSpecificExitCode := 0; srvStatus.dwCheckPoint := dwProgress; srvStatus.dwWaitHint := 3000; Result := SetServiceStatus( SvcStatsHandle, srvStatus );END;{ Service 控制函数 }PROCEDURE servicehandler(fdwcontrol:integer); STDCALL;BEGIN CASE fdwcontrol OF SERVICE_CONTROL_STOP: BEGIN TellSCM( SERVICE_STOP_PENDING, 0, 1 ); Sleep(10); TellSCM( SERVICE_STOPPED, 0, 0 ); END; SERVICE_CONTROL_PAUSE: BEGIN TellSCM( SERVICE_PAUSE_PENDING, 0, 1 ); TellSCM( SERVICE_PAUSED, 0, 0 ); END; SERVICE_CONTROL_CONTINUE: BEGIN TellSCM( SERVICE_CONTINUE_PENDING, 0, 1 ); TellSCM( SERVICE_RUNNING, 0, 0 ); END; SERVICE_CONTROL_INTERROGATE: TellSCM( dwCurrState, 0, 0 ); SERVICE_CONTROL_SHUTDOWN: TellSCM( SERVICE_STOPPED, 0, 0 ); END;END;{ service main }procedure ServiceMain(argc : Integer; VAR argv : pchar ); StdCall;begin{ try begin if ParamStr(1) <> '' then svcname := strNew(PChar(ParamStr(1))) else begin svcname := strAlloc(10 * Sizeof(Char)); svcname := 'none'; end; OutPutText(svcname); end finally strdispose(svcname); end; } // 注册控制函数 SvcStatsHandle := RegisterServiceCtrlHandler(ServiceName, @servicehandler); IF (SvcStatsHandle = 0) THEN BEGIN OutPutText('Error in RegisterServiceCtrlHandler'); exit; END else begin FreeConsole(); end; // 启动服务 TellSCM( SERVICE_START_PENDING, 0, 1 ); TellSCM( SERVICE_RUNNING, 0, 0 ); OutPutText('Service is Running'); // 这里可以执行我们真正要作的代码 while ((dwCurrState <> SERVICE_STOP_PENDING) and (dwCurrState <> SERVICE_STOPPED)) do begin sleep(1000); end; OutPutText('Service Exit');end;// 导出函数列表exports ServiceMain;{ dll入口点 }begin DllProc := @DLLEntryPoint;end.http://www.92mg.com/post/174/
APIHOOK实例剖析 APIHOOK实例剖析 2004-2-18加入 来自csdn 作者rivershan 0条评论 点击224次 关于APIHOOK的基础知识有很多,如dll的相关知识、Hook的相关知识、系统进程与线程之间的联系等。具体可以看我的另两篇文章:"我的Dll(动态链接库)学习笔记" 和 "我的Hook学习笔记"。:)下面进入这篇文章的重点,根据APIHook源码进行APIHook的剖析。 一、APIHOOK之dll部分 //////////////////////////////// APIHook_Dll.cpp ////////////////////////////////////////// rivershan写于2002.9.23 ///////////////////////////////////////////////////////////////////////////////////////////#include "stdafx.h"#include "APIHook_Dll.h"#include #include #pragma comment(lib,"ImageHlp") //定义全局共享数据段#pragma data_seg("Shared")HMODULE hmodDll=NULL;HHOOK hHook=NULL;#pragma data_seg()#pragma comment(linker,"/Section:Shared,rws") //设置全局共享数据段的属性///////////////////////////////////// DllMain 函数 ///////////////////////////////////////////dll的入口点BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){ switch(ul_reason_for_call) { case DLL_PROCESS_ATTACH: //if(sHook) case DLL_PROCESS_DETACH: UnInstallHook(); break; } hmodDll=hModule; return TRUE;}///////////////////////////////////// HookOneAPI 函数 ///////////////////////////////////////////进行IAT转换的关键函数,其参数含义://pszCalleeModuleName:需要hook的模块名//pfnOriginApiAddress:要替换的自己API函数的地址//pfnDummyFuncAddress:需要hook的模块名的地址//hModCallerModule:我们要查找的模块名称,如果没有被赋值,// 将会被赋值为枚举的程序所有调用的模块void WINAPI HookOneAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress, PROC pfnDummyFuncAddress,HMODULE hModCallerModule){ ULONG size; //获取指向PE文件中的Import中IMAGE_DIRECTORY_DESCRIPTOR数组的指针 PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData(hModCallerModule,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&size); if (pImportDesc == NULL) return; //查找记录,看看有没有我们想要的DLL for (;pImportDesc->Name;pImportDesc++) { LPSTR pszDllName = (LPSTR)((PBYTE)hModCallerModule+pImportDesc->Name); if (lstrcmpiA(pszDllName,pszCalleeModuleName) == 0) break; } if (pImportDesc->Name == NULL) { return; } //寻找我们想要的函数 PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)((PBYTE)hModCallerModule+pImportDesc->FirstThunk);//IAT for (;pThunk->u1.Function;pThunk++) { //ppfn记录了与IAT表项相应的函数的地址 PROC * ppfn= (PROC *)&pThunk->u1.Function; if (*ppfn == pfnOriginApiAddress) { //如果地址相同,也就是找到了我们想要的函数,进行改写,将其指向我们所定义的函数 WriteProcessMemory(GetCurrentProcess(),ppfn,&(pfnDummyFuncAddress), sizeof(pfnDummyFuncAddress),NULL); return; } }}//查找所挂钩的进程所应用的dll模块的BOOL WINAPI HookAllAPI(LPCTSTR pszCalleeModuleName,PROC pfnOriginApiAddress,
Rootkit For Windows[1] Rootkit For Windows *************************一.先说几句与技术无关的话。现在很多人对rootkit认识不够,可以说空白。而此愚文的目的就是让菜鸟认识rootkit→了解rootkit。也让一些想研究它的人把这篇文章当作一个参考或是入门级的指导。文章中介绍的rootkit的隐藏方法只是一部分。还有很多技术没有提到,另外还有一些未公开的技术。有些地方我未引用代码,因为不想占用过多的篇幅。以免有玩弄代码的嫌疑,不过写完以后还是觉得代码太多,请个位见谅。一-三的内容适合菜鸟看,也许第四部分之后对很多人来说都有些意义吧。如果高手不幸看到了,请准备好,不要吐到屏幕上或身上。以往的文章写的比较乱,而且格式不公正,这样的形式写文章也是第一次。以前文章中引用代码和文字也没有详细说明,再此也对作者表示谦意。感谢XX提的这个建议。今天是9月11号,庆祝一下童童的生日。顺便为911事件中的遇难者祈祷。同时也感谢MGF病毒的作者指点。*************************二.简单的说说rootkit.Rootkit的历史已经很悠久了。存在于windows,unix,linux等操作系统中,不只局限在windows,此文我只以windows平台为例来说rootkit。Root在英语中是根,扎根的意思,kit是包的意思。rootkit我们可以把它理解成一个利用很多技术来潜伏在你系统中的一个后门,并且包含了一个功能比较多的程序包,例如有、清除日志,添加用户,b7cmdshell,添加删除启动服务等功能。当然它的设计者也要用一些技术来隐藏自己,确保不被发现。隐藏包括隐藏进程,隐藏文件,端口,或句柄,注册表的项,键值等等。总之,写rootkit的人是狡尽乳汁利用很多办法不被发现。现在人们最熟悉的windows rootkit 就是hacker defender和ntrootkit了,还有使用了baiyuanfan在XCON提出的ring3 rootkit新思路的byshell,呵呵。而linux下就是knark了。*************************三.rootkit的一些以公开的隐藏技术以及检测技术。1. 删除进程双项链上的进程对象。ps:用的似乎很多,连现在的一些盗号的程序也利用上了现在所有人查看进程一般都是通过任务管理器(taskmgr.exe)来查看。了解一些编程知识的人都知道,任务管理器枚举进程信息是靠的NtQuerySystemInformation 也就是ZwQuerySystemInformation 函数。众所周知,这个Native Api (本机API)枚举进程是要通过进程活动链表的。我们就来看看这个结构。typedef struct _OBJECT_ATTRIBUTES{ULONG Length;HANDLE RootDirectory;PUNICODE_STRING ObjectName;ULONG Attributes;PVOID SecurityDescrīptor;PVOID SecurityQualityOfService;} OBJECT_ATTRIBDTES, *POBJECT_ ATTRIBUTES;typedef struct _IO_STATUS_BLOCK{NTSTATDS Status;ULONG Information;}IO_STATUS_BLOCK , * PIO_STATUS_BLOCK ;typedef struct _LIST_ENTRY{Struct _LIST_ENTRY *Flink;Struct _LIST_ENTRY *Blink;}LIST_ENTRY, *PLIST_ENTRY;双向链表的典型例子就是进程和线程链。内部变量PsActiveProcessHead是一个LIST_ENTRY结构,在ntoskrnl.exe的数据段中,指定了系统进程列表的第一个成员。仔细想想,如果我们将进程对象从进程双向链表中移除,那么调用NtQuerySystemInformation来枚举进程的任务管理器taskmgr.exe中就不会看到我们的进程了。那么就有人会担心了。如果进程从链表中删除,那还会被运行么?答案是,会。因为windows的ds,也就是线程分派器,也叫任务调度分配器(dispatcher scheduler)使用的是另一个数据结构,也就是说,进线程是否被调度处理与进程双向活动链表无关,不会被CPU忽略,不必担心。2003年pjf在安全焦点上提出的就是这个方法且给出了这个方法的实现代码。文章结尾处的参考资料中我会给出这个文章的URL。2.修改系统调用表(sst)rootkit可以通过在系统调用表中添加添加自己的服务然后运行想要执行的任务。He4HookInv就是这样。He4HookInv也是一个比较有名的windows rootkit。下面我们来看看He4HookInv具体的实现过程。在以前人们不知道它是如何实现的这些,一些介绍rootkit的文章也是提到一点,不过只知道是修改的SST,细节也没有过多描述。直到phrack杂志公布了He4HookInv的一些细节。
SSDT Hook的妙用-对抗ring0 inline hook SSDT Hook的妙用-对抗ring0 inline hook2007-03-13 13:16//好样的技术!!标 题: 【转载】SSDT Hook的妙用-对抗ring0 inline hook作 者: 堕落天才时 间: 2007-03-10,15:18链 接: http://bbs.pediy.com/showthread.php?threadid=40832********************************************************标题:【转载】SSDT Hook的妙用-对抗ring0 inline hook **作者:堕落天才 **日期:2007年3月10号 **声明:本文章的目的仅为技术交流讨论 ********************************************************1,SSDT SSDT即系统服务描述符表,它的结构如下(参考《Undocument Windows 2000 Secretes》第二章): typedef struct _SYSTEM_SERVICE_TABLE { PVOID ServiceTableBase; //这个指向系统服务函数地址表 PULONG ServiceCounterTableBase; ULONG NumberOfService; //服务函数的个数,NumberOfService*4 就是整个地址表的大小 ULONG ParamTableBase; }SYSTEM_SERVICE_TABLE,*PSYSTEM_SERVICE_TABLE; typedef struct _SERVICE_DEscrīptOR_TABLE { SYSTEM_SERVICE_TABLE ntoskrnel; //ntoskrnl.exe的服务函数 SYSTEM_SERVICE_TABLE win32k; //win32k.sys的服务函数,(gdi.dll/user.dll的内核支持) SYSTEM_SERVICE_TABLE NotUsed1; SYSTEM_SERVICE_TABLE NotUsed2; }SYSTEM_DEscrīptOR_TABLE,*PSYSTEM_DEscrīptOR_TABLE; 内核中有两个系统服务描述符表,一个是KeServiceDescrīptorTable(由ntoskrnl.exe导出),一个是KeServieDescrīptorTableShadow(没有导出)。两者的区别是,KeServiceDescrīptorTable仅有ntoskrnel一项,KeServieDescrīptorTableShadow包含了ntoskrnel以及win32k。一般的Native API的服务地址由KeServiceDescrīptorTable分派,gdi.dll/user.dll的内核API调用服务地址由KeServieDescrīptorTableShadow分派。还有要清楚一点的是win32k.sys只有在GUI线程中才加载,一般情况下是不加载的,所以要Hook KeServieDescrīptorTableShadow的话,一般是用一个GUI程序通过IoControlCode来触发(想当初不明白这点,蓝屏死机了N次都想不明白是怎么回事)。2,SSDT HOOK SSDT HOOK 的原理其实非常简单,我们先实际看看KeServiceDescrīptorTable是什么样的。 lkd> dd KeServiceDescrīptorTable 8055ab80 804e3d20 00000000 0000011c 804d9f48 8055ab90 00000000 00000000 00000000 00000000 8055aba0 00000000 00000000 00000000 00000000 8055abb0 00000000 00000000 00000000 00000000 在windbg.exe中我们就看得比较清楚,KeServiceDescrīptorTable中就只有第一项有数据,其他都是0。其中804e3d20就是KeServiceDescrīptorTable.ntoskrnel.ServiceTableBase,服务函数个数为0x11c个。我们再看看804e3d20地址里是什么东西: lkd> dd 804e3d20 804e3d20 80587691 805716ef 8057ab71 80581b5c 804e3d30 80599ff7 80637b80 80639d05 80639d4e 804e3d40 8057741c 8064855b 80637347 80599539 804e3d50 8062f4ec 8057a98c 8059155e 8062661f 如上,80587691 805716ef 8057ab71 80581b5c 这些就是系统服务函数的地址了。比如当我们在ring3调用OpenProcess时,进入sysenter的ID是0x7A(XP SP2),然后系统查KeServiceDescrīptorTable,大概是这样KeServiceDescrīptorTable.ntoskrnel.ServiceTableBase(804e3d20) + 0x7A * 4 = 804E3F08,然后804E3F08 ->8057559e 这个就是OpenProcess系统服务函数所在,我们再跟踪看看:
VB KeyCode 常数表 常数 值 描述 vbKeyLButton 0x1 鼠标左键 vbKeyRButton 0x2 鼠标右键 vbKeyCancel 0x3 CANCEL 键 vbKeyMButton 0x4 鼠标中键 vbKeyBack 0x8 BACKSPACE 键 vbKeyTab 0x9 TAB 键 vbKeyClear 0xC CLEAR 键 vbKeyReturn 0xD ENTER 键 vbKeyShift 0x10 SHIFT 键 vbKeyControl 0x11 CTRL 键 vbKeyMenu 0x12 MENU 键 vbKeyPause 0x13 PAUSE 键 vbKeyCapital 0x14 CAPS LOCK 键 vbKeyEscape 0x1B ESC 键 vbKeySpace 0x20 SPACEBAR 键 vbKeyPageUp 0x21 PAGE UP 键 vbKeyEnd 0x23 END 键 vbKeyHome 0x24 HOME 键 vbKeyLeft 0x25 LEFT ARROW 键 vbKeyUp 0x26 UP ARROW 键 vbKeyRight 0x27 RIGHT ARROW 键 vbKeyDown 0x28 DOWN ARROW 键 vbKeySelect 0x29 SELECT 键 vbKeyPrint 0x2A PRINT SCREEN 键 vbKeyExecute 0x2B EXECUTE 键 vbKeySnapshot 0x2C SNAPSHOT 键 vbKeyDelete 0x2E DELETE 键 vbKeyHelp 0x2F HELP 键 vbKeyNumlock 0x90 NUM LOCK 键 vbKeyA 65 A 键 vbKeyB 66 B 键 vbKeyC 67 C 键 vbKeyD 68 D 键 vbKeyE 69 E 键 vbKeyF 70 F 键 vbKeyG 71 G 键 vbKeyH 72 H 键 vbKeyI 73 I 键 vbKeyJ 74 J 键 vbKeyK 75 K 键 vbKeyL 76 L 键 vbKeyM 77 M 键 vbKeyN 78 N 键 vbKeyO 79 O 键 vbKeyP 80 P 键 vbKeyQ 81 Q 键 vbKeyR 82 R 键 vbKeyS 83 S 键 vbKeyT 84 T 键 vbKeyU 85 U 键 vbKeyV 86 V 键 vbKeyW 87 W 键 vbKeyX 88 X 键 vbKeyY 89 Y 键 vbKeyZ 90 Z 键 vbKey0 48 0 键 vbKey1 49 1 键 vbKey2 50 2 键 vbKey3 51 3 键 vbKey4 52 4 键 vbKey5 53 5 键 vbKey6 54 6 键 vbKey7 55 7 键 vbKey8 56 8 键 vbKey9 57 9 键 vbKeyNumpad0 0x60 0 键 vbKeyNumpad1 0x61 1 键 vbKeyNumpad2 0x62 2 键 vbKeyNumpad3 0x63 3 键 vbKeyNumpad4 0x64 4 键 vbKeyNumpad5 0x65 5 键 vbKeyNumpad6 0x66 6 键 vbKeyNumpad7 0x67 7 键 vbKeyNumpad8 0x68 8 键 vbKeyNumpad9 0x69 9 键 vbKeyMultiply 0x6A MULTIPLICATIONSIGN(*)键 vbKeyAdd 0x6B PLUS SIGN (+) 键 vbKeySeparator 0x6C ENTER 键 vbKeySubtract 0x6D MINUS SIGN (-) 键 vbKeyDecimal 0x6E DECIMAL POINT (.) 键 vbKeyDivide 0x6F DIVISION SIGN (/) 键 vbKeyF1 0x70 F1 键 vbKeyF2 0x71 F2 键 vbKeyF3 0x72 F3 键 vbKeyF4 0x73 F4 键 vbKeyF5 0x74 F5 键 vbKeyF6 0x75 F6 键 vbKeyF7 0x76 F7 键 vbKeyF8 0x77 F8 键 vbKeyF9 0x78 F9 键 vbKeyF10 0x79 F10 键 vbKeyF11 0x7A F11 键 vbKeyF12 0x7B F12 键
c#安装和卸载驱动程序 using System; using System.Runtime.InteropServices; namespace EAE.MyServiceInstaller { class ServiceInstaller { #region Private Variables private string _servicePath; private string _serviceName; private string _serviceDisplayName; #endregion Private Variables #region DLLImport [DllImport("advapi32.dll")] public static extern IntPtr OpenSCManager(string lpMachineName,string lpSCDB, int scParameter); [DllImport("Advapi32.dll")] public static extern IntPtr CreateService(IntPtr SC_HANDLE,string lpSvcName,string lpDisplayName, int dwDesiredAccess,int dwServiceType,int dwStartType,int dwErrorControl,string lpPathName, string lpLoadOrderGroup,int lpdwTagId,string lpDependencies,string lpServiceStartName,string lpPassword); [DllImport("advapi32.dll")] public static extern void CloseServiceHandle(IntPtr SCHANDLE); [DllImport("advapi32.dll")] public static extern int StartService(IntPtr SVHANDLE,int dwNumServiceArgs,string lpServiceArgVectors); [DllImport("advapi32.dll",SetLastError=true)] public static extern IntPtr OpenService(IntPtr SCHANDLE,string lpSvcName,int dwNumServiceArgs); [DllImport("advapi32.dll")] public static extern int DeleteService(IntPtr SVHANDLE); [DllImport("kernel32.dll")] public static extern int GetLastError(); #endregion DLLImport // /// // /// 应用程序入口. // /// // // [STAThread] // static void Main(string[] args) // { // // string svcPath; // string svcName; // string svcDispName; // //服务程序的路径 // svcPath = @"d:\service\EAEWS.exe"; // svcDispName="myEAEWS"; // svcName= "myEAEWS"; // ServiceInstaller c = new ServiceInstaller(); // c.InstallService(svcPath, svcName, svcDispName); // Console.Read(); // // } /// /// 安装和运行 /// /// 程序路径. /// 服务名 /// 服务显示名称. /// 服务安装是否成功. public bool InstallService(string svcPath, string svcName, string svcDispName) { #region Constants declaration. int SC_MANAGER_CREATE_SERVICE = 0x0002; int SERVICE_WIN32_OWN_PROCESS = 0x00000010; //int SERVICE_DEMAND_START = 0x00000003; int SERVICE_ERROR_NORMAL = 0x00000001; int STANDARD_RIGHTS_REQUIRED = 0xF0000; int SERVICE_QUERY_CONFIG = 0x0001; int SERVICE_CHANGE_CONFIG = 0x0002; int SERVICE_QUERY_STATUS = 0x0004; int SERVICE_ENUMERATE_DEPENDENTS = 0x0008; int SERVICE_START =0x0010; int SERVICE_STOP =0x0020; int SERVICE_PAUSE_CONTINUE =0x0040; int SERVICE_INTERROGATE =0x0080; int SERVICE_USER_DEFINED_CONTROL =0x0100; int SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL); int SERVICE_AUTO_START = 0x00000002; #endregion Constants declaration. try { IntPtr sc_handle = OpenSCManager(null,null,SC_MANAGER_CREATE_SERVICE); if (sc_handle.ToInt32() != 0) { IntPtr sv_handle = CreateService(sc_handle,svcName,svcDispName,SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START,SERVICE_ERROR_NORMAL,svcPath,null,0,null,null,null); if(sv_handle.ToInt32() ==0) { CloseServiceHandle(sc_handle); return false; } else { //试尝启动服务 int i = StartService(sv_handle,0,null); if(i==0) { return false; } CloseServiceHandle(sc_handle); return true; } } else return false; } catch(Exception e) { throw e; } } /// /// 反安装服务. /// /// 服务名. public bool UnInstallService(string svcName) { int GENERIC_WRITE = 0x40000000; IntPtr sc_hndl = OpenSCManager(null,null,GENERIC_WRITE); if(sc_hndl.ToInt32() !=0) { int DELETE = 0x10000; IntPtr svc_hndl = OpenService(sc_hndl,svcName,DELETE); if(svc_hndl.ToInt32() !=0) { int i = DeleteService(svc_hndl); if (i != 0) { CloseServiceHandle(sc_hndl); return true; } else { CloseServiceHandle(sc_hndl); return false; } } else return false; } else return false; } } }
办公自动化中最有技术含量最难的模块是什么? 办公自动化中最有技术含量最难的模块是什么? 对于普通用户来说一个办公自动化系统来说初看好像都差不多,国内的同行业的OA的模块每个厂家都有,甚至有些OA的模块还特别多,进去一看倒处都是功能,叫人很难理清思路.初始还以为功能很不错,但是仔细一分析每个模块就会发现有很大的区别. 下面以OA办公自动化系统的开发为例对各个比较难的模块进行说明:1) 办公自动化中最核心最难的模块"流程引擎"  可以说OA办公自动化好与不好都集中在流程这一块.光从开发时间上来说,对于一个好的工作流模块一个企业至少要投入2-3个一流的开发人员需要花大至一年左右的时间才能完成一个成熟、功能强大的工作流软件.国内有很多公司专门从事工作流软件的开发,他们在这一个模块上花的时间比有些OA开发商整个OA产品的开发时间还要长几倍。一个强大的工作流引擎光是从代码量上来说至少都能达到1万行以上的代码量建模模块的代码量也非常大,一个好的流程建模模块代码量也有几万行以上。还要配备专门测试人员来测试流程中的各种功能和异常情况。就目前来说国内的流程引擎都不可能100%的满足所有企业和政府中的所有特殊性的流程要求.以Linkey Workflow3.1为例,Linkey Workflow的建模模块的代码量在1.8万行左右其工作流引擎完全用Lotus Script实现其代码量在1.1万行左右,系统共采用了120多个核心API函数。Linkey Workflow 从1.0到3.0共历时13个月的时间,也就是说对于Linkey OA来说,光流程一个模板就花了13个月的时间。Linkey Workflow工作流模块包括下面的这些功能1) 流程建模2) 流程引擎3) 流程监控4) 流程实例库5) 流程权限角色控制库一个好的工作流引擎应该最少具有以下功能1)稳定的信息传递架构,支持大流量文档传递2)图形化流程定制3)图形化流程动态跟踪4)支持混合流,并行流5)支持任意流程之间的嵌套,支持子流程6)支持远程分发(省与地市之间的公文分发)7)基于关系的路由8)基于角色的路由更多工作流信息可以参见WMFC国际工作流联盟标准文档在很多大型的OA项目中基本上项目开发人员的时间都集中在流程开发这一块,完成了流程这一块则基本完成了整个项目的2/3工作量,这也是很多OA项目成败的关键,特别是对于政府单位的OA来说,OA是否能实施成功就在于流程这一块是否能满足用户的需求,如果一个OA系统连流程都无法流转的情况下,那么OA变成了一个邮件服务器和文档存储的服务器了.2)表单自定义模块 表单自定义模块目前来说是办公自动化中的技术难题,不管是基于关系型数据库还是Lotus Domino的OA系统都是一个难题.现有的表单自定义功能中要不就不能灵活定制要不就不能与流程进行很好的整合,要不就不能对自定义的表单进行权限控制. 总之表单自定义模块不只是时间上的问题,更大的是技术上的难题,能在表单自定义上突破技术难点的话,那么离完成这个模块的时间就就不长了. 以Linkey OA表单自定义系统来说: 从最初的构思开始不断尝试各种方式来对表单进行自定义,从最初的C++到Java等技术都尝试过,通过不断的试验,试验,失败,失败..最终找到了最完美的解决方案,基本上完全的解决了流程中的表单自定义需求. 从构思到技术突破上花了半年的时间,在技术上突破成功后只花了不到2个月的时间就完成了系统的编写工作.3)Word控件模块 在现行办公自动化中还基本上是以Word作为正文的编辑和排版工具,所以一个强大的Word控件就关系统到用户的工作效率.Word控件是否稳定,启动速度是否快速,都直接影响用户的工作效率. Word控件是否产生临时文件,能否进行手写批注,电子盖章等都是衡量一个Word控件的标准. 在IE启动和控制一个Word并不是难题,在Word控件开发中最难的模块应该是在文档编辑完成后在不产生临时文件的同时模拟HTTP提交给WEB服务器.国内还有很多开发商采用FTP上传的方法来进行,使用FTP方法在安全性方面存在很大的问题,而且服务器还要开启FTP服务.
[VB编程提高]VB编程中的技巧一行可以解决的代码 1、下列代码,则是对逻辑运算不清楚造成。If A=true Then C= Not BElse C= BEnd If可以:C=A XOR B2、如果加上下列代码:If C=true then D=28Else D=29 End IFD=Iif((A XOR B),28,29)3、布尔赋值,常被人忽略:如:If A= 13 then B=True Else B=False End If可以:B = A = 13或者:B = (A = 13)我更喜欢用后者,这样代码易于看懂。4、字串有效性检测:If IsNull(StrOrg) Or StrOrg="" then可以:If Len(StrOrg & "")<>0 then5、字串重复次数RepeatCount=Ubound(Split(StrOrg,StrFind))同样,如果要对字串有效性判断:RepeatCount=Iif((Len(StrOrg & "")=0), 0, Ubound(Split(StrOrg,StrFind))6、有时需要判断字串数组中是否有这一元素,这时最好不用数组,而用分隔符字串于是: If Len(OrgStr)= Len(Replace(OrgStr,FindStr)) then则表明,此元素不存在。 7、对数组初始化:最好用变体,这样,也是一行语句:如:IntArr=Array(12,28,29,30,31,52,24,60)注意,此时需要用变量后缀。上面代码,如要定义为长整型,则IntArr=Array(12&,28&,29&,30&,31&,52&,24&,60&)要将IntArr 定义为变体8、判断大小:IntMax = Iif((IntA > IntB), IntA, IntB) IntMin = Iif((IntA < IntB), IntA, IntB)9、按索引的Select CaseFunction GetChoice(Ind As Integer) GetChoice = Choose(Ind, "Speedy", "United", "Federal")End Function10、按表达式的Select Case(这种转换要求不能有Case Else的才可以这样,否则会出错)Function MatchUp (CityName As String) Matchup = Switch(CityName = "London", "English", CityName _ = "Rome", "Italian", CityName = "Paris", "French")End Function11、使用Iif,前面已有。 Function CheckIt (TestMe As Integer) CheckIt = IIf(TestMe > 1000, "Large", "Small")End Function12、字串动态数组是否已初始化 If Len(Join(StrArr))=0 then字串动态数组未初始化13、指定只读CombBox的当前值,如果能确认这个值就在其中,一定不会错,则: Combbox=CurValue 注意,不可以写成:Combbox.text=CurValue 前者实际是写 _default 这个属性,而后者则是写Text 因为只读,则会导致错误 14、如果有下列代码:Select Case CombBox.textCase "London" Call FuncStrLang(3)Case "Rome" Call FuncStrLang(5)......End Select 则可以用ItemData属性 即:"London" 的 Itemdata=3 "Rome" 的 Itemdata=5 于是: Call FuncStrLang(CombBox.ItenData)15、如果有下列代码: Select Case CombBox.textCase "London" Call ClsCity.CityIntr_LondonCase "Rome" Call ClsCity.CityIntr_Rome......End Select 只要:CallByName ClsCity, "CityIntr_" & CombBox.text, vbMethod16、复制数组到另一变量中: Dim iOrgArr(30) as Integer Dim iDesArr as Variant ...... iDesArr = iOrgArr 即主变体直接取数组指针,则所有元素都复制了过去17、如果有下列代码: Do While Not RsAdo.Eof If len(DesStr)<>0 then DesStr=DesStr & VbTab End if DesStr=RsAdo!Rec_id RsAdo.MoveNext loop 则只要: DesStr=RsAdo.GetString()
C# 参考之方法参数关键字:params、ref及out C# 参考之方法参数关键字:params、ref及out 如果在为方法声明参数时未使用 ref 或 out,则该参数可以具有关联的值。可以在方法中更改该值,但当控制传递回调用过程时,不会保留更改的值。通过使用方法参数关键字,可以更改这种行为。paramsparams 关键字可以指定在参数数目可变处采用参数的方法参数。在方法声明中的 params 关键字之后不允许任何其他参数,并且在方法声明中只允许一个 params 关键字。 示例:字面意思比较难懂,所以看示例很有用。// keywords_params.csusing System;class App{ public static void UseParams(params object[] list) { for (int i = 0; i < list.Length; i++) { Console.WriteLine(list[i]); } } static void Main() { // 一般做法是先构造一个对象数组,然后将此数组作为方法的参数 object[] arr = new object[3] { 100, 'a', "keywords" }; UseParams(arr); // 而使用了params修饰方法参数后,我们可以直接使用一组对象作为参数 // 当然这组参数需要符合调用的方法对参数的要求 UseParams(100, 'a', "keywords"); Console.Read(); }}refref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。 传递到 ref 参数的参数必须最先初始化。这与 out 不同,out 的参数在传递之前不需要显式初始化。 属性不是变量,因此不能作为 ref 参数传递。 尽管 ref 和 out 在运行时的处理方式不同,但它们在编译时的处理方式是相同的。因此,如果一个方法采用 ref 参数,而另一个方法采用 out 参数,则无法重载这两个方法。例如,从编译的角度来看,以下代码中的两个方法是完全相同的。如果尝试这么做,将导致不能编译该代码。 如果一个方法采用 ref 或 out 参数,而另一个方法不采用这两类参数,则可以进行重载。 示例:按引用传递值类型是有用的,但是 ref 对于传递引用类型也是很有用的。这允许被调用的方法修改该引用所引用的对象,因为引用本身是按引用来传递的。// keywords_ref.csusing System;class App{ public static void UseRef(ref int i) { i += 100; Console.WriteLine("i = {0}", i); } static void Main() { int i = 10; // 查看调用方法之前的值 Console.WriteLine("Before the method calling: i = {0}", i); UseRef(ref i); // 查看调用方法之后的值 Console.WriteLine("After the method calling: i = {0}", i); Console.Read(); }}/**//*控制台输出:Before the method calling : i = 10i = 110After the method calling: i = 110*/outout 关键字会导致参数通过引用来传递。这与 ref 关键字类似。与 ref 的不同之处:ref 要求变量必须在传递之前进行初始化。 尽管作为 out 参数传递的变量不需要在传递之前进行初始化,但需要调用方法以便在方法返回之前赋值。 示例:与 ref 示例不同的地方只要将 ref 改为 out,然后变量 i 仅需要声明即可。static void Main(){ //int i = 10; 改为 int i; //}
首页 1 2 3 下一页