您的位置:首页 > 其它

VC API常用函数简单例子大全五

2011-04-21 12:43 183 查看
第四十一个CreateCompatibleDC创建一个兼容的内存设备上下文(DC)
简单的来说,就是复制一个模一样的DC。就把窗口看成一幅幅图画,窗口有大有小,里面的内容也不一样(颜色值),每个像素点的颜色值可能不一样,所以就用设备上下文来描述每个窗口的信息,对于DC具体是怎样描述设备上下文的,我们暂时还不需要知道,只要了解这个概念就行了。这个窗口信息,获得一个窗口设备上下文,就用GetDC函数就行了,如HDC hDC=GetDC(hWnd);而CreateCompatibleDC的作用是根据一个设备上下文,再创建一个兼容的设备上下文,如 HDC mDC=CreateCompatibleDC(hDC)。这样mDC里的信息就跟hDC里的一样,那这有什么用呢?这个将会在后面的BitBltl输出一个位图(合并两个DC)函数里会用到。
第四十二个GetObject获取一个对象信息(如位图,图标,光标)
函数定义:int GetObject(HGDIOBJ hgdiobj, int cbBuffer, LPVOID lpvObject);
第一个参数hgdiobj是对象句柄,第二个参数cbBuffer是待写入lpvObject指针指向缓存区数据大小,第三个参数lpvObject是一个指针,指向一个缓存区。
这里举一个获取位图的信息,获取位图的大小,假设E盘下有一个aa.bmp的位图文件,输出位图的宽高
#include
#include
int main()
{
BITMAP bmInfo;//这个结构存储位图信息
HBITMAP bmp;
bmp=(HBITMAP)LoadImage(NULL,"e://aa.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
GetObject(bmp,sizeof(BITMAP),&bmInfo);
printf("位图宽:%d,位图高:%d/n",bmInfo.bmWidth,bmInfo.bmHeight);
return 0;
}
第四十三个BitBlt在窗口输出一个位图
其实倒不如说这个BitBlt函数是拷贝一个设备上下文(DC),或者合并两个窗口,再延伸一下,合并两个图片?也并无不可,往大了说,窗口难道不是图片吗?用截屏软件,把窗口截成图片,这样窗口便成了图片。可能有点瞎说,大家还是按照标准来吧,反正,你只要掌握这个函数就行了,而且这个概念也不会有什么影响,那就足够了。
BitBlt的作用跟把两幅图片合在一起一样,合并两幅图片。可能两幅图片大小不一样也可以合并,但合并DC就不行了,必须两个信息一样的DC才可以合并,那要如何确保两个DC一样呢?这就要用到CreateCompatibleDC函数了。
函数定义:BOOL BitBlt(HDC hdcDest,int nXDest,int nYDest,int nWidth,int nHeight,HDC hdcSrc,int nXSrc,int nYSrc,DWORD dwRop);
第一个参数hdcDest是原DC句柄,被覆盖的DC,nXdest,nYDest,nWidth,nHeight这四个参数,指明了一个矩形,覆盖原DC哪块区域。
第六个参数hdcSrc是覆盖的DC句柄,nXSrc,nYSrc参数指明从哪里开始覆盖。(覆盖DC的左上角),第九个参数dwPop表示以何种方式覆盖。因为这里我们只要输出一个位图,所以用SRCCOPY,直接覆盖。
好了,直接举个例子,在窗口输出一副图片,假设e盘下有一个aa.bmp的位图。为了方便,我们直接在记事本窗口输出位图,先运行一个窗口名为"无标题.txt - 记事本"记事本窗口程序。
#include
#include
int main()
{
BITMAP bmInfo;//这个结构存储位图信息
HBITMAP bmp;
bmp=(HBITMAP)LoadImage(NULL,"e://aa.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
GetObject(bmp,sizeof(BITMAP),&bmInfo);//获取位图信息
HWND wnd=FindWindow(NULL,"无标题.txt - 记事本");
HDC hdc=GetDC(wnd);
HDC memDC=::CreateCompatibleDC(hdc);//创造兼容的DC
SelectObject(memDC,bmp);//选入位图
while(1)
{
BitBlt(hdc,0,0,bmInfo.bmWidth,bmInfo.bmHeight,memDC,0,0,SRCCOPY);//输出位图
Sleep(200);

}
return 0;
}
下面介绍一下BitBlt函数最后一个参数的常用取值及意思。
参考(百度)
BLACKNESS:表示使用与物理调色板的索引0相关的色彩来填充目标矩形区域,(对缺省的物理调色板而言,该颜色为黑色)。   
DSTINVERT:表示使目标矩形区域颜色取反。   
MERGECOPY:表示使用布尔型的AND(与)操作符将源矩形区域的颜色与特定模式组合一起。   MERGEPAINT:通过使用布尔型的OR(或)操作符将反向的源矩形区域的颜色与目标矩形区域的颜色合并。 NOTSRCCOPY:将源矩形区域颜色取反,于拷贝到目标矩形区域。   
NOTSRCERASE:使用布尔类型的OR(或)操作符组合源和目标矩形区域的颜色值,然后将合成的颜色取反。 PATCOPY:将特定的模式拷贝到目标位图上。   
PATPAINT:通过使用布尔OR(或)操作符将源矩形区域取反后的颜色值与特定模式的颜色合并。然后使用OR(或)操作符将该操作的结果与目标矩形区域内的颜色合并。   
PATINVERT:通过使用XOR(异或)操作符将源和目标矩形区域内的颜色合并。   
SRCAND:通过使用AND(与)操作符来将源和目标矩形区域内的颜色合并。   
SRCCOPY:将源矩形区域直接拷贝到目标矩形区域。   
SRCERASE:通过使用AND(与)操作符将目标矩形区域颜色取反后与源矩形区域的颜色值合并。   SRCINVERT:通过使用布尔型的XOR(异或)操作符将源和目标矩形区域的颜色合并。   
SRCPAINT:通过使用布尔型的OR(或)操作符将源和目标矩形区域的颜色合并。   
WHITENESS:使用与物理调色板中索引1有关的颜色填充目标矩形区域。(对于缺省物理调色板来说,这个颜色就是白色)
第四十四个GetWindowText根据窗口句柄获得窗口标题名
函数定义:int GetWindowText(HWND hWnd,LPTSTR lpString,int nMaxCount);
第一个参数hWnd是要获取窗口标题名的窗口句柄,第二个lpString是个字符串,窗口标题名,将会存储在这里面,第三个参数nMaxCount指明了第二个参数字符数组的大小。
下面结合GetCursorPos和WindowFromPoint举个例子,鼠标指向哪个窗口,就在界面显示那窗口的标题名
#include
#include
int main()
{
char Text[256]={0};
HWND wnd;
POINT curpos;
while(1)
{
GetCursorPos(&curpos);
wnd = WindowFromPoint(curpos);
GetWindowText(wnd,Text,256);
printf("%s/n",Text);
Sleep(300);
}
return 0;
}
第四十五个SetWindowText根据窗口句柄设置窗口标题名
这个函数有两个参数,一个是窗口句柄,一个是标题名,这里就不需要解释了吧,直接看例子,设置一个窗口标题名,依旧以
"无标题.txt - 记事本"为例。
#include
#include
int main(int argc, char* argv[])
{
HWND wnd;
wnd=FindWindow(NULL,"无标题.txt - 记事本");//获取窗口句柄
SetWindowText(wnd,"新的窗口标题");//设置窗口标题名
return 0;
}
第四十六个GetCurrentProcess获得当前线程句柄
没有参数,直接调用即可,该函数返回线程句柄
第四十七个OpenProcessToken获得一个进程的访问令牌句柄
获得一个进程的访问令牌有什么用呢?主要是为了修改它的权限,前面在介绍结束一个进程的时候说过了,无法结束系统进程,是什么原因呢,原因是调用OpenProcess函数失败,无法获取系统进程句柄而引起的,那为什么会失败呢,权限不够,普通程序的进程没有SeDeDebug权限,而一个进程的权限是与访问令牌相关的,这样我们只要获取一个进程的访问令牌句柄,再以这个句柄为参数调用相应的函数提升进程的权限为SeDeDebug就可以获取系统进程句柄,进而结束它。
函数定义:BOOL OpenProcessToken(HANDLE ProcessHandle,DWORD DesiredAccess,PHANDLE TokenHandle)
第一个参数ProcessHandle待获取的进程句柄,第二个参数DesiredAccess操作类型,填TOKEN_ADJUST_PRIVILEGES就行了,
第三个TokenHandle是访问令牌句柄的指针,该参数接收句柄。
如获得本进程的访问令牌句柄:HANDLE hToken;
OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken);
第四十七个LookupPrivilegeValue函数查看对应系统权限的特权值,返回信息到一个LUID结构体里
上面讲过了,进程有权限一说,那么大家也能猜到,进程权限的信息也一定存储在一个结构体里,这个结构体描述了进程权限相关的一些信息。这个结构体在这里就不具体描述了,我们所要做的,只是把一个进程权限设置成SeDeDebug就行了,所以我们只要知道TOKEN_PRIVILEGES便是描述进程权限的结构体就可以了。而LookupPrivilegeValue函数是根据访问令牌句获取相应的权限信息吗?
不是的。TOKEN_PRIVILEGES结构里的Privileges[0].Luid跟这个函数所查询的东西相对应,也就是说,如果进程是SeDeDeBug权限,那Privileges[0].Luid的取值是怎样的呢?用LookupPrivilegeValue函数便可以获取其取值。
这个函数是这样定义的:BOOL LookupPrivilegeValue(LPCTSTR lpSystemName,LPCTSTR lpName,PLUID lpLuid);
第一个参数lpSystemName通常都填NULL,本地系统调用,第二个参数lpName填要查询的权限名,如要查询的是SeDeDebug权限则取值是SE_DEBUG_NAME,第三个参数lpLuid接收其取值。
如LUID luid;LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid);
第四十八个AdjustTokenPrivileges调整一个进程的访问令牌信息(权限)
函数定义:BOOL AdjustTokenPrivileges(HANDLE TokenHandle,BOOL DisableAllPrivileges,PTOKEN_PRIVILEGES NewState,DWORD BufferLength,PTOKEN_PRIVILEGES PreviousState,PDWORD ReturnLength)
第一个参数TokenHandle是令牌句柄,第二个是禁用所有权限标志,后面填FALSE就行了。第三个NewState是待刷进令牌句柄的PTOKEN_PRIVILEGES结构信息指针,第四个BufferLength指明TOKEN_PRIVILEGES结构大小,第五,六个参数填NULL就行了。
那么结束上面两个函数,提升一个进程权限制,让它能够结束系统进程的代码就是:
HANDLE hToken;
OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken );
TOKEN_PRIVILEGES tp;
LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid );
tp.PrivilegeCount = 1;//tp里其它一些属性设置
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof( TOKEN_PRIVILEGES ), NULL, NULL );
只上把上面的代码,加入结束普通进程例子的前面,那么就能结束系统进程了。
第四十九个LoadLibrary加载动态链接库,返回动态链接库模块句柄
该函数只有一个参数,那就是动态链接库的名称,如user32.dll,函数返回HMOUDLE类型的模块句柄,获得了一个动态链接库的模块句柄,就可以调用GetProcAddress函数获得模块里面的函数地址,从而调用动态链接库里的函数。
第五十个GetProcAddress根据模块句柄获取相应的函数地址
提到GetProcAddress函数,不得不讲一下怎么设计一个动态链接库,这里我们就以自己设计动态链接库作为GetProcAddress函数的例子。
动态链接库里的函数相对于头文件的函数有什么优势呢?更节省内存,相对于比较常用的函数而已。如果在一个程序里,调用一个头文件里的函数的话,那不管如何,函数的代码就会被复制一份到当前程序里,所以,当有十几个程序调用同一个函数的时候,这个函数在内存中所占用的空间,就会有十几份,分别在各自调用的进程内存空间里,而动态链接库的函数,只在内存中有一份空间(公用空间)如果哪个程序要用到这个函数的话,只要给这个函数的地址,进程就可以跑到这个空间执行函数,那么如何获取函数地址呢,用GetProcAddress函数就行了。
下面我们就自己设计一个动态链接库,点“文件->新建->工程",然后选中“Win32 Dynamic-Link Library”,再在右边给工程取一个名,点确定。接着弹出了一个对话框,询问希望创建什么类型,我们选择第二个“一个简单的DLL工程”,点完成->确定.然后单击右边的“+”号,很小的一个,接着下面会出现一个Globals的"+"号,单击该加号,然后再双击DllMain函数,进入代码编辑区,在这里编写代码,这里已经有了一些代码了,编译器自动生成的。那个DllMain函数,便是动态链接库的主函数。在程序进程加载动态链接的时候,进程会自动调用DllMain函数,也就是说会自动执行DllMain函数里的代码,也就是说,如果哪程序执行了这个语句“LoadLibrar("user32.dll")",那么执行这个语句的进程,便会自动执行user32.dll里的DllMain函数。如果是主线程加载动态库的话,那么该DllMain函数里的代码会被执行两次,分别是加载的时候执行一次,调用FreeLibrary函数释放或程序结束自动释放动态链接库的时候执行一次,至于是什么原因导致DllMain函数被调用,DllMain函数的第二个参数ul_reason_for_call说明了原因,它有四个取值,代表了四个原因。分别是:
DLL_PROCESS_ATTACH(进程加载),DLL_THREAD_ATTACH (线程加载)
DLL_THREAD_DETACH(线程释放),DLL_PROCESS_DETACH(进程释放)
因为这里我们只要设计一个动态链接函数,所以便不用管DllMain函数,DllMain函数将会在介绍CreateRemoteThread(创建一个远程线程)函数的时候讲到,所以我们只要在DllMain函数外定义一个函数就行了。
那么在动态链接库是如何定义函数呢?如果函数不需要导出的话,则跟普通函数定义没什么两样,导出是什么意思,就是可以用GetProcAddress函数获取地址的函数。那导出的函数要如何定义呢?
只要在函数前面加上extern "C" __declspec(dllexport)就行了,声明导出函数,防止函数重命名。那么接下来就举个例子。
动态链接里的代码:
#include "stdafx.h"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
extern "C" __declspec(dllexport) int Add(int a,int b)
{
return a+b;
}
点编译执行,然后就会弹出一个调试对话框,直接点取消,接着便生成了动态链接库DLL,然后到你的工程里把后缀名为dll的文件找到,
位置在MyProject/"你的工程名"/Debug下。接着把这个文件复制到要调用的工程下,或者直接复制C:/windows/system32目录下。
假设这个文件名为"sss.dll",那么要调用里面的Add函数便是如下代码:
HMODULE hmod=::LoadLibrary("sss.dll");//获取sss.dll的模块,加载sss.dll动态链接库
typedef int (*pAdd)(int a,int b);//定义一个对应的函数型,以便识别
pAdd add=(pAdd)GetProcAddress(hmod,"Add");//获取hmod模块里的Add函数地址
int a=add(3,5);//调用模块里的Add函数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: