SendMessage WM_GETCONTROLNAME PInvoke错误 [英] SendMessage WM_GETCONTROLNAME PInvoke Error

查看:91
本文介绍了SendMessage WM_GETCONTROLNAME PInvoke错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

全晚,



希望你能在这里提供一些建议。我试图从另一个应用程序获取窗口的控件名称。我已经设法通过另一个用户预先编写的类来获取hWnd(从Codeproject获得)。



所以我声明SendMessage如下:

Evening All,

Hoping you can offer some advice here. I am trying to get the control name of a window from another application. I have managed to get the hWnd via a class pre-written by another user (Obtained from Codeproject).

So i am declaring the SendMessage as follows:

Declare Function SendMessageS Lib "user32" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long





我把它放到一个虚拟的应用程序中,所以进入了form_load事件。我循环通过顶层窗口,抓住句柄,然后枚举子窗口,确保MainWindowTitle匹配特定的字符串值。



然后从此枚举所有子窗口并尝试执行SendMessage以从中获取控件名称。然而,当它达到这一点时,它会抛出一个PInvoke错误消息,如下所示:





I have put this into a dummy application so chucked into form_load event. I loop through the top level windows, grab the handle and then enumerate child windows ensuring he MainWindowTitle matches a specific string value.

Then from this i enumerate all the child windows and try to perform a 'SendMessage' to get the control name from it. However when it hits this point it then throws a PInvoke error message as follows:

A call to PInvoke function 'WindowsApplication1!WindowsApplication1.Form1::SendMessageS' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.





这是我的Form_Load代码,如果你欣赏它可以指出我正确的方向。





Here is my Form_Load code, appreciate it if you could point me in the right direction.

Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    Dim EnumWind As New WindowEnumeration
    Dim clsName As String = "WindowsForms10.Window.8.app.0.378734a"

    'Get a List of Top Window Belonging to: "WindowsForms10.Window.8.app.0.378734a"
    For Each TopWin As ApiWindow In EnumWind.GetTopLevelWindows(clsName)
        'Check the title of the Screen
        If (TopWin.MainWindowTitle = "Card Payment Screen") Then
            'We have the payment Screen

            'Enumerate all Child Windows (Controls) Passing Parent hWnd
            For Each ChildWin As ApiWindow In EnumWind.GetChildWindows(TopWin.hWnd)
                Dim WM_GETCONTROLNAME As Long = 50721
                Dim sText As String = Space(100)
                Try
                    'We get a stack PInvoke Error Here
                    SendMessageS(ChildWin.hWnd, WM_GETCONTROLNAME, 100, sText)
                Catch ex As Exception

                End Try
            Next
        End If
    Next
End Sub







非常感谢

Dev




Many Thanks
Dev

推荐答案

为你的P /调用声明, wMsg 参数应该是整数,而不是 Long 。参数是32位整数,而 Long 是64位整数。



wParam 参数和返回值应该是 IntPtr ,因为它们的大小取决于你是以32位还是64位运行比特进程。



当你希望函数更新一个字符串参数时,你应该传递一个 StringBuilder 。在.NET中, String 类型是不可变的。



然而,从我读过的,当窗口属于另一个进程,您必须为该进程中的名称分配一个缓冲区。这意味着你需要调用 OpenProcess VirtualAllocEx SendMessage ReadProcessMemory ,最后是 VirtualFreeEx



2006年有两篇MSDN博客文章,其中包含C#代码:

For your P/Invoke declaration, the wMsg parameter should be an Integer, not a Long. The parameter is a 32-bit integer, whereas Long is a 64-bit integer.

The wParam parameter and return values should be IntPtr, since their size depends on whether you're running as a 32-bit or 64-bit process.

When you expect the function to update a string parameter, you should pass a StringBuilder. In .NET, the String type is immutable.

However, from what I've read, when the window belongs to another process, you have to allocate a buffer for the name in that process. This means you'll need to call OpenProcess, VirtualAllocEx, SendMessage, ReadProcessMemory, and finally VirtualFreeEx.

There's a two-part MSDN blog post from 2006 with the C# code to do this:
  • Getting the WinForms ID of a Control[^]
  • PInvoke Declarations for My Sample Code[^]


请参阅我对该问题的评论。 .NET永远不会与SendMessageA一起使用(除非你进行特殊的编组),因为.NET可以使用Unicode,而不是ASCII。最好使用SendMessageA。如果使用错误的签名,错误的数字和/或参数大小,不平衡堆栈是标志。



这是你P / Invoke它的方式: http://pinvoke.net/default.aspx/user32.SendMessage [ ^ ]。



整合整合应用程序的想法通过Windows消息听起来太脏了我认真对待它。我想说:不要整合,做软件开发。



-SA
Please see my comment to the question. .NET will never work with "SendMessageA" (unless you do special marshaling), because .NET works with Unicode, not ASCII. It would be better to use "SendMessageA". Unbalance stack is the sign if using wrong signature, wrong number and/or sizes of parameters.

This is how you P/Invoke it: http://pinvoke.net/default.aspx/user32.SendMessage[^].

The whole idea to "integrate" applications via Windows messages sounds way too dirty to me to take it serious. I would like to say: "don't integrate, do software development".

—SA


这篇关于SendMessage WM_GETCONTROLNAME PInvoke错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆