Прямой доступ к макросам в документах MS WORD
Страница 2. Как получить доступ к потоку внутри документа


 

3. Как получить доступ к потоку внутри документа

Зная формат структурированного хранилища, можно самостоятельно написать программу сканирования файла. Но мы пойдем другим путем.

Библиотека OLE2.DLL содержит средства для работы со структурированными хранилищами. Функция stgIsStorageFile() возвращает для файла признак, является ли он структурированным хранилищем или нет. Функция stgOpenStorage() открывает файл хранилища и возвращает "интерфейс" IStorage. Это - объект класса, содержащего свойства и методы для работы со структурированными хранилищами:

  • IStorage::OpenStorage() - открывает подкаталог, возвращая интерфейс для доступа к подчиненным каталогам;
  • IStorage::Release() - закрывает подкаталог;
  • IStorage::EnumElements() - возвращает интерефейс перечислителя с методами Next(), Skip(), Reset() и т.п.;
  • IStorage::OpenStream() - открывает поток, возвращая интерефейс IStream с методами Read(), Write() и т.п.

Вот пример программы, сканирующей для указанного DOC-файла внутренние потоки.

//******************************************************************************
// Демонстрационная программа прямого доступа к макросам внутри DOC-файлов
// Компилятор Borland C/C++ v5.02
// (c) Климентьев К. aka DrMAD, Самара 2003
//******************************************************************************
#include "windows.h"
#include "ole2.h"
#include "iostream.h"

#define MAXBUF 0xFFFF
#define NAMELEN 256

char Buf[MAXBUF]; // Буфер под поток
char SBuf[MAXBUF]; // Буфер под распакованный текст

// Рекурсивный обход дерева потоков. (c) DrMad
walk(char *s, LPSTORAGE ls)
{
OLECHAR FileName[NAMELEN];// Unicode-имя для structured storage
char StreamName[NAMELEN];// ASCII-имя потока
LPENUMSTATSTG lpEnum=NULL;// Интерфейс перечислителя
LPSTORAGE pIStorage=NULL;// Интерфейс структурированного хранилища
LPSTORAGE pIStorage2=NULL;// Интерфейс хранилища нижнего уровня
LPSTREAM pIStream=NULL;// Интерфейс потока
STATSTG stat;// Очередная запись в каталоге
ULONG uCount;// Счетчик перечисления
ULONG streamlen;// Реальная длина потока
ULONG ch_pos;// Позиция чунка внутри потока

if (!ls) // Первый вызов
{
mbstowcs(FileName, s, 256);
StgOpenStorage(FileName,NULL,STGM_READ|STGM_SHARE_EXCLUSIVE, NULL,0,&
pIStorage);
walk("", pIStorage);
}
else // Повторный рекурсивный вызов
{
ls->EnumElements(0,NULL,0,&lpEnum);
if (lpEnum)
while (lpEnum->Next(1,&stat,&uCount)==S_OK)
{
if (stat.type==STGTY_STORAGE) // Это хранилище
{
ls->OpenStorage(stat.pwcsName,NULL,STGM_READ|STGM_SHARE_EXCLUSIVE,
NULL,0,&pIStorage2);
walk("", pIStorage2);
}
else // Это поток
{
ls->OpenStream(stat.pwcsName,NULL,STGM_READ|STGM_SHARE_EXCLUSIVE,0,
&pIStream);
pIStream->Read(Buf, MAXBUF, &streamlen);
wcstombs(StreamName, stat.pwcsName, 256);
ch_pos = search_chunk(Buf, streamlen); // См. ниже!
if (ch_pos) view_src(StreamName, Buf, ch_pos); // См. ниже!
}
};
ls->Release();
}
}

int main(int argc, char* argv[]) {
if (argc>1) walk(argv[1],NULL);
}

Недостатки подхода: невысокое быстродействие и проблемы доступа к запароленным и "слегка испорченным" документам.

 
« Предыдущая статья   Следующая статья »