Click here to Skip to main content
Click here to Skip to main content

Another OLE Doc Viewer but with editing facility

, 17 Jun 2004 CPOL
Rate this:
Please Sign up or sign in to vote.
An article on how to put and get information to an OLE Structured Document.

Sample Image - Another_OLE_Doc_Viewer.jpg

Introduction

This is just another OLE Document / Structured Document Viewer. Just to add a little to it, I have added deletion and insertion facilities in it. I developed it coz it was needed for our internal office use. We were working a lot on Structured Storage files and needed a utility to not only view all the details of Storages and Streams within a file but also to be able to edit the file. So, this is the end-product.

Background

You must be familiar with structured storage to have a complete grasp over this article. Just to introduce it to those who doesn't know about it, structured storage files are normally said to have a File System within a file. As with a normal file system in which we have folders and files, in a structured storage file, we have Storages and Streams. A storage can have streams as well as storages inside it, but a stream is like a simple binary file.

This is a small standalone exe. Now, some people would ask that Microsoft is itself providing an OLE Doc Viewer so what is the need for this. I think I have answered this before. I have added editing facilities which we needed for our office project and that was the only reason to develop it. Plus, I thought that it is something which should be shared. So, accept my apologies if somebody gets annoyed for repetition of work which I think isn't the case.

The Code

Since it is always considered best to represent a file system in a tree, so is done here. I have used a tree to show the full file system (so-called) within a storage file. By double-clicking or by selecting "Show Contents" from the right-click menu, you can see the value of the selected stream in the right side pane.

Well, coming to the code. I have stored all the Storages within a file in a linked list. There is a structure named StgPointers. This is used for a doubly linked list, I used a doubly linked list just to ease out the movement within the linked list. I have only stored the Storages in the linked list not the Streams. This was done just because if we have got a Storage pointer, then it is not difficult to open the streams within that particular storage.

Now, using a linked list for a tree caused me some problems especially while deleting, because logically a tree should be stored in a tree but that was again difficult to handle. So, I opted for the first difficult option because I thought I was good at that Smile | :) . I know self-praise leads to isolation but sometimes ....

Anyway, here are some of the important code snippets:

First of all, the structure which is used for the linked list:

typedef struct StgPointers
{
    IStorage * pointer;
    IStorage * parent;
    CString stgName;
    StgPointers * next;
    StgPointers * prev;
    HTREEITEM hTree;
} Pointers;

This is the API used for opening a Storage file on the disk.

HRESULT hRes = StgOpenStorage(wcFName, NULL, m_dwMode, NULL, 0, &m_pRootStg);

Now, this is the recursive function which is used to populate the tree. EnumElements is returning a pointer of type IEnumSTATSTG which holds the enumerated elements within that storage. By calling its next function, we get its name in an array of type STATSTG. Then it is being converted to a CString and added to the tree.

bool COLEDOCViewerDlg::PopulateTree(IStorage * pCurrentStorage, 
                                                   HTREEITEM htreeItem)
{
    HTREEITEM hNewItem;
    if(!m_bRootInserted)
    {
        htreeItem =  m_treeData.InsertItem(m_strFileName, 3 ,
        2);m_first->hTree = htreeItem;
        m_cur = m_prev = m_first;
        m_bRootInserted = true;
    }
    USES_CONVERSION;
    IEnumSTATSTG * ppenum = NULL;
    HRESULT hRes = pCurrentStorage->EnumElements(0,NULL, 0, &ppenum);
    CString addtoList;
    STATSTG arr[1];
    
    while(hRes != S_FALSE)
    {
        hRes = ppenum->Next(1, arr, NULL);
        addtoList = W2A(arr[0].pwcsName);
        if(arr[0].type == 1)
        {
            hNewItem = m_treeData.InsertItem(addtoList, 3, 2, htreeItem, NULL);
            WCHAR * stgName = A2W(addtoList);
            IStorage * pNewStorage = NULL;
            hRes = pCurrentStorage->OpenStorage(stgName, 
                   NULL, m_dwMode, NULL, 0, &pNewStorage);
            //Adding in Linked List
            m_prev = m_cur;
            m_cur =  new
            Pointers;m_cur->prev = 
            m_prev;m_cur->parent = 
            pCurrentStorage;m_cur->pointer = 
            pNewStorage;m_cur->stgName = 
            addtoList;m_cur->hTree = 
            hNewItem;m_cur->next = 
            NULL;m_prev->next = m_cur;
            //Added

            PopulateTree(pNewStorage, hNewItem);
            
        }
        if(arr[0].type == 2)
        {
            addtoList += "  <STREAM>";
            m_treeData.InsertItem(addtoList, htreeItem);
        }
        
    }
    ppenum->Release();
    return true;
}

The contents of a Stream are gotten like this. Here, pStream is a pointer to the Stream whose value we are reading.

            pStream->Read(readData, noofbytes, NULL);

The logic of DeleteItem is a bit complex because as I mentioned earlier, I am storing a tree in a linked list which caused me a good amount of problem here. Further, inserting Streams / Storages is not that difficult. It would be quite clear from the code, so I don't think I should further explain it here.

One important thing is the mode in which all the objects are opened. These are handled by one variable m_dwMode, and its value is set to:

m_dwMode = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT

STGM_READWRITE means that it is opened in both modes, STGM_SHARE_EXCLUSIVE suggests that no one else can open this while it is opened, and STGM_DIRECT means that we don't need to call Commit to ensure changes.

Remaining is quite simple.

My Thanks

I used a function SnapLine which was from an external source. This was probably from some version of Borland C, but I don't remember exactly. Thanx to the developer who created this.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Aamir Butt
Technical Lead
Pakistan Pakistan
No Biography provided

Comments and Discussions

 
Questioncan you upload the c source code Pinmembersonalirajput21-Feb-12 6:14 
QuestionCompiled version please? Pinmembergauravkale29-Jun-11 21:57 
Generalpassword protected excel 2007 file PinmemberMember 287760725-Feb-08 3:09 
GeneralExtract Macros Pinmemberfernandofre25-Apr-07 5:56 
General,Extract Macros Pinmemberfernandofre25-Apr-07 5:55 
GeneralUnwrap Objects PinmemberAndreasMoor23-Jun-04 3:32 
GeneralRe: Unwrap Objects PinmemberAamir Butt25-Jun-04 2:12 
GeneralWM_SETFONT PinmemberStephane Rodriguez.19-Jun-04 5:12 
GeneralRe: WM_SETFONT PinmemberAamir Butt20-Jun-04 20:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 18 Jun 2004
Article Copyright 2004 by Aamir Butt
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid