Step Six: Implement the IFileViewer Interface

To implement the IFileViewer interface, the file viewer must implement the three member functions FileShowInitialize, FileShow, and PrintTo.

FileShowInitialize

This is a pre-show function. It allows a file viewer to determine whether it can display a file and, if it can, to perform the necessary initialization operations. The system calls FileShowInitialize before calling IFileViewer::Show. FileShowInitialize must perform all operations that are prone to failure; if it succeeds, IFileViewer::Show will not fail. The system specifies the name of the file that will be displayed by calling the file viewer's IPersistFile::Load member function. This function returns NOERROR if it is successful; otherwise, it returns an OLE-defined error value. In my file viewer, this function calls AddRef, creates the windows it needs, loads the file, stores the filename, and returns the error status.

STDMETHODIMP CFileView::XFileViewer::ShowInitialize ( 
LPFILEVIEWERSITE lpfsi)
{
METHOD_PROLOGUE (CFileView, FileViewer);
TRACE ("CFileView::XFileViewer::ShowInitialize\n");

HRESULT hr;

// Be sure that you have the file viewer.
if (pThis->m_lpfsi != lpfsi)
{
pThis->m_lpfsi = lpfsi;
pThis->m_lpfsi->AddRef ();
}

// Default error code
hr = E_OUTOFMEMORY;

// Create the windows.
pThis->m_Wnd = new CMyFrame;
pThis->m_Wnd->Create ();

// Load a file.
HGLOBAL hMem=NULL;
char szwFile [512];

if (pThis->m_pszPath == NULL)
return E_UNEXPECTED;

// This file viewer is registered for a TXT extension that
// is either in a compound file (a single stream called "Text")
// or in a flat text file. This sample shows
// how to open and work with both types of files.

// Make a Unicode copy of the filename.
mbstowcs ((USHORT *)szwFile, pThis->m_pszPath, sizeof (szwFile));

// CAREFUL: StgIsStorageFile returns S_FALSE if the file doesn't
// contain an IStorage object. Don't use SUCCEEDED to test the
// return value!
if (StgIsStorageFile (szwFile) == NOERROR)
{
LPSTORAGE pIStorage = NULL;
LPSTREAM pIStream = NULL;
STATSTG stat;

// It is a compound file; open it and the text stream.
hr = StgOpenStorage (szwFile, NULL, pThis->m_grfMode, NULL, 0,
&pIStorage);

if (FAILED (hr))
return hr;

mbstowcs ((USHORT *)szwFile, "Text", sizeof (szwFile));

hr = pIStorage->OpenStream (szwFile, 0,
STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream);

if (SUCCEEDED (hr))
{
// Determine the amount of text and allocate memory.
hr = pIStream->Stat (&stat, STATFLAG_NONAME);

if (SUCCEEDED (hr))
{
hMem = (HGLOBAL) malloc (stat.cbSize.LowPart + 1);

if (hMem != NULL)
// Now load the text into the controls.
hr = pIStream->Read ((LPVOID)hMem, stat.cbSize.LowPart,
NULL);
else
hr = E_OUTOFMEMORY;
}
pIStream->Release ();
}
pIStorage->Release ();
}

else
{
HANDLE hFile;
DWORD dwFileSize, dwBytesRead;
char *lpBufPtr;

// Open the text file.
if ((hFile = CreateFile (pThis->m_pszPath,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
(HANDLE)NULL)) == (HANDLE)(-1))
{
AfxMessageBox ("Failed to open file");
return STG_E_FILENOTFOUND;
}

// Get the size of the file.
dwFileSize = GetFileSize (hFile, NULL);
if (dwFileSize == 0xFFFFFFFF)
return STG_E_READFAULT;

// Allocate a buffer into which the file will be read.
lpBufPtr = (char *) malloc (dwFileSize);
if (lpBufPtr == NULL)
{
CloseHandle (hFile);
return STG_E_READFAULT;
}

// Read the file contents into a buffer.
ReadFile (hFile, (LPVOID)lpBufPtr, dwFileSize, &dwBytesRead, NULL);

// Update the multiline edit control with the file contents.
pThis->m_Wnd->UpdateEdit (lpBufPtr);

// Close the file.
CloseHandle (hFile);
}

// Tell IFileViewer::Show it's OK to call it.
pThis->m_fShowInit = TRUE;

return NOERROR;
}

FileShow

This function is used to display a file. The system specifies the name of the file to display by calling the file viewer's IPersistFile::Load member function. This function returns NOERROR if it is successful or E_UNEXPECTED if IFileView::ShowInitialize wasn't called before IFileView::Show. This member function is similar to the Windows ShowWindow function in that it receives a Show command indicating how the file viewer should initially display its window.

STDMETHODIMP CFileView::XFileViewer::Show (LPFVSHOWINFO
pvsi)
{
METHOD_PROLOGUE (CFileView, FileViewer);
TRACE ("CFileView::XFileViewer::Show\n");

if (! pThis->m_fShowInit)
return E_UNEXPECTED;

pThis->m_pvsi = pvsi;

// If you could not view the file, go back to the message loop.
if ((pThis->m_pvsi->dwFlags & FVSIF_NEWFAILED) == 0)
{
if (pThis->m_pvsi->dwFlags & FVSIF_RECT)
pThis->m_Wnd.MoveWindow (pThis->m_pvsi->rect.left,
pThis->m_pvsi->rect.top, pThis->m_pvsi->rect.right,
pThis->m_pvsi->rect.bottom);
pThis->m_Wnd.ShowWindow (pThis->m_pvsi->iShow);

if (pThis->m_pvsi->iShow != SW_HIDE)
{
pThis->m_Wnd.SetForegroundWindow ();
pThis->m_Wnd.UpdateWindow ();
}

// If an old window exists, destroy it now.
if (pThis->m_pvsi->dwFlags & FVSIF_PINNED)
{
pThis->m_lpfsi->SetPinnedWindow (NULL);
pThis->m_lpfsi->SetPinnedWindow (pThis->m_Wnd.m_hWnd);
}

if (pThis->m_pvsi->punkRel != NULL)
{
pThis->m_pvsi->punkRel->Release ();
pThis->m_pvsi->punkRel = NULL;
}
}
return NOERROR;
}

PrintTo

This function prints a file. The system specifies the name of the file to print by calling the file viewer's IPersistFile::Load member function. This function returns NOERROR if it is successful; otherwise, it returns an OLE-defined error value. This member function resembles Show in that it does not return until it finishes printing or an error occurs. If a problem arises, the file viewer object is responsible for informing the user of the problem. This is not implemented in my file viewer—it's just a stub.

STDMETHODIMP CFileView::XFileViewer::PrintTo (
LPSTR pszDriver, BOOL fSuppressUI)
{
// This is a stub. Printing isn't implemented.
TRACE ("CFileView::XFileViewer::PrintTo\n");

return E_NOTIMPL;
}