??xml version="1.0" encoding="utf-8" standalone="yes"?>性高朝久久久久久久久久,777午夜精品久久av蜜臀 ,久久亚洲国产精品成人AV秋霞http://www.shnenglu.com/xi52qian/xi52qianzh-cnFri, 04 Jul 2025 08:07:33 GMTFri, 04 Jul 2025 08:07:33 GMT60Windows核心~程 W??q程http://www.shnenglu.com/xi52qian/archive/2011/03/07/141245.htmlxi52qianxi52qianMon, 07 Mar 2011 01:40:00 GMThttp://www.shnenglu.com/xi52qian/archive/2011/03/07/141245.htmlhttp://www.shnenglu.com/xi52qian/comments/141245.htmlhttp://www.shnenglu.com/xi52qian/archive/2011/03/07/141245.html#Feedback0http://www.shnenglu.com/xi52qian/comments/commentRss/141245.htmlhttp://www.shnenglu.com/xi52qian/services/trackbacks/141245.htmlq程׃部分l成Q?/p>
  • 操作pȝ理q程的内核对象。存放该q程 的统计信息的地方?
  • 地址I间Q包含可执行模块和DLL模块的代码和数据。动态分配的内存Q线E堆栈和堆)?

q程是不zL的,q程当中臛_要有一个线E,每个U程要有自己的堆栈和自己的CPU寄存器。CPU通过法l每个线E分配时间片的办法来造成假象是在同时工作Q多栔R过自己的算法实现同时运行)?/p>

4.1 ~写W一个Windiws应用E序

Windows两种cd的程序:

  • CUIE序Q比如CMD.EXE{等。Microsoft Visual C++q接开关ؓ/SUBSYSTEM:CONDOLEQ程序启动时不能创徏GUIE序Q?
  • GUIE序Q图形用L序,比如NotepadQWord{等。Microsoft Visual C++q接开关ؓ/SUBSYSTEM:WINDOWSQ程序启动时不能创徏CUIE序Q?

注意Q俩者的概念其实是很模糊的,CUI可以创徏GUI囑Ş界面Q反之GUIE序可能用CUIE序?/p>

Windowsq入点函敎ͼ区分在于CUI和GUIE序QANSI码和UNICODE码)

int WINAPI WinMain(
HINSTANCE hinstExe,
HINSTANCE,
PSTR pszCmdLine,
int nCmdShow);

int WINAPI wWinMain(
HINSTANCE hinstExe,
HINSTANCE,
PWSTR pszCmdLine,
int nCmdShow);

int __cdecl main(
int argc,
char *argv[],
char *envp[]);

int __cdecl wmain(
int argc,
wchar_t *argv[],
wchar_t *envp[]);

其实WindowsE序启动时最开始ƈ不调用自己写的入口函敎ͼ而是调用pȝ的几个入口函敎ͼ以便可以调用malloc和free之类的函敎ͼ初始化全局和静态C++对象{?/p>

  • 索指向新q程的完整命令行的指针?
  • 索指向新q程的环境变量的指针?
  • 对C/C++q行期的全局变量q行初始化。如果包含StdLib.h文gQ代码就可以讉Kq些变量?
  • 对Cq行期的malloc和callo和其他底层输?输出例程使用的内存栈q行初始化?
  • 为所有全局和静态C++cd象调用构造函数?

  应用E序cd                            q入?nbsp;                                                    嵌入可执行文件的启动函数


ANSI码GUI应用E序                   WinMain                                               WinMainCRTStattup

UNICODE码GUI应用E序           wWinMain                                            wWinMainCRTStattup

ANSI码CUI应用E序                   main                                                       mainCRTStattup

UNICODE码CUI应用E序           wmain                                                    wmainCRTStattup


注意Q应用程序会Ҏ(gu)SUBSYSTEM开x查找嵌入可执行启动函敎ͼ如果q入点函数和启动函数不匹配则昄链接错误。可以删除SUBSYSTEMQVS Project SettingsQ开养Iq样应用E序会自动需扑֌配的函数?/p>

q入点函数返回时调用pȝ的exit函数Q将q回g递给它。exit函数负责下面操作Q?/p>

  • 调用由_onexit函数的调用而注册的M函数?
  • 为所有全局的和静态的C++cd象调用析构函?
  • 调用操作pȝ的ExitProcessQƈ返回g递给他,关闭q程?

4.1.1 q程的实例句?/p>

WinMain/wWinMain函数的第一个参数表CE加载的可执行文件的基地址/句柄。对于加载资源的调用都要使用此句柄,比如HICON LoadIcon(HINSTANCE, PCTSTR)。有的函数需要用HMODULEQ和HINSTANCE是一个意思(区分主要在于16位的操作pȝ中)?/p>

HMODULE GetModuleHandle(PCTSTR pszModele);

函数作用Q返回加载调用进E中的可执行文g或者DLL的基地址/句柄Q参数是可执行文件或者DLL的名U。给pszModule赋值NULLQ则q回的是q程中可执行文g的句柄?/p>

注意Q如果找不到则返回NULL。如果在DLL中传递NULLQ返回的仍然是进E加载的可执行文件的句柄?/p>

4.1.2 q程的前一个实例句?/p>

W二个参数都传递NULLQ是?6位系l所保留的?/p>

4.1.3 q程的命令行

注意Q不要试图修改命令行内部内存的|要用修改先拯出来?/p>

PTSTR GetCommandLine(); // q回命o行字W串
 
PTSTR CommandLineToArgv(PTSTR pszCmdLine, int *pNumArgs); // 拆分命o行字W串函数

DemoQ?/p>

int nNumargs;
PTSTR *ppArgv = CommandLineToArgv(GetCommandLine(), &nNumargs);
if ('x' == *ppArgv[1]) {
// TODO:
}

// 手动释放内存Q一般不需要释放,pȝ会进E关闭时候自动释?/span>
HeapFree(GetProcessHeap, 0, ppArgv);


4.1.4 q程的环境变?/p>

环境块是q程地址I间中分配的内存块每个环境块都包含一l字W串,格式如下:

VarName1=VarVarlue1\0

VarName2=VarVarlue2\0

VarName3=VarVarlue3\0

?.

VarNameX=VarVarlueX\0

\0

注意Q?/p>

  • 排序必须按照字母序?
  • ?’号不能是变量名的一部分?
  • {号左右两边的空格将被算做名U或者倹{?
  • 最后必d个’\0’表C结束?
  • 子进E和父进E不q环境块,修改不会影响?子进E?
DWORD GetEnvironmentVariable(PCTSTR pszName, PTSTR pszValue, DWORD cchValue);


pszName指变量名QpszValue指向变量值的~存区,cchValue~存区的大小。找不到变量名或者设|的长度不够存放p??

 

ExpandEnvironmentStrings(PCSTR pszSrc, PSTR pszDst, DWORD nSize);

用来用现实出可替换的环境变量的字W串?/p>

BOOL SetEnvironmentVariable(PCTSTR pszName, PCTSTR pszValue);

讄环境变量的?如果不存在则创徏,如果存在则替换他的倹{?/p>

4.1.5 q程的亲~?/p>

子进E承父q程的亲~性。(具体什么意思没明白Q?/p>

4.1.6 q程的错误模?/p>

q程可以讄如何处理一些错误?/p>

UINT SetErrorMode(UINT fuErrorMode);


各个模式用ORq接


      标志                                                                                                               说明

SEM_FAILCRITICALERRORS                                                                    pȝ不显C关键错误句柄消息框Qƈ错误返回给调用q程

SEM_NOGOFAULTERRORBOX                                                               pȝ不显CZ般保护故障消息框。本标志只应该由采用异常情况处理E序来处理一般保护(GPQ故障的调式应用E式来设?/p>

SEM_NOOPENFILEERRORBOX                                                               当系l找不到文gӞ它不昄消息框?/p>

SEM_NOALIGNMENTFAULTEXCEPT                                                    pȝ自动排除内存没有对其的故障,q应用E序看不到这些故障。本标志对X86处理器不起作用?/p>


子进E承父q程的错误模式,如果不想让子q程l承父进E的错误模式的话Q可以再调用CreateProcess时设定CREATE_DEFAULT_ERROR_MODE标志?

4.1.7 q程的当前驱动器和目?/p>

默认情况下不提供全\径的话,pȝ׃在当前驱动器和目录中查找文gQ比如CreateFileQ因为驱动器和目录是每个q程来维护的Q所以某个线E改变了目录和驱动器会改变整个进E的目录和驱动器?/p>

下面两个函数d和设|:

DWORD GetCurrentDirectory(DWORD cchCurDir, PTSTR pszCurDir);

BOOL SetCurrentDirectory(PCTSTR pszCurDir);

4.1.8 q程的当前目?/p>

驱动器环境块的格?

=C:=C:\Utility\Bin

E序查找驱动器环境块Q如果没有则按驱动器名查找?/p>

子进E不能承父q程的驱动器块,如果想承必d到环境变量中厅R(好像是这P如果有不对请高h指点Q?/p>

DWORD GetFullPathName(PCTSTR pszFile, DWORD cchPath, PTSTR pszPath, PTSTR *ppszFilePart);

获取驱动器的当前目录,比如:

TCHAR szCurDir[MAX_PATH];
DWORD GetFullPathName(TEXT("C:"), MAX_PATH, szCurDir, NULL);


4.1.9 pȝ版本

DWORD GetVersion();此函数存在高C的؜论BUGQ所以尽量不要用?/p>

BOOL GetVersion(POSVERSIONINFOEX pVersionInfomation);
typedef struct _OSVERSIONINFOEXA {
    DWORD dwOSVersionInfoSize;    // 在调用GetVersionEx函数之前Q必必须|ؓsizeof(OSVERSIONINFOEX)
    DWORD dwMajorVersion;         // ȝl的主要版本?/span>
     DWORD dwMinorVersion;         // ȝl的ơ要版本?/span>
     DWORD dwBuildNumber;          // 当前pȝ的构建号
     DWORD dwPlatformId;           // 识别当前pȝ的^台。可以VER_PLATFORM_WIN32(WIN32),VER_PLATFORM_WIN32_WINDOWS(WINDOWS 95/WINDOWS 98),VER_PLATFORM_WIN32_NT(WINDOWS NT/WINDOWS 2000)或VER_PLATFORM_WIN32_CEHH(WINDOWS CE)
    CHAR   szCSDVersion[ 128 ];     // Maintenance string for PSS usage 本域包含了附加文本,用于提供关于已经安装的操作系l的详细信息
     WORD   wServicePackMajor;       // 最新安装的服务E序包的主要版本?/span>
     WORD   wServicePackMinor;       // 最新安装的服务E序包的ơ要版本?/span>
     WORD   wSuiteMask;              // 用于标识pȝ上存在那个程序组QVER_SUITE_SMALLBUSINESS,VER_SUITE_ENTERPRISE,VER_SUITE_BACKOFFICE,VER_SUITE_COMMUNICATIONS,VER_SUITE_TERMINAL,VER_SUITE_SMALLBUSINESS_RESTRICTED,VER_SUITE_EMBEDDEDNT和VER_SUITE_DATACENTERQ?/span>
     BYTE  wProductType;             // 用于标识安装了下面的哪个操作pȝQVER_NT_WORKSTATION,VER_NT_SERVER或VER_NT_DOMAIN_CONTROLLER
    BYTE  wReserved;                // 留作来使用
} OSVERSIONINFOEXA, *POSVERSIONINFOEXA, *LPOSVERSIONINFOEXA;

q个是扩展版本?/div>
 
4.2 CreateProcess函数
l于看到正题了~大笑
BOOL CreateProcess(
    LPCSTR lpApplicationName,
    LPSTR lpCommandLine,
    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    BOOL bInheritHandles,
    DWORD dwCreationFlags,
    LPVOID lpEnvironment,
    LPCSTR lpCurrentDirectory,
    LPSTARTUPINFOA lpStartupInfo,
    LPPROCESS_INFORMATION lpProcessInformation
    );

  1. q程启动Ӟ首先创徏一个进E内核对象,该内核对象不是进E,是一个管理进E存储进E信息的型数据l构。(计数?Q?
  2. 创徏一个虚拟地址I间Q加载可执行文g和DLL?
  3. E创ZȝE的内核对象Q和q程内核对象一P是用来管理和存储U程信息的小型数据结构。(计数?Q?
  4. 调用C/C++q行期启动代码,ȝE开始运行,最l调用启动函敎ͼ成功q回TRUEQ未能正加载DLL也返回TRUEQ所以父q程无法查看Q?

4.2.1 pszApplicationName和pszCommandLine

pszCommandLine参数Q用来创E的命o行参数。查看第一个标讎ͼ如果没有?exe”会自动d?exe”上厅R(如果pszApplicationName参数NULLQ?/p>

  1. 包含调用q程的?exe”文件的目录?
  2. 调用q程的当前目录?
  3. windowspȝ目录
  4. windows目录
  5. PATH环境变量中列出的目录?

如果pszApplicationName参数不ؓNULLQ系l将在当前目录中查找.exe文gQ不会自动添加?exe”)Q如果找不到失败,此时pszCommandLine作ؓ参数传递给可执行程序的q程?/p>

4.2.2 psaProcess,psaThread和binHeritHandles

psaProcess,psaThread是进E和q程ȝE内核对象的安全属性。默认gؓNULL?/p>

binHeritHandles讄为TRUE表示父进E在创徏子进E可以承安全属性标志里讄为TRUE的Q何可l承的内核对象。如果设|ؓFALSE子进E将不承Q何内核对象?/p>

4.2.3 fdwCreate

用于标识标志Q定义规则如何创建新q程。我一般写默认值NULL。具体的太多了,h看MSDN吧,不想写了?/p>

4.2.4 pvEnvironment

讄子进E用的环境内存块,一般默认gؓNULLQ表C子q程l承父进E的环境块?/p>

PVOID GetEnvironmentString(); // 获取当前内存块的地址
BOOL FreeEnvironmentStrings(PTSTR pszEnvironmentBlock); // 不用的时候调用此函数释放内存?/span>


4.2.5 pszCurDir

讑֮工作目录和驱动器P如果为NULL则和应用E序的目录相同,如果讄比如以’\0’结包含驱动器名的\径?/p>

4.2.6 psiStartInfo

typedef struct _STARTUPINFO {
    DWORD   cb;             //Q两者兼有,控制台和H口E序Q?
    LPSTR   lpReserved;     // Q两者兼有)保留Q必d始化为NULL
    LPSTR   lpDesktop;      // Q两者兼有)用于标识启动应用E序所在的桌面的名字。如果该桌面存在Q新q程便与指定的桌面相兌。如果桌面不存在Q便创徏一个带有默认属性的桌面Qƈ使用为新q程指定的名字。如果lpDesktop是NULLQ这是最常见的情况)Q那么该q程与当前桌面相关联?/span>
    LPSTR   lpTitle;        // Q控制台Q用于设定控制台H口名称。如果lpTitle是NULLQ则可执行文件的名字用作窗口名
    DWORD   dwX;            // x,y坐标Q只有当子进E用CW_USEDEFAULT作ؓCreateWindows的x参数来创建它的第一个重叠窗口时Q才使用q两个坐标。若是创建控制台H口的应用程序,q些成员用于指明控制台窗口的左上角?/span>
    DWORD   dwY;          
    DWORD   dwXSize;        //Q两者兼有)讑֮H口宽度和长度,只有子进E用WM_USEDEFAULT作ؓCreateWIndows的nWidth参数来创建它的第一个重叠窗口时才是用这个倹{控制台是控制台的宽和?/span>
    DWORD   dwYSize;
    DWORD   dwXCountChars;  //Q控制台Q用于设定子应用E序控制台的长度和宽度(字符表示Q?/span>
    DWORD   dwYCountChars;
    DWORD   dwFillAttribute;// Q控制台Q用于设定子应用E序的控制台背媄颜色和文本?/span>
    DWORD   dwFlags;        // Q两者兼有)参见下一D?/span>
    WORD    wShowWindow;    // (H口)用于讑֮子应用程序初ơ调用ShowWindowSW_SHOWDEFAULT作ؓnCmdShow参数传递时Q该应用E序的第一个重叠窗口应该如何出现。本成员可以是通常用于ShowWindow函数的Q何一个SW_*标识W?/span>
    WORD    cbReserved2;    // 保留Q必d始化?
    LPBYTE  lpReserved2;    // 保留Q必d始化为NULL
    HANDLE  hStdInput;      // (控制?用于讑֮控制台输入和输出用的~存的句柄。默认设|hStdInput是键盘缓存,hStdOutput和hStdErrorH口的缓存?/span>
    HANDLE  hStdOutput;     // 
    HANDLE  hStdError;
} STARTUPINFO, *LPSTARTUPINFO;


讄某些|大部分需要默认|必须初始化ؓ0都?/p>

STARTUPINFO si = {sizeof(si)};

dwFlags标志Q用于修改如何来创徏子进E?/p>


标志
STARTF_USESIZE                                                                              使用dwXSize和dwYSize成员

STARTF_USESHOWWINDOW                                                         使用wShowWIndow成员

STARTF_USEPOSITION                                                                    使用dwX和dwY成员

STARTF_USECOUNTCHARS                                                            使用dwXCountChars和dwYCountChars成员

STARTF_USEFILLATTRIBUTE                                                           使用dwFillAttribute成员

STARTF_USESTDHANDLES                                                             使用hStdInput,hStdOutput和hStdError成员

STARTF_RUN_FULLSCREEN                                                            强制再x86计算Zq行的控制台应用E序以全屏幕方式启动q行

STARTF_FORCEONFEEDBACK                                                        光标讄为沙漏,q了2U如果进E没启动GUIQCreateProcessE序光标设|ؓ头Q?U内昄一个窗口,成功调用GetMessage则反复箭_如果没有成功Q等?U?变ؓ头

STARTF_FORCEOFFFEEDBACK                                                                                      


4.2.7 ppiProcInfo

typedef struct _PROCESS_INFORMATION {
    HANDLE hProcess;
    HANDLE hThread;
    DWORD dwProcessId;
    DWORD dwThreadId;
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;

q回的分别是Q子q程q程句柄Q子q程中主U程的线E句柄,子进EIDQ子q程中主U程的ID?/p>

注意Q?/p>

  1. hProcess和hThread被赋值后Q内核对象的计数器分别被+1?
  2. pȝ为每个进E和U程分配的ID值都是不同的Q但是当某进E退出后Q新q程很可能会使用退E的ID?

 

4.3 l止q程的运?/p>

4.3.1 ȝE的q入点函数返?/p>

最好强力推荐用这U方式?/p>

  1. 调用C++析构函数?
  2. 释放堆栈内存?
  3. 进E退Z码(q程内核对象中维护)讄入点函数q回倹{?
  4. pȝ进E内核对象的q回值减??

4.3.2 ExitProcess函数

避免使用q个Ҏ(gu)?/p>

VOID ExitProcess(UINT fuExitCode);

l止q程q行Qƈ退出码讄为fuExitCode?/p>

注意Q?/p>

  1. 调用ExitProcess后,所有的代码都将不会执行Q关闭进E?
  2. 调用ExitProcess后,不会释放C++析构函数资源Q有pȝ清理q程时候直接释攑ֆ存?
  3. q程的主U程直接return退出后Q启动函C也会调用ExitProcess函数Q进E终止,其他U程也会关闭?
  4. q程的主U程调用_endThreadex或者EndThread函数关闭ȝE后Q进E没有被关闭Q子U程l箋q行?

 

4.3.3 TerminiateProcess函数

能不用就别用?/p>

BOOL TerminiateProcess(HANDLE hProcess, UINT fuExitCode;)

关闭指定为hProcess句柄的进E,推出代码为fuExitCode?/p>

注意Q?/p>

  1. 关闭q程丢失所有需要保存到盘的数据,因ؓq程关闭时候最后会自己释放内存资源Q关闭内核对象的句柄|所以不会造成内存泄露?
  2. 此函数是个异步函敎ͼ它返回的时候无法知道,需要关闭的q程是否已经被强制关闭了?

4.3.4 q程l止q行时出现的情况

  1. q程中剩余的所有线E全部终止运行?
  2. 释放该进E引用的GDI和用户对象,内核对象被关闭(别的q程有引用则计数器减1Q如果没有引用则关闭内核对象Q?
  3. 推出代码从STILL_ACTIVEQ后面章节线E将介绍该结构)改ؓ传递给ExitProcess和TerminiateProcess代码?
  4. 内核对象状态变为收到通知状态(U程中介l)Q其他线E挂P知道q程l止?
  5. q程内核对象计数减去1Q或者关闭?

注意Q?/p>

q程内核对象的寿命可能远q大于进E本w,父进E保留子q程内核对象可以查看它的推出代码调用下面函数Q?/p>

BOOL GetExitCodeProcess(HANDLE hProcess, PDWORD pdwExitCode);


可以调用q个函数来判断子q程是否关闭,如果子进E没有关?它的STILL_ACTIVE标识W定义ؓ0x103。但是这么作效率不是很高?/p>

 

4.4 子进E?/p>

没什么好说的Q前面的都说了,用CloseHandle关闭子进E和子进E中ȝE的句柄值来切断父进E和子进E的所有联pR?/p>

 

4.5 每局pȝ中运行的q程

利用ToolHelp函数族来开发管理操作系l上的进E。打自׃写个试试?/p>

 

本文章的内容是本人学习Windows核心~程W四章后的ȝQ有错误请大家纠正,转蝲注明出处:

http://www.cnblogs.com/xi52qian/



xi52qian 2011-03-07 09:40 发表评论
]]>Windows核心~程 W??q程http://www.shnenglu.com/xi52qian/archive/2011/03/04/141121.htmlxi52qianxi52qianFri, 04 Mar 2011 08:45:00 GMThttp://www.shnenglu.com/xi52qian/archive/2011/03/04/141121.htmlhttp://www.shnenglu.com/xi52qian/comments/141121.htmlhttp://www.shnenglu.com/xi52qian/archive/2011/03/04/141121.html#Feedback0http://www.shnenglu.com/xi52qian/comments/commentRss/141121.htmlhttp://www.shnenglu.com/xi52qian/services/trackbacks/141121.htmlq程׃部分l成Q?/p>
  • 操作pȝ理q程的内核对象。存放该q程 的统计信息的地方?
  • 地址I间Q包含可执行模块和DLL模块的代码和数据。动态分配的内存Q线E堆栈和堆)?

q程是不zL的,q程当中臛_要有一个线E,每个U程要有自己的堆栈和自己的CPU寄存器。CPU通过法l每个线E分配时间片的办法来造成假象是在同时工作Q多栔R过自己的算法实现同时运行)?/p>

4.1 ~写W一个Windiws应用E序

Windows两种cd的程序:

  • CUIE序Q比如CMD.EXE{等。Microsoft Visual C++q接开关ؓ/SUBSYSTEM:CONDOLEQ程序启动时不能创徏GUIE序Q?
  • GUIE序Q图形用L序,比如NotepadQWord{等。Microsoft Visual C++q接开关ؓ/SUBSYSTEM:WINDOWSQ程序启动时不能创徏CUIE序Q?

注意Q俩者的概念其实是很模糊的,CUI可以创徏GUI囑Ş界面Q反之GUIE序可能用CUIE序?/p>

Windowsq入点函敎ͼ区分在于CUI和GUIE序QANSI码和UNICODE码)

int WINAPI WinMain(
HINSTANCE hinstExe,
HINSTANCE,
PSTR pszCmdLine,
int nCmdShow);

int WINAPI wWinMain(
HINSTANCE hinstExe,
HINSTANCE,
PWSTR pszCmdLine,
int nCmdShow);

int __cdecl main(
int argc,
char *argv[],
char *envp[]);

int __cdecl wmain(
int argc,
wchar_t *argv[],
wchar_t *envp[]);

其实WindowsE序启动时最开始ƈ不调用自己写的入口函敎ͼ而是调用pȝ的几个入口函敎ͼ以便可以调用malloc和free之类的函敎ͼ初始化全局和静态C++对象{?/p>

  • 索指向新q程的完整命令行的指针?
  • 索指向新q程的环境变量的指针?
  • 对C/C++q行期的全局变量q行初始化。如果包含StdLib.h文gQ代码就可以讉Kq些变量?
  • 对Cq行期的malloc和callo和其他底层输?输出例程使用的内存栈q行初始化?
  • 为所有全局和静态C++cd象调用构造函数?

  应用E序cd                            q入?nbsp;                                                    嵌入可执行文件的启动函数


ANSI码GUI应用E序                   WinMain                                               WinMainCRTStattup

UNICODE码GUI应用E序           wWinMain                                            wWinMainCRTStattup

ANSI码CUI应用E序                   main                                                       mainCRTStattup

UNICODE码CUI应用E序           wmain                                                    wmainCRTStattup


注意Q应用程序会Ҏ(gu)SUBSYSTEM开x查找嵌入可执行启动函敎ͼ如果q入点函数和启动函数不匹配则昄链接错误。可以删除SUBSYSTEMQVS Project SettingsQ开养Iq样应用E序会自动需扑֌配的函数?/p>

q入点函数返回时调用pȝ的exit函数Q将q回g递给它。exit函数负责下面操作Q?/p>

  • 调用由_onexit函数的调用而注册的M函数?
  • 为所有全局的和静态的C++cd象调用析构函?
  • 调用操作pȝ的ExitProcessQƈ返回g递给他,关闭q程?

4.1.1 q程的实例句?/p>

WinMain/wWinMain函数的第一个参数表CE加载的可执行文件的基地址/句柄。对于加载资源的调用都要使用此句柄,比如HICON LoadIcon(HINSTANCE, PCTSTR)。有的函数需要用HMODULEQ和HINSTANCE是一个意思(区分主要在于16位的操作pȝ中)?/p>

HMODULE GetModuleHandle(PCTSTR pszModele);

函数作用Q返回加载调用进E中的可执行文g或者DLL的基地址/句柄Q参数是可执行文件或者DLL的名U。给pszModule赋值NULLQ则q回的是q程中可执行文g的句柄?/p>

注意Q如果找不到则返回NULL。如果在DLL中传递NULLQ返回的仍然是进E加载的可执行文件的句柄?/p>

4.1.2 q程的前一个实例句?/p>

W二个参数都传递NULLQ是?6位系l所保留的?/p>

4.1.3 q程的命令行

注意Q不要试图修改命令行内部内存的|要用修改先拯出来?/p>

PTSTR GetCommandLine(); // q回命o行字W串
 
PTSTR CommandLineToArgv(PTSTR pszCmdLine, int *pNumArgs); // 拆分命o行字W串函数

DemoQ?/p>

int nNumargs;
PTSTR *ppArgv = CommandLineToArgv(GetCommandLine(), &nNumargs);
if ('x' == *ppArgv[1]) {
// TODO:
}

// 手动释放内存Q一般不需要释放,pȝ会进E关闭时候自动释?/span>
HeapFree(GetProcessHeap, 0, ppArgv);


4.1.4 q程的环境变?/p>

环境块是q程地址I间中分配的内存块每个环境块都包含一l字W串,格式如下:

VarName1=VarVarlue1\0

VarName2=VarVarlue2\0

VarName3=VarVarlue3\0

?.

VarNameX=VarVarlueX\0

\0

注意Q?/p>

  • 排序必须按照字母序?
  • ?’号不能是变量名的一部分?
  • {号左右两边的空格将被算做名U或者倹{?
  • 最后必d个’\0’表C结束?
  • 子进E和父进E不q环境块,修改不会影响?子进E?
DWORD GetEnvironmentVariable(PCTSTR pszName, PTSTR pszValue, DWORD cchValue);


pszName指变量名QpszValue指向变量值的~存区,cchValue~存区的大小。找不到变量名或者设|的长度不够存放p??

 

ExpandEnvironmentStrings(PCSTR pszSrc, PSTR pszDst, DWORD nSize);

用来用现实出可替换的环境变量的字W串?/p>

BOOL SetEnvironmentVariable(PCTSTR pszName, PCTSTR pszValue);

讄环境变量的?如果不存在则创徏,如果存在则替换他的倹{?/p>

4.1.5 q程的亲~?/p>

子进E承父q程的亲~性。(具体什么意思没明白Q?/p>

4.1.6 q程的错误模?/p>

q程可以讄如何处理一些错误?/p>

UINT SetErrorMode(UINT fuErrorMode);


各个模式用ORq接


      标志                                                                                                               说明

SEM_FAILCRITICALERRORS                                                                    pȝ不显C关键错误句柄消息框Qƈ错误返回给调用q程

SEM_NOGOFAULTERRORBOX                                                               pȝ不显CZ般保护故障消息框。本标志只应该由采用异常情况处理E序来处理一般保护(GPQ故障的调式应用E式来设?/p>

SEM_NOOPENFILEERRORBOX                                                               当系l找不到文gӞ它不昄消息框?/p>

SEM_NOALIGNMENTFAULTEXCEPT                                                    pȝ自动排除内存没有对其的故障,q应用E序看不到这些故障。本标志对X86处理器不起作用?/p>


子进E承父q程的错误模式,如果不想让子q程l承父进E的错误模式的话Q可以再调用CreateProcess时设定CREATE_DEFAULT_ERROR_MODE标志?

4.1.7 q程的当前驱动器和目?/p>

默认情况下不提供全\径的话,pȝ׃在当前驱动器和目录中查找文gQ比如CreateFileQ因为驱动器和目录是每个q程来维护的Q所以某个线E改变了目录和驱动器会改变整个进E的目录和驱动器?/p>

下面两个函数d和设|:

DWORD GetCurrentDirectory(DWORD cchCurDir, PTSTR pszCurDir);

BOOL SetCurrentDirectory(PCTSTR pszCurDir);

4.1.8 q程的当前目?/p>

驱动器环境块的格?

=C:=C:\Utility\Bin

E序查找驱动器环境块Q如果没有则按驱动器名查找?/p>

子进E不能承父q程的驱动器块,如果想承必d到环境变量中厅R(好像是这P如果有不对请高h指点Q?/p>

DWORD GetFullPathName(PCTSTR pszFile, DWORD cchPath, PTSTR pszPath, PTSTR *ppszFilePart);

获取驱动器的当前目录,比如:

TCHAR szCurDir[MAX_PATH];
DWORD GetFullPathName(TEXT("C:"), MAX_PATH, szCurDir, NULL);


4.1.9 pȝ版本

DWORD GetVersion();此函数存在高C的؜论BUGQ所以尽量不要用?/p>

BOOL GetVersion(POSVERSIONINFOEX pVersionInfomation);
typedef struct _OSVERSIONINFOEXA {
    DWORD dwOSVersionInfoSize;    // 在调用GetVersionEx函数之前Q必必须|ؓsizeof(OSVERSIONINFOEX)
    DWORD dwMajorVersion;         // ȝl的主要版本?/span>
     DWORD dwMinorVersion;         // ȝl的ơ要版本?/span>
     DWORD dwBuildNumber;          // 当前pȝ的构建号
     DWORD dwPlatformId;           // 识别当前pȝ的^台。可以VER_PLATFORM_WIN32(WIN32),VER_PLATFORM_WIN32_WINDOWS(WINDOWS 95/WINDOWS 98),VER_PLATFORM_WIN32_NT(WINDOWS NT/WINDOWS 2000)或VER_PLATFORM_WIN32_CEHH(WINDOWS CE)
    CHAR   szCSDVersion[ 128 ];     // Maintenance string for PSS usage 本域包含了附加文本,用于提供关于已经安装的操作系l的详细信息
     WORD   wServicePackMajor;       // 最新安装的服务E序包的主要版本?/span>
     WORD   wServicePackMinor;       // 最新安装的服务E序包的ơ要版本?/span>
     WORD   wSuiteMask;              // 用于标识pȝ上存在那个程序组QVER_SUITE_SMALLBUSINESS,VER_SUITE_ENTERPRISE,VER_SUITE_BACKOFFICE,VER_SUITE_COMMUNICATIONS,VER_SUITE_TERMINAL,VER_SUITE_SMALLBUSINESS_RESTRICTED,VER_SUITE_EMBEDDEDNT和VER_SUITE_DATACENTERQ?/span>
     BYTE  wProductType;             // 用于标识安装了下面的哪个操作pȝQVER_NT_WORKSTATION,VER_NT_SERVER或VER_NT_DOMAIN_CONTROLLER
    BYTE  wReserved;                // 留作来使用
} OSVERSIONINFOEXA, *POSVERSIONINFOEXA, *LPOSVERSIONINFOEXA;

q个是扩展版本?/div>
 
4.2 CreateProcess函数
l于看到正题了~大笑
BOOL CreateProcess(
    LPCSTR lpApplicationName,
    LPSTR lpCommandLine,
    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    BOOL bInheritHandles,
    DWORD dwCreationFlags,
    LPVOID lpEnvironment,
    LPCSTR lpCurrentDirectory,
    LPSTARTUPINFOA lpStartupInfo,
    LPPROCESS_INFORMATION lpProcessInformation
    );

  1. q程启动Ӟ首先创徏一个进E内核对象,该内核对象不是进E,是一个管理进E存储进E信息的型数据l构。(计数?Q?
  2. 创徏一个虚拟地址I间Q加载可执行文g和DLL?
  3. E创ZȝE的内核对象Q和q程内核对象一P是用来管理和存储U程信息的小型数据结构。(计数?Q?
  4. 调用C/C++q行期启动代码,ȝE开始运行,最l调用启动函敎ͼ成功q回TRUEQ未能正加载DLL也返回TRUEQ所以父q程无法查看Q?

4.2.1 pszApplicationName和pszCommandLine

pszCommandLine参数Q用来创E的命o行参数。查看第一个标讎ͼ如果没有?exe”会自动d?exe”上厅R(如果pszApplicationName参数NULLQ?/p>

  1. 包含调用q程的?exe”文件的目录?
  2. 调用q程的当前目录?
  3. windowspȝ目录
  4. windows目录
  5. PATH环境变量中列出的目录?

如果pszApplicationName参数不ؓNULLQ系l将在当前目录中查找.exe文gQ不会自动添加?exe”)Q如果找不到失败,此时pszCommandLine作ؓ参数传递给可执行程序的q程?/p>

4.2.2 psaProcess,psaThread和binHeritHandles

psaProcess,psaThread是进E和q程ȝE内核对象的安全属性。默认gؓNULL?/p>

binHeritHandles讄为TRUE表示父进E在创徏子进E可以承安全属性标志里讄为TRUE的Q何可l承的内核对象。如果设|ؓFALSE子进E将不承Q何内核对象?/p>

4.2.3 fdwCreate

用于标识标志Q定义规则如何创建新q程。我一般写默认值NULL。具体的太多了,h看MSDN吧,不想写了?/p>

4.2.4 pvEnvironment

讄子进E用的环境内存块,一般默认gؓNULLQ表C子q程l承父进E的环境块?/p>

PVOID GetEnvironmentString(); // 获取当前内存块的地址
BOOL FreeEnvironmentStrings(PTSTR pszEnvironmentBlock); // 不用的时候调用此函数释放内存?/span>


4.2.5 pszCurDir

讑֮工作目录和驱动器P如果为NULL则和应用E序的目录相同,如果讄比如以’\0’结包含驱动器名的\径?/p>

4.2.6 psiStartInfo

typedef struct _STARTUPINFO {
    DWORD   cb;             //Q两者兼有,控制台和H口E序Q?
    LPSTR   lpReserved;     // Q两者兼有)保留Q必d始化为NULL
    LPSTR   lpDesktop;      // Q两者兼有)用于标识启动应用E序所在的桌面的名字。如果该桌面存在Q新q程便与指定的桌面相兌。如果桌面不存在Q便创徏一个带有默认属性的桌面Qƈ使用为新q程指定的名字。如果lpDesktop是NULLQ这是最常见的情况)Q那么该q程与当前桌面相关联?/span>
    LPSTR   lpTitle;        // Q控制台Q用于设定控制台H口名称。如果lpTitle是NULLQ则可执行文件的名字用作窗口名
    DWORD   dwX;            // x,y坐标Q只有当子进E用CW_USEDEFAULT作ؓCreateWindows的x参数来创建它的第一个重叠窗口时Q才使用q两个坐标。若是创建控制台H口的应用程序,q些成员用于指明控制台窗口的左上角?/span>
    DWORD   dwY;          
    DWORD   dwXSize;        //Q两者兼有)讑֮H口宽度和长度,只有子进E用WM_USEDEFAULT作ؓCreateWIndows的nWidth参数来创建它的第一个重叠窗口时才是用这个倹{控制台是控制台的宽和?/span>
    DWORD   dwYSize;
    DWORD   dwXCountChars;  //Q控制台Q用于设定子应用E序控制台的长度和宽度(字符表示Q?/span>
    DWORD   dwYCountChars;
    DWORD   dwFillAttribute;// Q控制台Q用于设定子应用E序的控制台背媄颜色和文本?/span>
    DWORD   dwFlags;        // Q两者兼有)参见下一D?/span>
    WORD    wShowWindow;    // (H口)用于讑֮子应用程序初ơ调用ShowWindowSW_SHOWDEFAULT作ؓnCmdShow参数传递时Q该应用E序的第一个重叠窗口应该如何出现。本成员可以是通常用于ShowWindow函数的Q何一个SW_*标识W?/span>
    WORD    cbReserved2;    // 保留Q必d始化?
    LPBYTE  lpReserved2;    // 保留Q必d始化为NULL
    HANDLE  hStdInput;      // (控制?用于讑֮控制台输入和输出用的~存的句柄。默认设|hStdInput是键盘缓存,hStdOutput和hStdErrorH口的缓存?/span>
    HANDLE  hStdOutput;     // 
    HANDLE  hStdError;
} STARTUPINFO, *LPSTARTUPINFO;


讄某些|大部分需要默认|必须初始化ؓ0都?/p>

STARTUPINFO si = {sizeof(si)};

dwFlags标志Q用于修改如何来创徏子进E?/p>


标志


STARTF_USESIZE                                                                              使用dwXSize和dwYSize成员

STARTF_USESHOWWINDOW                                                         使用wShowWIndow成员

STARTF_USEPOSITION                                                                    使用dwX和dwY成员

STARTF_USECOUNTCHARS                                                            使用dwXCountChars和dwYCountChars成员

STARTF_USEFILLATTRIBUTE                                                           使用dwFillAttribute成员

STARTF_USESTDHANDLES                                                             使用hStdInput,hStdOutput和hStdError成员

STARTF_RUN_FULLSCREEN                                                            强制再x86计算Zq行的控制台应用E序以全屏幕方式启动q行

STARTF_FORCEONFEEDBACK                                                        光标讄为沙漏,q了2U如果进E没启动GUIQCreateProcessE序光标设|ؓ头Q?U内昄一个窗口,成功调用GetMessage则反复箭_如果没有成功Q等?U?变ؓ头

STARTF_FORCEOFFFEEDBACK                                                                                      


4.2.7 ppiProcInfo

typedef struct _PROCESS_INFORMATION {
    HANDLE hProcess;
    HANDLE hThread;
    DWORD dwProcessId;
    DWORD dwThreadId;
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;

q回的分别是Q子q程q程句柄Q子q程中主U程的线E句柄,子进EIDQ子q程中主U程的ID?/p>

注意Q?/p>

  1. hProcess和hThread被赋值后Q内核对象的计数器分别被+1?
  2. pȝ为每个进E和U程分配的ID值都是不同的Q但是当某进E退出后Q新q程很可能会使用退E的ID?/li>

 

4.3 l止q程的运?/p>

4.3.1 ȝE的q入点函数返?/p>

最好强力推荐用这U方式?/p>

  1. 调用C++析构函数?
  2. 释放堆栈内存?
  3. 进E退Z码(q程内核对象中维护)讄入点函数q回倹{?
  4. pȝ进E内核对象的q回值减??/li>

4.3.2 ExitProcess函数

避免使用q个Ҏ(gu)?/p>

VOID ExitProcess(UINT fuExitCode);

l止q程q行Qƈ退出码讄为fuExitCode?/p>

注意Q?/p>

  1. 调用ExitProcess后,所有的代码都将不会执行Q关闭进E?
  2. 调用ExitProcess后,不会释放C++析构函数资源Q有pȝ清理q程时候直接释攑ֆ存?
  3. q程的主U程直接return退出后Q启动函C也会调用ExitProcess函数Q进E终止,其他U程也会关闭?
  4. q程的主U程调用_endThreadex或者EndThread函数关闭ȝE后Q进E没有被关闭Q子U程l箋q行?/li>

 

4.3.3 TerminiateProcess函数

能不用就别用?/p>

BOOL TerminiateProcess(HANDLE hProcess, UINT fuExitCode;)

关闭指定为hProcess句柄的进E,推出代码为fuExitCode?/p>

注意Q?/p>

  1. 关闭q程丢失所有需要保存到盘的数据,因ؓq程关闭时候最后会自己释放内存资源Q关闭内核对象的句柄|所以不会造成内存泄露?
  2. 此函数是个异步函敎ͼ它返回的时候无法知道,需要关闭的q程是否已经被强制关闭了?/li>

4.3.4 q程l止q行时出现的情况

  1. q程中剩余的所有线E全部终止运行?
  2. 释放该进E引用的GDI和用户对象,内核对象被关闭(别的q程有引用则计数器减1Q如果没有引用则关闭内核对象Q?
  3. 推出代码从STILL_ACTIVEQ后面章节线E将介绍该结构)改ؓ传递给ExitProcess和TerminiateProcess代码?
  4. 内核对象状态变为收到通知状态(U程中介l)Q其他线E挂P知道q程l止?
  5. q程内核对象计数减去1Q或者关闭?/li>

注意Q?/p>

q程内核对象的寿命可能远q大于进E本w,父进E保留子q程内核对象可以查看它的推出代码调用下面函数Q?/p>

BOOL GetExitCodeProcess(HANDLE hProcess, PDWORD pdwExitCode);


可以调用q个函数来判断子q程是否关闭,如果子进E没有关?它的STILL_ACTIVE标识W定义ؓ0x103。但是这么作效率不是很高?/p>

 

4.4 子进E?/p>

没什么好说的Q前面的都说了,用CloseHandle关闭子进E和子进E中ȝE的句柄值来切断父进E和子进E的所有联pR?/p>

 

4.5 每局pȝ中运行的q程

利用ToolHelp函数族来开发管理操作系l上的进E。打自׃写个试试?/p>

 

本文章的内容是本人学习Windows核心~程W四章后的ȝQ有错误请大家纠正,转蝲注明出处:

http://www.cnblogs.com/xi52qian/



xi52qian 2011-03-04 16:45 发表评论
]]>C++ Primer W?0?ȝhttp://www.shnenglu.com/xi52qian/archive/2011/03/03/141023.htmlxi52qianxi52qianThu, 03 Mar 2011 00:37:00 GMThttp://www.shnenglu.com/xi52qian/archive/2011/03/03/141023.htmlhttp://www.shnenglu.com/xi52qian/comments/141023.htmlhttp://www.shnenglu.com/xi52qian/archive/2011/03/03/141023.html#Feedback0http://www.shnenglu.com/xi52qian/comments/commentRss/141023.htmlhttp://www.shnenglu.com/xi52qian/services/trackbacks/141023.html头文?<iostream>
一. 对终端的操作
相关头文?include <iostream>
1. 输入istream
2. 输出ostream
3. iostreaml承istream和ostream 所以它h输入输出功能?
Z方便q个库定义了下列三个标准对象:
1. cin  代表标准输入istreamcd象一般地cin使我们能够从用户l端d数据?
2. cout 代表标准输出ostreamcd象一般地cout使我们能够向用户l端写数据?
3. cerr 代表标准错误ostreamcd象一般地cerr是导出程序错误消息的地方?
另外,输出主要由重载的左移操作W?lt;< 来完成类似地输入主要由重载的右移操作W?gt;>来完成?
Demo1Q?

#include <iostream>
#include <string>
int main() {
    string in_string;
    // 向用L端写字符?/span>
    std::cout << "Please enter your name: ";
    // 把用戯入的d?in_string ?/span>
    std::cin >> in_string;
    if ( in_string.empty() )
    // 产生一个错误消息输出到用户l端
    std::cerr << "error: input string is empty!\n";
    else std::cout << "hello, " << in_string << "!\n";
}

? Ҏ(gu)件的操作
相关?include <fstream>
1. ifstream 从istream z把一个文件绑到程序上从文件读取数据用来输入?
2. ofstream 从ostream z把一个文件绑到程序上用来向文件写入数据?
3. fstream 从iostream z把一个文件绑到程序上用来输入和输出?
注:׃在fstream 头文件中也包含了iostream 头文件所以我们不需要同时包含这两个?
件C++对于文g的输入输Z支持同样的输入和输出操作W?
Demo2Q?

#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
    string ifile;
    cout << "Please enter file to sort: ";
    cin >> ifile;
    // 构造一?ifstream 输入文g对象
    ifstream infile( ifile.c_str() );
    if( ! infile ) {
        cerr << "error: unable to open input file: " << ifile << endl;
        return -1;
    }
    string ofile = ifile + ".sort";
    // 构造一?ofstream 输出文g对象
    ofstream outfile( ofile.c_str() );
    if( !outfile ) {
      cerr << "error: unable to open output file: " << ofile << endl;
      return -2;
    }
    string buffer;
    vector<string> text;
    int cnt = 1;
    while ( infile >> buffer ) {
        text.push_back( buffer );
        cout << buffer << ( cnt++ % 8 ? " " : "\n" );
    }
    sort( text.begin(), text.end() );
    // ok: 把排序后的词打印?outfile
    vector<string>::iterator iter = text.begin();
    for ( cnt = 1; iter != text.end(); ++iter, ++cnt )
        outfile << *iter << (cnt%8 ? " " : "\n" );
    return 0;
}

? 对字W流操作
相关的头文g#include <sstream>
1 istringstream 从istream z从一个字W串中读取数据?
2 ostringstream 从ostream z写入C个字W串中?
3 stringstream 从iostream z从字W串中读取或者写入到字符串中?
Demo3Q?

#include <sstream>
string program_name( "our_program" );
string version( "0.01" );
// ...
string mumble( int *array, int size )
{
    if ( ! array ) {
        ostringstream out_message;
        out_message << "error: "
        << program_name << "--" << version
        << ": " << __FILE__ << ": " << __LINE__
        <<" -- ptr is set to 0; "
        << " must address some array.\n";
        // q回底层 string 对象
        return out_message.str();
}

? wchar_t?
支持wchar_tcd的流d操作
wcin wcout wcerr wiostream {等....

20.1 输出操作W?lt;<
1. 支持所有的内置数据cd 包括string Qconst char* 和complex。以及函数的调用?
2. endl{h(hun)于输出换行操作符Q然后再h~存区。cout << '\n' << flush;
3. <<可以q接使用,因ؓoperator<<的返回值是ostream&?
4. cout << p << &i << endl;会输出指针的地址Qp是int *,i是intQ。如果是const char * pcStr不会输出指针地址|
输出的是字符丌Ӏ{换ؓcout << static_cast<void *>(const_cast<char *>(pcStr));
5. <<q算W的优先U高?:所以和?:使用时注意加括号?
6. ostream_iterator和cout的用?
Demo4Q?

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
string pooh_pals[] = {
"Tigger", "Piglet", "Eeyore", "Rabbit"
};
int main()
{
    vector<string> ppals( pooh_pals, pooh_pals+4 );
    vector<string>::iterator iter = ppals.begin();
    vector<string>::iterator iter_end = ppals.end();
    cout << "These are Pooh's pals: ";
    // 把每个元素拷贝到 cout ...
    ostream_iterator< string > output( cout, " " );
    copy( iter, iter_end, output );
    cout << endl;
}

7. cout << 遇到‘\0’会定制输出?

20.2 输入操作W?gt;>
1. while(cin >> 变量)的时候有两种情况会让循环停止QfalseQ:
(1) d文gl束在这U情况下我们已经正确地读完文件中所有的倹{?
(2) 遇到一个无效的值比?.14159数Ҏ(gu)非法?e-1字符文字e是非法的或者一般的L字符串文字在d一个无效值的
情况下istream对象被放|到一U错误的状态中q且对于值的所有读入动作都停止?
2. 预定义的输入操作W可以接受Q何的内置数据cd包括C 风格字符׃及标准库string和complex cȝ型?
3. ~省情况下输入操作符丢弃M中间I白I格制表W换行符走纸以及回R?
Demo5:

#include <iostream>
#include <string>
int main()
{
    int item_number;
    string item_name;
    double item_price;
    cout << "Please enter the item_number, item_name, and price: " << endl;
    cin >> item_number;
    cin >> item_name;
    cin >> item_price;
    cout << "The values entered are: item# "
        << item_number << " "
        << item_name << " @$"
        << item_price << endl;
}

4. 如果希望dI白W号可以利用cin.get()Ҏ(gu)一个个dQ或者设|skipws和noskipws选项Q后面介l)?
5. isream_iterator和cin兌使用?
Demo6:
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
int main()
{
    istream_iterator< string > in( cin ), eos ;
    vector< string > text ;
    // 从标准输入向 text 拯?/span>
    copy( in , eos , back_inserter( text ) ) ;
    sort( text.begin() , text.end() ) ;
    // 删除所有重复的?/span>
    vector< string >::iterator it ;
    it = unique( text.begin() , text.end() ) ;
    text.erase( it , text.end() ) ;
    // 昄l果 vector
    int line_cnt = 1 ;
    for ( vector< string >::iterator iter = text.begin();
    iter != text.end() ; ++iter , ++line_cnt )
    cout << *iter
        << ( line_cnt % 9 ? " " : "\n" ) ;
    cout << endl;
}

20.2.1 字符串输?
1. setw函数Q防止读入字W串益处Qchar[4],输入4个以上字节)Qwhile ( cin >> setw( bufSize ) >> buf )
q里bufSize是字W数lbuf的长度setw()把长度等于或大于bufSize 的字W串分成最大长度ؓbufSize - 1的两?
或多个字W串Q在每个C的末放一个空字符Z使用setw()要求E序包含iomanip头文?include <iomanip>?
2. 用string没有char *那些长度和内存溢出问题,更容易用?/p>

20.3 其他输入输出操作W?
一. istream的成员get()一ơ读入一个字节。属于istream
1. get(char& ch)从输入流中提取一个字W包括空白字Wƈ它存储在ch中它q回被应用的istream对象?
与之对应的是ostream的put()Ҏ(gu)Q每ơ读入一个字节,然后q回ostream?
2. get()的第二个版本也从输入读入一个字W区别是它返回该字符D不是被应用的istream 对象它的q回cd
是int 而不是char 因ؓ它也q回文g标志end-of-file该标志通常?1 来表CZ便与字符集区分开为测试返?
值是否ؓ文g我们将它与iostream 头文件中定义的常量EOF 做比较?
Demo7:

#include <iostream>
int main()
{
    int ch;
    // 或?
    // while (( ch = cin.get() ) && ch != EOF)
    while (( ch = cin.get()) != EOF)
    cout.put(ch);
    return 0;
}

3. get(char *sink, streamsize size, char delimiter='\n')
(1) sink 代表一个字W数l用来存放被d到的字符?
(2) size 代表可以从istream 中读入的字符的最大数目?
(3) delimiter 表示如果遇到它就l束d字符的动作delimiter 字符本n不会被读入而是留在istream 中作为istream ?
下一个字W一U常见的错误是在执行W二个get()之前忘了Ldelimiter?

? ignore( streamsize length = 1, int delim = traits::eof )函数: 属于istream
我们用istream 成员函数ignore()来去掉delimiter
~省情况下换行符被用作delimiter?/p>

? gcount()函数: 属于istream
它返回由最后的get()或getline()调用实际提取的字W数?
Demo8:

#include <iostream>
int main()
{
    const int max_line = 1024;
    char line[ max_line ];
    while ( cin.get( line, max_line ))
    {
        // 最大读取数?max_line - 1, 也可以ؓ null
        int get_count = cin.gcount();
        cout << "characters actually read: "
        << get_count << endl;
        // 处理每一?/span>
        // 如果遇到换行W?/span>
        // 在读下一行之前去掉它
        if ( get_count & max_line-1 )
            cin.ignore();
     }
}

? getline(char *sink, streamsize size, char delimiter='\n')属于istream

? write( const char *sink, streamsize length )属于ostream
提供了另外一U方法可以输出字W数l”它不是输出直到l止I字Wؓ止的所有字W“而是输出某个长度的字W序列包括内含的
I字W它的函数。length 指定要显C的字符个数write()q回当前被调用的ostream cd象?/p>

? read( char* addr, streamsize size )属于istream
read()从输入流中提取size 个连l的字节q将其放在地址从addr 开始的内存中gcount()q回由最后一个read()调用提取的字
节数而read()q回当前被调用的istream cd象?
Demo9:

#include <iostream>
int main()
{
    const lineSize = 1024;
    int lcnt = 0; // d多少?/span>
    int max = -1; // 最长行的长?/span>
    char inBuf[ lineSize ];
    // d 1024 个字W或者遇到换行符
    while (cin.getline( inBuf, lineSize ))
    {
         // 实际d多少字符
         int readin = cin.gcount();
         // l计: 行数最长行
         ++lcnt;
         if ( readin > max )
             max = readin;
         cout << "Line #" << lcnt
             << "\tChars read: " << readin << endl;
         cout.write( inBuf, readin).put('\n').put('\n');
     }
     cout << "Total lines read: " << lcnt << endl;
     cout << "Longest line read: " << max << endl;
}

? getline( istream &is, string str, char delimiter );                         
q个getline()实例的行为如下读入最大数目ؓstr::max_size-1 个字W如果输入序列超个限制则L作失?
q且istream 对象被设|ؓ错误状态否则当ddelimiter 它被从istream 中丢弃但没有被插入到string 中或?
到文件结束符时输入结束?/p>

? putback( char c ); 字W放?iostream?/p>

? unget();往回重|下一?istream V?/p>

? peek(); q回下一个字W或 EOFQ但不要提取出来?
Demo10:

char ch, next, lookahead;
while ( cin.get( ch ))
{
    switch (ch) {
    case '/':
     // 是注释行? ?peek() 看一?
     // 是的? ignore() 余下的行
     next = cin.peek();
     if ( next == '/' )
         cin.ignore( lineSize, '\n' );
     break;
     case '>':
     // 查找 >>=
     next = cin.peek();
     if ( next == '>' ) {
         lookahead = cin.get();
         next = cin.peek();
     if ( next != '=' )
     cin.putback( lookahead );
}

20.4 重蝲输出操作W?lt;<
输出操作W是一个双目操作符它返回一个ostream 引用重蝲定义的通用框架如下
// 重蝲 output 操作W的通用框架
ostream&
operator <<( ostream& os, const ClassType &object )
{
// 准备对象的特定逻辑
// 成员的实际输?
os << // ...
// q回 ostream 对象
return os;
}
注:因ؓW一个实参是一个ostream 引用所以输出操作符必须定义为非成员函数Q当输出操作W要求访问非公有成员
时必d它声明ؓ该类的友元?/p>

20.5 重蝲输入操作W?gt;>
1 ׃不正的格式而导致失败istream 应该把状态标Cؓfail。setstate( ios_base::failbit )?
2 对于错误状态中的iostream 插入和提取操作没有媄响?
Demo11:

#include <iostream>
#include "WordCount.h"
/* 必须修改 WordCount, 指定输入操作Wؓ友元
class WordCount {
    friend ostream& operator<<( ostream&, const WordCount& );
    friend istream& operator>>( istream&, WordCount& );
*/
istream&
operator>>( istream &is, WordCount &wd )
{
/* WordCount 对象被读入的格式:
 * <2> string
 * <7,3> <12,36>
 */
int ch;
/* d于W号, 如果不存?
 * 则设|?istream 为失败状态ƈ退?
 */
if ((ch = is.get()) != '<' )
{
    is.setstate( ios_base::failbit );
    return is;
}
 // d多少?/span>
 int occurs;
 is >> occurs;
 // ?>; 不检查错?/span>
 while ( is && (ch = is.get()) != '>' );
 is >> wd._word;
 // d位置
 // 每个位置的格? < line, col >
 for ( int ix = 0; ix < occurs; ++ix )
 {
  int line, col;
  // 提取?/span>
  while (is && (ch = is.get())!= '<' );
  is >> line;
  while (is && (ch = is.get())!= ',' );
  is >> col;
  while (is && (ch = is.get())!= '>' );
  wd.occurList.push_back( Location( line, col ));
 }
 return is;
}

20.6 文g输入和输?
包含头文?include <fstream>
1. ofstream的构造函数要制定打开模式
输出模式ios_base::out 或附加模式ios_base::app {等。在~省情况下ostream文g以输出模式打开?
注:如果在输出模式下打开已经存在的文件则所有存储在该文件中的数据都被丢弃如果我们希望增加而不是替换现
有文件中的数据则应该以附加模式打开文g于是新写到文件中的数据将d到文件尾部在q两U模式下如果文g不存
在程序都会创Z个新文g?
2. 判断是否打开if (!outFile /*ofstream对象*/)
3. 因ؓofstreamz于ostreamQ所以ofstream拥有ostream的操作,比如put(){等?
4. 自定?lt;<操作输入到ofstream中?
5. 用ifstreamd一个文Ӟz于istreamQ所有拥有istream的操作,比如get(){等?
6. close()函数断开和文件的兌?
7. fstreamz于iostreamQ它hҎ(gu)件的d操作?
8. seekg和seekp标记当前位置Qg是在L件中使用Qp再写文g中用?
注:W二个参数标C定位标?
(1) ios_base::beg 文g的开?
(2) ios_base::cur 文g的当前位|?
(3) ios_base::end 文g的结?
9. tellg()或tellp()q回当前位置Qg和p意义同seekg和seekp。返回值是ios_base::pos_type?
10. clear()函数:清除状态?/p>

20.7 条g状?
一. 条g状?
1 如果一个流遇到文gl束W则eof()q回true?
2 如果试图做一个无效的操作比如seeking 重定位操作超Z文gֈbad()q回trueQ一般地q表C由于某U?
未定义的方式而被破坏了?
3 如果操作不成功比如打开一个文件流对象p|或遇CU无效的输入格式则fail()
q回true 例如
ifstream iFile( filename, ios_base::in );
if ( iFile.fail() ) // 不能打开
error_message( ... );
4 如果其他条g都不为true 则good()q回true

? 改变状?
1. clear()函数Q状态变为显C?
2. setstate()函数Q添加状态。参数设|ؓQ?
ios_base::badbit
ios_base::eofbit
ios_base::failbit
ios_base::goodbit
3. rdstate()获取成员状态,q回值ios_base::iostate?/p>

20.8 string ?
1. 包括头文?include <sstream>
2. str()q回与ostringstream cd象相兌的string 对象?/p>

20.9 格式状?
??W?nbsp;                   ??
boolalpha               把true 和false 表示为字W串
*noboolalpha            把true 和false 表示? 1
showbase                产生前缀指示数值的q制基数
*noshowbase             不生进制基数前~
showpoint               L昄数?
*noshowpoint            只有当小数部分存在时才显C小数点
Showpos                 在非负数g昄+
*noshowpos              在非负数g不显C?
*skipws                 输入操作W蟩q空白字W?
noskipws                输入操作W不跌I白字符
uppercase               在十六进制下昄0X U学计数法中昄E
*nouppercase            在十六进制下昄0x U学计数法中昄e
*dec                    以十q制昄
hex                     以十六进制显C?
oct                     以八q制昄
left                    填充字W加到数值的双
right                   填充字W加到数值的左边
Internal                填充字W加到符号和数值的中间
*fixed                  以小数Ş式显CQҎ(gu)
scientific              以科学计数法形式昄点?
flush                   hostream ~冲?
ends                    插入I字W然后刷新ostream ~冲?
endl                    插入换行W然后刷新ostream ~冲?
ws                      吃掉 I白字符
// 以下q些要求 #include <iomanip>
setfill(ch)            用ch 填充I白字符
setprecision(n)        Q点精度设|ؓn
setw(w)                按照w 个字W来L者写数?
setbase(b)             以进制基数b 输出整数?
?表示~省的流状?/p>

20.10 强类型库
iostream库是强类型的例如试图从一个ostream L据或者写数据C个istream都会在编译时刻被捕获到ƈ标记为类型违例?/p>

xi52qian 2011-03-03 08:37 发表评论
]]>
Windows核心~程 W??内核对象http://www.shnenglu.com/xi52qian/archive/2011/03/03/141022.htmlxi52qianxi52qianThu, 03 Mar 2011 00:35:00 GMThttp://www.shnenglu.com/xi52qian/archive/2011/03/03/141022.htmlhttp://www.shnenglu.com/xi52qian/comments/141022.htmlhttp://www.shnenglu.com/xi52qian/archive/2011/03/03/141022.html#Feedback1http://www.shnenglu.com/xi52qian/comments/commentRss/141022.htmlhttp://www.shnenglu.com/xi52qian/services/trackbacks/141022.html3.1 什么是内核对象

内核对象是内核中的一块内存,是一个结构,q且只能由内核对象访问,应用E序只能通过调用Windows提供的函数来操作内核对象。每个内核对象都有相同的部分比如安全属性和使用计数器?/p>

3.1.1 内核对象的用计?/p>

内核对象中的使用计数和进E无养I当进E第一ơ创建某个内核对象时候用计数变?Q当另一个进E也调用此内核对象时计数变ؓ2。当q程释放时或者关闭内核对象时QCloseHandleQ,内核的用计数减?Q如果用计C?的话Q内怸会释放此内核对象?/p>

3.2.2 安全?/p>

内核对象能够得到安全描述W的保护Q安全描q符定义了谁能够创徏Q访问和使用该对象,一般在服务器代码中使用Q客L可以忽略?/p>

所有创建内核对象的函数的参数都有一个指向SECURITY_ATTRIBUTESl构的指针?/p>

typedef struct _SECURITY_ATTRIBUTES {
    DWORD nLength;
    LPVOID lpSecurityDescriptor;
    BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
只有lpSecurityDescriptor成员和安全属性有兟뀂一般此参数传递NULLQ表C默认的安全描述?/font>
如果需要:
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = FALSE;
HANDLE h = CreateMutex(&sa, FALSE, "XI");
其余q程可用用OpenMutex函数打开Q如果权限可以就q回句柄Q如果失败返回NULLQGetLastError被设|ؓERROR_ACCESS_DENIED?/div>
Windows除了内核对象之外q有GDI和用户对象,区分它们的简单办法就是,创徏函数中带有安全描q符参数的就是内核对象?/div>
 
3.2 q程的内核对象句柄表

索引                         内核对象内存块得指针                             讉K屏蔽Q标志位的DWORDQ?nbsp;                     标志Q标志位的DWORDQ?/p>


1                               0x????????                                                0x????????                                                        0x????????
2                               0x????????                                                0x????????                                                        0x????????
?nbsp;                              ?nbsp;                                                              ?nbsp;                                                                      ?/div>
3.2.1 创徏内核对象

调用Create&函数族来创徏相应的内核对象,q回的是内核对象的句柄(也有个说法就是句柄表的烦引),如果创徏p|一般会q回0QNULLQ,也有的会q回INVALID_HANDLE_VALUE=-1Q比如CreateFilep|后会q回后者,p|的原因有可能是内存不x者是安全问题{等。其他对内核操作的函数都需要此句柄g为参C递进去,如果传递一个无效的句柄q去Q那么GetLastError函数的值将被置?QERROR_INVALID_HANDLEQ?/p>

3.2.2 关闭内核对象

BOOL CloseHandle(HANDLE hobj);

调用此函敎ͼpȝ会了清理q程的句柄表中的对应目Q如果用计数器?Q内栔R放该内核对象的资源,如果使用计数器不?Q说明其他进E还在用此内核对象Q则不释放资源?/p>

当进E忘记调用CloseHandle函数Q可能造成内存泄露Q但是当q程l束的时候资源一样会被释放?/p>

如果传递的参数无效Q则函数q回FALSEQƈ且GetLastError函数的D讄成ERROR_INVALID_HANDLE。如果是DEBUG阶段Q则q回错误信息?/p>

 
3.3 跨越q程边界׃n内核对象
3.3.1 对象句柄的承?/div>
  1. 在父q程创徏子进E的时候,参数SECURITY_ATTRIBUTESl构的Inherithandle字段讄为TRUE的话Q再父进E句柄表中标C内核对象的项的标志位的值将会变成TRUEQ标C内核对象是可以让子进E承的Q具有可l承性(仅仅标示 该句柄值具有可l承性,而内核对象没有可l承性)?
  2. CreateProcess的参数bInherithandle参数的D|ؓTRUEQ标C创建的q程可以l承有承性的父进E句柄?
  3. 子进E创建后不会先加载程序,它先搜烦父进E的句柄表将有承性的目原封不动的拷贝给自己Q烦引也没有变,所以句柄g不变Q?
  4. 父进E可以有3U方式将句柄g递给子进E,参数传递,q程间通信和环境变量(GetEnvironmentVariavle函数解析Q?
BOOL
WINAPI
CreateProcess(
    __in_opt    LPCSTR lpApplicationName,
    __inout_opt LPSTR lpCommandLine,
    __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    __in        BOOL bInheritHandles,
    __in        DWORD dwCreationFlags,
    __in_opt    LPVOID lpEnvironment,
    __in_opt    LPCSTR lpCurrentDirectory,
    __in        LPSTARTUPINFOA lpStartupInfo,
    __out       LPPROCESS_INFORMATION lpProcessInformation
    );
注意Q?/font>
子进E再创徏其子q程Q如果满上面方式,可以l箋l承?/font>
如果父进E再创徏子进E后Q再创徏句柄Q子q程不会被ѝ?/font>
3.3.2 改变句柄标志
BOOL SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags);
改变句柄的标志,目前可改变的标志有两U?/div>
#define HANDLE_FLAG_INHERIT   0x00000001  // l承标志
#define HANDLE_FLAG_PROJECT_FROM_CLOSE   0x00000001 // 保护不允许关闭句柄标?/div>
可以用OR操作同时讄2个标志。第一个参数是要设|的句柄|W二个就是要改变的标志,W三个参数是标志改~成什么倹{?/div>
BOOL GetHandleInformation(HANDLE hObkect, PDWORD pdwFlags);
获取当前句柄的标志的倹{?/div>
// 讄句柄值可l承Q?/span>
SetHandleInformation(hObject, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
// 讄句柄不可l承Q?/span>
SetHandleInformation(hObject, HANDLE_FLAG_INHERIT, 0);
// 讄句柄g可关闭,受保护:
SetHandleInformation(hObject, HANDLE_FLAG_PROJECT_FROM_CLOSE, HANDLE_FLAG_PROJECT_FROM_CLOSE);
// 讄句柄值可关闭Q不受保护:
SetHandleInformation(hObject, HANDLE_FLAG_PROJECT_FROM_CLOSE, 0);
3.3.3 命名对象
创徏内核对象函数族Create&中的最后一个参数是pszNameQ该参数是如果传递NULLQ表C是匿名内核对象Q可以通过其他俩种方式来用其他进E的内核对象。当pszName参数传递以’\0’(最多长度ؓMAX_PATH 260字符Q结字符串时Q表C启用命名对象,比如q程A调用CreateMutex(NULL, FALSE, “XI?的时候,他将创徏内核对象名字为“XI”,之后某一时刻如果q程B也调用CreateMutex(NULL, FALSE, “XI?函数他将l过以下几步Q?/div>
  1. 判断内核对象名称是否相同?
  2. 判断内核对象cd是否相同Q如果名字相同但是类型不相同则Create&函数族返回NULLQGetLastError函数gؓ6QERROR_INVALID_HANDLEQ?
  3. 判断安全性,q回?步,GetLastError值同2步?
  4. 如果验证通过则返回句柄(q回句柄的值和该内核对象其他句柄的g一定相同)QGetLastError的值等于ERROR_ALREADY_EXISTS?

也可以用Open&函数族来打开已经创徏的句柄,成功后GetLastError也不会被讄。具体如?/p>

HANDLE Open&(DWORD, BOOL, PCSTR);

W一个参敎ͼ表示讉K权限?/p>

W二个参敎ͼ表示新创建的句柄是否有承性(注意不是内核对象Q)?/p>

W三个参敎ͼ不能传递NULL。如果该句柄不存在则q回NULLQGetLastError被设|ؓ2QERROR_FILE_NOT_FOUNDQ?/p>

3.3.4 l端服务器的名字I间

GlobadQLocalQSessionE序保留关键字,具体的没弄明白,理解的就是说当服务器的时候,客户端可以访问以q些名字开头的内核对象?/p>

3.3.5 复制对象句柄

BOOL DuplicateHandle(
HANDLE hSourceProcessHandle,
HANDLE hSourceHandle,
HANDLE TargetProcessHandle,
PHANDLE phTargetHandle,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwOptions);

执行DuplicateHandle函数的进EؓProcessCQ原q程为ProcessSQ目标进EؓProcessT。则hSourceProcessHandleEProcessS的进E句柄,TargetProcessHandleEProcessT的进E句柄,ProcessC句柄hSourceHandle从ProcessC拯到ProcessT中,值存在phTargetHandle中,dwDesiredAccess新句柄的反问权限QbInheritHandle新句柄的l承性,参数dwOptions有两U类型分别是Q?/p>

DUPLICATE_SAME_ACCESS忽略参数dwDesiredAccessQ新句柄和原q程句柄h相同的反问权限?/p>

DUPLICATE_CLOSE_SOURCE关闭ProcessS中的拯句柄Q内核对象的计数不变?/p>

HANDLE hObjProcessS = CreateMutex(NULL, FALSE, NULL);
HANDLE hProcessT = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessIdT);
HANDLE hObjProcessT;
DuplicateHandle(GetCurrentProcess(), hObjProcessS, hProcessT , &hObjProcessT, 0, FALSE, DUPLICATE_SAME_ACCESS);
CloseHandle(hObjProcessS);
CloseHandle(hProcessT);
注意Q?
一般DuplicateHandle函数没有在三个进E中使用Q因为很隄道原q程的句柄倹{?
要用IPC机制通知目标q程Q新句柄已经拯q去?


xi52qian 2011-03-03 08:35 发表评论
]]> 2021Ʒҹþ| ձƷþþþĻ8| 66ƷۺϾþþþþþ| 99ƷȾþ| þ99Ʒþ| Ʒgzþþ| ˾þ뾫ƷĻ| þ¶ݺɫ| þþƷAV͵| ݺɫþۺ| Ʒþþ| þۺϾƷһ| ޾Ʒþþþþ | þþƷ| þۺϾƷþ| þþƵ| Ļþһ| Ʒþþþþ֣ݹ˾| Ʒþþþþþþþ| һAvëƬþþƷ| þw5www| ɫۺϺϾþۿ| þۺϹapp| Ʒ99þþþ| ݺɫþۺ| þþƷֻо99Ʒ| þer99ȾƷһ| һɫþۺ| 91Ʒպþò | ͵͵þþþվ| 99þ˾ƷۺϹۿ| þ޾ƷAVӣ| ŷþ޾Ʒ| þùƷƷ| ƷþëƬ| þ޹˾Ʒɫ| ˾þþƷӰԺ| 99ƷѾþþþþ| þܳ| ŷһþþƷ| ձƷһþþ|