自定义MessageBox----HOOK

 

HOOK自己接触的其实非常少,所以也从来没敢谈论过什么,这个MessageBox还真的研究了好几个hour呢,挺怕被大牛们嘲笑的,今天我也不要脸了,说说我的一些看法,欢迎扔砖头,西红柿。 

众所周知,一个标准的messagebox框通常不是自定义风格的,因为我们从来不能正常找到它的句柄handle.API函数MessageBox只有在messagebox框被销毁的时候才能返回,因此,我们的程序从来不曾看到messagebox窗口的消息,因为MessageBox这个API调用了它自己内部包含了消息循环,跟DialogBox这个创建非模态对话框的API函数类似的方式。

首先说如何修改标准OK按钮上的文本。

主要借助了hook,截取messagbox框的消息的最好的方法是安装一个Hook,这个非常容易实现----SetWindowsHookEx就可以实现。Hook有很多不同的类型,每个类型是为不同的目的所设计,这里不啰嗦,其实我也斗胆敢啰嗦。

这里用到的是WM_CBT hook,这个Hook被调用只为了很少的一些消息,比如,WM_ACTIVATE,WM_CREATE,WM_DESTROY,WM_SIZE,WM_MOVE等等。因为我们想在窗口创建期间来实现我们的自定义风格,因此这个Hook算是符合我们的目的吧。

 安装一个Hook

HHOOK hMsgBoxHook = SetWindowsHookEx(

 WH_CBT, // Type of hook 

CBTProc, // Hook procedure (see below) 

NULL, // Module handle. Must be NULL (see docs) 

GetCurrentThreadId() // Only install for THIS thread!!!

 );


 

需要简单注意一下GetCurrentThreadId(),仅仅安装在本线程。

移走一个Hook

UnhookWindowsHookEx(hMsgBoxHook);


 

核心部分--hook过程

上面已经说了无论何时当有WM_ACTIVATE,WM_CREATE消息被发送到我们的应用程序的时候都会有一个CBT事件发生。

 

 LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam){ HWND hwnd;

if(nCode < 0)
return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam);

switch(nCode)
{
case HCBT_ACTIVATE:

// Get handle to the message box!
hwnd = (HWND)wParam;

// Do customization!
return 0;

}

// Call the next hook, if there is one
return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam);
}



 

完整结合

围绕MessageBox,我们自己写个函数,此函数隐藏hook的细节,当我们想显示一个自定义的MessageBox的时候,就用这个函数替换就OK。

static HHOOK hMsgBoxHook;
...

int MsgBoxEx(HWND hwnd, TCHAR *szText, TCHAR *szCaption, UINT uType)
{
int retval;


hMsgBoxHook = SetWindowsHookEx(
WH_CBT, 
CBTProc, 
NULL, 
GetCurrentThreadId() 

);
retval = MessageBox(hwnd, szText, szCaption, uType);
UnhookWindowsHookEx(hMsgBoxHook);

return retval;
}


 

到此为止就已经把OK按钮的字体变成了我们自己的了。

运行效果如下:

这里我顺便给MessageBox把最大最小化按钮也给加上了,当然图标也是可以替换的,等等,剩下的就看想象力了。简单说下添加最大最小化按钮过程中的一点细节吧,起初我以为可以在创建的时候添加,因此写的代码如下:

case HCBT_CREATEWND:
  cbt_createwnd=(LPCBT_CREATEWND)lParam;
  cbt_createwnd->lpcs->style|=WS_MINIMIZEBOX;//MSDN中说的很清楚了,这里并不起作用
  cbt_createwnd->lpcs->cx=300;
  cbt_createwnd->lpcs->cy=300;


 

发现真的没任何效果,看了MSDN发现确实说的很清楚了,证据在这里:

HCBT_CREATEWND Specifies the handle to the new window. Specifies a long pointer to a CBT_CREATEWND structure containing initialization parameters for the window. The parameters include the coordinates and dimensions of the window. By changing these parameters, a CBTProc hook procedure can set the initial size and position of the window.

在这里只能设置坐标跟尺寸,想设置风格那就不可能了。

想来想去还是觉得得用窗口子类化,因为这家伙的确是很实用,思路:在窗口的WM_ACTIVATE消息中利用SetWindowLong来进行窗口子类化,在窗口过程函数中顺便我实现了对MessageBox框上的按钮响应了,让他继续弹出一个MessageBox框。。。。。列出一些MSDN的记载吧:

HCBT_ACTIVATE Specifies the handle to the window about to be activated. Specifies a long pointer to a CBTACTIVATESTRUCT structure containing the handle to the active window and specifies whether the activation is changing because of a mouse click.

就说到这里吧其余发挥,代码如下:
#include 
#include 

TCHAR szContents[] = _T("I really miss you very much--zxj!");
TCHAR szTitle[]    = _T("Hello");
#define IDC_PZG 123
HHOOK hMsgBoxHook;
LPCBT_CREATEWND cbt_createwnd;
WNDPROC OldWndProc;
INT_PTR CALLBACK MessageBoxProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)
{
	switch(Msg)
	{
	case WM_COMMAND:
		switch(LOWORD(wParam))
		{
		case IDC_PZG:
			MessageBox(hWnd,"痞子","痞子哥",MB_OK|MB_ICONINFORMATION);
			break;
		}
		case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
		default:
			return CallWindowProc(OldWndProc,hWnd,Msg,wParam,lParam);
	}
	return 0;
}

LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	TCHAR ach[40];
	HWND hwnd;
	HWND hwndButton;

	if(nCode < 0)
		return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam);

	switch(nCode)
	{
	case HCBT_CREATEWND:
		cbt_createwnd=(LPCBT_CREATEWND)lParam;
		cbt_createwnd->lpcs->style|=WS_MINIMIZEBOX;//MSDN中说的很清楚了,这里并不起作用
		cbt_createwnd->lpcs->cx=300;
		cbt_createwnd->lpcs->cy=300;
		//hwnd=(HWND)wParam;
		
		break;
	 case HCBT_ACTIVATE:
	//case HCBT_CREATEWND:

		// Get handle to the message box!
		hwnd = (HWND)wParam;
		OldWndProc=(WNDPROC)SetWindowLong(hwnd,GWL_WNDPROC,(LONG)MessageBoxProc);
		SetWindowLong(hwnd,GWL_STYLE,(long)WS_OVERLAPPEDWINDOW);
		SetWindowText(hwnd, _T("Message from yiruirui"));

		hwndButton = GetDlgItem(hwnd, IDOK);
		SetWindowText(hwndButton, _T("Thankyou"));
		CreateWindow("button","痞子--AV王子",WS_CHILD|WS_VISIBLE,10,50,250,250,hwnd,(HMENU)IDC_PZG,GetModuleHandle(NULL),NULL);
		return 0;

	}

	return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam);
}


int MsgBoxEx(HWND hwnd, TCHAR *szText, TCHAR *szCaption, UINT uType)
{
	int retval;

	// Install a window hook, so we can intercept the message-box
	// creation, and customize it
	hMsgBoxHook = SetWindowsHookEx(
		WH_CBT, 
		CBTProc, 
		NULL, 
		GetCurrentThreadId()			// Only install for THIS thread!!!
		);

	// Display a standard message box
	retval = MessageBox(hwnd, szText, szCaption, uType);

	// remove the window hook
	UnhookWindowsHookEx(hMsgBoxHook);

	return retval;
}


int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int nShowCmd)
{
	// Just display a standard message box.
	// It doesn't matter that we have no parent window or a
	// message-loop, because MessageBox has it's own message loop.

	MsgBoxEx(NULL, szContents, szTitle, MB_OK | MB_ICONSTOP);
		
	return 0;
}


 

你可能感兴趣的:(自定义MessageBox----HOOK)