[转载]备忘:VC++6.0 获取其他窗口中文本框内容

来源:互联网 发布:淘宝 发货地不符 编辑:程序博客网 时间:2024/05/16 11:07

[转载]备忘:VC++6.0 获取其他窗口中文本框内容

(2014-03-25 10:43:46)
转载
标签:

转载

 
原文地址:备忘:VC++6.0 获取其他窗口中文本框内容作者:青蛙

我有2程序:
  第1个程序是一个输入界面,界面上有2文本框。
 第2个程序点一个按钮,取第1个程序中文本框的内容。
现在我在第2个程序中,点击按钮的代码如下:
 // 取主窗体句柄
HWND hWndRcv =::FindWindow(_T("#32770"), _T("输入测试窗体"));
if(hWndRcv != NULL)
{
//MessageBoxA(NULL, "[输入测试窗体]窗口已经打开", "提示", MB_OK);
}
else
{
MessageBoxA(NULL, "[输入测试窗体]窗口没打开", "提示", MB_OK);
return;
}
  // 通过文本框的控件取某一文本框的控件句柄
HWND m_WndTextBox1 =::GetDlgItem(hWndRcv, 0x00003EA); // 文本1
  // 获取文本框的内容
  TCHAR tchar1[200];
CString str;
::GetDlgItemText(m_WndTextBox1, 0x00003EA, (LPWSTR)tchar1, 200); //用子窗体的句柄
str.Format(_T("%s"),tchar1);
AfxMessageBox(str);
本来在文本框中输入有数据,结果取出来显示为空。
 TCHAR tchar1[200];
CString str;
::GetDlgItemText(hWndRcv, 0x00003EA, (LPWSTR)tchar1, 200); //用母窗体体的句柄
str.Format(_T("%s"),tchar1);
AfxMessageBox(str);
这样出来的结果还是不对。
不大会使用VC,请各位帮忙看一下代码上有何问题,应该如何写才对,谢谢各位了。


::GetDlgItemText(m_WndTextBox1, 0x00003EA, (LPWSTR)tchar1, 200);
换成
::SendMessage(m_WndTextBox1, WM_GETTEXT, (sizeof(tchar1)/sizeof(TCHAR)), (LPARAM)(tchar1));


GetDlgItemText你要是能获得其他程序的文本框内容,那是你见了鬼,根本不可能的事情。
因为还没有把输入输出线程通道进行连接,当然得不到
建议你这么做先FindWindow找窗口句柄,然后FindWindowEx找文本框句柄,最后用GetWindowText


ID值啊?
建议还是用FindWindowEx来获取控件窗口句柄吧。


FindWindowEx用法:
函数原型:HWND FindWindowEx(HWND hwndParent,HWND hwndChildAfter,LPCTSTR lpszClass,LPCTSTR lpszWindow);
   参数;
   hwndParent:要查找子窗口的父窗口句柄。
   如果hwnjParent为NULL,则函数以桌面窗口为父窗口,查找桌面窗口的所有子窗口。
   Windows NT5.0 and later:如果hwndParent是HWND_MESSAGE,函数仅查找所有消息窗口。
   hwndChildAfter :子窗口句柄。查找从在Z序中的下一个子窗口开始。子窗口必须为hwndPareRt窗口的直接子窗口而非后代窗口。如果HwndChildAfter为NULL,查找从hwndParent的第一个子窗口开始。如果hwndParent 和 hwndChildAfter同时为NULL,则函数查找所有的顶层窗口及消息窗口。
   lpszClass:指向一个指定了类名的空结束字符串,或一个标识类名字符串的成员的指针。如果该参数为一个成员,则它必须为前次调用theGlobaIAddAtom函数产生的全局成员。该成员为16位,必须位于lpClassName的低16位,高位必须为0。
   lpszWindow:指向一个指定了窗口名(窗口标题)的空结束字符串。如果该参数为 NULL,则为所有窗口全匹配。返回值:如果函数成功,返回值为具有指定类名和窗口名的窗口句柄。如果函数失败,返回值为NULL。
我现在要取窗体中多个文本框的数据,只会知道其类名为Edit,并不知道窗口名,所以,用这个函数并不能区别是哪个文本框。
PS:第一个窗体是自己用VC写的,有固定的控件ID。
试过用SPY++来查看Foxmail的个人地址簿的某一文本框的控件ID,每次打开对应的控件ID值都不一样。
-- 这个问题可以暂时不管,你们可以测试下,确实存在这个问题。


用spy++查查句柄,用用SendMessage WM_GETTEXT,密码框的话不行


::SendMessage(m_WndSecond, WM_GETTEXT, (sizeof(tchar1)/sizeof(TCHAR)), (LPARAM)(tchar1));
::GetWindowText(m_WndSecond, (LPWSTR)tchar1, sizeof(tchar1)/sizeof(TCHAR));
测试结果:以上2种方式都可以。


void ? CDlgcsdn20Dlg::OnButton8()
{
HWND ? hWnd ? = ? ::FindWindow( ? NULL ? ? , ? "未定标题 ? - ? 记事本 "? );
// ? 取得其中输入框的窗口句柄
HWND ? hEdit ? = ? ::GetDlgItem( ? hWnd ? , ? 0x0F ? ); ? ? // ? 这里0x0F是编辑框的ID,可在SPY++中观察得到
// ? 向输入框中填写 'a '
? ? ? ? char ? chs[1000];
::SendMessage( ? hEdit ? , ? WM_GETTEXT ? , ? (WPARAM)999 ? , ? (LPARAM)chs ? );
AfxMessageBox( ? chs);
}


怎么用一个程序向另一个程序发送字符并让其显示出来
首先通过FindWindow取得windows程序的窗口句柄,
然后通过GetDlgItem取得其中输入框的窗口句柄,
最后,向该窗口句柄发送WM_CHAR消息即可显示字符
例如,对于Notepad窗口,可以以如下的方式向其中输入一个 'a ':
// ? 取得记事本的窗口句柄
HWND ? hWnd ? = ? ::FindWindow( ? NULL ? ? , ? "未定标题 ? - ? 记事本 "? );
// ? 取得其中输入框的窗口句柄
HWND ? hEdit ? = ? ::GetDlgItem( ? hWnd ? , ? 0x0F ? ); ? ? // ? 这里0x0F是编辑框的ID,可在SPY++中观察得到
// ? 向输入框中填写 'a '
::SendMessage( ? hEdit ? , ? WM_CHAR? , ? (WPARAM) 'A ' ? , ? 0x00000001? );


枚举所有的edit窗口,发送WM_GETTEXT的消息,可以预先发送WM_GETTEXTLENGTH得到长度


要得到文本框的句柄可以用GetDlgItem函数;
如果你想得到里面的文本内容可以这样:
MFC的方法:
CString str;
GetDlgItem(IDC_EDIT)-<GetWindowText(str); //str里就是文本的内容了
这样就可以了。
补充:
你补充的描述,我还是不是太明白,最后的目的不就是为了得到文本框或编辑框中的字符吗,如果是这样的话,用我上面的方法完全就可以了。
首先如果有一个编辑框,你在其中输入的大量的字符,而你不执行任何操作的话,程序是无法获得这些字符的。使用GetWindowText函数后,就把这些字符全部存放到了变量str中。str是一个CString类型的变量,它的内存大小是根据字符串的多少自动分配的,这样还省了你自己分配内存呢。
如果想得到这些字符串的大小,可以使用CString类的GetLength函数:
int nLength = str.GetLengeh();//得到输入的字符串长度
另外CString类中还有很多字符串处理的函数方便你的调用。


不光是文本框或静态框(继承自CWnd的窗口),都有附加的text。
文本是没有句柄这个概念的,只有系统资源有,象窗口句柄、设备句柄、图标,图像等的句柄。
窗口都可以通过 GetWindowText(),SetWindowText()来读取设置窗口文本内容,没必要使用SendMessage来发送消息才取得。
得到的确实是文本内容的副本,原本是得不到的,微软将这个数据封闭了,在CWnd-<CCmdTarget-<CObject里面都没有文本成员,看来它们是在系统中将窗口句柄和文本内容绑定的,而不是放在类的成员函数中。


Win32 API对文本框发送消息(多个文本Edit,动态 控件 ID)
最近在群里有人说用Win32 Api不能对文本框设置内容(是别人写的一个程序,设置它的文本框的值).但是搞过win32的人都会说.这个应该不难啊,大概是搞.net的人,被微软宠坏了.基本都不要用win32 api,这里我也不讨论用这个东西好不好,反正有人有这个需求,就要去做这个东西,我就自己建了一个工程,只要得到这个窗体的句柄,然后向他发送消息就搞定了,用到FindWindow,SendMessage搞定就可以了,我们所做的最核心的内容就是要找句柄.
要在win32 api下面使用FindWindow,SendMessage,必须这2个声明
代码
 [DllImport( " user32.dll " ,?EntryPoint = " FindWindow " ,?SetLastError = true )]
public static extern IntPtr?FindWindow( string lpClassName, string lpWindowName);
 DllImport( " User32.dll " ,?EntryPoint = " SendMessage " ,?CharSet = CharSet.Auto)]
public static extern int SendTextMessage(
 IntPtr?hWnd,
int Msg,
int wParam,
string lParam
 );
记得这里要加上CharSet,否则发送中文可能是乱码,调用的时候
查找窗体的句柄,然后再在这个窗体下面查找这个文本框的句柄,窗口我们是根据窗体的标题文本来查找,文本控件时根据控件的类型来找.
IntPtr?hwndCalc = WinAPIuser32.FindWindow( null , " Form1aa " );
IntPtr?hwndtext = WinAPIuser32.FindWindowEx(hwndCalc, 0 , " Edit " , null );
 设置文本
WinAPIuser32.SendTextMessage(hwndtext,?MSCODE.WM_SETTEXT, 0 , " mextb1860第一个文本框 " );
轻松搞定了.很简单.
这个时候我想,窗体上只有一个文本框,也就是说一个Edit,查找起来是很方便,可是往往,我们在实际情况中,一个窗体上有很多文本框,我们要找到其中一个文本框设置它的值,这个时候你在用WinAPIuser32.FindWindowEx(hwndCalc, 0 , " Edit " , null ); 就做不到了.因为他得到的,始终是最后一个 文本框的句柄,也就是说如果页面上有
3个文本,你使用这个时候只会获取到最后一个文本框的句柄,如果你要设置第2个文本框你是做不到的,我们有2个办法,一个是EnumChildWindows方法来遍历下面的所有文本框,对这些文本框进行赋值,第2中方法就是根据控件ID来查找句柄,在一个程序编译完成以后,也就是发布给客户用的时候,窗体上的控件ID就是固定的了,不可改变,我这里说的控件ID不是指.net的立面一个TextBox控件的ID,而是在windows下面,显现出来的ID,这样我们就可以通过固定的ID来查找,注意ID是固定的,不会再改变,这样我们就可以用GetDlgItem的方法来通过ID号来获取句柄,这里我们先讲第2中方法,第一种方法,比较复杂,而且后面我会用第一种方法来做一个非常特殊的演示,那就是如果控件ID时动态的时候,我们也如何获取句柄
[DllImport( " user32.dll " ,?EntryPoint = " GetDlgItem " )]
public static extern IntPtr?GetDlgItem(
IntPtr?hDlg,
int nIDDlgItem
);
当然得到了句柄还有什么做不到的,对这3个文本发送消息,设置文本内容
代码
 IntPtr?hwndtext = WinAPIuser32.GetDlgItem(hwndCalc, 1247226 );
WinAPIuser32.SendTextMessage(hwndtext,?MSCODE.WM_SETTEXT, 0 , " mextb1860第一个文本框 " );
hwndtext = WinAPIuser32.GetDlgItem(hwndCalc, 1181678 );
WinAPIuser32.SendTextMessage(hwndtext,?MSCODE.WM_SETTEXT, 0 , " mextb1860第二个文本框 " );
hwndtext = WinAPIuser32.GetDlgItem(hwndCalc, 919180 );
WinAPIuser32.SendTextMessage(hwndtext,?MSCODE.WM_SETTEXT, 0 , " mextb1860第三个文本框 " );
一切很顺利,就像我们想的一样,3个文本框的内容都改变了,太好了,不过不要太高兴了,因为我们这里的ID是固定所以都硬编码进去了,在一般情况下是没有问题,因为大部分的都是固定的,这个时候我发现.net的程序的控件ID时随时改变的,而且每次运行一次ID都不一样,这个ID是跟着句柄改变,句柄是多少ID就是多少,老火啊.这回要根据ID来获取句柄是获取是行不通了,现在的情况是一个页面多个Edit类控件的ID是动态的,程序每次运行都不一样,不固定.
关闭程序,再重新打开,在看下ID
那么我现在用第二种办法来解决,请出 EnumChildWindows方法,这个方法比较特殊,有个一个参数是一个回调函数
[DllImport( " user32.dll " )]
public static extern int EnumChildWindows( int hWndParent,?CallBack?lpfn, int lParam);
CallBack是一个委托
代码
[DllImport( " user32.dll " )]
public static extern int EnumChildWindows( int hWndParent,?CallBack?lpfn, int lParam);
///
/// 回调业务
///
public delegate void CallBusiness(IntPtr?hwnd);
public delegate bool CallBack(IntPtr?hwnd, int lParam);
///
/// 遍历子窗体的父窗体句柄
///
public static CallBack?callBackEnumChildWindows = new CallBack(ChildWindowProcess);
///
/// 委托业务,需要客户端添加
///
public static CallBusiness?CallFuntion;
///
/// 遍历子窗体或控件
///
///
///
///
public static bool EnumChildWindows(IntPtr?hWnd, int lParam)
{
EnumChildWindows(hWnd.ToInt32(),?callBackEnumChildWindows, 0 );
return true ;
}
///
/// 获取类名字
///
/// 需要获取类名的句柄
/// 类名(执行完成以后查看)
/// 缓冲区
///
[DllImport( " user32.dll " ,?EntryPoint = " GetClassName " )]
public static extern int GetClassName(
IntPtr?hwnd,
StringBuilder?lpClassName,
int nMaxCount
);
///
/// 遍历子控件
///
///
///
///
public static bool ChildWindowProcess(IntPtr?hwnd, int lParam)
{
if (CallFuntion != null )
{
CallFuntion(hwnd);
}
return true ;
}
EnumChildWindows用来遍历所有的子控件的句柄,有一个回调函数,CallBusiness也是一个代理,是提供给客户端调用的时候来编写逻辑的.代码很简单,应该很容易理解,客户端调用的代码,因为是.net开发的程序所以 Edit的控件类型有点不一样,不过没关系,不影响我们查找
代码
List < IntPtr /> list = new List < IntPtr /> ();
WinAPIuser32.CallFuntion = delegate (IntPtr?enumIntPtr)
{
StringBuilder?s = new StringBuilder( 2000 );
WinAPIuser32.GetClassName(enumIntPtr,?s, 255 );
if (s.ToString() == " WindowsForms10.EDIT.app.0.378734a " )
{
list.Add(enumIntPtr);
}
};
WinAPIuser32.EnumChildWindows(hwndCalc, 0 );
WinAPIuser32.CallFuntion = null ;
// 第1个文本框
WinAPIuser32.SendTextMessage(list[ 2 ],?MSCODE.WM_SETTEXT, 0 , " mextb1860第一个文本框 " );
// 第2个文本框
WinAPIuser32.SendTextMessage(list[ 1 ],?MSCODE.WM_SETTEXT, 0 , " mextb1860第二个文本框 " );
// 第3个文本框
WinAPIuser32.SendTextMessage(list[ 0 ],?MSCODE.WM_SETTEXT, 0 , " mextb1860第三个文本框 " );
代码会提供下载,不明白的可以自己仔细看看.

(由于是从手机粘贴进来的,有的地方有多余的?,使用时要去掉)

 

0

阅读(662)评论 (0)收藏(0)转载原文喜欢打印举报
加载中,请稍候......
前一篇:[转载]VC++中如何给对话框加背景图片
后一篇:[转载]VC中进度条实时显示的解决方法


0 0
原创粉丝点击