Window核心编程
Window核心编程
第一章:错误处理
FormatMessage/LocalLock\LocalFree
第二章:
TEXT("..") TCHAR(CHAR,WCHAR)
安全字符串函数 (必须在包含其他所有文件之后才包含StrSafe.h)
_tcscpy _tcscpy_s
_CrtSetReportMode(_CRT_ASSERT,0); //禁止可能由C运行时触发的所有Debug Assertion Failed对话框。
TCHAR szBuffer[10] = {....}
_tcscpy_s(szBuffer,_countof(szBuffer),TEXT("0123456789")); //最终的字符串被截断为一个空字符串。
StringCchCat(EX)\StringCchCopy(EX)\StringCbCat(EX)\StringCbCopy(EX)
Cch Count of Characters Cb 字节
最理想比较函数 CompareString(Ex) \CompareStringOrdinal
CompareStringW(
__in LCID Locale,
__in DWORD dwCmpFlags,
__in_ecount(cchCount1) PCNZWCH lpString1,
__in int cchCount1,
__in_ecount(cchCount2) PCNZWCH lpString2,
__in int cchCount2);
LCID GetThreadLocale(void)
为了比较程序内部所用的字符串,应该使用CompareStringOrdinal(只支持unicode)
CompareStringOrdinal(
__in LPCWSTR lpString1,
__in int cchCount1,
__in LPCWSTR lpString2,
__in int cchCount2,
__in BOOL bIgnoreCase
);//码位比较,不考虑区域设置,速度相对快。
TCHAR/PTSTR/BYTE/PBYTE/TEXT/_T/_countof而不用sizeof, malloc(nCharacters * sizeof(TCHAR))
MultiByteToWideChar / WideCharToMultiByte
IsTextUnicode //可能有错
第三章:内核对象
由于内核对象的数据结构只能由OS内核访问,所以应用程序不能在内存中定位这些数据结构并直接更改内容。
内核对象是和进程相关的,另一进程调用该进程下的内核对象就可能失败
使用计数是所有内核对象类型都有的一个数据成员。
几乎所有创建内核对象的函数都有一个PSECURITY_ATTRIBUTES参数,相反创建用户对象或GDI对象的函数都没有PSECURITY_ATTRIBUTES参数
由于句柄值实际是作为进程句柄表的索引来使用的,所以句柄是与当前这个进程相关的。
内核对象都要调用CloseHandle向系统表明结束使用内核对象,还应同时设这个变量为NULL
跨进程边界共享内核对象:
a.利用文件映射对象 //同台机器不同进程共享数据块
b.借助邮件槽和命名管道 //网络上不同机器不同进程相互发送数据块
c.互斥量,信号量和事件 //允许不同进程中的线程同步执行 通知
三种机制来允许进程共享内核对象:
a.使用对象句柄继承,b.为对象命名,c.复制对象句柄。
a.使用对象句柄继承:对象够本的继承只会在生成子进程的时候发生,假如父进程后来又创建了新的内核对象,并同时将它们的句柄设为可继承的句柄。
那么正在运行的子进程是不会继承这些新句柄的。
改变句柄标志 SetHandleInformation
b.为对象命名:并不是所有内核对象都可以进行命名 //防止重名,可用GUID或命名空间
CreateMutex\CreateEvent\CreateSemaphore\....创建有名的内核对象
进程A: HANDLE hMutexProcessA = CreateMutex(NULL,FALSE,TEXT("JeffMutex");
1-->进程B: HANDLE hMutexProcessB = CreateMutex(NULL,FALSE,TEXT("JeffMutex"); if(GetLastError() == ERROR_ALREADY_EXISTS)
2-->进程B: HANDLE hMutexProcessB = OpenMutex(.....); if(GetLastError() == ERROR_ALREADY_EXISTS)
终端服务命名空间
一个服务的命名内核对象始终位于全局命名空间内的。默认情况下,在终端服务中,在终端服务中,应用程序自己的命名内核对象在会话的命名空间内。
HANDLE h = CreateEvent(NULL,FALSE,FALSE,TEXT("Global\\MyName"));
HANDLE h = CreateEvent(NULL,FALSE,FALSE,TEXT("Local\\MyName"));
专有命名空间 ????????
第四章:进程
GUI Int WINAPI _tWinMain(HINSTANCE ....)
CUI int _tmain(int argc,TCHAR *argv[],TCHAR *envp[])
OS的加载程序(loader)会检查可执行文件的文件头,并获取链接时链接器开关/SUBSYSTEM:CONSOLE \ /SUBSYSTEM:WINDOWS的值,如是CUI,加载程序会自动确保有一个可用的文本控制
台窗口(如命令提示符启动),如有必要也会创建一个窗口。如果是GUI,则只负责加载。
WinMainCRTStartup\wWinMainCRTStartup --> _tWinMain
mainCRTStartup\wmainCRTStartup --> _tmain
c/c++运行库启动函数
1)---> 1.获得命令行指针;2.获得环境指针;3.初始化c\c++运行库全局变量;4.初始化C运行库malloc\calloc\IO例程使用的堆;5.调用所有全局和静态C++类对象的构造函数。
2)---> 1.GetStartupInfo(&StartupInfo);
2.int nMainRetVal = _tWinMain((HINSTANCE)&__ImageBase,NULL,pszCommandLineAnsi,(StartupInfo.dwFlags & STARTF_USESHOWWINDOW)?,StartupInfo.wShowWindow:SW_SHOWDEFAULT);
3)--->入口点函数返回后,启动函数将调用C运行库函数exit,向其传递返回值(nMainRetVal).
exit执行:1.调用_onexit函数;2.调用全局、静态C++类对象的析构函数;3.如DEBUG中需要则生成内在泄漏报告;4.调用OS的ExitProcess(nMainRetVal).
进程实例句柄
WinMain中的hInstance实际值是一个内存基地址;系统将可执行文件 的映像加载到进程地址空间中的这个位置,这个由链接器决定。
如果想知道一个可执行文件或DLL文件被加载进程地址空间什么位置,可用:HMODULE GetModuleHandle(PCTSTR pszModule); pszModule 为NULL时返回主调进程的可执行文件基地址。
在一个DLL中可用伪变量__ImageBase(extern "C" const IMAGE_DOS_HEADER _ImageBase;) 或 GetModuleHandleEx可返回DLL的基地址
调用GetModuleHandle(NULL)的代码是在一个DLL文件中,返回值仍是可执行文件的基地址,而非DLL文件的基地址。
第二个hPrevInstance方便移植16bit window
#define UNREFERENCED_PARAMETER(P) (P) 消息声明未引用告警
GetCommandLine() GetEnvironmentStrings
WM_SETTINGCHANGE //促使应用程序立即更新它们的环境块
VerifyVersionInfo 判断主机系统是否符合应用程序要求
进程内核对象不是进程本身,而是OS用来管理这个进程的一个小型数据结构。系统为新进程的主线程创建一个线程内核对象。
默认情况下,所有16位windows应用程序都在一个共享的VDM(virtual DOS machine)中执行。
IsWow64Process(__in HANDLE hProcess, __out PBOOL Wow64Process)
GetCurrentProcessId\GetCurrentThreadId\GetProcessId\GetThreadId\GetProcessIdOfThread(指定线程所在进程)
如果在入口点函数中调用的是ExitThread,而不是ExitProcess或者入口点函数直接返回,应用程序的主线程将停止执行,但只要进程中还有其他线程正在运行,进程就不会终止。
//断绝父子进程关系
BOOL fSuccess = CreatePorcess(...,&pi);
if(fSuccess){
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
手动提升进程的权限ShellExecuteEx
IsUserAnAdmin\\Tests whether the current user is a member of the Administrator's group.
第五章 作业
作业对象可以想象成一个进程窗口,“沙箱“
BOOL WINAPI IsProcessInJob(
__in HANDLE ProcessHandle,
__in_opt HANDLE JobHandle,
__out PBOOL Result ); //如果进程已与一个作业关联,就无法将当前进程或者它的任何子进程从作业中去除,这个安全特性确保进程无法摆脱作业对它的限制
默认情况下,Windows资源管理器启动一个应用程序都会放到名为PCA...专用作业中,(program Compatibility Assistant) 这纯粹解决兼容问题
调试器如关联了这个作业,调试对象自动关联这个作业,可以命令行启动调试器,这个就不会关联这个作业
CreateJobObject\SetInformationJobObject\AssignProcessToJobObject\CloseHandle
UserHandleGrantAccess 授权作业内进程对作业外用户对象的访问
TerminateJobObject ”杀死“作业内部的所有进程,类似每个进程调用TerminateProcess
第六章 线程基础
进程:一个进程内核对象+一个地址空间
线程:一个线程内核对象+一个线程栈
每个线程都有其CPU寄存器,称为线程的上下文(context)
CONTEXT结构本身保存在纯种内核对象中。
创建初始化线程 IP->RtlUserThreadStart
VOID RtlUserThreadStart(PTHREAD_START_ROUTINE pfnStartAddr,PVOID PVParam){
__try{
ExitThread((pfnStartAddr(pvParam));
}
__except(UnhandleExceptionFilter(GetExceptionInformation())){
ExitProcess(GetExceptionCode());
}
//NOTE: we never get here
}
当模块链接到CRT的DLL时,这个库会在线程终止时收到DLL_THREAD_DETACH通知,并会释放_tiddata块,但仍然强烈建议用_beginthreadex
HANDLE GetCurrentProcess()
HANDLE GetCurrentThread()
这两函数返回的是伪句柄,不会在相应的句柄表中新建句柄,不会影响使用计数,如果调用CloseHande,并传入伪句柄,CloseHandle只是简单地忽略些调用。
线程的伪句柄是一个指向当前线程的句柄
DuplicateHandle 可以转换伪句柄成真正的句柄,现此函数之后要调用CloseHandle递减下使用计数。
第七章:线程调度、优先级和关联性
ResumeThread\SuspendThread
SuspendThread调用须小心,如果此线程正在分配堆中内存,线程将锁定堆,其他线程将不能访问堆。
WaitForDebugEvent //挂起进程内所有线程 ContinueDebugEvent
也可通过CreateToolhelp32Snapshot函数去遍历所有线程并挂起。
Sleep(0) //主调线程放弃了时间片的剩余部分,它强制系统调度其他线程。但可能调度自己。
SwitchToThread 与 Sleep(0) 不同的是它允许执行低优先级线程。
GetThreadTime\GetProcessTime
SuspendThread->GetThreadContext //查看线程的内核对象的内部,一个线程实际上有两个上下文:用户模式,内核模式
SetThreadcontext 改变EIP值可以终止相应进程。
线程优先级0-31 0优先级的页面清零线程。线程优先级是相对进程优先级的
SetProcessPriorityBoost\SetThreadPriorityBoost 允许/禁止动态提升优先级
第八章:用户模式下的线程同步
原子访问、调整缓存行、高级线程同步、关键段、Slim读/写锁、条件变量
点【关闭】
DefWindowProc 检测鼠标向窗口发送WM_SYSCOMMAND
DefWindowProc响应WM_SYSCOMMAND便发送WM_CLOSE
DefWindowProc调用destroywindow响应WM_CLOSE
destroywindow便发送WM_DESTYOY
DefWindowProc调用Postquitmessage响应WM_DESTYOY
Postquitmessage便发送WM_QUIT
WM_PAINT消息触发事件:
1.用户移动一个窗口,导致原来被遮盖的部分窗口暴露出来;
2.用户调整窗口的大小;(CS_HREDRAW | CS_VERDRAW )
3.ScrollWindow || ScrollDC || InvalidateRect || InvalidateRgn
BeginPaint & EndPaint 成对使用
GetDC & ReleaseDC 成对使用,但相比上面的,不会使区域有效,需要手动调用validateRect(hwnd,NULL)
GetWindowDC 用于整个窗口,比GetDC 多包含非客户区
CreateDC & DeleteDC CreateDC(TEXT"DISPLAY"),NULL,NULL,NULL) 返回当前整个屏幕的设备环境句柄 GetDC使用NULL参数也可获得当前整个屏幕的设备环境句柄
TEXTMETRICS tm;
hdc = GetDC(hwnd);
GetTextMetrics(hdc,&tm);
ReleaseDC(hdc);
立刻更新无效区域:可以在调用InvalidateRect后调用UpdateWindow.
图形输出设备分为两大类:光栅设备(raster device) 和 矢量设备(vector device)
光栅:以点来绘图 矢量:以线条绘图
CreateIC 函数获取一个“信息上下文” CreateCompatibleDC \ CreateMetaFile & CloseMetaFile 图元文件
注册窗口类时style有CS_OWNDC时,相应窗口会有私有的DC,则只需要初始化一次,否则每次使用得初始化;
这个CS_OWNDC只影响GetDC & BeginPaint , 其他函数不受影响。
idSaved = SaveDC(hdc);
RestoreDC(hdc,idSaved);
RestoreDC(hdc,-1); //恢复到最近一次由SaveDC函数保存的状态。
SetPixel(hdc,x,y,crColor); //设备坐标像素点特定颜色 多次调用性能低。
crColor = GetPixel(hdc,x,y);
一个程序可以创建6种GDI对象:画笔,画刷,位图,区域,字体和调色板,除调色板外,其余用SelectObject函数选入设备环境。
填充空隙的颜色是由设备环境的两个属性(背景模式和背影颜色)决定
SetBkColor(hdc,crColor);
SetBkMode(hdc,TRANSPARENT);
如果使用带“DISPLAY"参数的CreateDC函数获得整个屏幕的设备环境,那逻辑坐标值将默认映射屏幕坐标
客户区坐标,屏幕坐标 ClientToScreen & ScreenToClient
映射模式被定义为从”窗口“(window)(逻辑坐标)到”视口“(viewport)(设备坐标)的映射
窗口:描述一个程序战胜屏幕的区域
视口:含有”剪切区域“之意。
FillRect & FrameRet & InvertRect(翻转所有像素1->0,0->1)
OffsetRect\InflateRect\SetRectEmpty\CopyRect\IntersectRect\UnionRect\IsRectEmpty\PtInRect
PeekMessage 空闲时处理,一旦有消息加载到程序的消息队列中就释放控制。
GetMessage函数并不把控制权交还给程序,除非获得消息。
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
替换后:\\overlay optimize
while(TRUE)
{
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
if(msg.messgae == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
else
{
do some other work;
}
}
return msg.wParam;
CreateRectRgn\CreateRectRgnIndirect\CreateEllipticRgn\createEllipticRgnIndirect\CreatePolygonRgn\CombinRgn
InvalidteRect\ValidateRgn
具有输入焦点的窗口要么是活动,要么是活动窗口的子孙窗口。
活动窗口总是最上层的窗口。
窗口过程通过捕获WM_SETFOCUS\WM_KILLFOCUS消息来确定自己的窗口是否具有输入焦点。\\overlay optimize
键盘和鼠标消息最初放入到单独的消息队列(系统消息队列),仅当windows应用程序完成了对前一个用户输入消息的处理后,
Window才从系统消息队列中取出下一条消息,并把它放入应用程序消息队列中。
键盘事件的消息可分为击键和字符。
系统键击和非系统键击,SYS类表明该击键对Windows比对Windows应用程序更加重要。当输入键和Alt键组合时通常产生的是系统键击
WM_KEYDOWN\WM_KEYUP\WM_SYSKEYDOWN\WM_SYSKEYUP \\optimize overlay window is foreground window. GetFocus
TranslateMessage函数负责把击键消息转换为字符消息。
字符消息分四类
字符 死字符
非系统字符 WM_CHAR WM_DEADCHAR //这两来自WM_KEYDOWN
系统字符 WM_SYSCHAR WM_SYSDEADCHAR //这两来自WM_SYSKEYDOWN
WM_CHAR wParam参数是ANSI或Unicode字符码
IsWindowUnicode(hwnd)
如果需要读取输入到窗口中的键盘字符,就处理WM_CHAR消息;如果需要读取光标,功能键,Delete键,Insert键,Shift,Ctrl,Alt键,则处理WM_KEYDOWN消息。
WM_INPUTLANGCHANGE 切换输入时系统派发此消息到窗口过程
GetFocus() This function retrieves the handle to the keyboard focus window associated with the thread that called the function.
WM_SETFOCUS\WM_KILLFOCUS
CreateCaret\SetCaretPos\ShowCaret\HideCaret\DestroyCaret
第七章:鼠标
GetSystemMetrics(SM_MOUSEPRESENT) \\判断是否连接鼠标
GetSystemMetrics(SM_CMOUSEBUTTONS) \\获得鼠标按钮个数
窗口类style = CS_DBLCLKS,则窗口过程能接收鼠标双击消息。
WM_NCHITTEST "非客户区击中测试”
case WM_NCHITTEST:
return (LRESULT) HTNOWHERE; //可以阻止系统向窗口发送所有客户区和非客户区鼠标消息。
Windows会利用WM_NCHITTEST消息来产生所有其他和氥位置相关的鼠标消息。
ShowCursor \ GetCursorPos \ SetCursorPos
idChild = GetWindowLong(hwnd,GWL_ID) \ GetKlgCtrlID(hwnd)
hwndChild = GetDlgItem(hwndParent,idChild);
SetCapture \ ReleaseCapture \ SetROP2
鼠标滚轮的滚动使Windows产生WM_MOUSEWHEEL消息,并发送给具有输入焦点的窗口。
第八章:计时器
WM_TIMER\WM_PAINT都是低优先级的,只有当消息队列中没有其他消息时,程序才会收到它们。
Windows把在消息队列时的多个WM_TIMER\WM_PAINT消息结合成一条消息。
WM_TIMER中wParam为计时器ID
MessageBeep函数产生一个响铃声
GetLocalTime
第九章:子窗口控件
子窗口控件向父窗口WM_COMMAND消息
LOWORD(wParam) 子窗口ID
HIWORD(wParam) 通知码
LParam 子窗口句柄
按钮通知码有:BN_CLICKED\BN_PAINT\BN_SETFOCUS\BN_KILLFOCUS\.....
通知码需要在按钮style里相应设置才会发送,如设置BS_NOTIFY,通知码BN_SETFOCUS\BN_KILLFOCUS才会发送。
8个按钮消息,以BM_开头
SetWindowText \ GetWindowText
ShowWindow \IsWindowVisible \ EnableWindow \ IsWindowEnable
WM_SYSCOLRCHANGE
BS_OWNERDRAW STYLE允许自绘按钮 在需要重绘按钮时,它会向其父窗口发送WM_DRAWITEM消息。DrawFocusRect画选中按钮时的虚框。
滚动条类 窗口滚动条和滚动条控件 //滚动条控件不同按钮控件发送WM_COMMAND,而是和窗口滚动条一样发送WM_VSCROLL & WM_HSCROLL
WM_VSCROLL & WM_HSCROLL 参数lParam 为0则为窗口滚动条,否则为滚动条控件句柄。
Window核心编程相关推荐
- 将VC++6.0的代码迁移到VS2005常见问题总结(Window核心编程第五版以前代码在VS2005无法编译的解决方案)...
额喜新厌旧是男人的通病吧,可是呢VS2005的界面看着的确比VC6.0看着舒服,而且也算用习惯了吧.可是网上现在大部分C/C++的代码还是用VC6.0的.这为我们这些菜鸟的学习之路增添了不少障碍,可能 ...
- 内存映射文件——Windows核心编程学习手札之十七
内存映射文件 --Windows核心编程学习手札之十七 与虚拟内存一样,内存映射文件保留地址空间,并将物理存储器提交给该区域,差别在于所提交的物理存储器是磁盘上有文件存在的空间,而非系统的页文件,一旦 ...
- 线程的堆栈——Windows核心编程学习手札之十六
线程的堆栈 --Windows核心编程学习手札之十六 系统会在进程的地址空间内保存一些区域,同时也会在进程地址空间内为线程的堆栈保留区域.线程都有自己的堆栈,创建时,系统就保留一个堆栈空间区域,并将相 ...
- 我对windows核心编程的理解之一
看了几天windows核心编程VC++,前几天对进程,作业,线程的关系很迷惑,还有就是内核对象的应用也很迷茫.昨天自己拿着书,又翻过去看看.突然有一点心得,初步对windows下的三种工作单位有了新的 ...
- python核心编程--笔记(不定时跟新)(转)
的解释器options: 1.1 –d 提供调试输出 1.2 –O 生成优化的字节码(生成.pyo文件) 1.3 –S 不导入site模块以在启动时查找python路径 1.4 –v ...
- Windows核心编程 - API HOOK应用
#Windows核心编程 - API HOOK应用 如需转载请标明出处:http://blog.csdn.net/itas109 QQ技术交流群:129518033 目录 文章目录 #Windows核 ...
- Spring Boot 核心编程思想-第一部分-读书笔记
怕什么真理无穷 进一步有近一步的欢喜 说明 本文是Spring Boot核心编程思想记录的笔记,书籍地址:Spring Boot编程思想(核心篇): 本书已经简单读过一遍,在第一遍读的时候发现里面有些 ...
- C++Windows核心编程读书笔记(转)
http://www.makaidong.com/(马开东博客) 这篇笔记是我在读<windows核心编程>第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多我个人的 ...
- C++核心编程(一)
C++ 核心编程 本系类列博客都是根据黑马的C++视频做的笔记. 本阶段主要针对C++面向对象编程技术做详细记录,探讨C++中的核心和精髓. 1.内存分区模型 C++程序在执行时,将内存大方向划分为4 ...
最新文章
- 如何在Ubuntu和CentOS上启用Nginx的HTTP/2 协议支持
- Oracle Sequence
- 秦汉考场科目三路线图_海淀驾校科目三校内考场总结
- 赞!图像生成PyTorch库火了,涵盖18+ SOTA GAN实现
- add_axes()——python绘图
- 大数四则运算java(转)
- 三维重建_对比几个三维重建系统(大部分开源)
- pg 简单备份和恢复
- 软件公司所犯的3种最严重的营销错误,你应该来看看
- linux怎么安装台式无线网卡,linux下安装无线网卡
- 推荐搜索的冷启动问题
- 科沃斯扫地机器人哪个型号最实用_科沃斯扫地机哪个型号好 三个价位三种选择...
- matplotlib绘制折线图的柱状图
- 上位机和三菱FN2x通信实例
- 互联网日报 | 贾跃亭乐视网股票流拍;东航组建“三亚国际航空”;苹果线上WWDC大会22日举办...
- 快给你的对象做一个微信公众号播报吧-java版
- js查找数组中符合条件的元素
- android framework-zygote进程
- html标签 ppt,HTML框架标签、超链接标签、控件标签.ppt
- IQOO换鸿蒙系统,1998 iQOO 845版明天发?| 华为自研系统鸿蒙在全球注册商标
热门文章
- Python语言学习之文件格式后缀那些事:python和常见各种文件格式后缀介绍、使用方法之详细攻略
- HighNewTech之5G网络:带你了解5G网络的前世今生—两张长图帮你捋清思路
- DL之GoogleNet:GoogleNet(InceptionV1)算法的简介(论文介绍)、架构详解、案例应用等配图集合之详细攻略
- 理解 java 中常用数据结构
- 在Javascript中 声明时用var与不用var的区别,== 和 ===的区别
- 阅读《Oracle内核技术揭秘》的读书笔记
- jquery,angular 对象数组的克隆和深度克隆
- VJ 1033 整数分解(版本2)
- [唐胡璐]Java操作Sql Server 2008数据库
- Maven报错“未结束的字符串字面值”