内核对象的内容
内核对象有 存取符号对象,事件对象,文件对象,文件映射对象,I/O完成端口对象,作业对象,信箱对象,互斥对象,管道对象,进程对象,信标对象,线程对象和等待计时器对象等
每个内核对象都有一个安全数据结构
创建映射文件:
HANDLE CreateFileMapping(
HANDLE hFile,
PSECURITY_ATTRIBUTES psa,
DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow,
PCTSTR pszName);
创建进程:
BOOL CreateProcess(
PCTSTR pszApplicationName,
PTSTR pszCommandLine,
PSECURITY_ATTRIBUTES psaProcess,
PSECURITY_ATTRIBUTES pszThread,
BOOL bInheritHandles,
DWORD dwCreationFlags,
PVOID pvEnvironment,
PCTSTR pszCurrentDirectory,
LPSTARTUPINFO pStartupInfo,
PPROCESS_INFORMATION pProcessInformation);
创建线程:
HANDLE CreateThread(
PSECURITY_ATTRIBUTES psa,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE pfnStartAddr,
PVOID pvParam,
DWORD dwCreationFlags,
PDWORD pdwThreadId);
创建文件:
HANDLE CreateFile(
PCTSTR pszFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
PSECURITY_ATTRIBUTES psa,
DWORD dwCreationDistribution,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile);
创建信号量:
HANDLE CreateSemaphore(
PSECURITY_ATTRIBUTES psa,
LONG lInitialCount,
LONG lMaximumCount,
PCTSTR pszName);
创建互斥量:
HANDLE CreateMutex(
PSECURITY_ATTRIBUTES psa;
BOOL bInitialOwner;
PCTSTR pszName);
创建事件:
HANDLE CreateEvent(
PSECURITY_ATTRIBUTES psa;
BOOL bManualReset,
BOOL bInitialState,
PCTSTR pszName);
HANDLE CreateJobObject(
PSECURITY_ATTRIBUTES psa,
PCTSTR pszName);
****一般创建失败会返回NULL,不过创建文件打开失败返回INVALID_HANDLE_VALUE值为-1
打开映射文件:
HANDLE OpenFileMapping(...);
关闭内核对象统一使用:
BOOL CloseHandle(HANDLE hobj);
失败使用GetLastError()返回ERROR_INVALID_HANDLE
用于创建用于对象或GDI对象的函数时没有PSECURITY_ATTRIBUTES参数的.
创建图标:
HICON CreateIcon(
HINSTANCE hinst,
int nWidth,
int nHeight,
BYTE cPlanes,
BYTE cBitsPixel,
CONST BYTE *pbANDbits,
CONST BYTE *pbXoRbits);
内核对象需要共享的几个原因:
文件映射对象能够在同一台机器上运行的两个进程间共享数据块
邮箱和指定的管道使用能够在连网的不同机器上运行的进程之间发送数据块
互斥对象,信标和事件能够同步不同进程的线程
改变内核对象句柄的继承标志:
BOOL SetHandleInformation(HANDLE hObject,DWORD dwMask,DWORD dwFlags);
dwMask一般有两个,可以使用OR操作连接起来:
#define HANDLE_FLAG_INHERIT 0x00000001 //继承
#define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002//防止关闭
打开一个内核对象句柄的继承标志:
SetHandleInformation(hobj,HANDLE_FLAG_INHERIT,HANDLE_FLAG_INHERIT);
关闭继承标志:
SetHandleInformation(hobj,HANDLE_FLAG_INHERIT,0);
告诉系统内核句柄不应该被关闭:
SetHandleInformation(hobj,HANDLE_FLAG_PROTECT_FROM_CLOSE,HANDLE_FLAG_PROTECT_FROM_CLOSE);
//如果使用关闭,将会引发一个异常 Exception is raised
CloseHandle(hobj);
获取一个内核对象的标志信息:
BOOL GetHandleInformation(HANDLE hobj, PDWORD pdwFlags);
了解内核句柄是否可继承:
DWORD dwFlags;
GetHandleInformation(hobj,&dwFlags);
BOOL fHandleIsInheritable = (0 !=(dwFlags & HANDLE_FLAG_INHERIT));
内核对象共用的方法:
#继承的方法 适用于父子进程之间
#内核对象命名 用Create*也可以,也可以使用Open*方法,后者在没有时不会创建
**一般在使用这些函数之后调用GetLastError()来判断是否成功
#复制对象句柄
终端服务器的名字空间: 终端服务器拥有内核对象的多个名字空间.
如果存在一个可供内核对象使用的全局名字空间,那么它可供所有的客户程序会话访问.这个适用服务程序.服务程序的名字空间对象总是放在全局名字空间中.在终端服务器,应用程序的命名内核对象将放入会话的名字空间中.如果使用"Global\"置于对象名的前面,就可以使命名对象进入全局名字空间:
HANDLE h = CreateEvent(NULL,FALSE,FALSE,"Global\\MyName");
也可以显式说明想让内核对象进入会话的名字空间"Local\":
HANDLE = CreateEvent(NULL,FALSE,FALSE,"Local\\MyName");
复制对象句柄:
是共享跨越进程边界的内核对象的最后一个方法DuplicateHandle():
BOOL DuplicateHandle(
HANDLE hSourceProcessHandle,
HANDLE hSourceHandle,
HANDLE hTargetProcessHandle,
PHANDLE phTargetHandle,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwOptions);
复制对象句柄之后要通过某种方式通知进程他获得了哪些内核对象的句柄,不然进程不知道.使用窗口消息或者IPC其他机制
eg:进程S有一个内核对象,想让进程T能够访问:
//下面所有代码被进程S执行
// 进程S创建一个互斥量
HANDLE hObjProcessS = CreateMutex(NULL, FALSE, NULL);
// 打开进程T的句柄对象
HANDLE hProcessT = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessIdT);
HANDLE hObjProcessT;//一个未初始化的与进程T相关联的句柄
//复制句柄
DuplicateHandle(GetCurrentProcess(),hObjProcessS,hProcessT,&hObjProcessT,0,FALSE,DUPLICATE_SAME_ACCESS);
//使用一些IPC方式告诉句柄值
//不在需要执行进程T相关的操作,关闭在进程S中的引用
CloseHandle(hProcessT);
//在进程S中,如果这个互斥量也不需要了,我们应当也关闭
CloseHandle(hObjProcessS);
GetCurrentProcess();的调用会返回一个伪句柄,这个句柄总是用来标识调用端的进程S