Newsgroup: it.comp.lang.c++
Titolo: Problema con IStorage

Grazie per l'attenzione,
ho un problema con Ole Structured Storage: dopo aver aperto un documento
composto con StgOpenStorage, non riesco ad aprire gli oggetti al suo
interno.
Qualche dettaglio in più:
Il docfile il questione è un qualunque documento di MSWord, ma anche con
altri tipi di docfile (xls, ppt, ecc.) la canzone non cambia;
la funzione StgOpenStorage ha esito positivo;
l'interfaccia IStorage restituita è valida;
non ho problemi a enumerare gli oggetti presenti nel documento (utilizzando
il metodo EnumElements e l'interfaccia IEnumSTATSTG);
i metodi IStorage::OpenStorage e IStorage::OpenStream restituiscono
STG_E_INVALIDFUNCTION che, a detta della documentazione, significa che la
combinazione dei flag passati al parametro grfMode non è valida. Nella
documentazione leggo inoltre che un oggetto (storage o stream) eredita le
restrizioni minime d'accesso dall'oggetto padre; quindi io ho passato ai
due metodi gli stessi flag che ho passato a StgOpenStorage. Ho provato a
cambiare flag, ma ho ottenuto risultati peggiori: in alcuni casi
StgOpenStorage falliva, e con il flag STG_SHARE_EXCLUSIVE mi sono beccato
pure una violazione 
d'accesso nel modulo kernel. Ecco una parte molto sintetizzata del codice:
IStorage *pIStorageDoc = NULL, *pIStorage = NULL;
DWORD dwOpenMode = STGM_READ | STGM_SHARE_DENY_WRITE;
// Ho provato anche STGM_READWRITE | STGM_SHARE_DENY_WRITE |
STGM_TRANSACTED
StgOpenStorage(L"...",NULL,dwOpenMode,NULL,0,&pIStorageDoc);
// i nomi degli oggetti derivano dall'enumerazione
// se è un oggetto storage
pIStorageDoc->OpenStorage(statstg.pwcsName,NULL,dwOpenMode,NULL,0,&pIStorage
);
// altrimenti
pIStorageDoc->OpenStream(statstg.pwcsName,NULL,dwOpenMode,0,&pIStream);
// entrambi i metodi falliscono e restituiscono STG_E_INVALIDFUNCTION
Qualcuno ha esperienza di OLE Structured Storage ?
Grazie,
Stefano.

Qualcuno ha esperienza di OLE Structured Storage ?
Io, qualcosina -- prova questo esempietto:
#define STRICT
#include <windows.h>
#include <stdio.h>
LPWSTR sToWide(const char* s)
{
    int rc = MultiByteToWideChar(CP_ACP , 0, s,
        -1, 0, 0);
    LPWSTR result =
        (LPWSTR)malloc(sizeof(wchar_t)*(rc+1));
    MultiByteToWideChar(CP_ACP , 0, s,
        -1, result, rc);
    return result;
}
int main(int argc, char**argv)
{
    if(argc!=2) {
        printf("Usage: %s storage\n", argv[0]);
        return 100;
    }
    CoInitialize(0);
    IStorage* pStor = 0;
    LPWSTR pW = sToWide(argv[1]);
    HRESULT hr = StgOpenStorage(pW, 0,
        STGM_READ | STGM_SHARE_DENY_WRITE, 0, 0, &pStor);
    if(FAILED(hr)) {
        printf("Can't open (%s)(%S), err=0x%x\n", argv[1], pW, hr);
        return 1;
    }
    free(pW);
    printf("(%s) opened OK\n", argv[1]);
    IEnumSTATSTG* pEs = 0;
    hr = pStor->EnumElements(0,0,0,&pEs);
    if(FAILED(hr)) {
        printf("Can't enum elems, err=0x%x\n", hr);
        return 1;
    }
    int nEs=0;
    for(;;++nEs) {
        STATSTG ssg;
        ULONG uc;
        pEs->Next(1, &ssg, &uc);
        if(!uc) break;
        printf("Type %d (%S) %d byte (F=%d)\n",
            ssg.type, ssg.pwcsName, ssg.cbSize, ssg.grfStateBits);
        CoTaskMemFree(ssg.pwcsName);
    }
    printf("%d elements\n", nEs);
    IStream* pStream=0;
    hr = pStor->OpenStream(L"WordDocument", 0,
        STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &pStream);
    if(FAILED(hr)) {
        printf("Can't open stream WordDocument, err=0x%x\n", hr);
        return 1;
    }
    printf("WordDocument opened OK\n");
    unsigned char buf[20];
    ULONG nb;
    hr = pStream->Read(buf,20,&nb);
    if(FAILED(hr)) {
        printf("Can't read stream WordDocument, err=0x%x\n", hr);
        return 1;
    }
    printf("%d byte read\n", nb);
    for(ULONG i=0; i<nb; ++i) {
        printf("%2.2x ", buf[i]);
    }
    if(nb)
        printf("\n");
    pStream->Release();
    pStor->Release();
    return 0;
}
Fatto girare su un file di Word (ne ho scelto uno che
puoi procurarti anche tu, se vuoi, perche` e` parte
del DDK98 che puoi scaricare dal sito Microsoft),
mi da` il seguente standard-output:
(gpcspec.doc) opened OK
Type 2 ( CompObj) 110 byte (F=0)
Type 1 (ObjectPool) 0 byte (F=0)
Type 2 (WordDocument) 229619 byte (F=0)
Type 2 ( SummaryInformation) 768 byte (F=0)
4 elements
WordDocument opened OK
20 byte read
dc a5 65 00 3d c0 09 04 00 00 00 00 65 00 00 00 00 00 00 00
A te questo programmino non funziona...?  Ti da`
l'errore che hai riferito...?  Facci sapere!
Alex

Ringrazio molto per l'aiuto e vengo al dunque:
l'esempio che mi hai mandato funziona, e funzionava anche il mio; la
violazione (che non è una violazione d'accesso, ma un errore di stack - ero
troppo incavolato per leggere tutto quello che c'era scritto) si verifica
proprio quando OpenStorage ha successo (quando, per caso, azzeccavo i flag
giusti), ed è generata da una parte di codice che mai avrei pensato potesse
generarla, ovvero una HeapAlloc, e questa ancora non me la spiego; vedo di
spiegarmi meglio:
il mio programma è un'applicazione con interfaccia di tipo explorer che
permette[rà, spero] di visualizzare gerarchicamente gli elementi di un
documento composto (decisamente inutile come applicazione, ma mi sembra un
buon esercizio). Ora, come parametro associato ad ogni elemento della
TreeView (che rappresenta gli oggetti storage) passo un puntatore ad una
struttura STORAGEINFO definita da me; la memoria per queste strutture è
allocata da un heap (destinato unicamente alle strutture di tipo
STORAGEINFO) che ha una dimensione iniziale pari a 4K ed è 'growable'.
All'interno di ogni struttura STORAGEINFO, oltre ad un puntatore
all'interfaccia IStorage e alcune altre cose, c'è un puntatore a un elenco
di strutture STATSTG; la memoria per queste strutture è allocata
dinamicamente da un altro heap (destinato unicamente alle strutture di tipo
STATSTG) con le stesse caratteristiche del primo. Non alla prima, ma alla
seconda HeapAlloc su quest'ultimo heap ottengo l'errore di stack. Ho
provato ad allocare le STATSTG dal primo heap, dal ProcessHeap e da un
terzo heap. Con il primo heap ho ottenuto lo stesso stack error; con il
ProcessHeap succedono cose strane con i nomi degli oggetti perché circa il
50% delle 
volte i membri pwcsName di STATSTG contengono stringhe nulle e i metodi
Open* mi restituiscono giustamente STG_E_FILENOTFOUND (stessi risultati con
CoTaskMemAlloc); con un terzo heap funziona, ma chi mi assicura che alla
terza o alla quarta allocazione non si presenti lo stesso errore? E 
comunque, non è giusto che si verifichino situazioni del genere. Se invece
faccio una seconda chiamata a HeapAlloc subito dopo la prima e con un
puntatore a STATSTG che non risiede nel primo heap, non si pianta.
Chiaramente una chiamata di questo tipo non ha alcuna utilità, è solo una
prova e non un'alternativa al precedente approccio. Hai idea di che cosa
stia succedendo? So di non essere stato per niente chiaro, ma credimi non è
affatto facile spiegare l'assurdità a cui sto assistendo. Postare il
listato 
potrebbe essere un problema; dal momento che non so da che cosa dipenda
l'errore, mi è impossibile isolare le parti interessate, e poi per renderti
conto di quello che succede dovresti farlo girare. Il listato completo
contiene più di 500 righe, e non so se sia il caso di postarlo tutto. Penso
che finirò col ricominciare da zero e vedere che cosa succede.
In definitiva, comunque, i problemi strettamente legati a Structured
Storage sono risolti.
Volevo farti un altro paio di domande, ma è meglio occuparsi di una cosa
alla volta.
Ciao,
Stefano.

stia succedendo? So di non essere stato per niente chiaro, ma credimi non
Purtroppo no, comunque un "errore alla seconda allocazione" e`
abbastanza tipico di quel che succede quando sulla "prima"
allocazione uno ha poi "debordato", scrivendo piu` dati di quanto
spazio non avesse riservato; questo danneggia la heap.  Non
mi pare pero` che la STATSTG sia prona a questo tipo di errori,
per come e` progettata come struttura.  Magari c'e` qualche
altro errore relativo alle allocazioni, come ad esempio (l'unica
possibilita` che mi viene in mente per STATSTG direttamente)
non tenere conto che la memoria a cui punta pwcsName e`
sempre allocata dal metodo chiamato con CoTaskMemAlloc,
e liberata poi dal chiamante con CoTaskMemFree.  Oppure
fai un errore quando chiami il metodo Next dell'interfaccia
IEnumSTATSTG, ad esempio passando come 1o parametro
un numero di strutture maggiore a quelle che hai veramente
allocato nell'array al cui inizio punta il 2o parametro...
Se puoi accere a strumenti come BoundsChecker o Purify,
magari anche solo in una qualche versione "trial", considera
che essi sono spesso molto utili per tenere traccia di errori
e problemi relativi alla gestione della memoria.
Alex

Se puoi accedere a strumenti come BoundsChecker o Purify,
li cercherò sicuramente.
Quello che però mi lascia veramente perplesso è che questo errore di stack,
si verifica nel modulo kernel32 e non all'interno del processo creato dalla
mia applicazione.
Ad ogni modo, ho intenzione di ripartire da zero con un approccio un po'
diverso: pensavo di utilizzare una classe con suoi propri heap e una
tabella contenente i puntatori ai blocchi di volta in volta allocati. In
questo modo posso passare alla TreeView dei semplici indici di tabella,
evitando troppi intrecci di puntatori.
Mah, speriamo bene; poi posterò qualcosa per farvi sapere com'è andata.
Grazie di tutto e arrisentirci,
Stefano.