python获取Powerbuilder窗口数据

因工作需要,需要获取一个windos客户端软件控件的值,使用win32api.SendMessage获取不到。
使用spy++观察发现标题和内容全是None,

img

晚上搜了下,发现这种属于Powerbuilder语言开发出的数据窗口,也叫pb数据窗口

求指点怎么用python怎么获取这个窗口的数据吗? 卡了好久, 平台最高悬赏只有0.5k,如果能解决,愿意另外有偿感谢

补充:我不确定是Powerbuilder语言开发的

https://bbs.csdn.net/topics/70097737
这个链接的问题和我一样,但是八九年以前的了,而且也没有解决

一、原理

PB数据窗口有一个导出文件的函数,通过调用API向数据窗口传递特定的消息,它就乖乖的弹出一个导出数据文件的窗口了。

二、实现步骤

 1、获取数据窗口的句柄。使用spy++工具获取,或者使用工具SpyLite24(http://www.asanscape.com/可以免费下载)

 2、调用让数据窗口导出文件的消息。SendMessage(pbdw_handle, 1305, 0, 0)

三、C#代码

public class Win32API
{
    [DllImport("user32.dll", CharSet=CharSet.Auto)]
    public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
}

调用示例:

       private void button_Click(object sender, EventArgs e)
    {
        try
        {

            IntPtr mwh = (IntPtr)Convert.ToInt32(tbPBDWHandle.Text);
            int result = Win32API.SendMessage(mwh, 1305, 0, 0);

            if (result == 0)
            {
                MessageBox.Show("操作失败!请确定数据窗口句柄是否正确!");
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }

四、PBDW的其他函数和查看资料

img

Win32 API不能解决问题的话,那么思路应该是从进程空间的固定位置读取到这个值。控件中的值,肯定不会放在栈上,一般是在全局变量里,保证了地址是不会变的。

下面这篇仔细阅读,抄作业就是了!

https://www.cnblogs.com/predator-wang/p/4788643.html

最后,用PYTHON调用C,完成整个事情。

可参考

外部程序读取Powerbuilder的数据窗口数据的方法_火山码哥的博客-CSDN博客 一、原理    PB数据窗口有一个导出文件的函数,通过调用API向数据窗口传递特定的消息,它就乖乖的弹出一个导出数据文件的窗口了。 二、实现步骤     1、获取数据窗口的句柄。使用spy++工具获取,或者使用工具SpyLite24(http://www.asanscape.com/可以免费下载)     2、调用让数据窗口导出文件的消息。SendMessage(pbdw_ha https://blog.csdn.net/xmzhaoym/article/details/3637267?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-3637267-blog-316283.pc_relevant_multi_platform_whitelistv3&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-3637267-blog-316283.pc_relevant_multi_platform_whitelistv3&utm_relevant_index=1

你试没试过用win32gui来获取

发私信给你个工具试试

看看这个能不能给你点帮助:外部程序读取Powerbuilder的数据窗口数据的方法_火山码哥的博客-CSDN博客

有两个点不知道你试过没:1)是否不同的控件需要使用不同的方法获取文本,比如,标签、按钮等的文本获取方式与下拉列表的文本获取方式不同;2)是否可能获取到的控件本身就是空的,而你想获取的其实在下一层

可以试试 绝对值的方式,直接操作坐标

参考一下这一个https://www.cnblogs.com/yarightok/p/6800540.html

程序涉密嘛?可以发给示例程序给我本地实验不?

如果现有方案无效的话,可以尝试两个思路:

  1. 逆向,需要专业安全人员对Powerbuilder进行逆向获取信息。然后将其方法写成代码。
  2. 可以使用截图,然后再使用OCR(推荐使用paddleocr)来迂回解决。这两步均可以自动化实现。

试一试c#的代码可不可以

   public class Win32API
    {
        [DllImport("user32.dll", CharSet=CharSet.Auto)]
        public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
    }

 

调用示例:

           private void button_Click(object sender, EventArgs e)
        {
            try
            {

                IntPtr mwh = (IntPtr)Convert.ToInt32(tbPBDWHandle.Text);
                int result = Win32API.SendMessage(mwh, 1305, 0, 0);

                if (result == 0)
                {
                    MessageBox.Show("操作失败!请确定数据窗口句柄是否正确!");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }


当然您也可以试一试这一个:

Function integer SndMsg(long hWnd, long uMsg, long wp, &
ref string filename) library "user32.dll" Alias For "SendMessageA"


long ll_dw_handle
ll_dw_handle = handle(dw_1)
string s
s="c:\111.txt"     这里把数据窗口的内容存到了文本文件111.txt
SndMsg(ll_dw_handle, 1305, 2, s)

可以转换下思路,尝试下使用截图,然后定位获取数据。

这边可以帮您看看,有过这方面的逆向经验,已私信楼主。

目前来看
一般就是三种方法,

  • 1、使用window的窗口句柄来获取信息
  • 2、使用OCR识别工具来获取
  • 3、如果这个程序是你有代码的话,或许二次开发来发送一下信息是更好的选择。

但是按照你目前的回复来说,

  • 第一方法
    大多数可能更本获取不到具体的值
  • 第二种方法
    OCR方法你正在使用,并且觉得准确度不高,所以要么选择更好的OCR工具或者方法(比如一些大公司的收费的OCR工具),要么就废弃这种方法。
  • 第三种方法
    需要具体的代码,以及二次开发

至于其他的方法,如果方便的话,需要发一下具体的程序和需要获取的文本截图到网盘,
需要本地测试才能看看是否有具体的方法可行。


另外
如果没有更好的解决方法的话
个人觉得可能继续你原先的OCR方法可能更好点或者说可行性更高,

1、通过Python脚本或者其他脚本来进行具体的截图
2、然后通过OCR API来识别获取到具体值

这些大概就是你原先的OCR步骤,
你可能需要做的就是
挑选一些更加准确的OCR工具或者方法,免费的或者一些大公司的收费的OCR解决方法

注:是否选择收费的API接口看你自己需求

浏览器搜索关键词OCR API查找


如有问题及时沟通

使用ocr是最简单的办法,有一款可以识别数字的免费ocr识别软件,tesseract,可以先用图像处理opencv获取窗口位置,简单的阈值分割就可以得到弹出窗口,由于窗口句柄和值是固定位置,得到对应像素位置的crop数值对应的空格,调用tesseract识别数字即可获得。实在搞不定可以私信我可以发代码给你。


long ll_dw_handle
ll_dw_handle = handle(dw_1)
string s
s="c:\111.txt"
SndMsg(ll_dw_handle, 1305, 2, s)

如果无法理解可以参考C#这个链接详情比较详细,逻辑原理都是一样,只是语法不同。

这种需求确实用C#更好实现

要先确定应用程序的的backend是 是什么。
不过win上就支持两种,你现在用的应该是win32,换uia试一下。
不行的话,python该自动化思路无法实现。
app = Application(backend='uia')

spy++检查不到可以换其它工具https://github.com/blackrosezy/gui-inspect-tool

使用pyqt

可以试试这个

#include<windows.h>
#include<conio.h>
#include<cstdio>

BOOL CALLBACK EnumChildProc(HWND hwndChild, LPARAM lParam) {
    LPRECT rcParent;
    int i, idChild;
    idChild = GetWindowLong(hwndChild, GWL_ID);
    char ClassName[200], Title[200],Text[200];
    GetWindowText(hwndChild, Title, 200);
    GetClassName(hwndChild, ClassName, 200);
    printf("Title:%s\n", Title);
    GetWindowText(hwndChild,Text,200);
    printf("内容:%s\n", Text);
    printf("----------------\n");
    HINSTANCE childHS = (HINSTANCE)GetWindowLong(hwndChild, GWL_HINSTANCE);
    WNDCLASSEX cls1;
    GetClassInfoEx(childHS, ClassName, &cls1);
    printf("结构体大小:%d\n", cls1.cbSize);
    printf("窗口类样式:%d\n", cls1.style);
    printf("窗口处理函数:0X%X\n", cls1.lpfnWndProc);
    printf("窗口类的额外信息:%d\n", cls1.cbClsExtra);
    printf("窗口实例的额外信息:%d\n", cls1.cbWndExtra);
    printf("本模块的实例句柄:0X%X\n", cls1.hInstance);
    printf("窗口类图标:0X%X\n", cls1.hIcon);
    printf("窗口类鼠标:0X%X\n", cls1.hCursor);
    printf("窗口类的背景刷:0X%X\n", cls1.hbrBackground);
    printf("窗口类的菜单名:%s\n", cls1.lpszMenuName);
    printf("窗口类名字:%s\n", cls1.lpszClassName);
    printf( "窗口类小图标:%s\n", cls1.hIconSm);
    printf("控件ID:%d\n",GetDlgCtrlID(hwndChild));
    printf("----------------\n");
    return TRUE;
}
int main() {
    HWND hwnd;
    char Title[200]="Test";
    hwnd = FindWindow(NULL,Title);
    EnumChildWindows(hwnd, EnumChildProc, NULL);
    return 0;
}

我可以准确的告诉你,如果是自绘出来的,或者只要不是win平台的控件,是根本获取不到控件句柄的,所以建议你获取到整个窗口句柄,然后进行模拟操作吧,比如可以发送消息点击固定的位置的按钮,或者按照窗口句柄,区域性的截取窗口,然后进行识别图片进行操作,这都是可以的,并不是说操作控件就非要知道控件句柄,没有控件句柄一样可以操作

楼主可以尝试下这个工具inspect.exe,可以在Windows SDK文件夹下找到该inspect.exe工具,该文件夹通常是C:\Program Files (x86)\Windows Kits\10\bin\x86


这个方案是否可用?

试试这个工具
获取数据窗口的句柄。使用spy++工具获取,或者使用工具SpyLite24
http://www.asanscape.com/
望采纳谢谢啦

我觉得可以有两种方案解决你的问题:
1、第一种方式通过窗口句柄和坐标获取到控件位置和控件绘制信息,从绘制的图片信息中ocr解析得到内容,这种方式因为是反向识别因此效率较低,准确率也不能完全保证,是比较被动的方式;
2、第二种方式就是在pb中开发,通过pb获取到窗口和控件,能够直接得到控件的值并进行操作和修改,这种方式需要在pb中开发并且运行,可以直接运用pb的内部方法直接获取,不会有效率和准确性的问题,应能较好满足你的需求。
从你的需求角度,个人建议采用第二种方式实现,只需简单掌握pb开发就能实现。有帮助请采纳谢谢!

如果随便能获取,那操作系统层面岂不是有重大漏洞。

这个用 QTP 应该可以做到。我原先就用QTP获取并定位windows桌面上的窗体和内容。 python与qtp结合用。

1、第一种方式通过窗口句柄和坐标获取到控件位置和控件绘制信息,从绘制的图片信息中ocr解析得到内容,这种方式因为是反向识别因此效率较低,准确率也不能完全保证,是比较被动的方式;
2、第二种方式就是在pb中开发,通过pb获取到窗口和控件,能够直接得到控件的值并进行操作和修改,这种方式需要在pb中开发并且运行,可以直接运用pb的内部方法直接获取,不会有效率和准确性的问题,应能较好满足你的需求。
从你的需求角度,个人建议采用第二种方式实现,只需简单掌握pb开发就能实现

能有个Powerbuilder 实例程序就方便了, 没有测试对象, 空谈理论 都不好使: 也可以考虑一下绕过Powerbuilder 直接从Powerbuilder 的数据源获取原始数据嘛,

1、不是所有程序都可以通过系统来获取其句柄,进而拿到程序进程的数据,跨进程的通信其实是很复杂的
2、win32提供的api可以访问的窗口组件,以及可以获取的窗口组件属性有限,其实很多时候不能满足全部需求。
3、控件的句柄会作为回调函数的参数传进去。"属性"的话,只能通过API获取。主要使用 "SendMessage",因为SDK中程序和控件的交互基本都是通过 windows 消息实现的。没有办法简单地获得一个控件的 "所有属性值",只能通过一个一个的方式按需读取。
4、尝试一下这款工具 "Control Spy" , 但是这个工具只能快速了解原生组件,对于少见的第三方组件,没有太大的作用。

一、原理

PB数据窗口有一个导出文件的函数,通过调用API向数据窗口传递特定的消息,它就乖乖的弹出一个导出数据文件的窗口了。
二、实现步骤

1、获取数据窗口的句柄。使用spy++工具获取,或者使用工具SpyLite24(http://www.asanscape.com/可以免费下载

2、调用让数据窗口导出文件的消息。SendMessage(pbdw_handle, 1305, 0, 0)
三、C#代码

public class Win32API
{
    [DllImport("user32.dll", CharSet=CharSet.Auto)]
    public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
}

调用示例:

       private void button_Click(object sender, EventArgs e)
    {
        try
        {
 
            IntPtr mwh = (IntPtr)Convert.ToInt32(tbPBDWHandle.Text);
            int result = Win32API.SendMessage(mwh, 1305, 0, 0);
 
            if (result == 0)
            {
                MessageBox.Show("操作失败!请确定数据窗口句柄是否正确!");
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }