Imports System.Text
Imports System.ComponentModel

Public Class Utils
    Private Shared GetControlNameMessage As Integer = 0

    Public Shared Function GetWinFormsId(ByVal hWnd As IntPtr) As String
        GetControlNameMessage = NativeMethods.RegisterWindowMessage("WM_GETCONTROLNAME")
        Return XProcGetControlName(hWnd, GetControlNameMessage)
    End Function

    Protected Shared Function XProcGetControlName(ByVal hwnd As IntPtr, ByVal msg As Integer) As String
        Dim bytearray As Byte() = New Byte(65535) {}
        Dim bufferMem As IntPtr = IntPtr.Zero
        Dim written As IntPtr = IntPtr.Zero
        Dim retHandle As IntPtr = IntPtr.Zero
        Dim retVal As Boolean
        Dim processHandle As IntPtr = IntPtr.Zero
        Dim fileHandle As IntPtr = IntPtr.Zero

        If Not (Environment.OSVersion.Platform = PlatformID.Win32Windows) Then

            Try
                Dim size As UInteger
                size = 65536
                processHandle = NativeMethods.OpenProcess(NativeMethods.PROCESS_VM_OPERATION Or NativeMethods.PROCESS_VM_READ Or NativeMethods.PROCESS_VM_WRITE, False, GetProcessIdFromHWnd(hwnd))

                If processHandle.ToInt64() = 0 Then
                    Throw New Win32Exception()
                End If

                bufferMem = NativeMethods.VirtualAllocEx(processHandle, IntPtr.Zero, New UIntPtr(size), NativeMethods.MEM_RESERVE Or NativeMethods.MEM_COMMIT, NativeMethods.PageProtection.ReadWrite)

                If bufferMem.ToInt64() = 0 Then
                    Throw New Win32Exception()
                End If

                retHandle = NativeMethods.SendMessage(hwnd, msg, New IntPtr(size), bufferMem)
                retVal = NativeMethods.ReadProcessMemory(processHandle, bufferMem, bytearray, New UIntPtr(size), written)

                If Not retVal Then
                    Throw New Win32Exception()
                End If

            Finally
                retVal = NativeMethods.VirtualFreeEx(processHandle, bufferMem, New UIntPtr(0), NativeMethods.MEM_RELEASE)

                If Not retVal Then
                    Throw New Win32Exception()
                End If

                NativeMethods.CloseHandle(processHandle)
            End Try
        Else

            Try
                Dim size2 As Integer
                size2 = 65536
                fileHandle = NativeMethods.CreateFileMapping(New IntPtr(NativeMethods.INVALID_HANDLE_VALUE), IntPtr.Zero, NativeMethods.PageProtection.ReadWrite, 0, size2, Nothing)

                If fileHandle.ToInt64() = 0 Then
                    Throw New Win32Exception()
                End If

                bufferMem = NativeMethods.MapViewOfFile(fileHandle, NativeMethods.FILE_MAP_ALL_ACCESS, 0, 0, New UIntPtr(0))

                If bufferMem.ToInt64() = 0 Then
                    Throw New Win32Exception()
                End If

                NativeMethods.MoveMemoryFromByte(bufferMem, bytearray(0), size2)
                retHandle = NativeMethods.SendMessage(hwnd, msg, New IntPtr(size2), bufferMem)
                NativeMethods.MoveMemoryToByte(bytearray(0), bufferMem, 1024)
            Finally
                NativeMethods.UnmapViewOfFile(bufferMem)
                NativeMethods.CloseHandle(fileHandle)
            End Try
        End If

        Return ByteArrayToString(bytearray)
    End Function

    Private Shared Function GetProcessIdFromHWnd(ByVal hwnd As IntPtr) As UInteger
        Dim pid As UInteger
        NativeMethods.GetWindowThreadProcessId(hwnd, pid)
        Return pid
    End Function

    Private Shared Function ByteArrayToString(ByVal bytes As Byte()) As String
        If Environment.OSVersion.Platform = PlatformID.Win32Windows Then
            Return Encoding.[Default].GetString(bytes).TrimEnd(vbNullChar)
        Else
            Return Encoding.Unicode.GetString(bytes).TrimEnd(vbNullChar)
        End If
    End Function
End Class
