Building Preview Handlers
This topic discusses the specific interfaces and methods required to create a preview handler.
A preview handler must implement the following interfaces:
- IInitializeWithStream::Initialize (strongly preferred), IInitializeWithFile, or IInitializeWithItem
If your preview handler supports visual settings provided by the host such as background color and font, it must also implement the following interface:
This topic assumes that the preview handler is initialized with a stream and is registered for a particular file name extension.
Store the IStream and mode parameters so that you can read the item's data when you are ready to preview the item. Do not load the data in Initialize. Load the data in IPreviewHandler::DoPreview just before you render.
Store the IUnknown pointer for later access.
If you currently have a reference to an IPreviewHandlerFrame object, release it. Use the stored IUnknown pointer to call QueryInterface on the site for a new IPreviewHandlerFrame reference.
If you currently have an accelerator table, destroy it. Call IPreviewHandlerFrame::GetWindowContext to get a new accelerator table. Store this table. Note that it is used only as a list of accelerator keys that the frame supports. Commands in the accelerator entries are ignored.
Return the site pointer, whatever it is.
Return E_NOTIMPL for this method.
If the preview handler's window currently exists, return the HWND of that window and S_OK. If the window does not exist, return E_FAIL.
Set the hwnd parameter of this method to the parent of your preview handler's HWND. This method can be called multiple times. Resize your preview so that it renders only in the area described by the prc parameter.
If the previewer is in the process of rendering, use the IPreviewHandler::SetWindow method to change the parent of the previewer. Also change the area in which the previewer is rendering.
Resize your preview so that it only renders in the area described by this method's prc.
If the previewer is in the process of rendering, change the area in which your previewer renders.
This is where the real work is done. Since a preview is dynamic, the preview content should only be loaded when it is needed. Do not load content in the initialization.
If the preview handler window does not exist, create it. Your preview handler's windows should be children of the window provided by IPreviewHandler::SetWindow. They should be the size provided by IPreviewHandler::SetWindow and IPreviewHandler::SetRect (whichever was called most recently).
Once you have a window, load the data from the IStream that the preview handler was initialized with, and render that data to your preview handler's window.
This method is called when the focus enters the reading pane through a tab action. Since it can be entered as a forward tab or reverse tab, use the current state of the SHIFT key to decide whether the first or last tab stop in the reading pane should receive the focus.
This method should call the GetFocus function and return the result of that call in the phwnd parameter.
This method is called by the message pump of the preview handler's process (whether prevhost.exe or a custom local server) in response to user keystrokes. Preview handlers should handle these keystrokes or forward them to their host according to the algorithm detailed below.
However, because previews are read-only, keyboard input should be minimal and optimizations such as this are not needed in many cases.
If the keyboard accelerator passed to this method through the message pump is an accelerator that your preview handler accepts, then process it and return S_OK. If your handler does not accept that accelerator, the accelerator message can be sent back as far as the frame to be handled.
There are two options for forwarding keyboard accelerators back to the frame:
The simplest model is to forward all keystrokes to the host using IPreviewHandlerFrame::TranslateAccelerator. This is done in the preview handler sample provided with the Windows Software Development Kit (SDK). All low-integrity preview handlers must use this model. If the accelerator is not handled by your preview handler, call IPreviewHandlerFrame::TranslateAccelerator and return its result.
The other model is to use an accelerator table as an optimization to avoid sending too many keystrokes across process boundaries:
- When IObjectWithSite::SetSite is called on your preview handler, acquire the accelerator table through IPreviewHandlerFrame::GetWindowContext. (Be sure to free the handle to the accelerator table when your previewer is destroyed.)
- If the accelerator is handled by your preview handler, handle it and return S_OK.
- If the accelerator is not handled by your preview handler, compare the message using IsAccelerator against the accelerator table acquired.
- If the accelerator matches an entry in that accelerator table, call IPreviewHandlerFrame::TranslateAccelerator and return its result.
- If the accelerator does not match any entry in the accelerator table, return S_FALSE.
When this method is called, stop any rendering, release any resources allocated by reading data from the stream, and release the IStream itself.
Once this method is called, the handler must be reinitialized before any attempt to call IPreviewHandler::DoPreview again.
These methods should be implemented when directing the preview handler to respond to the host's color and font schemes. The host queries the handler for IPreviewHandlerVisuals. If found to be supported, the host provides it with color, font, and text color.
Store this color and use it during rendering when you want to provide a background color. For instance, to fill the window when the handler renders to an area smaller than the area provided by IPreviewHandler::SetWindow and IPreviewHandler::SetRect. Note, however, that you should not draw outside the area provided by those methods.
If this method is called while the preview is already being rendered, the rendering should be restarted using this background color.
Store this font information and use it during rendering when you want to display text consistent with the current Windows Vista settings.
Store this text color information and use it during rendering when you want to display text consistent with the current Windows Vista settings.