Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Проводник, как бы

14K
01 ноября 2006 года
Mr. White
25 / / 17.09.2006
Здравствуйте!

Я хочу в своей программе создать такую ветку дисков и папок:

http://www.relib.com/forums/Uploads/Images/b5c3ba4e-225c-4e5d-a27e-ee25.jpg

Я создал CTreeCtrl и даже смог получить установленные на компьютере диски, но как мне получить доступ к Рабочему столу, Сетевому окружению и прочему? Т.е. сейчас у меня ничего кроме дисков и их содержимого показать не получается, а хотелось бы. И еще: можно ли как-то получить системные иконки для дисков и папок (я сейчас использую свои собственные)? Хотелось бы еще реализовать CTreeCtrl, как в стандартном проводнике, т.е. чтобы над ним была кнопочка "X", то бишь закрыть, но это не так уж важно.



Спасибо за внимание.
725
01 ноября 2006 года
UnErase
190 / / 08.06.2006
[QUOTE=Mr. White]Здравствуйте!

Я хочу в своей программе создать такую ветку дисков и папок:

http://www.relib.com/forums/Uploads/Images/b5c3ba4e-225c-4e5d-a27e-ee25.jpg

Я создал CTreeCtrl и даже смог получить установленные на компьютере диски, но как мне получить доступ к Рабочему столу, Сетевому окружению и прочему? Т.е. сейчас у меня ничего кроме дисков и их содержимого показать не получается, а хотелось бы. И еще: можно ли как-то получить системные иконки для дисков и папок (я сейчас использую свои собственные)? Хотелось бы еще реализовать CTreeCtrl, как в стандартном проводнике, т.е. чтобы над ним была кнопочка "X", то бишь закрыть, но это не так уж важно.



Спасибо за внимание.[/QUOTE]

На счет иконок я могу сказать что они вроде бы храняться в файле shell32.dll

А чтобы их от туда достать можно использовать ResHack
1.8K
01 ноября 2006 года
k3Eahn
365 / / 19.12.2005
[quote=Mr. White]
Я создал CTreeCtrl и даже смог получить установленные на компьютере диски, но как мне получить доступ к Рабочему столу, Сетевому окружению и прочему?
[/quote]

SHGetDesktopFolder
Дальше пляши на основе полученного интерфейса IShellFolder.

[quote=Mr. White]
И еще: можно ли как-то получить системные иконки для дисков и папок (я сейчас использую свои собственные)?
[/quote]

SHGetFileInfo

[quote=Mr. White]Хотелось бы еще реализовать CTreeCtrl, как в стандартном проводнике, т.е. чтобы над ним была кнопочка "X", то бишь закрыть, но это не так уж важно.
[/quote]

В WTL есть контрол CPaneContainer
14K
02 ноября 2006 года
Mr. White
25 / / 17.09.2006
Спасибо!
Буду теперь разбираться как оно работает))
14K
03 ноября 2006 года
Mr. White
25 / / 17.09.2006
[QUOTE=k3Eahn]SHGetDesktopFolder
Дальше пляши на основе полученного интерфейса IShellFolder.
[/QUOTE]
А можно здесь пример показать, как получить указатель, к примеру, на Рабочий стол и как потом к нему обращаться, чтобы получить доступ из моего CTreeCtrl.
1.8K
06 ноября 2006 года
k3Eahn
365 / / 19.12.2005
Ну, к примеру, по рабочему столу можно пройтись так:
Код:
CComPtr<IEnumIDList> peidl;
CComPtr<IShellFolder> pshfRoot;
 
::SHGetDesktopFolder(&pshfRoot);
 
HRESULT hr = pshfRoot->EnumObjects(GetParent()->GetSafeHwnd(),
  SHCONTF_FOLDERS, &peidl);
 
if(FAILED(hr))
{
  //DO SOMETHING!
};
 
ULONG ulFetched = 0;
DWORD dwAttrib;
LPITEMIDLIST lpidl;
 
while(peidl->Next(1, &lpidl, &ulFetched) == NOERROR)
{
  dwAttrib = SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
  pshfRoot->GetAttributesOf(1, (LPCITEMIDLIST *)&lpidl, &dwAttrib);
 
  if((dwAttrib & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER)) != 0)
  {
    //Объект на который указывает lpidl
    //является папкой и может иметь подпапки
  };
 
};
14K
08 ноября 2006 года
Mr. White
25 / / 17.09.2006
Круто. Спасибо.

Скажите, если мне нужно показать только диски c моего компьютера, мои документы и папки с рабочего стола, то как я могу отсеять все остальное (сетевое окружение, корзина, панель управления), кроме как проверять, что возвращает GetDisplayNameOf? Вероятно, нужно использовать какой-то флаг, только вот какой?
1.8K
09 ноября 2006 года
k3Eahn
365 / / 19.12.2005
Могу предложить такое решение (но не факт, что оно рабочее):

Получить абсолютные ITEMIDLIST'ы (относительно рабочего стола) для тех папок, которые отображать не надо, при помощи функции SHGetSpecialFolderLocation(SHGetFolderLocation). Имея интерфейс IShellFolder для рабочего стола, делать IShellFolder::CompareIDs для полученного при переборе объектов рабочего стола и полученного при помощи одной из выше перечисленных функций ITEMIDLIST'ов.
14K
12 ноября 2006 года
Mr. White
25 / / 17.09.2006
Решение оказалось рабочим в двух случаях из трех - на Панели управления только спотыкается. Но я думаю, что это я скорее что-то не так делаю.
Учитывая, что я в первый раз залез в такие дебри, то справедливо сомневаюсь в адекватности своего кода. Если специалисту не сложно, то хотелось бы услышать его мнение :)

Вот код (кажется, он даже работает):
Функция получает указатель на Рабочий стол
Код:
void CFolderViewView::ShowFolder(IShellFolder* folder)
{
    IEnumIDList* peidl;
    ITEMIDLIST itemidlist = { {0} };
    LPITEMIDLIST lpidl = &itemidlist;
    LPITEMIDLIST lpidNotVisible = &itemidlist;

    LPSHELLFOLDER child;
    ULONG ulFetched = 0;
    STRRET Value;
    char *sTempName;

    HRESULT hr = folder->EnumObjects(GetParent()->GetSafeHwnd(),
        SHCONTF_FOLDERS, &peidl);

    if( SUCCEEDED(hr) )
    {
        Level++;

        hNext = pTree.GetChildItem(hNext);
        while(pTree.GetNextItem( hNext, TVGN_NEXT) )
            hNext = pTree.GetNextItem( hNext, TVGN_NEXT);

        while(peidl->Next(1, &lpidl, &ulFetched) == NOERROR)
        {
            LPARAM lParam = SHCIDS_CANONICALONLY;
           
            //пропускаем Сетевое окружение
            SHGetSpecialFolderLocation(GetParent()->GetSafeHwnd(), CSIDL_NETWORK, &lpidNotVisible);
            if( (short)HRESULT_CODE( folder->CompareIDs(lParam, lpidNotVisible, lpidl) ) == 0)
                continue;
           
            //пропискаем Корзину
            SHGetSpecialFolderLocation(GetParent()->GetSafeHwnd(), CSIDL_BITBUCKET, &lpidNotVisible);
            if( (short)HRESULT_CODE( folder->CompareIDs(lParam, lpidNotVisible, lpidl) ) == 0)
                continue;

            //пропускаем Панель управления
            SHGetSpecialFolderLocation(GetParent()->GetSafeHwnd(), CSIDL_CONTROLS, &lpidNotVisible);
            if( (short)HRESULT_CODE( folder->CompareIDs(lParam, lpidNotVisible, lpidl) ) == 0)
                continue;
           

            //получаем имя объекта
            folder->GetDisplayNameOf(lpidl, SHGDN_NORMAL, &Value);
            StrRetToStr( &Value, lpidl, &sTempName);
            //добавляем его в CTreeCtrl
            ToTree(sTempName, /*HTREEITEM*/hNext);

            SFGAOF dwAttrib = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM;
            folder->GetAttributesOf(1, (LPCITEMIDLIST*)&lpidl, &dwAttrib );

            if((dwAttrib & (SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM)) != 0)
            {
                //получаем подпапку
                hr = folder->BindToObject( lpidl, NULL, IID_IShellFolder, (void**)&child );
                if( SUCCEEDED( hr ) )
                    ShowFolder(child);
                child->Release();
            }
        };
        Level--;
        hNext = pTree.GetParentItem(hNext);
    }
    peidl->Release();
}


Когда всё это отработает (это занимает некоторое время, но мы потерпим), оказывается, что оно отхватило под свои нужды больше 10Мб, что не есть хорошо. Из того, что я прочитал в MSDN понял только то, что умные программисты умеют освобождать память. Я пытался что-то делать, но оно, как правило, все с треском падало, так что мне это быстро наскучило.
Да и еще: когда я получаю указатель на объект Сетевое окружение и передаю ее в указанную выше функцию, то в строчке while(peidl->Next(1, &lpidl, &ulFetched) == NOERROR) всё останавливается, но продолжает пожирать память. Что-то не пойму, в каком месте смеяться.



Спасибо за то, что помогаете :)
1.8K
14 ноября 2006 года
k3Eahn
365 / / 19.12.2005
[quote=Mr. White]
Когда всё это отработает (это занимает некоторое время, но мы потерпим), оказывается, что оно отхватило под свои нужды больше 10Мб, что не есть хорошо.
[/quote]
А есть ли, собственно, необходимость в отображении в дереве ВСЕХ папок?
Я бы заполнял ветку дерева только тогда когда юзер её разворачивает. Соответственно, когда юзер хочет свернуть ветку - мы удаляем её элементы.

И ещё цитата из MSDN для 3-го параметра StrRetToStr:
Цитата:

ppszName [out] Pointer to an allocated string containing the result. StrRetToStr allocates memory for this string with CoTaskMemAlloc. You should free the string with CoTaskMemFree when it is no longer needed.


Это конечно если ты не освобождаешь память в ToTree.

14K
21 ноября 2006 года
Mr. White
25 / / 17.09.2006
Хм. Возникла вдруг проблема. Когда я пытаюсь получить доступ к папке, к чтению которой у меня нет прав, программа с треском падает. Психика моя такого не выдержит, наверное.

Суть в чем (т.е. мне так кажется):
Когда я получаю объект на подпапку через функцию BindToObject, мне нужно не передавать ее дальше (EnumObjects), а узнать обладает ли данный пользователь необходимыми правами. Я думаю, что копать надо где-то в функции GetAttributesOf, только я что-то не нашел подходящего флаг. Еще варианты?

И какой функцией получить полный путь к объекту, а то моей сообразительности хватило только на манипуляции с CTreeCtrl.
1.8K
23 ноября 2006 года
k3Eahn
365 / / 19.12.2005
Цитата: Mr. White
Когда я пытаюсь получить доступ к папке, к чтению которой у меня нет прав, программа с треском падает.


Дык где падает - непосредственно в коде программы или в одном из методов IShellFolder?

Цитата: Mr. White
И какой функцией получить полный путь к объекту, а то моей сообразительности хватило только на манипуляции с CTreeCtrl.


Ну тут долго рассказывать, поэтому проще послать, например, сюда http://www.codenet.ru/progr/delphi/zelez.php или сюда http://rsdn.ru/summary/329.xml.

14K
23 ноября 2006 года
Mr. White
25 / / 17.09.2006
Значит так, как получить путь к объекту я уже понял &#8211; функцией SHGetPathFromIDList (но она, конечно же, в моих руках не хочет работать, так что сейчас пойду по ссылкам искать ответы).


Падает, когда я пытаюсь получить EnumObjects (я получаю указатель на папку (IShellFolder) и передаю его в свою функцию ShowFolder, где программа падает, когда я пытаюсь получить EnumObjects. Т.е. мне надо как-то узнать до этого, что я не могу работать с этой папкой).
1.8K
23 ноября 2006 года
k3Eahn
365 / / 19.12.2005
По сути реализация IShellFolder должна обрабатывать такую ситуацию, когда у пользователя недостаточно прав для доступа к объекту (да и MSDN по этому поводу ничего не говорит). И она её обрабатывает (во всяком случае у меня). Т.е если в ходе выполнения одного метода, взять к примеру EnumObjects, оказывается, что прав недостаточно, метод просто возвратит ошибку и если ему передан валидный хэндл окна, то будет показан мессаджбокс с соответствующим сообщением.

Так что трабла скорей всего в твоём коде (совет: выложи именно тот кусок кода, где генерится исключение).
14K
28 ноября 2006 года
Mr. White
25 / / 17.09.2006
А что нужно (принято) запоминать в полях CTreeCtrl (SetItemData), чтобы реализовать проводник? Я до этого использовал указатель на IShellFolder, но это, конечно же, экстрим :)
1.8K
28 ноября 2006 года
k3Eahn
365 / / 19.12.2005
Цитата: Mr. White
Я до этого использовал указатель на IShellFolder, но это, конечно же, экстрим :)


Почему же? Я лично не вижу в этом ничего экстремального:) .
Хранить можно хотя бы указатель на экземпляр такой структуры:

 
Код:
typedef struct
 {
  CComPtr<IShellFolder> pshfParent;
  LPITEMIDLIST lpidlSelf;
  LPITEMIDLIST lpidlfq;
 }SHTVITEMDATA;

Где соответственно pshfParent - указатель на интерфейс родительской папки, lpidlSelf - указатель на ITEMIDLIST самой папки (относительно родительской папки), для удобства (сам решай - нужен он тебе, или нет) можно хранить и lpidlfq - указатель на ITEMIDLIST этой же папки относительно рабочего стола (aka абсолютный ITEMIDLIST).
14K
09 декабря 2006 года
Mr. White
25 / / 17.09.2006
У меня кое-что получилось, что странно.
Запоминаю в полях CTreeCtrl указатель на IShellFolder, и через EnumObjects получаю доступ к подпапкам. Тут все ясно, работает и славно. Но вот мне потребовалось получить указатель на ITEMIDLIST, используя полученный IShellFolder.

Почему сие отказывается работать:


 
Код:
IShellFolder* pFolder = (IShellFolder*)pTree.GetItemData( hCur );
IShellFolder *pDesktop;
hr = SHGetDesktopFolder(&pDesktop);

ITEMIDLIST *pidl = NULL;
STRRET Value;
TCHAR *szPath;

hr = pFolder->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &Value);
hr = pDesktop->ParseDisplayName(GetParent()->GetSafeHwnd(), 0, (LPOLESTR)&Value, NULL, &pidl, NULL);


IShellFolder указывает на Мои документы, а ITEMIDLIST почему-то получаю на Мой компьютер. Я, вероятно, не понимаю толком, как работает метод ParseDisplayName (я его вызываю, используя указатель на Рабочий стол, т.к. мне нужен абсолютный ITEMIDLIST, относительно Рабочего стола… или я как всегда ничего не понял…)
1.8K
10 декабря 2006 года
k3Eahn
365 / / 19.12.2005
Моё ИМХО: забей на IShellFolder::ParseDisplayName, как на средство получения абсолютного ITEMIDLIST'а.
Лучше используй способ как в этом коде (выдрал из примеров к WTL):
Код:
LPITEMIDLIST ConcatPidls(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
 UINT cb1 = 0;
 if (pidl1 != NULL)   // May be NULL
  cb1 = GetSize(pidl1) - sizeof(pidl1->mkid.cb);
 UINT cb2 = GetSize(pidl2);
 LPITEMIDLIST pidlNew = (LPITEMIDLIST)::CoTaskMemAlloc(cb1 + cb2);
 if (pidlNew != NULL)
 {
  if (pidl1 != NULL)
   memcpy(pidlNew, pidl1, cb1);
  memcpy(((LPSTR)pidlNew) + cb1, pidl2, cb2);
 }
 return pidlNew;
}
 
LPITEMIDLIST Next(LPCITEMIDLIST pidl)
{
 LPSTR lpMem = (LPSTR)pidl;
 lpMem += pidl->mkid.cb;
 return (LPITEMIDLIST)lpMem;
}
 
UINT GetSize(LPCITEMIDLIST pidl)
{
 UINT cbTotal = 0;
 if (pidl != NULL)
 {
  cbTotal += sizeof(pidl->mkid.cb);   // Null terminator
  while (pidl->mkid.cb != NULL)
  {
   cbTotal += pidl->mkid.cb;
   pidl = Next(pidl);
  }
 }
 return cbTotal;
}

По сути ITEMIDLIST(список SHITEMID'ов) похож на имя файла в файловой системе.
P.S.: Кстати по тем ссылкам, что я кидал, должны быть объяснения, что из себя представляют ITEMIDLIST'ы.
14K
11 декабря 2006 года
Mr. White
25 / / 17.09.2006
Я сейчас несколько под градусом, наверное, в этом вся проблема, но я не очень понял, как мне использовать твои функции в данном конкретном случае, а именно, как получить ITEMIDLIST из IShellFolder. Ведь все эти функции хотят LPCITEMIDLIST, который мне и нужно получить (кстати, а чем отличается LPCITEMIDLIST от ITEMIDLIST?).

У меня есть IShellFolder, нужно из него получить ITEMIDLIST. Что делать?..

>P.S.: Кстати по тем ссылкам, что я кидал, должны быть объяснения, что из себя представляют ITEMIDLIST'ы.
Что-то там точно есть. Например, описание метода ParseDisplayName :)




Меня, кстати, позбавила функция LPITEMIDLIST ConcatPidls(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) (о предназначении остальных я догадался из названий). Кто-то, наверное, переоценил мои возможности :)
1.8K
11 декабря 2006 года
k3Eahn
365 / / 19.12.2005
Цитата: Mr. White
Я сейчас несколько под градусом, наверное, в этом вся проблема


Несколько - это ещё не страшно:)

Цитата: Mr. White
кстати, а чем отличается LPCITEMIDLIST от ITEMIDLIST


LPCITEMIDLIST - это тип указателя на константный ITEMIDLIST, т.е. такой указатель говорит о том, что ITEMIDLIST модифицировать нельзя.

Цитата: Mr. White
>P.S.: Кстати по тем ссылкам, что я кидал, должны быть объяснения, что из себя представляют ITEMIDLIST'ы.
Что-то там точно есть. Например, описание метода ParseDisplayName :)


Я имел ввиду вот это:

Цитата:
Идентификатор элемента имеет смысл только в контексте той папки, которая его сконструировала.
Идентификатор элемента описывается структурой SHITEMID, для которой определено лишь значение первого поля - размер данной структуры.
Список идентификаторов, уникально идентифицирующих объект в определённом пространстве имён, эквивалентен понятию пути для файловой системы, и определяется как список из последовательно расположенных идентификаторов, за которыми следует завершающее список 16-битное значение 0x0000 (ITEMIDLIST). Список идентификаторов может быть как абсолютным, то есть определяющим положение объекта относительно корневой папки, так и относительным, то есть определяющим положение элемента относительно какой-либо конкретной папки.
Приложение оперирует понятием указателя на список идентификаторов (Pointer to an Identifier List), который кратко именуют как PIDL-указатель.


Там же, кстати, приведён код функций, похожих на те, что я привёл здесь.

Цитата: Mr. White
У меня есть IShellFolder, нужно из него получить ITEMIDLIST. Что делать?..



Извечный вопрос:) . Есть очень простое решение - использовать функцию SHGetRealIDL. Но у этого решения есть ограничение - эта функция появилась в Win2000.

P.S.: Изучение исходников очень помогает, так что всё-таки скачай WTL с http://sourceforge.net/project/showfiles.php?group_id=109071 и покопайся в исходниках примера WTLExplorer.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог