Не удается получить доступ к содержимому SystemListView с помощью API-интерфейса управляемого Win32 - PullRequest
0 голосов
/ 27 ноября 2010

Я использую API ManagedWindows в среде C #: http://mwinapi.sourceforge.net/

В прошлом я успешно очищал содержимое элементов, похожих на списки, других запущенных программ, используя приведенный ниже код, где я выполняю итерациипары ключ / значение, чтобы найти элементы списка.Однако для этого конкретного списка элементов я могу получить точное количество элементов, но значение всегда равно нулю!

Используя это:

TargetMidWindow.Content.ComponentType

Я обнаружил, что список, с которым у меня возникают проблемы, является «списком просмотра», тогда как другие окна, с которыми я имел успех, - это «просмотр списка деталей», есливопросы.Ниже приведен код для поиска нужных мне данных, который практически идентичен моему другому успешному коду, за исключением изменения поисковых терминов, которые я использовал.Кроме того, в случае необходимости программа, из которой я пытаюсь извлечь данные, называется MetaTrader4, и мне удалось успешно очистить данные от других частей программы.

    // Find the main window
        SystemWindow[] TopLevel = SystemWindow.AllToplevelWindows;
        SystemWindow TargetTopWindow = SystemWindow.ForegroundWindow;
        foreach (SystemWindow SearchWindow in TopLevel)
        {
            string Title = SearchWindow.Title;
            if (Title.Contains("MetaTrader"))
            {
                TargetTopWindow = SearchWindow;
                break;
            }
        }

        // Find the section where positions are contained
        SystemWindow[] MidLevel = TargetTopWindow.AllDescendantWindows;
        SystemWindow TargetMidWindow = SystemWindow.ForegroundWindow;
        foreach (SystemWindow SearchWindow in MidLevel)
        {
            string ClassName = SearchWindow.ClassName;
            if (ClassName.Contains("SysListView32"))
            {
                SystemWindow ParentWindow = SearchWindow.Parent;
                    if ((ParentWindow.Title.Contains("Terminal")))
                    {
                        TargetMidWindow = SearchWindow;

                    }
            }
        }

        // Get the positions
        Dictionary<string, string> RawValues = new Dictionary<string, string>();
        foreach (KeyValuePair<string, string> KVP in TargetMidWindow.Content.PropertyList)
        {
            string key = KVP.Key;
            string value = KVP.Value;
        }

Есть ли что-точто мне нужно сделать, чтобы я не получал нулевые значения для каждого элемента списка?

Спасибо!Билл

Ответы [ 2 ]

1 голос
/ 01 июня 2012

Если вы хотите найти правильный дескриптор для конкретного окна SysListView32, вам нужно начать с правильной иерархии окон.Из фрагмента кода не видно, что вы на самом деле находите правильный дескриптор для извлечения цитаты из окна SysListView32.Вот почему вы получаете нулевые значения обратно.Хорошо бы запустить spy ++ и определить правильную структуру окон терминала Metatrader для вашего конкретного брокера и сборки.Я обнаружил, что классы различаются между сборками для некоторых окон, а также между некоторыми брокерами, хотя и в меньшей степени.

Вы ищете определенную иерархию окон котировок, подобную этой:

Metatrader -> Market Watch -> Market Watch -> SysListView32

В отличие от этого, в настоящее время вы смотрите здесь в своем коде:

Metatrader -> Terminal -> (many sub-windows with SysListView32 class)

Где каждый уровень справа является дочерним окном окна слева.

Найдите родительское окно «Metatrader», затем цепочку ищите дочернее окно, пока не доберетесь до SysListView32.Если вы используете spy ++, вы можете прочитать класс для родительского окна SysListView32 (обзор рынка) и использовать его для перечисления окон, чтобы найти правильное окно SysListView32.К вашему сведению, правильное имя класса Market Watch для сборки 419:

Afx:00400000:b:00010003:00000000:00000000

Как только вы найдете правильное окно, вы сможете извлечь его содержимое, используя текущий компонент.Я не пробовал этого и пытаюсь перенести некоторый код из VB6 из модуля ListView, который на самом деле связан с эпическим хакерством.;) Я могу взглянуть на .NET Managed Windows API, чтобы увидеть, может ли это помочь упростить процесс.

Но в то же время, если вам придется перейти на низкоуровневую, следующий VB6Источник должен помочь вам получить представление о том, что происходит.Это довольно продвинутый материал, так что удачи!

Public Function GetListviewItem(ByVal hWindow As Long, ByVal pColumn As Long, ByVal pRow As Long) As String
Dim result              As Long
Dim myItem              As LV_ITEMA
Dim pHandle             As Long
Dim pStrBufferMemory    As Long
Dim pMyItemMemory       As Long
Dim strBuffer()         As Byte
Dim index               As Long
Dim tmpString           As String
Dim strLength           As Long

Dim ProcessID As Long, ThreadID As Long
ThreadID = GetWindowThreadProcessId(hWindow, ProcessID)
'**********************
'init the string buffer
'**********************
ReDim strBuffer(MAX_LVMSTRING)

'***********************************************************
'open a handle to the process and allocate the string buffer
'***********************************************************
pHandle = OpenProcess(PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, False, ProcessID)
pStrBufferMemory = VirtualAllocEx(pHandle, 0, MAX_LVMSTRING, MEM_COMMIT, PAGE_READWRITE)

'************************************************************************************
'initialize the local LV_ITEM structure
'The myItem.iSubItem member is set to the index of the column that is being retrieved
'************************************************************************************
myItem.mask = LVIF_TEXT
myItem.iSubItem = pColumn
myItem.pszText = pStrBufferMemory
myItem.cchTextMax = MAX_LVMSTRING

'**********************************************************
'write the structure into the remote process's memory space
'**********************************************************
pMyItemMemory = VirtualAllocEx(pHandle, 0, Len(myItem), MEM_COMMIT, PAGE_READWRITE)
result = WriteProcessMemory(pHandle, pMyItemMemory, myItem, Len(myItem), 0)

'*************************************************************
'send the get the item message and write back the memory space
'*************************************************************
result = SendMessage(hWindow, LVM_GETITEMTEXT, pRow, ByVal pMyItemMemory)
result = ReadProcessMemory(pHandle, pStrBufferMemory, strBuffer(0), MAX_LVMSTRING, 0)
result = ReadProcessMemory(pHandle, pMyItemMemory, myItem, Len(myItem), 0)

'**************************************************
'turn the byte array into a string and send it back
'**************************************************
For index = LBound(strBuffer) To UBound(strBuffer)
    If Chr(strBuffer(index)) = vbNullChar Then Exit For
    tmpString = tmpString & Chr(strBuffer(index))
Next index

tmpString = Trim(tmpString)

'**************************************************
'deallocate the memory and close the process handle
'**************************************************
result = VirtualFreeEx(pHandle, pStrBufferMemory, 0, MEM_RELEASE)
result = VirtualFreeEx(pHandle, pMyItemMemory, 0, MEM_RELEASE)

result = CloseHandle(pHandle)

If Len(tmpString) > 0 Then GetListviewItem = tmpString

End Function
1 голос
/ 27 ноября 2010

Хм, оборачивать сообщения Windows дружественным API не так уж и сложно. Windows Forms был бы хорошим примером. Но если вы начинаете делать это с другим процессом, у вас есть ловкость сталкиваться с очень прочной стеной.

Конкретное сообщение, которое вам нужно для чтения элементов ListView, это LVM_GETITEM. Это одно из тех твердых сообщений на стене. Аргумент LPARAM, который вы передаете SendMessage (), должен быть указателем на структуру LVITEM. Элемент управления заполняет поля в этой структуре. Проблема в том, что передаваемый вами указатель действителен только в вашем процессе, а не в процессе, которому принадлежит это окно.

Чтобы исправить это, нужно много взломать. Вы должны выделить память, которая действует внутри этого процесса. Это берет VirtualAllocEx () и ReadProcessMemory (). Плюс все вызовы клея, которые вам нужны, чтобы заставить их работать. Я предполагаю, что используемая вами библиотека не заботится об этом. Легко узнать, grep файлы исходного кода для этих имен функций API.

...