Я «встраиваю Windows Explorer» в свое приложение Win32. (Технически я размещаю ShellView папки в моем приложении, что и делает проводник Windows).
Проблема в том, что представление никогда не вызывает IShellBrowser.BrowseObject. Вместо того, чтобы просить меня перейти в новое место (через событие BrowseObject), представление оболочки запускает копию проводника Windows для просмотра папки.
Я хочу, чтобы вид оболочки по умолчанию (в просторечии известный как DefView) был доступен для просмотра.
Сначала нам нужно получить IShellFolder
для некоторой папки, которую я хочу отобразить. Самая простая папка - это папка рабочего стола, поскольку для нее есть SHGetDesktopFolder API
:
folder: IShellFolder;
SHGetDesktopFolder({out} folder);
Затем мы просим папку рабочего стола передать ее IShellView :
view: IShellView;
folder.CreateViewObject(Self.Handle, IID_IShellView, {out}view);
Теперь, когда у нас есть IShellView папки (в отличие от IContextMenu или IExtractIcon ), мы теперь хотим показать представление оболочки вызвав IShellView.CreateViewWindow :
hostRect: TRect; //where the view is to display itself
folderSettings: TFolderSettings; //display settings for the view
hwndView: HWND; //the newly created view's window handle
folderSettings.ViewMode := FVM_DETAILS; //details mode please, rather than icon/list/etc
folderSettings.fFlags := 0;
hostRect := Rect(20, 20, 660, 500); //the view can position itself there
view.CreateViewWindow(nil, folderSettings, shellBrowser, {var}hostRect, {out}hView);
view.UIActivate(SVUIA_ACTIVATE_NOFOCUS);
и вуаля, узнаваемый список оболочки, показывающий мой рабочий стол:
в комплекте с обработчиками контекстного меню:
За исключением того, что когда я нажимаю Открыть , а не отправляю мне Событие BrowseObject
через предоставленный мной интерфейс IShellBrowser
открывает новое окно:
То же самое происходит, когда я дважды щелкаю.
Как сделать Microsoft DefView доступным для просмотра?
При создании IShellView
вы должны предоставить ему объект, реализующий IShellBrowser
. Этот объект ShellBrowser
используется для обратной связи представления с размещающим контейнером.
Из 15 методов я внимательно рассмотрю только четыре - остальные могут вернуть E_NOTIMPL
(что, конечно, может быть проблемой):
{IShellBrowser}
BrowseObject (PCUIDLIST_RELATIVE pidl, UINT wFlags);
// Сообщает проводнику Windows перейти к другой папке.
// Это уведомление, которое я хочу!
Result: = BrowseToAnotherFolder (pidl, wFlags);
GetControlWindow (UINT id, HWND * lphwnd);
// Получает дескриптор окна для элемента управления браузера.
// Поскольку у меня нет панели инструментов, дерева, окна состояния или выполнения, возвращаем 0 {{ 1}} lphwnd: = 0;
Result: = S_OK;
SendControlMsg (UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT * pret);
// Отправляет управляющие сообщения либо на панель инструментов, либо в строку состояния в Windows
// Из MSDN: Примечания для разработчиков
// Если в вашем проводнике Windows нет этих элементов управления, вы можете вернуть E_NOTIMPL.
Result: = E_NOTIMPL;
GetViewStateStream (DWORD grfMode, IStream ** ppStrm);
// Получает интерфейс IStream, который можно использовать для хранения информации о состоянии конкретного представления .
Результат: = E_NOTIMPL; // у меня нет потока, который я мог бы передать вам
TranslateAcceleratorSB (LPMSG lpmsg, WORD wID);
// Переводит нажатия клавиш ускорителя, предназначенные для фрейма браузера
/ / пока вид активен.
Результат: = E_NOTIMPL; // я не буду переводить
OnViewWindowActive (IShellView * ppshv);
// Вызывается представлением оболочки, когда окно просмотра или одно из его дочерних
/ / windows получает фокус или становится активным.
Результат: = S_OK; // я получил уведомление, спасибо
QueryActiveShellView (IShellView ** ppshv);
// Извлекает текущий активный (отображаемый) объект представления оболочки.
ppshv: = view;
Результат: = S_OK; // я бы никогда не посмотрел другой, вы знаете, что
EnableModelessSB (BOOL fEnable);
// Указывает проводнику Windows включить или отключить его немодальные диалоговые окна.
Результат: = S_OK; // Вы хотите включить немодальные диалоговые окна? Интересно.
InsertMenusSB (HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths);
// Позволяет контейнеру вставлять свои группы меню в составное
// меню, которое отображается, когда расширенное пространство имен просматривается или используется.
Результат: = E_NOTIMPL; // у меня нет меню
RemoveMenusSB (HMENU hmenuShared);
// Разрешает контейнеру удалить любой из своих элементов меню
// из составного меню на месте и чтобы освободить все связанные ресурсы.
Результат: = E_NOTIMPL; // у меня нет меню
SetMenuSB (HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject);
// Устанавливает составное меню в окно просмотра.
Результат: = E_NOTIMPL; // у меня нет меню
SetStatusTextSB
// Устанавливает и отображает текст состояния о текущем объекте
// в строке состояния окна фрейма контейнера. {{1 }} Результат: = E_NOTIMPL; // у меня нет строки состояния
SetToolbarItems (LPTBBUTTONSB lpButtons, UINT nButtons, UINT uFlags);
// Добавляет элементы панели инструментов на панель инструментов Проводника Windows.
Результат: = E_NOTIMPL;// у меня нет панели инструментов
Затем есть предок IOleWindow
:
GetWindow ([out] HWND * phwnd);
// Извлекает дескриптор одного из окна, участвующие в
// активации на месте (окно фрейма, документа, родителя или объекта на месте).
phwnd: = Self.Handle; // это снова дескриптор вашего родителя
Result: = S_OK;
`ContextSensitiveHelp ([в] BOOL fEnterMode);
// Определяет, нужно ли переходить в режим контекстно-зависимой помощи
// во время сеанса активации на месте.
Result: = S_OK; // Хорошо, спасибо, я запомню это
function TShellBrowser.QueryService(const rsid, iid: TGuid; out Obj): HResult;
var
sb: IShellBrowser;
s: string;
const
SID_SInPlaceBrowser: TGUID = '{1D2AE02B-3655-46CC-B63A-285988153BCA}';
SID_IShellBrowser: TGUID = '{000214E2-0000-0000-C000-000000000046}';
begin
{
This code is executed when you double click a folder.
It's needed to implement inline browsing.
If you double click a folder the default action of IShellBrowser is to open a new Windows Explorer.
To open the folder in the current window you must implement IServiceProvider.
http://blogs.msdn.com/b/ieinternals/archive/2009/12/30/windows-7-web-browser-control-will-not-browse-file-system.aspx
}
Result := E_NOINTERFACE; //Return $E_NOINTERFACE
OutputDebugString(PChar('TShellBrowser.QueryService: '+IIDToString(rsid)));
{
Make a small change to your application to enable the filesystem object to navigate in-place within the WebOC
when running on Windows 7.
To do so, your hosting application will implement the IServiceProvider interface,
and hand back the WebBrowser control’s SID_SShellBrowser when asked for SID_SInPlaceBrowser
}
if IsEqualGUID(rsid, SID_SInPlaceBrowser) then
begin
sb := Self as IShellBrowser;
Pointer(Obj) := Pointer(sb);
sb._AddRef;
Result := S_OK;
end;
end;