支持直接粘贴IP字符串的CIPAddressCtrl控件
标准的CIPAddreeeCtrl控件在输入IP地址时很不方便,四个字段要一个一个的输入,平时倒没怎么注意,今天多输了几次,觉得很不爽,所以就想做一个能直接粘贴IP字符串的CIPAddreeeCtrl控件。
思路:
这种问题当然是要拦截WM_PASTE消息了,只不过WM_PASTE并不是直接发给CIPAddreeeCtrl的,因为CIPAddreeeCtrl下面有4个edit子控件,WM_PASTE是发给它们的。
接下来的工作就好办了。给edit控件定义一个消息处理函数:收到WM_PASTE时检查剪贴板的内容是不是一个合法的IP地址,如果是,就把IP地址设置到CIPAddreeeCtrl控件,否则就调用缺省的消息处理函数。
最后,将edit控件的消息处理函数设置成自定义的函数就可以了。
注意一些细节:
1. 设置edit控件的消息处理函数时,使用EnumChildWindows()+SetWindowLong();
2. edit控件设置CIPAddreeeCtrl的IP地址是通过发送一个自定义消息实现的;
3. 设置edit控件的消息处理函数的工作应放在CMyIPAddressCtrl::PreSubclassWindow()里,这样就不需要在使用CIPAddreeeCtrl的窗口里做什么别的操作了。
4. 消息处理函数的功能可以加强一点:如果不是合法的IP地址,就再判断是不是合法的数字,不是的话,就忽略掉WM_PASTE消息。
MyIPAddressCtrl.h
#pragma once
// CMyIPAddressCtrl
class CMyIPAddressCtrl : public CIPAddressCtrl
{
DECLARE_DYNAMIC(CMyIPAddressCtrl)
public:
CMyIPAddressCtrl();
virtual ~CMyIPAddressCtrl();
private:
void SetEditWindowProc();
LRESULT CMyIPAddressCtrl::OnSetAddress(WPARAM wParam, LPARAM lParam);
protected:
DECLARE_MESSAGE_MAP()
virtual void PreSubclassWindow();
};
MyIPAddressCtrl.cpp
// MyIPAddressCtrl.cpp : implementation file
//
#include "stdafx.h"
#include "MyIPAddressCtrl.h"
#include "./myipaddressctrl.h"
#define WM_USER_SET_ADDRESS WM_USER+1234
#ifdef STRICT
WNDPROC OldEditWindowProc = NULL;
#else
FARPROC OldEditWindowProc = NULL;
#endif
DWORD ConvertIPAddress( const char *sIP );
BOOL GetTextFromClipboard( HWND hWnd, CString &sText );
BOOL CALLBACK SetEditWindowLong( HWND hWnd, LPARAM param );
LRESULT CALLBACK NewEditWindowProc( HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam );
// CMyIPAddressCtrl
IMPLEMENT_DYNAMIC(CMyIPAddressCtrl, CIPAddressCtrl)
CMyIPAddressCtrl::CMyIPAddressCtrl()
{
}
CMyIPAddressCtrl::~CMyIPAddressCtrl()
{
}
BEGIN_MESSAGE_MAP(CMyIPAddressCtrl, CIPAddressCtrl)
ON_MESSAGE(WM_USER_SET_ADDRESS, OnSetAddress )
END_MESSAGE_MAP()
// CMyIPAddressCtrl message handlers
void CMyIPAddressCtrl::SetEditWindowProc()
{
EnumChildWindows( m_hWnd, SetEditWindowLong,NULL );
}
LRESULT CMyIPAddressCtrl::OnSetAddress(WPARAM wParam, LPARAM lParam)
{
SetAddress( (DWORD)wParam );
return 0;
}
void CMyIPAddressCtrl::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
SetEditWindowProc();
CIPAddressCtrl::PreSubclassWindow();
}
BOOL CALLBACK SetEditWindowLong( HWND hWnd, LPARAM param )
{
OldEditWindowProc = (WNDPROC) SetWindowLong (hWnd, GWL_WNDPROC, (LONG)NewEditWindowProc );
return TRUE;
}
LRESULT CALLBACK NewEditWindowProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
if( WM_PASTE == message )
{
//::MessageBox(NULL,"click!","",MB_OK);
CString sText;
if( GetTextFromClipboard( hwnd, sText ) )
{
DWORD dwIPAddress = ConvertIPAddress( sText );
HWND hParentWnd = ::GetParent( hwnd );
if( dwIPAddress != -1 && hParentWnd != NULL )
{
::SendMessage( hParentWnd, WM_USER_SET_ADDRESS, dwIPAddress, 0 );
return 0;
}
else
{
UINT8 *p = (UINT8*)(LPCSTR)sText;
BOOL nRet = TRUE;
while( nRet && *p )
nRet = isdigit( *p++ );
if( !nRet )
return 0;
}
}
}
//调用控件原来的消息处理函数
return CallWindowProc(OldEditWindowProc,hwnd,message,wParam,lParam);
}
DWORD ConvertIPAddress( const char *sIP )
{
DWORD dwIPAddress = -1;
BOOL bRet = true;
int ip[4] = { 0 };
char tmp[2] = { 0 };
bRet = sIP && *sIP && isdigit( *(UINT8*)sIP )
&& ( 4 == sscanf( sIP, "%d.%d.%d.%d%1s", &ip[0], &ip[1], &ip[2], &ip[3], tmp ) )
&& ( ip[0] >= 0 && ip[0] <= 255 )
&& ( ip[1] >= 0 && ip[1] <= 255 )
&& ( ip[2] >= 0 && ip[2] <= 255 )
&& ( ip[3] >= 0 && ip[3] <= 255 );
if( bRet )
{
dwIPAddress = (ip[0]<<24) | (ip[1]<<16) | (ip[2]<<8) | ip[3];
}
return dwIPAddress;
}
BOOL GetTextFromClipboard( HWND hWnd, CString &sText )
{
BOOL bRet = FALSE;
if( OpenClipboard( hWnd ) )
{
HANDLE hData = GetClipboardData( CF_TEXT );
if( hData != NULL )
{
char *buffer = (char*)GlobalLock( hData );
sText = buffer;
GlobalUnlock( hData );
bRet = TRUE;
}
CloseClipboard();
}
return bRet;
}