Помогите мне понять этот код C - PullRequest
4 голосов
/ 18 мая 2010
INT GetTree (HWND hWnd, HTREEITEM hItem, HKEY *pRoot, TCHAR *pszKey, 
             INT nMax) {
    TV_ITEM tvi;
    TCHAR szName[256];
    HTREEITEM hParent;
    HWND hwndTV = GetDlgItem (hWnd, ID_TREEV);

    memset (&tvi, 0, sizeof (tvi));

    hParent = TreeView_GetParent (hwndTV, hItem);
    if (hParent) { 
        // Get the parent of the parent of the...
        GetTree (hWnd, hParent, pRoot, pszKey, nMax);

        // Get the name of the item.
        tvi.mask = TVIF_TEXT;
        tvi.hItem = hItem;
        tvi.pszText = szName;
        tvi.cchTextMax = dim(szName);
        TreeView_GetItem (hwndTV, &tvi);  //send the TVM_GETITEM message?

        lstrcat (pszKey, TEXT ("\\"));
        lstrcat (pszKey, szName);
    } else {
        *pszKey = TEXT ('\0');
        szName[0] = TEXT ('\0');
        // Get the name of the item.
        tvi.mask = TVIF_TEXT | TVIF_PARAM;
        tvi.hItem = hItem;
        tvi.pszText = szName;
        tvi.cchTextMax = dim(szName);
        if (TreeView_GetItem (hwndTV, &tvi))
            //*pRoot = (HTREEITEM)tvi.lParam;  //original
      hItem = (HTREEITEM)tvi.lParam;
        else {
            INT rc = GetLastError();
        }
    }
    return 0;
}

Блок кода, который начинается с комментария «Получить название предмета», не имеет смысла для меня. Если вы получаете элемент списка, почему код устанавливает параметры получаемого элемента? Если у вас уже есть значения, их не нужно будет извлекать.

Во-вторых, рядом с комментарием «оригинал» - это оригинальная строка кода, которая будет компилироваться с предупреждением во встроенном Visual C ++ 4.0, но если вы скопируете точно такой же код в Visual Studio 2008, он не скомпилируется. Поскольку я не написал ни одного из этого кода и пытаюсь узнать, возможно ли, что первоначальный автор допустил ошибку в этой строке? * PRoot должен указывать на тип HKEY, но он приводит к типу HTREEITEM, который никогда не должен работать, поскольку типы данных не совпадают?

Ответы [ 4 ]

3 голосов
/ 18 мая 2010
Блок кода, который начинается с комментария «Получить название предмета», не имеет смысла для меня. Если вы получаете элемент списка, почему код задает параметры получаемого элемента, потому что, если у вас уже есть значения, их не нужно будет извлекать.

После этого комментария в первой строке указывается TreeView_GetItem (который, кстати, фактически является замаскированным SendMessage), который мы хотим извлечь из текста элемента и связанного с ним lParam. Следующая строка указывает дескриптор элемента, о котором мы хотим получить информацию.

Следующая строка указывает, где должен быть сохранен полученный текст, т. Е. В буфере szName, который был выделен в начале функции; последняя строка перед вызовом функции указывает размер такого буфера, чтобы избежать переполнения буфера.

Я предлагаю вам взглянуть на документацию TreeView_GetItem и TVITEM , чтобы лучше понять, что происходит.

Во-вторых, рядом с комментарием «оригинал» - это оригинальная строка кода, которая будет компилироваться с использованием varning под встроенным Visual C ++, но если вы скопируете точно такой же код в Visual Studio 2008, он не скомпилируется. Поскольку я не написал ни одного из этого кода и пытаюсь узнать, возможно ли, что первоначальный автор допустил ошибку в этой строке, поскольку * pRoot должен указывать на тип HKEY и тип HKEY, но он приводит к типу HTREEITEM, который никогда не должен работать типы данных не совпадают?

Не ясно, что код пытается там делать; на первый взгляд я бы сказал, что в lParam, связанном с каждым элементом в корневом узле дерева, хранится дескриптор ключа реестра, и процедура извлекает его таким образом. Тем не менее, если бы это было так, бросок (HTREEITEM) не имел бы никакого смысла; вероятно, это была ошибка, прощенная компилятором, потому что он обрабатывал все дескрипторы как просто void *; если моя гипотеза верна, вы должны сохранить исходную строку, просто заменив (HTREEITEM) на (HKEY).

1 голос
/ 18 мая 2010

Первый вопрос довольно прост: вы заполняете несколько элементов в структуре, чтобы указать, какие данные вам нужны, затем вызываете TreeView_GetItem, чтобы фактически извлечь указанные данные. В этом случае вы указываете TVIF_TEXT, который говорит, что вы хотите текст для конкретного элемента. Вы также даете ему буфер, куда он собирается поместить текст (szName), и сообщаете ему, как долго этот буфер (чтобы он не записывал после конца буфера). Когда вы вызываете TreeView_GetIem, он копирует текст для этого элемента в ваш буфер.

Что касается вашего второго вопроса: похоже all , что код (как старый, так и новый) несколько проблематичен. Общая цель, по-видимому, состоит в том, чтобы получить путь к элементу, который был первоначально передан, но, похоже, он делает это довольно плохо. Он начинается с рекурсивной прогулки по дереву к корню. Затем он извлекает текст для корневого элемента, но только в локальную переменную szName, которую затем игнорирует ( не копирует в szKey). Он сохраняет дескриптор корневого элемента в hItem (это то место, где он изначально записал pRoot).

Затем, возвращаясь (возвращаясь "вниз" по дереву), он извлекает текст для каждого элемента и добавляет эти имена к szKey (разделенному '\'), чтобы сформировать (большую часть) путь к элементу, переданному изначально. К сожалению, при этом он игнорирует переданный nMax, поэтому он может (очевидно) записывать после конца szKey буфера.

1 голос
/ 18 мая 2010

Параметр LPTVITEM для макроса TreeView_GetItem используется в двух направлениях.

TreeView_GetItem действительно отправляет сообщение TVM_GETITEM в древовидную структуру. Здесь происходит то, что вызывающая сторона заполняет небольшую часть структуры, чтобы сказать «вот что у меня есть и что я хочу», а затем древовидная структура заполнит запрошенные биты.

Из TreeView_GetItem документации

Когда отправляется сообщение TVM_GETITEM, член hItem структуры TVITEM или TVITEMEX идентифицирует элемент для получения информации, а элемент маски определяет атрибуты для извлечения.

Что касается второй части, я думаю, что это выглядит как ошибка, основанная на именах переменных и т. Д., Но вам, вероятно, следует проверить, как функция используется в остальной части кода, чтобы убедиться.

1 голос
/ 18 мая 2010

Часто вызовы API принимают информацию в структуре, а также возвращают информацию в той же структуре. Если вы посмотрите на документацию для TreeView_GetItem, она ясно покажет, как она работает.

Что касается второго вопроса, вы компилируете как C ++? В чем ошибка?

...