第一百零一个OpenFileMapping获取CreateFileMapping函数创建的文件映射对象句柄
函数定义:HANDLE
OpenFileMappingW(
DWORD dwDesiredAccess,//取值参考MapViewOfFile函数的dwDesiredAccess参数
BOOL bInheritHandle,//依据CreateFileMapping函数的lpFileMappingAttributes参数而定,不能被新进程继承,为FALSE
LPCWSTR lpName//指明获取哪个文件映射对象句柄,对应着CreateFileMapping函数的lpName参数
);
函数返回文件映射对象句柄。
例子:两进程间传递数据
进程1程序代码:
#include<windows.h>
#include<stdio.h>
int main()
{
char Data[11]="0123456789";
HANDLE hMap=CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,11,"ShareMemory");
LPVOID lpBase = ::MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
strcpy((char *)lpBase,Data);//写入数据
while(1)
{
Sleep(2000);
}
return 0;
}
进程2程序代码:
#include<stdio.h>
#include<windows.h>
int main()
{
HANDLE hMap=::OpenFileMapping(FILE_MAP_WRITE,FALSE,"ShareMemory");
LPVOID lpBase = ::MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0);
printf("ShareMemory Data:%s\n",lpBase);//输出数据
return 0;
}
第一百零二个CopyMemory复制一段内存
函数定义: VOID CopyMemory(
PVOID Destination, //目的地址
CONST VOID *Source, //源地址
DWORD Length //复制多少字节
);
这个函数跟C语言的memcpy函数一样,这里仅举个例子:
#include<stdio.h>
#include<windows.h>
int main()
{
DWORD dwDestin=0;
DWORD dwSource=120;
CopyMemory((void *)&dwDestin,(void *)&dwSource,sizeof(DWORD));
printf("%d\n",dwDestin);
return 0;
}
第一百零三个SetParent设置(更改)一个子窗口的父窗口
该函数有两个参数,第一个是子窗口的句柄,第二个是父窗口的句柄。
如果父窗口句柄为空,则以桌面窗口作为父窗口
例子:把记事本里状态栏的父窗口改为编辑框窗口
用spy++查看记事本编辑框窗口的类名为"Edit",状态栏为"msctls_statusbar32"(可能会有差异,具体可以用Spy++查看)
#include<windows.h>
int main()
{
HWND wnd=FindWindow(NULL,"无标题.txt - 记事本");
HWND EditWnd=FindWindowEx(wnd,NULL,"Edit",NULL);//查找获取编辑框窗口句柄
HWND StatusWnd=FindWindowEx(wnd,NULL,"msctls_statusbar32",NULL);//查找获取状态栏窗口句柄
::SetParent(StatusWnd,EditWnd);//设置状态栏父窗口
RECT rect;
GetClientRect(StatusWnd,&rect);//获取状态栏客户区大小
//移动状态栏窗口,如果编辑框窗口不是状态栏的父窗口,则状态栏是移不进编辑框窗口的
MoveWindow(StatusWnd,0,0,rect.right,rect.bottom,TRUE);
return 0;
}
第一百零四个OpenClipboard打开一个剪切板
剪切板是什么意思呢,可以把它看做一块内存,这块内存可以被任何进程调用相关函数进行读写。事实上,像我们平常的复制粘贴就是在读写这块内存,比如用选中一段文字,然后右击,选择复制,这时对应程序就会调用OpenClipboard函数打开剪切板,往里面写入数据,
当不再需要操作剪切板的时候就调用CloseClipboard函数关闭剪切板,剪切板不能同时被多个程序打开,也就是说如果其它程序已经调用OpenClipboard打开剪切板了,并且没有调用CloseClipboard关闭剪切板的话,那么其它程序调用OpenClipboard就会失败,这一点从下面的例子可以说明。
这个函数只有一个参数,是一个窗口句柄,也就是具体在哪个窗口里进行复制粘贴操作(剪切也算),如果为NULL,则跟调用这个函数的进程相关联。
例子:让粘贴复制失效
#include<windows.h>
int main()
{
OpenClipboard(NULL);
while(1)
Sleep(1000);
}
由于这个程序打开了剪切板却并不关闭它,导致了其它程序无法调用OpenClipboard函数打开剪切板,无法打开剪切板,自然也就无法复制粘贴数据了
第一百零五个SetClipboardData写入一段数据到剪切板(设置剪切板的数据)
HANDLE SetClipboardData( UINT uFormat,HANDLE hMem);
像我们使用windows的复制粘贴的时候,不仅能复制文字,也能复制文件,图片等。所以uFormat指明要写入的是什么数据。
uFormat的常用取值如下:
CF_UNICODETEXT含有Unicode文字的内存块
CF_BITMAP与设备相关的位图格式。位图是通过位图句柄传送给剪切板的
CF_TEXT以NULL结尾的ANSI字符集字符串
第二个指向存储要写入的数据内存,注意,存储数据的内存必须是在堆中分配的。
例子1:写入ASCII字符串到剪切版
#include<windows.h>
#include<string.h>
int main()
{
char *pData=new char[15];//在堆中申请内存
strcpy(pData,"ABCDEFG");
OpenClipboard(NULL);//打开剪切板
EmptyClipboard();//清空剪切板的数据
SetClipboardData(CF_TEXT,pData);//往剪切板里写入数据
CloseClipboard();//关闭剪切板
delete pData;
return 0;
}
//随便到可以输入文字的地方,右击->粘贴看写入是否成功
例子2:写入宽字符串(Unicode)到剪切板
#include<string.h>
#include<windows.h>
int main()
{
WCHAR *pData=new WCHAR[15];
WCHAR str[15]=L"ABC我们D";//用L把ASCII转换成Unicode
CopyMemory((void *)pData,(void *)str,sizeof(str));//相当于ASCII字符串处理函数strcpy
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_UNICODETEXT,pData);
CloseClipboard();
return 0;
}
第一百零六个GlobalAlloc从堆中分配一定数目的字节数
HGLOBAL
WINAPI
GlobalAlloc(
UINT uFlags,//分配属性(方式)
DWORD dwBytes//分配多少字节
);
uFlags常用取值:
GMEM_FIXED 分配固定的内存,返回值是一个指针
GMEM_MOVEABLE 返回值是一个内存句柄,可用GlobalLock函数根据一个内存句柄,返回内存句柄对应的首地址,并锁定内存中指定的内存块,对应的函数是:GlobalUnlock
对应的释放内存函数是GlobalFree,这里还是说明一个函数GlobalSize,这个根据内存句柄获得对应内存块大小
例子:GlobalAlloc函数应用
#include<stdio.h>
#include<windows.h>
int main()
{
HGLOBAL hMem=GlobalAlloc(GMEM_MOVEABLE,8);//按GEME_MOVEABLE方式分配内存
DWORD dwSize=GlobalSize(hMem);//获取内存块大小
int *pNumber=(int *)GlobalLock(hMem);//把内存句柄转换成内存首地址
pNumber[0]=5;pNumber[1]=6;
printf("内存块大小%d\n%d,%d\n",dwSize,pNumber[0],pNumber[1]);
GlobalFree(hMem);//释放内存
return 0;
}
第一百零七个GetClipboardData该函数获得剪切板里的数据,函数返回剪切板内存句柄
该函数只有一个参数,指明获取的是什么类型的数据,跟SetClipboardData函数的uFormat参数相对应,这里有一个问题,如何知道剪切板存储的是什么类型数据呢,用 IsClipboardFormatAvailable函数,这个函数只有一个参数,如: IsClipboardFormatAvailable(CF_TEXT)
这个语句用于判断当前剪切板有没有含有CF_TEXT数据,如果有的话,返回真(TRUE),否返回假。这个函数不用事先打开剪切板,也可以正常调用。
注意如果如果剪切板的数据是CF_UNICODETEXT形式的,用CF_TEXT类型打开也是可以的,因为windows系统会自动进行转换。
例子:获取剪切板里的CF_TEXT数据(先随便复制一段文字)
#include<stdio.h>
#include<windows.h>
int main()
{
if(IsClipboardFormatAvailable(CF_TEXT))//判断剪切板里是否有CF_TEXT数据
{
::OpenClipboard(NULL);
HGLOBAL hGlobal = GetClipboardData(CF_TEXT);//以CF_TEXT方式打开剪切板
char *pGlobal=(char *)GlobalLock(hGlobal);//获得剪切板内存的首地址,直接转换也可以,如(char *)hGlobal
printf("%s\n",pGlobal);//输出剪切板里的文字
GlobalUnlock(hGlobal);
CloseClipboard();
}
return 0;
}
第一百零八个Shell_NotifyIcon在任务栏里注册图标(任务栏托盘菜单)
(PS:今天看了一下以前写的这个函数,我描述这个函数为托盘菜单,今天来看,似乎压根就跟菜单没关系,我想,应该是那时候是在MFC里看到这个函数,那个例子是做一个托盘菜单,我就用了托盘菜单了,却没有实现托盘菜单的功能,不过,并不影响理解这个函数用法,以及它的意思,我也较烦)
函数定义:Shell_NotifyIcon(DWORD dwMessage, PNOTIFYICONDATAW lpData);
要想注册一个托盘菜单,首先你得提供一些信息,如在任务栏要显示的图标,系托盘菜单属于哪个窗口(严格来说,是托盘菜单产生的消息,发送给哪个窗口)
而这些信息就由Shell_NotifyIcon函数的第二个参数 lpData指明。它是一个NOTIFYICONDATAW结构指针。
NOTIFYICONDATAW结构定义及各成员意思如下:
typedef struct _NOTIFYICONDATAW {
DWORD cbSize;//指明NOTIFYICONDATA结构大小,用sizeof(NOTIFYICONDATA)给它赋值。
HWND hWnd;//窗口句柄,由鼠标在托盘图标产生的消息将发送给这个窗口
UINT uID;//标识托盘菜单的唯一ID号。
UINT uFlags;//指明结构中哪些成员有效,可以是NIF_ICON(对应hIcon), NIF_MESSAGE(对应uCallbackMessage),
//NIF_TIP(对应 szTip),可以用|按位或运算符结合在一起。
UINT uCallbackMessage;//自定义消息,鼠标在托菜图标上产生的行为将发送这个消息给hWnd成员对应的窗口
HICON hIcon;//图标句柄,
WCHAR szTip[64];//鼠标停留在托盘图标上产生的提示消息内容
} NOTIFYICONDATA, *PNOTIFYICONDATA;
dwMessage参数指明要进行的操作,常用取值有NIM_ADD(添加托盘菜单),NIM_DELETE(删除一个托盘菜单),NIM_MODIFY (修改一个托盘菜单)
了解了上面些我们来简单的在任务栏上显示一个托盘菜单的图标,其它什么也不做。
假设e盘下有一个名为"i.ico"的图标
代码如下:
#include<windows.h>
int main()
{
NOTIFYICONDATA notify;//定义一个托盘菜单信息结构
notify.cbSize=sizeof(NOTIFYICONDATA);//设置结构大小
notify.hIcon=(HICON)LoadImage(NULL,"e:\\i.ico",IMAGE_ICON,48,48,LR_LOADFROMFILE);//设置图标句柄
notify.uFlags=NIF_ICON;//指明哪些成员有效
::Shell_NotifyIcon(NIM_ADD,¬ify);//添加托盘菜单
while(1)
{
Sleep(1000);//避免程序退出,自动卸载托盘菜单
}
return 0;
}
怎么样任务栏是不是有一个图标显示了,但此时,用鼠单击,或双击任务上的图标都没反应。
如果想响应鼠标操作消息的话,得使 NOTIFYICONDATA结构的uCallbackMessage成员有效,这样当鼠标在托盘菜单图标上单击或双击后,就会产生uCallbackMessage成员对应的消息。而且还必须指定窗口句柄,不然产生了这个消息,发送给哪个窗口呢。
例子2:完整的托盘菜单应用
完整应用,必须得有自己的窗口,新建一个 “Win32 Application"工程。如果对用API函数创建窗口不了解的话,可以参考常用函数CreateWindow.
#include<windows.h>
#include<string.h>
//在WM_USER的基础上定义一个消息类型,用于托盘与窗口之间的消息传递
#define WM_TRAYMESSAGE WM_USER+25
LRESULT CALLBACK WinSunProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);//函数声明
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASS wndcls; //定义一个存储窗口信息WNDCLASS变量
wndcls.cbClsExtra=0; //默认为0
wndcls.cbWndExtra=0; //默认为0
wndcls.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH); //背景画刷
wndcls.hCursor=LoadCursor(NULL,IDC_ARROW); //光标
wndcls.hIcon=LoadIcon(NULL,IDI_ERROR); //窗口图标
wndcls.hInstance=hInstance; //应用程序实例句柄由WinMain函数传进来
wndcls.lpfnWndProc=WinSunProc; //窗口消息处理函数
wndcls.lpszClassName="windowclass"; //窗口类名
wndcls.lpszMenuName=NULL; //窗口菜单名,没有菜单,为NULL
wndcls.style=CS_HREDRAW | CS_VREDRAW;//窗口类型,CS_HREDRAW和CS_VERDRAW 表明
//当窗口水平方向垂直方向的宽度变化时重绘整个窗口
RegisterClass(&wndcls); //把窗口信息提交给系统,注册窗口类
HWND hwnd; //用以存储CreateWindow函数所创建的窗口句柄
hwnd=CreateWindow("windowclass","托盘菜单应用",
WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,hInstance,NULL);//创建窗口
NOTIFYICONDATA notify;//定义一个托盘菜单信息结构
notify.cbSize=sizeof(NOTIFYICONDATA);//设置结构大小
notify.hIcon=(HICON)LoadImage(NULL,"e:\\i.ico",IMAGE_ICON,48,48,LR_LOADFROMFILE);//设置图标句柄
notify.hWnd=hwnd;//接收消息的窗口句柄
strncpy(notify.szTip,"托盘菜单",sizeof("托盘菜单"));
notify.uCallbackMessage=WM_TRAYMESSAGE;//托盘菜单将发送这个消息给窗口
notify.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP;//指明哪些成员有效
::Shell_NotifyIcon(NIM_ADD,¬ify);//添加托盘菜单
ShowWindow(hwnd,SW_SHOWNORMAL);//窗口创建完了,显示它
UpdateWindow(hwnd); //更新窗口,让窗口毫无延迟的显示
MSG msg;//消息结构类型
while(GetMessage(&msg,NULL,0,0))//获取消息
{
TranslateMessage(&msg); //此函数用于把键盘消息(WM_KEYDOWN,WM_KEYUP)转换成字符消息WM_CHAR
DispatchMessage(&msg); //这个函数调用窗口过程处理函数,并把MSG里的信息处理后传给过程函数的四个参数
}
::Shell_NotifyIcon(NIM_DELETE,¬ify);//卸载托盘菜单
return 0;
}
LRESULT CALLBACK WinSunProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_SYSCOMMAND:
if(wParam==SC_MINIMIZE)//最小化了窗口
{
ShowWindow(hwnd,SW_HIDE);//隐藏窗口
}
else
{
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
break;
case WM_TRAYMESSAGE:
if(lParam==WM_LBUTTONDBLCLK)//双击托盘菜单图标,鼠标消息在lParam参数里
{
ShowWindow(hwnd,SW_RESTORE);//显示窗口
}
break;
case WM_CLOSE://用户关闭了窗口
DestroyWindow(hwnd);//销毁窗口,并发送WM_DESTROY消息
break;
case WM_DESTROY://如果窗口被销毁
PostQuitMessage(0);//让进程退出
break;
//未处理的消息通过DefWindowProc函数交给系统处理
default:return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
return 0;
}
第一百零九个FindResource从应用程序模块句柄找出一个资源
资源就是MFC里的资源,像位图,图标,对话框等这些资源都包含在exe文件里,如果看过PE文件结构分析及应用的话,应该会容易理解。
这个函数就是定位一个资源在模块里的位置。
函数定义:HRSRC FindResource(HMODULE hModule,//应用程序模块句柄,NULL表示本模块句柄
LPCTSTR lpName,//资源名
LPCTSTR lpType//资源类型
);
其中第一个参数hModule应用程序模块句柄,自身模块填NULL就行,如果想获取其它正在运行的应用程序模块,就用GetModuleHandle函数。
资源名就像资源的ID号一样,比如一个MFC的一个资源ID号是147,那么此参数应该是这样的"#147",或用MAKEINTRESOURCE宏转换
如:MAKEINTRESOURCE(147)
lpType用于表明资源类型,它是对话框?菜单?位图?还是自定义资源。。。
常用取值如下:
#define RT_CURSOR MAKEINTRESOURCE(1) //光标
#define RT_BITMAP MAKEINTRESOURCE(2) //位图
#define RT_ICON MAKEINTRESOURCE(3)//图标
#define RT_MENU MAKEINTRESOURCE(4)//菜单
#define RT_DIALOG MAKEINTRESOURCE(5)//对话框
#define RT_STRING MAKEINTRESOURCE(6)//字符串
#define RT_FONTDIR MAKEINTRESOURCE(7)
#define RT_FONT MAKEINTRESOURCE(8)//字体
#define RT_ACCELERATOR MAKEINTRESOURCE(9)
#define RT_RCDATA MAKEINTRESOURCE(10)
#define RT_MESSAGETABLE MAKEINTRESOURCE(11)
#define DIFFERENCE 11
#define RT_GROUP_CURSOR MAKEINTRESOURCE((DWORD)RT_CURSOR + DIFFERENCE)//光标组
#define RT_GROUP_ICON MAKEINTRESOURCE((DWORD)RT_ICON + DIFFERENCE)//图标组
#define RT_VERSION MAKEINTRESOURCE(16)
#define RT_DLGINCLUDE MAKEINTRESOURCE(17)
第一百一十个LoadResource根据资源指向句柄(HRSRC)把资源装载到内存。
函数返回资源所在内存句柄(HGLOBAL),可以用LockResource根据内存句柄,获取内存首地址
函数定义:
HGLOBAL LoadResource(HMODULE hModule,HRSRC hResiInfo);
hModule参数同FindResource对应的参一样,模块句柄,hResiInfo参数对应FindResource函数返回的值
LockResource函数定义:LPVOID LockResource(HGLOBAL hResDate);
hResDate参数对应LoadResource函数返回的值