请问,获取另一个软件中控件句柄的问题

sg_linfeng 2014-06-22 02:17:32
我想先用A程序获取B程序中控件句柄,并由A程序对B程序中控件进行一些相应的设置。
我是先用FindWindow先获取整个软件窗体的句柄,通过软件窗体的句柄,用FindWindowEx继续获取软件窗体里的控件,但句柄值为零,这是是什么原因造成的呢?用SPY++去查看软件中的控件属性,按照SPY++显示类名,在FindWindowEx函数中进行类名的参数设置,得到的结果依然是零。
(B程序中控件的布局是由一个GroupBox,标题为"设定变量",用SPY++查看的类名为Button;在GroupBox里面有一个ComboBox,用spy++查看的类名为ComboBox,窗口标题为"p还";在GroupBox里面有一个RichBox,用spy++查看的类名为RichEdit20A,窗口标题为空或为一串数字;还有两个按钮,一个是重置,用spy++查看的类名为Button,窗口标题为"重置",另一个按钮是应用,用spy++查看的类名为Button,窗口标题为"应用")

代码:
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim hwnd0 As Integer = 0
hwnd0 = FindWindow(vbNullString, “B程序")

Dim hwnd1 As Integer = 0
hwnd1 = FindWindowEx(hwnd0, 0&, "Button", "设定变量") '不管把Button改成别的hwnd1都是为零
End Sub


如果需要更改ComboBox里的值(ComboBox里有三个固定值:Code、Box、TxtCode),每改变一个值,下面的RichBox里的内容会自动清空,并由A程序赋值给RichBox,此段代码该如何写呢?
...全文
4721 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
wwwhuangxiaobiao 2016-05-14
  • 打赏
  • 举报
回复
可以给我一份吗?
Carlven2012 2014-08-30
  • 打赏
  • 举报
回复
不要用setwindowtext , 好像不行,我是用PostMessage实现的:

    aWnd = FindWindow("notepad", vbNullString)
    If aWnd = 0 Then
        Shell "notepad.exe", vbNormalNoFocus
        aWnd = FindWindow("notepad", vbNullString)
    End If

    Dim editWnd As Long
    editWnd = FindWindowEx(aWnd, 0, "edit", vbNullString)
    
    Dim stmp As String, c As String
    stmp = Text1.Text
    For i = 1 To Len(stmp)
        c = Mid(stmp, i, 1)
        call PostMessage(editWnd, WM_CHAR, CLng(Asc(c)), 0)
        'WM_SETTEXT 失败,为乱码
        Sleep 100
    Next
PctGL 2014-08-29
  • 打赏
  • 举报
回复
引用 14 楼 sg_linfeng 的回复:
获取控件的句柄已解决。 我是用对窗体控件遍历的方法,将句柄取出。 现在遇到一个新的问题,就是用SetWindwText设置或更变不了TextBox或RichTextBox里的内容,但可以设置窗体的标题。 这就真的很奇怪了,搞不明白怎么回事,还得麻烦各位,帮我看看程序有什么问题。
    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        '_intCboHwnd是设置变量里ComboBox的句柄,_intTxtHwnd是设置变量里RichTextBox的句柄
        SendMessage(_intCboHwnd, CB_SETCURSEL, 0, 0)    '指向指定记录号
        'SendMessage(_intTxtHwnd, WM_SETFOCUS, 0&, 0&)

         SetWindowText(_intTxtHwnd, "0537")
    End Sub
我当时也怀疑过是不是句柄不正确导致的,我又重新做了两个窗体Form1和Form2,Form1负责控制,Form2负责接收(Form2里有一个RichTextBox和一个TextBox),但结果一样,就只能更改Form2窗体的标题。
Public Class Form1
    Private Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" (ByVal hwnd As Integer, ByVal lpString As String) As Integer
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
    Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hwnd1 As Integer, ByVal hWnd2 As Integer, ByVal lpsz1 As String, ByVal lpsz2 As String) As Integer
    Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim hwnd0 As Integer = 0
        
        ‘可以更改Form2的窗体标题
        hwnd0 = FindWindow(vbNullString, "Form2")
        SetWindowText(hwnd0, "更改1")
        
        ‘这是RichTextBox控件,程序执行完后这段后,RichTextBox控件没有任何的变化
        hwnd0 = FindWindowEx(hwnd0, 0&, "WindowsForms10.RichEdit20W.app.0.bf7771", "")
        SetWindowText(hwnd0, "更改2")
        
        ‘这是TextBox控件,程序执行完后这段后,TextBox控件没有任何的变化
        hwnd0 = FindWindowEx(hwnd0, 0&, "WindowsForms10.EDIT.app.0.bf7771", "")
        SetWindowText(hwnd0, "更改3")
    End Sub
End Class
请问各大高手,这该怎么改呢?
在setwindowtext 之前确认一下,句柄是否正确 你确定,那个textbox和richbox 的类名没写错? 貌似这是。net的程序窗口类名 如果setwindowtext 不行, 可以试试 EM_ReplaceSel,EM_xxx, 最好先spy监看一下消息
赵4老师 2014-06-25
  • 打赏
  • 举报
回复
仅供参考,尽管不是VB6:
void MyGetListViewItem(HWND hWindow) {

    int          nLVItemCount;
    int          nColumns;
    DWORD        dwProcessID;
    HANDLE       hProcess;
    HWND         hHeaderCtrl;
    LVITEM       lvItemLocal;
    HDITEM       hdItemLocal;
    DWORD        dwBytesRead, dwBytesWrite;
    BOOL         bSuccess,bWriteOK;
    LPVOID       lpTextRemote;
    LPVOID       lpListItemRemote;
    LPVOID       lpHeadItemRemote;
    int i,j;

    GetWindowThreadProcessId(hWindow,&dwProcessID);
    hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessID);
    if (!hProcess) goto ABORT0;
    lpTextRemote=VirtualAllocEx(hProcess,NULL,nMaxLen+1,MEM_COMMIT,PAGE_READWRITE);
    if (!lpTextRemote) goto ABORT1;
    lpListItemRemote=VirtualAllocEx(hProcess,NULL,sizeof(LVITEM),MEM_COMMIT,PAGE_READWRITE);
    if (!lpListItemRemote) goto ABORT2;
    lpHeadItemRemote=VirtualAllocEx(hProcess,NULL,sizeof(HDITEM),MEM_COMMIT,PAGE_READWRITE);
    if (!lpHeadItemRemote) goto ABORT3;

    nLVItemCount=ListView_GetItemCount(hWindow);
    hHeaderCtrl =ListView_GetHeader(hWindow);
    nColumns    =Header_GetItemCount(hHeaderCtrl);

//  init();
    if (nColumns<=0) {
        nColumns=1;
    } else {
        ln[0]=0;
        for (j=0;j<nColumns;j++) {
            ZeroMemory(szBuf,nMaxLen+1);
            bWriteOK= WriteProcessMemory(hProcess,lpTextRemote,(LPVOID)szBuf,nMaxLen+1,(LPDWORD)&dwBytesWrite);
            if (!bWriteOK) goto ABORT4;
            hdItemLocal.mask=HDI_TEXT;
            hdItemLocal.cchTextMax=nMaxLen;
            hdItemLocal.pszText=(LPTSTR)lpTextRemote;
            dwBytesWrite=0;
            bWriteOK=WriteProcessMemory(hProcess,lpHeadItemRemote,(LPVOID)&hdItemLocal,sizeof(HDITEM),(LPDWORD)&dwBytesWrite);
            if (!bWriteOK) goto ABORT4;
            SendMessage(hHeaderCtrl,HDM_GETITEM,(WPARAM)j,(LPARAM)lpHeadItemRemote);
            bSuccess=ReadProcessMemory(hProcess,lpTextRemote,szBuf,nMaxLen+1,&dwBytesRead);
            if (!bSuccess) goto ABORT4;
            if (j>0) strcat(ln,"|");
            strstrip(szBuf1,szBuf);
            strcat(ln,szBuf1);
        }
        add1(ln);
    }
//  printf("ListView的Columns数: %d\n",nColumns);
//  printf("---------------------------\n");
    for (i=0;i<nLVItemCount;i++) {
        ln[0]=0;
        for (j=0;j<nColumns;j++) {
            ZeroMemory(szBuf,nMaxLen+1);
            bWriteOK= WriteProcessMemory(hProcess,lpTextRemote,(LPVOID)szBuf,nMaxLen+1,(LPDWORD)&dwBytesWrite);
            if (!bWriteOK) goto ABORT4;
            lvItemLocal.iItem=i;
            lvItemLocal.iSubItem=j;
            lvItemLocal.mask=LVIF_TEXT;
            lvItemLocal.cchTextMax=nMaxLen;
            lvItemLocal.pszText=(LPTSTR)lpTextRemote;
            dwBytesWrite=0;
            bWriteOK=WriteProcessMemory(hProcess,lpListItemRemote,(LPVOID)&lvItemLocal,sizeof(LVITEM),(LPDWORD)&dwBytesWrite);
            if (!bWriteOK) goto ABORT4;
            SendMessage(hWindow,LVM_GETITEMTEXT,(WPARAM)i,(LPARAM)lpListItemRemote);
            bSuccess=ReadProcessMemory(hProcess,lpTextRemote,szBuf,nMaxLen+1,&dwBytesRead);
            //从指定进程存储空间读取文本
            if (!bSuccess) goto ABORT4;
            if (j>0) strcat(ln,"|");
            strstrip(szBuf1,szBuf);
            strcat(ln,szBuf1);
        }
        add1(ln);
    }
ABORT4:
    VirtualFreeEx(hProcess,lpHeadItemRemote,0,MEM_RELEASE);
ABORT3:
    VirtualFreeEx(hProcess,lpListItemRemote,0,MEM_RELEASE);
ABORT2:
    VirtualFreeEx(hProcess,lpTextRemote,0,MEM_RELEASE);
ABORT1:
    CloseHandle(hProcess);
ABORT0:
//  over();
    return;
}
//---------------------------------------------------------------------------
Tiger_Zhao 2014-06-25
  • 打赏
  • 举报
回复
FindWindowEx 返回值为 0 吧!

调用 API 是要用 vbNullString 表示 null,"" 表示长度为 0 的字符串,意义完全不同。
sg_linfeng 2014-06-25
  • 打赏
  • 举报
回复
获取控件的句柄已解决。 我是用对窗体控件遍历的方法,将句柄取出。 现在遇到一个新的问题,就是用SetWindwText设置或更变不了TextBox或RichTextBox里的内容,但可以设置窗体的标题。 这就真的很奇怪了,搞不明白怎么回事,还得麻烦各位,帮我看看程序有什么问题。
    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        '_intCboHwnd是设置变量里ComboBox的句柄,_intTxtHwnd是设置变量里RichTextBox的句柄
        SendMessage(_intCboHwnd, CB_SETCURSEL, 0, 0)    '指向指定记录号
        'SendMessage(_intTxtHwnd, WM_SETFOCUS, 0&, 0&)

         SetWindowText(_intTxtHwnd, "0537")
    End Sub
我当时也怀疑过是不是句柄不正确导致的,我又重新做了两个窗体Form1和Form2,Form1负责控制,Form2负责接收(Form2里有一个RichTextBox和一个TextBox),但结果一样,就只能更改Form2窗体的标题。
Public Class Form1
    Private Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" (ByVal hwnd As Integer, ByVal lpString As String) As Integer
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
    Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hwnd1 As Integer, ByVal hWnd2 As Integer, ByVal lpsz1 As String, ByVal lpsz2 As String) As Integer
    Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim hwnd0 As Integer = 0
        
        ‘可以更改Form2的窗体标题
        hwnd0 = FindWindow(vbNullString, "Form2")
        SetWindowText(hwnd0, "更改1")
        
        ‘这是RichTextBox控件,程序执行完后这段后,RichTextBox控件没有任何的变化
        hwnd0 = FindWindowEx(hwnd0, 0&, "WindowsForms10.RichEdit20W.app.0.bf7771", "")
        SetWindowText(hwnd0, "更改2")
        
        ‘这是TextBox控件,程序执行完后这段后,TextBox控件没有任何的变化
        hwnd0 = FindWindowEx(hwnd0, 0&, "WindowsForms10.EDIT.app.0.bf7771", "")
        SetWindowText(hwnd0, "更改3")
    End Sub
End Class
请问各大高手,这该怎么改呢?
of123 2014-06-24
  • 打赏
  • 举报
回复
句柄变量使用 Long 型。
Tiger_Zhao 2014-06-24
  • 打赏
  • 举报
回复
虽然没用过 AccExploer2,但是“NAMELESS[窗口-Visible]”表示没有取到类名没错吧?
作为一个专业工具会取不到类名?
首先怀疑杀毒软件之类的屏蔽了某些跨进程操作!
sg_linfeng 2014-06-23
  • 打赏
  • 举报
回复
我用AccExploer2.0查了一下B程序的结构,如下: B程序[窗口-Visible] ┗---B程序[对话框-Visible] ┗---NAMELESS[窗口-Visible] ┗---NAMELESS[对话框-Visible] ┗---NAMELESS[窗口-Visible] ┗---NAMELESS[对话框-Visible] ┗---应用[窗口-Visible] ┗---NAMELESS[窗口-Visible] ‘这个是那个设定变量里的ComboBox ┗---NAMELESS[组合框-Visible] ┗---NAMELESS[文字-Visible] ┗---打开[按下按钮-Visible] ┗---NAMELESS[组合框-Visible] ┗---NAMELESS[列表项目-Invisible] ┗---NAMELESS[列表项目-Invisible] ┗---NAMELESS[列表项目-Invisible] ┗---重置[窗口-Visible] ┗---NAMELESS[窗口-Visible] ‘这个是那个设定变量里的RichTextBox ┗---NAMELESS[可编辑文本-Visible]
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        ‘#32770是窗口或对话框的类名,hwnd0~hwnd4均可获取相应的句柄

        Dim hwnd0 As Integer = FindWindow(vbNullString, ListBox1.Text)
        
        Dim hwnd1 As Integer = FindWindowEx(hwnd0, 0&, "#32770", "")

        Dim hwnd2 As Integer = FindWindowEx(hwnd0, hwnd1, "#32770", "")

        Dim hwnd3 As Integer = FindWindowEx(hwnd0, hwnd2, "#32770", "")

        Dim hwnd4 As Integer = FindWindowEx(hwnd0, hwnd3, "#32770", "")

        Dim hwnd5 As Integer = FindWindowEx(hwnd4, 0&, "Button", "应用")

    End Sub
我是先按照B程序的窗体名,用FindWindow函数获取B程序窗体的句柄;然后按照用AccExploer查询出来的结构一层层进入,但到了最后hwnd5还是为零。 我想应该是程序没有写对,导致hwnd5为零,请问各大高手,程序该如何写呢?
Tiger_Zhao 2014-06-23
  • 打赏
  • 举报
回复
请先确认 hwnd0 非零!
sg_linfeng 2014-06-23
  • 打赏
  • 举报
回复
我也查了一下资料,GroupBox是属于“Button“。 GroupBox类名为Button的, BS_PUSHBUTTON,BS_DEFPUSHBUTTON //按钮 BS_CHECKBOX //多选、单选 BS_GROUPBOX //组选框 BS_RADIOBUTTON // 单选组合框
sg_linfeng 2014-06-23
  • 打赏
  • 举报
回复


就是这个界面
我用SPY++ 查设定变量框的类名,类名是Button

试过用坐标定位的方法,可以取到“设定变量”的句柄,但要获取“设定变量”里面的控件,试过两种方法:1.通过FindWindowsEx来获取框里的控件句柄,结果为零,2.尝试直接用坐标定位,结果是“设定变量”的句柄。

还试过用GetDlgItem函数,获取“设定变量”的句柄,但获取出来句柄为零。

4楼的朋友,我刚刚也试了,把“Button”改成vbnullstring,结果为零。
of123 2014-06-23
  • 打赏
  • 举报
回复
将 "Button" 改为 vbNullString 试试。
赵4老师 2014-06-23
  • 打赏
  • 举报
回复
仅供参考,尽管是C++
HWND MyFindListViewWindow()
{
    const int MyMaxParentWinCount = 4;
    // 父窗口类名数组
    char *A_szClassName[MyMaxParentWinCount] = {
        "ThunderRT6FormDC",
        "ThunderRT6Frame",
        "ThunderRT6Frame",
        "ListView20WndClass"
    };
    // 父窗口标题数组
    char *A_szWinName[MyMaxParentWinCount] = {
        Title,
        "",
        "",
        ""
    };
    // 首先求得顶级父窗口
    HWND hMainWin = FindWindow(A_szClassName[0], A_szWinName[0]);
    if (NULL==hMainWin) {
        return NULL;
    }
    // 逐次用FindWindowEx函数求出各级子窗口
    HWND hNextChildWin=NULL;

    HWND hLastWin=NULL;
    for (int i=1; i<MyMaxParentWinCount; i++) {
        if (1==i) {
            hMainWin = FindWindowEx(hMainWin,NULL         ,A_szClassName[i],A_szWinName[i]);
        } else if (2==i) {
            hNextChildWin = FindWindowEx(hMainWin,hNextChildWin,A_szClassName[i],A_szWinName[i]);
            if (NULL==hNextChildWin) break;//
            hNextChildWin = FindWindowEx(hMainWin,hNextChildWin,A_szClassName[i],A_szWinName[i]);
            hLastWin=hNextChildWin;
        } else {
            hLastWin = FindWindowEx(hLastWin,NULL         ,A_szClassName[i],A_szWinName[i]);
        }
    }
    return hLastWin;
}
//---------------------------------------------------------------------------
Tiger_Zhao 2014-06-23
  • 打赏
  • 举报
回复
展开 Spy++ 右侧的树结构,确认 “设定变量” 在 hwnd0 下面。
用 Spy++ 获取的句柄,调用 GetClassName 和 GetWindowText 确认一下类名和标题。
sg_linfeng 2014-06-23
  • 打赏
  • 举报
回复
引用 7 楼 Tiger_Zhao 的回复:
请先确认 hwnd0 非零!
hwnd0是非零,hwnd0取的是B程序运行的窗体句柄。
zzyong00 2014-06-22
  • 打赏
  • 举报
回复
用spy++查查类名
threenewbee 2014-06-22
  • 打赏
  • 举报
回复
GroupBox的类名怎么是Button呢?你看错了吧。
sg_linfeng 2014-06-22
  • 打赏
  • 举报
回复

1,486

社区成员

发帖
与我相关
我的任务
社区描述
VB API
社区管理员
  • API
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧