核心编程随笔2 分类: VC++ 2013-09-28 08:43 518人阅读 评论(0) 收藏

Note 1:
以前版本的Windows设计的一些应用程序之所以在Windows Vista上不能正常工作,就是因为在实现这些程序时,没有充分考虑安全性.假定一个应用程序在启动时要从一个注册表子项中读取一些数据.正确的做法是调用RegOpenKeyEx,向其传入KEY_QUERY_VALUE,从而指定查询子项数据的权限.然而许多应用程序对安全性没有任何考虑.有的软件开发人员还是按照老习惯,在调用RegOpenKeyEx函数的时候,传入KEY_ALL_ACCESS作为期望的访问权限.这样做的问题在于,对于一个不是管理员的标准用户,注册表项(比如HKLM)也许是只读的.所以,当这样的应用程序在Windows Vista上面运行时,调用RegOpenKeyEx函数并传递KEY_ALL_ACCESS就会失败.

Note 2:
不同进程中运行的线程需要共享内核对象.下面罗列了一些理由.

利用文件映射对象,可以在同一台机器上运行的两个不同进程之间共享数据块.
借助mailslots和named pipes,在网络中的不同计算机上运行的进程可以相互发送数据块.
mutexes、semaphores和事件允许不同进程中的线程同步执行.例如,一个应用程序可能需要在完成某个任务之后,向另一个应用程序发出通知.
用三种不同的机制来允许进程共享内核对象:使用对象句柄继承,为对象命名,以及复制对象句柄;

Note 3:
如果你写的一个服务要同这些应用程序通信,就不能假定它和用户应用程序在同一个会话中运行.要想更多地了解Session0隔离问题,及其对服务开发人员的影响,请阅读"Impact of Session 0 Isolation on Services and Drivers in Windows Vista"一文,网址是http://www.microsoft.com/whdc/system/vista/services.mspx.

Note 4:

复制对象句柄的函数:
BOOL DuplicateHandle(
HANDLE hSourceProcessHandle,
HANDLE hSourceHandle,
HANDLE hTargetProcessHandle,
PHANDLE phTargetHandle,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwOptions);
(hyp:这个一个可以用来做很多邪恶事情的函数,比如你可以打开一个文件然后把句柄复制到系统进程里面,这样子文件就删不掉了)

Note 5;
一般将进程定义成一个正在运行的程序的一个实例,它由以下两个组件构成:
             一个内核对象,操作系统用它来管理进程.内核对象也是系统保存进程统计信息的地方.
             一个地址空间,其中包含所有执行体(executable)或DLL模块的代码和数据.此外,它还包含动态内存分配,比如线程堆栈和堆的分配.

Note 6:
进程要做任何事情,都必须让一个线程在它的上下文中运行.该线程要执行进程地址空间包含的代码.一个进程可以有多个线程,所有线程都在进程的地址空间中"同时"执行代码.因此每个线程都有它自己的一组CPU寄存器和它自己的堆栈.每个进程至少要有一个线程执行进程地址空间包含的代码.一个进程创建的时候,系统会自动创建它的第一个线程,这称为主线程(primary thread).然后这个线程再创建更多的线程,如果没有线程要执行进程地址空间包含的代码,进程就失去了继续存在的理由.所以,系统会自动销毁进程及其地址空间.(hyp:所以结束一个进程的所有线程将会导致进程被结束)

Note 7:
如果你的代码在一个DLL中,那么可利用两个办法来了解代码正在什么模块中运行:
第一个办法是利用链接器提供的伪变量__ImageBase,它指向当前正在运行的模块的基地址.
第二个办法是调用GetModuleHandleEx,将GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS作为它的第一个参数,将当前方法的地址作为第二个参数.最后一个参数是指向一个HMODULE的指针,该指针将由GetModuleHandleEx来填充,它就是包含了传入函数的那个DLL的基地址.
以下代码对这两个办法都进行了演示:
extern "C" const IMAGE_DOS_HEADER __ImageBase;
void DumpModule() {
// Get the base address of the running application.
// Can be different from the running module if this code is in a DLL.
HMODULE hModule = GetModuleHandle(NULL);
_tprintf(TEXT("with GetModuleHandle(NULL) = 0x%x\r\n"), hModule);
// Use the pseudo-variable __ImageBase to get
// the address of the current module hModule/hInstance.
_tprintf(TEXT("with __ImageBase = 0x%x\r\n"), (HINSTANCE)&__ImageBase);
// Pass the address of the current method DumpModule
// as parameter to GetModuleHandleEx to get the address
// of the current module hModule/hInstance.
hModule = NULL;
GetModuleHandleEx(
   GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
   (PCTSTR)DumpModule,
   &hModule);
_tprintf(TEXT("with GetModuleHandleEx = 0x%x\r\n"), hModule);
}
int _tmain(int argc, TCHAR* argv[]) {
DumpModule();
return(0);
}
Note 8:
调用GetCommandLine函数可以获得一个指向进程完整命令行的指针.
应用程序可以使用全局变量__argc和__argv(或__wargv)来访问对命令行的各个单独的组件,不过这些变量现在已经不提倡使用了.
利用在ShellAPI.h文件中声明并由Shell32.dll导出的函数CommandLineToArgvW可以将任何Unicode字符串分解成单独的标记:
PWSTR* CommandLineToArgvW(
PWSTR pszCmdLine,
int* pNumArgs);
CommandLineToArgvW在内部分配内存.许多应用程序不会释放这个内存——它们指望操作系统在进程终止时释放内存.这是完全可以接受的.不过,如果你想自己释放内存,正确的做法就是像下面这样调用HeapFree:
int nNumArgs;
PWSTR *ppArgv = CommandLineToArgvW(GetCommandLineW(), &nNumArgs);
// Use the arguments…
if (*ppArgv[1] == L'x') {
...
}
// Free the memory block
HeapFree(GetProcessHeap(), 0, ppArgv);
Note 9:
每个进程都有一个与它关联的环境块(environment block).这是在进程地址空间内分配的一个内存块.其中包含和下面相似的一组字符串:
=::=::\ ...
VarName1=VarValue1\0
VarName2=VarValue2\0
VarName3=VarValue3\0 ...
VarNameX=VarValueX\0
\0
每个字符串的第一部分是一个环境变量的名称,后跟一个等号,等号之后是希望赋给此变量的值.
注意,除了第一个=::=::\字符串,块中可能还有其他字符串是以等号(=)开头的.

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted @ 2013-09-28 08:43  毛毛虫的薄刻  阅读(136)  评论(0编辑  收藏  举报