Я встраиваю проводник Windows в свое приложение Win32. (Технически я размещаю ShellView папки в моем приложении, что и делает проводник Windows).
Проблема в том, что представление никогда не вызывает IShellBrowser.BrowseObject. Вместо того, чтобы просить меня перейти в новое место (через событие BrowseObject), представление оболочки запускает копию проводника Windows для просмотра папки.
Я хочу, чтобы вид оболочки по умолчанию (в просторечии известный как DefView) был доступен для просмотра.
Пример кода учебника
Сначала нам нужно получить IShellFolder
для какой-то папки, которую я хочу отобразить. Самая простая папка - это папка Desktop, так как там есть _ 2_ для этого:
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);
et voila, узнаваемый список оболочки, показывающий мой рабочий стол:
в комплекте с обработчиками контекстного меню:
За исключением того, что когда я нажимаю Открыть, а не отправляю мне _ 6_ через _ 7_, который я предоставил, он открывает новое окно:
То же самое происходит, когда я дважды щелкаю.
Как я могу сделать Microsoft DefView доступным для просмотра?
Обновить реализацию ShellBrowser
При создании IShellView
вы должны дать ему объект, реализующий IShellBrowser
. Этот ShellBrowser
объект определяет, как представление обменивается данными с размещающим контейнером.
Из 15 методов я внимательно смотрю только на четыре - остальные могут возвращать E_NOTIMPL
(что, конечно, может быть проблемой):
{IShellBrowser}
BrowseObject(PCUIDLIST_RELATIVE pidl, UINT wFlags);
//Informs Windows Explorer to browse to another folder. //This is the notification i want! Result := BrowseToAnotherFolder(pidl, wFlags);
GetControlWindow(UINT id, HWND *lphwnd);
//Gets the window handle to a browser control. //Since i don't have a toolbar, tree, status or progress windows, return 0 lphwnd := 0; Result := S_OK;
SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret);
//Sends control messages to either the toolbar or the status bar in a Windows //From MSDN: Notes to Implementers // If your Windows Explorer does not have these controls, you can return E_NOTIMPL. Result := E_NOTIMPL;
GetViewStateStream(DWORD grfMode, IStream **ppStrm);
//Gets an IStream interface that can be used for storage of view-specific state information. Result := E_NOTIMPL; //i'm don't have a stream to give you
TranslateAcceleratorSB(LPMSG lpmsg, WORD wID);
//Translates accelerator keystrokes intended for the browser's frame // while the view is active. Result := E_NOTIMPL; //i won't be doing any translating
OnViewWindowActive(IShellView *ppshv);
//Called by the Shell view when the view window or one of its child // windows gets the focus or becomes active. Result := S_OK; //i got the notification, thanks
QueryActiveShellView(IShellView **ppshv);
//Retrieves the currently active (displayed) Shell view object. ppshv := view; Result := S_OK; //i would never view another, you know that
EnableModelessSB(BOOL fEnable);
//Tells Windows Explorer to enable or disable its modeless dialog boxes. Result := S_OK; //You want to enable modeless dialog boxes? Interesting.
InsertMenusSB(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths);
//Allows the container to insert its menu groups into the composite // menu that is displayed when an extended namespace is being viewed or used. Result := E_NOTIMPL; //i no has menus
RemoveMenusSB(HMENU hmenuShared);
//Permits the container to remove any of its menu elements // from the in-place composite menu and to free all associated resources. Result := E_NOTIMPL; //i no has menus
SetMenuSB(HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject);
//Installs the composite menu in the view window. Result := E_NOTIMPL; //i no has menus
SetStatusTextSB
//Sets and displays status text about the in-place object //in the container's frame-window status bar. Result := E_NOTIMPL; //i no has status bar
SetToolbarItems(LPTBBUTTONSB lpButtons, UINT nButtons, UINT uFlags);
//Adds toolbar items to Windows Explorer's toolbar. Result := E_NOTIMPL; //i no has toolbar
Затем есть предок IOleWindow
< / а>:
GetWindow([out] HWND *phwnd);
//Retrieves a handle to one of the windows participating in // in-place activation (frame, document, parent, or in-place object window). phwnd := Self.Handle; //here's the handle, again, of your parent Result := S_OK;
`ContextSensitiveHelp ([in] BOOL fEnterMode);
//Determines whether context-sensitive help mode should be entered //during an in-place activation session. Result := S_OK; //Ok, thanks, i'll make a note of it
IServiceProvider
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;
Бонусное чтение
- бывший сотрудник MSFT Эрик Лоу описывает это поведение как инстанциональное изменение в Windows 7 и способы его решения. архив (кроме того, что это не работает)
- у Fogbit такая же проблема
- подробнее о том, как реализовать IServiceProvider для ответа на SID_SInPlaceBrowser
IExplorerBrowser
интерфейс сделает это намного проще. - person Raymond Chen   schedule 09.10.2011IShellView
, будь то стандартное представление или расширение пространства имен. Можете ли вы указать на то же имя файла / папки? Важно отметить, что я не создаю расширение пространства имен, а скорее действую как часть проводника Windows или общего диалогового окна файла (то есть реализацииIShellBrowser
, а не разговора к нему). - person Ian Boyd   schedule 09.10.2011