5,696,038 members and growing! (13,217 online)
Email Password   helpLost your password?
General Programming » Macros and Add-ins » DevStudio Add-ins     Intermediate

Structured Storage File Viewer Visual Studio Add-In

By Lim Bio Liong

Visual Studio add-in that allows you to view the contents of a Structured Storage File.
VC6, C++Windows, NT4VS6, Visual Studio, Dev

Posted: 1 Dec 2001
Updated: 3 Dec 2001
Views: 70,152
Bookmarked: 26 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
9 votes for this Article.
Popularity: 4.40 Rating: 4.62 out of 5
0 votes, 0.0%
1
0 votes, 0.0%
2
0 votes, 0.0%
3
1 vote, 20.0%
4
4 votes, 80.0%
5

Sample Image - SSFView.jpg

Introduction

A Structured Storage File is a binary file that is created and managed by the Microsoft OLE Structured Storage APIs. Structured Storage Files are also known as Compound Files. Essentially, we have a "file system within a file". Within such a compound file, we have two types of named objects: Storages and Streams.

A Storage Object acts like a directory of a typical file system. It manages other storages and streams but holds no data by itself. A Stream Object acts like a file in that it can hold information but not other storage objects. Examples of compound files include Microsoft Word (.doc) documents and Microsoft Excel (.xls) worksheet files.

SSFView is a Visual Studio add-in that allows a developer to view the contents of Structured Storage Files. An example view of a Microsoft Word document is shown in the screenshot above.

The motivation for the development of this add-in came about when my development team had to debug the implementation of a program data file which is stored using OLE's Structured Storage File format.

For debugging purposes, we had to compare stream outputs from existing storage files with live stream data being created. We had to dump out parts of stream data using trace statements and other file logging operations. It was messy and the use of these debugging constructs were short-termed.

We thus took the initiative to develop our own Structured Storage File Viewer which can be customized to meet our debugging needs. We thought it would be a good idea to share our code to readers out there who may be facing similar problems and would wish to have some startup code in order to develop a customized Structured Storage File Viewer.

Instead of developing a separate application, it was our unanimous choice to develop an add-in instead. The following are the advantages:

  1. Utilization of Visual Studio resources, especially the binary view windows.

    It would have taken much longer time for us to develop our own binary view window. Why not use the one supplied automatically by VS? Saving, searching capabilities are all provided.

  2. Integration with Visual Studio for debugging ease.

    Debugging is more intuitive when you can do everything in an integrated environment rather than having to step out into external applications every once in a while.

Installation

  1. Build the zipped SSFView.dsw project and copy SSFView.dll into Program Files\microsoft visual studio\common\msdev98\addins.
  2. Open Tools | Customize | Add-ins and Macro Files and tick "SSFView.DSAddIn.1".
  3. A new toolbar with an icon shown below will appear.

Usage

  1. Click on this icon and the usual Open dialog box will appear.

  2. Select any file known to be a compound file (e.g. a MS Word Doc file).
  3. The contents of the compound file will be displayed as a tree in the tree view window of the Viewer dialog box.

  4. Storages are displayed as folder icons.
  5. Streams are displayed as file icons.
  6. Clicking on either types of objects will cause the add-in to display statistics information about the selected object, on the edit box on the right.
  7. If you double-click on a Stream object, its full contents are displayed in a binary window in Visual Studio.
  8. You can opt to save the contents through Visual Studio in the usual way (via File | Save).

Limitations

Note that double-clicking the same stream item will cause its contents to be displayed even if its contents have already been displayed in a binary view window.

The contents of a stream object are first dumped by the add-in into a temporary file on your system. The contents of this file is displayed in the binary view window. Therefore the title of the window will be the name of the temp file and not the name of the stream object.

How It Works

The entire functionality of the add-in is encapsulated inside the CDlg_StructuredStorageFileViewer dialog box. This dialog box is designed to be a modeless dialog box. This dialog box will manage exactly one structured storage file and will do so until it is closed. This dialog box will start life when the add-in icon button is clicked at which time the following code will be executed:

STDMETHODIMP CCommands::StructuredStorageFileViewer()
{
      AFX_MANAGE_STATE(AfxGetStaticModuleState())

      // TODO: Add your implementation code here

        if (m_pDlg_StructuredStorageFileViewer == NULL)
      {
        LPTSTR lpszFileName = NULL;
        long lRetTemp = 0;

        lRetTemp = OpenAFile ((LPTSTR*)&lpszFileName);

        if ((lRetTemp == 0) && (lpszFileName))
        {
          m_pDlg_StructuredStorageFileViewer = 
            new CDlg_StructuredStorageFileViewer();
          m_pDlg_StructuredStorageFileViewer -> 
            SetFileToView((LPCTSTR)lpszFileName);
          m_pDlg_StructuredStorageFileViewer -> SetCommandsObject (this);
          m_pDlg_StructuredStorageFileViewer -> Display();
        }

        if (lpszFileName)
        {
          free (lpszFileName);
          lpszFileName = NULL;
        }
      }

      return S_OK;
}

A new instance of CDlg_StructuredStorageFileViewer is created, the file to view is set by the member SetFileToView() function. We also give this dialog box a pointer to the current CCommands object so that it can communicate with it. It is via the CCommands pointer that the dialog box instructs CCommands to display the contents of a stream object. We then instruct the dialog box to display itself.

The CDlg_StructuredStorageFileViewer dialog box responds to the TVN_SELCHANGED notification from the tree view control and the handler for this is CDlg_StructuredStorageFileViewer:: OnSelchangedTreeStructuredStorageFileContents(). The code for this function is shown below:

void 
  CDlg_StructuredStorageFileViewer::OnSelchangedTreeStructuredStorageFileContents
  (NMHDR* pNMHDR, LRESULT* pResult)
{
  NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
  // TODO: Add your control notification handler code here

  HWND hwndTree = pNMHDR -> hwndFrom;

  // If a selection in the Tree has changed, we investigate further.

  if (pNMHDR -> code == TVN_SELCHANGED)
  {
    // If this item is designated as a Storage item, 

    // we analyse it further.

    if ((pNMTreeView -> itemNew).lParam == STGTY_STORAGE)
    {
      // AnalyseStorage() will insert further Tree Items inside this item

      // if appropriate.

      AnalyseStorageItem ((HWND)hwndTree, 
        (pNMTreeView -> itemNew).hItem);
    }

    if ((pNMTreeView -> itemNew).lParam == STGTY_STREAM)
    {
      // AnalyseStreamItem() will display the

      // IStream information of this stream item.

      AnalyseStreamItem ((HWND)hwndTree, 
        (pNMTreeView -> itemNew).hItem);
    }
  }

  *pResult = 0;

  return;
}

Two functions stand out: AnalyseStorageItem() and AnalyseStreamItem(). AnalyseStorageItem() is called when a storage item is clicked on the tree view control. It will perform two things:

  1. It will expand this storage tree view item by examining it to see if it contains any storages and streams. If so, tree view children will be added to this item.
  2. It will also display the statistics information about this selected tree view item.

AnalyseStreamItem() will simply display statistics information about the stream object.

The CDlg_StructuredStorageFileViewer dialog box also responds to the NM_DBLCLK notification from the tree view control and the handler for this is CDlg_StructuredStorageFileViewer::OnDblclkTreeStructuredStorageFileContents(). The code for this function is shown below:

void 
  CDlg_StructuredStorageFileViewer::OnDblclkTreeStructuredStorageFileContents
  (NMHDR* pNMHDR, LRESULT* pResult) 
{
  // TODO: Add your control notification handler code here

  HWND hwndTree = pNMHDR -> hwndFrom;
  HTREEITEM hTreeItemCurrent = 
    TreeView_GetSelection(hwndTree);
  TV_ITEM tv_item_current;

  memset (&tv_item_current, 0, sizeof(TV_ITEM));
  tv_item_current.hItem = hTreeItemCurrent;
  tv_item_current.mask = TVIF_HANDLE | TVIF_PARAM;

  TreeView_GetItem (hwndTree, &tv_item_current);

  // If this item is designated as a Storage item, 

  // we analyse it further.

  if (tv_item_current.lParam == STGTY_STORAGE)
  {
    // Nothing needs to be done when a Storage Item is double-clicked.

    // It has already been analysed in TVN_SELCHANGED.

  }

  if (tv_item_current.lParam == STGTY_STREAM)
  {
    // When a Stream Item is double-clicked,

    // its contents will have to be displayed.

    DisplayStreamItem ((HWND)hwndTree, 
      (HTREEITEM)hTreeItemCurrent);
  }

  *pResult = 0;

  return;
}

Only when a Stream object is double-clicked will any meaningful thing be performed. We display the contents of this stream object when it is double-clicked. The main function to perform this is DisplayStreamItem().

Conclusion

A tree view provides a natural and intuitive layout for directories and files and this is the primary reason why we use it to display storages and streams. However, the emphasis of this add-in is to view and save data. Therefore nothing fancy is done with the tree view control.

This can be seen in the fact that although we used MFC's CTreeCtrl class to operate with the tree view, we did not fully use its MFC methods. Rather, we used TreeView_* macros. This is because we wanted to use several tried and tested code for working with tree views.

We also did not make extensive use of private item data (TV_INSERTSTRUCT.item.lParam) to point to structs. We simply used the lParam to indicate whether a tree view item is a Storage Item or a Stream Item.

HTREEITEM CDlg_StructuredStorageFileViewer::TreeItemInsert_Storage
  (HWND hwndTree, LPCTSTR lpszStorageName, HTREEITEM hTreeItemParent)
{
  TV_INSERTSTRUCT      tvis ;
      ...
      ...
      ...
>>tvis.item.lParam = STGTY_STORAGE;

  hTreeItemRet = TreeView_InsertItem(hwndTree, &tvis);

  return hTreeItemRet;
}

We plan to further enhance the statistics information display. The various date/time values are currently displayed as hex values. This is because we have yet to find out how to properly interpret FILETIME structs. If any reader knows how to interpret this, please contact us. :-)

We also plan to extend our add-in to read memory storages and streams which can prove very useful as well.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Lim Bio Liong


Lim Bio Liong is a Specialist at a leading Software House in Singapore.

Bio has been in software development for over 10 years. He specialises in C/C++ programming and Windows software development.

Bio has also done device-driver development and enjoys low-level programming. Bio has recently picked up C# programming and has been researching in this area.


Occupation: Web Developer
Location: Singapore Singapore

Other popular Macros and Add-ins articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 13 of 13 (Total in Forum: 13) (Refresh)FirstPrevNext
GeneralHelp ! how do I get the sub-storage count in SS filememberPrasad_th7:21 2 Jul '04  
GeneralDeleting Storages and StreammemberAamir Butt2:27 26 May '04  
GeneralRe: Deleting Storages and StreammemberAamir Butt2:41 26 May '04  
GeneralStructure of Stg filesmemberAndrew Phillips19:42 2 May '04  
GeneralDocFile Viewermemberton ot llet21:10 16 Dec '03  
GeneralHelp needed ,strip compound.... macro'smemberAtila2:47 29 May '02  
GeneralBrilliant!memberPaulMdx4:59 5 Apr '02  
GeneralRe: Brilliant!memberLim Bio Liong18:59 7 Apr '02  
GeneralVery, very cool codememberDanYELL6:58 17 Jan '02  
GeneralRe: Very, very cool codememberLim Bio Liong19:49 17 Jan '02  
GeneralFILETIMEmemberDale Stewart9:52 9 Jan '02  
GeneralRe: FILETIMEmemberLim Bio Liong16:28 9 Jan '02  
GeneralRe: FILETIMEsussAnonymous12:22 28 Oct '03  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 3 Dec 2001
Editor: Smitha Vijayan
Copyright 2001 by Lim Bio Liong
Everything else Copyright © CodeProject, 1999-2008
Web18 | Advertise on the Code Project